From f18f42d7497dbbde3ff314d0ad585b827ea74e48 Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Tue, 31 Jul 2018 12:21:49 +0200 Subject: PCI: imx6: Support MPLL reconfiguration for 100MHz and 200MHz refclock The power up defaults of the MPLL are designed for the standard 125MHz refclock derived from the ENET PLL. As this clock has a jitter that violates the PCIe Gen2 timing requirements, some board designs use an external reference clock generator. Those clock generators may output a clock at a different rate than what the MPLL expects (usually a 100MHz clock, to re-use the PCIe bus clock). In that case the MPLL must be reconfigured via overrides to use different refclock dividers and loop multipliers. The i.MX6 reference manual lists both 100MHz and 200MHz as supported refclock rates and the associated mult and div values. Only the 100MHz setup has been tested on a real board, but since the 200MHz setup only differs in the used pre-divider it seems safe to add it now. Signed-off-by: Lucas Stach Signed-off-by: Lorenzo Pieralisi Reviewed-by: Richard Zhu --- drivers/pci/controller/dwc/pci-imx6.c | 55 +++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c index 4a9a673b4777..21e03c6567da 100644 --- a/drivers/pci/controller/dwc/pci-imx6.c +++ b/drivers/pci/controller/dwc/pci-imx6.c @@ -97,6 +97,16 @@ struct imx6_pcie { #define PORT_LOGIC_SPEED_CHANGE (0x1 << 17) /* PHY registers (not memory-mapped) */ +#define PCIE_PHY_ATEOVRD 0x10 +#define PCIE_PHY_ATEOVRD_EN (0x1 << 2) +#define PCIE_PHY_ATEOVRD_REF_CLKDIV_SHIFT 0 +#define PCIE_PHY_ATEOVRD_REF_CLKDIV_MASK 0x1 + +#define PCIE_PHY_MPLL_OVRD_IN_LO 0x11 +#define PCIE_PHY_MPLL_MULTIPLIER_SHIFT 2 +#define PCIE_PHY_MPLL_MULTIPLIER_MASK 0x7f +#define PCIE_PHY_MPLL_MULTIPLIER_OVRD (0x1 << 9) + #define PCIE_PHY_RX_ASIC_OUT 0x100D #define PCIE_PHY_RX_ASIC_OUT_VALID (1 << 0) @@ -508,6 +518,50 @@ static void imx6_pcie_init_phy(struct imx6_pcie *imx6_pcie) IMX6Q_GPR12_DEVICE_TYPE, PCI_EXP_TYPE_ROOT_PORT << 12); } +static int imx6_setup_phy_mpll(struct imx6_pcie *imx6_pcie) +{ + unsigned long phy_rate = clk_get_rate(imx6_pcie->pcie_phy); + int mult, div; + u32 val; + + switch (phy_rate) { + case 125000000: + /* + * The default settings of the MPLL are for a 125MHz input + * clock, so no need to reconfigure anything in that case. + */ + return 0; + case 100000000: + mult = 25; + div = 0; + break; + case 200000000: + mult = 25; + div = 1; + break; + default: + dev_err(imx6_pcie->pci->dev, + "Unsupported PHY reference clock rate %lu\n", phy_rate); + return -EINVAL; + } + + pcie_phy_read(imx6_pcie, PCIE_PHY_MPLL_OVRD_IN_LO, &val); + val &= ~(PCIE_PHY_MPLL_MULTIPLIER_MASK << + PCIE_PHY_MPLL_MULTIPLIER_SHIFT); + val |= mult << PCIE_PHY_MPLL_MULTIPLIER_SHIFT; + val |= PCIE_PHY_MPLL_MULTIPLIER_OVRD; + pcie_phy_write(imx6_pcie, PCIE_PHY_MPLL_OVRD_IN_LO, val); + + pcie_phy_read(imx6_pcie, PCIE_PHY_ATEOVRD, &val); + val &= ~(PCIE_PHY_ATEOVRD_REF_CLKDIV_MASK << + PCIE_PHY_ATEOVRD_REF_CLKDIV_SHIFT); + val |= div << PCIE_PHY_ATEOVRD_REF_CLKDIV_SHIFT; + val |= PCIE_PHY_ATEOVRD_EN; + pcie_phy_write(imx6_pcie, PCIE_PHY_ATEOVRD, val); + + return 0; +} + static int imx6_pcie_wait_for_link(struct imx6_pcie *imx6_pcie) { struct dw_pcie *pci = imx6_pcie->pci; @@ -632,6 +686,7 @@ static int imx6_pcie_host_init(struct pcie_port *pp) imx6_pcie_assert_core_reset(imx6_pcie); imx6_pcie_init_phy(imx6_pcie); imx6_pcie_deassert_core_reset(imx6_pcie); + imx6_setup_phy_mpll(imx6_pcie); dw_pcie_setup_rc(pp); imx6_pcie_establish_link(imx6_pcie); -- cgit v1.2.3 From 0ee2c1f2429f74328c82ea559b127c96d5224ccd Mon Sep 17 00:00:00 2001 From: Leonard Crestez Date: Mon, 27 Aug 2018 14:28:37 +0300 Subject: PCI: imx: Initial imx7d pm support On imx7d the pcie-phy power domain is turned off in suspend and this can make the system hang after resume when attempting any read from PCI. Fix this by adding minimal suspend/resume code. This will prepare for powering down on suspend and reset the block on resume. Code is only for imx7d but a very similar sequence can be used for other SOCs. Original-by: Richard Zhu Signed-off-by: Leonard Crestez [lorenzo.pieralisi@arm.com: commit log update] Signed-off-by: Lorenzo Pieralisi Reviewed-by: Lucas Stach --- drivers/pci/controller/dwc/pci-imx6.c | 97 +++++++++++++++++++++++++++++++++-- 1 file changed, 92 insertions(+), 5 deletions(-) diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c index 21e03c6567da..d13dae50dc99 100644 --- a/drivers/pci/controller/dwc/pci-imx6.c +++ b/drivers/pci/controller/dwc/pci-imx6.c @@ -596,6 +596,24 @@ static int imx6_pcie_wait_for_speed_change(struct imx6_pcie *imx6_pcie) return -EINVAL; } +static void imx6_pcie_ltssm_enable(struct device *dev) +{ + struct imx6_pcie *imx6_pcie = dev_get_drvdata(dev); + + switch (imx6_pcie->variant) { + case IMX6Q: + case IMX6SX: + case IMX6QP: + regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12, + IMX6Q_GPR12_PCIE_CTL_2, + IMX6Q_GPR12_PCIE_CTL_2); + break; + case IMX7D: + reset_control_deassert(imx6_pcie->apps_reset); + break; + } +} + static int imx6_pcie_establish_link(struct imx6_pcie *imx6_pcie) { struct dw_pcie *pci = imx6_pcie->pci; @@ -614,11 +632,7 @@ static int imx6_pcie_establish_link(struct imx6_pcie *imx6_pcie) dw_pcie_writel_dbi(pci, PCIE_RC_LCR, tmp); /* Start LTSSM. */ - if (imx6_pcie->variant == IMX7D) - reset_control_deassert(imx6_pcie->apps_reset); - else - regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12, - IMX6Q_GPR12_PCIE_CTL_2, 1 << 10); + imx6_pcie_ltssm_enable(dev); ret = imx6_pcie_wait_for_link(imx6_pcie); if (ret) @@ -737,6 +751,78 @@ static const struct dw_pcie_ops dw_pcie_ops = { .link_up = imx6_pcie_link_up, }; +#ifdef CONFIG_PM_SLEEP +static void imx6_pcie_ltssm_disable(struct device *dev) +{ + struct imx6_pcie *imx6_pcie = dev_get_drvdata(dev); + + switch (imx6_pcie->variant) { + case IMX6SX: + case IMX6QP: + regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12, + IMX6Q_GPR12_PCIE_CTL_2, 0); + break; + case IMX7D: + reset_control_assert(imx6_pcie->apps_reset); + break; + default: + dev_err(dev, "ltssm_disable not supported\n"); + } +} + +static void imx6_pcie_clk_disable(struct imx6_pcie *imx6_pcie) +{ + clk_disable_unprepare(imx6_pcie->pcie); + clk_disable_unprepare(imx6_pcie->pcie_phy); + clk_disable_unprepare(imx6_pcie->pcie_bus); + + if (imx6_pcie->variant == IMX7D) { + regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12, + IMX7D_GPR12_PCIE_PHY_REFCLK_SEL, + IMX7D_GPR12_PCIE_PHY_REFCLK_SEL); + } +} + +static int imx6_pcie_suspend_noirq(struct device *dev) +{ + struct imx6_pcie *imx6_pcie = dev_get_drvdata(dev); + + if (imx6_pcie->variant != IMX7D) + return 0; + + imx6_pcie_clk_disable(imx6_pcie); + imx6_pcie_ltssm_disable(dev); + + return 0; +} + +static int imx6_pcie_resume_noirq(struct device *dev) +{ + int ret; + struct imx6_pcie *imx6_pcie = dev_get_drvdata(dev); + struct pcie_port *pp = &imx6_pcie->pci->pp; + + if (imx6_pcie->variant != IMX7D) + return 0; + + imx6_pcie_assert_core_reset(imx6_pcie); + imx6_pcie_init_phy(imx6_pcie); + imx6_pcie_deassert_core_reset(imx6_pcie); + dw_pcie_setup_rc(pp); + + ret = imx6_pcie_establish_link(imx6_pcie); + if (ret < 0) + dev_info(dev, "pcie link is down after resume.\n"); + + return 0; +} +#endif + +static const struct dev_pm_ops imx6_pcie_pm_ops = { + SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(imx6_pcie_suspend_noirq, + imx6_pcie_resume_noirq) +}; + static int imx6_pcie_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -903,6 +989,7 @@ static struct platform_driver imx6_pcie_driver = { .name = "imx6q-pcie", .of_match_table = imx6_pcie_of_match, .suppress_bind_attrs = true, + .pm = &imx6_pcie_pm_ops, }, .probe = imx6_pcie_probe, .shutdown = imx6_pcie_shutdown, -- cgit v1.2.3 From 6e5da6f7d82474e94c2d4a38cf9ca4edbb3e03a0 Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Fri, 31 Aug 2018 15:55:10 -0700 Subject: PCI: qcom: Fix error handling in runtime PM support The driver does not cope with the fact that probe can fail in a number of cases after enabling runtime PM on the device; this results in warnings about "Unbalanced pm_runtime_enable". Furthermore if probe fails after invoking qcom_pcie_host_init() the power-domain will be left referenced. As it is not possible for the error handling in qcom_pcie_host_init() to handle errors happening after returning from that function the pm_runtime_get_sync() is moved to qcom_pcie_probe() as well. Fixes: 854b69efbdd2 ("PCI: qcom: add runtime pm support to pcie_port") Signed-off-by: Bjorn Andersson [lorenzo.pieralisi@arm.com: updated commit log] Signed-off-by: Lorenzo Pieralisi Acked-by: Stanimir Varbanov --- drivers/pci/controller/dwc/pcie-qcom.c | 56 +++++++++++++++++++++++----------- 1 file changed, 39 insertions(+), 17 deletions(-) diff --git a/drivers/pci/controller/dwc/pcie-qcom.c b/drivers/pci/controller/dwc/pcie-qcom.c index 4352c1cb926d..d185ea5fe996 100644 --- a/drivers/pci/controller/dwc/pcie-qcom.c +++ b/drivers/pci/controller/dwc/pcie-qcom.c @@ -1089,7 +1089,6 @@ static int qcom_pcie_host_init(struct pcie_port *pp) struct qcom_pcie *pcie = to_qcom_pcie(pci); int ret; - pm_runtime_get_sync(pci->dev); qcom_ep_reset_assert(pcie); ret = pcie->ops->init(pcie); @@ -1126,7 +1125,6 @@ err_disable_phy: phy_power_off(pcie->phy); err_deinit: pcie->ops->deinit(pcie); - pm_runtime_put(pci->dev); return ret; } @@ -1216,6 +1214,12 @@ static int qcom_pcie_probe(struct platform_device *pdev) return -ENOMEM; pm_runtime_enable(dev); + ret = pm_runtime_get_sync(dev); + if (ret < 0) { + pm_runtime_disable(dev); + return ret; + } + pci->dev = dev; pci->ops = &dw_pcie_ops; pp = &pci->pp; @@ -1225,44 +1229,56 @@ static int qcom_pcie_probe(struct platform_device *pdev) pcie->ops = of_device_get_match_data(dev); pcie->reset = devm_gpiod_get_optional(dev, "perst", GPIOD_OUT_LOW); - if (IS_ERR(pcie->reset)) - return PTR_ERR(pcie->reset); + if (IS_ERR(pcie->reset)) { + ret = PTR_ERR(pcie->reset); + goto err_pm_runtime_put; + } res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "parf"); pcie->parf = devm_ioremap_resource(dev, res); - if (IS_ERR(pcie->parf)) - return PTR_ERR(pcie->parf); + if (IS_ERR(pcie->parf)) { + ret = PTR_ERR(pcie->parf); + goto err_pm_runtime_put; + } res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dbi"); pci->dbi_base = devm_pci_remap_cfg_resource(dev, res); - if (IS_ERR(pci->dbi_base)) - return PTR_ERR(pci->dbi_base); + if (IS_ERR(pci->dbi_base)) { + ret = PTR_ERR(pci->dbi_base); + goto err_pm_runtime_put; + } res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "elbi"); pcie->elbi = devm_ioremap_resource(dev, res); - if (IS_ERR(pcie->elbi)) - return PTR_ERR(pcie->elbi); + if (IS_ERR(pcie->elbi)) { + ret = PTR_ERR(pcie->elbi); + goto err_pm_runtime_put; + } pcie->phy = devm_phy_optional_get(dev, "pciephy"); - if (IS_ERR(pcie->phy)) - return PTR_ERR(pcie->phy); + if (IS_ERR(pcie->phy)) { + ret = PTR_ERR(pcie->phy); + goto err_pm_runtime_put; + } ret = pcie->ops->get_resources(pcie); if (ret) - return ret; + goto err_pm_runtime_put; pp->ops = &qcom_pcie_dw_ops; if (IS_ENABLED(CONFIG_PCI_MSI)) { pp->msi_irq = platform_get_irq_byname(pdev, "msi"); - if (pp->msi_irq < 0) - return pp->msi_irq; + if (pp->msi_irq < 0) { + ret = pp->msi_irq; + goto err_pm_runtime_put; + } } ret = phy_init(pcie->phy); if (ret) { pm_runtime_disable(&pdev->dev); - return ret; + goto err_pm_runtime_put; } platform_set_drvdata(pdev, pcie); @@ -1271,10 +1287,16 @@ static int qcom_pcie_probe(struct platform_device *pdev) if (ret) { dev_err(dev, "cannot initialize host\n"); pm_runtime_disable(&pdev->dev); - return ret; + goto err_pm_runtime_put; } return 0; + +err_pm_runtime_put: + pm_runtime_put(dev); + pm_runtime_disable(dev); + + return ret; } static const struct of_device_id qcom_pcie_match[] = { -- cgit v1.2.3 From e3336a18ff853c26031c578d49a23488b48ebc22 Mon Sep 17 00:00:00 2001 From: Vignesh R Date: Tue, 25 Sep 2018 14:00:23 +0530 Subject: dt-bindings: PCI: dra7xx: Add bindings for unaligned access in host mode Update device tree binding documentation of TI's dra7xx PCI controller for enabling unaligned mem access as applicable not just in EP mode but in host mode as well. Signed-off-by: Vignesh R Signed-off-by: Lorenzo Pieralisi Reviewed-by: Rob Herring --- Documentation/devicetree/bindings/pci/ti-pci.txt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Documentation/devicetree/bindings/pci/ti-pci.txt b/Documentation/devicetree/bindings/pci/ti-pci.txt index 7f7af3044016..452fe48c4fdd 100644 --- a/Documentation/devicetree/bindings/pci/ti-pci.txt +++ b/Documentation/devicetree/bindings/pci/ti-pci.txt @@ -26,6 +26,11 @@ HOST MODE ranges, interrupt-map-mask, interrupt-map : as specified in ../designware-pcie.txt + - ti,syscon-unaligned-access: phandle to the syscon DT node. The 1st argument + should contain the register offset within syscon + and the 2nd argument should contain the bit field + for setting the bit to enable unaligned + access. DEVICE MODE =========== -- cgit v1.2.3 From 726d75a6d243bf6730da3216f3592503f6f0f588 Mon Sep 17 00:00:00 2001 From: Vignesh R Date: Tue, 25 Sep 2018 14:00:24 +0530 Subject: PCI: dwc: pci-dra7xx: Enable errata i870 for both EP and RC mode Errata i870 is applicable in both EP and RC mode. Therefore rename function dra7xx_pcie_ep_unaligned_memaccess(), that implements errata workaround, to dra7xx_pcie_unaligned_memaccess() and call it for both RC and EP. Make sure driver probe does not fail in case the workaround is not applied for RC mode in order to maintain DT backward compatibility. Reported-by: Chris Welch Signed-off-by: Vignesh R [lorenzo.pieralisi@arm.com: reworded the log] Signed-off-by: Lorenzo Pieralisi Acked-by: Kishon Vijay Abraham I --- drivers/pci/controller/dwc/pci-dra7xx.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/drivers/pci/controller/dwc/pci-dra7xx.c b/drivers/pci/controller/dwc/pci-dra7xx.c index ce9224a36f62..a32d6dde7a57 100644 --- a/drivers/pci/controller/dwc/pci-dra7xx.c +++ b/drivers/pci/controller/dwc/pci-dra7xx.c @@ -542,7 +542,7 @@ static const struct of_device_id of_dra7xx_pcie_match[] = { }; /* - * dra7xx_pcie_ep_unaligned_memaccess: workaround for AM572x/AM571x Errata i870 + * dra7xx_pcie_unaligned_memaccess: workaround for AM572x/AM571x Errata i870 * @dra7xx: the dra7xx device where the workaround should be applied * * Access to the PCIe slave port that are not 32-bit aligned will result @@ -552,7 +552,7 @@ static const struct of_device_id of_dra7xx_pcie_match[] = { * * To avoid this issue set PCIE_SS1_AXI2OCP_LEGACY_MODE_ENABLE to 1. */ -static int dra7xx_pcie_ep_unaligned_memaccess(struct device *dev) +static int dra7xx_pcie_unaligned_memaccess(struct device *dev) { int ret; struct device_node *np = dev->of_node; @@ -704,6 +704,11 @@ static int __init dra7xx_pcie_probe(struct platform_device *pdev) dra7xx_pcie_writel(dra7xx, PCIECTRL_TI_CONF_DEVICE_TYPE, DEVICE_TYPE_RC); + + ret = dra7xx_pcie_unaligned_memaccess(dev); + if (ret) + dev_err(dev, "WA for Errata i870 not applied\n"); + ret = dra7xx_add_pcie_port(dra7xx, pdev); if (ret < 0) goto err_gpio; @@ -717,7 +722,7 @@ static int __init dra7xx_pcie_probe(struct platform_device *pdev) dra7xx_pcie_writel(dra7xx, PCIECTRL_TI_CONF_DEVICE_TYPE, DEVICE_TYPE_EP); - ret = dra7xx_pcie_ep_unaligned_memaccess(dev); + ret = dra7xx_pcie_unaligned_memaccess(dev); if (ret) goto err_gpio; -- cgit v1.2.3 From 6870b673509779195cab300aedc844b352d9cfbc Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Tue, 18 Sep 2018 22:38:29 -0700 Subject: PCI: kirin: Fix section mismatch warning The PCI kirin driver compilation produces the following section mismatch warning: WARNING: vmlinux.o(.text+0x4758cc): Section mismatch in reference from the function kirin_pcie_probe() to the function .init.text:kirin_add_pcie_port() The function kirin_pcie_probe() references the function __init kirin_add_pcie_port(). This is often because kirin_pcie_probe lacks a __init annotation or the annotation of kirin_add_pcie_port is wrong. Remove '__init' from kirin_add_pcie_port() to fix it. Fixes: fc5165db245a ("PCI: kirin: Add HiSilicon Kirin SoC PCIe controller driver") Reported-by: Nick Desaulniers Signed-off-by: Nathan Chancellor [lorenzo.pieralisi@arm.com: updated commit log] Signed-off-by: Lorenzo Pieralisi --- drivers/pci/controller/dwc/pcie-kirin.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/pci/controller/dwc/pcie-kirin.c b/drivers/pci/controller/dwc/pcie-kirin.c index 5352e0c3be82..9b599296205d 100644 --- a/drivers/pci/controller/dwc/pcie-kirin.c +++ b/drivers/pci/controller/dwc/pcie-kirin.c @@ -467,8 +467,8 @@ static int kirin_pcie_add_msi(struct dw_pcie *pci, return 0; } -static int __init kirin_add_pcie_port(struct dw_pcie *pci, - struct platform_device *pdev) +static int kirin_add_pcie_port(struct dw_pcie *pci, + struct platform_device *pdev) { int ret; -- cgit v1.2.3 From de248327091e7ab02f751cb288fc7cf7edbb0461 Mon Sep 17 00:00:00 2001 From: Leonard Crestez Date: Wed, 11 Jul 2018 22:30:02 +0300 Subject: reset: imx7: Add PCIE_CTRL_APPS_TURNOFF This is required for the imx pci driver to send the PME_Turn_Off TLP. Signed-off-by: Leonard Crestez Signed-off-by: Lorenzo Pieralisi Acked-by: Philipp Zabel Acked-by: Rob Herring --- drivers/reset/reset-imx7.c | 1 + include/dt-bindings/reset/imx7-reset.h | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/reset/reset-imx7.c b/drivers/reset/reset-imx7.c index 97d9f08271c5..77911fa8f31d 100644 --- a/drivers/reset/reset-imx7.c +++ b/drivers/reset/reset-imx7.c @@ -67,6 +67,7 @@ static const struct imx7_src_signal imx7_src_signals[IMX7_RESET_NUM] = { [IMX7_RESET_PCIEPHY] = { SRC_PCIEPHY_RCR, BIT(2) | BIT(1) }, [IMX7_RESET_PCIEPHY_PERST] = { SRC_PCIEPHY_RCR, BIT(3) }, [IMX7_RESET_PCIE_CTRL_APPS_EN] = { SRC_PCIEPHY_RCR, BIT(6) }, + [IMX7_RESET_PCIE_CTRL_APPS_TURNOFF] = { SRC_PCIEPHY_RCR, BIT(11) }, [IMX7_RESET_DDRC_PRST] = { SRC_DDRC_RCR, BIT(0) }, [IMX7_RESET_DDRC_CORE_RST] = { SRC_DDRC_RCR, BIT(1) }, }; diff --git a/include/dt-bindings/reset/imx7-reset.h b/include/dt-bindings/reset/imx7-reset.h index 63948170c7b2..31b3f87dde9a 100644 --- a/include/dt-bindings/reset/imx7-reset.h +++ b/include/dt-bindings/reset/imx7-reset.h @@ -56,7 +56,9 @@ #define IMX7_RESET_DDRC_PRST 23 #define IMX7_RESET_DDRC_CORE_RST 24 -#define IMX7_RESET_NUM 25 +#define IMX7_RESET_PCIE_CTRL_APPS_TURNOFF 25 + +#define IMX7_RESET_NUM 26 #endif -- cgit v1.2.3 From 3e3f50b148dd63caf66eabc7b2a9cd9dc485361f Mon Sep 17 00:00:00 2001 From: Leonard Crestez Date: Tue, 14 Aug 2018 15:59:12 +0300 Subject: dt-bindings: imx6q-pcie: Add turnoff reset for imx7d This is documented as "required" but won't be present in old dtbs. These resets are also present on other imx chips but right now only imx7d implements them through the reset controller subsystem. Signed-off-by: Leonard Crestez Signed-off-by: Lorenzo Pieralisi Acked-by: Philipp Zabel Acked-by: Rob Herring --- Documentation/devicetree/bindings/pci/fsl,imx6q-pcie.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/pci/fsl,imx6q-pcie.txt b/Documentation/devicetree/bindings/pci/fsl,imx6q-pcie.txt index cb33421184a0..f37494d5a7be 100644 --- a/Documentation/devicetree/bindings/pci/fsl,imx6q-pcie.txt +++ b/Documentation/devicetree/bindings/pci/fsl,imx6q-pcie.txt @@ -50,6 +50,7 @@ Additional required properties for imx7d-pcie: - reset-names: Must contain the following entires: - "pciephy" - "apps" + - "turnoff" Example: -- cgit v1.2.3 From 3aedf7e135b55cb74a62c0be79a86384f76e5724 Mon Sep 17 00:00:00 2001 From: Leonard Crestez Date: Wed, 11 Jul 2018 22:41:38 +0300 Subject: ARM: dts: imx7d: Add turnoff reset This is required for the imx pci driver to send the PME_Turn_Off TLP. Signed-off-by: Leonard Crestez Signed-off-by: Lorenzo Pieralisi Acked-by: Shawn Guo --- arch/arm/boot/dts/imx7d.dtsi | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/arch/arm/boot/dts/imx7d.dtsi b/arch/arm/boot/dts/imx7d.dtsi index 7234e8330a57..efbdeaaa8dcd 100644 --- a/arch/arm/boot/dts/imx7d.dtsi +++ b/arch/arm/boot/dts/imx7d.dtsi @@ -146,8 +146,9 @@ fsl,max-link-speed = <2>; power-domains = <&pgc_pcie_phy>; resets = <&src IMX7_RESET_PCIEPHY>, - <&src IMX7_RESET_PCIE_CTRL_APPS_EN>; - reset-names = "pciephy", "apps"; + <&src IMX7_RESET_PCIE_CTRL_APPS_EN>, + <&src IMX7_RESET_PCIE_CTRL_APPS_TURNOFF>; + reset-names = "pciephy", "apps", "turnoff"; status = "disabled"; }; }; -- cgit v1.2.3 From f4e833ba2a955bc15c1ccaa5b0b3c2a0d7989bca Mon Sep 17 00:00:00 2001 From: Leonard Crestez Date: Thu, 19 Jul 2018 17:02:10 +0300 Subject: PCI: imx: Add PME_Turn_Off support When the root complex suspends it must send a PME_Turn_Off TLP. Implement this by asserting the "turnoff" reset. On imx7d this functionality is part of the System Reset Controller (SRC) and is exposed through the linux reset-controller subsystem. On imx6 equivalent bits are in the IOMUXC pinmux controller General Purpose Register (GPR) area which the imx6-pcie driver accesses directly. This is only for imx7d right now but it's deliberately implemented as an optional reset, ignoring the chip variant: * Older dtbs won't have this reset so it will be ignored. * Future chips might also expose this as a reset controller. For example imx8m (not yet supported) has the exact same PCIE_CTRL_APPS_TURNOFF bit in the same location. Signed-off-by: Leonard Crestez [lorenzo.pieralisi@arm.com: updated commit log] Signed-off-by: Lorenzo Pieralisi Reviewed-by: Lucas Stach --- drivers/pci/controller/dwc/pci-imx6.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c index d13dae50dc99..2cbef2d7c207 100644 --- a/drivers/pci/controller/dwc/pci-imx6.c +++ b/drivers/pci/controller/dwc/pci-imx6.c @@ -50,6 +50,7 @@ struct imx6_pcie { struct regmap *iomuxc_gpr; struct reset_control *pciephy_reset; struct reset_control *apps_reset; + struct reset_control *turnoff_reset; enum imx6_pcie_variants variant; u32 tx_deemph_gen1; u32 tx_deemph_gen2_3p5db; @@ -770,6 +771,21 @@ static void imx6_pcie_ltssm_disable(struct device *dev) } } +static void imx6_pcie_pm_turnoff(struct imx6_pcie *imx6_pcie) +{ + reset_control_assert(imx6_pcie->turnoff_reset); + reset_control_deassert(imx6_pcie->turnoff_reset); + + /* + * Components with an upstream port must respond to + * PME_Turn_Off with PME_TO_Ack but we can't check. + * + * The standard recommends a 1-10ms timeout after which to + * proceed anyway as if acks were received. + */ + usleep_range(1000, 10000); +} + static void imx6_pcie_clk_disable(struct imx6_pcie *imx6_pcie) { clk_disable_unprepare(imx6_pcie->pcie); @@ -790,6 +806,7 @@ static int imx6_pcie_suspend_noirq(struct device *dev) if (imx6_pcie->variant != IMX7D) return 0; + imx6_pcie_pm_turnoff(imx6_pcie); imx6_pcie_clk_disable(imx6_pcie); imx6_pcie_ltssm_disable(dev); @@ -917,6 +934,13 @@ static int imx6_pcie_probe(struct platform_device *pdev) break; } + /* Grab turnoff reset */ + imx6_pcie->turnoff_reset = devm_reset_control_get_optional_exclusive(dev, "turnoff"); + if (IS_ERR(imx6_pcie->turnoff_reset)) { + dev_err(dev, "Failed to get TURNOFF reset control\n"); + return PTR_ERR(imx6_pcie->turnoff_reset); + } + /* Grab GPR config register range */ imx6_pcie->iomuxc_gpr = syscon_regmap_lookup_by_compatible("fsl,imx6q-iomuxc-gpr"); -- cgit v1.2.3