Lines Matching +full:pcie +full:- +full:0
1 // SPDX-License-Identifier: GPL-2.0
3 * PCIe host bridge driver for Apple system-on-chips.
6 * the driver mostly deals MSI mapping and handling of per-port
26 #include <linux/irqchip/irq-msi-lib.h>
32 #include <linux/pci-ecam.h>
34 #include "pci-host-common.h"
37 #define CORE_RC_PHYIF_CTL 0x00024
38 #define CORE_RC_PHYIF_CTL_RUN BIT(0)
39 #define CORE_RC_PHYIF_STAT 0x00028
41 #define CORE_RC_CTL 0x00050
42 #define CORE_RC_CTL_RUN BIT(0)
43 #define CORE_RC_STAT 0x00058
44 #define CORE_RC_STAT_READY BIT(0)
45 #define CORE_FABRIC_STAT 0x04000
46 #define CORE_FABRIC_STAT_MASK 0x001F001F
48 #define CORE_PHY_DEFAULT_BASE(port) (0x84000 + 0x4000 * (port))
50 #define PHY_LANE_CFG 0x00000
51 #define PHY_LANE_CFG_REFCLK0REQ BIT(0)
57 #define PHY_LANE_CTL 0x00004
60 #define PORT_LTSSMCTL 0x00080
61 #define PORT_LTSSMCTL_START BIT(0)
62 #define PORT_INTSTAT 0x00100
78 #define PORT_INTMSK 0x00104
79 #define PORT_INTMSKSET 0x00108
80 #define PORT_INTMSKCLR 0x0010c
81 #define PORT_MSICFG 0x00124
82 #define PORT_MSICFG_EN BIT(0)
84 #define PORT_MSIBASE 0x00128
86 #define PORT_MSIADDR 0x00168
87 #define PORT_LINKSTS 0x00208
88 #define PORT_LINKSTS_UP BIT(0)
90 #define PORT_LINKCMDSTS 0x00210
91 #define PORT_OUTS_NPREQS 0x00284
94 #define PORT_RXWR_FIFO 0x00288
96 #define PORT_RXWR_FIFO_DATA GENMASK(9, 0)
97 #define PORT_RXRD_FIFO 0x0028C
98 #define PORT_RXRD_FIFO_REQ GENMASK(6, 0)
99 #define PORT_OUTS_CPLS 0x00290
101 #define PORT_OUTS_CPLS_WAIT GENMASK(6, 0)
102 #define PORT_APPCLK 0x00800
103 #define PORT_APPCLK_EN BIT(0)
105 #define PORT_STATUS 0x00804
106 #define PORT_STATUS_READY BIT(0)
107 #define PORT_REFCLK 0x00810
108 #define PORT_REFCLK_EN BIT(0)
110 #define PORT_PERST 0x00814
111 #define PORT_PERST_OFF BIT(0)
112 #define PORT_RID2SID 0x00828
117 #define PORT_RID2SID_FUNC_SHIFT 0
118 #define PORT_OUTS_PREQS_HDR 0x00980
119 #define PORT_OUTS_PREQS_HDR_MASK GENMASK(9, 0)
120 #define PORT_OUTS_PREQS_DATA 0x00984
121 #define PORT_OUTS_PREQS_DATA_MASK GENMASK(15, 0)
122 #define PORT_TUNCTRL 0x00988
123 #define PORT_TUNCTRL_PERST_ON BIT(0)
125 #define PORT_TUNSTAT 0x0098c
126 #define PORT_TUNSTAT_PERST_ON BIT(0)
128 #define PORT_PREFMEM_ENABLE 0x00994
130 /* T602x (M2-pro and co) */
131 #define PORT_T602X_MSIADDR 0x016c
132 #define PORT_T602X_MSIADDR_HI 0x0170
133 #define PORT_T602X_PERST 0x082c
134 #define PORT_T602X_RID2SID 0x3000
135 #define PORT_T602X_MSIMAP 0x3800
138 #define PORT_MSIMAP_TARGET GENMASK(7, 0)
141 * The doorbell address is set to 0xfffff000, which by convention
163 .port_msiaddr_hi = 0,
167 .port_msimap = 0,
172 .phy_lane_ctl = 0,
175 .port_refclk = 0,
198 struct apple_pcie *pcie; member
224 msg->address_hi = upper_32_bits(DOORBELL_ADDR); in apple_msi_compose_msg()
225 msg->address_lo = lower_32_bits(DOORBELL_ADDR); in apple_msi_compose_msg()
226 msg->data = data->hwirq; in apple_msi_compose_msg()
242 struct apple_pcie *pcie = domain->host_data; in apple_msi_domain_alloc() local
243 struct irq_fwspec fwspec = pcie->fwspec; in apple_msi_domain_alloc()
247 mutex_lock(&pcie->lock); in apple_msi_domain_alloc()
249 hwirq = bitmap_find_free_region(pcie->bitmap, pcie->nvecs, in apple_msi_domain_alloc()
252 mutex_unlock(&pcie->lock); in apple_msi_domain_alloc()
254 if (hwirq < 0) in apple_msi_domain_alloc()
255 return -ENOSPC; in apple_msi_domain_alloc()
257 fwspec.param[fwspec.param_count - 2] += hwirq; in apple_msi_domain_alloc()
263 for (i = 0; i < nr_irqs; i++) { in apple_msi_domain_alloc()
265 &apple_msi_bottom_chip, pcie); in apple_msi_domain_alloc()
268 return 0; in apple_msi_domain_alloc()
275 struct apple_pcie *pcie = domain->host_data; in apple_msi_domain_free() local
277 mutex_lock(&pcie->lock); in apple_msi_domain_free()
279 bitmap_release_region(pcie->bitmap, d->hwirq, order_base_2(nr_irqs)); in apple_msi_domain_free()
281 mutex_unlock(&pcie->lock); in apple_msi_domain_free()
293 guard(raw_spinlock_irqsave)(&port->lock); in apple_port_irq_mask()
294 rmw_set(BIT(data->hwirq), port->base + PORT_INTMSK); in apple_port_irq_mask()
301 guard(raw_spinlock_irqsave)(&port->lock); in apple_port_irq_unmask()
302 rmw_clear(BIT(data->hwirq), port->base + PORT_INTMSK); in apple_port_irq_unmask()
314 if (!hwirq_is_intx(data->hwirq)) in apple_port_irq_ack()
315 writel_relaxed(BIT(data->hwirq), port->base + PORT_INTSTAT); in apple_port_irq_ack()
325 if (hwirq_is_intx(data->hwirq) ^ !!(type & IRQ_TYPE_LEVEL_MASK)) in apple_port_irq_set_type()
326 return -EINVAL; in apple_port_irq_set_type()
329 return 0; in apple_port_irq_set_type()
333 .name = "PCIe",
344 struct apple_pcie_port *port = domain->host_data; in apple_port_irq_domain_alloc()
348 for (i = 0; i < nr_irqs; i++) { in apple_port_irq_domain_alloc()
352 if (hwirq_is_intx(fwspec->param[0] + i)) { in apple_port_irq_domain_alloc()
357 irq_domain_set_info(domain, virq + i, fwspec->param[0] + i, in apple_port_irq_domain_alloc()
364 return 0; in apple_port_irq_domain_alloc()
372 for (i = 0; i < nr_irqs; i++) { in apple_port_irq_domain_free()
395 stat = readl_relaxed(port->base + PORT_INTSTAT); in apple_port_irq_handler()
398 generic_handle_domain_irq(port->domain, i); in apple_port_irq_handler()
405 struct fwnode_handle *fwnode = &port->np->fwnode; in apple_pcie_port_setup_irq()
406 struct apple_pcie *pcie = port->pcie; in apple_pcie_port_setup_irq() local
408 u32 val = 0; in apple_pcie_port_setup_irq()
411 irq = irq_of_parse_and_map(to_of_node(dev_fwnode(port->pcie->dev)), in apple_pcie_port_setup_irq()
412 port->idx); in apple_pcie_port_setup_irq()
414 return -ENXIO; in apple_pcie_port_setup_irq()
416 port->domain = irq_domain_create_linear(fwnode, 32, in apple_pcie_port_setup_irq()
419 if (!port->domain) in apple_pcie_port_setup_irq()
420 return -ENOMEM; in apple_pcie_port_setup_irq()
423 writel_relaxed(~0, port->base + PORT_INTMSK); in apple_pcie_port_setup_irq()
424 writel_relaxed(~0, port->base + PORT_INTSTAT); in apple_pcie_port_setup_irq()
425 writel_relaxed(~0, port->base + PORT_LINKCMDSTS); in apple_pcie_port_setup_irq()
432 port->base + pcie->hw->port_msiaddr); in apple_pcie_port_setup_irq()
433 if (pcie->hw->port_msiaddr_hi) in apple_pcie_port_setup_irq()
434 writel_relaxed(0, port->base + pcie->hw->port_msiaddr_hi); in apple_pcie_port_setup_irq()
437 if (pcie->hw->port_msimap) { in apple_pcie_port_setup_irq()
438 for (int i = 0; i < pcie->nvecs; i++) in apple_pcie_port_setup_irq()
441 port->base + pcie->hw->port_msimap + 4 * i); in apple_pcie_port_setup_irq()
443 writel_relaxed(0, port->base + PORT_MSIBASE); in apple_pcie_port_setup_irq()
444 val = ilog2(pcie->nvecs) << PORT_MSICFG_L2MSINUM_SHIFT; in apple_pcie_port_setup_irq()
447 writel_relaxed(val | PORT_MSICFG_EN, port->base + PORT_MSICFG); in apple_pcie_port_setup_irq()
448 return 0; in apple_pcie_port_setup_irq()
454 unsigned int hwirq = irq_domain_get_irq_data(port->domain, irq)->hwirq; in apple_pcie_port_irq()
458 dev_info_ratelimited(port->pcie->dev, "Link up on %pOF\n", in apple_pcie_port_irq()
459 port->np); in apple_pcie_port_irq()
460 complete_all(&port->pcie->event); in apple_pcie_port_irq()
463 dev_info_ratelimited(port->pcie->dev, "Link down on %pOF\n", in apple_pcie_port_irq()
464 port->np); in apple_pcie_port_irq()
484 for (i = 0; i < ARRAY_SIZE(port_irqs); i++) { in apple_pcie_port_register_irqs()
486 .fwnode = &port->np->fwnode, in apple_pcie_port_register_irqs()
489 [0] = port_irqs[i].hwirq, in apple_pcie_port_register_irqs()
495 irq = irq_domain_alloc_irqs(port->domain, 1, NUMA_NO_NODE, in apple_pcie_port_register_irqs()
500 ret = request_irq(irq, apple_pcie_port_irq, 0, in apple_pcie_port_register_irqs()
505 return 0; in apple_pcie_port_register_irqs()
508 static int apple_pcie_setup_refclk(struct apple_pcie *pcie, in apple_pcie_setup_refclk() argument
514 if (pcie->hw->phy_lane_ctl) in apple_pcie_setup_refclk()
515 rmw_set(PHY_LANE_CTL_CFGACC, port->phy + pcie->hw->phy_lane_ctl); in apple_pcie_setup_refclk()
517 rmw_set(PHY_LANE_CFG_REFCLK0REQ, port->phy + PHY_LANE_CFG); in apple_pcie_setup_refclk()
519 res = readl_relaxed_poll_timeout(port->phy + PHY_LANE_CFG, in apple_pcie_setup_refclk()
522 if (res < 0) in apple_pcie_setup_refclk()
525 rmw_set(PHY_LANE_CFG_REFCLK1REQ, port->phy + PHY_LANE_CFG); in apple_pcie_setup_refclk()
526 res = readl_relaxed_poll_timeout(port->phy + PHY_LANE_CFG, in apple_pcie_setup_refclk()
530 if (res < 0) in apple_pcie_setup_refclk()
533 if (pcie->hw->phy_lane_ctl) in apple_pcie_setup_refclk()
534 rmw_clear(PHY_LANE_CTL_CFGACC, port->phy + pcie->hw->phy_lane_ctl); in apple_pcie_setup_refclk()
536 rmw_set(PHY_LANE_CFG_REFCLKEN, port->phy + PHY_LANE_CFG); in apple_pcie_setup_refclk()
538 if (pcie->hw->port_refclk) in apple_pcie_setup_refclk()
539 rmw_set(PORT_REFCLK_EN, port->base + pcie->hw->port_refclk); in apple_pcie_setup_refclk()
541 return 0; in apple_pcie_setup_refclk()
546 return port->base + port->pcie->hw->port_rid2sid + 4 * idx; in port_rid2sid_addr()
557 static int apple_pcie_setup_port(struct apple_pcie *pcie, in apple_pcie_setup_port() argument
560 struct platform_device *platform = to_platform_device(pcie->dev); in apple_pcie_setup_port()
568 reset = devm_fwnode_gpiod_get(pcie->dev, of_fwnode_handle(np), "reset", in apple_pcie_setup_port()
573 port = devm_kzalloc(pcie->dev, sizeof(*port), GFP_KERNEL); in apple_pcie_setup_port()
575 return -ENOMEM; in apple_pcie_setup_port()
577 port->sid_map = devm_bitmap_zalloc(pcie->dev, pcie->hw->max_rid2sid, GFP_KERNEL); in apple_pcie_setup_port()
578 if (!port->sid_map) in apple_pcie_setup_port()
579 return -ENOMEM; in apple_pcie_setup_port()
581 ret = of_property_read_u32_index(np, "reg", 0, &idx); in apple_pcie_setup_port()
586 port->idx = idx >> 11; in apple_pcie_setup_port()
587 port->pcie = pcie; in apple_pcie_setup_port()
588 port->np = np; in apple_pcie_setup_port()
590 raw_spin_lock_init(&port->lock); in apple_pcie_setup_port()
592 snprintf(name, sizeof(name), "port%d", port->idx); in apple_pcie_setup_port()
595 res = platform_get_resource(platform, IORESOURCE_MEM, port->idx + 2); in apple_pcie_setup_port()
597 port->base = devm_ioremap_resource(&platform->dev, res); in apple_pcie_setup_port()
598 if (IS_ERR(port->base)) in apple_pcie_setup_port()
599 return PTR_ERR(port->base); in apple_pcie_setup_port()
601 snprintf(name, sizeof(name), "phy%d", port->idx); in apple_pcie_setup_port()
604 port->phy = devm_ioremap_resource(&platform->dev, res); in apple_pcie_setup_port()
606 port->phy = pcie->base + CORE_PHY_DEFAULT_BASE(port->idx); in apple_pcie_setup_port()
608 rmw_set(PORT_APPCLK_EN, port->base + PORT_APPCLK); in apple_pcie_setup_port()
613 ret = apple_pcie_setup_refclk(pcie, port); in apple_pcie_setup_port()
614 if (ret < 0) in apple_pcie_setup_port()
617 /* The minimal Tperst-clk value is 100us (PCIe CEM r5.0, 2.9.2) */ in apple_pcie_setup_port()
621 rmw_set(PORT_PERST_OFF, port->base + pcie->hw->port_perst); in apple_pcie_setup_port()
622 gpiod_set_value_cansleep(reset, 0); in apple_pcie_setup_port()
624 /* Wait for 100ms after PERST# deassertion (PCIe r5.0, 6.6.1) */ in apple_pcie_setup_port()
627 ret = readl_relaxed_poll_timeout(port->base + PORT_STATUS, stat, in apple_pcie_setup_port()
629 if (ret < 0) { in apple_pcie_setup_port()
630 dev_err(pcie->dev, "port %pOF ready wait timeout\n", np); in apple_pcie_setup_port()
634 if (pcie->hw->port_refclk) in apple_pcie_setup_port()
635 rmw_clear(PORT_REFCLK_CGDIS, port->base + pcie->hw->port_refclk); in apple_pcie_setup_port()
637 rmw_set(PHY_LANE_CFG_REFCLKCGEN, port->phy + PHY_LANE_CFG); in apple_pcie_setup_port()
639 rmw_clear(PORT_APPCLK_CGDIS, port->base + PORT_APPCLK); in apple_pcie_setup_port()
646 for (i = 0; i < pcie->hw->max_rid2sid; i++) { in apple_pcie_setup_port()
647 if (apple_pcie_rid2sid_write(port, i, 0xbad1d) != 0xbad1d) in apple_pcie_setup_port()
649 apple_pcie_rid2sid_write(port, i, 0); in apple_pcie_setup_port()
652 dev_dbg(pcie->dev, "%pOF: %d RID/SID mapping entries\n", np, i); in apple_pcie_setup_port()
654 port->sid_map_sz = i; in apple_pcie_setup_port()
656 list_add_tail(&port->entry, &pcie->ports); in apple_pcie_setup_port()
657 init_completion(&pcie->event); in apple_pcie_setup_port()
665 writel_relaxed(PORT_LTSSMCTL_START, port->base + PORT_LTSSMCTL); in apple_pcie_setup_port()
667 if (!wait_for_completion_timeout(&pcie->event, HZ / 10)) in apple_pcie_setup_port()
668 dev_warn(pcie->dev, "%pOF link didn't come up\n", np); in apple_pcie_setup_port()
670 return 0; in apple_pcie_setup_port()
685 static int apple_msi_init(struct apple_pcie *pcie) in apple_msi_init() argument
687 struct fwnode_handle *fwnode = dev_fwnode(pcie->dev); in apple_msi_init()
691 .size = pcie->nvecs, in apple_msi_init()
692 .host_data = pcie, in apple_msi_init()
697 ret = of_parse_phandle_with_args(to_of_node(fwnode), "msi-ranges", in apple_msi_init()
698 "#interrupt-cells", 0, &args); in apple_msi_init()
702 ret = of_property_read_u32_index(to_of_node(fwnode), "msi-ranges", in apple_msi_init()
703 args.args_count + 1, &pcie->nvecs); in apple_msi_init()
708 &pcie->fwspec); in apple_msi_init()
710 pcie->bitmap = devm_bitmap_zalloc(pcie->dev, pcie->nvecs, GFP_KERNEL); in apple_msi_init()
711 if (!pcie->bitmap) in apple_msi_init()
712 return -ENOMEM; in apple_msi_init()
714 info.parent = irq_find_matching_fwspec(&pcie->fwspec, DOMAIN_BUS_WIRED); in apple_msi_init()
716 dev_err(pcie->dev, "failed to find parent domain\n"); in apple_msi_init()
717 return -ENXIO; in apple_msi_init()
721 dev_err(pcie->dev, "failed to create IRQ domain\n"); in apple_msi_init()
722 return -ENOMEM; in apple_msi_init()
724 return 0; in apple_msi_init()
727 static void apple_pcie_register(struct apple_pcie *pcie) in apple_pcie_register() argument
731 list_add_tail(&pcie->entry, &pcie_list); in apple_pcie_register()
734 static void apple_pcie_unregister(struct apple_pcie *pcie) in apple_pcie_unregister() argument
738 list_del(&pcie->entry); in apple_pcie_unregister()
743 struct apple_pcie *pcie; in apple_pcie_lookup() local
747 list_for_each_entry(pcie, &pcie_list, entry) { in apple_pcie_lookup()
748 if (pcie->dev == dev) in apple_pcie_lookup()
749 return pcie; in apple_pcie_lookup()
757 struct pci_config_window *cfg = pdev->sysdata; in apple_pcie_get_port()
758 struct apple_pcie *pcie; in apple_pcie_get_port() local
762 pcie = apple_pcie_lookup(cfg->parent); in apple_pcie_get_port()
763 if (WARN_ON(!pcie)) in apple_pcie_get_port()
773 list_for_each_entry(port, &pcie->ports, entry) { in apple_pcie_get_port()
774 if (port->idx == PCI_SLOT(port_pdev->devfn)) in apple_pcie_get_port()
789 return 0; in apple_pcie_enable_device()
791 dev_dbg(&pdev->dev, "added to bus %s, index %d\n", in apple_pcie_enable_device()
792 pci_name(pdev->bus->self), port->idx); in apple_pcie_enable_device()
794 err = of_map_id(port->pcie->dev->of_node, rid, "iommu-map", in apple_pcie_enable_device()
795 "iommu-map-mask", NULL, &sid); in apple_pcie_enable_device()
799 mutex_lock(&port->pcie->lock); in apple_pcie_enable_device()
801 idx = bitmap_find_free_region(port->sid_map, port->sid_map_sz, 0); in apple_pcie_enable_device()
802 if (idx >= 0) { in apple_pcie_enable_device()
807 dev_dbg(&pdev->dev, "mapping RID%x to SID%x (index %d)\n", in apple_pcie_enable_device()
811 mutex_unlock(&port->pcie->lock); in apple_pcie_enable_device()
813 return idx >= 0 ? 0 : -ENOSPC; in apple_pcie_enable_device()
826 mutex_lock(&port->pcie->lock); in apple_pcie_disable_device()
828 for_each_set_bit(idx, port->sid_map, port->sid_map_sz) { in apple_pcie_disable_device()
832 if ((val & 0xffff) == rid) { in apple_pcie_disable_device()
833 apple_pcie_rid2sid_write(port, idx, 0); in apple_pcie_disable_device()
834 bitmap_release_region(port->sid_map, idx, 0); in apple_pcie_disable_device()
835 dev_dbg(&pdev->dev, "Released %x (%d)\n", val, idx); in apple_pcie_disable_device()
840 mutex_unlock(&port->pcie->lock); in apple_pcie_disable_device()
845 struct device *dev = cfg->parent; in apple_pcie_init()
846 struct apple_pcie *pcie; in apple_pcie_init() local
849 pcie = apple_pcie_lookup(dev); in apple_pcie_init()
850 if (WARN_ON(!pcie)) in apple_pcie_init()
851 return -ENOENT; in apple_pcie_init()
853 for_each_available_child_of_node_scoped(dev->of_node, of_port) { in apple_pcie_init()
854 ret = apple_pcie_setup_port(pcie, of_port); in apple_pcie_init()
861 return 0; in apple_pcie_init()
877 struct device *dev = &pdev->dev; in apple_pcie_probe()
878 struct apple_pcie *pcie; in apple_pcie_probe() local
881 pcie = devm_kzalloc(dev, sizeof(*pcie), GFP_KERNEL); in apple_pcie_probe()
882 if (!pcie) in apple_pcie_probe()
883 return -ENOMEM; in apple_pcie_probe()
885 pcie->dev = dev; in apple_pcie_probe()
886 pcie->hw = of_device_get_match_data(dev); in apple_pcie_probe()
887 if (!pcie->hw) in apple_pcie_probe()
888 return -ENODEV; in apple_pcie_probe()
889 pcie->base = devm_platform_ioremap_resource(pdev, 1); in apple_pcie_probe()
890 if (IS_ERR(pcie->base)) in apple_pcie_probe()
891 return PTR_ERR(pcie->base); in apple_pcie_probe()
893 mutex_init(&pcie->lock); in apple_pcie_probe()
894 INIT_LIST_HEAD(&pcie->ports); in apple_pcie_probe()
896 ret = apple_msi_init(pcie); in apple_pcie_probe()
900 apple_pcie_register(pcie); in apple_pcie_probe()
904 apple_pcie_unregister(pcie); in apple_pcie_probe()
910 { .compatible = "apple,t6020-pcie", .data = &t602x_hw },
911 { .compatible = "apple,pcie", .data = &t8103_hw },
919 .name = "pcie-apple",
926 MODULE_DESCRIPTION("Apple PCIe host bridge driver");