Commit f4ff0b0e authored by Bjorn Helgaas's avatar Bjorn Helgaas
Browse files

Merge branch 'pci/controller/imx6'

- Apply link training workaround only on IMX6Q, IMX6SX, IMX6SP (Richard
  Zhu)

- Remove redundant dw_pcie_wait_for_link() from imx_pcie_start_link();
  since the DWC core does this, imx6 only needs it when retraining for a
  faster link speed (Richard Zhu)

- Toggle i.MX95 core reset to align with PHY powerup (Richard Zhu)

- Set SYS_AUX_PWR_DET to work around i.MX95 ERR051624 erratum: in some
  cases, the controller can't exit 'L23 Ready' through Beacon or PERST#
  deassertion (Richard Zhu)

- Clear GEN3_ZRXDC_NONCOMPL to work around i.MX95 ERR051586 erratum:
  controller can't meet 2.5 GT/s ZRX-DC timing when operating at 8 GT/s,
  causing timeouts in L1 (Richard Zhu)

- Wait for i.MX95 PLL lock before enabling controller (Richard Zhu)

- Save/restore i.MX95 LUT for suspend/resume (Richard Zhu)

* pci/controller/imx6:
  PCI: imx6: Save and restore the LUT setting during suspend/resume for i.MX95 SoC
  PCI: imx6: Add PLL lock check for i.MX95 SoC
  PCI: imx6: Add workaround for errata ERR051586
  PCI: imx6: Add workaround for errata ERR051624
  PCI: imx6: Toggle the core reset for i.MX95 PCIe
  PCI: imx6: Call dw_pcie_wait_for_link() from start_link() callback only when required
  PCI: imx6: Skip link up workaround for newer platforms
parents 20611193 e4d66131
Loading
Loading
Loading
Loading
+182 −31
Original line number Diff line number Diff line
@@ -45,9 +45,14 @@
#define IMX95_PCIE_PHY_GEN_CTRL			0x0
#define IMX95_PCIE_REF_USE_PAD			BIT(17)

#define IMX95_PCIE_PHY_MPLLA_CTRL		0x10
#define IMX95_PCIE_PHY_MPLL_STATE		BIT(30)

#define IMX95_PCIE_SS_RW_REG_0			0xf0
#define IMX95_PCIE_REF_CLKEN			BIT(23)
#define IMX95_PCIE_PHY_CR_PARA_SEL		BIT(9)
#define IMX95_PCIE_SS_RW_REG_1			0xf4
#define IMX95_PCIE_SYS_AUX_PWR_DET		BIT(31)

#define IMX95_PE0_GEN_CTRL_1			0x1050
#define IMX95_PCIE_DEVICE_TYPE			GENMASK(3, 0)
@@ -71,6 +76,9 @@
#define IMX95_SID_MASK				GENMASK(5, 0)
#define IMX95_MAX_LUT				32

#define IMX95_PCIE_RST_CTRL			0x3010
#define IMX95_PCIE_COLD_RST			BIT(0)

#define to_imx_pcie(x)	dev_get_drvdata((x)->dev)

