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

PCI: cadence: Add generic PHY support to host and EP drivers

If PHYs are present, initialize and enable them at driver probe.

Signed-off-by: Alan Douglas <adouglas@cadence.com>
[lorenzo.pieralisi@arm.com: updated commit log]
Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>

authored by

Alan Douglas and committed by
Lorenzo Pieralisi
dfb80534 7e37dc1d

+128 -1
+13 -1
drivers/pci/controller/pcie-cadence-ep.c
··· 439 439 struct pci_epc *epc; 440 440 struct resource *res; 441 441 int ret; 442 + int phy_count; 442 443 443 444 ep = devm_kzalloc(dev, sizeof(*ep), GFP_KERNEL); 444 445 if (!ep) ··· 474 473 if (!ep->ob_addr) 475 474 return -ENOMEM; 476 475 476 + ret = cdns_pcie_init_phy(dev, pcie); 477 + if (ret) { 478 + dev_err(dev, "failed to init phy\n"); 479 + return ret; 480 + } 481 + platform_set_drvdata(pdev, pcie); 477 482 pm_runtime_enable(dev); 478 483 ret = pm_runtime_get_sync(dev); 479 484 if (ret < 0) { ··· 528 521 529 522 err_get_sync: 530 523 pm_runtime_disable(dev); 524 + cdns_pcie_disable_phy(pcie); 525 + phy_count = pcie->phy_count; 526 + while (phy_count--) 527 + device_link_del(pcie->link[phy_count]); 531 528 532 529 return ret; 533 530 } ··· 539 528 static void cdns_pcie_ep_shutdown(struct platform_device *pdev) 540 529 { 541 530 struct device *dev = &pdev->dev; 531 + struct cdns_pcie *pcie = dev_get_drvdata(dev); 542 532 int ret; 543 533 544 534 ret = pm_runtime_put_sync(dev); ··· 548 536 549 537 pm_runtime_disable(dev); 550 538 551 - /* The PCIe controller can't be disabled. */ 539 + cdns_pcie_disable_phy(pcie); 552 540 } 553 541 554 542 static struct platform_driver cdns_pcie_ep_driver = {
+15
drivers/pci/controller/pcie-cadence-host.c
··· 58 58 59 59 return pcie->reg_base + (where & 0xfff); 60 60 } 61 + /* Check that the link is up */ 62 + if (!(cdns_pcie_readl(pcie, CDNS_PCIE_LM_BASE) & 0x1)) 63 + return NULL; 61 64 62 65 /* Update Output registers for AXI region 0. */ 63 66 addr0 = CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_NBITS(12) | ··· 242 239 struct cdns_pcie *pcie; 243 240 struct resource *res; 244 241 int ret; 242 + int phy_count; 245 243 246 244 bridge = devm_pci_alloc_host_bridge(dev, sizeof(*rc)); 247 245 if (!bridge) ··· 294 290 } 295 291 pcie->mem_res = res; 296 292 293 + ret = cdns_pcie_init_phy(dev, pcie); 294 + if (ret) { 295 + dev_err(dev, "failed to init phy\n"); 296 + return ret; 297 + } 298 + platform_set_drvdata(pdev, pcie); 299 + 297 300 pm_runtime_enable(dev); 298 301 ret = pm_runtime_get_sync(dev); 299 302 if (ret < 0) { ··· 333 322 334 323 err_get_sync: 335 324 pm_runtime_disable(dev); 325 + cdns_pcie_disable_phy(pcie); 326 + phy_count = pcie->phy_count; 327 + while (phy_count--) 328 + device_link_del(pcie->link[phy_count]); 336 329 337 330 return ret; 338 331 }
+93
drivers/pci/controller/pcie-cadence.c
··· 124 124 cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_CPU_ADDR0(r), 0); 125 125 cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_CPU_ADDR1(r), 0); 126 126 } 127 + 128 + void cdns_pcie_disable_phy(struct cdns_pcie *pcie) 129 + { 130 + int i = pcie->phy_count; 131 + 132 + while (i--) { 133 + phy_power_off(pcie->phy[i]); 134 + phy_exit(pcie->phy[i]); 135 + } 136 + } 137 + 138 + int cdns_pcie_enable_phy(struct cdns_pcie *pcie) 139 + { 140 + int ret; 141 + int i; 142 + 143 + for (i = 0; i < pcie->phy_count; i++) { 144 + ret = phy_init(pcie->phy[i]); 145 + if (ret < 0) 146 + goto err_phy; 147 + 148 + ret = phy_power_on(pcie->phy[i]); 149 + if (ret < 0) { 150 + phy_exit(pcie->phy[i]); 151 + goto err_phy; 152 + } 153 + } 154 + 155 + return 0; 156 + 157 + err_phy: 158 + while (--i >= 0) { 159 + phy_power_off(pcie->phy[i]); 160 + phy_exit(pcie->phy[i]); 161 + } 162 + 163 + return ret; 164 + } 165 + 166 + int cdns_pcie_init_phy(struct device *dev, struct cdns_pcie *pcie) 167 + { 168 + struct device_node *np = dev->of_node; 169 + int phy_count; 170 + struct phy **phy; 171 + struct device_link **link; 172 + int i; 173 + int ret; 174 + const char *name; 175 + 176 + phy_count = of_property_count_strings(np, "phy-names"); 177 + if (phy_count < 1) { 178 + dev_err(dev, "no phy-names. PHY will not be initialized\n"); 179 + pcie->phy_count = 0; 180 + return 0; 181 + } 182 + 183 + phy = devm_kzalloc(dev, sizeof(*phy) * phy_count, GFP_KERNEL); 184 + if (!phy) 185 + return -ENOMEM; 186 + 187 + link = devm_kzalloc(dev, sizeof(*link) * phy_count, GFP_KERNEL); 188 + if (!link) 189 + return -ENOMEM; 190 + 191 + for (i = 0; i < phy_count; i++) { 192 + of_property_read_string_index(np, "phy-names", i, &name); 193 + phy[i] = devm_phy_optional_get(dev, name); 194 + if (IS_ERR(phy)) 195 + return PTR_ERR(phy); 196 + 197 + link[i] = device_link_add(dev, &phy[i]->dev, DL_FLAG_STATELESS); 198 + if (!link[i]) { 199 + ret = -EINVAL; 200 + goto err_link; 201 + } 202 + } 203 + 204 + pcie->phy_count = phy_count; 205 + pcie->phy = phy; 206 + pcie->link = link; 207 + 208 + ret = cdns_pcie_enable_phy(pcie); 209 + if (ret) 210 + goto err_link; 211 + 212 + return 0; 213 + 214 + err_link: 215 + while (--i >= 0) 216 + device_link_del(link[i]); 217 + 218 + return ret; 219 + }
+7
drivers/pci/controller/pcie-cadence.h
··· 8 8 9 9 #include <linux/kernel.h> 10 10 #include <linux/pci.h> 11 + #include <linux/phy/phy.h> 11 12 12 13 /* 13 14 * Local Management Registers ··· 230 229 struct resource *mem_res; 231 230 bool is_rc; 232 231 u8 bus; 232 + int phy_count; 233 + struct phy **phy; 234 + struct device_link **link; 233 235 }; 234 236 235 237 /* Register access */ ··· 311 307 u32 r, u64 cpu_addr); 312 308 313 309 void cdns_pcie_reset_outbound_region(struct cdns_pcie *pcie, u32 r); 310 + void cdns_pcie_disable_phy(struct cdns_pcie *pcie); 311 + int cdns_pcie_enable_phy(struct cdns_pcie *pcie); 312 + int cdns_pcie_init_phy(struct device *dev, struct cdns_pcie *pcie); 314 313 315 314 #endif /* _PCIE_CADENCE_H */