Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

PCI: imx: Add the imx8mm pcie support

i.MX8MM PCIe works mostly like the i.MX8MQ one, but has a different PHY
and allows to output the internal PHY reference clock via the refclk pad.
Add the i.MX8MM PCIe support based on the standalone PHY driver.

Link: https://lore.kernel.org/r/1640312885-31142-2-git-send-email-hongxing.zhu@nxp.com
Tested-by: Marcel Ziswiler <marcel.ziswiler@toradex.com>
Tested-by: Tim Harvey <tharvey@gateworks.com>
Signed-off-by: Richard Zhu <hongxing.zhu@nxp.com>
Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Reviewed-by: Tim Harvey <tharvey@gateworks.com>

authored by

Richard Zhu and committed by
Lorenzo Pieralisi
178e244c 3e15f623

+73 -8
+73 -8
drivers/pci/controller/dwc/pci-imx6.c
··· 29 29 #include <linux/types.h> 30 30 #include <linux/interrupt.h> 31 31 #include <linux/reset.h> 32 + #include <linux/phy/phy.h> 32 33 #include <linux/pm_domain.h> 33 34 #include <linux/pm_runtime.h> 34 35 ··· 50 49 IMX6QP, 51 50 IMX7D, 52 51 IMX8MQ, 52 + IMX8MM, 53 53 }; 54 54 55 55 #define IMX6_PCIE_FLAG_IMX6_PHY BIT(0) ··· 90 88 struct device *pd_pcie; 91 89 /* power domain for pcie phy */ 92 90 struct device *pd_pcie_phy; 91 + struct phy *phy; 93 92 const struct imx6_pcie_drvdata *drvdata; 94 93 }; 95 94 ··· 375 372 case IMX7D: 376 373 case IMX8MQ: 377 374 reset_control_assert(imx6_pcie->pciephy_reset); 375 + fallthrough; 376 + case IMX8MM: 378 377 reset_control_assert(imx6_pcie->apps_reset); 379 378 break; 380 379 case IMX6SX: ··· 412 407 413 408 static unsigned int imx6_pcie_grp_offset(const struct imx6_pcie *imx6_pcie) 414 409 { 415 - WARN_ON(imx6_pcie->drvdata->variant != IMX8MQ); 410 + WARN_ON(imx6_pcie->drvdata->variant != IMX8MQ && 411 + imx6_pcie->drvdata->variant != IMX8MM); 416 412 return imx6_pcie->controller_id == 1 ? IOMUXC_GPR16 : IOMUXC_GPR14; 417 413 } 418 414 ··· 451 445 IMX6Q_GPR1_PCIE_REF_CLK_EN, 1 << 16); 452 446 break; 453 447 case IMX7D: 448 + break; 449 + case IMX8MM: 450 + ret = clk_prepare_enable(imx6_pcie->pcie_aux); 451 + if (ret) 452 + dev_err(dev, "unable to enable pcie_aux clock\n"); 454 453 break; 455 454 case IMX8MQ: 456 455 ret = clk_prepare_enable(imx6_pcie->pcie_aux); ··· 533 522 goto err_ref_clk; 534 523 } 535 524 525 + switch (imx6_pcie->drvdata->variant) { 526 + case IMX8MM: 527 + if (phy_power_on(imx6_pcie->phy)) 528 + dev_err(dev, "unable to power on PHY\n"); 529 + break; 530 + default: 531 + break; 532 + } 536 533 /* allow the clocks to stabilize */ 537 534 usleep_range(200, 500); 538 535 ··· 556 537 switch (imx6_pcie->drvdata->variant) { 557 538 case IMX8MQ: 558 539 reset_control_deassert(imx6_pcie->pciephy_reset); 540 + break; 541 + case IMX8MM: 542 + if (phy_init(imx6_pcie->phy)) 543 + dev_err(dev, "waiting for phy ready timeout!\n"); 559 544 break; 560 545 case IMX7D: 561 546 reset_control_deassert(imx6_pcie->pciephy_reset); ··· 637 614 static void imx6_pcie_init_phy(struct imx6_pcie *imx6_pcie) 638 615 { 639 616 switch (imx6_pcie->drvdata->variant) { 617 + case IMX8MM: 618 + /* 619 + * The PHY initialization had been done in the PHY 620 + * driver, break here directly. 621 + */ 622 + break; 640 623 case IMX8MQ: 641 624 /* 642 625 * TODO: Currently this code assumes external ··· 782 753 break; 783 754 case IMX7D: 784 755 case IMX8MQ: 756 + case IMX8MM: 785 757 reset_control_deassert(imx6_pcie->apps_reset); 786 758 break; 787 759 } ··· 901 871 IMX6Q_GPR12_PCIE_CTL_2, 0); 902 872 break; 903 873 case IMX7D: 874 + case IMX8MM: 904 875 reset_control_assert(imx6_pcie->apps_reset); 905 876 break; 906 877 default: ··· 961 930 IMX7D_GPR12_PCIE_PHY_REFCLK_SEL); 962 931 break; 963 932 case IMX8MQ: 933 + case IMX8MM: 964 934 clk_disable_unprepare(imx6_pcie->pcie_aux); 965 935 break; 966 936 default: ··· 977 945 return 0; 978 946 979 947 imx6_pcie_pm_turnoff(imx6_pcie); 980 - imx6_pcie_clk_disable(imx6_pcie); 981 948 imx6_pcie_ltssm_disable(dev); 949 + imx6_pcie_clk_disable(imx6_pcie); 950 + switch (imx6_pcie->drvdata->variant) { 951 + case IMX8MM: 952 + if (phy_power_off(imx6_pcie->phy)) 953 + dev_err(dev, "unable to power off PHY\n"); 954 + break; 955 + default: 956 + break; 957 + } 982 958 983 959 return 0; 984 960 } ··· 1083 1043 } 1084 1044 1085 1045 /* Fetch clocks */ 1086 - imx6_pcie->pcie_phy = devm_clk_get(dev, "pcie_phy"); 1087 - if (IS_ERR(imx6_pcie->pcie_phy)) 1088 - return dev_err_probe(dev, PTR_ERR(imx6_pcie->pcie_phy), 1089 - "pcie_phy clock source missing or invalid\n"); 1090 - 1091 1046 imx6_pcie->pcie_bus = devm_clk_get(dev, "pcie_bus"); 1092 1047 if (IS_ERR(imx6_pcie->pcie_bus)) 1093 1048 return dev_err_probe(dev, PTR_ERR(imx6_pcie->pcie_bus), ··· 1125 1090 return PTR_ERR(imx6_pcie->apps_reset); 1126 1091 } 1127 1092 break; 1093 + case IMX8MM: 1094 + imx6_pcie->pcie_aux = devm_clk_get(dev, "pcie_aux"); 1095 + if (IS_ERR(imx6_pcie->pcie_aux)) 1096 + return dev_err_probe(dev, PTR_ERR(imx6_pcie->pcie_aux), 1097 + "pcie_aux clock source missing or invalid\n"); 1098 + imx6_pcie->apps_reset = devm_reset_control_get_exclusive(dev, 1099 + "apps"); 1100 + if (IS_ERR(imx6_pcie->apps_reset)) 1101 + return dev_err_probe(dev, PTR_ERR(imx6_pcie->apps_reset), 1102 + "failed to get pcie apps reset control\n"); 1103 + 1104 + imx6_pcie->phy = devm_phy_get(dev, "pcie-phy"); 1105 + if (IS_ERR(imx6_pcie->phy)) 1106 + return dev_err_probe(dev, PTR_ERR(imx6_pcie->phy), 1107 + "failed to get pcie phy\n"); 1108 + 1109 + break; 1128 1110 default: 1129 1111 break; 1130 1112 } 1113 + /* Don't fetch the pcie_phy clock, if it has abstract PHY driver */ 1114 + if (imx6_pcie->phy == NULL) { 1115 + imx6_pcie->pcie_phy = devm_clk_get(dev, "pcie_phy"); 1116 + if (IS_ERR(imx6_pcie->pcie_phy)) 1117 + return dev_err_probe(dev, PTR_ERR(imx6_pcie->pcie_phy), 1118 + "pcie_phy clock source missing or invalid\n"); 1119 + } 1120 + 1131 1121 1132 1122 /* Grab turnoff reset */ 1133 1123 imx6_pcie->turnoff_reset = devm_reset_control_get_optional_exclusive(dev, "turnoff"); ··· 1262 1202 [IMX8MQ] = { 1263 1203 .variant = IMX8MQ, 1264 1204 }, 1205 + [IMX8MM] = { 1206 + .variant = IMX8MM, 1207 + .flags = IMX6_PCIE_FLAG_SUPPORTS_SUSPEND, 1208 + }, 1265 1209 }; 1266 1210 1267 1211 static const struct of_device_id imx6_pcie_of_match[] = { ··· 1273 1209 { .compatible = "fsl,imx6sx-pcie", .data = &drvdata[IMX6SX], }, 1274 1210 { .compatible = "fsl,imx6qp-pcie", .data = &drvdata[IMX6QP], }, 1275 1211 { .compatible = "fsl,imx7d-pcie", .data = &drvdata[IMX7D], }, 1276 - { .compatible = "fsl,imx8mq-pcie", .data = &drvdata[IMX8MQ], } , 1212 + { .compatible = "fsl,imx8mq-pcie", .data = &drvdata[IMX8MQ], }, 1213 + { .compatible = "fsl,imx8mm-pcie", .data = &drvdata[IMX8MM], }, 1277 1214 {}, 1278 1215 }; 1279 1216