139bd5f82SMinda Chen // SPDX-License-Identifier: GPL-2.0 239bd5f82SMinda Chen /* 339bd5f82SMinda Chen * PLDA PCIe XpressRich host controller driver 439bd5f82SMinda Chen * 539bd5f82SMinda Chen * Copyright (C) 2023 Microchip Co. Ltd 676c91139SMinda Chen * StarFive Co. Ltd 739bd5f82SMinda Chen * 839bd5f82SMinda Chen * Author: Daire McNamara <daire.mcnamara@microchip.com> 939bd5f82SMinda Chen */ 1039bd5f82SMinda Chen 114602c370SMinda Chen #include <linux/irqchip/chained_irq.h> 124602c370SMinda Chen #include <linux/irqdomain.h> 134602c370SMinda Chen #include <linux/msi.h> 144602c370SMinda Chen #include <linux/pci_regs.h> 1539bd5f82SMinda Chen #include <linux/pci-ecam.h> 1639bd5f82SMinda Chen 1739bd5f82SMinda Chen #include "pcie-plda.h" 1839bd5f82SMinda Chen 1976c91139SMinda Chen void __iomem *plda_pcie_map_bus(struct pci_bus *bus, unsigned int devfn, 2076c91139SMinda Chen int where) 2176c91139SMinda Chen { 2276c91139SMinda Chen struct plda_pcie_rp *pcie = bus->sysdata; 2376c91139SMinda Chen 2476c91139SMinda Chen return pcie->config_base + PCIE_ECAM_OFFSET(bus->number, devfn, where); 2576c91139SMinda Chen } 2676c91139SMinda Chen EXPORT_SYMBOL_GPL(plda_pcie_map_bus); 2776c91139SMinda Chen 284602c370SMinda Chen static void plda_handle_msi(struct irq_desc *desc) 294602c370SMinda Chen { 304602c370SMinda Chen struct plda_pcie_rp *port = irq_desc_get_handler_data(desc); 314602c370SMinda Chen struct irq_chip *chip = irq_desc_get_chip(desc); 324602c370SMinda Chen struct device *dev = port->dev; 334602c370SMinda Chen struct plda_msi *msi = &port->msi; 344602c370SMinda Chen void __iomem *bridge_base_addr = port->bridge_addr; 354602c370SMinda Chen unsigned long status; 364602c370SMinda Chen u32 bit; 374602c370SMinda Chen int ret; 384602c370SMinda Chen 394602c370SMinda Chen chained_irq_enter(chip, desc); 404602c370SMinda Chen 414602c370SMinda Chen status = readl_relaxed(bridge_base_addr + ISTATUS_LOCAL); 424602c370SMinda Chen if (status & PM_MSI_INT_MSI_MASK) { 434602c370SMinda Chen writel_relaxed(status & PM_MSI_INT_MSI_MASK, 444602c370SMinda Chen bridge_base_addr + ISTATUS_LOCAL); 454602c370SMinda Chen status = readl_relaxed(bridge_base_addr + ISTATUS_MSI); 464602c370SMinda Chen for_each_set_bit(bit, &status, msi->num_vectors) { 474602c370SMinda Chen ret = generic_handle_domain_irq(msi->dev_domain, bit); 484602c370SMinda Chen if (ret) 494602c370SMinda Chen dev_err_ratelimited(dev, "bad MSI IRQ %d\n", 504602c370SMinda Chen bit); 514602c370SMinda Chen } 524602c370SMinda Chen } 534602c370SMinda Chen 544602c370SMinda Chen chained_irq_exit(chip, desc); 554602c370SMinda Chen } 564602c370SMinda Chen 574602c370SMinda Chen static void plda_msi_bottom_irq_ack(struct irq_data *data) 584602c370SMinda Chen { 594602c370SMinda Chen struct plda_pcie_rp *port = irq_data_get_irq_chip_data(data); 604602c370SMinda Chen void __iomem *bridge_base_addr = port->bridge_addr; 614602c370SMinda Chen u32 bitpos = data->hwirq; 624602c370SMinda Chen 634602c370SMinda Chen writel_relaxed(BIT(bitpos), bridge_base_addr + ISTATUS_MSI); 644602c370SMinda Chen } 654602c370SMinda Chen 664602c370SMinda Chen static void plda_compose_msi_msg(struct irq_data *data, struct msi_msg *msg) 674602c370SMinda Chen { 684602c370SMinda Chen struct plda_pcie_rp *port = irq_data_get_irq_chip_data(data); 694602c370SMinda Chen phys_addr_t addr = port->msi.vector_phy; 704602c370SMinda Chen 714602c370SMinda Chen msg->address_lo = lower_32_bits(addr); 724602c370SMinda Chen msg->address_hi = upper_32_bits(addr); 734602c370SMinda Chen msg->data = data->hwirq; 744602c370SMinda Chen 754602c370SMinda Chen dev_dbg(port->dev, "msi#%x address_hi %#x address_lo %#x\n", 764602c370SMinda Chen (int)data->hwirq, msg->address_hi, msg->address_lo); 774602c370SMinda Chen } 784602c370SMinda Chen 794602c370SMinda Chen static struct irq_chip plda_msi_bottom_irq_chip = { 804602c370SMinda Chen .name = "PLDA MSI", 814602c370SMinda Chen .irq_ack = plda_msi_bottom_irq_ack, 824602c370SMinda Chen .irq_compose_msi_msg = plda_compose_msi_msg, 834602c370SMinda Chen }; 844602c370SMinda Chen 854602c370SMinda Chen static int plda_irq_msi_domain_alloc(struct irq_domain *domain, 864602c370SMinda Chen unsigned int virq, 874602c370SMinda Chen unsigned int nr_irqs, 884602c370SMinda Chen void *args) 894602c370SMinda Chen { 904602c370SMinda Chen struct plda_pcie_rp *port = domain->host_data; 914602c370SMinda Chen struct plda_msi *msi = &port->msi; 924602c370SMinda Chen unsigned long bit; 934602c370SMinda Chen 944602c370SMinda Chen mutex_lock(&msi->lock); 954602c370SMinda Chen bit = find_first_zero_bit(msi->used, msi->num_vectors); 964602c370SMinda Chen if (bit >= msi->num_vectors) { 974602c370SMinda Chen mutex_unlock(&msi->lock); 984602c370SMinda Chen return -ENOSPC; 994602c370SMinda Chen } 1004602c370SMinda Chen 1014602c370SMinda Chen set_bit(bit, msi->used); 1024602c370SMinda Chen 1034602c370SMinda Chen irq_domain_set_info(domain, virq, bit, &plda_msi_bottom_irq_chip, 1044602c370SMinda Chen domain->host_data, handle_edge_irq, NULL, NULL); 1054602c370SMinda Chen 1064602c370SMinda Chen mutex_unlock(&msi->lock); 1074602c370SMinda Chen 1084602c370SMinda Chen return 0; 1094602c370SMinda Chen } 1104602c370SMinda Chen 1114602c370SMinda Chen static void plda_irq_msi_domain_free(struct irq_domain *domain, 1124602c370SMinda Chen unsigned int virq, 1134602c370SMinda Chen unsigned int nr_irqs) 1144602c370SMinda Chen { 1154602c370SMinda Chen struct irq_data *d = irq_domain_get_irq_data(domain, virq); 1164602c370SMinda Chen struct plda_pcie_rp *port = irq_data_get_irq_chip_data(d); 1174602c370SMinda Chen struct plda_msi *msi = &port->msi; 1184602c370SMinda Chen 1194602c370SMinda Chen mutex_lock(&msi->lock); 1204602c370SMinda Chen 1214602c370SMinda Chen if (test_bit(d->hwirq, msi->used)) 1224602c370SMinda Chen __clear_bit(d->hwirq, msi->used); 1234602c370SMinda Chen else 1244602c370SMinda Chen dev_err(port->dev, "trying to free unused MSI%lu\n", d->hwirq); 1254602c370SMinda Chen 1264602c370SMinda Chen mutex_unlock(&msi->lock); 1274602c370SMinda Chen } 1284602c370SMinda Chen 1294602c370SMinda Chen static const struct irq_domain_ops msi_domain_ops = { 1304602c370SMinda Chen .alloc = plda_irq_msi_domain_alloc, 1314602c370SMinda Chen .free = plda_irq_msi_domain_free, 1324602c370SMinda Chen }; 1334602c370SMinda Chen 1344602c370SMinda Chen static struct irq_chip plda_msi_irq_chip = { 1354602c370SMinda Chen .name = "PLDA PCIe MSI", 1364602c370SMinda Chen .irq_ack = irq_chip_ack_parent, 1374602c370SMinda Chen .irq_mask = pci_msi_mask_irq, 1384602c370SMinda Chen .irq_unmask = pci_msi_unmask_irq, 1394602c370SMinda Chen }; 1404602c370SMinda Chen 1414602c370SMinda Chen static struct msi_domain_info plda_msi_domain_info = { 142*e934abaaSMarek Vasut .flags = MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS | 143*e934abaaSMarek Vasut MSI_FLAG_NO_AFFINITY | MSI_FLAG_PCI_MSIX, 1444602c370SMinda Chen .chip = &plda_msi_irq_chip, 1454602c370SMinda Chen }; 1464602c370SMinda Chen 1474602c370SMinda Chen static int plda_allocate_msi_domains(struct plda_pcie_rp *port) 1484602c370SMinda Chen { 1494602c370SMinda Chen struct device *dev = port->dev; 1504602c370SMinda Chen struct fwnode_handle *fwnode = of_node_to_fwnode(dev->of_node); 1514602c370SMinda Chen struct plda_msi *msi = &port->msi; 1524602c370SMinda Chen 1534602c370SMinda Chen mutex_init(&port->msi.lock); 1544602c370SMinda Chen 1554602c370SMinda Chen msi->dev_domain = irq_domain_add_linear(NULL, msi->num_vectors, 1564602c370SMinda Chen &msi_domain_ops, port); 1574602c370SMinda Chen if (!msi->dev_domain) { 1584602c370SMinda Chen dev_err(dev, "failed to create IRQ domain\n"); 1594602c370SMinda Chen return -ENOMEM; 1604602c370SMinda Chen } 1614602c370SMinda Chen 1624602c370SMinda Chen msi->msi_domain = pci_msi_create_irq_domain(fwnode, 1634602c370SMinda Chen &plda_msi_domain_info, 1644602c370SMinda Chen msi->dev_domain); 1654602c370SMinda Chen if (!msi->msi_domain) { 1664602c370SMinda Chen dev_err(dev, "failed to create MSI domain\n"); 1674602c370SMinda Chen irq_domain_remove(msi->dev_domain); 1684602c370SMinda Chen return -ENOMEM; 1694602c370SMinda Chen } 1704602c370SMinda Chen 1714602c370SMinda Chen return 0; 1724602c370SMinda Chen } 1734602c370SMinda Chen 1744602c370SMinda Chen static void plda_handle_intx(struct irq_desc *desc) 1754602c370SMinda Chen { 1764602c370SMinda Chen struct plda_pcie_rp *port = irq_desc_get_handler_data(desc); 1774602c370SMinda Chen struct irq_chip *chip = irq_desc_get_chip(desc); 1784602c370SMinda Chen struct device *dev = port->dev; 1794602c370SMinda Chen void __iomem *bridge_base_addr = port->bridge_addr; 1804602c370SMinda Chen unsigned long status; 1814602c370SMinda Chen u32 bit; 1824602c370SMinda Chen int ret; 1834602c370SMinda Chen 1844602c370SMinda Chen chained_irq_enter(chip, desc); 1854602c370SMinda Chen 1864602c370SMinda Chen status = readl_relaxed(bridge_base_addr + ISTATUS_LOCAL); 1874602c370SMinda Chen if (status & PM_MSI_INT_INTX_MASK) { 1884602c370SMinda Chen status &= PM_MSI_INT_INTX_MASK; 1894602c370SMinda Chen status >>= PM_MSI_INT_INTX_SHIFT; 1904602c370SMinda Chen for_each_set_bit(bit, &status, PCI_NUM_INTX) { 1914602c370SMinda Chen ret = generic_handle_domain_irq(port->intx_domain, bit); 1924602c370SMinda Chen if (ret) 1934602c370SMinda Chen dev_err_ratelimited(dev, "bad INTx IRQ %d\n", 1944602c370SMinda Chen bit); 1954602c370SMinda Chen } 1964602c370SMinda Chen } 1974602c370SMinda Chen 1984602c370SMinda Chen chained_irq_exit(chip, desc); 1994602c370SMinda Chen } 2004602c370SMinda Chen 2014602c370SMinda Chen static void plda_ack_intx_irq(struct irq_data *data) 2024602c370SMinda Chen { 2034602c370SMinda Chen struct plda_pcie_rp *port = irq_data_get_irq_chip_data(data); 2044602c370SMinda Chen void __iomem *bridge_base_addr = port->bridge_addr; 2054602c370SMinda Chen u32 mask = BIT(data->hwirq + PM_MSI_INT_INTX_SHIFT); 2064602c370SMinda Chen 2074602c370SMinda Chen writel_relaxed(mask, bridge_base_addr + ISTATUS_LOCAL); 2084602c370SMinda Chen } 2094602c370SMinda Chen 2104602c370SMinda Chen static void plda_mask_intx_irq(struct irq_data *data) 2114602c370SMinda Chen { 2124602c370SMinda Chen struct plda_pcie_rp *port = irq_data_get_irq_chip_data(data); 2134602c370SMinda Chen void __iomem *bridge_base_addr = port->bridge_addr; 2144602c370SMinda Chen unsigned long flags; 2154602c370SMinda Chen u32 mask = BIT(data->hwirq + PM_MSI_INT_INTX_SHIFT); 2164602c370SMinda Chen u32 val; 2174602c370SMinda Chen 2184602c370SMinda Chen raw_spin_lock_irqsave(&port->lock, flags); 2194602c370SMinda Chen val = readl_relaxed(bridge_base_addr + IMASK_LOCAL); 2204602c370SMinda Chen val &= ~mask; 2214602c370SMinda Chen writel_relaxed(val, bridge_base_addr + IMASK_LOCAL); 2224602c370SMinda Chen raw_spin_unlock_irqrestore(&port->lock, flags); 2234602c370SMinda Chen } 2244602c370SMinda Chen 2254602c370SMinda Chen static void plda_unmask_intx_irq(struct irq_data *data) 2264602c370SMinda Chen { 2274602c370SMinda Chen struct plda_pcie_rp *port = irq_data_get_irq_chip_data(data); 2284602c370SMinda Chen void __iomem *bridge_base_addr = port->bridge_addr; 2294602c370SMinda Chen unsigned long flags; 2304602c370SMinda Chen u32 mask = BIT(data->hwirq + PM_MSI_INT_INTX_SHIFT); 2314602c370SMinda Chen u32 val; 2324602c370SMinda Chen 2334602c370SMinda Chen raw_spin_lock_irqsave(&port->lock, flags); 2344602c370SMinda Chen val = readl_relaxed(bridge_base_addr + IMASK_LOCAL); 2354602c370SMinda Chen val |= mask; 2364602c370SMinda Chen writel_relaxed(val, bridge_base_addr + IMASK_LOCAL); 2374602c370SMinda Chen raw_spin_unlock_irqrestore(&port->lock, flags); 2384602c370SMinda Chen } 2394602c370SMinda Chen 2404602c370SMinda Chen static struct irq_chip plda_intx_irq_chip = { 2414602c370SMinda Chen .name = "PLDA PCIe INTx", 2424602c370SMinda Chen .irq_ack = plda_ack_intx_irq, 2434602c370SMinda Chen .irq_mask = plda_mask_intx_irq, 2444602c370SMinda Chen .irq_unmask = plda_unmask_intx_irq, 2454602c370SMinda Chen }; 2464602c370SMinda Chen 2474602c370SMinda Chen static int plda_pcie_intx_map(struct irq_domain *domain, unsigned int irq, 2484602c370SMinda Chen irq_hw_number_t hwirq) 2494602c370SMinda Chen { 2504602c370SMinda Chen irq_set_chip_and_handler(irq, &plda_intx_irq_chip, handle_level_irq); 2514602c370SMinda Chen irq_set_chip_data(irq, domain->host_data); 2524602c370SMinda Chen 2534602c370SMinda Chen return 0; 2544602c370SMinda Chen } 2554602c370SMinda Chen 2564602c370SMinda Chen static const struct irq_domain_ops intx_domain_ops = { 2574602c370SMinda Chen .map = plda_pcie_intx_map, 2584602c370SMinda Chen }; 2594602c370SMinda Chen 2604602c370SMinda Chen static u32 plda_get_events(struct plda_pcie_rp *port) 2614602c370SMinda Chen { 2624602c370SMinda Chen u32 events, val, origin; 2634602c370SMinda Chen 2644602c370SMinda Chen origin = readl_relaxed(port->bridge_addr + ISTATUS_LOCAL); 2654602c370SMinda Chen 2664602c370SMinda Chen /* MSI event and sys events */ 2674602c370SMinda Chen val = (origin & SYS_AND_MSI_MASK) >> PM_MSI_INT_MSI_SHIFT; 2684602c370SMinda Chen events = val << (PM_MSI_INT_MSI_SHIFT - PCI_NUM_INTX + 1); 2694602c370SMinda Chen 2704602c370SMinda Chen /* INTx events */ 2714602c370SMinda Chen if (origin & PM_MSI_INT_INTX_MASK) 2724602c370SMinda Chen events |= BIT(PM_MSI_INT_INTX_SHIFT); 2734602c370SMinda Chen 2744602c370SMinda Chen /* remains are same with register */ 2754602c370SMinda Chen events |= origin & GENMASK(P_ATR_EVT_DOORBELL_SHIFT, 0); 2764602c370SMinda Chen 2774602c370SMinda Chen return events; 2784602c370SMinda Chen } 2794602c370SMinda Chen 2804602c370SMinda Chen static irqreturn_t plda_event_handler(int irq, void *dev_id) 2814602c370SMinda Chen { 2824602c370SMinda Chen return IRQ_HANDLED; 2834602c370SMinda Chen } 2844602c370SMinda Chen 2854602c370SMinda Chen static void plda_handle_event(struct irq_desc *desc) 2864602c370SMinda Chen { 2874602c370SMinda Chen struct plda_pcie_rp *port = irq_desc_get_handler_data(desc); 2884602c370SMinda Chen unsigned long events; 2894602c370SMinda Chen u32 bit; 2904602c370SMinda Chen struct irq_chip *chip = irq_desc_get_chip(desc); 2914602c370SMinda Chen 2924602c370SMinda Chen chained_irq_enter(chip, desc); 2934602c370SMinda Chen 2944602c370SMinda Chen events = port->event_ops->get_events(port); 2954602c370SMinda Chen 296a576fff3SMinda Chen events &= port->events_bitmap; 2974602c370SMinda Chen for_each_set_bit(bit, &events, port->num_events) 2984602c370SMinda Chen generic_handle_domain_irq(port->event_domain, bit); 2994602c370SMinda Chen 3004602c370SMinda Chen chained_irq_exit(chip, desc); 3014602c370SMinda Chen } 3024602c370SMinda Chen 3034602c370SMinda Chen static u32 plda_hwirq_to_mask(int hwirq) 3044602c370SMinda Chen { 3054602c370SMinda Chen u32 mask; 3064602c370SMinda Chen 3074602c370SMinda Chen /* hwirq 23 - 0 are the same with register */ 3084602c370SMinda Chen if (hwirq < EVENT_PM_MSI_INT_INTX) 3094602c370SMinda Chen mask = BIT(hwirq); 3104602c370SMinda Chen else if (hwirq == EVENT_PM_MSI_INT_INTX) 3114602c370SMinda Chen mask = PM_MSI_INT_INTX_MASK; 3124602c370SMinda Chen else 3134602c370SMinda Chen mask = BIT(hwirq + PCI_NUM_INTX - 1); 3144602c370SMinda Chen 3154602c370SMinda Chen return mask; 3164602c370SMinda Chen } 3174602c370SMinda Chen 3184602c370SMinda Chen static void plda_ack_event_irq(struct irq_data *data) 3194602c370SMinda Chen { 3204602c370SMinda Chen struct plda_pcie_rp *port = irq_data_get_irq_chip_data(data); 3214602c370SMinda Chen 3224602c370SMinda Chen writel_relaxed(plda_hwirq_to_mask(data->hwirq), 3234602c370SMinda Chen port->bridge_addr + ISTATUS_LOCAL); 3244602c370SMinda Chen } 3254602c370SMinda Chen 3264602c370SMinda Chen static void plda_mask_event_irq(struct irq_data *data) 3274602c370SMinda Chen { 3284602c370SMinda Chen struct plda_pcie_rp *port = irq_data_get_irq_chip_data(data); 3294602c370SMinda Chen u32 mask, val; 3304602c370SMinda Chen 3314602c370SMinda Chen mask = plda_hwirq_to_mask(data->hwirq); 3324602c370SMinda Chen 3334602c370SMinda Chen raw_spin_lock(&port->lock); 3344602c370SMinda Chen val = readl_relaxed(port->bridge_addr + IMASK_LOCAL); 3354602c370SMinda Chen val &= ~mask; 3364602c370SMinda Chen writel_relaxed(val, port->bridge_addr + IMASK_LOCAL); 3374602c370SMinda Chen raw_spin_unlock(&port->lock); 3384602c370SMinda Chen } 3394602c370SMinda Chen 3404602c370SMinda Chen static void plda_unmask_event_irq(struct irq_data *data) 3414602c370SMinda Chen { 3424602c370SMinda Chen struct plda_pcie_rp *port = irq_data_get_irq_chip_data(data); 3434602c370SMinda Chen u32 mask, val; 3444602c370SMinda Chen 3454602c370SMinda Chen mask = plda_hwirq_to_mask(data->hwirq); 3464602c370SMinda Chen 3474602c370SMinda Chen raw_spin_lock(&port->lock); 3484602c370SMinda Chen val = readl_relaxed(port->bridge_addr + IMASK_LOCAL); 3494602c370SMinda Chen val |= mask; 3504602c370SMinda Chen writel_relaxed(val, port->bridge_addr + IMASK_LOCAL); 3514602c370SMinda Chen raw_spin_unlock(&port->lock); 3524602c370SMinda Chen } 3534602c370SMinda Chen 3544602c370SMinda Chen static struct irq_chip plda_event_irq_chip = { 3554602c370SMinda Chen .name = "PLDA PCIe EVENT", 3564602c370SMinda Chen .irq_ack = plda_ack_event_irq, 3574602c370SMinda Chen .irq_mask = plda_mask_event_irq, 3584602c370SMinda Chen .irq_unmask = plda_unmask_event_irq, 3594602c370SMinda Chen }; 3604602c370SMinda Chen 3614602c370SMinda Chen static const struct plda_event_ops plda_event_ops = { 3624602c370SMinda Chen .get_events = plda_get_events, 3634602c370SMinda Chen }; 3644602c370SMinda Chen 3654602c370SMinda Chen static int plda_pcie_event_map(struct irq_domain *domain, unsigned int irq, 3664602c370SMinda Chen irq_hw_number_t hwirq) 3674602c370SMinda Chen { 3684602c370SMinda Chen struct plda_pcie_rp *port = (void *)domain->host_data; 3694602c370SMinda Chen 3704602c370SMinda Chen irq_set_chip_and_handler(irq, port->event_irq_chip, handle_level_irq); 3714602c370SMinda Chen irq_set_chip_data(irq, domain->host_data); 3724602c370SMinda Chen 3734602c370SMinda Chen return 0; 3744602c370SMinda Chen } 3754602c370SMinda Chen 3764602c370SMinda Chen static const struct irq_domain_ops plda_event_domain_ops = { 3774602c370SMinda Chen .map = plda_pcie_event_map, 3784602c370SMinda Chen }; 3794602c370SMinda Chen 3804602c370SMinda Chen static int plda_pcie_init_irq_domains(struct plda_pcie_rp *port) 3814602c370SMinda Chen { 3824602c370SMinda Chen struct device *dev = port->dev; 3834602c370SMinda Chen struct device_node *node = dev->of_node; 3844602c370SMinda Chen struct device_node *pcie_intc_node; 3854602c370SMinda Chen 3864602c370SMinda Chen /* Setup INTx */ 3874602c370SMinda Chen pcie_intc_node = of_get_next_child(node, NULL); 3884602c370SMinda Chen if (!pcie_intc_node) { 3894602c370SMinda Chen dev_err(dev, "failed to find PCIe Intc node\n"); 3904602c370SMinda Chen return -EINVAL; 3914602c370SMinda Chen } 3924602c370SMinda Chen 3934602c370SMinda Chen port->event_domain = irq_domain_add_linear(pcie_intc_node, 3944602c370SMinda Chen port->num_events, 3954602c370SMinda Chen &plda_event_domain_ops, 3964602c370SMinda Chen port); 3974602c370SMinda Chen if (!port->event_domain) { 3984602c370SMinda Chen dev_err(dev, "failed to get event domain\n"); 3994602c370SMinda Chen of_node_put(pcie_intc_node); 4004602c370SMinda Chen return -ENOMEM; 4014602c370SMinda Chen } 4024602c370SMinda Chen 4034602c370SMinda Chen irq_domain_update_bus_token(port->event_domain, DOMAIN_BUS_NEXUS); 4044602c370SMinda Chen 4054602c370SMinda Chen port->intx_domain = irq_domain_add_linear(pcie_intc_node, PCI_NUM_INTX, 4064602c370SMinda Chen &intx_domain_ops, port); 4074602c370SMinda Chen if (!port->intx_domain) { 4084602c370SMinda Chen dev_err(dev, "failed to get an INTx IRQ domain\n"); 4094602c370SMinda Chen of_node_put(pcie_intc_node); 4104602c370SMinda Chen return -ENOMEM; 4114602c370SMinda Chen } 4124602c370SMinda Chen 4134602c370SMinda Chen irq_domain_update_bus_token(port->intx_domain, DOMAIN_BUS_WIRED); 4144602c370SMinda Chen 4154602c370SMinda Chen of_node_put(pcie_intc_node); 4164602c370SMinda Chen raw_spin_lock_init(&port->lock); 4174602c370SMinda Chen 4184602c370SMinda Chen return plda_allocate_msi_domains(port); 4194602c370SMinda Chen } 4204602c370SMinda Chen 4214602c370SMinda Chen int plda_init_interrupts(struct platform_device *pdev, 4224602c370SMinda Chen struct plda_pcie_rp *port, 4234602c370SMinda Chen const struct plda_event *event) 4244602c370SMinda Chen { 4254602c370SMinda Chen struct device *dev = &pdev->dev; 42676c91139SMinda Chen int event_irq, ret; 427a576fff3SMinda Chen u32 i; 4284602c370SMinda Chen 4294602c370SMinda Chen if (!port->event_ops) 4304602c370SMinda Chen port->event_ops = &plda_event_ops; 4314602c370SMinda Chen 4324602c370SMinda Chen if (!port->event_irq_chip) 4334602c370SMinda Chen port->event_irq_chip = &plda_event_irq_chip; 4344602c370SMinda Chen 4354602c370SMinda Chen ret = plda_pcie_init_irq_domains(port); 4364602c370SMinda Chen if (ret) { 4374602c370SMinda Chen dev_err(dev, "failed creating IRQ domains\n"); 4384602c370SMinda Chen return ret; 4394602c370SMinda Chen } 4404602c370SMinda Chen 44176c91139SMinda Chen port->irq = platform_get_irq(pdev, 0); 44276c91139SMinda Chen if (port->irq < 0) 4434602c370SMinda Chen return -ENODEV; 4444602c370SMinda Chen 445a576fff3SMinda Chen for_each_set_bit(i, &port->events_bitmap, port->num_events) { 4464602c370SMinda Chen event_irq = irq_create_mapping(port->event_domain, i); 4474602c370SMinda Chen if (!event_irq) { 4484602c370SMinda Chen dev_err(dev, "failed to map hwirq %d\n", i); 4494602c370SMinda Chen return -ENXIO; 4504602c370SMinda Chen } 4514602c370SMinda Chen 4524602c370SMinda Chen if (event->request_event_irq) 4534602c370SMinda Chen ret = event->request_event_irq(port, event_irq, i); 4544602c370SMinda Chen else 4554602c370SMinda Chen ret = devm_request_irq(dev, event_irq, 4564602c370SMinda Chen plda_event_handler, 4574602c370SMinda Chen 0, NULL, port); 4584602c370SMinda Chen 4594602c370SMinda Chen if (ret) { 4604602c370SMinda Chen dev_err(dev, "failed to request IRQ %d\n", event_irq); 4614602c370SMinda Chen return ret; 4624602c370SMinda Chen } 4634602c370SMinda Chen } 4644602c370SMinda Chen 46576c91139SMinda Chen port->intx_irq = irq_create_mapping(port->event_domain, 4664602c370SMinda Chen event->intx_event); 46776c91139SMinda Chen if (!port->intx_irq) { 4684602c370SMinda Chen dev_err(dev, "failed to map INTx interrupt\n"); 4694602c370SMinda Chen return -ENXIO; 4704602c370SMinda Chen } 4714602c370SMinda Chen 4724602c370SMinda Chen /* Plug the INTx chained handler */ 47376c91139SMinda Chen irq_set_chained_handler_and_data(port->intx_irq, plda_handle_intx, port); 4744602c370SMinda Chen 47576c91139SMinda Chen port->msi_irq = irq_create_mapping(port->event_domain, 4764602c370SMinda Chen event->msi_event); 47776c91139SMinda Chen if (!port->msi_irq) 4784602c370SMinda Chen return -ENXIO; 4794602c370SMinda Chen 4804602c370SMinda Chen /* Plug the MSI chained handler */ 48176c91139SMinda Chen irq_set_chained_handler_and_data(port->msi_irq, plda_handle_msi, port); 4824602c370SMinda Chen 4834602c370SMinda Chen /* Plug the main event chained handler */ 48476c91139SMinda Chen irq_set_chained_handler_and_data(port->irq, plda_handle_event, port); 4854602c370SMinda Chen 4864602c370SMinda Chen return 0; 4874602c370SMinda Chen } 4884602c370SMinda Chen EXPORT_SYMBOL_GPL(plda_init_interrupts); 4894602c370SMinda Chen 49039bd5f82SMinda Chen void plda_pcie_setup_window(void __iomem *bridge_base_addr, u32 index, 49139bd5f82SMinda Chen phys_addr_t axi_addr, phys_addr_t pci_addr, 49239bd5f82SMinda Chen size_t size) 49339bd5f82SMinda Chen { 49439bd5f82SMinda Chen u32 atr_sz = ilog2(size) - 1; 49539bd5f82SMinda Chen u32 val; 49639bd5f82SMinda Chen 49739bd5f82SMinda Chen if (index == 0) 49839bd5f82SMinda Chen val = PCIE_CONFIG_INTERFACE; 49939bd5f82SMinda Chen else 50039bd5f82SMinda Chen val = PCIE_TX_RX_INTERFACE; 50139bd5f82SMinda Chen 50239bd5f82SMinda Chen writel(val, bridge_base_addr + (index * ATR_ENTRY_SIZE) + 50339bd5f82SMinda Chen ATR0_AXI4_SLV0_TRSL_PARAM); 50439bd5f82SMinda Chen 50539bd5f82SMinda Chen val = lower_32_bits(axi_addr) | (atr_sz << ATR_SIZE_SHIFT) | 50639bd5f82SMinda Chen ATR_IMPL_ENABLE; 50739bd5f82SMinda Chen writel(val, bridge_base_addr + (index * ATR_ENTRY_SIZE) + 50839bd5f82SMinda Chen ATR0_AXI4_SLV0_SRCADDR_PARAM); 50939bd5f82SMinda Chen 51039bd5f82SMinda Chen val = upper_32_bits(axi_addr); 51139bd5f82SMinda Chen writel(val, bridge_base_addr + (index * ATR_ENTRY_SIZE) + 51239bd5f82SMinda Chen ATR0_AXI4_SLV0_SRC_ADDR); 51339bd5f82SMinda Chen 51439bd5f82SMinda Chen val = lower_32_bits(pci_addr); 51539bd5f82SMinda Chen writel(val, bridge_base_addr + (index * ATR_ENTRY_SIZE) + 51639bd5f82SMinda Chen ATR0_AXI4_SLV0_TRSL_ADDR_LSB); 51739bd5f82SMinda Chen 51839bd5f82SMinda Chen val = upper_32_bits(pci_addr); 51939bd5f82SMinda Chen writel(val, bridge_base_addr + (index * ATR_ENTRY_SIZE) + 52039bd5f82SMinda Chen ATR0_AXI4_SLV0_TRSL_ADDR_UDW); 52139bd5f82SMinda Chen 52239bd5f82SMinda Chen val = readl(bridge_base_addr + ATR0_PCIE_WIN0_SRCADDR_PARAM); 52339bd5f82SMinda Chen val |= (ATR0_PCIE_ATR_SIZE << ATR0_PCIE_ATR_SIZE_SHIFT); 52439bd5f82SMinda Chen writel(val, bridge_base_addr + ATR0_PCIE_WIN0_SRCADDR_PARAM); 52539bd5f82SMinda Chen writel(0, bridge_base_addr + ATR0_PCIE_WIN0_SRC_ADDR); 52639bd5f82SMinda Chen } 52739bd5f82SMinda Chen EXPORT_SYMBOL_GPL(plda_pcie_setup_window); 52839bd5f82SMinda Chen 529d76ef053SMinda Chen int plda_pcie_setup_iomems(struct pci_host_bridge *bridge, 53039bd5f82SMinda Chen struct plda_pcie_rp *port) 53139bd5f82SMinda Chen { 53239bd5f82SMinda Chen void __iomem *bridge_base_addr = port->bridge_addr; 53339bd5f82SMinda Chen struct resource_entry *entry; 53439bd5f82SMinda Chen u64 pci_addr; 53539bd5f82SMinda Chen u32 index = 1; 53639bd5f82SMinda Chen 53739bd5f82SMinda Chen resource_list_for_each_entry(entry, &bridge->windows) { 53839bd5f82SMinda Chen if (resource_type(entry->res) == IORESOURCE_MEM) { 53939bd5f82SMinda Chen pci_addr = entry->res->start - entry->offset; 54039bd5f82SMinda Chen plda_pcie_setup_window(bridge_base_addr, index, 54139bd5f82SMinda Chen entry->res->start, pci_addr, 54239bd5f82SMinda Chen resource_size(entry->res)); 54339bd5f82SMinda Chen index++; 54439bd5f82SMinda Chen } 54539bd5f82SMinda Chen } 54639bd5f82SMinda Chen 54739bd5f82SMinda Chen return 0; 54839bd5f82SMinda Chen } 54939bd5f82SMinda Chen EXPORT_SYMBOL_GPL(plda_pcie_setup_iomems); 55076c91139SMinda Chen 55176c91139SMinda Chen static void plda_pcie_irq_domain_deinit(struct plda_pcie_rp *pcie) 55276c91139SMinda Chen { 55376c91139SMinda Chen irq_set_chained_handler_and_data(pcie->irq, NULL, NULL); 55476c91139SMinda Chen irq_set_chained_handler_and_data(pcie->msi_irq, NULL, NULL); 55576c91139SMinda Chen irq_set_chained_handler_and_data(pcie->intx_irq, NULL, NULL); 55676c91139SMinda Chen 55776c91139SMinda Chen irq_domain_remove(pcie->msi.msi_domain); 55876c91139SMinda Chen irq_domain_remove(pcie->msi.dev_domain); 55976c91139SMinda Chen 56076c91139SMinda Chen irq_domain_remove(pcie->intx_domain); 56176c91139SMinda Chen irq_domain_remove(pcie->event_domain); 56276c91139SMinda Chen } 56376c91139SMinda Chen 56476c91139SMinda Chen int plda_pcie_host_init(struct plda_pcie_rp *port, struct pci_ops *ops, 56576c91139SMinda Chen const struct plda_event *plda_event) 56676c91139SMinda Chen { 56776c91139SMinda Chen struct device *dev = port->dev; 56876c91139SMinda Chen struct pci_host_bridge *bridge; 56976c91139SMinda Chen struct platform_device *pdev = to_platform_device(dev); 57076c91139SMinda Chen struct resource *cfg_res; 57176c91139SMinda Chen int ret; 57276c91139SMinda Chen 57376c91139SMinda Chen pdev = to_platform_device(dev); 57476c91139SMinda Chen 57576c91139SMinda Chen port->bridge_addr = 57676c91139SMinda Chen devm_platform_ioremap_resource_byname(pdev, "apb"); 57776c91139SMinda Chen 57876c91139SMinda Chen if (IS_ERR(port->bridge_addr)) 57976c91139SMinda Chen return dev_err_probe(dev, PTR_ERR(port->bridge_addr), 58076c91139SMinda Chen "failed to map reg memory\n"); 58176c91139SMinda Chen 58276c91139SMinda Chen cfg_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "cfg"); 58376c91139SMinda Chen if (!cfg_res) 58476c91139SMinda Chen return dev_err_probe(dev, -ENODEV, 58576c91139SMinda Chen "failed to get config memory\n"); 58676c91139SMinda Chen 58776c91139SMinda Chen port->config_base = devm_ioremap_resource(dev, cfg_res); 58876c91139SMinda Chen if (IS_ERR(port->config_base)) 58976c91139SMinda Chen return dev_err_probe(dev, PTR_ERR(port->config_base), 59076c91139SMinda Chen "failed to map config memory\n"); 59176c91139SMinda Chen 59276c91139SMinda Chen bridge = devm_pci_alloc_host_bridge(dev, 0); 59376c91139SMinda Chen if (!bridge) 59476c91139SMinda Chen return dev_err_probe(dev, -ENOMEM, 59576c91139SMinda Chen "failed to alloc bridge\n"); 59676c91139SMinda Chen 59776c91139SMinda Chen if (port->host_ops && port->host_ops->host_init) { 59876c91139SMinda Chen ret = port->host_ops->host_init(port); 59976c91139SMinda Chen if (ret) 60076c91139SMinda Chen return ret; 60176c91139SMinda Chen } 60276c91139SMinda Chen 60376c91139SMinda Chen port->bridge = bridge; 60476c91139SMinda Chen plda_pcie_setup_window(port->bridge_addr, 0, cfg_res->start, 0, 60576c91139SMinda Chen resource_size(cfg_res)); 60676c91139SMinda Chen plda_pcie_setup_iomems(bridge, port); 60776c91139SMinda Chen plda_set_default_msi(&port->msi); 60876c91139SMinda Chen ret = plda_init_interrupts(pdev, port, plda_event); 60976c91139SMinda Chen if (ret) 61076c91139SMinda Chen goto err_host; 61176c91139SMinda Chen 61276c91139SMinda Chen /* Set default bus ops */ 61376c91139SMinda Chen bridge->ops = ops; 61476c91139SMinda Chen bridge->sysdata = port; 61576c91139SMinda Chen 61676c91139SMinda Chen ret = pci_host_probe(bridge); 61776c91139SMinda Chen if (ret < 0) { 61876c91139SMinda Chen dev_err_probe(dev, ret, "failed to probe pci host\n"); 61976c91139SMinda Chen goto err_probe; 62076c91139SMinda Chen } 62176c91139SMinda Chen 62276c91139SMinda Chen return ret; 62376c91139SMinda Chen 62476c91139SMinda Chen err_probe: 62576c91139SMinda Chen plda_pcie_irq_domain_deinit(port); 62676c91139SMinda Chen err_host: 62776c91139SMinda Chen if (port->host_ops && port->host_ops->host_deinit) 62876c91139SMinda Chen port->host_ops->host_deinit(port); 62976c91139SMinda Chen 63076c91139SMinda Chen return ret; 63176c91139SMinda Chen } 63276c91139SMinda Chen EXPORT_SYMBOL_GPL(plda_pcie_host_init); 63376c91139SMinda Chen 63476c91139SMinda Chen void plda_pcie_host_deinit(struct plda_pcie_rp *port) 63576c91139SMinda Chen { 63676c91139SMinda Chen pci_stop_root_bus(port->bridge->bus); 63776c91139SMinda Chen pci_remove_root_bus(port->bridge->bus); 63876c91139SMinda Chen 63976c91139SMinda Chen plda_pcie_irq_domain_deinit(port); 64076c91139SMinda Chen 64176c91139SMinda Chen if (port->host_ops && port->host_ops->host_deinit) 64276c91139SMinda Chen port->host_ops->host_deinit(port); 64376c91139SMinda Chen } 64476c91139SMinda Chen EXPORT_SYMBOL_GPL(plda_pcie_host_deinit); 645