Commit 62dea871 authored by Bjorn Helgaas's avatar Bjorn Helgaas
Browse files

Merge branch 'pci/controller/dwc-imx6'

- Add DT binding and driver support for an optional external refclock in
  addition to the refclock from the internal PLL (Richard Zhu)

- Apply i.MX95 ERR051586 erratum workaround (release CLKREQ# so endpoint
  can assert it when required) during resume (Richard Zhu)

- Enable i.MX95 REFCLK by overriding CLKREQ# so it's driven by default
  (Richard Zhu)

- Clear CLKREQ# override if link is up and DT says 'supports-clkreq' so
  endpoints can use CLKREQ# to exit the L1.2 state (Richard Zhu)

* pci/controller/dwc-imx6:
  PCI: imx6: Clear CLKREQ# override if 'supports-clkreq' DT property is available
  PCI: imx6: Add CLKREQ# override to enable REFCLK for i.MX95 PCIe
  PCI: dwc: Invoke post_init in dw_pcie_resume_noirq()
  PCI: imx6: Add external reference clock input mode support
  dt-bindings: PCI: pci-imx6: Add external reference clock input
  dt-bindings: PCI: dwc: Add external reference clock input
parents 93c398be a152a90f
Loading
Loading
Loading
Loading
+5 −2
Original line number Diff line number Diff line
@@ -44,7 +44,7 @@ properties:

  clock-names:
    minItems: 3
    maxItems: 5
    maxItems: 6

  interrupts:
    minItems: 1
@@ -212,14 +212,17 @@ allOf:
    then:
      properties:
        clocks:
          maxItems: 5
          minItems: 5
          maxItems: 6
        clock-names:
          minItems: 5
          items:
            - const: pcie
            - const: pcie_bus
            - const: pcie_phy
            - const: pcie_aux
            - const: ref
            - const: extref  # Optional

unevaluatedProperties: false

+6 −0
Original line number Diff line number Diff line
@@ -105,6 +105,12 @@ properties:
            define it with this name (for instance pipe, core and aux can
            be connected to a single source of the periodic signal).
          const: ref
        - description:
            Some dwc wrappers (like i.MX95 PCIes) have two reference clock
            inputs, one from an internal PLL, the other from an off-chip crystal
            oscillator. If present, 'extref' refers to a reference clock from
            an external oscillator.
          const: extref
        - description:
            Clock for the PHY registers interface. Originally this is
            a PHY-viewport-based interface, but some platform may have
+61 −8
Original line number Diff line number Diff line
@@ -52,6 +52,8 @@
#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_CLKREQ_OVERRIDE_EN		BIT(8)
#define IMX95_PCIE_CLKREQ_OVERRIDE_VAL		BIT(9)
#define IMX95_PCIE_SYS_AUX_PWR_DET		BIT(31)

#define IMX95_PE0_GEN_CTRL_1			0x1050
@@ -137,6 +139,7 @@ struct imx_pcie_drvdata {
	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);
	void (*clr_clkreq_override)(struct imx_pcie *pcie);
	const struct dw_pcie_host_ops *ops;
};

