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
This commit is contained in:
Bjorn Helgaas 2025-01-23 13:05:03 -06:00
commit 5b9c74b635
4 changed files with 130 additions and 76 deletions

View File

@ -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

View File

@ -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

View File

@ -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:

View File

@ -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,16 +1304,27 @@ 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
* ================================================================================================
* BAR0 | Enable | 64-bit | 1 MB | Programmable Size
* BAR1 | Disable | 32-bit | 64 KB | Fixed Size
* BAR1 should be disabled if BAR0 is 64bit.
* BAR2 | Enable | 32-bit | 1 MB | Programmable Size
* BAR3 | Enable | 32-bit | 64 KB | Programmable Size
* BAR4 | Enable | 32-bit | 1M | Programmable Size
* BAR5 | Enable | 32-bit | 64 KB | Programmable Size
* | 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 64-bit)
* BAR2 | Enable | 32-bit | 1 MB | Programmable Size
* BAR3 | Enable | 32-bit | 64 KB | 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 = {
.msi_capable = true,
@ -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], },
{},
};