Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge branch 'pci/xilinx-cpm'

* pci/xilinx-cpm:
PCI: xilinx-cpm: Add Versal CPM Root Port driver
PCI: xilinx-cpm: Add YAML schemas for Versal CPM Root Port

+722
+99
Documentation/devicetree/bindings/pci/xilinx-versal-cpm.yaml
··· 1 + # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) 2 + %YAML 1.2 3 + --- 4 + $id: http://devicetree.org/schemas/pci/xilinx-versal-cpm.yaml# 5 + $schema: http://devicetree.org/meta-schemas/core.yaml# 6 + 7 + title: CPM Host Controller device tree for Xilinx Versal SoCs 8 + 9 + maintainers: 10 + - Bharat Kumar Gogada <bharat.kumar.gogada@xilinx.com> 11 + 12 + allOf: 13 + - $ref: /schemas/pci/pci-bus.yaml# 14 + 15 + properties: 16 + compatible: 17 + const: xlnx,versal-cpm-host-1.00 18 + 19 + reg: 20 + items: 21 + - description: Configuration space region and bridge registers. 22 + - description: CPM system level control and status registers. 23 + 24 + reg-names: 25 + items: 26 + - const: cfg 27 + - const: cpm_slcr 28 + 29 + interrupts: 30 + maxItems: 1 31 + 32 + msi-map: 33 + description: 34 + Maps a Requester ID to an MSI controller and associated MSI sideband data. 35 + 36 + ranges: 37 + maxItems: 2 38 + 39 + "#interrupt-cells": 40 + const: 1 41 + 42 + interrupt-controller: 43 + description: Interrupt controller node for handling legacy PCI interrupts. 44 + type: object 45 + properties: 46 + "#address-cells": 47 + const: 0 48 + "#interrupt-cells": 49 + const: 1 50 + "interrupt-controller": true 51 + additionalProperties: false 52 + 53 + required: 54 + - reg 55 + - reg-names 56 + - "#interrupt-cells" 57 + - interrupts 58 + - interrupt-parent 59 + - interrupt-map 60 + - interrupt-map-mask 61 + - bus-range 62 + - msi-map 63 + - interrupt-controller 64 + 65 + unevaluatedProperties: false 66 + 67 + examples: 68 + - | 69 + 70 + versal { 71 + #address-cells = <2>; 72 + #size-cells = <2>; 73 + cpm_pcie: pcie@fca10000 { 74 + compatible = "xlnx,versal-cpm-host-1.00"; 75 + device_type = "pci"; 76 + #address-cells = <3>; 77 + #interrupt-cells = <1>; 78 + #size-cells = <2>; 79 + interrupts = <0 72 4>; 80 + interrupt-parent = <&gic>; 81 + interrupt-map-mask = <0 0 0 7>; 82 + interrupt-map = <0 0 0 1 &pcie_intc_0 0>, 83 + <0 0 0 2 &pcie_intc_0 1>, 84 + <0 0 0 3 &pcie_intc_0 2>, 85 + <0 0 0 4 &pcie_intc_0 3>; 86 + bus-range = <0x00 0xff>; 87 + ranges = <0x02000000 0x0 0xe0000000 0x0 0xe0000000 0x0 0x10000000>, 88 + <0x43000000 0x80 0x00000000 0x80 0x00000000 0x0 0x80000000>; 89 + msi-map = <0x0 &its_gic 0x0 0x10000>; 90 + reg = <0x6 0x00000000 0x0 0x10000000>, 91 + <0x0 0xfca10000 0x0 0x1000>; 92 + reg-names = "cfg", "cpm_slcr"; 93 + pcie_intc_0: interrupt-controller { 94 + #address-cells = <0>; 95 + #interrupt-cells = <1>; 96 + interrupt-controller; 97 + }; 98 + }; 99 + };
+8
drivers/pci/controller/Kconfig
··· 99 99 Say 'Y' here if you want kernel to support the Xilinx AXI PCIe 100 100 Host Bridge driver. 101 101 102 + config PCIE_XILINX_CPM 103 + bool "Xilinx Versal CPM host bridge support" 104 + depends on ARCH_ZYNQMP || COMPILE_TEST 105 + select PCI_HOST_COMMON 106 + help 107 + Say 'Y' here if you want kernel support for the 108 + Xilinx Versal CPM host bridge. 109 + 102 110 config PCI_XGENE 103 111 bool "X-Gene PCIe controller" 104 112 depends on ARM64 || COMPILE_TEST
+1
drivers/pci/controller/Makefile
··· 13 13 obj-$(CONFIG_PCI_HOST_GENERIC) += pci-host-generic.o 14 14 obj-$(CONFIG_PCIE_XILINX) += pcie-xilinx.o 15 15 obj-$(CONFIG_PCIE_XILINX_NWL) += pcie-xilinx-nwl.o 16 + obj-$(CONFIG_PCIE_XILINX_CPM) += pcie-xilinx-cpm.o 16 17 obj-$(CONFIG_PCI_V3_SEMI) += pci-v3-semi.o 17 18 obj-$(CONFIG_PCI_XGENE_MSI) += pci-xgene-msi.o 18 19 obj-$(CONFIG_PCI_VERSATILE) += pci-versatile.o
+614
drivers/pci/controller/pcie-xilinx-cpm.c
··· 1 + // SPDX-License-Identifier: GPL-2.0+ 2 + /* 3 + * PCIe host controller driver for Xilinx Versal CPM DMA Bridge 4 + * 5 + * (C) Copyright 2019 - 2020, Xilinx, Inc. 6 + */ 7 + 8 + #include <linux/bitfield.h> 9 + #include <linux/interrupt.h> 10 + #include <linux/irq.h> 11 + #include <linux/irqchip.h> 12 + #include <linux/irqchip/chained_irq.h> 13 + #include <linux/irqdomain.h> 14 + #include <linux/kernel.h> 15 + #include <linux/module.h> 16 + #include <linux/of_address.h> 17 + #include <linux/of_pci.h> 18 + #include <linux/of_platform.h> 19 + #include <linux/of_irq.h> 20 + #include <linux/pci.h> 21 + #include <linux/platform_device.h> 22 + #include <linux/pci-ecam.h> 23 + 24 + #include "../pci.h" 25 + 26 + /* Register definitions */ 27 + #define XILINX_CPM_PCIE_REG_IDR 0x00000E10 28 + #define XILINX_CPM_PCIE_REG_IMR 0x00000E14 29 + #define XILINX_CPM_PCIE_REG_PSCR 0x00000E1C 30 + #define XILINX_CPM_PCIE_REG_RPSC 0x00000E20 31 + #define XILINX_CPM_PCIE_REG_RPEFR 0x00000E2C 32 + #define XILINX_CPM_PCIE_REG_IDRN 0x00000E38 33 + #define XILINX_CPM_PCIE_REG_IDRN_MASK 0x00000E3C 34 + #define XILINX_CPM_PCIE_MISC_IR_STATUS 0x00000340 35 + #define XILINX_CPM_PCIE_MISC_IR_ENABLE 0x00000348 36 + #define XILINX_CPM_PCIE_MISC_IR_LOCAL BIT(1) 37 + 38 + /* Interrupt registers definitions */ 39 + #define XILINX_CPM_PCIE_INTR_LINK_DOWN 0 40 + #define XILINX_CPM_PCIE_INTR_HOT_RESET 3 41 + #define XILINX_CPM_PCIE_INTR_CFG_PCIE_TIMEOUT 4 42 + #define XILINX_CPM_PCIE_INTR_CFG_TIMEOUT 8 43 + #define XILINX_CPM_PCIE_INTR_CORRECTABLE 9 44 + #define XILINX_CPM_PCIE_INTR_NONFATAL 10 45 + #define XILINX_CPM_PCIE_INTR_FATAL 11 46 + #define XILINX_CPM_PCIE_INTR_CFG_ERR_POISON 12 47 + #define XILINX_CPM_PCIE_INTR_PME_TO_ACK_RCVD 15 48 + #define XILINX_CPM_PCIE_INTR_INTX 16 49 + #define XILINX_CPM_PCIE_INTR_PM_PME_RCVD 17 50 + #define XILINX_CPM_PCIE_INTR_SLV_UNSUPP 20 51 + #define XILINX_CPM_PCIE_INTR_SLV_UNEXP 21 52 + #define XILINX_CPM_PCIE_INTR_SLV_COMPL 22 53 + #define XILINX_CPM_PCIE_INTR_SLV_ERRP 23 54 + #define XILINX_CPM_PCIE_INTR_SLV_CMPABT 24 55 + #define XILINX_CPM_PCIE_INTR_SLV_ILLBUR 25 56 + #define XILINX_CPM_PCIE_INTR_MST_DECERR 26 57 + #define XILINX_CPM_PCIE_INTR_MST_SLVERR 27 58 + #define XILINX_CPM_PCIE_INTR_SLV_PCIE_TIMEOUT 28 59 + 60 + #define IMR(x) BIT(XILINX_CPM_PCIE_INTR_ ##x) 61 + 62 + #define XILINX_CPM_PCIE_IMR_ALL_MASK \ 63 + ( \ 64 + IMR(LINK_DOWN) | \ 65 + IMR(HOT_RESET) | \ 66 + IMR(CFG_PCIE_TIMEOUT) | \ 67 + IMR(CFG_TIMEOUT) | \ 68 + IMR(CORRECTABLE) | \ 69 + IMR(NONFATAL) | \ 70 + IMR(FATAL) | \ 71 + IMR(CFG_ERR_POISON) | \ 72 + IMR(PME_TO_ACK_RCVD) | \ 73 + IMR(INTX) | \ 74 + IMR(PM_PME_RCVD) | \ 75 + IMR(SLV_UNSUPP) | \ 76 + IMR(SLV_UNEXP) | \ 77 + IMR(SLV_COMPL) | \ 78 + IMR(SLV_ERRP) | \ 79 + IMR(SLV_CMPABT) | \ 80 + IMR(SLV_ILLBUR) | \ 81 + IMR(MST_DECERR) | \ 82 + IMR(MST_SLVERR) | \ 83 + IMR(SLV_PCIE_TIMEOUT) \ 84 + ) 85 + 86 + #define XILINX_CPM_PCIE_IDR_ALL_MASK 0xFFFFFFFF 87 + #define XILINX_CPM_PCIE_IDRN_MASK GENMASK(19, 16) 88 + #define XILINX_CPM_PCIE_IDRN_SHIFT 16 89 + 90 + /* Root Port Error FIFO Read Register definitions */ 91 + #define XILINX_CPM_PCIE_RPEFR_ERR_VALID BIT(18) 92 + #define XILINX_CPM_PCIE_RPEFR_REQ_ID GENMASK(15, 0) 93 + #define XILINX_CPM_PCIE_RPEFR_ALL_MASK 0xFFFFFFFF 94 + 95 + /* Root Port Status/control Register definitions */ 96 + #define XILINX_CPM_PCIE_REG_RPSC_BEN BIT(0) 97 + 98 + /* Phy Status/Control Register definitions */ 99 + #define XILINX_CPM_PCIE_REG_PSCR_LNKUP BIT(11) 100 + 101 + /** 102 + * struct xilinx_cpm_pcie_port - PCIe port information 103 + * @reg_base: Bridge Register Base 104 + * @cpm_base: CPM System Level Control and Status Register(SLCR) Base 105 + * @dev: Device pointer 106 + * @intx_domain: Legacy IRQ domain pointer 107 + * @cpm_domain: CPM IRQ domain pointer 108 + * @cfg: Holds mappings of config space window 109 + * @intx_irq: legacy interrupt number 110 + * @irq: Error interrupt number 111 + * @lock: lock protecting shared register access 112 + */ 113 + struct xilinx_cpm_pcie_port { 114 + void __iomem *reg_base; 115 + void __iomem *cpm_base; 116 + struct device *dev; 117 + struct irq_domain *intx_domain; 118 + struct irq_domain *cpm_domain; 119 + struct pci_config_window *cfg; 120 + int intx_irq; 121 + int irq; 122 + raw_spinlock_t lock; 123 + }; 124 + 125 + static u32 pcie_read(struct xilinx_cpm_pcie_port *port, u32 reg) 126 + { 127 + return readl_relaxed(port->reg_base + reg); 128 + } 129 + 130 + static void pcie_write(struct xilinx_cpm_pcie_port *port, 131 + u32 val, u32 reg) 132 + { 133 + writel_relaxed(val, port->reg_base + reg); 134 + } 135 + 136 + static bool cpm_pcie_link_up(struct xilinx_cpm_pcie_port *port) 137 + { 138 + return (pcie_read(port, XILINX_CPM_PCIE_REG_PSCR) & 139 + XILINX_CPM_PCIE_REG_PSCR_LNKUP); 140 + } 141 + 142 + static void cpm_pcie_clear_err_interrupts(struct xilinx_cpm_pcie_port *port) 143 + { 144 + unsigned long val = pcie_read(port, XILINX_CPM_PCIE_REG_RPEFR); 145 + 146 + if (val & XILINX_CPM_PCIE_RPEFR_ERR_VALID) { 147 + dev_dbg(port->dev, "Requester ID %lu\n", 148 + val & XILINX_CPM_PCIE_RPEFR_REQ_ID); 149 + pcie_write(port, XILINX_CPM_PCIE_RPEFR_ALL_MASK, 150 + XILINX_CPM_PCIE_REG_RPEFR); 151 + } 152 + } 153 + 154 + static void xilinx_cpm_mask_leg_irq(struct irq_data *data) 155 + { 156 + struct xilinx_cpm_pcie_port *port = irq_data_get_irq_chip_data(data); 157 + unsigned long flags; 158 + u32 mask; 159 + u32 val; 160 + 161 + mask = BIT(data->hwirq + XILINX_CPM_PCIE_IDRN_SHIFT); 162 + raw_spin_lock_irqsave(&port->lock, flags); 163 + val = pcie_read(port, XILINX_CPM_PCIE_REG_IDRN_MASK); 164 + pcie_write(port, (val & (~mask)), XILINX_CPM_PCIE_REG_IDRN_MASK); 165 + raw_spin_unlock_irqrestore(&port->lock, flags); 166 + } 167 + 168 + static void xilinx_cpm_unmask_leg_irq(struct irq_data *data) 169 + { 170 + struct xilinx_cpm_pcie_port *port = irq_data_get_irq_chip_data(data); 171 + unsigned long flags; 172 + u32 mask; 173 + u32 val; 174 + 175 + mask = BIT(data->hwirq + XILINX_CPM_PCIE_IDRN_SHIFT); 176 + raw_spin_lock_irqsave(&port->lock, flags); 177 + val = pcie_read(port, XILINX_CPM_PCIE_REG_IDRN_MASK); 178 + pcie_write(port, (val | mask), XILINX_CPM_PCIE_REG_IDRN_MASK); 179 + raw_spin_unlock_irqrestore(&port->lock, flags); 180 + } 181 + 182 + static struct irq_chip xilinx_cpm_leg_irq_chip = { 183 + .name = "INTx", 184 + .irq_mask = xilinx_cpm_mask_leg_irq, 185 + .irq_unmask = xilinx_cpm_unmask_leg_irq, 186 + }; 187 + 188 + /** 189 + * xilinx_cpm_pcie_intx_map - Set the handler for the INTx and mark IRQ as valid 190 + * @domain: IRQ domain 191 + * @irq: Virtual IRQ number 192 + * @hwirq: HW interrupt number 193 + * 194 + * Return: Always returns 0. 195 + */ 196 + static int xilinx_cpm_pcie_intx_map(struct irq_domain *domain, 197 + unsigned int irq, irq_hw_number_t hwirq) 198 + { 199 + irq_set_chip_and_handler(irq, &xilinx_cpm_leg_irq_chip, 200 + handle_level_irq); 201 + irq_set_chip_data(irq, domain->host_data); 202 + irq_set_status_flags(irq, IRQ_LEVEL); 203 + 204 + return 0; 205 + } 206 + 207 + /* INTx IRQ Domain operations */ 208 + static const struct irq_domain_ops intx_domain_ops = { 209 + .map = xilinx_cpm_pcie_intx_map, 210 + }; 211 + 212 + static void xilinx_cpm_pcie_intx_flow(struct irq_desc *desc) 213 + { 214 + struct xilinx_cpm_pcie_port *port = irq_desc_get_handler_data(desc); 215 + struct irq_chip *chip = irq_desc_get_chip(desc); 216 + unsigned long val; 217 + int i; 218 + 219 + chained_irq_enter(chip, desc); 220 + 221 + val = FIELD_GET(XILINX_CPM_PCIE_IDRN_MASK, 222 + pcie_read(port, XILINX_CPM_PCIE_REG_IDRN)); 223 + 224 + for_each_set_bit(i, &val, PCI_NUM_INTX) 225 + generic_handle_irq(irq_find_mapping(port->intx_domain, i)); 226 + 227 + chained_irq_exit(chip, desc); 228 + } 229 + 230 + static void xilinx_cpm_mask_event_irq(struct irq_data *d) 231 + { 232 + struct xilinx_cpm_pcie_port *port = irq_data_get_irq_chip_data(d); 233 + u32 val; 234 + 235 + raw_spin_lock(&port->lock); 236 + val = pcie_read(port, XILINX_CPM_PCIE_REG_IMR); 237 + val &= ~BIT(d->hwirq); 238 + pcie_write(port, val, XILINX_CPM_PCIE_REG_IMR); 239 + raw_spin_unlock(&port->lock); 240 + } 241 + 242 + static void xilinx_cpm_unmask_event_irq(struct irq_data *d) 243 + { 244 + struct xilinx_cpm_pcie_port *port = irq_data_get_irq_chip_data(d); 245 + u32 val; 246 + 247 + raw_spin_lock(&port->lock); 248 + val = pcie_read(port, XILINX_CPM_PCIE_REG_IMR); 249 + val |= BIT(d->hwirq); 250 + pcie_write(port, val, XILINX_CPM_PCIE_REG_IMR); 251 + raw_spin_unlock(&port->lock); 252 + } 253 + 254 + static struct irq_chip xilinx_cpm_event_irq_chip = { 255 + .name = "RC-Event", 256 + .irq_mask = xilinx_cpm_mask_event_irq, 257 + .irq_unmask = xilinx_cpm_unmask_event_irq, 258 + }; 259 + 260 + static int xilinx_cpm_pcie_event_map(struct irq_domain *domain, 261 + unsigned int irq, irq_hw_number_t hwirq) 262 + { 263 + irq_set_chip_and_handler(irq, &xilinx_cpm_event_irq_chip, 264 + handle_level_irq); 265 + irq_set_chip_data(irq, domain->host_data); 266 + irq_set_status_flags(irq, IRQ_LEVEL); 267 + return 0; 268 + } 269 + 270 + static const struct irq_domain_ops event_domain_ops = { 271 + .map = xilinx_cpm_pcie_event_map, 272 + }; 273 + 274 + static void xilinx_cpm_pcie_event_flow(struct irq_desc *desc) 275 + { 276 + struct xilinx_cpm_pcie_port *port = irq_desc_get_handler_data(desc); 277 + struct irq_chip *chip = irq_desc_get_chip(desc); 278 + unsigned long val; 279 + int i; 280 + 281 + chained_irq_enter(chip, desc); 282 + val = pcie_read(port, XILINX_CPM_PCIE_REG_IDR); 283 + val &= pcie_read(port, XILINX_CPM_PCIE_REG_IMR); 284 + for_each_set_bit(i, &val, 32) 285 + generic_handle_irq(irq_find_mapping(port->cpm_domain, i)); 286 + pcie_write(port, val, XILINX_CPM_PCIE_REG_IDR); 287 + 288 + /* 289 + * XILINX_CPM_PCIE_MISC_IR_STATUS register is mapped to 290 + * CPM SLCR block. 291 + */ 292 + val = readl_relaxed(port->cpm_base + XILINX_CPM_PCIE_MISC_IR_STATUS); 293 + if (val) 294 + writel_relaxed(val, 295 + port->cpm_base + XILINX_CPM_PCIE_MISC_IR_STATUS); 296 + 297 + chained_irq_exit(chip, desc); 298 + } 299 + 300 + #define _IC(x, s) \ 301 + [XILINX_CPM_PCIE_INTR_ ## x] = { __stringify(x), s } 302 + 303 + static const struct { 304 + const char *sym; 305 + const char *str; 306 + } intr_cause[32] = { 307 + _IC(LINK_DOWN, "Link Down"), 308 + _IC(HOT_RESET, "Hot reset"), 309 + _IC(CFG_TIMEOUT, "ECAM access timeout"), 310 + _IC(CORRECTABLE, "Correctable error message"), 311 + _IC(NONFATAL, "Non fatal error message"), 312 + _IC(FATAL, "Fatal error message"), 313 + _IC(SLV_UNSUPP, "Slave unsupported request"), 314 + _IC(SLV_UNEXP, "Slave unexpected completion"), 315 + _IC(SLV_COMPL, "Slave completion timeout"), 316 + _IC(SLV_ERRP, "Slave Error Poison"), 317 + _IC(SLV_CMPABT, "Slave Completer Abort"), 318 + _IC(SLV_ILLBUR, "Slave Illegal Burst"), 319 + _IC(MST_DECERR, "Master decode error"), 320 + _IC(MST_SLVERR, "Master slave error"), 321 + _IC(CFG_PCIE_TIMEOUT, "PCIe ECAM access timeout"), 322 + _IC(CFG_ERR_POISON, "ECAM poisoned completion received"), 323 + _IC(PME_TO_ACK_RCVD, "PME_TO_ACK message received"), 324 + _IC(PM_PME_RCVD, "PM_PME message received"), 325 + _IC(SLV_PCIE_TIMEOUT, "PCIe completion timeout received"), 326 + }; 327 + 328 + static irqreturn_t xilinx_cpm_pcie_intr_handler(int irq, void *dev_id) 329 + { 330 + struct xilinx_cpm_pcie_port *port = dev_id; 331 + struct device *dev = port->dev; 332 + struct irq_data *d; 333 + 334 + d = irq_domain_get_irq_data(port->cpm_domain, irq); 335 + 336 + switch (d->hwirq) { 337 + case XILINX_CPM_PCIE_INTR_CORRECTABLE: 338 + case XILINX_CPM_PCIE_INTR_NONFATAL: 339 + case XILINX_CPM_PCIE_INTR_FATAL: 340 + cpm_pcie_clear_err_interrupts(port); 341 + fallthrough; 342 + 343 + default: 344 + if (intr_cause[d->hwirq].str) 345 + dev_warn(dev, "%s\n", intr_cause[d->hwirq].str); 346 + else 347 + dev_warn(dev, "Unknown IRQ %ld\n", d->hwirq); 348 + } 349 + 350 + return IRQ_HANDLED; 351 + } 352 + 353 + static void xilinx_cpm_free_irq_domains(struct xilinx_cpm_pcie_port *port) 354 + { 355 + if (port->intx_domain) { 356 + irq_domain_remove(port->intx_domain); 357 + port->intx_domain = NULL; 358 + } 359 + 360 + if (port->cpm_domain) { 361 + irq_domain_remove(port->cpm_domain); 362 + port->cpm_domain = NULL; 363 + } 364 + } 365 + 366 + /** 367 + * xilinx_cpm_pcie_init_irq_domain - Initialize IRQ domain 368 + * @port: PCIe port information 369 + * 370 + * Return: '0' on success and error value on failure 371 + */ 372 + static int xilinx_cpm_pcie_init_irq_domain(struct xilinx_cpm_pcie_port *port) 373 + { 374 + struct device *dev = port->dev; 375 + struct device_node *node = dev->of_node; 376 + struct device_node *pcie_intc_node; 377 + 378 + /* Setup INTx */ 379 + pcie_intc_node = of_get_next_child(node, NULL); 380 + if (!pcie_intc_node) { 381 + dev_err(dev, "No PCIe Intc node found\n"); 382 + return -EINVAL; 383 + } 384 + 385 + port->cpm_domain = irq_domain_add_linear(pcie_intc_node, 32, 386 + &event_domain_ops, 387 + port); 388 + if (!port->cpm_domain) 389 + goto out; 390 + 391 + irq_domain_update_bus_token(port->cpm_domain, DOMAIN_BUS_NEXUS); 392 + 393 + port->intx_domain = irq_domain_add_linear(pcie_intc_node, PCI_NUM_INTX, 394 + &intx_domain_ops, 395 + port); 396 + if (!port->intx_domain) 397 + goto out; 398 + 399 + irq_domain_update_bus_token(port->intx_domain, DOMAIN_BUS_WIRED); 400 + 401 + of_node_put(pcie_intc_node); 402 + raw_spin_lock_init(&port->lock); 403 + 404 + return 0; 405 + out: 406 + xilinx_cpm_free_irq_domains(port); 407 + dev_err(dev, "Failed to allocate IRQ domains\n"); 408 + 409 + return -ENOMEM; 410 + } 411 + 412 + static int xilinx_cpm_setup_irq(struct xilinx_cpm_pcie_port *port) 413 + { 414 + struct device *dev = port->dev; 415 + struct platform_device *pdev = to_platform_device(dev); 416 + int i, irq; 417 + 418 + port->irq = platform_get_irq(pdev, 0); 419 + if (port->irq < 0) 420 + return port->irq; 421 + 422 + for (i = 0; i < ARRAY_SIZE(intr_cause); i++) { 423 + int err; 424 + 425 + if (!intr_cause[i].str) 426 + continue; 427 + 428 + irq = irq_create_mapping(port->cpm_domain, i); 429 + if (!irq) { 430 + dev_err(dev, "Failed to map interrupt\n"); 431 + return -ENXIO; 432 + } 433 + 434 + err = devm_request_irq(dev, irq, xilinx_cpm_pcie_intr_handler, 435 + 0, intr_cause[i].sym, port); 436 + if (err) { 437 + dev_err(dev, "Failed to request IRQ %d\n", irq); 438 + return err; 439 + } 440 + } 441 + 442 + port->intx_irq = irq_create_mapping(port->cpm_domain, 443 + XILINX_CPM_PCIE_INTR_INTX); 444 + if (!port->intx_irq) { 445 + dev_err(dev, "Failed to map INTx interrupt\n"); 446 + return -ENXIO; 447 + } 448 + 449 + /* Plug the INTx chained handler */ 450 + irq_set_chained_handler_and_data(port->intx_irq, 451 + xilinx_cpm_pcie_intx_flow, port); 452 + 453 + /* Plug the main event chained handler */ 454 + irq_set_chained_handler_and_data(port->irq, 455 + xilinx_cpm_pcie_event_flow, port); 456 + 457 + return 0; 458 + } 459 + 460 + /** 461 + * xilinx_cpm_pcie_init_port - Initialize hardware 462 + * @port: PCIe port information 463 + */ 464 + static void xilinx_cpm_pcie_init_port(struct xilinx_cpm_pcie_port *port) 465 + { 466 + if (cpm_pcie_link_up(port)) 467 + dev_info(port->dev, "PCIe Link is UP\n"); 468 + else 469 + dev_info(port->dev, "PCIe Link is DOWN\n"); 470 + 471 + /* Disable all interrupts */ 472 + pcie_write(port, ~XILINX_CPM_PCIE_IDR_ALL_MASK, 473 + XILINX_CPM_PCIE_REG_IMR); 474 + 475 + /* Clear pending interrupts */ 476 + pcie_write(port, pcie_read(port, XILINX_CPM_PCIE_REG_IDR) & 477 + XILINX_CPM_PCIE_IMR_ALL_MASK, 478 + XILINX_CPM_PCIE_REG_IDR); 479 + 480 + /* 481 + * XILINX_CPM_PCIE_MISC_IR_ENABLE register is mapped to 482 + * CPM SLCR block. 483 + */ 484 + writel(XILINX_CPM_PCIE_MISC_IR_LOCAL, 485 + port->cpm_base + XILINX_CPM_PCIE_MISC_IR_ENABLE); 486 + /* Enable the Bridge enable bit */ 487 + pcie_write(port, pcie_read(port, XILINX_CPM_PCIE_REG_RPSC) | 488 + XILINX_CPM_PCIE_REG_RPSC_BEN, 489 + XILINX_CPM_PCIE_REG_RPSC); 490 + } 491 + 492 + /** 493 + * xilinx_cpm_pcie_parse_dt - Parse Device tree 494 + * @port: PCIe port information 495 + * @bus_range: Bus resource 496 + * 497 + * Return: '0' on success and error value on failure 498 + */ 499 + static int xilinx_cpm_pcie_parse_dt(struct xilinx_cpm_pcie_port *port, 500 + struct resource *bus_range) 501 + { 502 + struct device *dev = port->dev; 503 + struct platform_device *pdev = to_platform_device(dev); 504 + struct resource *res; 505 + 506 + port->cpm_base = devm_platform_ioremap_resource_byname(pdev, 507 + "cpm_slcr"); 508 + if (IS_ERR(port->cpm_base)) 509 + return PTR_ERR(port->cpm_base); 510 + 511 + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "cfg"); 512 + if (!res) 513 + return -ENXIO; 514 + 515 + port->cfg = pci_ecam_create(dev, res, bus_range, 516 + &pci_generic_ecam_ops); 517 + if (IS_ERR(port->cfg)) 518 + return PTR_ERR(port->cfg); 519 + 520 + port->reg_base = port->cfg->win; 521 + 522 + return 0; 523 + } 524 + 525 + static void xilinx_cpm_free_interrupts(struct xilinx_cpm_pcie_port *port) 526 + { 527 + irq_set_chained_handler_and_data(port->intx_irq, NULL, NULL); 528 + irq_set_chained_handler_and_data(port->irq, NULL, NULL); 529 + } 530 + 531 + /** 532 + * xilinx_cpm_pcie_probe - Probe function 533 + * @pdev: Platform device pointer 534 + * 535 + * Return: '0' on success and error value on failure 536 + */ 537 + static int xilinx_cpm_pcie_probe(struct platform_device *pdev) 538 + { 539 + struct xilinx_cpm_pcie_port *port; 540 + struct device *dev = &pdev->dev; 541 + struct pci_host_bridge *bridge; 542 + struct resource *bus_range; 543 + int err; 544 + 545 + bridge = devm_pci_alloc_host_bridge(dev, sizeof(*port)); 546 + if (!bridge) 547 + return -ENODEV; 548 + 549 + port = pci_host_bridge_priv(bridge); 550 + 551 + port->dev = dev; 552 + 553 + err = pci_parse_request_of_pci_ranges(dev, &bridge->windows, 554 + &bridge->dma_ranges, &bus_range); 555 + if (err) { 556 + dev_err(dev, "Getting bridge resources failed\n"); 557 + return err; 558 + } 559 + 560 + err = xilinx_cpm_pcie_init_irq_domain(port); 561 + if (err) 562 + return err; 563 + 564 + err = xilinx_cpm_pcie_parse_dt(port, bus_range); 565 + if (err) { 566 + dev_err(dev, "Parsing DT failed\n"); 567 + goto err_parse_dt; 568 + } 569 + 570 + xilinx_cpm_pcie_init_port(port); 571 + 572 + err = xilinx_cpm_setup_irq(port); 573 + if (err) { 574 + dev_err(dev, "Failed to set up interrupts\n"); 575 + goto err_setup_irq; 576 + } 577 + 578 + bridge->dev.parent = dev; 579 + bridge->sysdata = port->cfg; 580 + bridge->busnr = port->cfg->busr.start; 581 + bridge->ops = (struct pci_ops *)&pci_generic_ecam_ops.pci_ops; 582 + bridge->map_irq = of_irq_parse_and_map_pci; 583 + bridge->swizzle_irq = pci_common_swizzle; 584 + 585 + err = pci_host_probe(bridge); 586 + if (err < 0) 587 + goto err_host_bridge; 588 + 589 + return 0; 590 + 591 + err_host_bridge: 592 + xilinx_cpm_free_interrupts(port); 593 + err_setup_irq: 594 + pci_ecam_free(port->cfg); 595 + err_parse_dt: 596 + xilinx_cpm_free_irq_domains(port); 597 + return err; 598 + } 599 + 600 + static const struct of_device_id xilinx_cpm_pcie_of_match[] = { 601 + { .compatible = "xlnx,versal-cpm-host-1.00", }, 602 + {} 603 + }; 604 + 605 + static struct platform_driver xilinx_cpm_pcie_driver = { 606 + .driver = { 607 + .name = "xilinx-cpm-pcie", 608 + .of_match_table = xilinx_cpm_pcie_of_match, 609 + .suppress_bind_attrs = true, 610 + }, 611 + .probe = xilinx_cpm_pcie_probe, 612 + }; 613 + 614 + builtin_platform_driver(xilinx_cpm_pcie_driver);