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

PCI: imx6: Add i.MX PCIe EP mode support

i.MX PCIe is one dual mode PCIe controller.

Add i.MX PCIe EP mode support here, and split the PCIe modes to the Root
Complex mode and Endpoint mode.

Link: https://lore.kernel.org/r/1673847684-31893-12-git-send-email-hongxing.zhu@nxp.com
Signed-off-by: Richard Zhu <hongxing.zhu@nxp.com>
Signed-off-by: Lorenzo Pieralisi <lpieralisi@kernel.org>

authored by

Richard Zhu and committed by
Lorenzo Pieralisi
75c2f26d 01ea5ede

+137 -14
+22 -1
drivers/pci/controller/dwc/Kconfig
··· 92 92 functions to implement the driver. 93 93 94 94 config PCI_IMX6 95 - bool "Freescale i.MX6/7/8 PCIe controller" 95 + bool 96 + 97 + config PCI_IMX6_HOST 98 + bool "Freescale i.MX6/7/8 PCIe controller host mode" 96 99 depends on ARCH_MXC || COMPILE_TEST 97 100 depends on PCI_MSI 98 101 select PCIE_DW_HOST 102 + select PCI_IMX6 103 + help 104 + Enables support for the PCIe controller in the i.MX SoCs to 105 + work in Root Complex mode. The PCI controller on i.MX is based 106 + on DesignWare hardware and therefore the driver re-uses the 107 + DesignWare core functions to implement the driver. 108 + 109 + config PCI_IMX6_EP 110 + bool "Freescale i.MX6/7/8 PCIe controller endpoint mode" 111 + depends on ARCH_MXC || COMPILE_TEST 112 + depends on PCI_ENDPOINT 113 + select PCIE_DW_EP 114 + select PCI_IMX6 115 + help 116 + Enables support for the PCIe controller in the i.MX SoCs to 117 + work in endpoint mode. The PCI controller on i.MX is based 118 + on DesignWare hardware and therefore the driver re-uses the 119 + DesignWare core functions to implement the driver. 99 120 100 121 config PCIE_SPEAR13XX 101 122 bool "STMicroelectronics SPEAr PCIe controller"
+115 -13
drivers/pci/controller/dwc/pci-imx6.c
··· 60 60 61 61 struct imx6_pcie_drvdata { 62 62 enum imx6_pcie_variants variant; 63 + enum dw_pcie_device_mode mode; 63 64 u32 flags; 64 65 int dbi_length; 65 66 const char *gpr; ··· 160 159 161 160 static void imx6_pcie_configure_type(struct imx6_pcie *imx6_pcie) 162 161 { 163 - unsigned int mask, val; 162 + unsigned int mask, val, mode; 163 + 164 + if (imx6_pcie->drvdata->mode == DW_PCIE_EP_TYPE) 165 + mode = PCI_EXP_TYPE_ENDPOINT; 166 + else 167 + mode = PCI_EXP_TYPE_ROOT_PORT; 164 168 165 169 if (imx6_pcie->drvdata->variant == IMX8MQ && 166 170 imx6_pcie->controller_id == 1) { 167 171 mask = IMX8MQ_GPR12_PCIE2_CTRL_DEVICE_TYPE; 168 - val = FIELD_PREP(IMX8MQ_GPR12_PCIE2_CTRL_DEVICE_TYPE, 169 - PCI_EXP_TYPE_ROOT_PORT); 172 + val = FIELD_PREP(IMX8MQ_GPR12_PCIE2_CTRL_DEVICE_TYPE, mode); 170 173 } else { 171 174 mask = IMX6Q_GPR12_DEVICE_TYPE; 172 - val = FIELD_PREP(IMX6Q_GPR12_DEVICE_TYPE, 173 - PCI_EXP_TYPE_ROOT_PORT); 175 + val = FIELD_PREP(IMX6Q_GPR12_DEVICE_TYPE, mode); 174 176 } 175 177 176 178 regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12, mask, val); ··· 1007 1003 1008 1004 static const struct dw_pcie_ops dw_pcie_ops = { 1009 1005 .start_link = imx6_pcie_start_link, 1006 + .stop_link = imx6_pcie_stop_link, 1010 1007 }; 1008 + 1009 + static void imx6_pcie_ep_init(struct dw_pcie_ep *ep) 1010 + { 1011 + enum pci_barno bar; 1012 + struct dw_pcie *pci = to_dw_pcie_from_ep(ep); 1013 + 1014 + for (bar = BAR_0; bar <= BAR_5; bar++) 1015 + dw_pcie_ep_reset_bar(pci, bar); 1016 + } 1017 + 1018 + static int imx6_pcie_ep_raise_irq(struct dw_pcie_ep *ep, u8 func_no, 1019 + enum pci_epc_irq_type type, 1020 + u16 interrupt_num) 1021 + { 1022 + struct dw_pcie *pci = to_dw_pcie_from_ep(ep); 1023 + 1024 + switch (type) { 1025 + case PCI_EPC_IRQ_LEGACY: 1026 + return dw_pcie_ep_raise_legacy_irq(ep, func_no); 1027 + case PCI_EPC_IRQ_MSI: 1028 + return dw_pcie_ep_raise_msi_irq(ep, func_no, interrupt_num); 1029 + case PCI_EPC_IRQ_MSIX: 1030 + return dw_pcie_ep_raise_msix_irq(ep, func_no, interrupt_num); 1031 + default: 1032 + dev_err(pci->dev, "UNKNOWN IRQ type\n"); 1033 + return -EINVAL; 1034 + } 1035 + 1036 + return 0; 1037 + } 1038 + 1039 + static const struct pci_epc_features imx8m_pcie_epc_features = { 1040 + .linkup_notifier = false, 1041 + .msi_capable = true, 1042 + .msix_capable = false, 1043 + .reserved_bar = 1 << BAR_1 | 1 << BAR_3, 1044 + .align = SZ_64K, 1045 + }; 1046 + 1047 + static const struct pci_epc_features* 1048 + imx6_pcie_ep_get_features(struct dw_pcie_ep *ep) 1049 + { 1050 + return &imx8m_pcie_epc_features; 1051 + } 1052 + 1053 + static const struct dw_pcie_ep_ops pcie_ep_ops = { 1054 + .ep_init = imx6_pcie_ep_init, 1055 + .raise_irq = imx6_pcie_ep_raise_irq, 1056 + .get_features = imx6_pcie_ep_get_features, 1057 + }; 1058 + 1059 + static int imx6_add_pcie_ep(struct imx6_pcie *imx6_pcie, 1060 + struct platform_device *pdev) 1061 + { 1062 + int ret; 1063 + unsigned int pcie_dbi2_offset; 1064 + struct dw_pcie_ep *ep; 1065 + struct resource *res; 1066 + struct dw_pcie *pci = imx6_pcie->pci; 1067 + struct dw_pcie_rp *pp = &pci->pp; 1068 + struct device *dev = pci->dev; 1069 + 1070 + imx6_pcie_host_init(pp); 1071 + ep = &pci->ep; 1072 + ep->ops = &pcie_ep_ops; 1073 + 1074 + switch (imx6_pcie->drvdata->variant) { 1075 + default: 1076 + pcie_dbi2_offset = SZ_4K; 1077 + break; 1078 + } 1079 + pci->dbi_base2 = pci->dbi_base + pcie_dbi2_offset; 1080 + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "addr_space"); 1081 + if (!res) 1082 + return -EINVAL; 1083 + 1084 + ep->phys_base = res->start; 1085 + ep->addr_size = resource_size(res); 1086 + ep->page_size = SZ_64K; 1087 + 1088 + ret = dw_pcie_ep_init(ep); 1089 + if (ret) { 1090 + dev_err(dev, "failed to initialize endpoint\n"); 1091 + return ret; 1092 + } 1093 + /* Start LTSSM. */ 1094 + imx6_pcie_ltssm_enable(dev); 1095 + 1096 + return 0; 1097 + } 1011 1098 1012 1099 static void imx6_pcie_pm_turnoff(struct imx6_pcie *imx6_pcie) 1013 1100 { ··· 1374 1279 if (ret) 1375 1280 return ret; 1376 1281 1377 - ret = dw_pcie_host_init(&pci->pp); 1378 - if (ret < 0) 1379 - return ret; 1282 + if (imx6_pcie->drvdata->mode == DW_PCIE_EP_TYPE) { 1283 + ret = imx6_add_pcie_ep(imx6_pcie, pdev); 1284 + if (ret < 0) 1285 + return ret; 1286 + } else { 1287 + ret = dw_pcie_host_init(&pci->pp); 1288 + if (ret < 0) 1289 + return ret; 1380 1290 1381 - if (pci_msi_enabled()) { 1382 - u8 offset = dw_pcie_find_capability(pci, PCI_CAP_ID_MSI); 1383 - val = dw_pcie_readw_dbi(pci, offset + PCI_MSI_FLAGS); 1384 - val |= PCI_MSI_FLAGS_ENABLE; 1385 - dw_pcie_writew_dbi(pci, offset + PCI_MSI_FLAGS, val); 1291 + if (pci_msi_enabled()) { 1292 + u8 offset = dw_pcie_find_capability(pci, PCI_CAP_ID_MSI); 1293 + 1294 + val = dw_pcie_readw_dbi(pci, offset + PCI_MSI_FLAGS); 1295 + val |= PCI_MSI_FLAGS_ENABLE; 1296 + dw_pcie_writew_dbi(pci, offset + PCI_MSI_FLAGS, val); 1297 + } 1386 1298 } 1387 1299 1388 1300 return 0;