Commit 5b9c74b6 authored by Bjorn Helgaas's avatar Bjorn Helgaas
Browse files

Merge branch 'pci/controller/imx6'

- Add DT compatible string 'fsl,imx8q-pcie-ep' and driver support for
  i.MX8Q series (i.MX8QM, i.MX8QXP, and i.MX8DXL) Endpoints (Frank Li)

- Add DT binding for optional i.MX95 Refclk and driver support to enable it
  if the platform hasn't enabled it (Richard Zhu)

- Configure PHY based on controller being in Root Complex or Endpoint mode
  (Frank Li)

- Rely on dbi2 and iATU base addresses from DT via dw_pcie_get_resources()
  instead of hardcoding them in imx6 (Richard Zhu)

- Skip controller_id computation for i.MX7D since it only has one
  controller (Richard Zhu)

- Deassert apps_reset in imx_pcie_deassert_core_reset() since it is
  asserted in imx_pcie_assert_core_reset() (Richard Zhu)

- Add missing reference clock enable or disable logic for IMX6SX, IMX7D,
  IMX8MM (Richard Zhu)

- Remove redundant imx7d_pcie_init_phy() since imx7d_pcie_enable_ref_clk()
  does the same thing (Richard Zhu)

* pci/controller/imx6:
  PCI: imx6: Clean up comments and whitespace
  PCI: imx6: Remove surplus imx7d_pcie_init_phy() function
  PCI: imx6: Add missing reference clock disable logic
  PCI: imx6: Deassert apps_reset in imx_pcie_deassert_core_reset()
  PCI: imx6: Skip controller_id generation logic for i.MX7D
  PCI: imx6: Fetch dbi2 and iATU base addesses from DT
  PCI: imx6: Configure PHY based on Root Complex or Endpoint mode
  PCI: imx6: Add Refclk for i.MX95 PCIe
  dt-bindings: PCI: fsl,imx6q-pcie: Add Refclk for i.MX95 RC
  PCI: imx6: Add i.MX8Q PCIe Endpoint (EP) support
  dt-bindings: PCI: fsl,imx6q-pcie-ep: Add compatible string fsl,imx8q-pcie-ep

# Conflicts:
#	drivers/pci/controller/dwc/pci-imx6.c
parents 349b434b b8815329
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -17,11 +17,11 @@ description:
properties:
  clocks:
    minItems: 3
    maxItems: 4
    maxItems: 5

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

  num-lanes:
    const: 1
+38 −1
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@ properties:
      - fsl,imx8mm-pcie-ep
      - fsl,imx8mq-pcie-ep
      - fsl,imx8mp-pcie-ep
      - fsl,imx8q-pcie-ep
      - fsl,imx95-pcie-ep

  clocks:
@@ -74,6 +75,20 @@ allOf:
            - const: dbi2
            - const: atu

  - if:
      properties:
        compatible:
          enum:
            - fsl,imx8q-pcie-ep
    then:
      properties:
        reg:
          maxItems: 2
        reg-names:
          items:
            - const: dbi
            - const: addr_space

  - if:
      properties:
        compatible:
@@ -103,13 +118,21 @@ allOf:
      properties:
        clocks:
          minItems: 4
          maxItems: 4
        clock-names:
          items:
            - const: pcie
            - const: pcie_bus
            - const: pcie_phy
            - const: pcie_aux
    else:

  - if:
      properties:
        compatible:
          enum:
            - fsl,imx8mm-pcie-ep
            - fsl,imx8mp-pcie-ep
    then:
      properties:
        clocks:
          maxItems: 3
@@ -119,6 +142,20 @@ allOf:
            - const: pcie_bus
            - const: pcie_aux

  - if:
      properties:
        compatible:
          enum:
            - fsl,imxq-pcie-ep
    then:
      properties:
        clocks:
          maxItems: 3
        clock-names:
          items:
            - const: dbi
            - const: mstr
            - const: slv

unevaluatedProperties: false

+21 −4
Original line number Diff line number Diff line
@@ -40,10 +40,11 @@ properties:
      - description: PCIe PHY clock.
      - description: Additional required clock entry for imx6sx-pcie,
           imx6sx-pcie-ep, imx8mq-pcie, imx8mq-pcie-ep.
      - description: PCIe reference clock.

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

  interrupts:
    items:
@@ -127,7 +128,7 @@ allOf:
    then:
      properties:
        clocks:
          minItems: 4
          maxItems: 4
        clock-names:
          items:
            - const: pcie