@@ -150,6 +153,8 @@ struct imx_pcie {
	struct gpio_desc	*reset_gpiod;
	struct clk_bulk_data	*clks;
	int			num_clks;
	bool			supports_clkreq;
	bool			enable_ext_refclk;
	struct regmap		*iomuxc_gpr;
	u16			msi_ctrl;
	u32			controller_id;
@@ -242,6 +247,8 @@ static unsigned int imx_pcie_grp_offset(const struct imx_pcie *imx_pcie)

static int imx95_pcie_init_phy(struct imx_pcie *imx_pcie)
{
	bool ext = imx_pcie->enable_ext_refclk;

	/*
	 * ERR051624: The Controller Without Vaux Cannot Exit L23 Ready
	 * Through Beacon or PERST# De-assertion
@@ -260,13 +267,12 @@ static int imx95_pcie_init_phy(struct imx_pcie *imx_pcie)
			IMX95_PCIE_PHY_CR_PARA_SEL,
			IMX95_PCIE_PHY_CR_PARA_SEL);

	regmap_update_bits(imx_pcie->iomuxc_gpr,
			   IMX95_PCIE_PHY_GEN_CTRL,
			   IMX95_PCIE_REF_USE_PAD, 0);
	regmap_update_bits(imx_pcie->iomuxc_gpr,
			   IMX95_PCIE_SS_RW_REG_0,
	regmap_update_bits(imx_pcie->iomuxc_gpr, IMX95_PCIE_PHY_GEN_CTRL,
			   ext ? IMX95_PCIE_REF_USE_PAD : 0,
			   IMX95_PCIE_REF_USE_PAD);
	regmap_update_bits(imx_pcie->iomuxc_gpr, IMX95_PCIE_SS_RW_REG_0,
			   IMX95_PCIE_REF_CLKEN,
			   IMX95_PCIE_REF_CLKEN);
			   ext ? 0 : IMX95_PCIE_REF_CLKEN);

	return 0;
}
@@ -686,7 +692,7 @@ static int imx6q_pcie_enable_ref_clk(struct imx_pcie *imx_pcie, bool enable)
	return 0;
}

static int imx8mm_pcie_enable_ref_clk(struct imx_pcie *imx_pcie, bool enable)
static void imx8mm_pcie_clkreq_override(struct imx_pcie *imx_pcie, bool enable)
{
	int offset = imx_pcie_grp_offset(imx_pcie);

@@ -696,6 +702,11 @@ static int imx8mm_pcie_enable_ref_clk(struct imx_pcie *imx_pcie, bool enable)
	regmap_update_bits(imx_pcie->iomuxc_gpr, offset,
			   IMX8MQ_GPR_PCIE_CLK_REQ_OVERRIDE_EN,
			   enable ? IMX8MQ_GPR_PCIE_CLK_REQ_OVERRIDE_EN : 0);
}

static int imx8mm_pcie_enable_ref_clk(struct imx_pcie *imx_pcie, bool enable)
{
	imx8mm_pcie_clkreq_override(imx_pcie, enable);
	return 0;
}

@@ -707,6 +718,32 @@ static int imx7d_pcie_enable_ref_clk(struct imx_pcie *imx_pcie, bool enable)
	return 0;
}

static void imx95_pcie_clkreq_override(struct imx_pcie *imx_pcie, bool enable)
{
	regmap_update_bits(imx_pcie->iomuxc_gpr, IMX95_PCIE_SS_RW_REG_1,
			   IMX95_PCIE_CLKREQ_OVERRIDE_EN,
			   enable ? IMX95_PCIE_CLKREQ_OVERRIDE_EN : 0);
	regmap_update_bits(imx_pcie->iomuxc_gpr, IMX95_PCIE_SS_RW_REG_1,
			   IMX95_PCIE_CLKREQ_OVERRIDE_VAL,
			   enable ? IMX95_PCIE_CLKREQ_OVERRIDE_VAL : 0);
}

static int imx95_pcie_enable_ref_clk(struct imx_pcie *imx_pcie, bool enable)
{
	imx95_pcie_clkreq_override(imx_pcie, enable);
	return 0;
}

static void imx8mm_pcie_clr_clkreq_override(struct imx_pcie *imx_pcie)
{
	imx8mm_pcie_clkreq_override(imx_pcie, false);
}

static void imx95_pcie_clr_clkreq_override(struct imx_pcie *imx_pcie)
{
	imx95_pcie_clkreq_override(imx_pcie, false);
}

static int imx_pcie_clk_enable(struct imx_pcie *imx_pcie)
{
	struct dw_pcie *pci = imx_pcie->pci;
@@ -1323,6 +1360,12 @@ static void imx_pcie_host_post_init(struct dw_pcie_rp *pp)
		dw_pcie_writel_dbi(pci, GEN3_RELATED_OFF, val);
		dw_pcie_dbi_ro_wr_dis(pci);
	}

	/* Clear CLKREQ# override if supports_clkreq is true and link is up */
	if (dw_pcie_link_up(pci) && imx_pcie->supports_clkreq) {
		if (imx_pcie->drvdata->clr_clkreq_override)
			imx_pcie->drvdata->clr_clkreq_override(imx_pcie);
	}
}

/*
@@ -1606,7 +1649,7 @@ static int imx_pcie_probe(struct platform_device *pdev)
	struct imx_pcie *imx_pcie;
	struct device_node *np;
	struct device_node *node = dev->of_node;
	int ret, domain;
	int i, ret, domain;
	u16 val;

	imx_pcie = devm_kzalloc(dev, sizeof(*imx_pcie), GFP_KERNEL);
@@ -1657,6 +1700,9 @@ static int imx_pcie_probe(struct platform_device *pdev)
	if (imx_pcie->num_clks < 0)
		return dev_err_probe(dev, imx_pcie->num_clks,
				     "failed to get clocks\n");
	for (i = 0; i < imx_pcie->num_clks; i++)
		if (strncmp(imx_pcie->clks[i].id, "extref", 6) == 0)
			imx_pcie->enable_ext_refclk = true;

	if (imx_check_flag(imx_pcie, IMX_PCIE_FLAG_HAS_PHYDRV)) {
		imx_pcie->phy = devm_phy_get(dev, "pcie-phy");
@@ -1744,6 +1790,7 @@ static int imx_pcie_probe(struct platform_device *pdev)
	/* Limit link speed */
	pci->max_link_speed = 1;
	of_property_read_u32(node, "fsl,max-link-speed", &pci->max_link_speed);
	imx_pcie->supports_clkreq = of_property_read_bool(node, "supports-clkreq");

	ret = devm_regulator_get_enable_optional(&pdev->dev, "vpcie3v3aux");
	if (ret < 0 && ret != -ENODEV)
@@ -1881,6 +1928,7 @@ static const struct imx_pcie_drvdata drvdata[] = {
		.mode_mask[1] = IMX8MQ_GPR12_PCIE2_CTRL_DEVICE_TYPE,
		.init_phy = imx8mq_pcie_init_phy,
		.enable_ref_clk = imx8mm_pcie_enable_ref_clk,
		.clr_clkreq_override = imx8mm_pcie_clr_clkreq_override,
	},
	[IMX8MM] = {
		.variant = IMX8MM,
@@ -1891,6 +1939,7 @@ static const struct imx_pcie_drvdata drvdata[] = {
		.mode_off[0] = IOMUXC_GPR12,
		.mode_mask[0] = IMX6Q_GPR12_DEVICE_TYPE,
		.enable_ref_clk = imx8mm_pcie_enable_ref_clk,
		.clr_clkreq_override = imx8mm_pcie_clr_clkreq_override,
	},
	[IMX8MP] = {
		.variant = IMX8MP,
@@ -1901,6 +1950,7 @@ static const struct imx_pcie_drvdata drvdata[] = {
		.mode_off[0] = IOMUXC_GPR12,
		.mode_mask[0] = IMX6Q_GPR12_DEVICE_TYPE,
		.enable_ref_clk = imx8mm_pcie_enable_ref_clk,
		.clr_clkreq_override = imx8mm_pcie_clr_clkreq_override,
	},
	[IMX8Q] = {
		.variant = IMX8Q,
@@ -1921,6 +1971,8 @@ static const struct imx_pcie_drvdata drvdata[] = {
		.core_reset = imx95_pcie_core_reset,
		.init_phy = imx95_pcie_init_phy,
		.wait_pll_lock = imx95_pcie_wait_for_phy_pll_lock,
		.enable_ref_clk = imx95_pcie_enable_ref_clk,
		.clr_clkreq_override = imx95_pcie_clr_clkreq_override,
	},
	[IMX8MQ_EP] = {
		.variant = IMX8MQ_EP,
@@ -1977,6 +2029,7 @@ static const struct imx_pcie_drvdata drvdata[] = {
		.core_reset = imx95_pcie_core_reset,
		.wait_pll_lock = imx95_pcie_wait_for_phy_pll_lock,
		.epc_features = &imx95_pcie_epc_features,
		.enable_ref_clk = imx95_pcie_enable_ref_clk,
		.mode = DW_PCIE_EP_TYPE,
	},
};
+3 −0
Original line number Diff line number Diff line
@@ -1317,6 +1317,9 @@ int dw_pcie_resume_noirq(struct dw_pcie *pci)
	if (ret)
		return ret;

	if (pci->pp.ops->post_init)
		pci->pp.ops->post_init(&pci->pp);

	return ret;
}
EXPORT_SYMBOL_GPL(dw_pcie_resume_noirq);