[PATCH] PCI: imx6: Add L1SS support for i.MX8MQ

From: Andrey Smirnov
Date: Tue Jan 14 2020 - 12:02:48 EST


Add code to configure PCI IP block to utilize supported ASPM features.

Signed-off-by: Andrey Smirnov <andrew.smirnov@xxxxxxxxx>
Cc: Lorenzo Pieralisi <lorenzo.pieralisi@xxxxxxx>
Cc: Bjorn Helgaas <bhelgaas@xxxxxxxxxx>
Cc: Chris Healy <cphealy@xxxxxxxxx>
Cc: Lucas Stach <l.stach@xxxxxxxxxxxxxx>
Cc: Richard Zhu <hongxing.zhu@xxxxxxx>
Cc: linux-imx@xxxxxxx
Cc: linux-arm-kernel@xxxxxxxxxxxxxxxxxxx
Cc: linux-kernel@xxxxxxxxxxxxxxx
Cc: linux-pci@xxxxxxxxxxxxxxx
---
drivers/pci/controller/dwc/pci-imx6.c | 72 ++++++++++++++++++++++-----
1 file changed, 60 insertions(+), 12 deletions(-)

diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c
index acfbd34032a8..3cc94ab7d22b 100644
--- a/drivers/pci/controller/dwc/pci-imx6.c
+++ b/drivers/pci/controller/dwc/pci-imx6.c
@@ -40,6 +40,9 @@
#define IMX8MQ_GPR12_PCIE2_CTRL_DEVICE_TYPE GENMASK(11, 8)
#define IMX8MQ_PCIE2_BASE_ADDR 0x33c00000

+#define IMX8MQ_PCIE_LINK_CAP_L1EL_64US (0x6 << 15)
+#define IMX8MQ_PCIE_CTRL_APPS_CLK_REQ BIT(4)
+
#define to_imx6_pcie(x) dev_get_drvdata((x)->dev)