@@ -140,11 +141,10 @@ allOf:
        compatible:
          enum:
            - fsl,imx8mq-pcie
            - fsl,imx95-pcie
    then:
      properties:
        clocks:
          minItems: 4
          maxItems: 4
        clock-names:
          items:
            - const: pcie
@@ -200,6 +200,23 @@ allOf:
            - const: mstr
            - const: slv

  - if:
      properties:
        compatible:
          enum:
            - fsl,imx95-pcie
    then:
      properties:
        clocks:
          maxItems: 5
        clock-names:
          items:
            - const: pcie
            - const: pcie_bus
            - const: pcie_phy
            - const: pcie_aux
            - const: ref

unevaluatedProperties: false

examples:
+69 −69
Original line number Diff line number Diff line
@@ -87,6 +87,7 @@ enum imx_pcie_variants {
	IMX8MQ_EP,
	IMX8MM_EP,
	IMX8MP_EP,
	IMX8Q_EP,
	IMX95_EP,
};

@@ -121,6 +122,7 @@ struct imx_pcie_drvdata {
	const char *gpr;
	const char * const *clk_names;
	const u32 clks_cnt;
	const u32 clks_optional_cnt;
	const u32 ltssm_off;
	const u32 ltssm_mask;
	const u32 mode_off[IMX_PCIE_MAX_INSTANCES];
@@ -254,11 +256,11 @@ static void imx_pcie_configure_type(struct imx_pcie *imx_pcie)

	id = imx_pcie->controller_id;

	/* If mode_mask is 0, then generic PHY driver is used to set the mode */
	/* If mode_mask is 0, generic PHY driver is used to set the mode */
	if (!drvdata->mode_mask[0])
		return;

	/* If mode_mask[id] is zero, means each controller have its individual gpr */
	/* If mode_mask[id] is 0, each controller has its individual GPR */
	if (!drvdata->mode_mask[id])
		id = 0;

@@ -395,14 +397,15 @@ static int pcie_phy_write(struct imx_pcie *imx_pcie, int addr, u16 data)

static int imx8mq_pcie_init_phy(struct imx_pcie *imx_pcie)
{
	/* TODO: Currently this code assumes external oscillator is being used */
	/* TODO: This code assumes external oscillator is being used */
	regmap_update_bits(imx_pcie->iomuxc_gpr,
			   imx_pcie_grp_offset(imx_pcie),
			   IMX8MQ_GPR_PCIE_REF_USE_PAD,
			   IMX8MQ_GPR_PCIE_REF_USE_PAD);
	/*
	 * Regarding the datasheet, the PCIE_VPH is suggested to be 1.8V. If the PCIE_VPH is
	 * supplied by 3.3V, the VREG_BYPASS should be cleared to zero.
	 * Per the datasheet, the PCIE_VPH is suggested to be 1.8V.  If the
	 * PCIE_VPH is supplied by 3.3V, the VREG_BYPASS should be cleared
	 * to zero.
	 */
	if (imx_pcie->vph && regulator_get_voltage(imx_pcie->vph) > 3000000)
		regmap_update_bits(imx_pcie->iomuxc_gpr,
@@ -413,13 +416,6 @@ static int imx8mq_pcie_init_phy(struct imx_pcie *imx_pcie)
	return 0;
}

static int imx7d_pcie_init_phy(struct imx_pcie *imx_pcie)
{
	regmap_update_bits(imx_pcie->iomuxc_gpr, IOMUXC_GPR12, IMX7D_GPR12_PCIE_PHY_REFCLK_SEL, 0);

	return 0;
}

static int imx_pcie_init_phy(struct imx_pcie *imx_pcie)
{
	regmap_update_bits(imx_pcie->iomuxc_gpr, IOMUXC_GPR12,
@@ -596,7 +592,7 @@ static int imx_pcie_attach_pd(struct device *dev)
			DL_FLAG_PM_RUNTIME |
			DL_FLAG_RPM_ACTIVE);
	if (!link) {
		dev_err(dev, "Failed to add device_link to pcie pd.\n");
		dev_err(dev, "Failed to add device_link to pcie pd\n");
		return -EINVAL;
	}

@@ -609,7 +605,7 @@ static int imx_pcie_attach_pd(struct device *dev)
			DL_FLAG_PM_RUNTIME |
			DL_FLAG_RPM_ACTIVE);
	if (!link) {
		dev_err(dev, "Failed to add device_link to pcie_phy pd.\n");
		dev_err(dev, "Failed to add device_link to pcie_phy pd\n");
		return -EINVAL;
	}

@@ -618,10 +614,9 @@ static int imx_pcie_attach_pd(struct device *dev)

static int imx6sx_pcie_enable_ref_clk(struct imx_pcie *imx_pcie, bool enable)
{
	if (enable)
		regmap_clear_bits(imx_pcie->iomuxc_gpr, IOMUXC_GPR12,
				  IMX6SX_GPR12_PCIE_TEST_POWERDOWN);

	regmap_update_bits(imx_pcie->iomuxc_gpr, IOMUXC_GPR12,
			   IMX6SX_GPR12_PCIE_TEST_POWERDOWN,
			   enable ? 0 : IMX6SX_GPR12_PCIE_TEST_POWERDOWN);
	return 0;
}

@@ -631,10 +626,10 @@ static int imx6q_pcie_enable_ref_clk(struct imx_pcie *imx_pcie, bool enable)
		/* power up core phy and enable ref clock */
		regmap_clear_bits(imx_pcie->iomuxc_gpr, IOMUXC_GPR1, IMX6Q_GPR1_PCIE_TEST_PD);
		/*
		 * the async reset input need ref clock to sync internally,
		 * The async reset input need ref clock to sync internally,
		 * when the ref clock comes after reset, internal synced
		 * reset time is too short, cannot meet the requirement.
		 * add one ~10us delay here.
		 * Add a ~10us delay here.
		 */
		usleep_range(10, 100);
		regmap_set_bits(imx_pcie->iomuxc_gpr, IOMUXC_GPR1, IMX6Q_GPR1_PCIE_REF_CLK_EN);
@@ -650,19 +645,20 @@ static int imx8mm_pcie_enable_ref_clk(struct imx_pcie *imx_pcie, bool enable)
{
	int offset = imx_pcie_grp_offset(imx_pcie);

	if (enable) {
		regmap_clear_bits(imx_pcie->iomuxc_gpr, offset, IMX8MQ_GPR_PCIE_CLK_REQ_OVERRIDE);
		regmap_set_bits(imx_pcie->iomuxc_gpr, offset, IMX8MQ_GPR_PCIE_CLK_REQ_OVERRIDE_EN);
	}

	regmap_update_bits(imx_pcie->iomuxc_gpr, offset,
			   IMX8MQ_GPR_PCIE_CLK_REQ_OVERRIDE,
			   enable ? 0 : IMX8MQ_GPR_PCIE_CLK_REQ_OVERRIDE);
	regmap_update_bits(imx_pcie->iomuxc_gpr, offset,
			   IMX8MQ_GPR_PCIE_CLK_REQ_OVERRIDE_EN,
			   enable ? IMX8MQ_GPR_PCIE_CLK_REQ_OVERRIDE_EN : 0);
	return 0;
}

static int imx7d_pcie_enable_ref_clk(struct imx_pcie *imx_pcie, bool enable)
{
	if (!enable)
		regmap_set_bits(imx_pcie->iomuxc_gpr, IOMUXC_GPR12,
				IMX7D_GPR12_PCIE_PHY_REFCLK_SEL);
	regmap_update_bits(imx_pcie->iomuxc_gpr, IOMUXC_GPR12,
			   IMX7D_GPR12_PCIE_PHY_REFCLK_SEL,
			   enable ? 0 : IMX7D_GPR12_PCIE_PHY_REFCLK_SEL);
	return 0;
}

@@ -795,6 +791,7 @@ static void imx_pcie_assert_core_reset(struct imx_pcie *imx_pcie)
static int imx_pcie_deassert_core_reset(struct imx_pcie *imx_pcie)
{
	reset_control_deassert(imx_pcie->pciephy_reset);
	reset_control_deassert(imx_pcie->apps_reset);

	if (imx_pcie->drvdata->core_reset)
		imx_pcie->drvdata->core_reset(imx_pcie, false);
@@ -904,6 +901,7 @@ static int imx_pcie_start_link(struct dw_pcie *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
@@ -912,7 +910,6 @@ static int imx_pcie_start_link(struct dw_pcie *pci)
			 * 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");
@@ -1167,7 +1164,9 @@ static int imx_pcie_host_init(struct dw_pcie_rp *pp)
			goto err_clk_disable;
		}

		ret = phy_set_mode_ext(imx_pcie->phy, PHY_MODE_PCIE, PHY_MODE_PCIE_RC);
		ret = phy_set_mode_ext(imx_pcie->phy, PHY_MODE_PCIE,
				       imx_pcie->drvdata->mode == DW_PCIE_EP_TYPE ?
						PHY_MODE_PCIE_EP : PHY_MODE_PCIE_RC);
		if (ret) {
			dev_err(dev, "unable to set PCIe PHY mode\n");
			goto err_phy_exit;
@@ -1305,15 +1304,26 @@ static const struct pci_epc_features imx8m_pcie_epc_features = {
	.align = SZ_64K,
};

static const struct pci_epc_features imx8q_pcie_epc_features = {
	.linkup_notifier = false,
	.msi_capable = true,
	.msix_capable = false,
	.bar[BAR_1] = { .type = BAR_RESERVED, },
	.bar[BAR_3] = { .type = BAR_RESERVED, },
	.bar[BAR_5] = { .type = BAR_RESERVED, },
	.align = SZ_64K,
};

/*
 * BAR#	| Default BAR enable	| Default BAR Type	| Default BAR Size	| BAR Sizing Scheme
 * ================================================================================================
 *     	| Default  | Default | Default | BAR Sizing
 * BAR#	| Enable?  | Type    | Size    | Scheme
 * =======================================================
 * BAR0	| Enable   | 64-bit  |  1 MB   | Programmable Size
 * BAR1	| Disable  | 32-bit  | 64 KB   | Fixed Size
 *        BAR1 should be disabled if BAR0 is 64bit.
 *       (BAR1 should be disabled if BAR0 is 64-bit)
 * BAR2	| Enable   | 32-bit  |  1 MB   | Programmable Size
 * BAR3	| Enable   | 32-bit  | 64 KB   | Programmable Size
 * BAR4	| Enable		| 32-bit		| 1M			| Programmable Size
 * BAR4	| Enable   | 32-bit  |  1 MB   | Programmable Size
 * BAR5	| Enable   | 32-bit  | 64 KB   | Programmable Size
 */
static const struct pci_epc_features imx95_pcie_epc_features = {
@@ -1341,7 +1351,6 @@ static int imx_add_pcie_ep(struct imx_pcie *imx_pcie,
			   struct platform_device *pdev)
{
	int ret;
	unsigned int pcie_dbi2_offset;
	struct dw_pcie_ep *ep;
	struct dw_pcie *pci = imx_pcie->pci;
	struct dw_pcie_rp *pp = &pci->pp;
@@ -1351,28 +1360,6 @@ static int imx_add_pcie_ep(struct imx_pcie *imx_pcie,
	ep = &pci->ep;
	ep->ops = &pcie_ep_ops;

	switch (imx_pcie->drvdata->variant) {
	case IMX8MQ_EP:
	case IMX8MM_EP:
	case IMX8MP_EP:
		pcie_dbi2_offset = SZ_1M;
		break;
	default:
		pcie_dbi2_offset = SZ_4K;
		break;
	}

	pci->dbi_base2 = pci->dbi_base + pcie_dbi2_offset;

	/*
	 * FIXME: Ideally, dbi2 base address should come from DT. But since only IMX95 is defining
	 * "dbi2" in DT, "dbi_base2" is set to NULL here for that platform alone so that the DWC
	 * core code can fetch that from DT. But once all platform DTs were fixed, this and the
	 * above "dbi_base2" setting should be removed.
	 */
	if (device_property_match_string(dev, "reg-names", "dbi2") >= 0)
		pci->dbi_base2 = NULL;

	if (imx_check_flag(imx_pcie, IMX_PCIE_FLAG_SUPPORT_64BIT))
		dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64));

@@ -1457,6 +1444,7 @@ static int imx_pcie_resume_noirq(struct device *dev)
		ret = imx_pcie_deassert_core_reset(imx_pcie);
		if (ret)
			return ret;

		/*
		 * Using PCIE_TEST_PD seems to disable MSI and powers down the
		 * root complex. This is why we have to setup the rc again and
@@ -1488,9 +1476,8 @@ static int imx_pcie_probe(struct platform_device *pdev)
	struct device_node *np;
	struct resource *dbi_base;
	struct device_node *node = dev->of_node;
	int ret;
	int i, ret, req_cnt;
	u16 val;
	int i;

	imx_pcie = devm_kzalloc(dev, sizeof(*imx_pcie), GFP_KERNEL);
	if (!imx_pcie)
@@ -1546,9 +1533,13 @@ static int imx_pcie_probe(struct platform_device *pdev)
		imx_pcie->clks[i].id = imx_pcie->drvdata->clk_names[i];

	/* Fetch clocks */
	ret = devm_clk_bulk_get(dev, imx_pcie->drvdata->clks_cnt, imx_pcie->clks);
	req_cnt = imx_pcie->drvdata->clks_cnt - imx_pcie->drvdata->clks_optional_cnt;
	ret = devm_clk_bulk_get(dev, req_cnt, imx_pcie->clks);
	if (ret)
		return ret;
	imx_pcie->clks[req_cnt].clk = devm_clk_get_optional(dev, "ref");
	if (IS_ERR(imx_pcie->clks[req_cnt].clk))
		return PTR_ERR(imx_pcie->clks[req_cnt].clk);

	if (imx_check_flag(imx_pcie, IMX_PCIE_FLAG_HAS_PHYDRV)) {
		imx_pcie->phy = devm_phy_get(dev, "pcie-phy");
@@ -1574,7 +1565,6 @@ static int imx_pcie_probe(struct platform_device *pdev)
	switch (imx_pcie->drvdata->variant) {
	case IMX8MQ:
	case IMX8MQ_EP:
	case IMX7D:
		if (dbi_base->start == IMX8MQ_PCIE2_BASE_ADDR)
			imx_pcie->controller_id = 1;
		break;
@@ -1690,6 +1680,7 @@ static const char * const imx8mm_clks[] = {"pcie_bus", "pcie", "pcie_aux"};
static const char * const imx8mq_clks[] = {"pcie_bus", "pcie", "pcie_phy", "pcie_aux"};
static const char * const imx6sx_clks[] = {"pcie_bus", "pcie", "pcie_phy", "pcie_inbound_axi"};
static const char * const imx8q_clks[] = {"mstr", "slv", "dbi"};
static const char * const imx95_clks[] = {"pcie_bus", "pcie", "pcie_phy", "pcie_aux", "ref"};

static const struct imx_pcie_drvdata drvdata[] = {
	[IMX6Q] = {
@@ -1755,7 +1746,6 @@ static const struct imx_pcie_drvdata drvdata[] = {
		.clks_cnt = ARRAY_SIZE(imx6q_clks),
		.mode_off[0] = IOMUXC_GPR12,
		.mode_mask[0] = IMX6Q_GPR12_DEVICE_TYPE,
		.init_phy = imx7d_pcie_init_phy,
		.enable_ref_clk = imx7d_pcie_enable_ref_clk,
		.core_reset = imx7d_pcie_core_reset,
	},
@@ -1811,8 +1801,9 @@ static const struct imx_pcie_drvdata drvdata[] = {
		.flags = IMX_PCIE_FLAG_HAS_SERDES |
			 IMX_PCIE_FLAG_HAS_LUT |
			 IMX_PCIE_FLAG_SUPPORTS_SUSPEND,
		.clk_names = imx8mq_clks,
		.clks_cnt = ARRAY_SIZE(imx8mq_clks),
		.clk_names = imx95_clks,
		.clks_cnt = ARRAY_SIZE(imx95_clks),
		.clks_optional_cnt = 1,
		.ltssm_off = IMX95_PE0_GEN_CTRL_3,
		.ltssm_mask = IMX95_PCIE_LTSSM_EN,
		.mode_off[0]  = IMX95_PE0_GEN_CTRL_1,
@@ -1861,6 +1852,14 @@ static const struct imx_pcie_drvdata drvdata[] = {
		.epc_features = &imx8m_pcie_epc_features,
		.enable_ref_clk = imx8mm_pcie_enable_ref_clk,
	},
	[IMX8Q_EP] = {
		.variant = IMX8Q_EP,
		.flags = IMX_PCIE_FLAG_HAS_PHYDRV,
		.mode = DW_PCIE_EP_TYPE,
		.epc_features = &imx8q_pcie_epc_features,
		.clk_names = imx8q_clks,
		.clks_cnt = ARRAY_SIZE(imx8q_clks),
	},
	[IMX95_EP] = {
		.variant = IMX95_EP,
		.flags = IMX_PCIE_FLAG_HAS_SERDES |
@@ -1890,6 +1889,7 @@ static const struct of_device_id imx_pcie_of_match[] = {
	{ .compatible = "fsl,imx8mq-pcie-ep", .data = &drvdata[IMX8MQ_EP], },
	{ .compatible = "fsl,imx8mm-pcie-ep", .data = &drvdata[IMX8MM_EP], },
	{ .compatible = "fsl,imx8mp-pcie-ep", .data = &drvdata[IMX8MP_EP], },
	{ .compatible = "fsl,imx8q-pcie-ep", .data = &drvdata[IMX8Q_EP], },
	{ .compatible = "fsl,imx95-pcie-ep", .data = &drvdata[IMX95_EP], },
	{},
};