Lines Matching +full:pcie +full:- +full:ep
1 // SPDX-License-Identifier: GPL-2.0
3 // Cadence PCIe endpoint controller driver.
4 // Author: Cyrille Pitchen <cyrille.pitchen@free-electrons.com>
9 #include <linux/pci-epc.h>
14 #include "pcie-cadence.h"
21 * struct cdns_pcie_ep - private data for this PCIe endpoint controller driver
22 * @pcie: Cadence PCIe controller
30 * IRQ) TLP through the PCIe bus.
38 struct cdns_pcie pcie; member
52 struct cdns_pcie_ep *ep = epc_get_drvdata(epc); in cdns_pcie_ep_write_header() local
53 struct cdns_pcie *pcie = &ep->pcie; in cdns_pcie_ep_write_header() local
55 cdns_pcie_ep_fn_writew(pcie, fn, PCI_DEVICE_ID, hdr->deviceid); in cdns_pcie_ep_write_header()
56 cdns_pcie_ep_fn_writeb(pcie, fn, PCI_REVISION_ID, hdr->revid); in cdns_pcie_ep_write_header()
57 cdns_pcie_ep_fn_writeb(pcie, fn, PCI_CLASS_PROG, hdr->progif_code); in cdns_pcie_ep_write_header()
58 cdns_pcie_ep_fn_writew(pcie, fn, PCI_CLASS_DEVICE, in cdns_pcie_ep_write_header()
59 hdr->subclass_code | hdr->baseclass_code << 8); in cdns_pcie_ep_write_header()
60 cdns_pcie_ep_fn_writeb(pcie, fn, PCI_CACHE_LINE_SIZE, in cdns_pcie_ep_write_header()
61 hdr->cache_line_size); in cdns_pcie_ep_write_header()
62 cdns_pcie_ep_fn_writew(pcie, fn, PCI_SUBSYSTEM_ID, hdr->subsys_id); in cdns_pcie_ep_write_header()
63 cdns_pcie_ep_fn_writeb(pcie, fn, PCI_INTERRUPT_PIN, hdr->interrupt_pin); in cdns_pcie_ep_write_header()
71 u32 id = CDNS_PCIE_LM_ID_VENDOR(hdr->vendorid) | in cdns_pcie_ep_write_header()
72 CDNS_PCIE_LM_ID_SUBSYS(hdr->subsys_vendor_id); in cdns_pcie_ep_write_header()
74 cdns_pcie_writel(pcie, CDNS_PCIE_LM_ID, id); in cdns_pcie_ep_write_header()
83 struct cdns_pcie_ep *ep = epc_get_drvdata(epc); in cdns_pcie_ep_set_bar() local
84 struct cdns_pcie *pcie = &ep->pcie; in cdns_pcie_ep_set_bar() local
85 dma_addr_t bar_phys = epf_bar->phys_addr; in cdns_pcie_ep_set_bar()
86 enum pci_barno bar = epf_bar->barno; in cdns_pcie_ep_set_bar()
87 int flags = epf_bar->flags; in cdns_pcie_ep_set_bar()
92 sz = max_t(size_t, epf_bar->size, CDNS_PCIE_EP_MIN_APERTURE); in cdns_pcie_ep_set_bar()
97 sz = 1ULL << fls64(sz - 1); in cdns_pcie_ep_set_bar()
98 aperture = ilog2(sz) - 7; /* 128B -> 0, 256B -> 1, 512B -> 2, ... */ in cdns_pcie_ep_set_bar()
107 return -EINVAL; in cdns_pcie_ep_set_bar()
110 epf_bar->flags |= PCI_BASE_ADDRESS_MEM_TYPE_64; in cdns_pcie_ep_set_bar()
124 cdns_pcie_writel(pcie, CDNS_PCIE_AT_IB_EP_FUNC_BAR_ADDR0(fn, bar), in cdns_pcie_ep_set_bar()
126 cdns_pcie_writel(pcie, CDNS_PCIE_AT_IB_EP_FUNC_BAR_ADDR1(fn, bar), in cdns_pcie_ep_set_bar()
134 b = bar - BAR_4; in cdns_pcie_ep_set_bar()
137 cfg = cdns_pcie_readl(pcie, reg); in cdns_pcie_ep_set_bar()
142 cdns_pcie_writel(pcie, reg, cfg); in cdns_pcie_ep_set_bar()
150 struct cdns_pcie_ep *ep = epc_get_drvdata(epc); in cdns_pcie_ep_clear_bar() local
151 struct cdns_pcie *pcie = &ep->pcie; in cdns_pcie_ep_clear_bar() local
152 enum pci_barno bar = epf_bar->barno; in cdns_pcie_ep_clear_bar()
160 b = bar - BAR_4; in cdns_pcie_ep_clear_bar()
164 cfg = cdns_pcie_readl(pcie, reg); in cdns_pcie_ep_clear_bar()
168 cdns_pcie_writel(pcie, reg, cfg); in cdns_pcie_ep_clear_bar()
170 cdns_pcie_writel(pcie, CDNS_PCIE_AT_IB_EP_FUNC_BAR_ADDR0(fn, bar), 0); in cdns_pcie_ep_clear_bar()
171 cdns_pcie_writel(pcie, CDNS_PCIE_AT_IB_EP_FUNC_BAR_ADDR1(fn, bar), 0); in cdns_pcie_ep_clear_bar()
177 struct cdns_pcie_ep *ep = epc_get_drvdata(epc); in cdns_pcie_ep_map_addr() local
178 struct cdns_pcie *pcie = &ep->pcie; in cdns_pcie_ep_map_addr() local
181 r = find_first_zero_bit(&ep->ob_region_map, in cdns_pcie_ep_map_addr()
182 sizeof(ep->ob_region_map) * BITS_PER_LONG); in cdns_pcie_ep_map_addr()
183 if (r >= ep->max_regions - 1) { in cdns_pcie_ep_map_addr()
184 dev_err(&epc->dev, "no free outbound region\n"); in cdns_pcie_ep_map_addr()
185 return -EINVAL; in cdns_pcie_ep_map_addr()
188 cdns_pcie_set_outbound_region(pcie, fn, r, false, addr, pci_addr, size); in cdns_pcie_ep_map_addr()
190 set_bit(r, &ep->ob_region_map); in cdns_pcie_ep_map_addr()
191 ep->ob_addr[r] = addr; in cdns_pcie_ep_map_addr()
199 struct cdns_pcie_ep *ep = epc_get_drvdata(epc); in cdns_pcie_ep_unmap_addr() local
200 struct cdns_pcie *pcie = &ep->pcie; in cdns_pcie_ep_unmap_addr() local
203 for (r = 0; r < ep->max_regions - 1; r++) in cdns_pcie_ep_unmap_addr()
204 if (ep->ob_addr[r] == addr) in cdns_pcie_ep_unmap_addr()
207 if (r == ep->max_regions - 1) in cdns_pcie_ep_unmap_addr()
210 cdns_pcie_reset_outbound_region(pcie, r); in cdns_pcie_ep_unmap_addr()
212 ep->ob_addr[r] = 0; in cdns_pcie_ep_unmap_addr()
213 clear_bit(r, &ep->ob_region_map); in cdns_pcie_ep_unmap_addr()
218 struct cdns_pcie_ep *ep = epc_get_drvdata(epc); in cdns_pcie_ep_set_msi() local
219 struct cdns_pcie *pcie = &ep->pcie; in cdns_pcie_ep_set_msi() local
227 flags = cdns_pcie_ep_fn_readw(pcie, fn, cap + PCI_MSI_FLAGS); in cdns_pcie_ep_set_msi()
231 cdns_pcie_ep_fn_writew(pcie, fn, cap + PCI_MSI_FLAGS, flags); in cdns_pcie_ep_set_msi()
238 struct cdns_pcie_ep *ep = epc_get_drvdata(epc); in cdns_pcie_ep_get_msi() local
239 struct cdns_pcie *pcie = &ep->pcie; in cdns_pcie_ep_get_msi() local
244 flags = cdns_pcie_ep_fn_readw(pcie, fn, cap + PCI_MSI_FLAGS); in cdns_pcie_ep_get_msi()
246 return -EINVAL; in cdns_pcie_ep_get_msi()
257 static void cdns_pcie_ep_assert_intx(struct cdns_pcie_ep *ep, u8 fn, in cdns_pcie_ep_assert_intx() argument
260 struct cdns_pcie *pcie = &ep->pcie; in cdns_pcie_ep_assert_intx() local
268 if (unlikely(ep->irq_pci_addr != CDNS_PCIE_EP_IRQ_PCI_ADDR_LEGACY || in cdns_pcie_ep_assert_intx()
269 ep->irq_pci_fn != fn)) { in cdns_pcie_ep_assert_intx()
271 cdns_pcie_set_outbound_region_for_normal_msg(pcie, fn, 0, in cdns_pcie_ep_assert_intx()
272 ep->irq_phys_addr); in cdns_pcie_ep_assert_intx()
273 ep->irq_pci_addr = CDNS_PCIE_EP_IRQ_PCI_ADDR_LEGACY; in cdns_pcie_ep_assert_intx()
274 ep->irq_pci_fn = fn; in cdns_pcie_ep_assert_intx()
278 ep->irq_pending |= BIT(intx); in cdns_pcie_ep_assert_intx()
281 ep->irq_pending &= ~BIT(intx); in cdns_pcie_ep_assert_intx()
285 status = cdns_pcie_ep_fn_readw(pcie, fn, PCI_STATUS); in cdns_pcie_ep_assert_intx()
286 if (((status & PCI_STATUS_INTERRUPT) != 0) ^ (ep->irq_pending != 0)) { in cdns_pcie_ep_assert_intx()
288 cdns_pcie_ep_fn_writew(pcie, fn, PCI_STATUS, status); in cdns_pcie_ep_assert_intx()
294 writel(0, ep->irq_cpu_addr + offset); in cdns_pcie_ep_assert_intx()
297 static int cdns_pcie_ep_send_legacy_irq(struct cdns_pcie_ep *ep, u8 fn, u8 intx) in cdns_pcie_ep_send_legacy_irq() argument
301 cmd = cdns_pcie_ep_fn_readw(&ep->pcie, fn, PCI_COMMAND); in cdns_pcie_ep_send_legacy_irq()
303 return -EINVAL; in cdns_pcie_ep_send_legacy_irq()
305 cdns_pcie_ep_assert_intx(ep, fn, intx, true); in cdns_pcie_ep_send_legacy_irq()
308 * from drivers/pci/dwc/pci-dra7xx.c in cdns_pcie_ep_send_legacy_irq()
311 cdns_pcie_ep_assert_intx(ep, fn, intx, false); in cdns_pcie_ep_send_legacy_irq()
315 static int cdns_pcie_ep_send_msi_irq(struct cdns_pcie_ep *ep, u8 fn, in cdns_pcie_ep_send_msi_irq() argument
318 struct cdns_pcie *pcie = &ep->pcie; in cdns_pcie_ep_send_msi_irq() local
325 flags = cdns_pcie_ep_fn_readw(pcie, fn, cap + PCI_MSI_FLAGS); in cdns_pcie_ep_send_msi_irq()
327 return -EINVAL; in cdns_pcie_ep_send_msi_irq()
333 return -EINVAL; in cdns_pcie_ep_send_msi_irq()
336 data_mask = msi_count - 1; in cdns_pcie_ep_send_msi_irq()
337 data = cdns_pcie_ep_fn_readw(pcie, fn, cap + PCI_MSI_DATA_64); in cdns_pcie_ep_send_msi_irq()
338 data = (data & ~data_mask) | ((interrupt_num - 1) & data_mask); in cdns_pcie_ep_send_msi_irq()
341 pci_addr = cdns_pcie_ep_fn_readl(pcie, fn, cap + PCI_MSI_ADDRESS_HI); in cdns_pcie_ep_send_msi_irq()
343 pci_addr |= cdns_pcie_ep_fn_readl(pcie, fn, cap + PCI_MSI_ADDRESS_LO); in cdns_pcie_ep_send_msi_irq()
347 if (unlikely(ep->irq_pci_addr != (pci_addr & ~pci_addr_mask) || in cdns_pcie_ep_send_msi_irq()
348 ep->irq_pci_fn != fn)) { in cdns_pcie_ep_send_msi_irq()
350 cdns_pcie_set_outbound_region(pcie, fn, 0, in cdns_pcie_ep_send_msi_irq()
352 ep->irq_phys_addr, in cdns_pcie_ep_send_msi_irq()
355 ep->irq_pci_addr = (pci_addr & ~pci_addr_mask); in cdns_pcie_ep_send_msi_irq()
356 ep->irq_pci_fn = fn; in cdns_pcie_ep_send_msi_irq()
358 writel(data, ep->irq_cpu_addr + (pci_addr & pci_addr_mask)); in cdns_pcie_ep_send_msi_irq()
367 struct cdns_pcie_ep *ep = epc_get_drvdata(epc); in cdns_pcie_ep_raise_irq() local
371 return cdns_pcie_ep_send_legacy_irq(ep, fn, 0); in cdns_pcie_ep_raise_irq()
374 return cdns_pcie_ep_send_msi_irq(ep, fn, interrupt_num); in cdns_pcie_ep_raise_irq()
380 return -EINVAL; in cdns_pcie_ep_raise_irq()
385 struct cdns_pcie_ep *ep = epc_get_drvdata(epc); in cdns_pcie_ep_start() local
386 struct cdns_pcie *pcie = &ep->pcie; in cdns_pcie_ep_start() local
395 list_for_each_entry(epf, &epc->pci_epf, list) in cdns_pcie_ep_start()
396 cfg |= BIT(epf->func_no); in cdns_pcie_ep_start()
397 cdns_pcie_writel(pcie, CDNS_PCIE_LM_EP_FUNC_CFG, cfg); in cdns_pcie_ep_start()
400 * The PCIe links are automatically established by the controller in cdns_pcie_ep_start()
404 * Then we only have to notify the EP core that our links are already in cdns_pcie_ep_start()
406 * we've already locked the epc->lock. in cdns_pcie_ep_start()
408 list_for_each_entry(epf, &epc->pci_epf, list) in cdns_pcie_ep_start()
427 { .compatible = "cdns,cdns-pcie-ep" },
434 struct device *dev = &pdev->dev; in cdns_pcie_ep_probe()
435 struct device_node *np = dev->of_node; in cdns_pcie_ep_probe()
436 struct cdns_pcie_ep *ep; in cdns_pcie_ep_probe() local
437 struct cdns_pcie *pcie; in cdns_pcie_ep_probe() local
443 ep = devm_kzalloc(dev, sizeof(*ep), GFP_KERNEL); in cdns_pcie_ep_probe()
444 if (!ep) in cdns_pcie_ep_probe()
445 return -ENOMEM; in cdns_pcie_ep_probe()
447 pcie = &ep->pcie; in cdns_pcie_ep_probe()
448 pcie->is_rc = false; in cdns_pcie_ep_probe()
451 pcie->reg_base = devm_ioremap_resource(dev, res); in cdns_pcie_ep_probe()
452 if (IS_ERR(pcie->reg_base)) { in cdns_pcie_ep_probe()
454 return PTR_ERR(pcie->reg_base); in cdns_pcie_ep_probe()
460 return -EINVAL; in cdns_pcie_ep_probe()
462 pcie->mem_res = res; in cdns_pcie_ep_probe()
464 ret = of_property_read_u32(np, "cdns,max-outbound-regions", in cdns_pcie_ep_probe()
465 &ep->max_regions); in cdns_pcie_ep_probe()
467 dev_err(dev, "missing \"cdns,max-outbound-regions\"\n"); in cdns_pcie_ep_probe()
470 ep->ob_addr = devm_kcalloc(dev, in cdns_pcie_ep_probe()
471 ep->max_regions, sizeof(*ep->ob_addr), in cdns_pcie_ep_probe()
473 if (!ep->ob_addr) in cdns_pcie_ep_probe()
474 return -ENOMEM; in cdns_pcie_ep_probe()
476 ret = cdns_pcie_init_phy(dev, pcie); in cdns_pcie_ep_probe()
481 platform_set_drvdata(pdev, pcie); in cdns_pcie_ep_probe()
490 cdns_pcie_writel(pcie, CDNS_PCIE_LM_EP_FUNC_CFG, BIT(0)); in cdns_pcie_ep_probe()
499 epc_set_drvdata(epc, ep); in cdns_pcie_ep_probe()
501 if (of_property_read_u8(np, "max-functions", &epc->max_functions) < 0) in cdns_pcie_ep_probe()
502 epc->max_functions = 1; in cdns_pcie_ep_probe()
504 ret = pci_epc_mem_init(epc, pcie->mem_res->start, in cdns_pcie_ep_probe()
505 resource_size(pcie->mem_res)); in cdns_pcie_ep_probe()
511 ep->irq_cpu_addr = pci_epc_mem_alloc_addr(epc, &ep->irq_phys_addr, in cdns_pcie_ep_probe()
513 if (!ep->irq_cpu_addr) { in cdns_pcie_ep_probe()
515 ret = -ENOMEM; in cdns_pcie_ep_probe()
518 ep->irq_pci_addr = CDNS_PCIE_EP_IRQ_PCI_ADDR_NONE; in cdns_pcie_ep_probe()
520 set_bit(0, &ep->ob_region_map); in cdns_pcie_ep_probe()
532 cdns_pcie_disable_phy(pcie); in cdns_pcie_ep_probe()
533 phy_count = pcie->phy_count; in cdns_pcie_ep_probe()
534 while (phy_count--) in cdns_pcie_ep_probe()
535 device_link_del(pcie->link[phy_count]); in cdns_pcie_ep_probe()
542 struct device *dev = &pdev->dev; in cdns_pcie_ep_shutdown()
543 struct cdns_pcie *pcie = dev_get_drvdata(dev); in cdns_pcie_ep_shutdown() local
552 cdns_pcie_disable_phy(pcie); in cdns_pcie_ep_shutdown()
557 .name = "cdns-pcie-ep",