18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * PCIe host controller driver for Xilinx AXI PCIe Bridge 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (c) 2012 - 2014 Xilinx, Inc. 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Based on the Tegra PCIe driver 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * Bits taken from Synopsys DesignWare Host controller driver and 108c2ecf20Sopenharmony_ci * ARM PCI Host generic driver. 118c2ecf20Sopenharmony_ci */ 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 148c2ecf20Sopenharmony_ci#include <linux/irq.h> 158c2ecf20Sopenharmony_ci#include <linux/irqdomain.h> 168c2ecf20Sopenharmony_ci#include <linux/kernel.h> 178c2ecf20Sopenharmony_ci#include <linux/init.h> 188c2ecf20Sopenharmony_ci#include <linux/msi.h> 198c2ecf20Sopenharmony_ci#include <linux/of_address.h> 208c2ecf20Sopenharmony_ci#include <linux/of_pci.h> 218c2ecf20Sopenharmony_ci#include <linux/of_platform.h> 228c2ecf20Sopenharmony_ci#include <linux/of_irq.h> 238c2ecf20Sopenharmony_ci#include <linux/pci.h> 248c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci#include "../pci.h" 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci/* Register definitions */ 298c2ecf20Sopenharmony_ci#define XILINX_PCIE_REG_BIR 0x00000130 308c2ecf20Sopenharmony_ci#define XILINX_PCIE_REG_IDR 0x00000138 318c2ecf20Sopenharmony_ci#define XILINX_PCIE_REG_IMR 0x0000013c 328c2ecf20Sopenharmony_ci#define XILINX_PCIE_REG_PSCR 0x00000144 338c2ecf20Sopenharmony_ci#define XILINX_PCIE_REG_RPSC 0x00000148 348c2ecf20Sopenharmony_ci#define XILINX_PCIE_REG_MSIBASE1 0x0000014c 358c2ecf20Sopenharmony_ci#define XILINX_PCIE_REG_MSIBASE2 0x00000150 368c2ecf20Sopenharmony_ci#define XILINX_PCIE_REG_RPEFR 0x00000154 378c2ecf20Sopenharmony_ci#define XILINX_PCIE_REG_RPIFR1 0x00000158 388c2ecf20Sopenharmony_ci#define XILINX_PCIE_REG_RPIFR2 0x0000015c 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci/* Interrupt registers definitions */ 418c2ecf20Sopenharmony_ci#define XILINX_PCIE_INTR_LINK_DOWN BIT(0) 428c2ecf20Sopenharmony_ci#define XILINX_PCIE_INTR_ECRC_ERR BIT(1) 438c2ecf20Sopenharmony_ci#define XILINX_PCIE_INTR_STR_ERR BIT(2) 448c2ecf20Sopenharmony_ci#define XILINX_PCIE_INTR_HOT_RESET BIT(3) 458c2ecf20Sopenharmony_ci#define XILINX_PCIE_INTR_CFG_TIMEOUT BIT(8) 468c2ecf20Sopenharmony_ci#define XILINX_PCIE_INTR_CORRECTABLE BIT(9) 478c2ecf20Sopenharmony_ci#define XILINX_PCIE_INTR_NONFATAL BIT(10) 488c2ecf20Sopenharmony_ci#define XILINX_PCIE_INTR_FATAL BIT(11) 498c2ecf20Sopenharmony_ci#define XILINX_PCIE_INTR_INTX BIT(16) 508c2ecf20Sopenharmony_ci#define XILINX_PCIE_INTR_MSI BIT(17) 518c2ecf20Sopenharmony_ci#define XILINX_PCIE_INTR_SLV_UNSUPP BIT(20) 528c2ecf20Sopenharmony_ci#define XILINX_PCIE_INTR_SLV_UNEXP BIT(21) 538c2ecf20Sopenharmony_ci#define XILINX_PCIE_INTR_SLV_COMPL BIT(22) 548c2ecf20Sopenharmony_ci#define XILINX_PCIE_INTR_SLV_ERRP BIT(23) 558c2ecf20Sopenharmony_ci#define XILINX_PCIE_INTR_SLV_CMPABT BIT(24) 568c2ecf20Sopenharmony_ci#define XILINX_PCIE_INTR_SLV_ILLBUR BIT(25) 578c2ecf20Sopenharmony_ci#define XILINX_PCIE_INTR_MST_DECERR BIT(26) 588c2ecf20Sopenharmony_ci#define XILINX_PCIE_INTR_MST_SLVERR BIT(27) 598c2ecf20Sopenharmony_ci#define XILINX_PCIE_INTR_MST_ERRP BIT(28) 608c2ecf20Sopenharmony_ci#define XILINX_PCIE_IMR_ALL_MASK 0x1FF30FED 618c2ecf20Sopenharmony_ci#define XILINX_PCIE_IMR_ENABLE_MASK 0x1FF30F0D 628c2ecf20Sopenharmony_ci#define XILINX_PCIE_IDR_ALL_MASK 0xFFFFFFFF 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci/* Root Port Error FIFO Read Register definitions */ 658c2ecf20Sopenharmony_ci#define XILINX_PCIE_RPEFR_ERR_VALID BIT(18) 668c2ecf20Sopenharmony_ci#define XILINX_PCIE_RPEFR_REQ_ID GENMASK(15, 0) 678c2ecf20Sopenharmony_ci#define XILINX_PCIE_RPEFR_ALL_MASK 0xFFFFFFFF 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci/* Root Port Interrupt FIFO Read Register 1 definitions */ 708c2ecf20Sopenharmony_ci#define XILINX_PCIE_RPIFR1_INTR_VALID BIT(31) 718c2ecf20Sopenharmony_ci#define XILINX_PCIE_RPIFR1_MSI_INTR BIT(30) 728c2ecf20Sopenharmony_ci#define XILINX_PCIE_RPIFR1_INTR_MASK GENMASK(28, 27) 738c2ecf20Sopenharmony_ci#define XILINX_PCIE_RPIFR1_ALL_MASK 0xFFFFFFFF 748c2ecf20Sopenharmony_ci#define XILINX_PCIE_RPIFR1_INTR_SHIFT 27 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci/* Bridge Info Register definitions */ 778c2ecf20Sopenharmony_ci#define XILINX_PCIE_BIR_ECAM_SZ_MASK GENMASK(18, 16) 788c2ecf20Sopenharmony_ci#define XILINX_PCIE_BIR_ECAM_SZ_SHIFT 16 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci/* Root Port Interrupt FIFO Read Register 2 definitions */ 818c2ecf20Sopenharmony_ci#define XILINX_PCIE_RPIFR2_MSG_DATA GENMASK(15, 0) 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci/* Root Port Status/control Register definitions */ 848c2ecf20Sopenharmony_ci#define XILINX_PCIE_REG_RPSC_BEN BIT(0) 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci/* Phy Status/Control Register definitions */ 878c2ecf20Sopenharmony_ci#define XILINX_PCIE_REG_PSCR_LNKUP BIT(11) 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci/* ECAM definitions */ 908c2ecf20Sopenharmony_ci#define ECAM_BUS_NUM_SHIFT 20 918c2ecf20Sopenharmony_ci#define ECAM_DEV_NUM_SHIFT 12 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci/* Number of MSI IRQs */ 948c2ecf20Sopenharmony_ci#define XILINX_NUM_MSI_IRQS 128 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci/** 978c2ecf20Sopenharmony_ci * struct xilinx_pcie_port - PCIe port information 988c2ecf20Sopenharmony_ci * @reg_base: IO Mapped Register Base 998c2ecf20Sopenharmony_ci * @irq: Interrupt number 1008c2ecf20Sopenharmony_ci * @msi_pages: MSI pages 1018c2ecf20Sopenharmony_ci * @dev: Device pointer 1028c2ecf20Sopenharmony_ci * @msi_domain: MSI IRQ domain pointer 1038c2ecf20Sopenharmony_ci * @leg_domain: Legacy IRQ domain pointer 1048c2ecf20Sopenharmony_ci * @resources: Bus Resources 1058c2ecf20Sopenharmony_ci */ 1068c2ecf20Sopenharmony_cistruct xilinx_pcie_port { 1078c2ecf20Sopenharmony_ci void __iomem *reg_base; 1088c2ecf20Sopenharmony_ci u32 irq; 1098c2ecf20Sopenharmony_ci unsigned long msi_pages; 1108c2ecf20Sopenharmony_ci struct device *dev; 1118c2ecf20Sopenharmony_ci struct irq_domain *msi_domain; 1128c2ecf20Sopenharmony_ci struct irq_domain *leg_domain; 1138c2ecf20Sopenharmony_ci struct list_head resources; 1148c2ecf20Sopenharmony_ci}; 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_cistatic DECLARE_BITMAP(msi_irq_in_use, XILINX_NUM_MSI_IRQS); 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_cistatic inline u32 pcie_read(struct xilinx_pcie_port *port, u32 reg) 1198c2ecf20Sopenharmony_ci{ 1208c2ecf20Sopenharmony_ci return readl(port->reg_base + reg); 1218c2ecf20Sopenharmony_ci} 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_cistatic inline void pcie_write(struct xilinx_pcie_port *port, u32 val, u32 reg) 1248c2ecf20Sopenharmony_ci{ 1258c2ecf20Sopenharmony_ci writel(val, port->reg_base + reg); 1268c2ecf20Sopenharmony_ci} 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_cistatic inline bool xilinx_pcie_link_up(struct xilinx_pcie_port *port) 1298c2ecf20Sopenharmony_ci{ 1308c2ecf20Sopenharmony_ci return (pcie_read(port, XILINX_PCIE_REG_PSCR) & 1318c2ecf20Sopenharmony_ci XILINX_PCIE_REG_PSCR_LNKUP) ? 1 : 0; 1328c2ecf20Sopenharmony_ci} 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci/** 1358c2ecf20Sopenharmony_ci * xilinx_pcie_clear_err_interrupts - Clear Error Interrupts 1368c2ecf20Sopenharmony_ci * @port: PCIe port information 1378c2ecf20Sopenharmony_ci */ 1388c2ecf20Sopenharmony_cistatic void xilinx_pcie_clear_err_interrupts(struct xilinx_pcie_port *port) 1398c2ecf20Sopenharmony_ci{ 1408c2ecf20Sopenharmony_ci struct device *dev = port->dev; 1418c2ecf20Sopenharmony_ci unsigned long val = pcie_read(port, XILINX_PCIE_REG_RPEFR); 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci if (val & XILINX_PCIE_RPEFR_ERR_VALID) { 1448c2ecf20Sopenharmony_ci dev_dbg(dev, "Requester ID %lu\n", 1458c2ecf20Sopenharmony_ci val & XILINX_PCIE_RPEFR_REQ_ID); 1468c2ecf20Sopenharmony_ci pcie_write(port, XILINX_PCIE_RPEFR_ALL_MASK, 1478c2ecf20Sopenharmony_ci XILINX_PCIE_REG_RPEFR); 1488c2ecf20Sopenharmony_ci } 1498c2ecf20Sopenharmony_ci} 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci/** 1528c2ecf20Sopenharmony_ci * xilinx_pcie_valid_device - Check if a valid device is present on bus 1538c2ecf20Sopenharmony_ci * @bus: PCI Bus structure 1548c2ecf20Sopenharmony_ci * @devfn: device/function 1558c2ecf20Sopenharmony_ci * 1568c2ecf20Sopenharmony_ci * Return: 'true' on success and 'false' if invalid device is found 1578c2ecf20Sopenharmony_ci */ 1588c2ecf20Sopenharmony_cistatic bool xilinx_pcie_valid_device(struct pci_bus *bus, unsigned int devfn) 1598c2ecf20Sopenharmony_ci{ 1608c2ecf20Sopenharmony_ci struct xilinx_pcie_port *port = bus->sysdata; 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci /* Check if link is up when trying to access downstream ports */ 1638c2ecf20Sopenharmony_ci if (!pci_is_root_bus(bus)) { 1648c2ecf20Sopenharmony_ci if (!xilinx_pcie_link_up(port)) 1658c2ecf20Sopenharmony_ci return false; 1668c2ecf20Sopenharmony_ci } else if (devfn > 0) { 1678c2ecf20Sopenharmony_ci /* Only one device down on each root port */ 1688c2ecf20Sopenharmony_ci return false; 1698c2ecf20Sopenharmony_ci } 1708c2ecf20Sopenharmony_ci return true; 1718c2ecf20Sopenharmony_ci} 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci/** 1748c2ecf20Sopenharmony_ci * xilinx_pcie_map_bus - Get configuration base 1758c2ecf20Sopenharmony_ci * @bus: PCI Bus structure 1768c2ecf20Sopenharmony_ci * @devfn: Device/function 1778c2ecf20Sopenharmony_ci * @where: Offset from base 1788c2ecf20Sopenharmony_ci * 1798c2ecf20Sopenharmony_ci * Return: Base address of the configuration space needed to be 1808c2ecf20Sopenharmony_ci * accessed. 1818c2ecf20Sopenharmony_ci */ 1828c2ecf20Sopenharmony_cistatic void __iomem *xilinx_pcie_map_bus(struct pci_bus *bus, 1838c2ecf20Sopenharmony_ci unsigned int devfn, int where) 1848c2ecf20Sopenharmony_ci{ 1858c2ecf20Sopenharmony_ci struct xilinx_pcie_port *port = bus->sysdata; 1868c2ecf20Sopenharmony_ci int relbus; 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci if (!xilinx_pcie_valid_device(bus, devfn)) 1898c2ecf20Sopenharmony_ci return NULL; 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci relbus = (bus->number << ECAM_BUS_NUM_SHIFT) | 1928c2ecf20Sopenharmony_ci (devfn << ECAM_DEV_NUM_SHIFT); 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci return port->reg_base + relbus + where; 1958c2ecf20Sopenharmony_ci} 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci/* PCIe operations */ 1988c2ecf20Sopenharmony_cistatic struct pci_ops xilinx_pcie_ops = { 1998c2ecf20Sopenharmony_ci .map_bus = xilinx_pcie_map_bus, 2008c2ecf20Sopenharmony_ci .read = pci_generic_config_read, 2018c2ecf20Sopenharmony_ci .write = pci_generic_config_write, 2028c2ecf20Sopenharmony_ci}; 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci/* MSI functions */ 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci/** 2078c2ecf20Sopenharmony_ci * xilinx_pcie_destroy_msi - Free MSI number 2088c2ecf20Sopenharmony_ci * @irq: IRQ to be freed 2098c2ecf20Sopenharmony_ci */ 2108c2ecf20Sopenharmony_cistatic void xilinx_pcie_destroy_msi(unsigned int irq) 2118c2ecf20Sopenharmony_ci{ 2128c2ecf20Sopenharmony_ci struct msi_desc *msi; 2138c2ecf20Sopenharmony_ci struct xilinx_pcie_port *port; 2148c2ecf20Sopenharmony_ci struct irq_data *d = irq_get_irq_data(irq); 2158c2ecf20Sopenharmony_ci irq_hw_number_t hwirq = irqd_to_hwirq(d); 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci if (!test_bit(hwirq, msi_irq_in_use)) { 2188c2ecf20Sopenharmony_ci msi = irq_get_msi_desc(irq); 2198c2ecf20Sopenharmony_ci port = msi_desc_to_pci_sysdata(msi); 2208c2ecf20Sopenharmony_ci dev_err(port->dev, "Trying to free unused MSI#%d\n", irq); 2218c2ecf20Sopenharmony_ci } else { 2228c2ecf20Sopenharmony_ci clear_bit(hwirq, msi_irq_in_use); 2238c2ecf20Sopenharmony_ci } 2248c2ecf20Sopenharmony_ci} 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci/** 2278c2ecf20Sopenharmony_ci * xilinx_pcie_assign_msi - Allocate MSI number 2288c2ecf20Sopenharmony_ci * 2298c2ecf20Sopenharmony_ci * Return: A valid IRQ on success and error value on failure. 2308c2ecf20Sopenharmony_ci */ 2318c2ecf20Sopenharmony_cistatic int xilinx_pcie_assign_msi(void) 2328c2ecf20Sopenharmony_ci{ 2338c2ecf20Sopenharmony_ci int pos; 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci pos = find_first_zero_bit(msi_irq_in_use, XILINX_NUM_MSI_IRQS); 2368c2ecf20Sopenharmony_ci if (pos < XILINX_NUM_MSI_IRQS) 2378c2ecf20Sopenharmony_ci set_bit(pos, msi_irq_in_use); 2388c2ecf20Sopenharmony_ci else 2398c2ecf20Sopenharmony_ci return -ENOSPC; 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci return pos; 2428c2ecf20Sopenharmony_ci} 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci/** 2458c2ecf20Sopenharmony_ci * xilinx_msi_teardown_irq - Destroy the MSI 2468c2ecf20Sopenharmony_ci * @chip: MSI Chip descriptor 2478c2ecf20Sopenharmony_ci * @irq: MSI IRQ to destroy 2488c2ecf20Sopenharmony_ci */ 2498c2ecf20Sopenharmony_cistatic void xilinx_msi_teardown_irq(struct msi_controller *chip, 2508c2ecf20Sopenharmony_ci unsigned int irq) 2518c2ecf20Sopenharmony_ci{ 2528c2ecf20Sopenharmony_ci xilinx_pcie_destroy_msi(irq); 2538c2ecf20Sopenharmony_ci irq_dispose_mapping(irq); 2548c2ecf20Sopenharmony_ci} 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci/** 2578c2ecf20Sopenharmony_ci * xilinx_pcie_msi_setup_irq - Setup MSI request 2588c2ecf20Sopenharmony_ci * @chip: MSI chip pointer 2598c2ecf20Sopenharmony_ci * @pdev: PCIe device pointer 2608c2ecf20Sopenharmony_ci * @desc: MSI descriptor pointer 2618c2ecf20Sopenharmony_ci * 2628c2ecf20Sopenharmony_ci * Return: '0' on success and error value on failure 2638c2ecf20Sopenharmony_ci */ 2648c2ecf20Sopenharmony_cistatic int xilinx_pcie_msi_setup_irq(struct msi_controller *chip, 2658c2ecf20Sopenharmony_ci struct pci_dev *pdev, 2668c2ecf20Sopenharmony_ci struct msi_desc *desc) 2678c2ecf20Sopenharmony_ci{ 2688c2ecf20Sopenharmony_ci struct xilinx_pcie_port *port = pdev->bus->sysdata; 2698c2ecf20Sopenharmony_ci unsigned int irq; 2708c2ecf20Sopenharmony_ci int hwirq; 2718c2ecf20Sopenharmony_ci struct msi_msg msg; 2728c2ecf20Sopenharmony_ci phys_addr_t msg_addr; 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci hwirq = xilinx_pcie_assign_msi(); 2758c2ecf20Sopenharmony_ci if (hwirq < 0) 2768c2ecf20Sopenharmony_ci return hwirq; 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci irq = irq_create_mapping(port->msi_domain, hwirq); 2798c2ecf20Sopenharmony_ci if (!irq) 2808c2ecf20Sopenharmony_ci return -EINVAL; 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci irq_set_msi_desc(irq, desc); 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci msg_addr = virt_to_phys((void *)port->msi_pages); 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci msg.address_hi = 0; 2878c2ecf20Sopenharmony_ci msg.address_lo = msg_addr; 2888c2ecf20Sopenharmony_ci msg.data = irq; 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci pci_write_msi_msg(irq, &msg); 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci return 0; 2938c2ecf20Sopenharmony_ci} 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci/* MSI Chip Descriptor */ 2968c2ecf20Sopenharmony_cistatic struct msi_controller xilinx_pcie_msi_chip = { 2978c2ecf20Sopenharmony_ci .setup_irq = xilinx_pcie_msi_setup_irq, 2988c2ecf20Sopenharmony_ci .teardown_irq = xilinx_msi_teardown_irq, 2998c2ecf20Sopenharmony_ci}; 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci/* HW Interrupt Chip Descriptor */ 3028c2ecf20Sopenharmony_cistatic struct irq_chip xilinx_msi_irq_chip = { 3038c2ecf20Sopenharmony_ci .name = "Xilinx PCIe MSI", 3048c2ecf20Sopenharmony_ci .irq_enable = pci_msi_unmask_irq, 3058c2ecf20Sopenharmony_ci .irq_disable = pci_msi_mask_irq, 3068c2ecf20Sopenharmony_ci .irq_mask = pci_msi_mask_irq, 3078c2ecf20Sopenharmony_ci .irq_unmask = pci_msi_unmask_irq, 3088c2ecf20Sopenharmony_ci}; 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci/** 3118c2ecf20Sopenharmony_ci * xilinx_pcie_msi_map - Set the handler for the MSI and mark IRQ as valid 3128c2ecf20Sopenharmony_ci * @domain: IRQ domain 3138c2ecf20Sopenharmony_ci * @irq: Virtual IRQ number 3148c2ecf20Sopenharmony_ci * @hwirq: HW interrupt number 3158c2ecf20Sopenharmony_ci * 3168c2ecf20Sopenharmony_ci * Return: Always returns 0. 3178c2ecf20Sopenharmony_ci */ 3188c2ecf20Sopenharmony_cistatic int xilinx_pcie_msi_map(struct irq_domain *domain, unsigned int irq, 3198c2ecf20Sopenharmony_ci irq_hw_number_t hwirq) 3208c2ecf20Sopenharmony_ci{ 3218c2ecf20Sopenharmony_ci irq_set_chip_and_handler(irq, &xilinx_msi_irq_chip, handle_simple_irq); 3228c2ecf20Sopenharmony_ci irq_set_chip_data(irq, domain->host_data); 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci return 0; 3258c2ecf20Sopenharmony_ci} 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci/* IRQ Domain operations */ 3288c2ecf20Sopenharmony_cistatic const struct irq_domain_ops msi_domain_ops = { 3298c2ecf20Sopenharmony_ci .map = xilinx_pcie_msi_map, 3308c2ecf20Sopenharmony_ci}; 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci/** 3338c2ecf20Sopenharmony_ci * xilinx_pcie_enable_msi - Enable MSI support 3348c2ecf20Sopenharmony_ci * @port: PCIe port information 3358c2ecf20Sopenharmony_ci */ 3368c2ecf20Sopenharmony_cistatic int xilinx_pcie_enable_msi(struct xilinx_pcie_port *port) 3378c2ecf20Sopenharmony_ci{ 3388c2ecf20Sopenharmony_ci phys_addr_t msg_addr; 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci port->msi_pages = __get_free_pages(GFP_KERNEL, 0); 3418c2ecf20Sopenharmony_ci if (!port->msi_pages) 3428c2ecf20Sopenharmony_ci return -ENOMEM; 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci msg_addr = virt_to_phys((void *)port->msi_pages); 3458c2ecf20Sopenharmony_ci pcie_write(port, 0x0, XILINX_PCIE_REG_MSIBASE1); 3468c2ecf20Sopenharmony_ci pcie_write(port, msg_addr, XILINX_PCIE_REG_MSIBASE2); 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci return 0; 3498c2ecf20Sopenharmony_ci} 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci/* INTx Functions */ 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci/** 3548c2ecf20Sopenharmony_ci * xilinx_pcie_intx_map - Set the handler for the INTx and mark IRQ as valid 3558c2ecf20Sopenharmony_ci * @domain: IRQ domain 3568c2ecf20Sopenharmony_ci * @irq: Virtual IRQ number 3578c2ecf20Sopenharmony_ci * @hwirq: HW interrupt number 3588c2ecf20Sopenharmony_ci * 3598c2ecf20Sopenharmony_ci * Return: Always returns 0. 3608c2ecf20Sopenharmony_ci */ 3618c2ecf20Sopenharmony_cistatic int xilinx_pcie_intx_map(struct irq_domain *domain, unsigned int irq, 3628c2ecf20Sopenharmony_ci irq_hw_number_t hwirq) 3638c2ecf20Sopenharmony_ci{ 3648c2ecf20Sopenharmony_ci irq_set_chip_and_handler(irq, &dummy_irq_chip, handle_simple_irq); 3658c2ecf20Sopenharmony_ci irq_set_chip_data(irq, domain->host_data); 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci return 0; 3688c2ecf20Sopenharmony_ci} 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci/* INTx IRQ Domain operations */ 3718c2ecf20Sopenharmony_cistatic const struct irq_domain_ops intx_domain_ops = { 3728c2ecf20Sopenharmony_ci .map = xilinx_pcie_intx_map, 3738c2ecf20Sopenharmony_ci .xlate = pci_irqd_intx_xlate, 3748c2ecf20Sopenharmony_ci}; 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci/* PCIe HW Functions */ 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci/** 3798c2ecf20Sopenharmony_ci * xilinx_pcie_intr_handler - Interrupt Service Handler 3808c2ecf20Sopenharmony_ci * @irq: IRQ number 3818c2ecf20Sopenharmony_ci * @data: PCIe port information 3828c2ecf20Sopenharmony_ci * 3838c2ecf20Sopenharmony_ci * Return: IRQ_HANDLED on success and IRQ_NONE on failure 3848c2ecf20Sopenharmony_ci */ 3858c2ecf20Sopenharmony_cistatic irqreturn_t xilinx_pcie_intr_handler(int irq, void *data) 3868c2ecf20Sopenharmony_ci{ 3878c2ecf20Sopenharmony_ci struct xilinx_pcie_port *port = (struct xilinx_pcie_port *)data; 3888c2ecf20Sopenharmony_ci struct device *dev = port->dev; 3898c2ecf20Sopenharmony_ci u32 val, mask, status; 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci /* Read interrupt decode and mask registers */ 3928c2ecf20Sopenharmony_ci val = pcie_read(port, XILINX_PCIE_REG_IDR); 3938c2ecf20Sopenharmony_ci mask = pcie_read(port, XILINX_PCIE_REG_IMR); 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci status = val & mask; 3968c2ecf20Sopenharmony_ci if (!status) 3978c2ecf20Sopenharmony_ci return IRQ_NONE; 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci if (status & XILINX_PCIE_INTR_LINK_DOWN) 4008c2ecf20Sopenharmony_ci dev_warn(dev, "Link Down\n"); 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci if (status & XILINX_PCIE_INTR_ECRC_ERR) 4038c2ecf20Sopenharmony_ci dev_warn(dev, "ECRC failed\n"); 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci if (status & XILINX_PCIE_INTR_STR_ERR) 4068c2ecf20Sopenharmony_ci dev_warn(dev, "Streaming error\n"); 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ci if (status & XILINX_PCIE_INTR_HOT_RESET) 4098c2ecf20Sopenharmony_ci dev_info(dev, "Hot reset\n"); 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci if (status & XILINX_PCIE_INTR_CFG_TIMEOUT) 4128c2ecf20Sopenharmony_ci dev_warn(dev, "ECAM access timeout\n"); 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci if (status & XILINX_PCIE_INTR_CORRECTABLE) { 4158c2ecf20Sopenharmony_ci dev_warn(dev, "Correctable error message\n"); 4168c2ecf20Sopenharmony_ci xilinx_pcie_clear_err_interrupts(port); 4178c2ecf20Sopenharmony_ci } 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci if (status & XILINX_PCIE_INTR_NONFATAL) { 4208c2ecf20Sopenharmony_ci dev_warn(dev, "Non fatal error message\n"); 4218c2ecf20Sopenharmony_ci xilinx_pcie_clear_err_interrupts(port); 4228c2ecf20Sopenharmony_ci } 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ci if (status & XILINX_PCIE_INTR_FATAL) { 4258c2ecf20Sopenharmony_ci dev_warn(dev, "Fatal error message\n"); 4268c2ecf20Sopenharmony_ci xilinx_pcie_clear_err_interrupts(port); 4278c2ecf20Sopenharmony_ci } 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci if (status & (XILINX_PCIE_INTR_INTX | XILINX_PCIE_INTR_MSI)) { 4308c2ecf20Sopenharmony_ci val = pcie_read(port, XILINX_PCIE_REG_RPIFR1); 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ci /* Check whether interrupt valid */ 4338c2ecf20Sopenharmony_ci if (!(val & XILINX_PCIE_RPIFR1_INTR_VALID)) { 4348c2ecf20Sopenharmony_ci dev_warn(dev, "RP Intr FIFO1 read error\n"); 4358c2ecf20Sopenharmony_ci goto error; 4368c2ecf20Sopenharmony_ci } 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_ci /* Decode the IRQ number */ 4398c2ecf20Sopenharmony_ci if (val & XILINX_PCIE_RPIFR1_MSI_INTR) { 4408c2ecf20Sopenharmony_ci val = pcie_read(port, XILINX_PCIE_REG_RPIFR2) & 4418c2ecf20Sopenharmony_ci XILINX_PCIE_RPIFR2_MSG_DATA; 4428c2ecf20Sopenharmony_ci } else { 4438c2ecf20Sopenharmony_ci val = (val & XILINX_PCIE_RPIFR1_INTR_MASK) >> 4448c2ecf20Sopenharmony_ci XILINX_PCIE_RPIFR1_INTR_SHIFT; 4458c2ecf20Sopenharmony_ci val = irq_find_mapping(port->leg_domain, val); 4468c2ecf20Sopenharmony_ci } 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ci /* Clear interrupt FIFO register 1 */ 4498c2ecf20Sopenharmony_ci pcie_write(port, XILINX_PCIE_RPIFR1_ALL_MASK, 4508c2ecf20Sopenharmony_ci XILINX_PCIE_REG_RPIFR1); 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_ci /* Handle the interrupt */ 4538c2ecf20Sopenharmony_ci if (IS_ENABLED(CONFIG_PCI_MSI) || 4548c2ecf20Sopenharmony_ci !(val & XILINX_PCIE_RPIFR1_MSI_INTR)) 4558c2ecf20Sopenharmony_ci generic_handle_irq(val); 4568c2ecf20Sopenharmony_ci } 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_ci if (status & XILINX_PCIE_INTR_SLV_UNSUPP) 4598c2ecf20Sopenharmony_ci dev_warn(dev, "Slave unsupported request\n"); 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci if (status & XILINX_PCIE_INTR_SLV_UNEXP) 4628c2ecf20Sopenharmony_ci dev_warn(dev, "Slave unexpected completion\n"); 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci if (status & XILINX_PCIE_INTR_SLV_COMPL) 4658c2ecf20Sopenharmony_ci dev_warn(dev, "Slave completion timeout\n"); 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_ci if (status & XILINX_PCIE_INTR_SLV_ERRP) 4688c2ecf20Sopenharmony_ci dev_warn(dev, "Slave Error Poison\n"); 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_ci if (status & XILINX_PCIE_INTR_SLV_CMPABT) 4718c2ecf20Sopenharmony_ci dev_warn(dev, "Slave Completer Abort\n"); 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_ci if (status & XILINX_PCIE_INTR_SLV_ILLBUR) 4748c2ecf20Sopenharmony_ci dev_warn(dev, "Slave Illegal Burst\n"); 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci if (status & XILINX_PCIE_INTR_MST_DECERR) 4778c2ecf20Sopenharmony_ci dev_warn(dev, "Master decode error\n"); 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_ci if (status & XILINX_PCIE_INTR_MST_SLVERR) 4808c2ecf20Sopenharmony_ci dev_warn(dev, "Master slave error\n"); 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_ci if (status & XILINX_PCIE_INTR_MST_ERRP) 4838c2ecf20Sopenharmony_ci dev_warn(dev, "Master error poison\n"); 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_cierror: 4868c2ecf20Sopenharmony_ci /* Clear the Interrupt Decode register */ 4878c2ecf20Sopenharmony_ci pcie_write(port, status, XILINX_PCIE_REG_IDR); 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_ci return IRQ_HANDLED; 4908c2ecf20Sopenharmony_ci} 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_ci/** 4938c2ecf20Sopenharmony_ci * xilinx_pcie_init_irq_domain - Initialize IRQ domain 4948c2ecf20Sopenharmony_ci * @port: PCIe port information 4958c2ecf20Sopenharmony_ci * 4968c2ecf20Sopenharmony_ci * Return: '0' on success and error value on failure 4978c2ecf20Sopenharmony_ci */ 4988c2ecf20Sopenharmony_cistatic int xilinx_pcie_init_irq_domain(struct xilinx_pcie_port *port) 4998c2ecf20Sopenharmony_ci{ 5008c2ecf20Sopenharmony_ci struct device *dev = port->dev; 5018c2ecf20Sopenharmony_ci struct device_node *node = dev->of_node; 5028c2ecf20Sopenharmony_ci struct device_node *pcie_intc_node; 5038c2ecf20Sopenharmony_ci int ret; 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_ci /* Setup INTx */ 5068c2ecf20Sopenharmony_ci pcie_intc_node = of_get_next_child(node, NULL); 5078c2ecf20Sopenharmony_ci if (!pcie_intc_node) { 5088c2ecf20Sopenharmony_ci dev_err(dev, "No PCIe Intc node found\n"); 5098c2ecf20Sopenharmony_ci return -ENODEV; 5108c2ecf20Sopenharmony_ci } 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_ci port->leg_domain = irq_domain_add_linear(pcie_intc_node, PCI_NUM_INTX, 5138c2ecf20Sopenharmony_ci &intx_domain_ops, 5148c2ecf20Sopenharmony_ci port); 5158c2ecf20Sopenharmony_ci of_node_put(pcie_intc_node); 5168c2ecf20Sopenharmony_ci if (!port->leg_domain) { 5178c2ecf20Sopenharmony_ci dev_err(dev, "Failed to get a INTx IRQ domain\n"); 5188c2ecf20Sopenharmony_ci return -ENODEV; 5198c2ecf20Sopenharmony_ci } 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ci /* Setup MSI */ 5228c2ecf20Sopenharmony_ci if (IS_ENABLED(CONFIG_PCI_MSI)) { 5238c2ecf20Sopenharmony_ci port->msi_domain = irq_domain_add_linear(node, 5248c2ecf20Sopenharmony_ci XILINX_NUM_MSI_IRQS, 5258c2ecf20Sopenharmony_ci &msi_domain_ops, 5268c2ecf20Sopenharmony_ci &xilinx_pcie_msi_chip); 5278c2ecf20Sopenharmony_ci if (!port->msi_domain) { 5288c2ecf20Sopenharmony_ci dev_err(dev, "Failed to get a MSI IRQ domain\n"); 5298c2ecf20Sopenharmony_ci return -ENODEV; 5308c2ecf20Sopenharmony_ci } 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_ci ret = xilinx_pcie_enable_msi(port); 5338c2ecf20Sopenharmony_ci if (ret) 5348c2ecf20Sopenharmony_ci return ret; 5358c2ecf20Sopenharmony_ci } 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_ci return 0; 5388c2ecf20Sopenharmony_ci} 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_ci/** 5418c2ecf20Sopenharmony_ci * xilinx_pcie_init_port - Initialize hardware 5428c2ecf20Sopenharmony_ci * @port: PCIe port information 5438c2ecf20Sopenharmony_ci */ 5448c2ecf20Sopenharmony_cistatic void xilinx_pcie_init_port(struct xilinx_pcie_port *port) 5458c2ecf20Sopenharmony_ci{ 5468c2ecf20Sopenharmony_ci struct device *dev = port->dev; 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_ci if (xilinx_pcie_link_up(port)) 5498c2ecf20Sopenharmony_ci dev_info(dev, "PCIe Link is UP\n"); 5508c2ecf20Sopenharmony_ci else 5518c2ecf20Sopenharmony_ci dev_info(dev, "PCIe Link is DOWN\n"); 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_ci /* Disable all interrupts */ 5548c2ecf20Sopenharmony_ci pcie_write(port, ~XILINX_PCIE_IDR_ALL_MASK, 5558c2ecf20Sopenharmony_ci XILINX_PCIE_REG_IMR); 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ci /* Clear pending interrupts */ 5588c2ecf20Sopenharmony_ci pcie_write(port, pcie_read(port, XILINX_PCIE_REG_IDR) & 5598c2ecf20Sopenharmony_ci XILINX_PCIE_IMR_ALL_MASK, 5608c2ecf20Sopenharmony_ci XILINX_PCIE_REG_IDR); 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_ci /* Enable all interrupts we handle */ 5638c2ecf20Sopenharmony_ci pcie_write(port, XILINX_PCIE_IMR_ENABLE_MASK, XILINX_PCIE_REG_IMR); 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_ci /* Enable the Bridge enable bit */ 5668c2ecf20Sopenharmony_ci pcie_write(port, pcie_read(port, XILINX_PCIE_REG_RPSC) | 5678c2ecf20Sopenharmony_ci XILINX_PCIE_REG_RPSC_BEN, 5688c2ecf20Sopenharmony_ci XILINX_PCIE_REG_RPSC); 5698c2ecf20Sopenharmony_ci} 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_ci/** 5728c2ecf20Sopenharmony_ci * xilinx_pcie_parse_dt - Parse Device tree 5738c2ecf20Sopenharmony_ci * @port: PCIe port information 5748c2ecf20Sopenharmony_ci * 5758c2ecf20Sopenharmony_ci * Return: '0' on success and error value on failure 5768c2ecf20Sopenharmony_ci */ 5778c2ecf20Sopenharmony_cistatic int xilinx_pcie_parse_dt(struct xilinx_pcie_port *port) 5788c2ecf20Sopenharmony_ci{ 5798c2ecf20Sopenharmony_ci struct device *dev = port->dev; 5808c2ecf20Sopenharmony_ci struct device_node *node = dev->of_node; 5818c2ecf20Sopenharmony_ci struct resource regs; 5828c2ecf20Sopenharmony_ci int err; 5838c2ecf20Sopenharmony_ci 5848c2ecf20Sopenharmony_ci err = of_address_to_resource(node, 0, ®s); 5858c2ecf20Sopenharmony_ci if (err) { 5868c2ecf20Sopenharmony_ci dev_err(dev, "missing \"reg\" property\n"); 5878c2ecf20Sopenharmony_ci return err; 5888c2ecf20Sopenharmony_ci } 5898c2ecf20Sopenharmony_ci 5908c2ecf20Sopenharmony_ci port->reg_base = devm_pci_remap_cfg_resource(dev, ®s); 5918c2ecf20Sopenharmony_ci if (IS_ERR(port->reg_base)) 5928c2ecf20Sopenharmony_ci return PTR_ERR(port->reg_base); 5938c2ecf20Sopenharmony_ci 5948c2ecf20Sopenharmony_ci port->irq = irq_of_parse_and_map(node, 0); 5958c2ecf20Sopenharmony_ci err = devm_request_irq(dev, port->irq, xilinx_pcie_intr_handler, 5968c2ecf20Sopenharmony_ci IRQF_SHARED | IRQF_NO_THREAD, 5978c2ecf20Sopenharmony_ci "xilinx-pcie", port); 5988c2ecf20Sopenharmony_ci if (err) { 5998c2ecf20Sopenharmony_ci dev_err(dev, "unable to request irq %d\n", port->irq); 6008c2ecf20Sopenharmony_ci return err; 6018c2ecf20Sopenharmony_ci } 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_ci return 0; 6048c2ecf20Sopenharmony_ci} 6058c2ecf20Sopenharmony_ci 6068c2ecf20Sopenharmony_ci/** 6078c2ecf20Sopenharmony_ci * xilinx_pcie_probe - Probe function 6088c2ecf20Sopenharmony_ci * @pdev: Platform device pointer 6098c2ecf20Sopenharmony_ci * 6108c2ecf20Sopenharmony_ci * Return: '0' on success and error value on failure 6118c2ecf20Sopenharmony_ci */ 6128c2ecf20Sopenharmony_cistatic int xilinx_pcie_probe(struct platform_device *pdev) 6138c2ecf20Sopenharmony_ci{ 6148c2ecf20Sopenharmony_ci struct device *dev = &pdev->dev; 6158c2ecf20Sopenharmony_ci struct xilinx_pcie_port *port; 6168c2ecf20Sopenharmony_ci struct pci_host_bridge *bridge; 6178c2ecf20Sopenharmony_ci int err; 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_ci if (!dev->of_node) 6208c2ecf20Sopenharmony_ci return -ENODEV; 6218c2ecf20Sopenharmony_ci 6228c2ecf20Sopenharmony_ci bridge = devm_pci_alloc_host_bridge(dev, sizeof(*port)); 6238c2ecf20Sopenharmony_ci if (!bridge) 6248c2ecf20Sopenharmony_ci return -ENODEV; 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_ci port = pci_host_bridge_priv(bridge); 6278c2ecf20Sopenharmony_ci 6288c2ecf20Sopenharmony_ci port->dev = dev; 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_ci err = xilinx_pcie_parse_dt(port); 6318c2ecf20Sopenharmony_ci if (err) { 6328c2ecf20Sopenharmony_ci dev_err(dev, "Parsing DT failed\n"); 6338c2ecf20Sopenharmony_ci return err; 6348c2ecf20Sopenharmony_ci } 6358c2ecf20Sopenharmony_ci 6368c2ecf20Sopenharmony_ci xilinx_pcie_init_port(port); 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_ci err = xilinx_pcie_init_irq_domain(port); 6398c2ecf20Sopenharmony_ci if (err) { 6408c2ecf20Sopenharmony_ci dev_err(dev, "Failed creating IRQ Domain\n"); 6418c2ecf20Sopenharmony_ci return err; 6428c2ecf20Sopenharmony_ci } 6438c2ecf20Sopenharmony_ci 6448c2ecf20Sopenharmony_ci bridge->sysdata = port; 6458c2ecf20Sopenharmony_ci bridge->ops = &xilinx_pcie_ops; 6468c2ecf20Sopenharmony_ci 6478c2ecf20Sopenharmony_ci#ifdef CONFIG_PCI_MSI 6488c2ecf20Sopenharmony_ci xilinx_pcie_msi_chip.dev = dev; 6498c2ecf20Sopenharmony_ci bridge->msi = &xilinx_pcie_msi_chip; 6508c2ecf20Sopenharmony_ci#endif 6518c2ecf20Sopenharmony_ci return pci_host_probe(bridge); 6528c2ecf20Sopenharmony_ci} 6538c2ecf20Sopenharmony_ci 6548c2ecf20Sopenharmony_cistatic const struct of_device_id xilinx_pcie_of_match[] = { 6558c2ecf20Sopenharmony_ci { .compatible = "xlnx,axi-pcie-host-1.00.a", }, 6568c2ecf20Sopenharmony_ci {} 6578c2ecf20Sopenharmony_ci}; 6588c2ecf20Sopenharmony_ci 6598c2ecf20Sopenharmony_cistatic struct platform_driver xilinx_pcie_driver = { 6608c2ecf20Sopenharmony_ci .driver = { 6618c2ecf20Sopenharmony_ci .name = "xilinx-pcie", 6628c2ecf20Sopenharmony_ci .of_match_table = xilinx_pcie_of_match, 6638c2ecf20Sopenharmony_ci .suppress_bind_attrs = true, 6648c2ecf20Sopenharmony_ci }, 6658c2ecf20Sopenharmony_ci .probe = xilinx_pcie_probe, 6668c2ecf20Sopenharmony_ci}; 6678c2ecf20Sopenharmony_cibuiltin_platform_driver(xilinx_pcie_driver); 668