xlp_pci.c revision 225394
1225394Sjchandra/*- 2225394Sjchandra * Copyright (c) 2003-2009 RMI Corporation 3225394Sjchandra * 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: 8225394Sjchandra * 1. Redistributions of source code must retain the above copyright 9225394Sjchandra * notice, this list of conditions and the following disclaimer. 10225394Sjchandra * 2. Redistributions in binary form must reproduce the above copyright 11225394Sjchandra * notice, this list of conditions and the following disclaimer in the 12225394Sjchandra * documentation and/or other materials provided with the distribution. 13225394Sjchandra * 3. Neither the name of RMI Corporation, nor the names of its contributors, 14225394Sjchandra * may be used to endorse or promote products derived from this software 15225394Sjchandra * without specific prior written permission. 16225394Sjchandra * 17225394Sjchandra * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18225394Sjchandra * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19225394Sjchandra * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20225394Sjchandra * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21225394Sjchandra * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22225394Sjchandra * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23225394Sjchandra * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24225394Sjchandra * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25225394Sjchandra * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26225394Sjchandra * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27225394Sjchandra * SUCH DAMAGE. 28225394Sjchandra * 29225394Sjchandra * NETLOGIC_BSD */ 30225394Sjchandra#include <sys/cdefs.h> 31225394Sjchandra__FBSDID("$FreeBSD: head/sys/mips/nlm/xlp_pci.c 225394 2011-09-05 10:45:29Z jchandra $"); 32225394Sjchandra 33225394Sjchandra#include <sys/param.h> 34225394Sjchandra#include <sys/systm.h> 35225394Sjchandra#include <sys/types.h> 36225394Sjchandra#include <sys/kernel.h> 37225394Sjchandra#include <sys/module.h> 38225394Sjchandra#include <sys/malloc.h> 39225394Sjchandra#include <sys/bus.h> 40225394Sjchandra#include <sys/endian.h> 41225394Sjchandra#include <sys/rman.h> 42225394Sjchandra 43225394Sjchandra#include <vm/vm.h> 44225394Sjchandra#include <vm/vm_param.h> 45225394Sjchandra#include <vm/pmap.h> 46225394Sjchandra 47225394Sjchandra#include <sys/pciio.h> 48225394Sjchandra#include <dev/pci/pcivar.h> 49225394Sjchandra#include <dev/pci/pcireg.h> 50225394Sjchandra#include <dev/uart/uart.h> 51225394Sjchandra#include <dev/uart/uart_bus.h> 52225394Sjchandra#include <dev/uart/uart_cpu.h> 53225394Sjchandra 54225394Sjchandra#include <machine/bus.h> 55225394Sjchandra#include <machine/md_var.h> 56225394Sjchandra#include <machine/intr_machdep.h> 57225394Sjchandra#include <machine/cpuregs.h> 58225394Sjchandra 59225394Sjchandra#include <mips/nlm/hal/haldefs.h> 60225394Sjchandra#include <mips/nlm/interrupt.h> 61225394Sjchandra#include <mips/nlm/hal/iomap.h> 62225394Sjchandra#include <mips/nlm/hal/mips-extns.h> 63225394Sjchandra#include <mips/nlm/hal/pic.h> 64225394Sjchandra#include <mips/nlm/hal/pcibus.h> 65225394Sjchandra#include <mips/nlm/hal/uart.h> 66225394Sjchandra#include <mips/nlm/xlp.h> 67225394Sjchandra 68225394Sjchandra#include "pcib_if.h" 69225394Sjchandra 70225394Sjchandrastruct xlp_pcib_softc { 71225394Sjchandra bus_dma_tag_t sc_pci_dmat; /* PCI DMA tag pointer */ 72225394Sjchandra}; 73225394Sjchandra 74225394Sjchandrastatic devclass_t pcib_devclass; 75225394Sjchandrastatic struct rman irq_rman, port_rman, mem_rman, emul_rman; 76225394Sjchandra 77225394Sjchandrastatic void 78225394Sjchandraxlp_pci_init_resources(void) 79225394Sjchandra{ 80225394Sjchandra 81225394Sjchandra irq_rman.rm_start = 0; 82225394Sjchandra irq_rman.rm_end = 255; 83225394Sjchandra irq_rman.rm_type = RMAN_ARRAY; 84225394Sjchandra irq_rman.rm_descr = "PCI Mapped Interrupts"; 85225394Sjchandra if (rman_init(&irq_rman) 86225394Sjchandra || rman_manage_region(&irq_rman, 0, 255)) 87225394Sjchandra panic("pci_init_resources irq_rman"); 88225394Sjchandra 89225394Sjchandra port_rman.rm_start = 0; 90225394Sjchandra port_rman.rm_end = ~0ul; 91225394Sjchandra port_rman.rm_type = RMAN_ARRAY; 92225394Sjchandra port_rman.rm_descr = "I/O ports"; 93225394Sjchandra if (rman_init(&port_rman) 94225394Sjchandra || rman_manage_region(&port_rman, 0x14000000UL, 0x15ffffffUL)) 95225394Sjchandra panic("pci_init_resources port_rman"); 96225394Sjchandra 97225394Sjchandra mem_rman.rm_start = 0; 98225394Sjchandra mem_rman.rm_end = ~0ul; 99225394Sjchandra mem_rman.rm_type = RMAN_ARRAY; 100225394Sjchandra mem_rman.rm_descr = "I/O memory"; 101225394Sjchandra if (rman_init(&mem_rman) 102225394Sjchandra || rman_manage_region(&mem_rman, 0xd0000000ULL, 0xdfffffffULL)) 103225394Sjchandra panic("pci_init_resources mem_rman"); 104225394Sjchandra 105225394Sjchandra emul_rman.rm_start = 0; 106225394Sjchandra emul_rman.rm_end = ~0ul; 107225394Sjchandra emul_rman.rm_type = RMAN_ARRAY; 108225394Sjchandra emul_rman.rm_descr = "Emulated MEMIO"; 109225394Sjchandra if (rman_init(&emul_rman) 110225394Sjchandra || rman_manage_region(&emul_rman, 0x18000000ULL, 0x18ffffffULL)) 111225394Sjchandra panic("pci_init_resources emul_rman"); 112225394Sjchandra 113225394Sjchandra} 114225394Sjchandra 115225394Sjchandrastatic int 116225394Sjchandraxlp_pcib_probe(device_t dev) 117225394Sjchandra{ 118225394Sjchandra 119225394Sjchandra device_set_desc(dev, "XLP PCI bus"); 120225394Sjchandra 121225394Sjchandra xlp_pci_init_resources(); 122225394Sjchandra return (0); 123225394Sjchandra} 124225394Sjchandra 125225394Sjchandrastatic int 126225394Sjchandraxlp_pcib_read_ivar(device_t dev, device_t child, int which, uintptr_t *result) 127225394Sjchandra{ 128225394Sjchandra 129225394Sjchandra switch (which) { 130225394Sjchandra case PCIB_IVAR_DOMAIN: 131225394Sjchandra *result = 0; 132225394Sjchandra return (0); 133225394Sjchandra case PCIB_IVAR_BUS: 134225394Sjchandra *result = 0; 135225394Sjchandra return (0); 136225394Sjchandra } 137225394Sjchandra return (ENOENT); 138225394Sjchandra} 139225394Sjchandra 140225394Sjchandrastatic int 141225394Sjchandraxlp_pcib_write_ivar(device_t dev, device_t child, int which, uintptr_t result) 142225394Sjchandra{ 143225394Sjchandra switch (which) { 144225394Sjchandra case PCIB_IVAR_DOMAIN: 145225394Sjchandra return (EINVAL); 146225394Sjchandra case PCIB_IVAR_BUS: 147225394Sjchandra return (EINVAL); 148225394Sjchandra } 149225394Sjchandra return (ENOENT); 150225394Sjchandra} 151225394Sjchandra 152225394Sjchandrastatic int 153225394Sjchandraxlp_pcib_maxslots(device_t dev) 154225394Sjchandra{ 155225394Sjchandra 156225394Sjchandra return (PCI_SLOTMAX); 157225394Sjchandra} 158225394Sjchandra 159225394Sjchandrastatic u_int32_t 160225394Sjchandraxlp_pcib_read_config(device_t dev, u_int b, u_int s, u_int f, 161225394Sjchandra u_int reg, int width) 162225394Sjchandra{ 163225394Sjchandra uint32_t data = 0; 164225394Sjchandra uint64_t cfgaddr; 165225394Sjchandra int regindex = reg/sizeof(uint32_t); 166225394Sjchandra 167225394Sjchandra cfgaddr = nlm_pcicfg_base(XLP_HDR_OFFSET(0, b, s, f)); 168225394Sjchandra if ((width == 2) && (reg & 1)) 169225394Sjchandra return 0xFFFFFFFF; 170225394Sjchandra else if ((width == 4) && (reg & 3)) 171225394Sjchandra return 0xFFFFFFFF; 172225394Sjchandra 173225394Sjchandra data = nlm_read_pci_reg(cfgaddr, regindex); 174225394Sjchandra 175225394Sjchandra /* 176225394Sjchandra * Fix up read data in some SoC devices 177225394Sjchandra * to emulate complete PCIe header 178225394Sjchandra */ 179225394Sjchandra if (b == 0) { 180225394Sjchandra int dev = s % 8; 181225394Sjchandra 182225394Sjchandra /* Fake intpin on config read for UART/I2C, USB, SD/Flash */ 183225394Sjchandra if (regindex == 0xf && 184225394Sjchandra (dev == 6 || dev == 2 || dev == 7)) 185225394Sjchandra data |= 0x1 << 8; /* Fake int pin */ 186225394Sjchandra } 187225394Sjchandra 188225394Sjchandra if (width == 1) 189225394Sjchandra return ((data >> ((reg & 3) << 3)) & 0xff); 190225394Sjchandra else if (width == 2) 191225394Sjchandra return ((data >> ((reg & 3) << 3)) & 0xffff); 192225394Sjchandra else 193225394Sjchandra return (data); 194225394Sjchandra} 195225394Sjchandra 196225394Sjchandrastatic void 197225394Sjchandraxlp_pcib_write_config(device_t dev, u_int b, u_int s, u_int f, 198225394Sjchandra u_int reg, u_int32_t val, int width) 199225394Sjchandra{ 200225394Sjchandra uint64_t cfgaddr; 201225394Sjchandra uint32_t data = 0; 202225394Sjchandra int regindex = reg / sizeof(uint32_t); 203225394Sjchandra 204225394Sjchandra cfgaddr = nlm_pcicfg_base(XLP_HDR_OFFSET(0, b, s, f)); 205225394Sjchandra if ((width == 2) && (reg & 1)) 206225394Sjchandra return; 207225394Sjchandra else if ((width == 4) && (reg & 3)) 208225394Sjchandra return; 209225394Sjchandra 210225394Sjchandra if (width == 1) { 211225394Sjchandra data = nlm_read_pci_reg(cfgaddr, regindex); 212225394Sjchandra data = (data & ~(0xff << ((reg & 3) << 3))) | 213225394Sjchandra (val << ((reg & 3) << 3)); 214225394Sjchandra } else if (width == 2) { 215225394Sjchandra data = nlm_read_pci_reg(cfgaddr, regindex); 216225394Sjchandra data = (data & ~(0xffff << ((reg & 3) << 3))) | 217225394Sjchandra (val << ((reg & 3) << 3)); 218225394Sjchandra } else { 219225394Sjchandra data = val; 220225394Sjchandra } 221225394Sjchandra 222225394Sjchandra nlm_write_pci_reg(cfgaddr, regindex, data); 223225394Sjchandra 224225394Sjchandra return; 225225394Sjchandra} 226225394Sjchandra 227225394Sjchandrastatic int 228225394Sjchandraxlp_pcib_attach(device_t dev) 229225394Sjchandra{ 230225394Sjchandra struct xlp_pcib_softc *sc; 231225394Sjchandra sc = device_get_softc(dev); 232225394Sjchandra 233225394Sjchandra device_add_child(dev, "pci", 0); 234225394Sjchandra bus_generic_attach(dev); 235225394Sjchandra 236225394Sjchandra return (0); 237225394Sjchandra} 238225394Sjchandra 239225394Sjchandrastatic void 240225394Sjchandraxlp_pcib_identify(driver_t * driver, device_t parent) 241225394Sjchandra{ 242225394Sjchandra 243225394Sjchandra BUS_ADD_CHILD(parent, 0, "pcib", 0); 244225394Sjchandra} 245225394Sjchandra 246225394Sjchandra/* 247225394Sjchandra * XLS PCIe can have upto 4 links, and each link has its on IRQ 248225394Sjchandra * Find the link on which the device is on 249225394Sjchandra */ 250225394Sjchandrastatic int 251225394Sjchandraxlp_pcie_link(device_t pcib, device_t dev) 252225394Sjchandra{ 253225394Sjchandra device_t parent, tmp; 254225394Sjchandra 255225394Sjchandra /* find the lane on which the slot is connected to */ 256225394Sjchandra printf("xlp_pcie_link : bus %s dev %s\n", device_get_nameunit(pcib), 257225394Sjchandra device_get_nameunit(dev)); 258225394Sjchandra tmp = dev; 259225394Sjchandra while (1) { 260225394Sjchandra parent = device_get_parent(tmp); 261225394Sjchandra if (parent == NULL || parent == pcib) { 262225394Sjchandra device_printf(dev, "Cannot find parent bus\n"); 263225394Sjchandra return (-1); 264225394Sjchandra } 265225394Sjchandra if (strcmp(device_get_nameunit(parent), "pci0") == 0) 266225394Sjchandra break; 267225394Sjchandra tmp = parent; 268225394Sjchandra } 269225394Sjchandra return (pci_get_function(tmp)); 270225394Sjchandra} 271225394Sjchandra 272225394Sjchandra/* 273225394Sjchandra * Find the IRQ for the link, each link has a different interrupt 274225394Sjchandra * at the XLP pic 275225394Sjchandra */ 276225394Sjchandrastatic int 277225394Sjchandraxlp_pcie_link_irt(int link) 278225394Sjchandra{ 279225394Sjchandra 280225394Sjchandra if( (link < 0) || (link > 3)) 281225394Sjchandra return (-1); 282225394Sjchandra 283225394Sjchandra return PIC_IRT_PCIE_LINK_INDEX(link); 284225394Sjchandra} 285225394Sjchandra 286225394Sjchandrastatic int 287225394Sjchandraxlp_alloc_msi(device_t pcib, device_t dev, int count, int maxcount, int *irqs) 288225394Sjchandra{ 289225394Sjchandra int i, link; 290225394Sjchandra 291225394Sjchandra /* 292225394Sjchandra * Each link has 32 MSIs that can be allocated, but for now 293225394Sjchandra * we only support one device per link. 294225394Sjchandra * msi_alloc() equivalent is needed when we start supporting 295225394Sjchandra * bridges on the PCIe link. 296225394Sjchandra */ 297225394Sjchandra link = xlp_pcie_link(pcib, dev); 298225394Sjchandra if (link == -1) 299225394Sjchandra return (ENXIO); 300225394Sjchandra 301225394Sjchandra /* 302225394Sjchandra * encode the irq so that we know it is a MSI interrupt when we 303225394Sjchandra * setup interrupts 304225394Sjchandra */ 305225394Sjchandra for (i = 0; i < count; i++) 306225394Sjchandra irqs[i] = 64 + link * 32 + i; 307225394Sjchandra 308225394Sjchandra return (0); 309225394Sjchandra} 310225394Sjchandra 311225394Sjchandrastatic int 312225394Sjchandraxlp_release_msi(device_t pcib, device_t dev, int count, int *irqs) 313225394Sjchandra{ 314225394Sjchandra device_printf(dev, "%s: msi release %d\n", device_get_nameunit(pcib), 315225394Sjchandra count); 316225394Sjchandra return (0); 317225394Sjchandra} 318225394Sjchandra 319225394Sjchandrastatic int 320225394Sjchandraxlp_map_msi(device_t pcib, device_t dev, int irq, uint64_t *addr, 321225394Sjchandra uint32_t *data) 322225394Sjchandra{ 323225394Sjchandra int msi, irt; 324225394Sjchandra 325225394Sjchandra if (irq >= 64) { 326225394Sjchandra msi = irq - 64; 327225394Sjchandra *addr = MIPS_MSI_ADDR(0); 328225394Sjchandra 329225394Sjchandra irt = xlp_pcie_link_irt(msi/32); 330225394Sjchandra if (irt != -1) 331225394Sjchandra *data = MIPS_MSI_DATA(xlp_irt_to_irq(irt)); 332225394Sjchandra return (0); 333225394Sjchandra } else { 334225394Sjchandra device_printf(dev, "%s: map_msi for irq %d - ignored", 335225394Sjchandra device_get_nameunit(pcib), irq); 336225394Sjchandra return (ENXIO); 337225394Sjchandra } 338225394Sjchandra} 339225394Sjchandra 340225394Sjchandrastatic void 341225394Sjchandrabridge_pcie_ack(int irq) 342225394Sjchandra{ 343225394Sjchandra uint32_t node,reg; 344225394Sjchandra uint64_t base; 345225394Sjchandra 346225394Sjchandra node = nlm_nodeid(); 347225394Sjchandra reg = PCIE_MSI_STATUS; 348225394Sjchandra 349225394Sjchandra switch(irq) { 350225394Sjchandra case PIC_PCIE_0_IRQ: 351225394Sjchandra base = nlm_pcicfg_base(XLP_IO_PCIE0_OFFSET(node)); 352225394Sjchandra break; 353225394Sjchandra case PIC_PCIE_1_IRQ: 354225394Sjchandra base = nlm_pcicfg_base(XLP_IO_PCIE1_OFFSET(node)); 355225394Sjchandra break; 356225394Sjchandra case PIC_PCIE_2_IRQ: 357225394Sjchandra base = nlm_pcicfg_base(XLP_IO_PCIE2_OFFSET(node)); 358225394Sjchandra break; 359225394Sjchandra case PIC_PCIE_3_IRQ: 360225394Sjchandra base = nlm_pcicfg_base(XLP_IO_PCIE3_OFFSET(node)); 361225394Sjchandra break; 362225394Sjchandra default: 363225394Sjchandra return; 364225394Sjchandra } 365225394Sjchandra 366225394Sjchandra nlm_write_pci_reg(base, reg, 0xFFFFFFFF); 367225394Sjchandra 368225394Sjchandra return; 369225394Sjchandra} 370225394Sjchandra 371225394Sjchandrastatic int 372225394Sjchandramips_platform_pci_setup_intr(device_t dev, device_t child, 373225394Sjchandra struct resource *irq, int flags, driver_filter_t *filt, 374225394Sjchandra driver_intr_t *intr, void *arg, void **cookiep) 375225394Sjchandra{ 376225394Sjchandra int error = 0; 377225394Sjchandra int xlpirq; 378225394Sjchandra int node,base,val,link; 379225394Sjchandra void *extra_ack; 380225394Sjchandra 381225394Sjchandra error = rman_activate_resource(irq); 382225394Sjchandra if (error) 383225394Sjchandra return error; 384225394Sjchandra if (rman_get_start(irq) != rman_get_end(irq)) { 385225394Sjchandra device_printf(dev, "Interrupt allocation %lu != %lu\n", 386225394Sjchandra rman_get_start(irq), rman_get_end(irq)); 387225394Sjchandra return (EINVAL); 388225394Sjchandra } 389225394Sjchandra xlpirq = rman_get_start(irq); 390225394Sjchandra device_printf(dev, "setup intr %d\n", xlpirq); 391225394Sjchandra 392225394Sjchandra if (strcmp(device_get_name(dev), "pcib") != 0) { 393225394Sjchandra device_printf(dev, "ret 0 on dev\n"); 394225394Sjchandra return (0); 395225394Sjchandra } 396225394Sjchandra 397225394Sjchandra /* 398225394Sjchandra * temporary hack for MSI, we support just one device per 399225394Sjchandra * link, and assign the link interrupt to the device interrupt 400225394Sjchandra */ 401225394Sjchandra if (xlpirq >= 64) { 402225394Sjchandra xlpirq -= 64; 403225394Sjchandra if (xlpirq % 32 != 0) 404225394Sjchandra return (0); 405225394Sjchandra 406225394Sjchandra node = nlm_nodeid(); 407225394Sjchandra link = (xlpirq / 32); 408225394Sjchandra base = nlm_pcicfg_base(XLP_IO_PCIE_OFFSET(node,link)); 409225394Sjchandra 410225394Sjchandra /* MSI Interrupt Vector enable at bridge's configuration */ 411225394Sjchandra nlm_write_pci_reg(base, PCIE_MSI_EN, PCIE_MSI_VECTOR_INT_EN); 412225394Sjchandra 413225394Sjchandra val = nlm_read_pci_reg(base, PCIE_INT_EN0); 414225394Sjchandra /* MSI Interrupt enable at bridge's configuration */ 415225394Sjchandra nlm_write_pci_reg(base, PCIE_INT_EN0, 416225394Sjchandra (val | PCIE_MSI_INT_EN)); 417225394Sjchandra 418225394Sjchandra /* legacy interrupt disable at bridge */ 419225394Sjchandra val = nlm_read_pci_reg(base, PCIE_BRIDGE_CMD); 420225394Sjchandra nlm_write_pci_reg(base, PCIE_BRIDGE_CMD, 421225394Sjchandra (val | PCIM_CMD_INTxDIS)); 422225394Sjchandra 423225394Sjchandra /* MSI address update at bridge */ 424225394Sjchandra val = nlm_read_pci_reg(base, PCIE_BRIDGE_MSI_ADDRL); 425225394Sjchandra nlm_write_pci_reg(base, PCIE_BRIDGE_MSI_ADDRL, 426225394Sjchandra (val | MSI_MIPS_ADDR_BASE)); 427225394Sjchandra 428225394Sjchandra val = nlm_read_pci_reg(base, PCIE_BRIDGE_MSI_CAP); 429225394Sjchandra /* MSI capability enable at bridge */ 430225394Sjchandra nlm_write_pci_reg(base, PCIE_BRIDGE_MSI_CAP, 431225394Sjchandra (val | 432225394Sjchandra (PCIM_MSICTRL_MSI_ENABLE << 16) | 433225394Sjchandra (PCIM_MSICTRL_MMC_32 << 16))); 434225394Sjchandra 435225394Sjchandra xlpirq = xlp_pcie_link_irt(xlpirq / 32); 436225394Sjchandra if (xlpirq == -1) 437225394Sjchandra return (EINVAL); 438225394Sjchandra xlpirq = xlp_irt_to_irq(xlpirq); 439225394Sjchandra } 440225394Sjchandra /* Set all irqs to CPU 0 for now */ 441225394Sjchandra nlm_pic_write_irt_direct(xlp_pic_base, xlp_irq_to_irt(xlpirq), 1, 0, 442225394Sjchandra PIC_LOCAL_SCHEDULING, xlpirq, 0); 443225394Sjchandra extra_ack = NULL; 444225394Sjchandra if (xlpirq >= PIC_PCIE_0_IRQ && 445225394Sjchandra xlpirq <= PIC_PCIE_3_IRQ) 446225394Sjchandra extra_ack = bridge_pcie_ack; 447225394Sjchandra xlp_establish_intr(device_get_name(child), filt, 448225394Sjchandra intr, arg, xlpirq, flags, cookiep, extra_ack); 449225394Sjchandra 450225394Sjchandra return (0); 451225394Sjchandra} 452225394Sjchandra 453225394Sjchandrastatic int 454225394Sjchandramips_platform_pci_teardown_intr(device_t dev, device_t child, 455225394Sjchandra struct resource *irq, void *cookie) 456225394Sjchandra{ 457225394Sjchandra if (strcmp(device_get_name(child), "pci") == 0) { 458225394Sjchandra /* if needed reprogram the pic to clear pcix related entry */ 459225394Sjchandra device_printf(dev, "teardown intr\n"); 460225394Sjchandra } 461225394Sjchandra return (bus_generic_teardown_intr(dev, child, irq, cookie)); 462225394Sjchandra} 463225394Sjchandra 464225394Sjchandrastatic void 465225394Sjchandraassign_soc_resource(device_t child, int type, u_long *startp, u_long *endp, 466225394Sjchandra u_long *countp, struct rman **rm, bus_space_tag_t *bst, vm_offset_t *va) 467225394Sjchandra{ 468225394Sjchandra int devid = pci_get_device(child); 469225394Sjchandra int inst = pci_get_function(child); 470225394Sjchandra int node = pci_get_slot(child) / 8; 471225394Sjchandra 472225394Sjchandra *rm = NULL; 473225394Sjchandra *va = 0; 474225394Sjchandra *bst = 0; 475225394Sjchandra switch (devid) { 476225394Sjchandra case PCI_DEVICE_ID_NLM_UART: 477225394Sjchandra switch (type) { 478225394Sjchandra case SYS_RES_IRQ: 479225394Sjchandra *startp = *endp = PIC_UART_0_IRQ + inst; 480225394Sjchandra *countp = 1; 481225394Sjchandra break; 482225394Sjchandra case SYS_RES_MEMORY: 483225394Sjchandra *va = nlm_get_uart_regbase(node, inst); 484225394Sjchandra *startp = MIPS_KSEG1_TO_PHYS(va); 485225394Sjchandra *countp = 0x100; 486225394Sjchandra *rm = &emul_rman; 487225394Sjchandra *bst = uart_bus_space_mem; 488225394Sjchandra break; 489225394Sjchandra }; 490225394Sjchandra break; 491225394Sjchandra 492225394Sjchandra case PCI_DEVICE_ID_NLM_EHCI: 493225394Sjchandra if (type == SYS_RES_IRQ) { 494225394Sjchandra if (inst == 0) 495225394Sjchandra *startp = *endp = PIC_EHCI_0_IRQ; 496225394Sjchandra else if (inst == 3) 497225394Sjchandra *startp = *endp = PIC_EHCI_1_IRQ; 498225394Sjchandra else 499225394Sjchandra device_printf(child, "bad instance %d\n", inst); 500225394Sjchandra 501225394Sjchandra *countp = 1; 502225394Sjchandra } 503225394Sjchandra break; 504225394Sjchandra } 505225394Sjchandra 506225394Sjchandra /* default to rmi_bus_space for SoC resources */ 507225394Sjchandra if (type == SYS_RES_MEMORY && *bst == 0) 508225394Sjchandra *bst = rmi_bus_space; 509225394Sjchandra} 510225394Sjchandra 511225394Sjchandrastatic struct resource * 512225394Sjchandraxlp_pci_alloc_resource(device_t bus, device_t child, int type, int *rid, 513225394Sjchandra u_long start, u_long end, u_long count, u_int flags) 514225394Sjchandra{ 515225394Sjchandra struct rman *rm = NULL; 516225394Sjchandra struct resource *rv; 517225394Sjchandra vm_offset_t va = 0; 518225394Sjchandra int needactivate = flags & RF_ACTIVE; 519225394Sjchandra bus_space_tag_t bst = 0; 520225394Sjchandra 521225394Sjchandra /* 522225394Sjchandra * For SoC PCI devices, we have to assign resources correctly 523225394Sjchandra * since the IRQ and MEM resources depend on the block. 524225394Sjchandra * If the address is not from BAR0, then we use emul_rman 525225394Sjchandra */ 526225394Sjchandra if (pci_get_bus(child) == 0 && 527225394Sjchandra pci_get_vendor(child) == PCI_VENDOR_NETLOGIC) 528225394Sjchandra assign_soc_resource(child, type, &start, &end, 529225394Sjchandra &count, &rm, &bst, &va); 530225394Sjchandra if (rm == NULL) { 531225394Sjchandra switch (type) { 532225394Sjchandra case SYS_RES_IRQ: 533225394Sjchandra rm = &irq_rman; 534225394Sjchandra break; 535225394Sjchandra 536225394Sjchandra case SYS_RES_IOPORT: 537225394Sjchandra rm = &port_rman; 538225394Sjchandra break; 539225394Sjchandra 540225394Sjchandra case SYS_RES_MEMORY: 541225394Sjchandra rm = &mem_rman; 542225394Sjchandra break; 543225394Sjchandra 544225394Sjchandra default: 545225394Sjchandra return (0); 546225394Sjchandra } 547225394Sjchandra } 548225394Sjchandra 549225394Sjchandra rv = rman_reserve_resource(rm, start, end, count, flags, child); 550225394Sjchandra if (rv == 0) 551225394Sjchandra return (0); 552225394Sjchandra 553225394Sjchandra rman_set_rid(rv, *rid); 554225394Sjchandra 555225394Sjchandra if (type == SYS_RES_MEMORY || type == SYS_RES_IOPORT) { 556225394Sjchandra if (va == 0) 557225394Sjchandra va = (vm_offset_t)pmap_mapdev(start, count); 558225394Sjchandra if (bst == 0) 559225394Sjchandra bst = rmi_pci_bus_space; 560225394Sjchandra 561225394Sjchandra rman_set_bushandle(rv, va); 562225394Sjchandra rman_set_virtual(rv, (void *)va); 563225394Sjchandra rman_set_bustag(rv, bst); 564225394Sjchandra } 565225394Sjchandra 566225394Sjchandra if (needactivate) { 567225394Sjchandra if (bus_activate_resource(child, type, *rid, rv)) { 568225394Sjchandra rman_release_resource(rv); 569225394Sjchandra return (NULL); 570225394Sjchandra } 571225394Sjchandra } 572225394Sjchandra 573225394Sjchandra return (rv); 574225394Sjchandra} 575225394Sjchandra 576225394Sjchandrastatic int 577225394Sjchandraxlp_pci_release_resource(device_t bus, device_t child, int type, int rid, 578225394Sjchandra struct resource *r) 579225394Sjchandra{ 580225394Sjchandra 581225394Sjchandra return (rman_release_resource(r)); 582225394Sjchandra} 583225394Sjchandra 584225394Sjchandrastatic bus_dma_tag_t 585225394Sjchandraxlp_pci_get_dma_tag(device_t bus, device_t child) 586225394Sjchandra{ 587225394Sjchandra struct xlp_pcib_softc *sc; 588225394Sjchandra 589225394Sjchandra sc = device_get_softc(bus); 590225394Sjchandra return (sc->sc_pci_dmat); 591225394Sjchandra} 592225394Sjchandra 593225394Sjchandrastatic int 594225394Sjchandraxlp_pci_activate_resource(device_t bus, device_t child, int type, int rid, 595225394Sjchandra struct resource *r) 596225394Sjchandra{ 597225394Sjchandra 598225394Sjchandra return (rman_activate_resource(r)); 599225394Sjchandra} 600225394Sjchandra 601225394Sjchandrastatic int 602225394Sjchandraxlp_pci_deactivate_resource(device_t bus, device_t child, int type, int rid, 603225394Sjchandra struct resource *r) 604225394Sjchandra{ 605225394Sjchandra 606225394Sjchandra return (rman_deactivate_resource(r)); 607225394Sjchandra} 608225394Sjchandra 609225394Sjchandrastatic int 610225394Sjchandramips_pci_route_interrupt(device_t bus, device_t dev, int pin) 611225394Sjchandra{ 612225394Sjchandra int irt, link; 613225394Sjchandra 614225394Sjchandra /* 615225394Sjchandra * Validate requested pin number. 616225394Sjchandra */ 617225394Sjchandra device_printf(bus, "route %s %d", device_get_nameunit(dev), pin); 618225394Sjchandra if ((pin < 1) || (pin > 4)) 619225394Sjchandra return (255); 620225394Sjchandra 621225394Sjchandra link = xlp_pcie_link(bus, dev); 622225394Sjchandra irt = xlp_pcie_link_irt(link); 623225394Sjchandra if (irt != -1) 624225394Sjchandra return (xlp_irt_to_irq(irt)); 625225394Sjchandra 626225394Sjchandra return (255); 627225394Sjchandra} 628225394Sjchandra 629225394Sjchandrastatic device_method_t xlp_pcib_methods[] = { 630225394Sjchandra /* Device interface */ 631225394Sjchandra DEVMETHOD(device_identify, xlp_pcib_identify), 632225394Sjchandra DEVMETHOD(device_probe, xlp_pcib_probe), 633225394Sjchandra DEVMETHOD(device_attach, xlp_pcib_attach), 634225394Sjchandra 635225394Sjchandra /* Bus interface */ 636225394Sjchandra DEVMETHOD(bus_print_child, bus_generic_print_child), 637225394Sjchandra DEVMETHOD(bus_read_ivar, xlp_pcib_read_ivar), 638225394Sjchandra DEVMETHOD(bus_write_ivar, xlp_pcib_write_ivar), 639225394Sjchandra DEVMETHOD(bus_alloc_resource, xlp_pci_alloc_resource), 640225394Sjchandra DEVMETHOD(bus_release_resource, xlp_pci_release_resource), 641225394Sjchandra DEVMETHOD(bus_get_dma_tag, xlp_pci_get_dma_tag), 642225394Sjchandra DEVMETHOD(bus_activate_resource, xlp_pci_activate_resource), 643225394Sjchandra DEVMETHOD(bus_deactivate_resource, xlp_pci_deactivate_resource), 644225394Sjchandra DEVMETHOD(bus_setup_intr, mips_platform_pci_setup_intr), 645225394Sjchandra DEVMETHOD(bus_teardown_intr, mips_platform_pci_teardown_intr), 646225394Sjchandra 647225394Sjchandra /* pcib interface */ 648225394Sjchandra DEVMETHOD(pcib_maxslots, xlp_pcib_maxslots), 649225394Sjchandra DEVMETHOD(pcib_read_config, xlp_pcib_read_config), 650225394Sjchandra DEVMETHOD(pcib_write_config, xlp_pcib_write_config), 651225394Sjchandra DEVMETHOD(pcib_route_interrupt, mips_pci_route_interrupt), 652225394Sjchandra 653225394Sjchandra DEVMETHOD(pcib_alloc_msi, xlp_alloc_msi), 654225394Sjchandra DEVMETHOD(pcib_release_msi, xlp_release_msi), 655225394Sjchandra DEVMETHOD(pcib_map_msi, xlp_map_msi), 656225394Sjchandra 657225394Sjchandra {0, 0} 658225394Sjchandra}; 659225394Sjchandra 660225394Sjchandrastatic driver_t xlp_pcib_driver = { 661225394Sjchandra "pcib", 662225394Sjchandra xlp_pcib_methods, 663225394Sjchandra sizeof(struct xlp_pcib_softc), 664225394Sjchandra}; 665225394Sjchandra 666225394SjchandraDRIVER_MODULE(pcib, nexus, xlp_pcib_driver, pcib_devclass, 0, 0); 667