xlp_pci.c revision 279387
1225394Sjchandra/*- 2233563Sjchandra * Copyright (c) 2003-2012 Broadcom Corporation 3233563Sjchandra * All Rights Reserved 4225394Sjchandra * 5225394Sjchandra * Redistribution and use in source and binary forms, with or without 6225394Sjchandra * modification, are permitted provided that the following conditions 7225394Sjchandra * are met: 8233563Sjchandra * 9225394Sjchandra * 1. Redistributions of source code must retain the above copyright 10225394Sjchandra * notice, this list of conditions and the following disclaimer. 11225394Sjchandra * 2. Redistributions in binary form must reproduce the above copyright 12233563Sjchandra * notice, this list of conditions and the following disclaimer in 13233563Sjchandra * the documentation and/or other materials provided with the 14233563Sjchandra * distribution. 15279387Sjchandra * 16233563Sjchandra * THIS SOFTWARE IS PROVIDED BY BROADCOM ``AS IS'' AND ANY EXPRESS OR 17233563Sjchandra * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18233563Sjchandra * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19233563Sjchandra * ARE DISCLAIMED. IN NO EVENT SHALL BROADCOM OR CONTRIBUTORS BE LIABLE 20233563Sjchandra * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21233563Sjchandra * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22233563Sjchandra * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 23233563Sjchandra * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 24233563Sjchandra * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 25233563Sjchandra * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN 26233563Sjchandra * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27233563Sjchandra */ 28233563Sjchandra 29225394Sjchandra#include <sys/cdefs.h> 30225394Sjchandra__FBSDID("$FreeBSD: head/sys/mips/nlm/xlp_pci.c 279387 2015-02-28 00:17:29Z jchandra $"); 31225394Sjchandra 32225394Sjchandra#include <sys/param.h> 33225394Sjchandra#include <sys/systm.h> 34225394Sjchandra#include <sys/types.h> 35225394Sjchandra#include <sys/kernel.h> 36225394Sjchandra#include <sys/module.h> 37225394Sjchandra#include <sys/malloc.h> 38225394Sjchandra#include <sys/bus.h> 39225394Sjchandra#include <sys/endian.h> 40225394Sjchandra#include <sys/rman.h> 41233563Sjchandra#include <sys/pciio.h> 42225394Sjchandra 43225394Sjchandra#include <vm/vm.h> 44225394Sjchandra#include <vm/vm_param.h> 45225394Sjchandra#include <vm/pmap.h> 46225394Sjchandra 47225394Sjchandra#include <dev/pci/pcivar.h> 48225394Sjchandra#include <dev/pci/pcireg.h> 49233563Sjchandra#include <dev/pci/pci_private.h> 50233563Sjchandra 51225394Sjchandra#include <dev/uart/uart.h> 52225394Sjchandra#include <dev/uart/uart_bus.h> 53225394Sjchandra#include <dev/uart/uart_cpu.h> 54225394Sjchandra 55279384Sjchandra#include <dev/ofw/openfirm.h> 56279345Sjchandra#include <dev/ofw/ofw_bus.h> 57279345Sjchandra#include <dev/ofw/ofw_bus_subr.h> 58279345Sjchandra 59225394Sjchandra#include <machine/bus.h> 60225394Sjchandra#include <machine/md_var.h> 61225394Sjchandra#include <machine/intr_machdep.h> 62225394Sjchandra#include <machine/cpuregs.h> 63225394Sjchandra 64225394Sjchandra#include <mips/nlm/hal/haldefs.h> 65225394Sjchandra#include <mips/nlm/interrupt.h> 66225394Sjchandra#include <mips/nlm/hal/iomap.h> 67225394Sjchandra#include <mips/nlm/hal/mips-extns.h> 68225394Sjchandra#include <mips/nlm/hal/pic.h> 69233536Sjchandra#include <mips/nlm/hal/bridge.h> 70233556Sjchandra#include <mips/nlm/hal/gbu.h> 71225394Sjchandra#include <mips/nlm/hal/pcibus.h> 72225394Sjchandra#include <mips/nlm/hal/uart.h> 73225394Sjchandra#include <mips/nlm/xlp.h> 74225394Sjchandra 75225394Sjchandra#include "pcib_if.h" 76233563Sjchandra#include "pci_if.h" 77225394Sjchandra 78233563Sjchandrastatic int 79279384Sjchandraxlp_pci_attach(device_t dev) 80233563Sjchandra{ 81233563Sjchandra struct pci_devinfo *dinfo; 82279384Sjchandra device_t pcib; 83279384Sjchandra int maxslots, s, f, pcifunchigh, irq; 84279384Sjchandra int busno, node, devoffset; 85233563Sjchandra uint16_t devid; 86233563Sjchandra uint8_t hdrtype; 87233563Sjchandra 88233563Sjchandra /* 89233563Sjchandra * The on-chip devices are on a bus that is almost, but not 90233563Sjchandra * quite, completely like PCI. Add those things by hand. 91233563Sjchandra */ 92279384Sjchandra pcib = device_get_parent(dev); 93233563Sjchandra busno = pcib_get_bus(dev); 94233563Sjchandra maxslots = PCIB_MAXSLOTS(pcib); 95233563Sjchandra for (s = 0; s <= maxslots; s++) { 96233563Sjchandra pcifunchigh = 0; 97233563Sjchandra f = 0; 98233563Sjchandra hdrtype = PCIB_READ_CONFIG(pcib, busno, s, f, PCIR_HDRTYPE, 1); 99233563Sjchandra if ((hdrtype & PCIM_HDRTYPE) > PCI_MAXHDRTYPE) 100233563Sjchandra continue; 101233563Sjchandra if (hdrtype & PCIM_MFDEV) 102233563Sjchandra pcifunchigh = PCI_FUNCMAX; 103279384Sjchandra node = s / 8; 104279384Sjchandra for (f = 0; f <= pcifunchigh; f++) { 105279384Sjchandra devoffset = XLP_HDR_OFFSET(node, 0, s % 8, f); 106279384Sjchandra if (!nlm_dev_exists(devoffset)) 107279384Sjchandra continue; 108279384Sjchandra 109279384Sjchandra /* Find if there is a desc for the SoC device */ 110279384Sjchandra devid = PCIB_READ_CONFIG(pcib, busno, s, f, PCIR_DEVICE, 2); 111279384Sjchandra 112279384Sjchandra /* Skip devices that don't have a proper PCI header */ 113279384Sjchandra switch (devid) { 114279384Sjchandra case PCI_DEVICE_ID_NLM_ICI: 115279384Sjchandra case PCI_DEVICE_ID_NLM_PIC: 116279384Sjchandra case PCI_DEVICE_ID_NLM_FMN: 117279384Sjchandra case PCI_DEVICE_ID_NLM_UART: 118279384Sjchandra case PCI_DEVICE_ID_NLM_I2C: 119279384Sjchandra case PCI_DEVICE_ID_NLM_NOR: 120279384Sjchandra case PCI_DEVICE_ID_NLM_MMC: 121279384Sjchandra continue; 122279384Sjchandra case PCI_DEVICE_ID_NLM_EHCI: 123279384Sjchandra irq = PIC_USB_IRQ(f); 124279384Sjchandra PCIB_WRITE_CONFIG(pcib, busno, s, f, 125279384Sjchandra XLP_PCI_DEVSCRATCH_REG0 << 2, 126279384Sjchandra (1 << 8) | irq, 4); 127279384Sjchandra } 128279384Sjchandra dinfo = pci_read_device(pcib, pcib_get_domain(dev), 129279384Sjchandra busno, s, f, sizeof(*dinfo)); 130279384Sjchandra pci_add_child(dev, dinfo); 131279384Sjchandra } 132233563Sjchandra } 133233563Sjchandra return (bus_generic_attach(dev)); 134233563Sjchandra} 135233563Sjchandra 136233563Sjchandrastatic int 137233563Sjchandraxlp_pci_probe(device_t dev) 138233563Sjchandra{ 139233563Sjchandra device_t pcib; 140233563Sjchandra 141233563Sjchandra pcib = device_get_parent(dev); 142233563Sjchandra /* 143233563Sjchandra * Only the top level bus has SoC devices, leave the rest to 144233563Sjchandra * Generic PCI code 145233563Sjchandra */ 146233563Sjchandra if (strcmp(device_get_nameunit(pcib), "pcib0") != 0) 147233563Sjchandra return (ENXIO); 148233563Sjchandra device_set_desc(dev, "XLP SoCbus"); 149233563Sjchandra return (BUS_PROBE_DEFAULT); 150233563Sjchandra} 151233563Sjchandra 152233563Sjchandrastatic devclass_t pci_devclass; 153233563Sjchandrastatic device_method_t xlp_pci_methods[] = { 154233563Sjchandra /* Device interface */ 155233563Sjchandra DEVMETHOD(device_probe, xlp_pci_probe), 156233563Sjchandra DEVMETHOD(device_attach, xlp_pci_attach), 157233563Sjchandra DEVMETHOD_END 158233563Sjchandra}; 159233563Sjchandra 160233570SjchandraDEFINE_CLASS_1(pci, xlp_pci_driver, xlp_pci_methods, sizeof(struct pci_softc), 161233570Sjchandra pci_driver); 162233563SjchandraDRIVER_MODULE(xlp_pci, pcib, xlp_pci_driver, pci_devclass, 0, 0); 163233563Sjchandra 164225394Sjchandrastatic int 165225394Sjchandraxlp_pcib_probe(device_t dev) 166225394Sjchandra{ 167225394Sjchandra 168279345Sjchandra if (ofw_bus_is_compatible(dev, "netlogic,xlp-pci")) { 169279345Sjchandra device_set_desc(dev, "XLP PCI bus"); 170279345Sjchandra return (BUS_PROBE_DEFAULT); 171279345Sjchandra } 172279345Sjchandra return (ENXIO); 173225394Sjchandra} 174225394Sjchandra 175225394Sjchandrastatic int 176225394Sjchandraxlp_pcib_read_ivar(device_t dev, device_t child, int which, uintptr_t *result) 177225394Sjchandra{ 178225394Sjchandra 179225394Sjchandra switch (which) { 180225394Sjchandra case PCIB_IVAR_DOMAIN: 181225394Sjchandra *result = 0; 182225394Sjchandra return (0); 183225394Sjchandra case PCIB_IVAR_BUS: 184225394Sjchandra *result = 0; 185225394Sjchandra return (0); 186225394Sjchandra } 187225394Sjchandra return (ENOENT); 188225394Sjchandra} 189225394Sjchandra 190225394Sjchandrastatic int 191225394Sjchandraxlp_pcib_write_ivar(device_t dev, device_t child, int which, uintptr_t result) 192225394Sjchandra{ 193225394Sjchandra switch (which) { 194225394Sjchandra case PCIB_IVAR_DOMAIN: 195225394Sjchandra return (EINVAL); 196225394Sjchandra case PCIB_IVAR_BUS: 197225394Sjchandra return (EINVAL); 198225394Sjchandra } 199225394Sjchandra return (ENOENT); 200225394Sjchandra} 201225394Sjchandra 202225394Sjchandrastatic int 203225394Sjchandraxlp_pcib_maxslots(device_t dev) 204225394Sjchandra{ 205225394Sjchandra 206225394Sjchandra return (PCI_SLOTMAX); 207225394Sjchandra} 208225394Sjchandra 209225394Sjchandrastatic u_int32_t 210225394Sjchandraxlp_pcib_read_config(device_t dev, u_int b, u_int s, u_int f, 211225394Sjchandra u_int reg, int width) 212225394Sjchandra{ 213225394Sjchandra uint32_t data = 0; 214225394Sjchandra uint64_t cfgaddr; 215225394Sjchandra int regindex = reg/sizeof(uint32_t); 216225394Sjchandra 217225394Sjchandra cfgaddr = nlm_pcicfg_base(XLP_HDR_OFFSET(0, b, s, f)); 218225394Sjchandra if ((width == 2) && (reg & 1)) 219225394Sjchandra return 0xFFFFFFFF; 220225394Sjchandra else if ((width == 4) && (reg & 3)) 221225394Sjchandra return 0xFFFFFFFF; 222225394Sjchandra 223279387Sjchandra /* 224233563Sjchandra * The intline and int pin of SoC devices are DOA, except 225233563Sjchandra * for bridges (slot %8 == 1). 226233563Sjchandra * use the values we stashed in a writable PCI scratch reg. 227225394Sjchandra */ 228233563Sjchandra if (b == 0 && regindex == 0xf && s % 8 > 1) 229233563Sjchandra regindex = XLP_PCI_DEVSCRATCH_REG0; 230225394Sjchandra 231233563Sjchandra data = nlm_read_pci_reg(cfgaddr, regindex); 232225394Sjchandra if (width == 1) 233225394Sjchandra return ((data >> ((reg & 3) << 3)) & 0xff); 234225394Sjchandra else if (width == 2) 235225394Sjchandra return ((data >> ((reg & 3) << 3)) & 0xffff); 236225394Sjchandra else 237225394Sjchandra return (data); 238225394Sjchandra} 239225394Sjchandra 240225394Sjchandrastatic void 241225394Sjchandraxlp_pcib_write_config(device_t dev, u_int b, u_int s, u_int f, 242225394Sjchandra u_int reg, u_int32_t val, int width) 243225394Sjchandra{ 244225394Sjchandra uint64_t cfgaddr; 245225394Sjchandra uint32_t data = 0; 246225394Sjchandra int regindex = reg / sizeof(uint32_t); 247225394Sjchandra 248225394Sjchandra cfgaddr = nlm_pcicfg_base(XLP_HDR_OFFSET(0, b, s, f)); 249225394Sjchandra if ((width == 2) && (reg & 1)) 250225394Sjchandra return; 251225394Sjchandra else if ((width == 4) && (reg & 3)) 252225394Sjchandra return; 253225394Sjchandra 254225394Sjchandra if (width == 1) { 255225394Sjchandra data = nlm_read_pci_reg(cfgaddr, regindex); 256225394Sjchandra data = (data & ~(0xff << ((reg & 3) << 3))) | 257225394Sjchandra (val << ((reg & 3) << 3)); 258225394Sjchandra } else if (width == 2) { 259225394Sjchandra data = nlm_read_pci_reg(cfgaddr, regindex); 260225394Sjchandra data = (data & ~(0xffff << ((reg & 3) << 3))) | 261225394Sjchandra (val << ((reg & 3) << 3)); 262225394Sjchandra } else { 263225394Sjchandra data = val; 264225394Sjchandra } 265225394Sjchandra 266233563Sjchandra /* 267233563Sjchandra * use shadow reg for intpin/intline which are dead 268233563Sjchandra */ 269233563Sjchandra if (b == 0 && regindex == 0xf && s % 8 > 1) 270233563Sjchandra regindex = XLP_PCI_DEVSCRATCH_REG0; 271225394Sjchandra nlm_write_pci_reg(cfgaddr, regindex, data); 272225394Sjchandra} 273225394Sjchandra 274233536Sjchandra/* 275245877Sjchandra * Enable byte swap in hardware when compiled big-endian. 276245877Sjchandra * Programs a link's PCIe SWAP regions from the link's IO and MEM address 277245877Sjchandra * ranges. 278233536Sjchandra */ 279233536Sjchandrastatic void 280233563Sjchandraxlp_pcib_hardware_swap_enable(int node, int link) 281233536Sjchandra{ 282245877Sjchandra#if BYTE_ORDER == BIG_ENDIAN 283233536Sjchandra uint64_t bbase, linkpcibase; 284233536Sjchandra uint32_t bar; 285233536Sjchandra int pcieoffset; 286233536Sjchandra 287233536Sjchandra pcieoffset = XLP_IO_PCIE_OFFSET(node, link); 288233536Sjchandra if (!nlm_dev_exists(pcieoffset)) 289233536Sjchandra return; 290233536Sjchandra 291233536Sjchandra bbase = nlm_get_bridge_regbase(node); 292233536Sjchandra linkpcibase = nlm_pcicfg_base(pcieoffset); 293233536Sjchandra bar = nlm_read_bridge_reg(bbase, BRIDGE_PCIEMEM_BASE0 + link); 294233536Sjchandra nlm_write_pci_reg(linkpcibase, PCIE_BYTE_SWAP_MEM_BASE, bar); 295233536Sjchandra 296233536Sjchandra bar = nlm_read_bridge_reg(bbase, BRIDGE_PCIEMEM_LIMIT0 + link); 297238289Sjchandra nlm_write_pci_reg(linkpcibase, PCIE_BYTE_SWAP_MEM_LIM, bar | 0xFFF); 298233536Sjchandra 299233536Sjchandra bar = nlm_read_bridge_reg(bbase, BRIDGE_PCIEIO_BASE0 + link); 300233536Sjchandra nlm_write_pci_reg(linkpcibase, PCIE_BYTE_SWAP_IO_BASE, bar); 301233536Sjchandra 302233536Sjchandra bar = nlm_read_bridge_reg(bbase, BRIDGE_PCIEIO_LIMIT0 + link); 303238289Sjchandra nlm_write_pci_reg(linkpcibase, PCIE_BYTE_SWAP_IO_LIM, bar | 0xFFF); 304245877Sjchandra#endif 305233536Sjchandra} 306233536Sjchandra 307279387Sjchandrastatic int 308225394Sjchandraxlp_pcib_attach(device_t dev) 309225394Sjchandra{ 310233536Sjchandra int node, link; 311225394Sjchandra 312233536Sjchandra /* enable hardware swap on all nodes/links */ 313233536Sjchandra for (node = 0; node < XLP_MAX_NODES; node++) 314233536Sjchandra for (link = 0; link < 4; link++) 315233563Sjchandra xlp_pcib_hardware_swap_enable(node, link); 316233536Sjchandra 317225394Sjchandra device_add_child(dev, "pci", 0); 318225394Sjchandra bus_generic_attach(dev); 319225394Sjchandra return (0); 320225394Sjchandra} 321225394Sjchandra 322225394Sjchandra/* 323225394Sjchandra * XLS PCIe can have upto 4 links, and each link has its on IRQ 324279387Sjchandra * Find the link on which the device is on 325225394Sjchandra */ 326225394Sjchandrastatic int 327225394Sjchandraxlp_pcie_link(device_t pcib, device_t dev) 328225394Sjchandra{ 329225394Sjchandra device_t parent, tmp; 330225394Sjchandra 331225394Sjchandra /* find the lane on which the slot is connected to */ 332225394Sjchandra tmp = dev; 333225394Sjchandra while (1) { 334225394Sjchandra parent = device_get_parent(tmp); 335225394Sjchandra if (parent == NULL || parent == pcib) { 336225394Sjchandra device_printf(dev, "Cannot find parent bus\n"); 337225394Sjchandra return (-1); 338225394Sjchandra } 339225394Sjchandra if (strcmp(device_get_nameunit(parent), "pci0") == 0) 340225394Sjchandra break; 341225394Sjchandra tmp = parent; 342225394Sjchandra } 343225394Sjchandra return (pci_get_function(tmp)); 344225394Sjchandra} 345225394Sjchandra 346225394Sjchandrastatic int 347225394Sjchandraxlp_alloc_msi(device_t pcib, device_t dev, int count, int maxcount, int *irqs) 348225394Sjchandra{ 349225394Sjchandra int i, link; 350225394Sjchandra 351225394Sjchandra /* 352225394Sjchandra * Each link has 32 MSIs that can be allocated, but for now 353225394Sjchandra * we only support one device per link. 354279387Sjchandra * msi_alloc() equivalent is needed when we start supporting 355225394Sjchandra * bridges on the PCIe link. 356225394Sjchandra */ 357225394Sjchandra link = xlp_pcie_link(pcib, dev); 358225394Sjchandra if (link == -1) 359225394Sjchandra return (ENXIO); 360225394Sjchandra 361225394Sjchandra /* 362225394Sjchandra * encode the irq so that we know it is a MSI interrupt when we 363225394Sjchandra * setup interrupts 364225394Sjchandra */ 365225394Sjchandra for (i = 0; i < count; i++) 366225394Sjchandra irqs[i] = 64 + link * 32 + i; 367225394Sjchandra 368225394Sjchandra return (0); 369225394Sjchandra} 370225394Sjchandra 371225394Sjchandrastatic int 372225394Sjchandraxlp_release_msi(device_t pcib, device_t dev, int count, int *irqs) 373225394Sjchandra{ 374225394Sjchandra return (0); 375225394Sjchandra} 376225394Sjchandra 377225394Sjchandrastatic int 378225394Sjchandraxlp_map_msi(device_t pcib, device_t dev, int irq, uint64_t *addr, 379225394Sjchandra uint32_t *data) 380225394Sjchandra{ 381279306Sjchandra int link; 382225394Sjchandra 383279306Sjchandra if (irq < 64) { 384279387Sjchandra device_printf(dev, "%s: map_msi for irq %d - ignored", 385225394Sjchandra device_get_nameunit(pcib), irq); 386225394Sjchandra return (ENXIO); 387225394Sjchandra } 388279306Sjchandra link = (irq - 64) / 32; 389279306Sjchandra *addr = MIPS_MSI_ADDR(0); 390279306Sjchandra *data = MIPS_MSI_DATA(PIC_PCIE_IRQ(link)); 391279306Sjchandra return (0); 392225394Sjchandra} 393225394Sjchandra 394225394Sjchandrastatic void 395279341Sjchandrabridge_pcie_ack(int irq, void *arg) 396225394Sjchandra{ 397225394Sjchandra uint32_t node,reg; 398225394Sjchandra uint64_t base; 399225394Sjchandra 400225394Sjchandra node = nlm_nodeid(); 401225394Sjchandra reg = PCIE_MSI_STATUS; 402225394Sjchandra 403227783Sjchandra switch (irq) { 404225394Sjchandra case PIC_PCIE_0_IRQ: 405225394Sjchandra base = nlm_pcicfg_base(XLP_IO_PCIE0_OFFSET(node)); 406225394Sjchandra break; 407225394Sjchandra case PIC_PCIE_1_IRQ: 408225394Sjchandra base = nlm_pcicfg_base(XLP_IO_PCIE1_OFFSET(node)); 409225394Sjchandra break; 410225394Sjchandra case PIC_PCIE_2_IRQ: 411225394Sjchandra base = nlm_pcicfg_base(XLP_IO_PCIE2_OFFSET(node)); 412225394Sjchandra break; 413225394Sjchandra case PIC_PCIE_3_IRQ: 414225394Sjchandra base = nlm_pcicfg_base(XLP_IO_PCIE3_OFFSET(node)); 415225394Sjchandra break; 416225394Sjchandra default: 417225394Sjchandra return; 418225394Sjchandra } 419225394Sjchandra 420225394Sjchandra nlm_write_pci_reg(base, reg, 0xFFFFFFFF); 421225394Sjchandra return; 422225394Sjchandra} 423225394Sjchandra 424225394Sjchandrastatic int 425233563Sjchandramips_platform_pcib_setup_intr(device_t dev, device_t child, 426225394Sjchandra struct resource *irq, int flags, driver_filter_t *filt, 427225394Sjchandra driver_intr_t *intr, void *arg, void **cookiep) 428225394Sjchandra{ 429225394Sjchandra int error = 0; 430225394Sjchandra int xlpirq; 431225394Sjchandra 432225394Sjchandra error = rman_activate_resource(irq); 433225394Sjchandra if (error) 434225394Sjchandra return error; 435225394Sjchandra if (rman_get_start(irq) != rman_get_end(irq)) { 436225394Sjchandra device_printf(dev, "Interrupt allocation %lu != %lu\n", 437225394Sjchandra rman_get_start(irq), rman_get_end(irq)); 438225394Sjchandra return (EINVAL); 439225394Sjchandra } 440225394Sjchandra xlpirq = rman_get_start(irq); 441233563Sjchandra if (xlpirq == 0) 442233563Sjchandra return (0); 443225394Sjchandra 444233563Sjchandra if (strcmp(device_get_name(dev), "pcib") != 0) 445225394Sjchandra return (0); 446225394Sjchandra 447279387Sjchandra /* 448225394Sjchandra * temporary hack for MSI, we support just one device per 449225394Sjchandra * link, and assign the link interrupt to the device interrupt 450225394Sjchandra */ 451225394Sjchandra if (xlpirq >= 64) { 452227783Sjchandra int node, val, link; 453227783Sjchandra uint64_t base; 454227783Sjchandra 455225394Sjchandra xlpirq -= 64; 456225394Sjchandra if (xlpirq % 32 != 0) 457225394Sjchandra return (0); 458225394Sjchandra 459225394Sjchandra node = nlm_nodeid(); 460233536Sjchandra link = xlpirq / 32; 461225394Sjchandra base = nlm_pcicfg_base(XLP_IO_PCIE_OFFSET(node,link)); 462225394Sjchandra 463225394Sjchandra /* MSI Interrupt Vector enable at bridge's configuration */ 464225394Sjchandra nlm_write_pci_reg(base, PCIE_MSI_EN, PCIE_MSI_VECTOR_INT_EN); 465225394Sjchandra 466225394Sjchandra val = nlm_read_pci_reg(base, PCIE_INT_EN0); 467225394Sjchandra /* MSI Interrupt enable at bridge's configuration */ 468225394Sjchandra nlm_write_pci_reg(base, PCIE_INT_EN0, 469233536Sjchandra (val | PCIE_MSI_INT_EN)); 470225394Sjchandra 471225394Sjchandra /* legacy interrupt disable at bridge */ 472225394Sjchandra val = nlm_read_pci_reg(base, PCIE_BRIDGE_CMD); 473225394Sjchandra nlm_write_pci_reg(base, PCIE_BRIDGE_CMD, 474233536Sjchandra (val | PCIM_CMD_INTxDIS)); 475225394Sjchandra 476225394Sjchandra /* MSI address update at bridge */ 477225394Sjchandra nlm_write_pci_reg(base, PCIE_BRIDGE_MSI_ADDRL, 478233536Sjchandra MSI_MIPS_ADDR_BASE); 479233536Sjchandra nlm_write_pci_reg(base, PCIE_BRIDGE_MSI_ADDRH, 0); 480225394Sjchandra 481225394Sjchandra val = nlm_read_pci_reg(base, PCIE_BRIDGE_MSI_CAP); 482225394Sjchandra /* MSI capability enable at bridge */ 483279387Sjchandra nlm_write_pci_reg(base, PCIE_BRIDGE_MSI_CAP, 484233536Sjchandra (val | (PCIM_MSICTRL_MSI_ENABLE << 16) | 485233536Sjchandra (PCIM_MSICTRL_MMC_32 << 16))); 486279306Sjchandra xlpirq = PIC_PCIE_IRQ(link); 487279306Sjchandra } 488225394Sjchandra 489279341Sjchandra /* if it is for real PCIe, we need to ack at bridge too */ 490279341Sjchandra if (xlpirq >= PIC_PCIE_IRQ(0) && xlpirq <= PIC_PCIE_IRQ(3)) 491279341Sjchandra xlp_set_bus_ack(xlpirq, bridge_pcie_ack, NULL); 492279341Sjchandra cpu_establish_hardintr(device_get_name(child), filt, intr, arg, 493279341Sjchandra xlpirq, flags, cookiep); 494225394Sjchandra 495225394Sjchandra return (0); 496225394Sjchandra} 497225394Sjchandra 498225394Sjchandrastatic int 499233563Sjchandramips_platform_pcib_teardown_intr(device_t dev, device_t child, 500225394Sjchandra struct resource *irq, void *cookie) 501225394Sjchandra{ 502225394Sjchandra if (strcmp(device_get_name(child), "pci") == 0) { 503225394Sjchandra /* if needed reprogram the pic to clear pcix related entry */ 504225394Sjchandra device_printf(dev, "teardown intr\n"); 505225394Sjchandra } 506225394Sjchandra return (bus_generic_teardown_intr(dev, child, irq, cookie)); 507225394Sjchandra} 508225394Sjchandra 509225394Sjchandrastatic int 510233563Sjchandramips_pcib_route_interrupt(device_t bus, device_t dev, int pin) 511225394Sjchandra{ 512279306Sjchandra int f, d; 513225394Sjchandra 514225394Sjchandra /* 515225394Sjchandra * Validate requested pin number. 516225394Sjchandra */ 517225394Sjchandra if ((pin < 1) || (pin > 4)) 518225394Sjchandra return (255); 519225394Sjchandra 520227783Sjchandra if (pci_get_bus(dev) == 0 && 521227783Sjchandra pci_get_vendor(dev) == PCI_VENDOR_NETLOGIC) { 522227783Sjchandra f = pci_get_function(dev); 523227783Sjchandra d = pci_get_slot(dev) % 8; 524227783Sjchandra 525227783Sjchandra /* 526227783Sjchandra * For PCIe links, return link IRT, for other SoC devices 527227783Sjchandra * get the IRT from its PCIe header 528227783Sjchandra */ 529279306Sjchandra if (d == 1) 530279306Sjchandra return (PIC_PCIE_IRQ(f)); 531279306Sjchandra else 532279306Sjchandra return (255); /* use intline, don't reroute */ 533227783Sjchandra } else { 534227783Sjchandra /* Regular PCI devices */ 535279306Sjchandra return (PIC_PCIE_IRQ(xlp_pcie_link(bus, dev))); 536227783Sjchandra } 537225394Sjchandra} 538225394Sjchandra 539225394Sjchandrastatic device_method_t xlp_pcib_methods[] = { 540225394Sjchandra /* Device interface */ 541225394Sjchandra DEVMETHOD(device_probe, xlp_pcib_probe), 542225394Sjchandra DEVMETHOD(device_attach, xlp_pcib_attach), 543225394Sjchandra 544225394Sjchandra /* Bus interface */ 545225394Sjchandra DEVMETHOD(bus_read_ivar, xlp_pcib_read_ivar), 546225394Sjchandra DEVMETHOD(bus_write_ivar, xlp_pcib_write_ivar), 547279384Sjchandra DEVMETHOD(bus_alloc_resource, bus_generic_alloc_resource), 548279384Sjchandra DEVMETHOD(bus_release_resource, bus_generic_release_resource), 549279384Sjchandra DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), 550279384Sjchandra DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), 551233563Sjchandra DEVMETHOD(bus_setup_intr, mips_platform_pcib_setup_intr), 552233563Sjchandra DEVMETHOD(bus_teardown_intr, mips_platform_pcib_teardown_intr), 553225394Sjchandra 554225394Sjchandra /* pcib interface */ 555225394Sjchandra DEVMETHOD(pcib_maxslots, xlp_pcib_maxslots), 556225394Sjchandra DEVMETHOD(pcib_read_config, xlp_pcib_read_config), 557225394Sjchandra DEVMETHOD(pcib_write_config, xlp_pcib_write_config), 558233563Sjchandra DEVMETHOD(pcib_route_interrupt, mips_pcib_route_interrupt), 559225394Sjchandra 560225394Sjchandra DEVMETHOD(pcib_alloc_msi, xlp_alloc_msi), 561225394Sjchandra DEVMETHOD(pcib_release_msi, xlp_release_msi), 562225394Sjchandra DEVMETHOD(pcib_map_msi, xlp_map_msi), 563225394Sjchandra 564227843Smarius DEVMETHOD_END 565225394Sjchandra}; 566225394Sjchandra 567225394Sjchandrastatic driver_t xlp_pcib_driver = { 568225394Sjchandra "pcib", 569225394Sjchandra xlp_pcib_methods, 570233563Sjchandra 1, /* no softc */ 571225394Sjchandra}; 572225394Sjchandra 573279345Sjchandrastatic devclass_t pcib_devclass; 574279345SjchandraDRIVER_MODULE(xlp_pcib, simplebus, xlp_pcib_driver, pcib_devclass, 0, 0); 575