enum imx_pcie_variants {
@@ -91,7 +99,7 @@ enum imx_pcie_variants {
};

#define IMX_PCIE_FLAG_IMX_PHY			BIT(0)
#define IMX_PCIE_FLAG_IMX_SPEED_CHANGE		BIT(1)
#define IMX_PCIE_FLAG_SPEED_CHANGE_WORKAROUND	BIT(1)
#define IMX_PCIE_FLAG_SUPPORTS_SUSPEND		BIT(2)
#define IMX_PCIE_FLAG_HAS_PHYDRV		BIT(3)
#define IMX_PCIE_FLAG_HAS_APP_RESET		BIT(4)
@@ -105,6 +113,7 @@ enum imx_pcie_variants {
 */
#define IMX_PCIE_FLAG_BROKEN_SUSPEND		BIT(9)
#define IMX_PCIE_FLAG_HAS_LUT			BIT(10)
#define IMX_PCIE_FLAG_8GT_ECN_ERR051586		BIT(11)

#define imx_check_flag(pci, val)	(pci->drvdata->flags & val)

@@ -126,9 +135,15 @@ struct imx_pcie_drvdata {
	int (*init_phy)(struct imx_pcie *pcie);
	int (*enable_ref_clk)(struct imx_pcie *pcie, bool enable);
	int (*core_reset)(struct imx_pcie *pcie, bool assert);
	int (*wait_pll_lock)(struct imx_pcie *pcie);
	const struct dw_pcie_host_ops *ops;
};

struct imx_lut_data {
	u32 data1;
	u32 data2;
};

struct imx_pcie {
	struct dw_pcie		*pci;
	struct gpio_desc	*reset_gpiod;
@@ -148,6 +163,8 @@ struct imx_pcie {
	struct regulator	*vph;
	void __iomem		*phy_base;

	/* LUT data for pcie */
	struct imx_lut_data	luts[IMX95_MAX_LUT];
	/* power domain for pcie */
	struct device		*pd_pcie;
	/* power domain for pcie phy */
@@ -224,6 +241,19 @@ static unsigned int imx_pcie_grp_offset(const struct imx_pcie *imx_pcie)

static int imx95_pcie_init_phy(struct imx_pcie *imx_pcie)
{
	/*
	 * ERR051624: The Controller Without Vaux Cannot Exit L23 Ready
	 * Through Beacon or PERST# De-assertion
	 *
	 * When the auxiliary power is not available, the controller
	 * cannot exit from L23 Ready with beacon or PERST# de-assertion
	 * when main power is not removed.
	 *
	 * Workaround: Set SS_RW_REG_1[SYS_AUX_PWR_DET] to 1.
	 */
	regmap_set_bits(imx_pcie->iomuxc_gpr, IMX95_PCIE_SS_RW_REG_1,
			IMX95_PCIE_SYS_AUX_PWR_DET);

	regmap_update_bits(imx_pcie->iomuxc_gpr,
			IMX95_PCIE_SS_RW_REG_0,
			IMX95_PCIE_PHY_CR_PARA_SEL,
@@ -460,6 +490,23 @@ static void imx7d_pcie_wait_for_phy_pll_lock(struct imx_pcie *imx_pcie)
		dev_err(dev, "PCIe PLL lock timeout\n");
}

static int imx95_pcie_wait_for_phy_pll_lock(struct imx_pcie *imx_pcie)
{
	u32 val;
	struct device *dev = imx_pcie->pci->dev;

	if (regmap_read_poll_timeout(imx_pcie->iomuxc_gpr,
				     IMX95_PCIE_PHY_MPLLA_CTRL, val,
				     val & IMX95_PCIE_PHY_MPLL_STATE,
				     PHY_PLL_LOCK_WAIT_USLEEP_MAX,
				     PHY_PLL_LOCK_WAIT_TIMEOUT)) {
		dev_err(dev, "PCIe PLL lock timeout\n");
		return -ETIMEDOUT;
	}

	return 0;
}

static int imx_setup_phy_mpll(struct imx_pcie *imx_pcie)
{
	unsigned long phy_rate = 0;
@@ -773,6 +820,43 @@ static int imx7d_pcie_core_reset(struct imx_pcie *imx_pcie, bool assert)
	return 0;
}

static int imx95_pcie_core_reset(struct imx_pcie *imx_pcie, bool assert)
{
	u32 val;

	if (assert) {
		/*
		 * From i.MX95 PCIe PHY perspective, the COLD reset toggle
		 * should be complete after power-up by the following sequence.
		 *                 > 10us(at power-up)
		 *                 > 10ns(warm reset)
		 *               |<------------>|
		 *                ______________
		 * phy_reset ____/              \________________
		 *                                   ____________
		 * ref_clk_en_______________________/
		 * Toggle COLD reset aligned with this sequence for i.MX95 PCIe.
		 */
		regmap_set_bits(imx_pcie->iomuxc_gpr, IMX95_PCIE_RST_CTRL,
				IMX95_PCIE_COLD_RST);
		/*
		 * Make sure the write to IMX95_PCIE_RST_CTRL is flushed to the
		 * hardware by doing a read. Otherwise, there is no guarantee
		 * that the write has reached the hardware before udelay().
		 */
		regmap_read_bypassed(imx_pcie->iomuxc_gpr, IMX95_PCIE_RST_CTRL,
				     &val);
		udelay(15);
		regmap_clear_bits(imx_pcie->iomuxc_gpr, IMX95_PCIE_RST_CTRL,
				  IMX95_PCIE_COLD_RST);
		regmap_read_bypassed(imx_pcie->iomuxc_gpr, IMX95_PCIE_RST_CTRL,
				     &val);
		udelay(10);
	}

	return 0;
}

static void imx_pcie_assert_core_reset(struct imx_pcie *imx_pcie)
{
	reset_control_assert(imx_pcie->pciephy_reset);
@@ -860,6 +944,12 @@ static int imx_pcie_start_link(struct dw_pcie *pci)
	u32 tmp;
	int ret;

	if (!(imx_pcie->drvdata->flags &
	    IMX_PCIE_FLAG_SPEED_CHANGE_WORKAROUND)) {
		imx_pcie_ltssm_enable(dev);
		return 0;
	}

	/*
	 * Force Gen1 operation when starting the link.  In case the link is
	 * started in Gen2 mode, there is a possibility the devices on the
@@ -875,11 +965,11 @@ static int imx_pcie_start_link(struct dw_pcie *pci)
	/* Start LTSSM. */
	imx_pcie_ltssm_enable(dev);

	if (pci->max_link_speed > 1) {
		ret = dw_pcie_wait_for_link(pci);
		if (ret)
			goto err_reset_phy;

	if (pci->max_link_speed > 1) {
		/* Allow faster modes after the link is up */
		dw_pcie_dbi_ro_wr_en(pci);
		tmp = dw_pcie_readl_dbi(pci, offset + PCI_EXP_LNKCAP);
@@ -896,34 +986,15 @@ static int imx_pcie_start_link(struct dw_pcie *pci)
		dw_pcie_writel_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL, tmp);
		dw_pcie_dbi_ro_wr_dis(pci);

		if (imx_pcie->drvdata->flags &
		    IMX_PCIE_FLAG_IMX_SPEED_CHANGE) {

			/*
			 * On i.MX7, DIRECT_SPEED_CHANGE behaves differently
			 * from i.MX6 family when no link speed transition
			 * occurs and we go Gen1 -> yep, Gen1. The difference
			 * is that, in such case, it will not be cleared by HW
			 * which will cause the following code to report false
			 * failure.
			 */
		ret = imx_pcie_wait_for_speed_change(imx_pcie);
		if (ret) {
			dev_err(dev, "Failed to bring link up!\n");
			goto err_reset_phy;
		}
		}

		/* Make sure link training is finished as well! */
		ret = dw_pcie_wait_for_link(pci);
		if (ret)
			goto err_reset_phy;
	} else {
		dev_info(dev, "Link: Only Gen1 is enabled\n");
	}

	tmp = dw_pcie_readw_dbi(pci, offset + PCI_EXP_LNKSTA);
	dev_info(dev, "Link up, Gen%i\n", tmp & PCI_EXP_LNKSTA_CLS);
	return 0;

err_reset_phy:
@@ -1182,6 +1253,12 @@ static int imx_pcie_host_init(struct dw_pcie_rp *pp)
		goto err_phy_off;
	}

	if (imx_pcie->drvdata->wait_pll_lock) {
		ret = imx_pcie->drvdata->wait_pll_lock(imx_pcie);
		if (ret < 0)
			goto err_phy_off;
	}

	imx_setup_phy_mpll(imx_pcie);

	return 0;
@@ -1214,6 +1291,32 @@ static void imx_pcie_host_exit(struct dw_pcie_rp *pp)
		regulator_disable(imx_pcie->vpcie);
}

static void imx_pcie_host_post_init(struct dw_pcie_rp *pp)
{
	struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
	struct imx_pcie *imx_pcie = to_imx_pcie(pci);
	u32 val;

	if (imx_pcie->drvdata->flags & IMX_PCIE_FLAG_8GT_ECN_ERR051586) {
		/*
		 * ERR051586: Compliance with 8GT/s Receiver Impedance ECN
		 *
		 * The default value of GEN3_RELATED_OFF[GEN3_ZRXDC_NONCOMPL]
		 * is 1 which makes receiver non-compliant with the ZRX-DC
		 * parameter for 2.5 GT/s when operating at 8 GT/s or higher.
		 * It causes unnecessary timeout in L1.
		 *
		 * Workaround: Program GEN3_RELATED_OFF[GEN3_ZRXDC_NONCOMPL]
		 * to 0.
		 */
		dw_pcie_dbi_ro_wr_en(pci);
		val = dw_pcie_readl_dbi(pci, GEN3_RELATED_OFF);
		val &= ~GEN3_RELATED_OFF_GEN3_ZRXDC_NONCOMPL;
		dw_pcie_writel_dbi(pci, GEN3_RELATED_OFF, val);
		dw_pcie_dbi_ro_wr_dis(pci);
	}
}

/*
 * In old DWC implementations, PCIE_ATU_INHIBIT_PAYLOAD in iATU Ctrl2
 * register is reserved, so the generic DWC implementation of sending the
@@ -1239,6 +1342,7 @@ static const struct dw_pcie_host_ops imx_pcie_host_ops = {
static const struct dw_pcie_host_ops imx_pcie_host_dw_pme_ops = {
	.init = imx_pcie_host_init,
	.deinit = imx_pcie_host_exit,
	.post_init = imx_pcie_host_post_init,
};

static const struct dw_pcie_ops dw_pcie_ops = {
@@ -1350,6 +1454,7 @@ static int imx_add_pcie_ep(struct imx_pcie *imx_pcie,
		dev_err(dev, "failed to initialize endpoint\n");
		return ret;
	}
	imx_pcie_host_post_init(pp);

	ret = dw_pcie_ep_init_registers(ep);
	if (ret) {
@@ -1386,6 +1491,42 @@ static void imx_pcie_msi_save_restore(struct imx_pcie *imx_pcie, bool save)
	}
}

static void imx_pcie_lut_save(struct imx_pcie *imx_pcie)
{
	u32 data1, data2;
	int i;

	for (i = 0; i < IMX95_MAX_LUT; i++) {
		regmap_write(imx_pcie->iomuxc_gpr, IMX95_PE0_LUT_ACSCTRL,
			     IMX95_PEO_LUT_RWA | i);
		regmap_read(imx_pcie->iomuxc_gpr, IMX95_PE0_LUT_DATA1, &data1);
		regmap_read(imx_pcie->iomuxc_gpr, IMX95_PE0_LUT_DATA2, &data2);
		if (data1 & IMX95_PE0_LUT_VLD) {
			imx_pcie->luts[i].data1 = data1;
			imx_pcie->luts[i].data2 = data2;
		} else {
			imx_pcie->luts[i].data1 = 0;
			imx_pcie->luts[i].data2 = 0;
		}
	}
}

static void imx_pcie_lut_restore(struct imx_pcie *imx_pcie)
{
	int i;

	for (i = 0; i < IMX95_MAX_LUT; i++) {
		if ((imx_pcie->luts[i].data1 & IMX95_PE0_LUT_VLD) == 0)
			continue;

		regmap_write(imx_pcie->iomuxc_gpr, IMX95_PE0_LUT_DATA1,
			     imx_pcie->luts[i].data1);
		regmap_write(imx_pcie->iomuxc_gpr, IMX95_PE0_LUT_DATA2,
			     imx_pcie->luts[i].data2);
		regmap_write(imx_pcie->iomuxc_gpr, IMX95_PE0_LUT_ACSCTRL, i);
	}
}

static int imx_pcie_suspend_noirq(struct device *dev)
{
	struct imx_pcie *imx_pcie = dev_get_drvdata(dev);
@@ -1394,6 +1535,8 @@ static int imx_pcie_suspend_noirq(struct device *dev)
		return 0;

	imx_pcie_msi_save_restore(imx_pcie, true);
	if (imx_check_flag(imx_pcie, IMX_PCIE_FLAG_HAS_LUT))
		imx_pcie_lut_save(imx_pcie);
	if (imx_check_flag(imx_pcie, IMX_PCIE_FLAG_BROKEN_SUSPEND)) {
		/*
		 * The minimum for a workaround would be to set PERST# and to
@@ -1438,6 +1581,8 @@ static int imx_pcie_resume_noirq(struct device *dev)
		if (ret)
			return ret;
	}
	if (imx_check_flag(imx_pcie, IMX_PCIE_FLAG_HAS_LUT))
		imx_pcie_lut_restore(imx_pcie);
	imx_pcie_msi_save_restore(imx_pcie, false);

	return 0;
@@ -1649,7 +1794,7 @@ static const struct imx_pcie_drvdata drvdata[] = {
	[IMX6Q] = {
		.variant = IMX6Q,
		.flags = IMX_PCIE_FLAG_IMX_PHY |
			 IMX_PCIE_FLAG_IMX_SPEED_CHANGE |
			 IMX_PCIE_FLAG_SPEED_CHANGE_WORKAROUND |
			 IMX_PCIE_FLAG_BROKEN_SUSPEND |
			 IMX_PCIE_FLAG_SUPPORTS_SUSPEND,
		.dbi_length = 0x200,
@@ -1665,7 +1810,7 @@ static const struct imx_pcie_drvdata drvdata[] = {
	[IMX6SX] = {
		.variant = IMX6SX,
		.flags = IMX_PCIE_FLAG_IMX_PHY |
			 IMX_PCIE_FLAG_IMX_SPEED_CHANGE |
			 IMX_PCIE_FLAG_SPEED_CHANGE_WORKAROUND |
			 IMX_PCIE_FLAG_SUPPORTS_SUSPEND,
		.gpr = "fsl,imx6q-iomuxc-gpr",
		.ltssm_off = IOMUXC_GPR12,
@@ -1680,7 +1825,7 @@ static const struct imx_pcie_drvdata drvdata[] = {
	[IMX6QP] = {
		.variant = IMX6QP,
		.flags = IMX_PCIE_FLAG_IMX_PHY |
			 IMX_PCIE_FLAG_IMX_SPEED_CHANGE |
			 IMX_PCIE_FLAG_SPEED_CHANGE_WORKAROUND |
			 IMX_PCIE_FLAG_SUPPORTS_SUSPEND,
		.dbi_length = 0x200,
		.gpr = "fsl,imx6q-iomuxc-gpr",
@@ -1747,12 +1892,15 @@ static const struct imx_pcie_drvdata drvdata[] = {
		.variant = IMX95,
		.flags = IMX_PCIE_FLAG_HAS_SERDES |
			 IMX_PCIE_FLAG_HAS_LUT |
			 IMX_PCIE_FLAG_8GT_ECN_ERR051586 |
			 IMX_PCIE_FLAG_SUPPORTS_SUSPEND,
		.ltssm_off = IMX95_PE0_GEN_CTRL_3,
		.ltssm_mask = IMX95_PCIE_LTSSM_EN,
		.mode_off[0]  = IMX95_PE0_GEN_CTRL_1,
		.mode_mask[0] = IMX95_PCIE_DEVICE_TYPE,
		.core_reset = imx95_pcie_core_reset,
		.init_phy = imx95_pcie_init_phy,
		.wait_pll_lock = imx95_pcie_wait_for_phy_pll_lock,
	},
	[IMX8MQ_EP] = {
		.variant = IMX8MQ_EP,
@@ -1799,12 +1947,15 @@ static const struct imx_pcie_drvdata drvdata[] = {
	[IMX95_EP] = {
		.variant = IMX95_EP,
		.flags = IMX_PCIE_FLAG_HAS_SERDES |
			 IMX_PCIE_FLAG_8GT_ECN_ERR051586 |
			 IMX_PCIE_FLAG_SUPPORT_64BIT,
		.ltssm_off = IMX95_PE0_GEN_CTRL_3,
		.ltssm_mask = IMX95_PCIE_LTSSM_EN,
		.mode_off[0]  = IMX95_PE0_GEN_CTRL_1,
		.mode_mask[0] = IMX95_PCIE_DEVICE_TYPE,
		.init_phy = imx95_pcie_init_phy,
		.core_reset = imx95_pcie_core_reset,
		.wait_pll_lock = imx95_pcie_wait_for_phy_pll_lock,
		.epc_features = &imx95_pcie_epc_features,
		.mode = DW_PCIE_EP_TYPE,
	},