aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlan Douglas <adouglas@cadence.com>2018-06-25 04:30:50 -0400
committerLorenzo Pieralisi <lorenzo.pieralisi@arm.com>2018-07-11 05:39:39 -0400
commitdfb80534692ddc5b97e1da4384f13dc0287fccb2 (patch)
tree7d565642e9c5fce2567d5f43db48288647f864e7
parent7e37dc1db594d5a4ed062dbaf51ef89596a9df8a (diff)
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>
-rw-r--r--drivers/pci/controller/pcie-cadence-ep.c14
-rw-r--r--drivers/pci/controller/pcie-cadence-host.c15
-rw-r--r--drivers/pci/controller/pcie-cadence.c93
-rw-r--r--drivers/pci/controller/pcie-cadence.h7
4 files changed, 128 insertions, 1 deletions
diff --git a/drivers/pci/controller/pcie-cadence-ep.c b/drivers/pci/controller/pcie-cadence-ep.c
index e3fe4124e3af..c02f33d8e506 100644
--- a/drivers/pci/controller/pcie-cadence-ep.c
+++ b/drivers/pci/controller/pcie-cadence-ep.c
@@ -439,6 +439,7 @@ static int cdns_pcie_ep_probe(struct platform_device *pdev)
439 struct pci_epc *epc; 439 struct pci_epc *epc;
440 struct resource *res; 440 struct resource *res;
441 int ret; 441 int ret;
442 int phy_count;
442 443
443 ep = devm_kzalloc(dev, sizeof(*ep), GFP_KERNEL); 444 ep = devm_kzalloc(dev, sizeof(*ep), GFP_KERNEL);
444 if (!ep) 445 if (!ep)
@@ -473,6 +474,12 @@ static int cdns_pcie_ep_probe(struct platform_device *pdev)
473 if (!ep->ob_addr) 474 if (!ep->ob_addr)
474 return -ENOMEM; 475 return -ENOMEM;
475 476
477 ret = cdns_pcie_init_phy(dev, pcie);
478 if (ret) {
479 dev_err(dev, "failed to init phy\n");
480 return ret;
481 }
482 platform_set_drvdata(pdev, pcie);
476 pm_runtime_enable(dev); 483 pm_runtime_enable(dev);
477 ret = pm_runtime_get_sync(dev); 484 ret = pm_runtime_get_sync(dev);
478 if (ret < 0) { 485 if (ret < 0) {
@@ -521,6 +528,10 @@ static int cdns_pcie_ep_probe(struct platform_device *pdev)
521 528
522 err_get_sync: 529 err_get_sync:
523 pm_runtime_disable(dev); 530 pm_runtime_disable(dev);
531 cdns_pcie_disable_phy(pcie);
532 phy_count = pcie->phy_count;
533 while (phy_count--)
534 device_link_del(pcie->link[phy_count]);
524 535
525 return ret; 536 return ret;
526} 537}
@@ -528,6 +539,7 @@ static int cdns_pcie_ep_probe(struct platform_device *pdev)
528static void cdns_pcie_ep_shutdown(struct platform_device *pdev) 539static void cdns_pcie_ep_shutdown(struct platform_device *pdev)
529{ 540{
530 struct device *dev = &pdev->dev; 541 struct device *dev = &pdev->dev;
542 struct cdns_pcie *pcie = dev_get_drvdata(dev);
531 int ret; 543 int ret;
532 544
533 ret = pm_runtime_put_sync(dev); 545 ret = pm_runtime_put_sync(dev);
@@ -536,7 +548,7 @@ static void cdns_pcie_ep_shutdown(struct platform_device *pdev)
536 548
537 pm_runtime_disable(dev); 549 pm_runtime_disable(dev);
538 550
539 /* The PCIe controller can't be disabled. */ 551 cdns_pcie_disable_phy(pcie);
540} 552}
541 553
542static struct platform_driver cdns_pcie_ep_driver = { 554static struct platform_driver cdns_pcie_ep_driver = {
diff --git a/drivers/pci/controller/pcie-cadence-host.c b/drivers/pci/controller/pcie-cadence-host.c
index a4ebbd37b553..36f31092562f 100644
--- a/drivers/pci/controller/pcie-cadence-host.c
+++ b/drivers/pci/controller/pcie-cadence-host.c
@@ -58,6 +58,9 @@ static void __iomem *cdns_pci_map_bus(struct pci_bus *bus, unsigned int devfn,
58 58
59 return pcie->reg_base + (where & 0xfff); 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 /* Update Output registers for AXI region 0. */ 65 /* Update Output registers for AXI region 0. */
63 addr0 = CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_NBITS(12) | 66 addr0 = CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_NBITS(12) |
@@ -239,6 +242,7 @@ static int cdns_pcie_host_probe(struct platform_device *pdev)
239 struct cdns_pcie *pcie; 242 struct cdns_pcie *pcie;
240 struct resource *res; 243 struct resource *res;
241 int ret; 244 int ret;
245 int phy_count;
242 246
243 bridge = devm_pci_alloc_host_bridge(dev, sizeof(*rc)); 247 bridge = devm_pci_alloc_host_bridge(dev, sizeof(*rc));
244 if (!bridge) 248 if (!bridge)
@@ -290,6 +294,13 @@ static int cdns_pcie_host_probe(struct platform_device *pdev)
290 } 294 }
291 pcie->mem_res = res; 295 pcie->mem_res = res;
292 296
297 ret = cdns_pcie_init_phy(dev, pcie);
298 if (ret) {
299 dev_err(dev, "failed to init phy\n");
300 return ret;
301 }
302 platform_set_drvdata(pdev, pcie);
303
293 pm_runtime_enable(dev); 304 pm_runtime_enable(dev);
294 ret = pm_runtime_get_sync(dev); 305 ret = pm_runtime_get_sync(dev);
295 if (ret < 0) { 306 if (ret < 0) {
@@ -322,6 +333,10 @@ static int cdns_pcie_host_probe(struct platform_device *pdev)
322 333
323 err_get_sync: 334 err_get_sync:
324 pm_runtime_disable(dev); 335 pm_runtime_disable(dev);
336 cdns_pcie_disable_phy(pcie);
337 phy_count = pcie->phy_count;
338 while (phy_count--)
339 device_link_del(pcie->link[phy_count]);
325 340
326 return ret; 341 return ret;
327} 342}
diff --git a/drivers/pci/controller/pcie-cadence.c b/drivers/pci/controller/pcie-cadence.c
index 138d113eb45d..2edc12661e44 100644
--- a/drivers/pci/controller/pcie-cadence.c
+++ b/drivers/pci/controller/pcie-cadence.c
@@ -124,3 +124,96 @@ void cdns_pcie_reset_outbound_region(struct cdns_pcie *pcie, u32 r)
124 cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_CPU_ADDR0(r), 0); 124 cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_CPU_ADDR0(r), 0);
125 cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_CPU_ADDR1(r), 0); 125 cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_CPU_ADDR1(r), 0);
126} 126}
127
128void 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
138int 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
157err_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
166int 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
214err_link:
215 while (--i >= 0)
216 device_link_del(link[i]);
217
218 return ret;
219}
diff --git a/drivers/pci/controller/pcie-cadence.h b/drivers/pci/controller/pcie-cadence.h
index ed336cc7f4ba..b342c808f7d6 100644
--- a/drivers/pci/controller/pcie-cadence.h
+++ b/drivers/pci/controller/pcie-cadence.h
@@ -8,6 +8,7 @@
8 8
9#include <linux/kernel.h> 9#include <linux/kernel.h>
10#include <linux/pci.h> 10#include <linux/pci.h>
11#include <linux/phy/phy.h>
11 12
12/* 13/*
13 * Local Management Registers 14 * Local Management Registers
@@ -229,6 +230,9 @@ struct cdns_pcie {
229 struct resource *mem_res; 230 struct resource *mem_res;
230 bool is_rc; 231 bool is_rc;
231 u8 bus; 232 u8 bus;
233 int phy_count;
234 struct phy **phy;
235 struct device_link **link;
232}; 236};
233 237
234/* Register access */ 238/* Register access */
@@ -307,5 +311,8 @@ void cdns_pcie_set_outbound_region_for_normal_msg(struct cdns_pcie *pcie, u8 fn,
307 u32 r, u64 cpu_addr); 311 u32 r, u64 cpu_addr);
308 312
309void cdns_pcie_reset_outbound_region(struct cdns_pcie *pcie, u32 r); 313void cdns_pcie_reset_outbound_region(struct cdns_pcie *pcie, u32 r);
314void cdns_pcie_disable_phy(struct cdns_pcie *pcie);
315int cdns_pcie_enable_phy(struct cdns_pcie *pcie);
316int cdns_pcie_init_phy(struct device *dev, struct cdns_pcie *pcie);
310 317
311#endif /* _PCIE_CADENCE_H */ 318#endif /* _PCIE_CADENCE_H */