[U-Boot] [PATCH 1/5] pci: tegra: port to standard clock/reset/pwr domain APIs

From: Stephen Warren swarren@nvidia.com
Tegra186 supports the new standard clock, reset, and power domain APIs. Older Tegra SoCs still use custom APIs. Enhance the Tegra PCIe driver so that it can operate with either set of APIs.
On Tegra186, the BPMP handles all aspects of PCIe PHY (UPHY) programming. Consequently, this logic is disabled too.
Signed-off-by: Stephen Warren swarren@nvidia.com --- This whole series builds on the other Tegra186 series that I just sent.
drivers/pci/Kconfig | 1 + drivers/pci/pci_tegra.c | 154 ++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 150 insertions(+), 5 deletions(-)
diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig index 26aa2b0930a0..669e37bb5dc5 100644 --- a/drivers/pci/Kconfig +++ b/drivers/pci/Kconfig @@ -31,6 +31,7 @@ config PCI_SANDBOX config PCI_TEGRA bool "Tegra PCI support" depends on TEGRA + depends on (TEGRA186 && POWER_DOMAIN) || (!TEGRA186) help Enable support for the PCIe controller found on some generations of Tegra. Tegra20 has 2 root ports with a total of 4 lanes, Tegra30 has diff --git a/drivers/pci/pci_tegra.c b/drivers/pci/pci_tegra.c index 352cdef56ab4..a6785ad0bbee 100644 --- a/drivers/pci/pci_tegra.c +++ b/drivers/pci/pci_tegra.c @@ -13,22 +13,26 @@ #define pr_fmt(fmt) "tegra-pcie: " fmt
#include <common.h> +#include <clk.h> #include <dm.h> #include <errno.h> #include <fdtdec.h> #include <malloc.h> #include <pci.h> +#include <power-domain.h> +#include <reset.h>
#include <asm/io.h> #include <asm/gpio.h>
+#include <linux/list.h> + +#ifndef CONFIG_TEGRA186 #include <asm/arch/clock.h> #include <asm/arch/powergate.h> #include <asm/arch-tegra/xusb-padctl.h> - -#include <linux/list.h> - #include <dt-bindings/pinctrl/pinctrl-tegra-xusb.h> +#endif
DECLARE_GLOBAL_DATA_PTR;
@@ -103,6 +107,9 @@ DECLARE_GLOBAL_DATA_PTR; #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_411 (0x2 << 20) +#define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_T186_401 (0x0 << 20) +#define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_T186_211 (0x1 << 20) +#define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_T186_111 (0x2 << 20)
#define AFI_FUSE 0x104 #define AFI_FUSE_PCIE_T0_GEN2_DIS (1 << 2) @@ -110,6 +117,7 @@ DECLARE_GLOBAL_DATA_PTR; #define AFI_PEX0_CTRL 0x110 #define AFI_PEX1_CTRL 0x118 #define AFI_PEX2_CTRL 0x128 +#define AFI_PEX2_CTRL_T186 0x19c #define AFI_PEX_CTRL_RST (1 << 0) #define AFI_PEX_CTRL_CLKREQ_EN (1 << 1) #define AFI_PEX_CTRL_REFCLK_EN (1 << 3) @@ -173,6 +181,7 @@ enum tegra_pci_id { TEGRA30_PCIE, TEGRA124_PCIE, TEGRA210_PCIE, + TEGRA186_PCIE, };
struct tegra_pcie_port { @@ -189,6 +198,7 @@ struct tegra_pcie_soc { unsigned int num_ports; unsigned long pads_pll_ctl; unsigned long tx_ref_sel; + unsigned long afi_pex2_ctrl; u32 pads_refclk_cfg0; u32 pads_refclk_cfg1; bool has_pex_clkreq_en; @@ -209,7 +219,17 @@ struct tegra_pcie { unsigned long xbar;
const struct tegra_pcie_soc *soc; + +#ifdef CONFIG_TEGRA186 + struct clk clk_afi; + struct clk clk_pex; + struct reset_ctl reset_afi; + struct reset_ctl reset_pex; + struct reset_ctl reset_pcie_x; + struct power_domain pwrdom; +#else struct tegra_xusb_phy *phy; +#endif };
static void afi_writel(struct tegra_pcie *pcie, unsigned long value, @@ -229,10 +249,12 @@ static void pads_writel(struct tegra_pcie *pcie, unsigned long value, writel(value, pcie->pads.start + offset); }
+#ifndef CONFIG_TEGRA186 static unsigned long pads_readl(struct tegra_pcie *pcie, unsigned long offset) { return readl(pcie->pads.start + offset); } +#endif
static unsigned long rp_readl(struct tegra_pcie_port *port, unsigned long offset) @@ -400,6 +422,24 @@ static int tegra_pcie_get_xbar_config(const void *fdt, int node, u32 lanes, return 0; } break; + case TEGRA186_PCIE: + switch (lanes) { + case 0x0010004: + debug("x4 x1 configuration\n"); + *xbar = AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_T186_401; + return 0; + + case 0x0010102: + debug("x2 x1 x1 configuration\n"); + *xbar = AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_T186_211; + return 0; + + case 0x0010101: + debug("x1 x1 x1 configuration\n"); + *xbar = AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_T186_111; + return 0; + } + break; default: break; } @@ -471,6 +511,7 @@ static int tegra_pcie_parse_dt(const void *fdt, int node, enum tegra_pci_id id, return err; }
+#ifndef CONFIG_TEGRA186 pcie->phy = tegra_xusb_phy_get(TEGRA_XUSB_PADCTL_PCIE); if (pcie->phy) { err = tegra_xusb_phy_prepare(pcie->phy); @@ -479,6 +520,7 @@ static int tegra_pcie_parse_dt(const void *fdt, int node, enum tegra_pci_id id, return err; } } +#endif
fdt_for_each_subnode(fdt, subnode, node) { unsigned int index = 0, num_lanes = 0; @@ -523,6 +565,44 @@ static int tegra_pcie_parse_dt(const void *fdt, int node, enum tegra_pci_id id, return 0; }
+#ifdef CONFIG_TEGRA186 +static int tegra_pcie_power_on(struct tegra_pcie *pcie) +{ + int ret; + + ret = power_domain_on(&pcie->pwrdom); + if (ret) { + error("power_domain_on() failed: %d\n", ret); + return ret; + } + + ret = clk_enable(&pcie->clk_afi); + if (ret) { + error("clk_enable(afi) failed: %d\n", ret); + return ret; + } + + ret = clk_enable(&pcie->clk_pex); + if (ret) { + error("clk_enable(pex) failed: %d\n", ret); + return ret; + } + + ret = reset_deassert(&pcie->reset_afi); + if (ret) { + error("reset_deassert(afi) failed: %d\n", ret); + return ret; + } + + ret = reset_deassert(&pcie->reset_pex); + if (ret) { + error("reset_deassert(pex) failed: %d\n", ret); + return ret; + } + + return 0; +} +#else static int tegra_pcie_power_on(struct tegra_pcie *pcie) { const struct tegra_pcie_soc *soc = pcie->soc; @@ -639,6 +719,7 @@ static int tegra_pcie_phy_enable(struct tegra_pcie *pcie)
return 0; } +#endif
static int tegra_pcie_enable_controller(struct tegra_pcie *pcie) { @@ -647,7 +728,11 @@ static int tegra_pcie_enable_controller(struct tegra_pcie *pcie) u32 value; int err;
+#ifdef CONFIG_TEGRA186 + { +#else if (pcie->phy) { +#endif value = afi_readl(pcie, AFI_PLLE_CONTROL); value &= ~AFI_PLLE_CONTROL_BYPASS_PADS2PLLE_CONTROL; value |= AFI_PLLE_CONTROL_PADS2PLLE_CONTROL_EN; @@ -675,6 +760,7 @@ static int tegra_pcie_enable_controller(struct tegra_pcie *pcie)
afi_writel(pcie, value, AFI_FUSE);
+#ifndef CONFIG_TEGRA186 if (pcie->phy) err = tegra_xusb_phy_enable(pcie->phy); else @@ -684,9 +770,18 @@ static int tegra_pcie_enable_controller(struct tegra_pcie *pcie) error("failed to power on PHY: %d\n", err); return err; } +#endif
/* take the PCIEXCLK logic out of reset */ +#ifdef CONFIG_TEGRA186 + err = reset_deassert(&pcie->reset_pcie_x); + if (err) { + error("reset_deassert(pcie_x) failed: %d\n", err); + return err; + } +#else reset_set_enable(PERIPH_ID_PCIEXCLK, 0); +#endif
/* finally enable PCIe */ value = afi_readl(pcie, AFI_CONFIGURATION); @@ -787,7 +882,7 @@ static unsigned long tegra_pcie_port_get_pex_ctrl(struct tegra_pcie_port *port) break;
case 2: - ret = AFI_PEX2_CTRL; + ret = port->pcie->soc->afi_pex2_ctrl; break; }
@@ -945,6 +1040,7 @@ static const struct tegra_pcie_soc pci_tegra_soc[] = { .num_ports = 3, .pads_pll_ctl = PADS_PLL_CTL_TEGRA30, .tx_ref_sel = PADS_PLL_CTL_TXCLKREF_BUF_EN, + .afi_pex2_ctrl = AFI_PEX2_CTRL, .pads_refclk_cfg0 = 0xfa5cfa5c, .pads_refclk_cfg1 = 0xfa5cfa5c, .has_pex_clkreq_en = true, @@ -972,7 +1068,16 @@ static const struct tegra_pcie_soc pci_tegra_soc[] = { .has_cml_clk = true, .has_gen2 = true, .force_pca_enable = true, - } + }, + [TEGRA186_PCIE] = { + .num_ports = 3, + .afi_pex2_ctrl = AFI_PEX2_CTRL_T186, + .pads_refclk_cfg0 = 0x80b880b8, + .pads_refclk_cfg1 = 0x000480b8, + .has_pex_clkreq_en = true, + .has_pex_bias_ctrl = true, + .has_gen2 = true, + }, };
static int pci_tegra_ofdata_to_platdata(struct udevice *dev) @@ -996,6 +1101,44 @@ static int pci_tegra_probe(struct udevice *dev) struct tegra_pcie *pcie = dev_get_priv(dev); int err;
+#ifdef CONFIG_TEGRA186 + err = clk_get_by_name(dev, "afi", &pcie->clk_afi); + if (err) { + debug("clk_get_by_name(afi) failed: %d\n", err); + return err; + } + + err = clk_get_by_name(dev, "pex", &pcie->clk_pex); + if (err) { + debug("clk_get_by_name(pex) failed: %d\n", err); + return err; + } + + err = reset_get_by_name(dev, "afi", &pcie->reset_afi); + if (err) { + debug("reset_get_by_name(afi) failed: %d\n", err); + return err; + } + + err = reset_get_by_name(dev, "pex", &pcie->reset_pex); + if (err) { + debug("reset_get_by_name(pex) failed: %d\n", err); + return err; + } + + err = reset_get_by_name(dev, "pcie_x", &pcie->reset_pcie_x); + if (err) { + debug("reset_get_by_name(pcie_x) failed: %d\n", err); + return err; + } + + err = power_domain_get(dev, &pcie->pwrdom); + if (err) { + debug("power_domain_get() failed: %d\n", err); + return err; + } +#endif + err = tegra_pcie_power_on(pcie); if (err < 0) { error("failed to power on"); @@ -1033,6 +1176,7 @@ static const struct udevice_id pci_tegra_ids[] = { { .compatible = "nvidia,tegra30-pcie", .data = TEGRA30_PCIE }, { .compatible = "nvidia,tegra124-pcie", .data = TEGRA124_PCIE }, { .compatible = "nvidia,tegra210-pcie", .data = TEGRA210_PCIE }, + { .compatible = "nvidia,tegra186-pcie", .data = TEGRA186_PCIE }, { } };

From: Stephen Warren swarren@nvidia.com
The Tegra186 PCIe DT content is almost identical to previous chips, except that the:
- There are 3 ports instead of 2. - Some physical addresses have moved. - PHY programming is handled by firmware, so CCPLEX DTs don't need to reference any PHY. - The power domain is explicitly represented in DT. This change is mandatory for Tegra186 since standard power domain APIs are used, and should be made to the DT for older SoCs, although we get away without doing so since U-Boot currently uses custom APIs that hard-code power domain IDs.
Signed-off-by: Stephen Warren swarren@nvidia.com --- arch/arm/dts/tegra186.dtsi | 92 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 92 insertions(+)
diff --git a/arch/arm/dts/tegra186.dtsi b/arch/arm/dts/tegra186.dtsi index 25e1e8dfc035..7f22d644129a 100644 --- a/arch/arm/dts/tegra186.dtsi +++ b/arch/arm/dts/tegra186.dtsi @@ -3,10 +3,12 @@ #include <dt-bindings/gpio/tegra186-gpio.h> #include <dt-bindings/interrupt-controller/arm-gic.h> #include <dt-bindings/mailbox/tegra186-hsp.h> +#include <dt-bindings/power/tegra186-powergate.h> #include <dt-bindings/reset/tegra186-reset.h>
/ { compatible = "nvidia,tegra186"; + interrupt-parent = <&gic>; #address-cells = <2>; #size-cells = <2>;
@@ -58,6 +60,19 @@ status = "disabled"; };
+ gic: interrupt-controller@3881000 { + compatible = "arm,gic-400"; + #interrupt-cells = <3>; + interrupt-controller; + reg = <0x0 0x3881000 0x0 0x1000>, + <0x0 0x3882000 0x0 0x2000>, + <0x0 0x3884000 0x0 0x2000>, + <0x0 0x3886000 0x0 0x2000>; + interrupts = <GIC_PPI 9 + (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>; + interrupt-parent = <&gic>; + }; + hsp: hsp@3c00000 { compatible = "nvidia,tegra186-hsp"; reg = <0x0 0x03c00000 0x0 0xa0000>; @@ -80,6 +95,83 @@ #interrupt-cells = <2>; };
+ pcie-controller@10003000 { + compatible = "nvidia,tegra186-pcie"; + 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 = <GIC_SPI 72 IRQ_TYPE_LEVEL_HIGH>, /* controller interrupt */ + <GIC_SPI 73 IRQ_TYPE_LEVEL_HIGH>, /* MSI interrupt */ + <GIC_SPI 74 IRQ_TYPE_LEVEL_HIGH>; /* Wake interrupt */ + interrupt-names = "intr", "msi", "wake"; + + #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_PCIE>, + <&bpmp TEGRA186_CLK_AFI>; + clock-names = "pex", "afi"; + resets = <&bpmp TEGRA186_RESET_PCIE>, + <&bpmp TEGRA186_RESET_AFI>, + <&bpmp TEGRA186_RESET_PCIEXCLK>; + reset-names = "pex", "afi", "pcie_x"; + power-domains = <&bpmp TEGRA186_POWER_DOMAIN_PCX>; + 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>; + }; + }; + sysram@30000000 { compatible = "nvidia,tegra186-sysram", "mmio-sram"; reg = <0x0 0x30000000 0x0 0x50000>;

On 27 July 2016 at 15:48, Stephen Warren swarren@wwwdotorg.org wrote:
From: Stephen Warren swarren@nvidia.com
The Tegra186 PCIe DT content is almost identical to previous chips, except that the:
- There are 3 ports instead of 2.
- Some physical addresses have moved.
- PHY programming is handled by firmware, so CCPLEX DTs don't need to reference any PHY.
- The power domain is explicitly represented in DT. This change is mandatory for Tegra186 since standard power domain APIs are used, and should be made to the DT for older SoCs, although we get away without doing so since U-Boot currently uses custom APIs that hard-code power domain IDs.
Signed-off-by: Stephen Warren swarren@nvidia.com
arch/arm/dts/tegra186.dtsi | 92 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 92 insertions(+)
Reviewed-by: Simon Glass sjg@chromium.org

From: Bryan Wu pengw@nvidia.com
clk/reset API was tested on T186 platform and previous chip like T210/T124 will still use the old APIs.
Signed-off-by: Bryan Wu pengw@nvidia.com (swarren, simplified some ifdefs, removed indent level inside an ifdef) Signed-off-by: Stephen Warren swarren@nvidia.com Cc: Heiko Schocher hs@denx.de --- drivers/i2c/tegra_i2c.c | 80 ++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 76 insertions(+), 4 deletions(-)
diff --git a/drivers/i2c/tegra_i2c.c b/drivers/i2c/tegra_i2c.c index 2fa07f9c57c4..b8cb24ec87d5 100644 --- a/drivers/i2c/tegra_i2c.c +++ b/drivers/i2c/tegra_i2c.c @@ -12,11 +12,16 @@ #include <fdtdec.h> #include <i2c.h> #include <asm/io.h> +#ifdef CONFIG_TEGRA186 +#include <clk.h> +#include <reset.h> +#else #include <asm/arch/clock.h> #include <asm/arch/funcmux.h> -#include <asm/arch/gpio.h> #include <asm/arch/pinmux.h> #include <asm/arch-tegra/clk_rst.h> +#endif +#include <asm/arch/gpio.h> #include <asm/arch-tegra/tegra_i2c.h>
DECLARE_GLOBAL_DATA_PTR; @@ -30,7 +35,12 @@ enum i2c_type { /* Information about i2c controller */ struct i2c_bus { int id; +#ifdef CONFIG_TEGRA186 + struct reset_ctl reset_ctl; + struct clk clk; +#else enum periph_id periph_id; +#endif int speed; int pinmux_config; struct i2c_control *control; @@ -62,12 +72,41 @@ static void set_packet_mode(struct i2c_bus *i2c_bus) static void i2c_reset_controller(struct i2c_bus *i2c_bus) { /* Reset I2C controller. */ +#ifdef CONFIG_TEGRA186 + reset_assert(&i2c_bus->reset_ctl); + udelay(1); + reset_deassert(&i2c_bus->reset_ctl); + udelay(1); +#else reset_periph(i2c_bus->periph_id, 1); +#endif
/* re-program config register to packet mode */ set_packet_mode(i2c_bus); }
+#ifdef CONFIG_TEGRA186 +static int i2c_init_clock(struct i2c_bus *i2c_bus, unsigned rate) +{ + int ret; + + ret = reset_assert(&i2c_bus->reset_ctl); + if (ret) + return ret; + ret = clk_enable(&i2c_bus->clk); + if (ret) + return ret; + ret = clk_set_rate(&i2c_bus->clk, rate); + if (IS_ERR_VALUE(ret)) + return ret; + ret = reset_deassert(&i2c_bus->reset_ctl); + if (ret) + return ret; + + return 0; +} +#endif + static void i2c_init_controller(struct i2c_bus *i2c_bus) { if (!i2c_bus->speed) @@ -78,8 +117,12 @@ static void i2c_init_controller(struct i2c_bus *i2c_bus) * here, in section 23.3.1, but in fact we seem to need a factor of * 16 to get the right frequency. */ +#ifdef CONFIG_TEGRA186 + i2c_init_clock(i2c_bus, i2c_bus->speed * 2 * 8); +#else clock_start_periph_pll(i2c_bus->periph_id, CLOCK_ID_PERIPH, i2c_bus->speed * 2 * 8); +#endif
if (i2c_bus->type == TYPE_114) { /* @@ -94,12 +137,17 @@ static void i2c_init_controller(struct i2c_bus *i2c_bus) * is running, we hang, and we need it for the new calc. */ int clk_div_stdfst_mode = readl(&i2c_bus->regs->clk_div) >> 16; + unsigned rate = CLK_MULT_STD_FAST_MODE * + (clk_div_stdfst_mode + 1) * i2c_bus->speed * 2; debug("%s: CLK_DIV_STD_FAST_MODE setting = %d\n", __func__, clk_div_stdfst_mode);
+#ifdef CONFIG_TEGRA186 + i2c_init_clock(i2c_bus, rate); +#else clock_start_periph_pll(i2c_bus->periph_id, CLOCK_ID_PERIPH, - CLK_MULT_STD_FAST_MODE * (clk_div_stdfst_mode + 1) * - i2c_bus->speed * 2); + rate); +#endif }
/* Reset I2C controller. */ @@ -112,7 +160,9 @@ static void i2c_init_controller(struct i2c_bus *i2c_bus) setbits_le32(&dvc->ctrl3, DVC_CTRL_REG3_I2C_HW_SW_PROG_MASK); }
+#ifndef CONFIG_TEGRA186 funcmux_select(i2c_bus->periph_id, i2c_bus->pinmux_config); +#endif }
static void send_packet_headers( @@ -333,8 +383,12 @@ static int tegra_i2c_set_bus_speed(struct udevice *dev, unsigned int speed) static int tegra_i2c_probe(struct udevice *dev) { struct i2c_bus *i2c_bus = dev_get_priv(dev); +#ifdef CONFIG_TEGRA186 + int ret; +#else const void *blob = gd->fdt_blob; int node = dev->of_offset; +#endif bool is_dvc;
i2c_bus->id = dev->seq; @@ -345,6 +399,18 @@ static int tegra_i2c_probe(struct udevice *dev) * We don't have a binding for pinmux yet. Leave it out for now. So * far no one needs anything other than the default. */ +#ifdef CONFIG_TEGRA186 + ret = reset_get_by_name(dev, "i2c", &i2c_bus->reset_ctl); + if (ret) { + error("reset_get_by_name() failed: %d\n", ret); + return ret; + } + ret = clk_get_by_name(dev, "i2c", &i2c_bus->clk); + if (ret) { + error("clk_get_by_name() failed: %d\n", ret); + return ret; + } +#else i2c_bus->pinmux_config = FUNCMUX_DEFAULT; i2c_bus->periph_id = clock_decode_periph_id(blob, node);
@@ -359,6 +425,7 @@ static int tegra_i2c_probe(struct udevice *dev) */ if (i2c_bus->periph_id == -1) return -EINVAL; +#endif
is_dvc = dev_get_driver_data(dev) == TYPE_DVC; if (is_dvc) { @@ -370,7 +437,12 @@ static int tegra_i2c_probe(struct udevice *dev) i2c_init_controller(i2c_bus); debug("%s: controller bus %d at %p, periph_id %d, speed %d: ", is_dvc ? "dvc" : "i2c", dev->seq, i2c_bus->regs, - i2c_bus->periph_id, i2c_bus->speed); +#ifndef CONFIG_TEGRA186 + i2c_bus->periph_id, +#else + -1, +#endif + i2c_bus->speed);
return 0; }

Hi Stephen,
On 27 July 2016 at 15:48, Stephen Warren swarren@wwwdotorg.org wrote:
From: Bryan Wu pengw@nvidia.com
clk/reset API was tested on T186 platform and previous chip like T210/T124 will still use the old APIs.
Signed-off-by: Bryan Wu pengw@nvidia.com (swarren, simplified some ifdefs, removed indent level inside an ifdef) Signed-off-by: Stephen Warren swarren@nvidia.com Cc: Heiko Schocher hs@denx.de
drivers/i2c/tegra_i2c.c | 80 ++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 76 insertions(+), 4 deletions(-)
diff --git a/drivers/i2c/tegra_i2c.c b/drivers/i2c/tegra_i2c.c index 2fa07f9c57c4..b8cb24ec87d5 100644 --- a/drivers/i2c/tegra_i2c.c +++ b/drivers/i2c/tegra_i2c.c @@ -12,11 +12,16 @@ #include <fdtdec.h> #include <i2c.h> #include <asm/io.h> +#ifdef CONFIG_TEGRA186 +#include <clk.h> +#include <reset.h> +#else #include <asm/arch/clock.h> #include <asm/arch/funcmux.h> -#include <asm/arch/gpio.h> #include <asm/arch/pinmux.h> #include <asm/arch-tegra/clk_rst.h> +#endif +#include <asm/arch/gpio.h> #include <asm/arch-tegra/tegra_i2c.h>
DECLARE_GLOBAL_DATA_PTR; @@ -30,7 +35,12 @@ enum i2c_type { /* Information about i2c controller */ struct i2c_bus { int id; +#ifdef CONFIG_TEGRA186
struct reset_ctl reset_ctl;
struct clk clk;
+#else enum periph_id periph_id; +#endif
This doesn't seem right - the drivers should be SoC-independent at compile-time.
int speed; int pinmux_config; struct i2c_control *control;
@@ -62,12 +72,41 @@ static void set_packet_mode(struct i2c_bus *i2c_bus) static void i2c_reset_controller(struct i2c_bus *i2c_bus) { /* Reset I2C controller. */ +#ifdef CONFIG_TEGRA186
reset_assert(&i2c_bus->reset_ctl);
udelay(1);
reset_deassert(&i2c_bus->reset_ctl);
udelay(1);
+#else reset_periph(i2c_bus->periph_id, 1); +#endif
/* re-program config register to packet mode */ set_packet_mode(i2c_bus);
}
+#ifdef CONFIG_TEGRA186 +static int i2c_init_clock(struct i2c_bus *i2c_bus, unsigned rate) +{
int ret;
ret = reset_assert(&i2c_bus->reset_ctl);
if (ret)
return ret;
ret = clk_enable(&i2c_bus->clk);
if (ret)
return ret;
ret = clk_set_rate(&i2c_bus->clk, rate);
if (IS_ERR_VALUE(ret))
return ret;
ret = reset_deassert(&i2c_bus->reset_ctl);
if (ret)
return ret;
return 0;
+} +#endif
static void i2c_init_controller(struct i2c_bus *i2c_bus) { if (!i2c_bus->speed) @@ -78,8 +117,12 @@ static void i2c_init_controller(struct i2c_bus *i2c_bus) * here, in section 23.3.1, but in fact we seem to need a factor of * 16 to get the right frequency. */ +#ifdef CONFIG_TEGRA186
i2c_init_clock(i2c_bus, i2c_bus->speed * 2 * 8);
+#else clock_start_periph_pll(i2c_bus->periph_id, CLOCK_ID_PERIPH, i2c_bus->speed * 2 * 8); +#endif
if (i2c_bus->type == TYPE_114) { /*
@@ -94,12 +137,17 @@ static void i2c_init_controller(struct i2c_bus *i2c_bus) * is running, we hang, and we need it for the new calc. */ int clk_div_stdfst_mode = readl(&i2c_bus->regs->clk_div) >> 16;
unsigned rate = CLK_MULT_STD_FAST_MODE *
(clk_div_stdfst_mode + 1) * i2c_bus->speed * 2; debug("%s: CLK_DIV_STD_FAST_MODE setting = %d\n", __func__, clk_div_stdfst_mode);
+#ifdef CONFIG_TEGRA186
i2c_init_clock(i2c_bus, rate);
+#else clock_start_periph_pll(i2c_bus->periph_id, CLOCK_ID_PERIPH,
CLK_MULT_STD_FAST_MODE * (clk_div_stdfst_mode + 1) *
i2c_bus->speed * 2);
rate);
+#endif }
/* Reset I2C controller. */
@@ -112,7 +160,9 @@ static void i2c_init_controller(struct i2c_bus *i2c_bus) setbits_le32(&dvc->ctrl3, DVC_CTRL_REG3_I2C_HW_SW_PROG_MASK); }
+#ifndef CONFIG_TEGRA186 funcmux_select(i2c_bus->periph_id, i2c_bus->pinmux_config); +#endif }
static void send_packet_headers( @@ -333,8 +383,12 @@ static int tegra_i2c_set_bus_speed(struct udevice *dev, unsigned int speed) static int tegra_i2c_probe(struct udevice *dev) { struct i2c_bus *i2c_bus = dev_get_priv(dev); +#ifdef CONFIG_TEGRA186
int ret;
+#else const void *blob = gd->fdt_blob; int node = dev->of_offset; +#endif bool is_dvc;
i2c_bus->id = dev->seq;
@@ -345,6 +399,18 @@ static int tegra_i2c_probe(struct udevice *dev) * We don't have a binding for pinmux yet. Leave it out for now. So * far no one needs anything other than the default. */ +#ifdef CONFIG_TEGRA186
ret = reset_get_by_name(dev, "i2c", &i2c_bus->reset_ctl);
if (ret) {
error("reset_get_by_name() failed: %d\n", ret);
return ret;
}
ret = clk_get_by_name(dev, "i2c", &i2c_bus->clk);
if (ret) {
error("clk_get_by_name() failed: %d\n", ret);
return ret;
}
+#else i2c_bus->pinmux_config = FUNCMUX_DEFAULT; i2c_bus->periph_id = clock_decode_periph_id(blob, node);
@@ -359,6 +425,7 @@ static int tegra_i2c_probe(struct udevice *dev) */ if (i2c_bus->periph_id == -1) return -EINVAL; +#endif
is_dvc = dev_get_driver_data(dev) == TYPE_DVC; if (is_dvc) {
@@ -370,7 +437,12 @@ static int tegra_i2c_probe(struct udevice *dev) i2c_init_controller(i2c_bus); debug("%s: controller bus %d at %p, periph_id %d, speed %d: ", is_dvc ? "dvc" : "i2c", dev->seq, i2c_bus->regs,
i2c_bus->periph_id, i2c_bus->speed);
+#ifndef CONFIG_TEGRA186
i2c_bus->periph_id,
Probably the concept of periph_id can go away now? Perhaps this driver needs a clean-up?
+#else
-1,
+#endif
i2c_bus->speed); return 0;
}
2.9.2
Regards, Simon

On 07/31/2016 07:02 PM, Simon Glass wrote:
Hi Stephen,
On 27 July 2016 at 15:48, Stephen Warren swarren@wwwdotorg.org wrote:
From: Bryan Wu pengw@nvidia.com
clk/reset API was tested on T186 platform and previous chip like T210/T124 will still use the old APIs.
diff --git a/drivers/i2c/tegra_i2c.c b/drivers/i2c/tegra_i2c.c
@@ -30,7 +35,12 @@ enum i2c_type { /* Information about i2c controller */ struct i2c_bus { int id; +#ifdef CONFIG_TEGRA186
struct reset_ctl reset_ctl;
struct clk clk;
+#else enum periph_id periph_id; +#endif
This doesn't seem right - the drivers should be SoC-independent at compile-time.
Same comment as before; there's not yet a common clock/reset API implementation except on the latest SoC.
@@ -370,7 +437,12 @@ static int tegra_i2c_probe(struct udevice *dev) i2c_init_controller(i2c_bus); debug("%s: controller bus %d at %p, periph_id %d, speed %d: ", is_dvc ? "dvc" : "i2c", dev->seq, i2c_bus->regs,
i2c_bus->periph_id, i2c_bus->speed);
+#ifndef CONFIG_TEGRA186
i2c_bus->periph_id,
Probably the concept of periph_id can go away now? Perhaps this driver needs a clean-up?
It's still needed for the legacy APIs on older SoCs.

From: Bryan Wu pengw@nvidia.com
Tegra186 has 8 I2C controllers including BPMP I2C. This patch adds the other 7 generic controllers to Tegra186's DT.
Signed-off-by: Bryan Wu pengw@nvidia.com (swarren, fixed DT node sort order, tweak patch description) Signed-off-by: Stephen Warren swarren@nvidia.com --- arch/arm/dts/tegra186.dtsi | 104 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 104 insertions(+)
diff --git a/arch/arm/dts/tegra186.dtsi b/arch/arm/dts/tegra186.dtsi index 7f22d644129a..0778d2117658 100644 --- a/arch/arm/dts/tegra186.dtsi +++ b/arch/arm/dts/tegra186.dtsi @@ -38,6 +38,84 @@ status = "disabled"; };
+ gen1_i2c: i2c@3160000 { + compatible = "nvidia,tegra186-i2c", "nvidia,tegra114-i2c"; + reg = <0x0 0x3160000 0x0 0x100>; + interrupts = <GIC_SPI 25 IRQ_TYPE_LEVEL_HIGH>; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&bpmp TEGRA186_CLK_I2C1>; + clock-names = "i2c"; + resets = <&bpmp TEGRA186_RESET_I2C1>; + reset-names = "i2c"; + status = "disabled"; + }; + + cam_i2c: i2c@3180000 { + compatible = "nvidia,tegra186-i2c", "nvidia,tegra114-i2c"; + reg = <0x0 0x3180000 0x0 0x100>; + interrupts = <GIC_SPI 27 IRQ_TYPE_LEVEL_HIGH>; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&bpmp TEGRA186_CLK_I2C3>; + clock-names = "i2c"; + resets = <&bpmp TEGRA186_RESET_I2C3>; + reset-names = "i2c"; + status = "disabled"; + }; + + dp_aux_ch1_i2c: i2c@3190000 { + compatible = "nvidia,tegra186-i2c", "nvidia,tegra114-i2c"; + reg = <0x0 0x3190000 0x0 0x100>; + interrupts = <GIC_SPI 28 IRQ_TYPE_LEVEL_HIGH>; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&bpmp TEGRA186_CLK_I2C4>; + clock-names = "i2c"; + resets = <&bpmp TEGRA186_RESET_I2C4>; + reset-names = "i2c"; + status = "disabled"; + }; + + dp_aux_ch0_i2c: i2c@31b0000 { + compatible = "nvidia,tegra186-i2c", "nvidia,tegra114-i2c"; + reg = <0x0 0x31b0000 0x0 0x100>; + interrupts = <GIC_SPI 30 IRQ_TYPE_LEVEL_HIGH>; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&bpmp TEGRA186_CLK_I2C6>; + clock-names = "i2c"; + resets = <&bpmp TEGRA186_RESET_I2C6>; + reset-names = "i2c"; + status = "disabled"; + }; + + gen7_i2c: i2c@31c0000 { + compatible = "nvidia,tegra186-i2c", "nvidia,tegra114-i2c"; + reg = <0x0 0x31c0000 0x0 0x100>; + interrupts = <GIC_SPI 31 IRQ_TYPE_LEVEL_HIGH>; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&bpmp TEGRA186_CLK_I2C7>; + clock-names = "i2c"; + resets = <&bpmp TEGRA186_RESET_I2C7>; + reset-names = "i2c"; + status = "disabled"; + }; + + gen9_i2c: i2c@31e0000 { + compatible = "nvidia,tegra186-i2c", "nvidia,tegra114-i2c"; + reg = <0x0 0x31e0000 0x0 0x100>; + interrupts = <GIC_SPI 33 IRQ_TYPE_LEVEL_HIGH>; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&bpmp TEGRA186_CLK_I2C9>; + clock-names = "i2c"; + resets = <&bpmp TEGRA186_RESET_I2C9>; + reset-names = "i2c"; + status = "disabled"; + }; + sdhci@3400000 { compatible = "nvidia,tegra186-sdhci"; reg = <0x0 0x03400000 0x0 0x200>; @@ -81,6 +159,32 @@ #mbox-cells = <2>; };
+ gen2_i2c: i2c@c240000 { + compatible = "nvidia,tegra186-i2c", "nvidia,tegra114-i2c"; + reg = <0x0 0xc240000 0x0 0x100>; + interrupts = <GIC_SPI 26 IRQ_TYPE_LEVEL_HIGH>; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&bpmp TEGRA186_CLK_I2C2>; + clock-names = "i2c"; + resets = <&bpmp TEGRA186_RESET_I2C2>; + reset-names = "i2c"; + status = "disabled"; + }; + + gen8_i2c: i2c@c250000 { + compatible = "nvidia,tegra186-i2c", "nvidia,tegra114-i2c"; + reg = <0x0 0xc250000 0x0 0x100>; + interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&bpmp TEGRA186_CLK_I2C8>; + clock-names = "i2c"; + resets = <&bpmp TEGRA186_RESET_I2C8>; + reset-names = "i2c"; + status = "disabled"; + }; + gpio_aon: gpio@c2f0000 { compatible = "nvidia,tegra186-gpio-aon"; reg-names = "security", "gpio";

On 27 July 2016 at 15:48, Stephen Warren swarren@wwwdotorg.org wrote:
From: Bryan Wu pengw@nvidia.com
Tegra186 has 8 I2C controllers including BPMP I2C. This patch adds the other 7 generic controllers to Tegra186's DT.
Signed-off-by: Bryan Wu pengw@nvidia.com (swarren, fixed DT node sort order, tweak patch description) Signed-off-by: Stephen Warren swarren@nvidia.com
arch/arm/dts/tegra186.dtsi | 104 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 104 insertions(+)
Reviewed-by: Simon Glass sjg@chromium.org

From: Bryan Wu pengw@nvidia.com
Enable I2C devices in DT and enable building tegra_i2c.c driver.
Signed-off-by: Bryan Wu pengw@nvidia.com (swarren, commit msg rework, fixed DT node sort order) Signed-off-by: Stephen Warren swarren@nvidia.com --- arch/arm/dts/tegra186-p2771-0000.dtsi | 35 +++++++++++++++++++++++++++++++++++ include/configs/p2771-0000.h | 3 +++ 2 files changed, 38 insertions(+)
diff --git a/arch/arm/dts/tegra186-p2771-0000.dtsi b/arch/arm/dts/tegra186-p2771-0000.dtsi index 87f0427e80c1..4e2b6fbf97f8 100644 --- a/arch/arm/dts/tegra186-p2771-0000.dtsi +++ b/arch/arm/dts/tegra186-p2771-0000.dtsi @@ -10,14 +10,49 @@
aliases { sdhci0 = "/sdhci@3460000"; + i2c1 = "/i2c@3160000"; + i2c2 = "/i2c@c240000"; + i2c3 = "/i2c@3180000"; + i2c4 = "/i2c@3190000"; + i2c5 = "/i2c@31c0000"; + i2c6 = "/i2c@c250000"; + i2c7 = "/i2c@31e0000"; };
memory { reg = <0x0 0x80000000 0x0 0x60000000>; };
+ i2c@3160000 { + status = "okay"; + }; + + i2c@3180000 { + status = "okay"; + }; + + i2c@3190000 { + status = "okay"; + }; + + i2c@31c0000 { + status = "okay"; + }; + sdhci@3460000 { status = "okay"; bus-width = <8>; }; + + i2c@c240000 { + status = "okay"; + }; + + i2c@c250000 { + status = "okay"; + }; + + i2c@31e0000 { + status = "okay"; + }; }; diff --git a/include/configs/p2771-0000.h b/include/configs/p2771-0000.h index 257283f3b937..3ce72086ce9c 100644 --- a/include/configs/p2771-0000.h +++ b/include/configs/p2771-0000.h @@ -14,6 +14,9 @@ /* High-level configuration options */ #define CONFIG_TEGRA_BOARD_STRING "NVIDIA P2771-0000"
+/* I2C */ +#define CONFIG_SYS_I2C_TEGRA + /* SD/MMC */ #define CONFIG_MMC #define CONFIG_GENERIC_MMC

On 27 July 2016 at 15:48, Stephen Warren swarren@wwwdotorg.org wrote:
From: Bryan Wu pengw@nvidia.com
Enable I2C devices in DT and enable building tegra_i2c.c driver.
Signed-off-by: Bryan Wu pengw@nvidia.com (swarren, commit msg rework, fixed DT node sort order) Signed-off-by: Stephen Warren swarren@nvidia.com
arch/arm/dts/tegra186-p2771-0000.dtsi | 35 +++++++++++++++++++++++++++++++++++ include/configs/p2771-0000.h | 3 +++ 2 files changed, 38 insertions(+)
Reviewed-by: Simon Glass sjg@chromium.org

Hi Stephen,
On 27 July 2016 at 15:48, Stephen Warren swarren@wwwdotorg.org wrote:
From: Stephen Warren swarren@nvidia.com
Tegra186 supports the new standard clock, reset, and power domain APIs. Older Tegra SoCs still use custom APIs. Enhance the Tegra PCIe driver so that it can operate with either set of APIs.
On Tegra186, the BPMP handles all aspects of PCIe PHY (UPHY) programming. Consequently, this logic is disabled too.
Signed-off-by: Stephen Warren swarren@nvidia.com
This whole series builds on the other Tegra186 series that I just sent.
drivers/pci/Kconfig | 1 + drivers/pci/pci_tegra.c | 154 ++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 150 insertions(+), 5 deletions(-)
diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig index 26aa2b0930a0..669e37bb5dc5 100644 --- a/drivers/pci/Kconfig +++ b/drivers/pci/Kconfig @@ -31,6 +31,7 @@ config PCI_SANDBOX config PCI_TEGRA bool "Tegra PCI support" depends on TEGRA
depends on (TEGRA186 && POWER_DOMAIN) || (!TEGRA186) help Enable support for the PCIe controller found on some generations of Tegra. Tegra20 has 2 root ports with a total of 4 lanes, Tegra30 has
diff --git a/drivers/pci/pci_tegra.c b/drivers/pci/pci_tegra.c index 352cdef56ab4..a6785ad0bbee 100644 --- a/drivers/pci/pci_tegra.c +++ b/drivers/pci/pci_tegra.c @@ -13,22 +13,26 @@ #define pr_fmt(fmt) "tegra-pcie: " fmt
#include <common.h> +#include <clk.h> #include <dm.h> #include <errno.h> #include <fdtdec.h> #include <malloc.h> #include <pci.h> +#include <power-domain.h> +#include <reset.h>
#include <asm/io.h> #include <asm/gpio.h>
+#include <linux/list.h>
+#ifndef CONFIG_TEGRA186 #include <asm/arch/clock.h> #include <asm/arch/powergate.h> #include <asm/arch-tegra/xusb-padctl.h>
-#include <linux/list.h>
#include <dt-bindings/pinctrl/pinctrl-tegra-xusb.h> +#endif
DECLARE_GLOBAL_DATA_PTR;
@@ -103,6 +107,9 @@ DECLARE_GLOBAL_DATA_PTR; #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_411 (0x2 << 20) +#define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_T186_401 (0x0 << 20) +#define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_T186_211 (0x1 << 20) +#define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_T186_111 (0x2 << 20)
#define AFI_FUSE 0x104 #define AFI_FUSE_PCIE_T0_GEN2_DIS (1 << 2) @@ -110,6 +117,7 @@ DECLARE_GLOBAL_DATA_PTR; #define AFI_PEX0_CTRL 0x110 #define AFI_PEX1_CTRL 0x118 #define AFI_PEX2_CTRL 0x128 +#define AFI_PEX2_CTRL_T186 0x19c #define AFI_PEX_CTRL_RST (1 << 0) #define AFI_PEX_CTRL_CLKREQ_EN (1 << 1) #define AFI_PEX_CTRL_REFCLK_EN (1 << 3) @@ -173,6 +181,7 @@ enum tegra_pci_id { TEGRA30_PCIE, TEGRA124_PCIE, TEGRA210_PCIE,
TEGRA186_PCIE,
};
struct tegra_pcie_port { @@ -189,6 +198,7 @@ struct tegra_pcie_soc { unsigned int num_ports; unsigned long pads_pll_ctl; unsigned long tx_ref_sel;
unsigned long afi_pex2_ctrl; u32 pads_refclk_cfg0; u32 pads_refclk_cfg1; bool has_pex_clkreq_en;
@@ -209,7 +219,17 @@ struct tegra_pcie { unsigned long xbar;
const struct tegra_pcie_soc *soc;
+#ifdef CONFIG_TEGRA186
struct clk clk_afi;
struct clk clk_pex;
struct reset_ctl reset_afi;
struct reset_ctl reset_pex;
struct reset_ctl reset_pcie_x;
struct power_domain pwrdom;
+#else
Eek. This is a compile-time driver configuration. Can you use the device tree compatible string to detect which to use?
[...]
Regards, Simon

On 07/31/2016 07:02 PM, Simon Glass wrote:
Hi Stephen,
On 27 July 2016 at 15:48, Stephen Warren swarren@wwwdotorg.org wrote:
From: Stephen Warren swarren@nvidia.com
Tegra186 supports the new standard clock, reset, and power domain APIs. Older Tegra SoCs still use custom APIs. Enhance the Tegra PCIe driver so that it can operate with either set of APIs.
On Tegra186, the BPMP handles all aspects of PCIe PHY (UPHY) programming. Consequently, this logic is disabled too.
Signed-off-by: Stephen Warren swarren@nvidia.com
This whole series builds on the other Tegra186 series that I just sent.
drivers/pci/Kconfig | 1 + drivers/pci/pci_tegra.c | 154 ++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 150 insertions(+), 5 deletions(-)
diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig index 26aa2b0930a0..669e37bb5dc5 100644 --- a/drivers/pci/Kconfig +++ b/drivers/pci/Kconfig @@ -31,6 +31,7 @@ config PCI_SANDBOX config PCI_TEGRA bool "Tegra PCI support" depends on TEGRA
depends on (TEGRA186 && POWER_DOMAIN) || (!TEGRA186) help Enable support for the PCIe controller found on some generations of Tegra. Tegra20 has 2 root ports with a total of 4 lanes, Tegra30 has
diff --git a/drivers/pci/pci_tegra.c b/drivers/pci/pci_tegra.c index 352cdef56ab4..a6785ad0bbee 100644 --- a/drivers/pci/pci_tegra.c +++ b/drivers/pci/pci_tegra.c @@ -13,22 +13,26 @@ #define pr_fmt(fmt) "tegra-pcie: " fmt
#include <common.h> +#include <clk.h> #include <dm.h> #include <errno.h> #include <fdtdec.h> #include <malloc.h> #include <pci.h> +#include <power-domain.h> +#include <reset.h>
#include <asm/io.h> #include <asm/gpio.h>
+#include <linux/list.h>
+#ifndef CONFIG_TEGRA186 #include <asm/arch/clock.h> #include <asm/arch/powergate.h> #include <asm/arch-tegra/xusb-padctl.h>
-#include <linux/list.h>
#include <dt-bindings/pinctrl/pinctrl-tegra-xusb.h> +#endif
DECLARE_GLOBAL_DATA_PTR;
@@ -103,6 +107,9 @@ DECLARE_GLOBAL_DATA_PTR; #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_411 (0x2 << 20) +#define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_T186_401 (0x0 << 20) +#define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_T186_211 (0x1 << 20) +#define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_T186_111 (0x2 << 20)
#define AFI_FUSE 0x104 #define AFI_FUSE_PCIE_T0_GEN2_DIS (1 << 2) @@ -110,6 +117,7 @@ DECLARE_GLOBAL_DATA_PTR; #define AFI_PEX0_CTRL 0x110 #define AFI_PEX1_CTRL 0x118 #define AFI_PEX2_CTRL 0x128 +#define AFI_PEX2_CTRL_T186 0x19c #define AFI_PEX_CTRL_RST (1 << 0) #define AFI_PEX_CTRL_CLKREQ_EN (1 << 1) #define AFI_PEX_CTRL_REFCLK_EN (1 << 3) @@ -173,6 +181,7 @@ enum tegra_pci_id { TEGRA30_PCIE, TEGRA124_PCIE, TEGRA210_PCIE,
TEGRA186_PCIE,
};
struct tegra_pcie_port { @@ -189,6 +198,7 @@ struct tegra_pcie_soc { unsigned int num_ports; unsigned long pads_pll_ctl; unsigned long tx_ref_sel;
unsigned long afi_pex2_ctrl; u32 pads_refclk_cfg0; u32 pads_refclk_cfg1; bool has_pex_clkreq_en;
@@ -209,7 +219,17 @@ struct tegra_pcie { unsigned long xbar;
const struct tegra_pcie_soc *soc;
+#ifdef CONFIG_TEGRA186
struct clk clk_afi;
struct clk clk_pex;
struct reset_ctl reset_afi;
struct reset_ctl reset_pex;
struct reset_ctl reset_pcie_x;
struct power_domain pwrdom;
+#else
Eek. This is a compile-time driver configuration. Can you use the device tree compatible string to detect which to use?
No. The legacy APIs are simply not available (not compiled in) on the newer SoCs, so there must be a compile-time condition.
It is theoretically possible to convert all the old SoCs to the new APIs so that this conditional goes away in the future, but we don't have that work scheduled at present.

Hi Stephen,
On 1 August 2016 at 09:22, Stephen Warren swarren@wwwdotorg.org wrote:
On 07/31/2016 07:02 PM, Simon Glass wrote:
Hi Stephen,
On 27 July 2016 at 15:48, Stephen Warren swarren@wwwdotorg.org wrote:
From: Stephen Warren swarren@nvidia.com
Tegra186 supports the new standard clock, reset, and power domain APIs. Older Tegra SoCs still use custom APIs. Enhance the Tegra PCIe driver so that it can operate with either set of APIs.
On Tegra186, the BPMP handles all aspects of PCIe PHY (UPHY) programming. Consequently, this logic is disabled too.
Signed-off-by: Stephen Warren swarren@nvidia.com
This whole series builds on the other Tegra186 series that I just sent.
drivers/pci/Kconfig | 1 + drivers/pci/pci_tegra.c | 154 ++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 150 insertions(+), 5 deletions(-)
diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig index 26aa2b0930a0..669e37bb5dc5 100644 --- a/drivers/pci/Kconfig +++ b/drivers/pci/Kconfig @@ -31,6 +31,7 @@ config PCI_SANDBOX config PCI_TEGRA bool "Tegra PCI support" depends on TEGRA
depends on (TEGRA186 && POWER_DOMAIN) || (!TEGRA186) help Enable support for the PCIe controller found on some
generations of Tegra. Tegra20 has 2 root ports with a total of 4 lanes, Tegra30 has diff --git a/drivers/pci/pci_tegra.c b/drivers/pci/pci_tegra.c index 352cdef56ab4..a6785ad0bbee 100644 --- a/drivers/pci/pci_tegra.c +++ b/drivers/pci/pci_tegra.c @@ -13,22 +13,26 @@ #define pr_fmt(fmt) "tegra-pcie: " fmt
#include <common.h> +#include <clk.h> #include <dm.h> #include <errno.h> #include <fdtdec.h> #include <malloc.h> #include <pci.h> +#include <power-domain.h> +#include <reset.h>
#include <asm/io.h> #include <asm/gpio.h>
+#include <linux/list.h>
+#ifndef CONFIG_TEGRA186 #include <asm/arch/clock.h> #include <asm/arch/powergate.h> #include <asm/arch-tegra/xusb-padctl.h>
-#include <linux/list.h>
#include <dt-bindings/pinctrl/pinctrl-tegra-xusb.h> +#endif
DECLARE_GLOBAL_DATA_PTR;
@@ -103,6 +107,9 @@ DECLARE_GLOBAL_DATA_PTR; #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_411 (0x2 << 20) +#define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_T186_401 (0x0 << 20) +#define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_T186_211 (0x1 << 20) +#define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_T186_111 (0x2 << 20)
#define AFI_FUSE 0x104 #define AFI_FUSE_PCIE_T0_GEN2_DIS (1 << 2) @@ -110,6 +117,7 @@ DECLARE_GLOBAL_DATA_PTR; #define AFI_PEX0_CTRL 0x110 #define AFI_PEX1_CTRL 0x118 #define AFI_PEX2_CTRL 0x128 +#define AFI_PEX2_CTRL_T186 0x19c #define AFI_PEX_CTRL_RST (1 << 0) #define AFI_PEX_CTRL_CLKREQ_EN (1 << 1) #define AFI_PEX_CTRL_REFCLK_EN (1 << 3) @@ -173,6 +181,7 @@ enum tegra_pci_id { TEGRA30_PCIE, TEGRA124_PCIE, TEGRA210_PCIE,
TEGRA186_PCIE,
};
struct tegra_pcie_port { @@ -189,6 +198,7 @@ struct tegra_pcie_soc { unsigned int num_ports; unsigned long pads_pll_ctl; unsigned long tx_ref_sel;
unsigned long afi_pex2_ctrl; u32 pads_refclk_cfg0; u32 pads_refclk_cfg1; bool has_pex_clkreq_en;
@@ -209,7 +219,17 @@ struct tegra_pcie { unsigned long xbar;
const struct tegra_pcie_soc *soc;
+#ifdef CONFIG_TEGRA186
struct clk clk_afi;
struct clk clk_pex;
struct reset_ctl reset_afi;
struct reset_ctl reset_pex;
struct reset_ctl reset_pcie_x;
struct power_domain pwrdom;
+#else
Eek. This is a compile-time driver configuration. Can you use the device tree compatible string to detect which to use?
No. The legacy APIs are simply not available (not compiled in) on the newer SoCs, so there must be a compile-time condition.
It is theoretically possible to convert all the old SoCs to the new APIs so that this conditional goes away in the future, but we don't have that work scheduled at present.
What did you do with Linux?
Regards, Simon

On 08/03/2016 07:16 PM, Simon Glass wrote:
Hi Stephen,
On 1 August 2016 at 09:22, Stephen Warren swarren@wwwdotorg.org wrote:
On 07/31/2016 07:02 PM, Simon Glass wrote:
Hi Stephen,
On 27 July 2016 at 15:48, Stephen Warren swarren@wwwdotorg.org wrote:
From: Stephen Warren swarren@nvidia.com
Tegra186 supports the new standard clock, reset, and power domain APIs. Older Tegra SoCs still use custom APIs. Enhance the Tegra PCIe driver so that it can operate with either set of APIs.
On Tegra186, the BPMP handles all aspects of PCIe PHY (UPHY) programming. Consequently, this logic is disabled too.
Signed-off-by: Stephen Warren swarren@nvidia.com
This whole series builds on the other Tegra186 series that I just sent.
drivers/pci/Kconfig | 1 + drivers/pci/pci_tegra.c | 154 ++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 150 insertions(+), 5 deletions(-)
diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig index 26aa2b0930a0..669e37bb5dc5 100644 --- a/drivers/pci/Kconfig +++ b/drivers/pci/Kconfig @@ -31,6 +31,7 @@ config PCI_SANDBOX config PCI_TEGRA bool "Tegra PCI support" depends on TEGRA
depends on (TEGRA186 && POWER_DOMAIN) || (!TEGRA186) help Enable support for the PCIe controller found on some
generations of Tegra. Tegra20 has 2 root ports with a total of 4 lanes, Tegra30 has diff --git a/drivers/pci/pci_tegra.c b/drivers/pci/pci_tegra.c index 352cdef56ab4..a6785ad0bbee 100644 --- a/drivers/pci/pci_tegra.c +++ b/drivers/pci/pci_tegra.c @@ -13,22 +13,26 @@ #define pr_fmt(fmt) "tegra-pcie: " fmt
#include <common.h> +#include <clk.h> #include <dm.h> #include <errno.h> #include <fdtdec.h> #include <malloc.h> #include <pci.h> +#include <power-domain.h> +#include <reset.h>
#include <asm/io.h> #include <asm/gpio.h>
+#include <linux/list.h>
+#ifndef CONFIG_TEGRA186 #include <asm/arch/clock.h> #include <asm/arch/powergate.h> #include <asm/arch-tegra/xusb-padctl.h>
-#include <linux/list.h>
#include <dt-bindings/pinctrl/pinctrl-tegra-xusb.h> +#endif
DECLARE_GLOBAL_DATA_PTR;
@@ -103,6 +107,9 @@ DECLARE_GLOBAL_DATA_PTR; #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_411 (0x2 << 20) +#define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_T186_401 (0x0 << 20) +#define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_T186_211 (0x1 << 20) +#define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_T186_111 (0x2 << 20)
#define AFI_FUSE 0x104 #define AFI_FUSE_PCIE_T0_GEN2_DIS (1 << 2) @@ -110,6 +117,7 @@ DECLARE_GLOBAL_DATA_PTR; #define AFI_PEX0_CTRL 0x110 #define AFI_PEX1_CTRL 0x118 #define AFI_PEX2_CTRL 0x128 +#define AFI_PEX2_CTRL_T186 0x19c #define AFI_PEX_CTRL_RST (1 << 0) #define AFI_PEX_CTRL_CLKREQ_EN (1 << 1) #define AFI_PEX_CTRL_REFCLK_EN (1 << 3) @@ -173,6 +181,7 @@ enum tegra_pci_id { TEGRA30_PCIE, TEGRA124_PCIE, TEGRA210_PCIE,
TEGRA186_PCIE,
};
struct tegra_pcie_port { @@ -189,6 +198,7 @@ struct tegra_pcie_soc { unsigned int num_ports; unsigned long pads_pll_ctl; unsigned long tx_ref_sel;
unsigned long afi_pex2_ctrl; u32 pads_refclk_cfg0; u32 pads_refclk_cfg1; bool has_pex_clkreq_en;
@@ -209,7 +219,17 @@ struct tegra_pcie { unsigned long xbar;
const struct tegra_pcie_soc *soc;
+#ifdef CONFIG_TEGRA186
struct clk clk_afi;
struct clk clk_pex;
struct reset_ctl reset_afi;
struct reset_ctl reset_pex;
struct reset_ctl reset_pcie_x;
struct power_domain pwrdom;
+#else
Eek. This is a compile-time driver configuration. Can you use the device tree compatible string to detect which to use?
No. The legacy APIs are simply not available (not compiled in) on the newer SoCs, so there must be a compile-time condition.
It is theoretically possible to convert all the old SoCs to the new APIs so that this conditional goes away in the future, but we don't have that work scheduled at present.
What did you do with Linux?
We lucked out and life was a bit simpler:
When we started adding Tegra support, there was already a standard clock API header, albeit with an entirely separate implementation for each SoC. When the common clock framework/core appeared, it maintained this same API so drivers weren't affected, except for a change in a #include filename.
As far as converting the clock driver from a standalone/custom implementation to being based on the common clock framework/core, life was much easier. At that time, we only supported 2 Tegra SoC generations and many fewer boards and drivers, and so significantly less testing was required for the converted implementation. Many SoC generations, board, and drivers were only written once the new clock implementation was in place, so never needed conversion.
Tegra started out with a completely custom reset API and implementation. When Tegra converted from its custom standalone clock implementation to the common clock framework/core, that same API was re-implemented using the new clock code (as you know, clocks and resets on Tegra are very closely tied), and so there was no effect on drivers.
Later, we converted to the new reset API/framework/core. At this point, we did support 4 SoC generations and many more boards. However, IIRC during this time, there was a huge focus on converting to standard APIs, and a lull in new SoC and board support, so there was time to spend on large-scale conversions; they didn't take time away from other work required to support new SoCs/boards. This conversion implemented the new standard reset for all SoCs first, converted all drivers to use the new API roughly at once, and then removed the old API.
So we got away without ifdefs.
In U-Boot, we now support many more SoCs, boards, and perhaps even drivers, so a "convert everything at once" approach is quite a lot more work than it was in the kernel, especially on the clock/reset driver implementation side. Equally, to be honest, my primary focus is currently on adding Tegra186 support at the moment. Given we needed a completely new clock/reset/... implementation anyway due to the existence of the BPMP, it was a no-brainer to create and/or use the new standard clock/reset/... APIs for Tegra186, rather than basing the new implementation on the old custom APIs. However, converting all the other SoCs/boards first is just going to delay any forward progress on Tegra186 and lead to a mega series of code conversions that I'd rather avoid doing all at once. Adding these ifdefs, allows incremental forward progress to be made pretty easily. They should be removed when older SoC generations are converted to the new APIs, so everything is unified again. Granted, I have no definite timescale for that at present.

Hi Stephen,
On 4 August 2016 at 12:52, Stephen Warren swarren@wwwdotorg.org wrote:
On 08/03/2016 07:16 PM, Simon Glass wrote:
Hi Stephen,
On 1 August 2016 at 09:22, Stephen Warren swarren@wwwdotorg.org wrote:
On 07/31/2016 07:02 PM, Simon Glass wrote:
Hi Stephen,
On 27 July 2016 at 15:48, Stephen Warren swarren@wwwdotorg.org wrote:
From: Stephen Warren swarren@nvidia.com
Tegra186 supports the new standard clock, reset, and power domain APIs. Older Tegra SoCs still use custom APIs. Enhance the Tegra PCIe driver so that it can operate with either set of APIs.
On Tegra186, the BPMP handles all aspects of PCIe PHY (UPHY) programming. Consequently, this logic is disabled too.
Signed-off-by: Stephen Warren swarren@nvidia.com
This whole series builds on the other Tegra186 series that I just sent.
drivers/pci/Kconfig | 1 + drivers/pci/pci_tegra.c | 154 ++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 150 insertions(+), 5 deletions(-)
diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig index 26aa2b0930a0..669e37bb5dc5 100644 --- a/drivers/pci/Kconfig +++ b/drivers/pci/Kconfig @@ -31,6 +31,7 @@ config PCI_SANDBOX config PCI_TEGRA bool "Tegra PCI support" depends on TEGRA
depends on (TEGRA186 && POWER_DOMAIN) || (!TEGRA186) help Enable support for the PCIe controller found on some
generations of Tegra. Tegra20 has 2 root ports with a total of 4 lanes, Tegra30 has diff --git a/drivers/pci/pci_tegra.c b/drivers/pci/pci_tegra.c index 352cdef56ab4..a6785ad0bbee 100644 --- a/drivers/pci/pci_tegra.c +++ b/drivers/pci/pci_tegra.c @@ -13,22 +13,26 @@ #define pr_fmt(fmt) "tegra-pcie: " fmt
#include <common.h> +#include <clk.h> #include <dm.h> #include <errno.h> #include <fdtdec.h> #include <malloc.h> #include <pci.h> +#include <power-domain.h> +#include <reset.h>
#include <asm/io.h> #include <asm/gpio.h>
+#include <linux/list.h>
+#ifndef CONFIG_TEGRA186 #include <asm/arch/clock.h> #include <asm/arch/powergate.h> #include <asm/arch-tegra/xusb-padctl.h>
-#include <linux/list.h>
#include <dt-bindings/pinctrl/pinctrl-tegra-xusb.h> +#endif
DECLARE_GLOBAL_DATA_PTR;
@@ -103,6 +107,9 @@ DECLARE_GLOBAL_DATA_PTR; #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_411 (0x2 << 20) +#define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_T186_401 (0x0 << 20) +#define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_T186_211 (0x1 << 20) +#define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_T186_111 (0x2 << 20)
#define AFI_FUSE 0x104 #define AFI_FUSE_PCIE_T0_GEN2_DIS (1 << 2) @@ -110,6 +117,7 @@ DECLARE_GLOBAL_DATA_PTR; #define AFI_PEX0_CTRL 0x110 #define AFI_PEX1_CTRL 0x118 #define AFI_PEX2_CTRL 0x128 +#define AFI_PEX2_CTRL_T186 0x19c #define AFI_PEX_CTRL_RST (1 << 0) #define AFI_PEX_CTRL_CLKREQ_EN (1 << 1) #define AFI_PEX_CTRL_REFCLK_EN (1 << 3) @@ -173,6 +181,7 @@ enum tegra_pci_id { TEGRA30_PCIE, TEGRA124_PCIE, TEGRA210_PCIE,
TEGRA186_PCIE,
};
struct tegra_pcie_port { @@ -189,6 +198,7 @@ struct tegra_pcie_soc { unsigned int num_ports; unsigned long pads_pll_ctl; unsigned long tx_ref_sel;
unsigned long afi_pex2_ctrl; u32 pads_refclk_cfg0; u32 pads_refclk_cfg1; bool has_pex_clkreq_en;
@@ -209,7 +219,17 @@ struct tegra_pcie { unsigned long xbar;
const struct tegra_pcie_soc *soc;
+#ifdef CONFIG_TEGRA186
struct clk clk_afi;
struct clk clk_pex;
struct reset_ctl reset_afi;
struct reset_ctl reset_pex;
struct reset_ctl reset_pcie_x;
struct power_domain pwrdom;
+#else
Eek. This is a compile-time driver configuration. Can you use the device tree compatible string to detect which to use?
No. The legacy APIs are simply not available (not compiled in) on the newer SoCs, so there must be a compile-time condition.
It is theoretically possible to convert all the old SoCs to the new APIs so that this conditional goes away in the future, but we don't have that work scheduled at present.
What did you do with Linux?
We lucked out and life was a bit simpler:
When we started adding Tegra support, there was already a standard clock API header, albeit with an entirely separate implementation for each SoC. When the common clock framework/core appeared, it maintained this same API so drivers weren't affected, except for a change in a #include filename.
As far as converting the clock driver from a standalone/custom implementation to being based on the common clock framework/core, life was much easier. At that time, we only supported 2 Tegra SoC generations and many fewer boards and drivers, and so significantly less testing was required for the converted implementation. Many SoC generations, board, and drivers were only written once the new clock implementation was in place, so never needed conversion.
Tegra started out with a completely custom reset API and implementation. When Tegra converted from its custom standalone clock implementation to the common clock framework/core, that same API was re-implemented using the new clock code (as you know, clocks and resets on Tegra are very closely tied), and so there was no effect on drivers.
Later, we converted to the new reset API/framework/core. At this point, we did support 4 SoC generations and many more boards. However, IIRC during this time, there was a huge focus on converting to standard APIs, and a lull in new SoC and board support, so there was time to spend on large-scale conversions; they didn't take time away from other work required to support new SoCs/boards. This conversion implemented the new standard reset for all SoCs first, converted all drivers to use the new API roughly at once, and then removed the old API.
So we got away without ifdefs.
In U-Boot, we now support many more SoCs, boards, and perhaps even drivers, so a "convert everything at once" approach is quite a lot more work than it was in the kernel, especially on the clock/reset driver implementation side. Equally, to be honest, my primary focus is currently on adding Tegra186 support at the moment. Given we needed a completely new clock/reset/... implementation anyway due to the existence of the BPMP, it was a no-brainer to create and/or use the new standard clock/reset/... APIs for Tegra186, rather than basing the new implementation on the old custom APIs. However, converting all the other SoCs/boards first is just going to delay any forward progress on Tegra186 and lead to a mega series of code conversions that I'd rather avoid doing all at once. Adding these ifdefs, allows incremental forward progress to be made pretty easily. They should be removed when older SoC generations are converted to the new APIs, so everything is unified again. Granted, I have no definite timescale for that at present.
OK, well I'd like to see some TODOs in the code around these #ifdefs. They are definitely not what we want, and should be marked as interim. Please see if you can find someone to convert things over. I can perhaps help too.
Regards, Simon
participants (2)
-
Simon Glass
-
Stephen Warren