From b6cfe8bd4118cb2896902c76bb2ea3d79c97eeae Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Fri, 22 Sep 2017 23:18:41 -0700 Subject: PCI: tegra: Use generic accessors where possible The Tegra PCI host controller can generate configuration space accesses with byte, word and dword granularity for devices. Only root ports can't have their configuration space accessed in this way. Signed-off-by: Thierry Reding Signed-off-by: Bjorn Helgaas --- drivers/pci/host/pci-tegra.c | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/drivers/pci/host/pci-tegra.c b/drivers/pci/host/pci-tegra.c index 9c40da54f88a..e8e1ddbaabc9 100644 --- a/drivers/pci/host/pci-tegra.c +++ b/drivers/pci/host/pci-tegra.c @@ -491,12 +491,32 @@ static void __iomem *tegra_pcie_map_bus(struct pci_bus *bus, return addr; } +static int tegra_pcie_config_read(struct pci_bus *bus, unsigned int devfn, + int where, int size, u32 *value) +{ + if (bus->number == 0) + return pci_generic_config_read32(bus, devfn, where, size, + value); + + return pci_generic_config_read(bus, devfn, where, size, value); +} + +static int tegra_pcie_config_write(struct pci_bus *bus, unsigned int devfn, + int where, int size, u32 value) +{ + if (bus->number == 0) + return pci_generic_config_write32(bus, devfn, where, size, + value); + + return pci_generic_config_write(bus, devfn, where, size, value); +} + static struct pci_ops tegra_pcie_ops = { .add_bus = tegra_pcie_add_bus, .remove_bus = tegra_pcie_remove_bus, .map_bus = tegra_pcie_map_bus, - .read = pci_generic_config_read32, - .write = pci_generic_config_write32, + .read = tegra_pcie_config_read, + .write = tegra_pcie_config_write, }; static unsigned long tegra_pcie_port_get_pex_ctrl(struct tegra_pcie_port *port) -- cgit v1.2.3 From 904fb8e452b4a95490357841291fa523ad1d6442 Mon Sep 17 00:00:00 2001 From: Manikanta Maddireddy Date: Wed, 27 Sep 2017 17:28:34 +0530 Subject: dt-bindings: pci: tegra: Document Tegra186 PCIe DT Tegra186 PCIe controller DT properties has couple of differences wrt Tegra210 PCIe, rest of the DT properties are same. Tested-by: Mikko Perttunen Signed-off-by: Manikanta Maddireddy Signed-off-by: Bjorn Helgaas Reviewed-by: Mikko Perttunen Acked-by: Thierry Reding --- .../bindings/pci/nvidia,tegra20-pcie.txt | 134 ++++++++++++++++++++- 1 file changed, 130 insertions(+), 4 deletions(-) diff --git a/Documentation/devicetree/bindings/pci/nvidia,tegra20-pcie.txt b/Documentation/devicetree/bindings/pci/nvidia,tegra20-pcie.txt index 982a74ea6df9..33d2e2139333 100644 --- a/Documentation/devicetree/bindings/pci/nvidia,tegra20-pcie.txt +++ b/Documentation/devicetree/bindings/pci/nvidia,tegra20-pcie.txt @@ -1,10 +1,15 @@ NVIDIA Tegra PCIe controller Required properties: -- compatible: For Tegra20, must contain "nvidia,tegra20-pcie". For Tegra30, - "nvidia,tegra30-pcie". For Tegra124, must contain "nvidia,tegra124-pcie". - Otherwise, must contain "nvidia,-pcie", plus one of the above, where - is tegra132 or tegra210. +- compatible: Must be: + - "nvidia,tegra20-pcie": for Tegra20 + - "nvidia,tegra30-pcie": for Tegra30 + - "nvidia,tegra124-pcie": for Tegra124 and Tegra132 + - "nvidia,tegra210-pcie": for Tegra210 + - "nvidia,tegra186-pcie": for Tegra186 +- power-domains: To ungate power partition by BPMP powergate driver. Must + contain BPMP phandle and PCIe power partition ID. This is required only + for Tegra186. - device_type: Must be "pci" - reg: A list of physical base address and length for each set of controller registers. Must contain an entry for each entry in the reg-names property. @@ -124,6 +129,16 @@ Power supplies for Tegra210: - vddio-pex-ctl-supply: Power supply for PCIe control I/O partition. Must supply 1.8 V. +Power supplies for Tegra186: +- Required: + - dvdd-pex-supply: Power supply for digital PCIe I/O. Must supply 1.05 V. + - hvdd-pex-pll-supply: High-voltage supply for PLLE (shared with USB3). Must + supply 1.8 V. + - hvdd-pex-supply: High-voltage supply for PCIe I/O and PCIe output clocks. + Must supply 1.8 V. + - vddio-pexctl-aud-supply: Power supply for PCIe side band signals. Must + supply 1.8 V. + Root ports are defined as subnodes of the PCIe controller node. Required properties: @@ -546,3 +561,114 @@ Board DTS: status = "okay"; }; }; + +Tegra186: +--------- + +SoC DTSI: + + pcie@10003000 { + compatible = "nvidia,tegra186-pcie"; + power-domains = <&bpmp TEGRA186_POWER_DOMAIN_PCX>; + device_type = "pci"; + reg = <0x0 0x10003000 0x0 0x00000800 /* PADS registers */ + 0x0 0x10003800 0x0 0x00000800 /* AFI registers */ + 0x0 0x40000000 0x0 0x10000000>; /* configuration space */ + reg-names = "pads", "afi", "cs"; + + interrupts = , /* controller interrupt */ + ; /* MSI interrupt */ + interrupt-names = "intr", "msi"; + + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 0>; + interrupt-map = <0 0 0 0 &gic GIC_SPI 72 IRQ_TYPE_LEVEL_HIGH>; + + bus-range = <0x00 0xff>; + #address-cells = <3>; + #size-cells = <2>; + + ranges = <0x82000000 0 0x10000000 0x0 0x10000000 0 0x00001000 /* port 0 configuration space */ + 0x82000000 0 0x10001000 0x0 0x10001000 0 0x00001000 /* port 1 configuration space */ + 0x82000000 0 0x10004000 0x0 0x10004000 0 0x00001000 /* port 2 configuration space */ + 0x81000000 0 0x0 0x0 0x50000000 0 0x00010000 /* downstream I/O (64 KiB) */ + 0x82000000 0 0x50100000 0x0 0x50100000 0 0x07F00000 /* non-prefetchable memory (127 MiB) */ + 0xc2000000 0 0x58000000 0x0 0x58000000 0 0x28000000>; /* prefetchable memory (640 MiB) */ + + clocks = <&bpmp TEGRA186_CLK_AFI>, + <&bpmp TEGRA186_CLK_PCIE>, + <&bpmp TEGRA186_CLK_PLLE>; + clock-names = "afi", "pex", "pll_e"; + + resets = <&bpmp TEGRA186_RESET_AFI>, + <&bpmp TEGRA186_RESET_PCIE>, + <&bpmp TEGRA186_RESET_PCIEXCLK>; + reset-names = "afi", "pex", "pcie_x"; + + status = "disabled"; + + pci@1,0 { + device_type = "pci"; + assigned-addresses = <0x82000800 0 0x10000000 0 0x1000>; + reg = <0x000800 0 0 0 0>; + status = "disabled"; + + #address-cells = <3>; + #size-cells = <2>; + ranges; + + nvidia,num-lanes = <2>; + }; + + pci@2,0 { + device_type = "pci"; + assigned-addresses = <0x82001000 0 0x10001000 0 0x1000>; + reg = <0x001000 0 0 0 0>; + status = "disabled"; + + #address-cells = <3>; + #size-cells = <2>; + ranges; + + nvidia,num-lanes = <1>; + }; + + pci@3,0 { + device_type = "pci"; + assigned-addresses = <0x82001800 0 0x10004000 0 0x1000>; + reg = <0x001800 0 0 0 0>; + status = "disabled"; + + #address-cells = <3>; + #size-cells = <2>; + ranges; + + nvidia,num-lanes = <1>; + }; + }; + +Board DTS: + + pcie@10003000 { + status = "okay"; + + dvdd-pex-supply = <&vdd_pex>; + hvdd-pex-pll-supply = <&vdd_1v8>; + hvdd-pex-supply = <&vdd_1v8>; + vddio-pexctl-aud-supply = <&vdd_1v8>; + + pci@1,0 { + nvidia,num-lanes = <4>; + status = "okay"; + }; + + pci@2,0 { + nvidia,num-lanes = <0>; + status = "disabled"; + }; + + pci@3,0 { + nvidia,num-lanes = <1>; + status = "disabled"; + }; + }; -- cgit v1.2.3 From 9cea513d8cbc75ee26327d3d8971fe7b58288d8f Mon Sep 17 00:00:00 2001 From: Manikanta Maddireddy Date: Wed, 27 Sep 2017 17:28:35 +0530 Subject: PCI: tegra: Add Tegra186 PCIe support Add Tegra186 PCIe support. UPHY programming is performed by BPMP; PHY enable calls are not required for Tegra186 PCIe. Power partition ungate is done by BPMP powergate driver. The Tegra186 DT description must include a "power-domains" property, which results in dev->pm_domain being set. Tested-by: Mikko Perttunen Tested-by: Thierry Reding Signed-off-by: Manikanta Maddireddy [bhelgaas: add "power-domains" reference] Signed-off-by: Bjorn Helgaas Reviewed-by: Mikko Perttunen Acked-by: Thierry Reding --- drivers/pci/host/pci-tegra.c | 134 +++++++++++++++++++++++++++++++++++-------- 1 file changed, 109 insertions(+), 25 deletions(-) diff --git a/drivers/pci/host/pci-tegra.c b/drivers/pci/host/pci-tegra.c index e8e1ddbaabc9..8dd3b3f7d141 100644 --- a/drivers/pci/host/pci-tegra.c +++ b/drivers/pci/host/pci-tegra.c @@ -159,10 +159,13 @@ #define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_SINGLE (0x0 << 20) #define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_420 (0x0 << 20) #define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_X2_X1 (0x0 << 20) +#define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_401 (0x0 << 20) #define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_DUAL (0x1 << 20) #define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_222 (0x1 << 20) #define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_X4_X1 (0x1 << 20) +#define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_211 (0x1 << 20) #define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_411 (0x2 << 20) +#define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_111 (0x2 << 20) #define AFI_FUSE 0x104 #define AFI_FUSE_PCIE_T0_GEN2_DIS (1 << 2) @@ -252,6 +255,7 @@ struct tegra_pcie_soc { bool has_cml_clk; bool has_gen2; bool force_pca_enable; + bool program_uphy; }; static inline struct tegra_msi *to_tegra_msi(struct msi_controller *chip) @@ -1032,10 +1036,12 @@ static int tegra_pcie_enable_controller(struct tegra_pcie *pcie) afi_writel(pcie, value, AFI_FUSE); } - err = tegra_pcie_phy_power_on(pcie); - if (err < 0) { - dev_err(dev, "failed to power on PHY(s): %d\n", err); - return err; + if (soc->program_uphy) { + err = tegra_pcie_phy_power_on(pcie); + if (err < 0) { + dev_err(dev, "failed to power on PHY(s): %d\n", err); + return err; + } } /* take the PCIe interface module out of reset */ @@ -1068,19 +1074,23 @@ static int tegra_pcie_enable_controller(struct tegra_pcie *pcie) static void tegra_pcie_power_off(struct tegra_pcie *pcie) { struct device *dev = pcie->dev; + const struct tegra_pcie_soc *soc = pcie->soc; int err; /* TODO: disable and unprepare clocks? */ - err = tegra_pcie_phy_power_off(pcie); - if (err < 0) - dev_err(dev, "failed to power off PHY(s): %d\n", err); + if (soc->program_uphy) { + err = tegra_pcie_phy_power_off(pcie); + if (err < 0) + dev_err(dev, "failed to power off PHY(s): %d\n", err); + } reset_control_assert(pcie->pcie_xrst); reset_control_assert(pcie->afi_rst); reset_control_assert(pcie->pex_rst); - tegra_powergate_power_off(TEGRA_POWERGATE_PCIE); + if (!dev->pm_domain) + tegra_powergate_power_off(TEGRA_POWERGATE_PCIE); err = regulator_bulk_disable(pcie->num_supplies, pcie->supplies); if (err < 0) @@ -1097,19 +1107,29 @@ static int tegra_pcie_power_on(struct tegra_pcie *pcie) reset_control_assert(pcie->afi_rst); reset_control_assert(pcie->pex_rst); - tegra_powergate_power_off(TEGRA_POWERGATE_PCIE); + if (!dev->pm_domain) + tegra_powergate_power_off(TEGRA_POWERGATE_PCIE); /* enable regulators */ err = regulator_bulk_enable(pcie->num_supplies, pcie->supplies); if (err < 0) dev_err(dev, "failed to enable regulators: %d\n", err); - err = tegra_powergate_sequence_power_up(TEGRA_POWERGATE_PCIE, - pcie->pex_clk, - pcie->pex_rst); - if (err) { - dev_err(dev, "powerup sequence failed: %d\n", err); - return err; + if (dev->pm_domain) { + err = clk_prepare_enable(pcie->pex_clk); + if (err) { + dev_err(dev, "failed to enable PEX clock: %d\n", err); + return err; + } + reset_control_deassert(pcie->pex_rst); + } else { + err = tegra_powergate_sequence_power_up(TEGRA_POWERGATE_PCIE, + pcie->pex_clk, + pcie->pex_rst); + if (err) { + dev_err(dev, "powerup sequence failed: %d\n", err); + return err; + } } reset_control_deassert(pcie->afi_rst); @@ -1282,6 +1302,7 @@ static int tegra_pcie_get_resources(struct tegra_pcie *pcie) struct device *dev = pcie->dev; struct platform_device *pdev = to_platform_device(dev); struct resource *pads, *afi, *res; + const struct tegra_pcie_soc *soc = pcie->soc; int err; err = tegra_pcie_clocks_get(pcie); @@ -1296,10 +1317,12 @@ static int tegra_pcie_get_resources(struct tegra_pcie *pcie) return err; } - err = tegra_pcie_phys_get(pcie); - if (err < 0) { - dev_err(dev, "failed to get PHYs: %d\n", err); - return err; + if (soc->program_uphy) { + err = tegra_pcie_phys_get(pcie); + if (err < 0) { + dev_err(dev, "failed to get PHYs: %d\n", err); + return err; + } } err = tegra_pcie_power_on(pcie); @@ -1361,6 +1384,7 @@ poweroff: static int tegra_pcie_put_resources(struct tegra_pcie *pcie) { struct device *dev = pcie->dev; + const struct tegra_pcie_soc *soc = pcie->soc; int err; if (pcie->irq > 0) @@ -1368,9 +1392,11 @@ static int tegra_pcie_put_resources(struct tegra_pcie *pcie) tegra_pcie_power_off(pcie); - err = phy_exit(pcie->phy); - if (err < 0) - dev_err(dev, "failed to teardown PHY: %d\n", err); + if (soc->program_uphy) { + err = phy_exit(pcie->phy); + if (err < 0) + dev_err(dev, "failed to teardown PHY: %d\n", err); + } return 0; } @@ -1636,8 +1662,32 @@ static int tegra_pcie_get_xbar_config(struct tegra_pcie *pcie, u32 lanes, struct device *dev = pcie->dev; struct device_node *np = dev->of_node; - if (of_device_is_compatible(np, "nvidia,tegra124-pcie") || - of_device_is_compatible(np, "nvidia,tegra210-pcie")) { + if (of_device_is_compatible(np, "nvidia,tegra186-pcie")) { + switch (lanes) { + case 0x010004: + dev_info(dev, "4x1, 1x1 configuration\n"); + *xbar = AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_401; + return 0; + + case 0x010102: + dev_info(dev, "2x1, 1X1, 1x1 configuration\n"); + *xbar = AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_211; + return 0; + + case 0x010101: + dev_info(dev, "1x1, 1x1, 1x1 configuration\n"); + *xbar = AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_111; + return 0; + + default: + dev_info(dev, "wrong configuration updated in DT, " + "switching to default 2x1, 1x1, 1x1 " + "configuration\n"); + *xbar = AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_211; + return 0; + } + } else if (of_device_is_compatible(np, "nvidia,tegra124-pcie") || + of_device_is_compatible(np, "nvidia,tegra210-pcie")) { switch (lanes) { case 0x0000104: dev_info(dev, "4x1, 1x1 configuration\n"); @@ -1757,7 +1807,20 @@ static int tegra_pcie_get_regulators(struct tegra_pcie *pcie, u32 lane_mask) struct device_node *np = dev->of_node; unsigned int i = 0; - if (of_device_is_compatible(np, "nvidia,tegra210-pcie")) { + if (of_device_is_compatible(np, "nvidia,tegra186-pcie")) { + pcie->num_supplies = 4; + + pcie->supplies = devm_kcalloc(pcie->dev, pcie->num_supplies, + sizeof(*pcie->supplies), + GFP_KERNEL); + if (!pcie->supplies) + return -ENOMEM; + + pcie->supplies[i++].supply = "dvdd-pex"; + pcie->supplies[i++].supply = "hvdd-pex-pll"; + pcie->supplies[i++].supply = "hvdd-pex"; + pcie->supplies[i++].supply = "vddio-pexctl-aud"; + } else if (of_device_is_compatible(np, "nvidia,tegra210-pcie")) { pcie->num_supplies = 6; pcie->supplies = devm_kcalloc(pcie->dev, pcie->num_supplies, @@ -2096,6 +2159,7 @@ static const struct tegra_pcie_soc tegra20_pcie = { .has_cml_clk = false, .has_gen2 = false, .force_pca_enable = false, + .program_uphy = true, }; static const struct tegra_pcie_soc tegra30_pcie = { @@ -2111,6 +2175,7 @@ static const struct tegra_pcie_soc tegra30_pcie = { .has_cml_clk = true, .has_gen2 = false, .force_pca_enable = false, + .program_uphy = true, }; static const struct tegra_pcie_soc tegra124_pcie = { @@ -2125,6 +2190,7 @@ static const struct tegra_pcie_soc tegra124_pcie = { .has_cml_clk = true, .has_gen2 = true, .force_pca_enable = false, + .program_uphy = true, }; static const struct tegra_pcie_soc tegra210_pcie = { @@ -2139,9 +2205,27 @@ static const struct tegra_pcie_soc tegra210_pcie = { .has_cml_clk = true, .has_gen2 = true, .force_pca_enable = true, + .program_uphy = true, +}; + +static const struct tegra_pcie_soc tegra186_pcie = { + .num_ports = 3, + .msi_base_shift = 8, + .pads_pll_ctl = PADS_PLL_CTL_TEGRA30, + .tx_ref_sel = PADS_PLL_CTL_TXCLKREF_BUF_EN, + .pads_refclk_cfg0 = 0x80b880b8, + .pads_refclk_cfg1 = 0x000480b8, + .has_pex_clkreq_en = true, + .has_pex_bias_ctrl = true, + .has_intr_prsnt_sense = true, + .has_cml_clk = false, + .has_gen2 = true, + .force_pca_enable = false, + .program_uphy = false, }; static const struct of_device_id tegra_pcie_of_match[] = { + { .compatible = "nvidia,tegra186-pcie", .data = &tegra186_pcie }, { .compatible = "nvidia,tegra210-pcie", .data = &tegra210_pcie }, { .compatible = "nvidia,tegra124-pcie", .data = &tegra124_pcie }, { .compatible = "nvidia,tegra30-pcie", .data = &tegra30_pcie }, -- cgit v1.2.3