enum imx6_pcie_variants {
@@ -64,12 +67,14 @@ struct imx6_pcie {
struct dw_pcie *pci;
int reset_gpio;
bool gpio_active_high;
+ bool supports_clkreq;
struct clk *pcie_bus;
struct clk *pcie_phy;
struct clk *pcie_inbound_axi;
struct clk *pcie;
struct clk *pcie_aux;
struct regmap *iomuxc_gpr;
+ struct regmap *src;
u32 controller_id;
struct reset_control *pciephy_reset;
struct reset_control *apps_reset;
@@ -421,11 +426,17 @@ static unsigned int imx6_pcie_grp_offset(const struct imx6_pcie *imx6_pcie)
return imx6_pcie->controller_id == 1 ? IOMUXC_GPR16 : IOMUXC_GPR14;
}

+static unsigned int
+imx6_pcie_pciphy_rcr_offset(const struct imx6_pcie *imx6_pcie)
+{
+ WARN_ON(imx6_pcie->drvdata->variant != IMX8MQ);
+ return imx6_pcie->controller_id == 1 ? 0x48 : 0x2C;
+}
+
static int imx6_pcie_enable_ref_clk(struct imx6_pcie *imx6_pcie)
{
struct dw_pcie *pci = imx6_pcie->pci;
struct device *dev = pci->dev;
- unsigned int offset;
int ret = 0;

switch (imx6_pcie->drvdata->variant) {
@@ -463,17 +474,19 @@ static int imx6_pcie_enable_ref_clk(struct imx6_pcie *imx6_pcie)
break;
}

- offset = imx6_pcie_grp_offset(imx6_pcie);
- /*
- * Set the over ride low and enabled
- * make sure that REF_CLK is turned on.
- */
- regmap_update_bits(imx6_pcie->iomuxc_gpr, offset,
- IMX8MQ_GPR_PCIE_CLK_REQ_OVERRIDE,
- 0);
- regmap_update_bits(imx6_pcie->iomuxc_gpr, offset,
- IMX8MQ_GPR_PCIE_CLK_REQ_OVERRIDE_EN,
- IMX8MQ_GPR_PCIE_CLK_REQ_OVERRIDE_EN);
+ if (!imx6_pcie->supports_clkreq) {
+ unsigned int offset = imx6_pcie_grp_offset(imx6_pcie);
+ /*
+ * Set the over ride low and enabled
+ * make sure that REF_CLK is turned on.
+ */
+ regmap_update_bits(imx6_pcie->iomuxc_gpr, offset,
+ IMX8MQ_GPR_PCIE_CLK_REQ_OVERRIDE,
+ 0);
+ regmap_update_bits(imx6_pcie->iomuxc_gpr, offset,
+ IMX8MQ_GPR_PCIE_CLK_REQ_OVERRIDE_EN,
+ IMX8MQ_GPR_PCIE_CLK_REQ_OVERRIDE_EN);
+ }
break;
}

@@ -547,6 +560,27 @@ static void imx6_pcie_deassert_core_reset(struct imx6_pcie *imx6_pcie)
switch (imx6_pcie->drvdata->variant) {
case IMX8MQ:
reset_control_deassert(imx6_pcie->pciephy_reset);
+ if (imx6_pcie->supports_clkreq) {
+ u32 lcr;
+
+ regmap_update_bits(imx6_pcie->src,
+ imx6_pcie_pciphy_rcr_offset(imx6_pcie),
+ IMX8MQ_PCIE_CTRL_APPS_CLK_REQ,
+ IMX8MQ_PCIE_CTRL_APPS_CLK_REQ);
+ /*
+ * Configure the L1 latency of rc to less than
+ * 64us Otherwise, the L1/L1SUB wouldn't be
+ * enable by ASPM.
+ */
+ dw_pcie_dbi_ro_wr_en(pci);
+
+ lcr = dw_pcie_readl_dbi2(pci, PCIE_RC_LCR);
+ lcr &= ~PCI_EXP_LNKCAP_L1EL;
+ lcr |= IMX8MQ_PCIE_LINK_CAP_L1EL_64US;
+ dw_pcie_writel_dbi2(pci, PCIE_RC_LCR, lcr);
+
+ dw_pcie_dbi_ro_wr_dis(pci);
+ }
break;
case IMX7D:
reset_control_deassert(imx6_pcie->pciephy_reset);
@@ -1054,6 +1088,11 @@ static int imx6_pcie_probe(struct platform_device *pdev)
pci->dbi_base = devm_ioremap_resource(dev, dbi_base);
if (IS_ERR(pci->dbi_base))
return PTR_ERR(pci->dbi_base);
+ /*
+ * Configure dbi_base2 to access DBI space with CS2
+ * asserted
+ */
+ pci->dbi_base2 = pci->dbi_base + SZ_1M;

/* Fetch GPIOs */
imx6_pcie->reset_gpio = of_get_named_gpio(node, "reset-gpio", 0);
@@ -1107,6 +1146,13 @@ static int imx6_pcie_probe(struct platform_device *pdev)
dev_err(dev, "pcie_aux clock source missing or invalid\n");
return PTR_ERR(imx6_pcie->pcie_aux);
}
+ imx6_pcie->src =
+ syscon_regmap_lookup_by_compatible("fsl,imx8mq-src");
+ if (IS_ERR(imx6_pcie->src)) {
+ dev_err(dev, "SRC regmap is missing or invalid\n");
+ return PTR_ERR(imx6_pcie->src);
+ }
+
/* fall through */
case IMX7D:
if (dbi_base->start == IMX8MQ_PCIE2_BASE_ADDR)
@@ -1179,6 +1225,8 @@ static int imx6_pcie_probe(struct platform_device *pdev)
imx6_pcie->vpcie = NULL;
}

+ imx6_pcie->supports_clkreq = of_property_read_bool(node,
+ "supports-clkreq");
platform_set_drvdata(pdev, imx6_pcie);

ret = imx6_pcie_attach_pd(dev);
--
2.21.0