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 int plda_msi_set_affinity(struct irq_data *irq_data, 804602c370SMinda Chen const struct cpumask *mask, bool force) 814602c370SMinda Chen { 824602c370SMinda Chen return -EINVAL; 834602c370SMinda Chen } 844602c370SMinda Chen 854602c370SMinda Chen static struct irq_chip plda_msi_bottom_irq_chip = { 864602c370SMinda Chen .name = "PLDA MSI", 874602c370SMinda Chen .irq_ack = plda_msi_bottom_irq_ack, 884602c370SMinda Chen .irq_compose_msi_msg = plda_compose_msi_msg, 894602c370SMinda Chen .irq_set_affinity = plda_msi_set_affinity, 904602c370SMinda Chen }; 914602c370SMinda Chen 924602c370SMinda Chen static int plda_irq_msi_domain_alloc(struct irq_domain *domain, 934602c370SMinda Chen unsigned int virq, 944602c370SMinda Chen unsigned int nr_irqs, 954602c370SMinda Chen void *args) 964602c370SMinda Chen { 974602c370SMinda Chen struct plda_pcie_rp *port = domain->host_data; 984602c370SMinda Chen struct plda_msi *msi = &port->msi; 994602c370SMinda Chen unsigned long bit; 1004602c370SMinda Chen 1014602c370SMinda Chen mutex_lock(&msi->lock); 1024602c370SMinda Chen bit = find_first_zero_bit(msi->used, msi->num_vectors); 1034602c370SMinda Chen if (bit >= msi->num_vectors) { 1044602c370SMinda Chen mutex_unlock(&msi->lock); 1054602c370SMinda Chen return -ENOSPC; 1064602c370SMinda Chen } 1074602c370SMinda Chen 1084602c370SMinda Chen set_bit(bit, msi->used); 1094602c370SMinda Chen 1104602c370SMinda Chen irq_domain_set_info(domain, virq, bit, &plda_msi_bottom_irq_chip, 1114602c370SMinda Chen domain->host_data, handle_edge_irq, NULL, NULL); 1124602c370SMinda Chen 1134602c370SMinda Chen mutex_unlock(&msi->lock); 1144602c370SMinda Chen 1154602c370SMinda Chen return 0; 1164602c370SMinda Chen } 1174602c370SMinda Chen 1184602c370SMinda Chen static void plda_irq_msi_domain_free(struct irq_domain *domain, 1194602c370SMinda Chen unsigned int virq, 1204602c370SMinda Chen unsigned int nr_irqs) 1214602c370SMinda Chen { 1224602c370SMinda Chen struct irq_data *d = irq_domain_get_irq_data(domain, virq); 1234602c370SMinda Chen struct plda_pcie_rp *port = irq_data_get_irq_chip_data(d); 1244602c370SMinda Chen struct plda_msi *msi = &port->msi; 1254602c370SMinda Chen 1264602c370SMinda Chen mutex_lock(&msi->lock); 1274602c370SMinda Chen 1284602c370SMinda Chen if (test_bit(d->hwirq, msi->used)) 1294602c370SMinda Chen __clear_bit(d->hwirq, msi->used); 1304602c370SMinda Chen else 1314602c370SMinda Chen dev_err(port->dev, "trying to free unused MSI%lu\n", d->hwirq); 1324602c370SMinda Chen 1334602c370SMinda Chen mutex_unlock(&msi->lock); 1344602c370SMinda Chen } 1354602c370SMinda Chen 1364602c370SMinda Chen static const struct irq_domain_ops msi_domain_ops = { 1374602c370SMinda Chen .alloc = plda_irq_msi_domain_alloc, 1384602c370SMinda Chen .free = plda_irq_msi_domain_free, 1394602c370SMinda Chen }; 1404602c370SMinda Chen 1414602c370SMinda Chen static struct irq_chip plda_msi_irq_chip = { 1424602c370SMinda Chen .name = "PLDA PCIe MSI", 1434602c370SMinda Chen .irq_ack = irq_chip_ack_parent, 1444602c370SMinda Chen .irq_mask = pci_msi_mask_irq, 1454602c370SMinda Chen .irq_unmask = pci_msi_unmask_irq, 1464602c370SMinda Chen }; 1474602c370SMinda Chen 1484602c370SMinda Chen static struct msi_domain_info plda_msi_domain_info = { 1494602c370SMinda Chen .flags = (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS | 1504602c370SMinda Chen MSI_FLAG_PCI_MSIX), 1514602c370SMinda Chen .chip = &plda_msi_irq_chip, 1524602c370SMinda Chen }; 1534602c370SMinda Chen 1544602c370SMinda Chen static int plda_allocate_msi_domains(struct plda_pcie_rp *port) 1554602c370SMinda Chen { 1564602c370SMinda Chen struct device *dev = port->dev; 1574602c370SMinda Chen struct fwnode_handle *fwnode = of_node_to_fwnode(dev->of_node); 1584602c370SMinda Chen struct plda_msi *msi = &port->msi; 1594602c370SMinda Chen 1604602c370SMinda Chen mutex_init(&port->msi.lock); 1614602c370SMinda Chen 1624602c370SMinda Chen msi->dev_domain = irq_domain_add_linear(NULL, msi->num_vectors, 1634602c370SMinda Chen &msi_domain_ops, port); 1644602c370SMinda Chen if (!msi->dev_domain) { 1654602c370SMinda Chen dev_err(dev, "failed to create IRQ domain\n"); 1664602c370SMinda Chen return -ENOMEM; 1674602c370SMinda Chen } 1684602c370SMinda Chen 1694602c370SMinda Chen msi->msi_domain = pci_msi_create_irq_domain(fwnode, 1704602c370SMinda Chen &plda_msi_domain_info, 1714602c370SMinda Chen msi->dev_domain); 1724602c370SMinda Chen if (!msi->msi_domain) { 1734602c370SMinda Chen dev_err(dev, "failed to create MSI domain\n"); 1744602c370SMinda Chen irq_domain_remove(msi->dev_domain); 1754602c370SMinda Chen return -ENOMEM; 1764602c370SMinda Chen } 1774602c370SMinda Chen 1784602c370SMinda Chen return 0; 1794602c370SMinda Chen } 1804602c370SMinda Chen 1814602c370SMinda Chen static void plda_handle_intx(struct irq_desc *desc) 1824602c370SMinda Chen { 1834602c370SMinda Chen struct plda_pcie_rp *port = irq_desc_get_handler_data(desc); 1844602c370SMinda Chen struct irq_chip *chip = irq_desc_get_chip(desc); 1854602c370SMinda Chen struct device *dev = port->dev; 1864602c370SMinda Chen void __iomem *bridge_base_addr = port->bridge_addr; 1874602c370SMinda Chen unsigned long status; 1884602c370SMinda Chen u32 bit; 1894602c370SMinda Chen int ret; 1904602c370SMinda Chen 1914602c370SMinda Chen chained_irq_enter(chip, desc); 1924602c370SMinda Chen 1934602c370SMinda Chen status = readl_relaxed(bridge_base_addr + ISTATUS_LOCAL); 1944602c370SMinda Chen if (status & PM_MSI_INT_INTX_MASK) { 1954602c370SMinda Chen status &= PM_MSI_INT_INTX_MASK; 1964602c370SMinda Chen status >>= PM_MSI_INT_INTX_SHIFT; 1974602c370SMinda Chen for_each_set_bit(bit, &status, PCI_NUM_INTX) { 1984602c370SMinda Chen ret = generic_handle_domain_irq(port->intx_domain, bit); 1994602c370SMinda Chen if (ret) 2004602c370SMinda Chen dev_err_ratelimited(dev, "bad INTx IRQ %d\n", 2014602c370SMinda Chen bit); 2024602c370SMinda Chen } 2034602c370SMinda Chen } 2044602c370SMinda Chen 2054602c370SMinda Chen chained_irq_exit(chip, desc); 2064602c370SMinda Chen } 2074602c370SMinda Chen 2084602c370SMinda Chen static void plda_ack_intx_irq(struct irq_data *data) 2094602c370SMinda Chen { 2104602c370SMinda Chen struct plda_pcie_rp *port = irq_data_get_irq_chip_data(data); 2114602c370SMinda Chen void __iomem *bridge_base_addr = port->bridge_addr; 2124602c370SMinda Chen u32 mask = BIT(data->hwirq + PM_MSI_INT_INTX_SHIFT); 2134602c370SMinda Chen 2144602c370SMinda Chen writel_relaxed(mask, bridge_base_addr + ISTATUS_LOCAL); 2154602c370SMinda Chen } 2164602c370SMinda Chen 2174602c370SMinda Chen static void plda_mask_intx_irq(struct irq_data *data) 2184602c370SMinda Chen { 2194602c370SMinda Chen struct plda_pcie_rp *port = irq_data_get_irq_chip_data(data); 2204602c370SMinda Chen void __iomem *bridge_base_addr = port->bridge_addr; 2214602c370SMinda Chen unsigned long flags; 2224602c370SMinda Chen u32 mask = BIT(data->hwirq + PM_MSI_INT_INTX_SHIFT); 2234602c370SMinda Chen u32 val; 2244602c370SMinda Chen 2254602c370SMinda Chen raw_spin_lock_irqsave(&port->lock, flags); 2264602c370SMinda Chen val = readl_relaxed(bridge_base_addr + IMASK_LOCAL); 2274602c370SMinda Chen val &= ~mask; 2284602c370SMinda Chen writel_relaxed(val, bridge_base_addr + IMASK_LOCAL); 2294602c370SMinda Chen raw_spin_unlock_irqrestore(&port->lock, flags); 2304602c370SMinda Chen } 2314602c370SMinda Chen 2324602c370SMinda Chen static void plda_unmask_intx_irq(struct irq_data *data) 2334602c370SMinda Chen { 2344602c370SMinda Chen struct plda_pcie_rp *port = irq_data_get_irq_chip_data(data); 2354602c370SMinda Chen void __iomem *bridge_base_addr = port->bridge_addr; 2364602c370SMinda Chen unsigned long flags; 2374602c370SMinda Chen u32 mask = BIT(data->hwirq + PM_MSI_INT_INTX_SHIFT); 2384602c370SMinda Chen u32 val; 2394602c370SMinda Chen 2404602c370SMinda Chen raw_spin_lock_irqsave(&port->lock, flags); 2414602c370SMinda Chen val = readl_relaxed(bridge_base_addr + IMASK_LOCAL); 2424602c370SMinda Chen val |= mask; 2434602c370SMinda Chen writel_relaxed(val, bridge_base_addr + IMASK_LOCAL); 2444602c370SMinda Chen raw_spin_unlock_irqrestore(&port->lock, flags); 2454602c370SMinda Chen } 2464602c370SMinda Chen 2474602c370SMinda Chen static struct irq_chip plda_intx_irq_chip = { 2484602c370SMinda Chen .name = "PLDA PCIe INTx", 2494602c370SMinda Chen .irq_ack = plda_ack_intx_irq, 2504602c370SMinda Chen .irq_mask = plda_mask_intx_irq, 2514602c370SMinda Chen .irq_unmask = plda_unmask_intx_irq, 2524602c370SMinda Chen }; 2534602c370SMinda Chen 2544602c370SMinda Chen static int plda_pcie_intx_map(struct irq_domain *domain, unsigned int irq, 2554602c370SMinda Chen irq_hw_number_t hwirq) 2564602c370SMinda Chen { 2574602c370SMinda Chen irq_set_chip_and_handler(irq, &plda_intx_irq_chip, handle_level_irq); 2584602c370SMinda Chen irq_set_chip_data(irq, domain->host_data); 2594602c370SMinda Chen 2604602c370SMinda Chen return 0; 2614602c370SMinda Chen } 2624602c370SMinda Chen 2634602c370SMinda Chen static const struct irq_domain_ops intx_domain_ops = { 2644602c370SMinda Chen .map = plda_pcie_intx_map, 2654602c370SMinda Chen }; 2664602c370SMinda Chen 2674602c370SMinda Chen static u32 plda_get_events(struct plda_pcie_rp *port) 2684602c370SMinda Chen { 2694602c370SMinda Chen u32 events, val, origin; 2704602c370SMinda Chen 2714602c370SMinda Chen origin = readl_relaxed(port->bridge_addr + ISTATUS_LOCAL); 2724602c370SMinda Chen 2734602c370SMinda Chen /* MSI event and sys events */ 2744602c370SMinda Chen val = (origin & SYS_AND_MSI_MASK) >> PM_MSI_INT_MSI_SHIFT; 2754602c370SMinda Chen events = val << (PM_MSI_INT_MSI_SHIFT - PCI_NUM_INTX + 1); 2764602c370SMinda Chen 2774602c370SMinda Chen /* INTx events */ 2784602c370SMinda Chen if (origin & PM_MSI_INT_INTX_MASK) 2794602c370SMinda Chen events |= BIT(PM_MSI_INT_INTX_SHIFT); 2804602c370SMinda Chen 2814602c370SMinda Chen /* remains are same with register */ 2824602c370SMinda Chen events |= origin & GENMASK(P_ATR_EVT_DOORBELL_SHIFT, 0); 2834602c370SMinda Chen 2844602c370SMinda Chen return events; 2854602c370SMinda Chen } 2864602c370SMinda Chen 2874602c370SMinda Chen static irqreturn_t plda_event_handler(int irq, void *dev_id) 2884602c370SMinda Chen { 2894602c370SMinda Chen return IRQ_HANDLED; 2904602c370SMinda Chen } 2914602c370SMinda Chen 2924602c370SMinda Chen static void plda_handle_event(struct irq_desc *desc) 2934602c370SMinda Chen { 2944602c370SMinda Chen struct plda_pcie_rp *port = irq_desc_get_handler_data(desc); 2954602c370SMinda Chen unsigned long events; 2964602c370SMinda Chen u32 bit; 2974602c370SMinda Chen struct irq_chip *chip = irq_desc_get_chip(desc); 2984602c370SMinda Chen 2994602c370SMinda Chen chained_irq_enter(chip, desc); 3004602c370SMinda Chen 3014602c370SMinda Chen events = port->event_ops->get_events(port); 3024602c370SMinda Chen 303a576fff3SMinda Chen events &= port->events_bitmap; 3044602c370SMinda Chen for_each_set_bit(bit, &events, port->num_events) 3054602c370SMinda Chen generic_handle_domain_irq(port->event_domain, bit); 3064602c370SMinda Chen 3074602c370SMinda Chen chained_irq_exit(chip, desc); 3084602c370SMinda Chen } 3094602c370SMinda Chen 3104602c370SMinda Chen static u32 plda_hwirq_to_mask(int hwirq) 3114602c370SMinda Chen { 3124602c370SMinda Chen u32 mask; 3134602c370SMinda Chen 3144602c370SMinda Chen /* hwirq 23 - 0 are the same with register */ 3154602c370SMinda Chen if (hwirq < EVENT_PM_MSI_INT_INTX) 3164602c370SMinda Chen mask = BIT(hwirq); 3174602c370SMinda Chen else if (hwirq == EVENT_PM_MSI_INT_INTX) 3184602c370SMinda Chen mask = PM_MSI_INT_INTX_MASK; 3194602c370SMinda Chen else 3204602c370SMinda Chen mask = BIT(hwirq + PCI_NUM_INTX - 1); 3214602c370SMinda Chen 3224602c370SMinda Chen return mask; 3234602c370SMinda Chen } 3244602c370SMinda Chen 3254602c370SMinda Chen static void plda_ack_event_irq(struct irq_data *data) 3264602c370SMinda Chen { 3274602c370SMinda Chen struct plda_pcie_rp *port = irq_data_get_irq_chip_data(data); 3284602c370SMinda Chen 3294602c370SMinda Chen writel_relaxed(plda_hwirq_to_mask(data->hwirq), 3304602c370SMinda Chen port->bridge_addr + ISTATUS_LOCAL); 3314602c370SMinda Chen } 3324602c370SMinda Chen 3334602c370SMinda Chen static void plda_mask_event_irq(struct irq_data *data) 3344602c370SMinda Chen { 3354602c370SMinda Chen struct plda_pcie_rp *port = irq_data_get_irq_chip_data(data); 3364602c370SMinda Chen u32 mask, val; 3374602c370SMinda Chen 3384602c370SMinda Chen mask = plda_hwirq_to_mask(data->hwirq); 3394602c370SMinda Chen 3404602c370SMinda Chen raw_spin_lock(&port->lock); 3414602c370SMinda Chen val = readl_relaxed(port->bridge_addr + IMASK_LOCAL); 3424602c370SMinda Chen val &= ~mask; 3434602c370SMinda Chen writel_relaxed(val, port->bridge_addr + IMASK_LOCAL); 3444602c370SMinda Chen raw_spin_unlock(&port->lock); 3454602c370SMinda Chen } 3464602c370SMinda Chen 3474602c370SMinda Chen static void plda_unmask_event_irq(struct irq_data *data) 3484602c370SMinda Chen { 3494602c370SMinda Chen struct plda_pcie_rp *port = irq_data_get_irq_chip_data(data); 3504602c370SMinda Chen u32 mask, val; 3514602c370SMinda Chen 3524602c370SMinda Chen mask = plda_hwirq_to_mask(data->hwirq); 3534602c370SMinda Chen 3544602c370SMinda Chen raw_spin_lock(&port->lock); 3554602c370SMinda Chen val = readl_relaxed(port->bridge_addr + IMASK_LOCAL); 3564602c370SMinda Chen val |= mask; 3574602c370SMinda Chen writel_relaxed(val, port->bridge_addr + IMASK_LOCAL); 3584602c370SMinda Chen raw_spin_unlock(&port->lock); 3594602c370SMinda Chen } 3604602c370SMinda Chen 3614602c370SMinda Chen static struct irq_chip plda_event_irq_chip = { 3624602c370SMinda Chen .name = "PLDA PCIe EVENT", 3634602c370SMinda Chen .irq_ack = plda_ack_event_irq, 3644602c370SMinda Chen .irq_mask = plda_mask_event_irq, 3654602c370SMinda Chen .irq_unmask = plda_unmask_event_irq, 3664602c370SMinda Chen }; 3674602c370SMinda Chen 3684602c370SMinda Chen static const struct plda_event_ops plda_event_ops = { 3694602c370SMinda Chen .get_events = plda_get_events, 3704602c370SMinda Chen }; 3714602c370SMinda Chen 3724602c370SMinda Chen static int plda_pcie_event_map(struct irq_domain *domain, unsigned int irq, 3734602c370SMinda Chen irq_hw_number_t hwirq) 3744602c370SMinda Chen { 3754602c370SMinda Chen struct plda_pcie_rp *port = (void *)domain->host_data; 3764602c370SMinda Chen 3774602c370SMinda Chen irq_set_chip_and_handler(irq, port->event_irq_chip, handle_level_irq); 3784602c370SMinda Chen irq_set_chip_data(irq, domain->host_data); 3794602c370SMinda Chen 3804602c370SMinda Chen return 0; 3814602c370SMinda Chen } 3824602c370SMinda Chen 3834602c370SMinda Chen static const struct irq_domain_ops plda_event_domain_ops = { 3844602c370SMinda Chen .map = plda_pcie_event_map, 3854602c370SMinda Chen }; 3864602c370SMinda Chen 3874602c370SMinda Chen static int plda_pcie_init_irq_domains(struct plda_pcie_rp *port) 3884602c370SMinda Chen { 3894602c370SMinda Chen struct device *dev = port->dev; 3904602c370SMinda Chen struct device_node *node = dev->of_node; 3914602c370SMinda Chen struct device_node *pcie_intc_node; 3924602c370SMinda Chen 3934602c370SMinda Chen /* Setup INTx */ 3944602c370SMinda Chen pcie_intc_node = of_get_next_child(node, NULL); 3954602c370SMinda Chen if (!pcie_intc_node) { 3964602c370SMinda Chen dev_err(dev, "failed to find PCIe Intc node\n"); 3974602c370SMinda Chen return -EINVAL; 3984602c370SMinda Chen } 3994602c370SMinda Chen 4004602c370SMinda Chen port->event_domain = irq_domain_add_linear(pcie_intc_node, 4014602c370SMinda Chen port->num_events, 4024602c370SMinda Chen &plda_event_domain_ops, 4034602c370SMinda Chen port); 4044602c370SMinda Chen if (!port->event_domain) { 4054602c370SMinda Chen dev_err(dev, "failed to get event domain\n"); 4064602c370SMinda Chen of_node_put(pcie_intc_node); 4074602c370SMinda Chen return -ENOMEM; 4084602c370SMinda Chen } 4094602c370SMinda Chen 4104602c370SMinda Chen irq_domain_update_bus_token(port->event_domain, DOMAIN_BUS_NEXUS); 4114602c370SMinda Chen 4124602c370SMinda Chen port->intx_domain = irq_domain_add_linear(pcie_intc_node, PCI_NUM_INTX, 4134602c370SMinda Chen &intx_domain_ops, port); 4144602c370SMinda Chen if (!port->intx_domain) { 4154602c370SMinda Chen dev_err(dev, "failed to get an INTx IRQ domain\n"); 4164602c370SMinda Chen of_node_put(pcie_intc_node); 4174602c370SMinda Chen return -ENOMEM; 4184602c370SMinda Chen } 4194602c370SMinda Chen 4204602c370SMinda Chen irq_domain_update_bus_token(port->intx_domain, DOMAIN_BUS_WIRED); 4214602c370SMinda Chen 4224602c370SMinda Chen of_node_put(pcie_intc_node); 4234602c370SMinda Chen raw_spin_lock_init(&port->lock); 4244602c370SMinda Chen 4254602c370SMinda Chen return plda_allocate_msi_domains(port); 4264602c370SMinda Chen } 4274602c370SMinda Chen 4284602c370SMinda Chen int plda_init_interrupts(struct platform_device *pdev, 4294602c370SMinda Chen struct plda_pcie_rp *port, 4304602c370SMinda Chen const struct plda_event *event) 4314602c370SMinda Chen { 4324602c370SMinda Chen struct device *dev = &pdev->dev; 43376c91139SMinda Chen int event_irq, ret; 434a576fff3SMinda Chen u32 i; 4354602c370SMinda Chen 4364602c370SMinda Chen if (!port->event_ops) 4374602c370SMinda Chen port->event_ops = &plda_event_ops; 4384602c370SMinda Chen 4394602c370SMinda Chen if (!port->event_irq_chip) 4404602c370SMinda Chen port->event_irq_chip = &plda_event_irq_chip; 4414602c370SMinda Chen 4424602c370SMinda Chen ret = plda_pcie_init_irq_domains(port); 4434602c370SMinda Chen if (ret) { 4444602c370SMinda Chen dev_err(dev, "failed creating IRQ domains\n"); 4454602c370SMinda Chen return ret; 4464602c370SMinda Chen } 4474602c370SMinda Chen 44876c91139SMinda Chen port->irq = platform_get_irq(pdev, 0); 44976c91139SMinda Chen if (port->irq < 0) 4504602c370SMinda Chen return -ENODEV; 4514602c370SMinda Chen 452a576fff3SMinda Chen for_each_set_bit(i, &port->events_bitmap, port->num_events) { 4534602c370SMinda Chen event_irq = irq_create_mapping(port->event_domain, i); 4544602c370SMinda Chen if (!event_irq) { 4554602c370SMinda Chen dev_err(dev, "failed to map hwirq %d\n", i); 4564602c370SMinda Chen return -ENXIO; 4574602c370SMinda Chen } 4584602c370SMinda Chen 4594602c370SMinda Chen if (event->request_event_irq) 4604602c370SMinda Chen ret = event->request_event_irq(port, event_irq, i); 4614602c370SMinda Chen else 4624602c370SMinda Chen ret = devm_request_irq(dev, event_irq, 4634602c370SMinda Chen plda_event_handler, 4644602c370SMinda Chen 0, NULL, port); 4654602c370SMinda Chen 4664602c370SMinda Chen if (ret) { 4674602c370SMinda Chen dev_err(dev, "failed to request IRQ %d\n", event_irq); 4684602c370SMinda Chen return ret; 4694602c370SMinda Chen } 4704602c370SMinda Chen } 4714602c370SMinda Chen 47276c91139SMinda Chen port->intx_irq = irq_create_mapping(port->event_domain, 4734602c370SMinda Chen event->intx_event); 47476c91139SMinda Chen if (!port->intx_irq) { 4754602c370SMinda Chen dev_err(dev, "failed to map INTx interrupt\n"); 4764602c370SMinda Chen return -ENXIO; 4774602c370SMinda Chen } 4784602c370SMinda Chen 4794602c370SMinda Chen /* Plug the INTx chained handler */ 48076c91139SMinda Chen irq_set_chained_handler_and_data(port->intx_irq, plda_handle_intx, port); 4814602c370SMinda Chen 48276c91139SMinda Chen port->msi_irq = irq_create_mapping(port->event_domain, 4834602c370SMinda Chen event->msi_event); 48476c91139SMinda Chen if (!port->msi_irq) 4854602c370SMinda Chen return -ENXIO; 4864602c370SMinda Chen 4874602c370SMinda Chen /* Plug the MSI chained handler */ 48876c91139SMinda Chen irq_set_chained_handler_and_data(port->msi_irq, plda_handle_msi, port); 4894602c370SMinda Chen 4904602c370SMinda Chen /* Plug the main event chained handler */ 49176c91139SMinda Chen irq_set_chained_handler_and_data(port->irq, plda_handle_event, port); 4924602c370SMinda Chen 4934602c370SMinda Chen return 0; 4944602c370SMinda Chen } 4954602c370SMinda Chen EXPORT_SYMBOL_GPL(plda_init_interrupts); 4964602c370SMinda Chen 49739bd5f82SMinda Chen void plda_pcie_setup_window(void __iomem *bridge_base_addr, u32 index, 49839bd5f82SMinda Chen phys_addr_t axi_addr, phys_addr_t pci_addr, 49939bd5f82SMinda Chen size_t size) 50039bd5f82SMinda Chen { 50139bd5f82SMinda Chen u32 atr_sz = ilog2(size) - 1; 50239bd5f82SMinda Chen u32 val; 50339bd5f82SMinda Chen 50439bd5f82SMinda Chen if (index == 0) 50539bd5f82SMinda Chen val = PCIE_CONFIG_INTERFACE; 50639bd5f82SMinda Chen else 50739bd5f82SMinda Chen val = PCIE_TX_RX_INTERFACE; 50839bd5f82SMinda Chen 50939bd5f82SMinda Chen writel(val, bridge_base_addr + (index * ATR_ENTRY_SIZE) + 51039bd5f82SMinda Chen ATR0_AXI4_SLV0_TRSL_PARAM); 51139bd5f82SMinda Chen 51239bd5f82SMinda Chen val = lower_32_bits(axi_addr) | (atr_sz << ATR_SIZE_SHIFT) | 51339bd5f82SMinda Chen ATR_IMPL_ENABLE; 51439bd5f82SMinda Chen writel(val, bridge_base_addr + (index * ATR_ENTRY_SIZE) + 51539bd5f82SMinda Chen ATR0_AXI4_SLV0_SRCADDR_PARAM); 51639bd5f82SMinda Chen 51739bd5f82SMinda Chen val = upper_32_bits(axi_addr); 51839bd5f82SMinda Chen writel(val, bridge_base_addr + (index * ATR_ENTRY_SIZE) + 51939bd5f82SMinda Chen ATR0_AXI4_SLV0_SRC_ADDR); 52039bd5f82SMinda Chen 52139bd5f82SMinda Chen val = lower_32_bits(pci_addr); 52239bd5f82SMinda Chen writel(val, bridge_base_addr + (index * ATR_ENTRY_SIZE) + 52339bd5f82SMinda Chen ATR0_AXI4_SLV0_TRSL_ADDR_LSB); 52439bd5f82SMinda Chen 52539bd5f82SMinda Chen val = upper_32_bits(pci_addr); 52639bd5f82SMinda Chen writel(val, bridge_base_addr + (index * ATR_ENTRY_SIZE) + 52739bd5f82SMinda Chen ATR0_AXI4_SLV0_TRSL_ADDR_UDW); 52839bd5f82SMinda Chen 52939bd5f82SMinda Chen val = readl(bridge_base_addr + ATR0_PCIE_WIN0_SRCADDR_PARAM); 53039bd5f82SMinda Chen val |= (ATR0_PCIE_ATR_SIZE << ATR0_PCIE_ATR_SIZE_SHIFT); 53139bd5f82SMinda Chen writel(val, bridge_base_addr + ATR0_PCIE_WIN0_SRCADDR_PARAM); 53239bd5f82SMinda Chen writel(0, bridge_base_addr + ATR0_PCIE_WIN0_SRC_ADDR); 53339bd5f82SMinda Chen } 53439bd5f82SMinda Chen EXPORT_SYMBOL_GPL(plda_pcie_setup_window); 53539bd5f82SMinda Chen 536*d76ef053SMinda Chen int plda_pcie_setup_iomems(struct pci_host_bridge *bridge, 53739bd5f82SMinda Chen struct plda_pcie_rp *port) 53839bd5f82SMinda Chen { 53939bd5f82SMinda Chen void __iomem *bridge_base_addr = port->bridge_addr; 54039bd5f82SMinda Chen struct resource_entry *entry; 54139bd5f82SMinda Chen u64 pci_addr; 54239bd5f82SMinda Chen u32 index = 1; 54339bd5f82SMinda Chen 54439bd5f82SMinda Chen resource_list_for_each_entry(entry, &bridge->windows) { 54539bd5f82SMinda Chen if (resource_type(entry->res) == IORESOURCE_MEM) { 54639bd5f82SMinda Chen pci_addr = entry->res->start - entry->offset; 54739bd5f82SMinda Chen plda_pcie_setup_window(bridge_base_addr, index, 54839bd5f82SMinda Chen entry->res->start, pci_addr, 54939bd5f82SMinda Chen resource_size(entry->res)); 55039bd5f82SMinda Chen index++; 55139bd5f82SMinda Chen } 55239bd5f82SMinda Chen } 55339bd5f82SMinda Chen 55439bd5f82SMinda Chen return 0; 55539bd5f82SMinda Chen } 55639bd5f82SMinda Chen EXPORT_SYMBOL_GPL(plda_pcie_setup_iomems); 55776c91139SMinda Chen 55876c91139SMinda Chen static void plda_pcie_irq_domain_deinit(struct plda_pcie_rp *pcie) 55976c91139SMinda Chen { 56076c91139SMinda Chen irq_set_chained_handler_and_data(pcie->irq, NULL, NULL); 56176c91139SMinda Chen irq_set_chained_handler_and_data(pcie->msi_irq, NULL, NULL); 56276c91139SMinda Chen irq_set_chained_handler_and_data(pcie->intx_irq, NULL, NULL); 56376c91139SMinda Chen 56476c91139SMinda Chen irq_domain_remove(pcie->msi.msi_domain); 56576c91139SMinda Chen irq_domain_remove(pcie->msi.dev_domain); 56676c91139SMinda Chen 56776c91139SMinda Chen irq_domain_remove(pcie->intx_domain); 56876c91139SMinda Chen irq_domain_remove(pcie->event_domain); 56976c91139SMinda Chen } 57076c91139SMinda Chen 57176c91139SMinda Chen int plda_pcie_host_init(struct plda_pcie_rp *port, struct pci_ops *ops, 57276c91139SMinda Chen const struct plda_event *plda_event) 57376c91139SMinda Chen { 57476c91139SMinda Chen struct device *dev = port->dev; 57576c91139SMinda Chen struct pci_host_bridge *bridge; 57676c91139SMinda Chen struct platform_device *pdev = to_platform_device(dev); 57776c91139SMinda Chen struct resource *cfg_res; 57876c91139SMinda Chen int ret; 57976c91139SMinda Chen 58076c91139SMinda Chen pdev = to_platform_device(dev); 58176c91139SMinda Chen 58276c91139SMinda Chen port->bridge_addr = 58376c91139SMinda Chen devm_platform_ioremap_resource_byname(pdev, "apb"); 58476c91139SMinda Chen 58576c91139SMinda Chen if (IS_ERR(port->bridge_addr)) 58676c91139SMinda Chen return dev_err_probe(dev, PTR_ERR(port->bridge_addr), 58776c91139SMinda Chen "failed to map reg memory\n"); 58876c91139SMinda Chen 58976c91139SMinda Chen cfg_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "cfg"); 59076c91139SMinda Chen if (!cfg_res) 59176c91139SMinda Chen return dev_err_probe(dev, -ENODEV, 59276c91139SMinda Chen "failed to get config memory\n"); 59376c91139SMinda Chen 59476c91139SMinda Chen port->config_base = devm_ioremap_resource(dev, cfg_res); 59576c91139SMinda Chen if (IS_ERR(port->config_base)) 59676c91139SMinda Chen return dev_err_probe(dev, PTR_ERR(port->config_base), 59776c91139SMinda Chen "failed to map config memory\n"); 59876c91139SMinda Chen 59976c91139SMinda Chen bridge = devm_pci_alloc_host_bridge(dev, 0); 60076c91139SMinda Chen if (!bridge) 60176c91139SMinda Chen return dev_err_probe(dev, -ENOMEM, 60276c91139SMinda Chen "failed to alloc bridge\n"); 60376c91139SMinda Chen 60476c91139SMinda Chen if (port->host_ops && port->host_ops->host_init) { 60576c91139SMinda Chen ret = port->host_ops->host_init(port); 60676c91139SMinda Chen if (ret) 60776c91139SMinda Chen return ret; 60876c91139SMinda Chen } 60976c91139SMinda Chen 61076c91139SMinda Chen port->bridge = bridge; 61176c91139SMinda Chen plda_pcie_setup_window(port->bridge_addr, 0, cfg_res->start, 0, 61276c91139SMinda Chen resource_size(cfg_res)); 61376c91139SMinda Chen plda_pcie_setup_iomems(bridge, port); 61476c91139SMinda Chen plda_set_default_msi(&port->msi); 61576c91139SMinda Chen ret = plda_init_interrupts(pdev, port, plda_event); 61676c91139SMinda Chen if (ret) 61776c91139SMinda Chen goto err_host; 61876c91139SMinda Chen 61976c91139SMinda Chen /* Set default bus ops */ 62076c91139SMinda Chen bridge->ops = ops; 62176c91139SMinda Chen bridge->sysdata = port; 62276c91139SMinda Chen 62376c91139SMinda Chen ret = pci_host_probe(bridge); 62476c91139SMinda Chen if (ret < 0) { 62576c91139SMinda Chen dev_err_probe(dev, ret, "failed to probe pci host\n"); 62676c91139SMinda Chen goto err_probe; 62776c91139SMinda Chen } 62876c91139SMinda Chen 62976c91139SMinda Chen return ret; 63076c91139SMinda Chen 63176c91139SMinda Chen err_probe: 63276c91139SMinda Chen plda_pcie_irq_domain_deinit(port); 63376c91139SMinda Chen err_host: 63476c91139SMinda Chen if (port->host_ops && port->host_ops->host_deinit) 63576c91139SMinda Chen port->host_ops->host_deinit(port); 63676c91139SMinda Chen 63776c91139SMinda Chen return ret; 63876c91139SMinda Chen } 63976c91139SMinda Chen EXPORT_SYMBOL_GPL(plda_pcie_host_init); 64076c91139SMinda Chen 64176c91139SMinda Chen void plda_pcie_host_deinit(struct plda_pcie_rp *port) 64276c91139SMinda Chen { 64376c91139SMinda Chen pci_stop_root_bus(port->bridge->bus); 64476c91139SMinda Chen pci_remove_root_bus(port->bridge->bus); 64576c91139SMinda Chen 64676c91139SMinda Chen plda_pcie_irq_domain_deinit(port); 64776c91139SMinda Chen 64876c91139SMinda Chen if (port->host_ops && port->host_ops->host_deinit) 64976c91139SMinda Chen port->host_ops->host_deinit(port); 65076c91139SMinda Chen } 65176c91139SMinda Chen EXPORT_SYMBOL_GPL(plda_pcie_host_deinit); 652