1210311Sjmallett/*- 2217254Sjmallett * Copyright (c) 2010-2011 Juli Mallett <jmallett@FreeBSD.org> 3210311Sjmallett * All rights reserved. 4210311Sjmallett * 5210311Sjmallett * Redistribution and use in source and binary forms, with or without 6210311Sjmallett * modification, are permitted provided that the following conditions 7210311Sjmallett * are met: 8210311Sjmallett * 1. Redistributions of source code must retain the above copyright 9210311Sjmallett * notice, this list of conditions and the following disclaimer. 10210311Sjmallett * 2. Redistributions in binary form must reproduce the above copyright 11210311Sjmallett * notice, this list of conditions and the following disclaimer in the 12210311Sjmallett * documentation and/or other materials provided with the distribution. 13210311Sjmallett * 14210311Sjmallett * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15210311Sjmallett * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16210311Sjmallett * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17210311Sjmallett * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18210311Sjmallett * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19210311Sjmallett * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20210311Sjmallett * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21210311Sjmallett * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22210311Sjmallett * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23210311Sjmallett * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24210311Sjmallett * SUCH DAMAGE. 25210311Sjmallett * 26210311Sjmallett * $FreeBSD$ 27210311Sjmallett */ 28210311Sjmallett 29210311Sjmallett#include <sys/cdefs.h> 30210311Sjmallett__FBSDID("$FreeBSD$"); 31210311Sjmallett 32210311Sjmallett#include <sys/param.h> 33210311Sjmallett#include <sys/systm.h> 34210311Sjmallett 35210311Sjmallett#include <sys/bus.h> 36210311Sjmallett#include <sys/endian.h> 37210311Sjmallett#include <sys/interrupt.h> 38210311Sjmallett#include <sys/malloc.h> 39210311Sjmallett#include <sys/kernel.h> 40210311Sjmallett#include <sys/module.h> 41210311Sjmallett#include <sys/rman.h> 42210311Sjmallett 43210311Sjmallett#include <vm/vm.h> 44210311Sjmallett#include <vm/pmap.h> 45210311Sjmallett#include <vm/vm_extern.h> 46210311Sjmallett 47210311Sjmallett#include <machine/bus.h> 48210311Sjmallett#include <machine/cpu.h> 49210311Sjmallett#include <machine/pmap.h> 50210311Sjmallett 51210311Sjmallett#include <contrib/octeon-sdk/cvmx.h> 52210311Sjmallett#include <contrib/octeon-sdk/cvmx-interrupt.h> 53217254Sjmallett#include <contrib/octeon-sdk/cvmx-pcie.h> 54210311Sjmallett 55210311Sjmallett#include <dev/pci/pcireg.h> 56210311Sjmallett#include <dev/pci/pcivar.h> 57210311Sjmallett 58210311Sjmallett#include <dev/pci/pcib_private.h> 59210311Sjmallett 60210311Sjmallett#include <mips/cavium/octopcireg.h> 61210311Sjmallett#include <mips/cavium/octopcivar.h> 62210311Sjmallett 63210311Sjmallett#include "pcib_if.h" 64210311Sjmallett 65213089Sjmallett#define NPI_WRITE(addr, value) cvmx_write64_uint32((addr) ^ 4, (value)) 66213089Sjmallett#define NPI_READ(addr) cvmx_read64_uint32((addr) ^ 4) 67213089Sjmallett 68210311Sjmallettstruct octopci_softc { 69210311Sjmallett device_t sc_dev; 70210311Sjmallett 71210311Sjmallett unsigned sc_domain; 72210311Sjmallett unsigned sc_bus; 73210311Sjmallett 74217254Sjmallett bus_addr_t sc_io_base; 75213089Sjmallett unsigned sc_io_next; 76210311Sjmallett struct rman sc_io; 77213089Sjmallett 78217254Sjmallett bus_addr_t sc_mem1_base; 79213089Sjmallett unsigned sc_mem1_next; 80210311Sjmallett struct rman sc_mem1; 81210311Sjmallett}; 82210311Sjmallett 83210311Sjmallettstatic void octopci_identify(driver_t *, device_t); 84210311Sjmallettstatic int octopci_probe(device_t); 85210311Sjmallettstatic int octopci_attach(device_t); 86210311Sjmallettstatic int octopci_read_ivar(device_t, device_t, int, 87210311Sjmallett uintptr_t *); 88210311Sjmallettstatic struct resource *octopci_alloc_resource(device_t, device_t, int, int *, 89210311Sjmallett u_long, u_long, u_long, u_int); 90210311Sjmallettstatic int octopci_activate_resource(device_t, device_t, int, int, 91210311Sjmallett struct resource *); 92210311Sjmallettstatic int octopci_maxslots(device_t); 93210311Sjmallettstatic uint32_t octopci_read_config(device_t, u_int, u_int, u_int, u_int, int); 94210311Sjmallettstatic void octopci_write_config(device_t, u_int, u_int, u_int, u_int, 95210311Sjmallett uint32_t, int); 96210311Sjmallettstatic int octopci_route_interrupt(device_t, device_t, int); 97210311Sjmallett 98217254Sjmallettstatic unsigned octopci_init_bar(device_t, unsigned, unsigned, unsigned, unsigned, uint8_t *); 99213089Sjmallettstatic unsigned octopci_init_device(device_t, unsigned, unsigned, unsigned, unsigned); 100213089Sjmallettstatic unsigned octopci_init_bus(device_t, unsigned); 101217254Sjmallettstatic void octopci_init_pci(device_t); 102210311Sjmallettstatic uint64_t octopci_cs_addr(unsigned, unsigned, unsigned, unsigned); 103210311Sjmallett 104210311Sjmallettstatic void 105210311Sjmallettoctopci_identify(driver_t *drv, device_t parent) 106210311Sjmallett{ 107217254Sjmallett /* XXX Check sysinfo flag. */ 108217254Sjmallett 109210311Sjmallett BUS_ADD_CHILD(parent, 0, "pcib", 0); 110217254Sjmallett if (octeon_has_feature(OCTEON_FEATURE_PCIE)) 111217254Sjmallett BUS_ADD_CHILD(parent, 0, "pcib", 1); 112210311Sjmallett} 113210311Sjmallett 114210311Sjmallettstatic int 115210311Sjmallettoctopci_probe(device_t dev) 116210311Sjmallett{ 117217254Sjmallett if (octeon_has_feature(OCTEON_FEATURE_PCIE)) { 118217254Sjmallett device_set_desc(dev, "Cavium Octeon PCIe bridge"); 119217254Sjmallett return (0); 120217254Sjmallett } 121217254Sjmallett 122210311Sjmallett if (device_get_unit(dev) != 0) 123210311Sjmallett return (ENXIO); 124217254Sjmallett 125210311Sjmallett device_set_desc(dev, "Cavium Octeon PCI bridge"); 126210311Sjmallett return (0); 127210311Sjmallett} 128210311Sjmallett 129210311Sjmallettstatic int 130210311Sjmallettoctopci_attach(device_t dev) 131210311Sjmallett{ 132210311Sjmallett struct octopci_softc *sc; 133213089Sjmallett unsigned subbus; 134210311Sjmallett int error; 135210311Sjmallett 136217254Sjmallett sc = device_get_softc(dev); 137217254Sjmallett sc->sc_dev = dev; 138210311Sjmallett 139217254Sjmallett if (octeon_has_feature(OCTEON_FEATURE_PCIE)) { 140217254Sjmallett sc->sc_domain = device_get_unit(dev); 141213089Sjmallett 142217254Sjmallett error = cvmx_pcie_rc_initialize(sc->sc_domain); 143217254Sjmallett if (error != 0) { 144217254Sjmallett device_printf(dev, "Failed to put PCIe bus in host mode.\n"); 145217254Sjmallett return (ENXIO); 146217254Sjmallett } 147213089Sjmallett 148217254Sjmallett /* 149217254Sjmallett * In RC mode, the Simple Executive programs the first bus to 150217254Sjmallett * be numbered as bus 1, because some IDT bridges used in 151217254Sjmallett * Octeon systems object to being attached to bus 0. 152217254Sjmallett */ 153217254Sjmallett sc->sc_bus = 1; 154213089Sjmallett 155217254Sjmallett sc->sc_io_base = CVMX_ADD_IO_SEG(cvmx_pcie_get_io_base_address(sc->sc_domain)); 156217254Sjmallett sc->sc_io.rm_descr = "Cavium Octeon PCIe I/O Ports"; 157213089Sjmallett 158217254Sjmallett sc->sc_mem1_base = CVMX_ADD_IO_SEG(cvmx_pcie_get_mem_base_address(sc->sc_domain)); 159217254Sjmallett sc->sc_mem1.rm_descr = "Cavium Octeon PCIe Memory"; 160213089Sjmallett } else { 161217254Sjmallett octopci_init_pci(dev); 162213089Sjmallett 163217254Sjmallett sc->sc_domain = 0; 164217254Sjmallett sc->sc_bus = 0; 165213089Sjmallett 166217254Sjmallett sc->sc_io_base = CVMX_ADDR_DID(CVMX_FULL_DID(CVMX_OCT_DID_PCI, CVMX_OCT_SUBDID_PCI_IO)); 167217254Sjmallett sc->sc_io.rm_descr = "Cavium Octeon PCI I/O Ports"; 168213089Sjmallett 169217254Sjmallett sc->sc_mem1_base = CVMX_ADDR_DID(CVMX_FULL_DID(CVMX_OCT_DID_PCI, CVMX_OCT_SUBDID_PCI_MEM1)); 170217254Sjmallett sc->sc_mem1.rm_descr = "Cavium Octeon PCI Memory"; 171213089Sjmallett } 172213089Sjmallett 173210311Sjmallett sc->sc_io.rm_type = RMAN_ARRAY; 174210311Sjmallett error = rman_init(&sc->sc_io); 175210311Sjmallett if (error != 0) 176210311Sjmallett return (error); 177210311Sjmallett 178210311Sjmallett error = rman_manage_region(&sc->sc_io, CVMX_OCT_PCI_IO_BASE, 179210311Sjmallett CVMX_OCT_PCI_IO_BASE + CVMX_OCT_PCI_IO_SIZE); 180210311Sjmallett if (error != 0) 181210311Sjmallett return (error); 182210311Sjmallett 183210311Sjmallett sc->sc_mem1.rm_type = RMAN_ARRAY; 184210311Sjmallett error = rman_init(&sc->sc_mem1); 185210311Sjmallett if (error != 0) 186210311Sjmallett return (error); 187210311Sjmallett 188210311Sjmallett error = rman_manage_region(&sc->sc_mem1, CVMX_OCT_PCI_MEM1_BASE, 189210311Sjmallett CVMX_OCT_PCI_MEM1_BASE + CVMX_OCT_PCI_MEM1_SIZE); 190210311Sjmallett if (error != 0) 191210311Sjmallett return (error); 192210311Sjmallett 193213089Sjmallett /* 194213089Sjmallett * Next offsets for resource allocation in octopci_init_bar. 195213089Sjmallett */ 196213089Sjmallett sc->sc_io_next = 0; 197213089Sjmallett sc->sc_mem1_next = 0; 198213089Sjmallett 199213089Sjmallett /* 200213089Sjmallett * Configure devices. 201213089Sjmallett */ 202217254Sjmallett octopci_write_config(dev, sc->sc_bus, 0, 0, PCIR_SUBBUS_1, 0xff, 1); 203217254Sjmallett subbus = octopci_init_bus(dev, sc->sc_bus); 204217254Sjmallett octopci_write_config(dev, sc->sc_bus, 0, 0, PCIR_SUBBUS_1, subbus, 1); 205213089Sjmallett 206217254Sjmallett device_add_child(dev, "pci", device_get_unit(dev)); 207210311Sjmallett 208210311Sjmallett return (bus_generic_attach(dev)); 209210311Sjmallett} 210210311Sjmallett 211210311Sjmallettstatic int 212210311Sjmallettoctopci_read_ivar(device_t dev, device_t child, int which, uintptr_t *result) 213210311Sjmallett{ 214210311Sjmallett struct octopci_softc *sc; 215210311Sjmallett 216210311Sjmallett sc = device_get_softc(dev); 217210311Sjmallett 218210311Sjmallett switch (which) { 219210311Sjmallett case PCIB_IVAR_DOMAIN: 220210311Sjmallett *result = sc->sc_domain; 221210311Sjmallett return (0); 222210311Sjmallett case PCIB_IVAR_BUS: 223210311Sjmallett *result = sc->sc_bus; 224210311Sjmallett return (0); 225210311Sjmallett 226210311Sjmallett } 227210311Sjmallett return (ENOENT); 228210311Sjmallett} 229210311Sjmallett 230210311Sjmallettstatic struct resource * 231210311Sjmallettoctopci_alloc_resource(device_t bus, device_t child, int type, int *rid, 232210311Sjmallett u_long start, u_long end, u_long count, u_int flags) 233210311Sjmallett{ 234210311Sjmallett struct octopci_softc *sc; 235210311Sjmallett struct resource *res; 236210311Sjmallett struct rman *rm; 237210311Sjmallett int error; 238210311Sjmallett 239210311Sjmallett sc = device_get_softc(bus); 240210311Sjmallett 241210311Sjmallett switch (type) { 242210311Sjmallett case SYS_RES_IRQ: 243210311Sjmallett res = bus_generic_alloc_resource(bus, child, type, rid, start, 244210311Sjmallett end, count, flags); 245210311Sjmallett if (res != NULL) 246210311Sjmallett return (res); 247210311Sjmallett return (NULL); 248210311Sjmallett case SYS_RES_MEMORY: 249210311Sjmallett rm = &sc->sc_mem1; 250210311Sjmallett break; 251210311Sjmallett case SYS_RES_IOPORT: 252210311Sjmallett rm = &sc->sc_io; 253210311Sjmallett break; 254210311Sjmallett default: 255210311Sjmallett return (NULL); 256210311Sjmallett } 257210311Sjmallett 258210311Sjmallett res = rman_reserve_resource(rm, start, end, count, flags, child); 259210311Sjmallett if (res == NULL) 260210311Sjmallett return (NULL); 261210311Sjmallett 262210311Sjmallett rman_set_rid(res, *rid); 263210311Sjmallett rman_set_bustag(res, octopci_bus_space); 264210311Sjmallett 265210311Sjmallett switch (type) { 266210311Sjmallett case SYS_RES_MEMORY: 267217254Sjmallett rman_set_bushandle(res, sc->sc_mem1_base + rman_get_start(res)); 268210311Sjmallett break; 269210311Sjmallett case SYS_RES_IOPORT: 270217254Sjmallett rman_set_bushandle(res, sc->sc_io_base + rman_get_start(res)); 271213228Sjmallett#if __mips_n64 272213228Sjmallett rman_set_virtual(res, (void *)rman_get_bushandle(res)); 273213228Sjmallett#else 274210311Sjmallett /* 275210311Sjmallett * XXX 276213228Sjmallett * We can't access ports via a 32-bit pointer. 277210311Sjmallett */ 278213228Sjmallett rman_set_virtual(res, NULL); 279210311Sjmallett#endif 280210311Sjmallett break; 281210311Sjmallett } 282210311Sjmallett 283210311Sjmallett if ((flags & RF_ACTIVE) != 0) { 284210311Sjmallett error = bus_activate_resource(child, type, *rid, res); 285210311Sjmallett if (error != 0) { 286210311Sjmallett rman_release_resource(res); 287210311Sjmallett return (NULL); 288210311Sjmallett } 289210311Sjmallett } 290210311Sjmallett 291210311Sjmallett return (res); 292210311Sjmallett} 293210311Sjmallett 294210311Sjmallettstatic int 295210311Sjmallettoctopci_activate_resource(device_t bus, device_t child, int type, int rid, 296210311Sjmallett struct resource *res) 297210311Sjmallett{ 298210311Sjmallett bus_space_handle_t bh; 299210311Sjmallett int error; 300210311Sjmallett 301210311Sjmallett switch (type) { 302210311Sjmallett case SYS_RES_IRQ: 303210311Sjmallett error = bus_generic_activate_resource(bus, child, type, rid, 304210311Sjmallett res); 305210311Sjmallett if (error != 0) 306210311Sjmallett return (error); 307210311Sjmallett return (0); 308210311Sjmallett case SYS_RES_MEMORY: 309210311Sjmallett case SYS_RES_IOPORT: 310210311Sjmallett error = bus_space_map(rman_get_bustag(res), 311210311Sjmallett rman_get_bushandle(res), rman_get_size(res), 0, &bh); 312210311Sjmallett if (error != 0) 313210311Sjmallett return (error); 314210311Sjmallett rman_set_bushandle(res, bh); 315210311Sjmallett break; 316210311Sjmallett default: 317210311Sjmallett return (ENXIO); 318210311Sjmallett } 319210311Sjmallett 320210311Sjmallett error = rman_activate_resource(res); 321210311Sjmallett if (error != 0) 322210311Sjmallett return (error); 323210311Sjmallett return (0); 324210311Sjmallett} 325210311Sjmallett 326210311Sjmallettstatic int 327210311Sjmallettoctopci_maxslots(device_t dev) 328210311Sjmallett{ 329210311Sjmallett return (PCI_SLOTMAX); 330210311Sjmallett} 331210311Sjmallett 332210311Sjmallettstatic uint32_t 333210311Sjmallettoctopci_read_config(device_t dev, u_int bus, u_int slot, u_int func, u_int reg, 334210311Sjmallett int bytes) 335210311Sjmallett{ 336210311Sjmallett struct octopci_softc *sc; 337210311Sjmallett uint64_t addr; 338210311Sjmallett uint32_t data; 339210311Sjmallett 340210311Sjmallett sc = device_get_softc(dev); 341210311Sjmallett 342217254Sjmallett if (octeon_has_feature(OCTEON_FEATURE_PCIE)) { 343217254Sjmallett if (bus == 0 && slot == 0 && func == 0) 344217254Sjmallett return ((uint32_t)-1); 345217254Sjmallett 346217254Sjmallett switch (bytes) { 347217254Sjmallett case 4: 348217254Sjmallett return (cvmx_pcie_config_read32(sc->sc_domain, bus, slot, func, reg)); 349217254Sjmallett case 2: 350217254Sjmallett return (cvmx_pcie_config_read16(sc->sc_domain, bus, slot, func, reg)); 351217254Sjmallett case 1: 352217254Sjmallett return (cvmx_pcie_config_read8(sc->sc_domain, bus, slot, func, reg)); 353217254Sjmallett default: 354217254Sjmallett return ((uint32_t)-1); 355217254Sjmallett } 356217254Sjmallett } 357217254Sjmallett 358210311Sjmallett addr = octopci_cs_addr(bus, slot, func, reg); 359210311Sjmallett 360210311Sjmallett switch (bytes) { 361210311Sjmallett case 4: 362210311Sjmallett data = le32toh(cvmx_read64_uint32(addr)); 363210311Sjmallett return (data); 364210311Sjmallett case 2: 365210311Sjmallett data = le16toh(cvmx_read64_uint16(addr)); 366210311Sjmallett return (data); 367210311Sjmallett case 1: 368210311Sjmallett data = cvmx_read64_uint8(addr); 369210311Sjmallett return (data); 370210311Sjmallett default: 371210311Sjmallett return ((uint32_t)-1); 372210311Sjmallett } 373210311Sjmallett} 374210311Sjmallett 375210311Sjmallettstatic void 376210311Sjmallettoctopci_write_config(device_t dev, u_int bus, u_int slot, u_int func, 377210311Sjmallett u_int reg, uint32_t data, int bytes) 378210311Sjmallett{ 379210311Sjmallett struct octopci_softc *sc; 380210311Sjmallett uint64_t addr; 381210311Sjmallett 382210311Sjmallett sc = device_get_softc(dev); 383210311Sjmallett 384217254Sjmallett if (octeon_has_feature(OCTEON_FEATURE_PCIE)) { 385217254Sjmallett switch (bytes) { 386217254Sjmallett case 4: 387217254Sjmallett cvmx_pcie_config_write32(sc->sc_domain, bus, slot, func, reg, data); 388217254Sjmallett return; 389217254Sjmallett case 2: 390217254Sjmallett cvmx_pcie_config_write16(sc->sc_domain, bus, slot, func, reg, data); 391217254Sjmallett return; 392217254Sjmallett case 1: 393217254Sjmallett cvmx_pcie_config_write8(sc->sc_domain, bus, slot, func, reg, data); 394217254Sjmallett return; 395217254Sjmallett default: 396217254Sjmallett return; 397217254Sjmallett } 398217254Sjmallett } 399217254Sjmallett 400210311Sjmallett addr = octopci_cs_addr(bus, slot, func, reg); 401210311Sjmallett 402210311Sjmallett switch (bytes) { 403210311Sjmallett case 4: 404210311Sjmallett cvmx_write64_uint32(addr, htole32(data)); 405210311Sjmallett return; 406210311Sjmallett case 2: 407210311Sjmallett cvmx_write64_uint16(addr, htole16(data)); 408210311Sjmallett return; 409210311Sjmallett case 1: 410210311Sjmallett cvmx_write64_uint8(addr, data); 411210311Sjmallett return; 412210311Sjmallett default: 413210311Sjmallett return; 414210311Sjmallett } 415210311Sjmallett} 416210311Sjmallett 417210311Sjmallettstatic int 418210311Sjmallettoctopci_route_interrupt(device_t dev, device_t child, int pin) 419210311Sjmallett{ 420210311Sjmallett struct octopci_softc *sc; 421210311Sjmallett unsigned bus, slot, func; 422210311Sjmallett unsigned irq; 423210311Sjmallett 424210311Sjmallett sc = device_get_softc(dev); 425210311Sjmallett 426217254Sjmallett if (octeon_has_feature(OCTEON_FEATURE_PCIE)) 427217254Sjmallett return (CVMX_IRQ_PCI_INT0 + pin - 1); 428217254Sjmallett 429210311Sjmallett bus = pci_get_bus(child); 430210311Sjmallett slot = pci_get_slot(child); 431210311Sjmallett func = pci_get_function(child); 432210311Sjmallett 433213228Sjmallett /* 434213228Sjmallett * Board types we have to know at compile-time. 435213228Sjmallett */ 436213228Sjmallett#if defined(OCTEON_BOARD_CAPK_0100ND) 437213228Sjmallett if (bus == 0 && slot == 12 && func == 0) 438213228Sjmallett return (CVMX_IRQ_PCI_INT2); 439213228Sjmallett#endif 440213228Sjmallett 441213228Sjmallett /* 442213228Sjmallett * For board types we can determine at runtime. 443213228Sjmallett */ 444213228Sjmallett switch (cvmx_sysinfo_get()->board_type) { 445210311Sjmallett#if defined(OCTEON_VENDOR_LANNER) 446213089Sjmallett case CVMX_BOARD_TYPE_CUST_LANNER_MR955: 447213089Sjmallett return (CVMX_IRQ_PCI_INT0 + pin - 1); 448213089Sjmallett case CVMX_BOARD_TYPE_CUST_LANNER_MR320: 449213089Sjmallett if (slot < 32) { 450213089Sjmallett if (slot == 3 || slot == 9) 451213089Sjmallett irq = pin; 452213089Sjmallett else 453213089Sjmallett irq = pin - 1; 454213089Sjmallett return (CVMX_IRQ_PCI_INT0 + (irq & 3)); 455213089Sjmallett } 456213089Sjmallett break; 457213228Sjmallett#endif 458213089Sjmallett default: 459213089Sjmallett break; 460210311Sjmallett } 461210311Sjmallett 462210311Sjmallett irq = slot + pin - 3; 463210311Sjmallett 464210311Sjmallett return (CVMX_IRQ_PCI_INT0 + (irq & 3)); 465210311Sjmallett} 466210311Sjmallett 467217254Sjmallettstatic unsigned 468213228Sjmallettoctopci_init_bar(device_t dev, unsigned b, unsigned s, unsigned f, unsigned barnum, uint8_t *commandp) 469213089Sjmallett{ 470213089Sjmallett struct octopci_softc *sc; 471217254Sjmallett uint64_t bar; 472213089Sjmallett unsigned size; 473217254Sjmallett int barsize; 474213089Sjmallett 475213089Sjmallett sc = device_get_softc(dev); 476213089Sjmallett 477213089Sjmallett octopci_write_config(dev, b, s, f, PCIR_BAR(barnum), 0xffffffff, 4); 478213089Sjmallett bar = octopci_read_config(dev, b, s, f, PCIR_BAR(barnum), 4); 479213089Sjmallett 480213089Sjmallett if (bar == 0) { 481217254Sjmallett /* Bar not implemented; got to next bar. */ 482217254Sjmallett return (barnum + 1); 483213089Sjmallett } 484213089Sjmallett 485213089Sjmallett if (PCI_BAR_IO(bar)) { 486213089Sjmallett size = ~(bar & PCIM_BAR_IO_BASE) + 1; 487213089Sjmallett 488213089Sjmallett sc->sc_io_next = (sc->sc_io_next + size - 1) & ~(size - 1); 489213089Sjmallett if (sc->sc_io_next + size > CVMX_OCT_PCI_IO_SIZE) { 490213089Sjmallett device_printf(dev, "%02x.%02x:%02x: no ports for BAR%u.\n", 491213089Sjmallett b, s, f, barnum); 492217254Sjmallett return (barnum + 1); 493213089Sjmallett } 494213089Sjmallett octopci_write_config(dev, b, s, f, PCIR_BAR(barnum), 495213089Sjmallett CVMX_OCT_PCI_IO_BASE + sc->sc_io_next, 4); 496213089Sjmallett sc->sc_io_next += size; 497213228Sjmallett 498213228Sjmallett /* 499213228Sjmallett * Enable I/O ports. 500213228Sjmallett */ 501213228Sjmallett *commandp |= PCIM_CMD_PORTEN; 502217254Sjmallett 503217254Sjmallett return (barnum + 1); 504213089Sjmallett } else { 505217254Sjmallett if (PCIR_BAR(barnum) == PCIR_BIOS) { 506217254Sjmallett /* 507217254Sjmallett * ROM BAR is always 32-bit. 508217254Sjmallett */ 509217254Sjmallett barsize = 1; 510217254Sjmallett } else { 511217254Sjmallett switch (bar & PCIM_BAR_MEM_TYPE) { 512217254Sjmallett case PCIM_BAR_MEM_64: 513217254Sjmallett /* 514217254Sjmallett * XXX 515217254Sjmallett * High 32 bits are all zeroes for now. 516217254Sjmallett */ 517217254Sjmallett octopci_write_config(dev, b, s, f, PCIR_BAR(barnum + 1), 0, 4); 518217254Sjmallett barsize = 2; 519217254Sjmallett break; 520217254Sjmallett default: 521217254Sjmallett barsize = 1; 522217254Sjmallett break; 523217254Sjmallett } 524217254Sjmallett } 525217254Sjmallett 526213089Sjmallett size = ~(bar & (uint32_t)PCIM_BAR_MEM_BASE) + 1; 527213089Sjmallett 528213089Sjmallett sc->sc_mem1_next = (sc->sc_mem1_next + size - 1) & ~(size - 1); 529213089Sjmallett if (sc->sc_mem1_next + size > CVMX_OCT_PCI_MEM1_SIZE) { 530213089Sjmallett device_printf(dev, "%02x.%02x:%02x: no memory for BAR%u.\n", 531213089Sjmallett b, s, f, barnum); 532217254Sjmallett return (barnum + barsize); 533213089Sjmallett } 534213089Sjmallett octopci_write_config(dev, b, s, f, PCIR_BAR(barnum), 535213089Sjmallett CVMX_OCT_PCI_MEM1_BASE + sc->sc_mem1_next, 4); 536213089Sjmallett sc->sc_mem1_next += size; 537213228Sjmallett 538213228Sjmallett /* 539213228Sjmallett * Enable memory access. 540213228Sjmallett */ 541213228Sjmallett *commandp |= PCIM_CMD_MEMEN; 542217254Sjmallett 543217254Sjmallett return (barnum + barsize); 544213089Sjmallett } 545213089Sjmallett} 546213089Sjmallett 547213089Sjmallettstatic unsigned 548213089Sjmallettoctopci_init_device(device_t dev, unsigned b, unsigned s, unsigned f, unsigned secbus) 549213089Sjmallett{ 550213089Sjmallett unsigned barnum, bars; 551213089Sjmallett uint8_t brctl; 552213089Sjmallett uint8_t class, subclass; 553213089Sjmallett uint8_t command; 554213089Sjmallett uint8_t hdrtype; 555213089Sjmallett 556213089Sjmallett /* Read header type (again.) */ 557213089Sjmallett hdrtype = octopci_read_config(dev, b, s, f, PCIR_HDRTYPE, 1); 558213089Sjmallett 559213228Sjmallett /* 560213228Sjmallett * Disable memory and I/O while programming BARs. 561213228Sjmallett */ 562213228Sjmallett command = octopci_read_config(dev, b, s, f, PCIR_COMMAND, 1); 563213228Sjmallett command &= ~(PCIM_CMD_MEMEN | PCIM_CMD_PORTEN); 564213228Sjmallett octopci_write_config(dev, b, s, f, PCIR_COMMAND, command, 1); 565213228Sjmallett 566213230Sjmallett DELAY(10000); 567213230Sjmallett 568213089Sjmallett /* Program BARs. */ 569213089Sjmallett switch (hdrtype & PCIM_HDRTYPE) { 570213089Sjmallett case PCIM_HDRTYPE_NORMAL: 571213089Sjmallett bars = 6; 572213089Sjmallett break; 573213089Sjmallett case PCIM_HDRTYPE_BRIDGE: 574213089Sjmallett bars = 2; 575213089Sjmallett break; 576213089Sjmallett case PCIM_HDRTYPE_CARDBUS: 577213089Sjmallett bars = 0; 578213089Sjmallett break; 579213089Sjmallett default: 580213089Sjmallett device_printf(dev, "%02x.%02x:%02x: invalid header type %#x\n", 581213089Sjmallett b, s, f, hdrtype); 582213089Sjmallett return (secbus); 583213089Sjmallett } 584213089Sjmallett 585217254Sjmallett barnum = 0; 586217254Sjmallett while (barnum < bars) 587217254Sjmallett barnum = octopci_init_bar(dev, b, s, f, barnum, &command); 588213089Sjmallett 589213089Sjmallett /* Enable bus mastering. */ 590213089Sjmallett command |= PCIM_CMD_BUSMASTEREN; 591213228Sjmallett 592213228Sjmallett /* Enable whatever facilities the BARs require. */ 593213089Sjmallett octopci_write_config(dev, b, s, f, PCIR_COMMAND, command, 1); 594213089Sjmallett 595213230Sjmallett DELAY(10000); 596213230Sjmallett 597213090Sjmallett /* 598213090Sjmallett * Set cache line size. On Octeon it should be 128 bytes, 599213090Sjmallett * but according to Linux some Intel bridges have trouble 600213090Sjmallett * with values over 64 bytes, so use 64 bytes. 601213090Sjmallett */ 602213090Sjmallett octopci_write_config(dev, b, s, f, PCIR_CACHELNSZ, 16, 1); 603213090Sjmallett 604213090Sjmallett /* Set latency timer. */ 605213090Sjmallett octopci_write_config(dev, b, s, f, PCIR_LATTIMER, 48, 1); 606213090Sjmallett 607213228Sjmallett /* Board-specific or device-specific fixups and workarounds. */ 608213228Sjmallett switch (cvmx_sysinfo_get()->board_type) { 609213228Sjmallett#if defined(OCTEON_VENDOR_LANNER) 610213228Sjmallett case CVMX_BOARD_TYPE_CUST_LANNER_MR955: 611213228Sjmallett if (b == 1 && s == 7 && f == 0) { 612213228Sjmallett bus_addr_t busaddr, unitbusaddr; 613213228Sjmallett uint32_t bar; 614213228Sjmallett uint32_t tmp; 615213228Sjmallett unsigned unit; 616213228Sjmallett 617213228Sjmallett /* 618213228Sjmallett * Set Tx DMA power. 619213228Sjmallett */ 620213228Sjmallett bar = octopci_read_config(dev, b, s, f, 621213228Sjmallett PCIR_BAR(3), 4); 622213228Sjmallett busaddr = CVMX_ADDR_DID(CVMX_FULL_DID(CVMX_OCT_DID_PCI, 623213228Sjmallett CVMX_OCT_SUBDID_PCI_MEM1)); 624213228Sjmallett busaddr += (bar & (uint32_t)PCIM_BAR_MEM_BASE); 625213228Sjmallett for (unit = 0; unit < 4; unit++) { 626213228Sjmallett unitbusaddr = busaddr + 0x430 + (unit << 8); 627213228Sjmallett tmp = le32toh(cvmx_read64_uint32(unitbusaddr)); 628213228Sjmallett tmp &= ~0x700; 629213228Sjmallett tmp |= 0x300; 630213228Sjmallett cvmx_write64_uint32(unitbusaddr, htole32(tmp)); 631213228Sjmallett } 632213228Sjmallett } 633213228Sjmallett break; 634213228Sjmallett#endif 635213228Sjmallett default: 636213228Sjmallett break; 637213228Sjmallett } 638213228Sjmallett 639213089Sjmallett /* Configure PCI-PCI bridges. */ 640213089Sjmallett class = octopci_read_config(dev, b, s, f, PCIR_CLASS, 1); 641213089Sjmallett if (class != PCIC_BRIDGE) 642213089Sjmallett return (secbus); 643213089Sjmallett 644213089Sjmallett subclass = octopci_read_config(dev, b, s, f, PCIR_SUBCLASS, 1); 645213089Sjmallett if (subclass != PCIS_BRIDGE_PCI) 646213089Sjmallett return (secbus); 647213089Sjmallett 648213228Sjmallett /* Enable memory and I/O access. */ 649213228Sjmallett command |= PCIM_CMD_MEMEN | PCIM_CMD_PORTEN; 650213228Sjmallett octopci_write_config(dev, b, s, f, PCIR_COMMAND, command, 1); 651213228Sjmallett 652213089Sjmallett /* Enable errors and parity checking. Do a bus reset. */ 653213089Sjmallett brctl = octopci_read_config(dev, b, s, f, PCIR_BRIDGECTL_1, 1); 654213089Sjmallett brctl |= PCIB_BCR_PERR_ENABLE | PCIB_BCR_SERR_ENABLE; 655213089Sjmallett 656213089Sjmallett /* Perform a secondary bus reset. */ 657213089Sjmallett brctl |= PCIB_BCR_SECBUS_RESET; 658213089Sjmallett octopci_write_config(dev, b, s, f, PCIR_BRIDGECTL_1, brctl, 1); 659213089Sjmallett DELAY(100000); 660213089Sjmallett brctl &= ~PCIB_BCR_SECBUS_RESET; 661213089Sjmallett octopci_write_config(dev, b, s, f, PCIR_BRIDGECTL_1, brctl, 1); 662213089Sjmallett 663213089Sjmallett secbus++; 664213089Sjmallett 665213089Sjmallett /* Program memory and I/O ranges. */ 666213089Sjmallett octopci_write_config(dev, b, s, f, PCIR_MEMBASE_1, 667213089Sjmallett CVMX_OCT_PCI_MEM1_BASE >> 16, 2); 668213089Sjmallett octopci_write_config(dev, b, s, f, PCIR_MEMLIMIT_1, 669213089Sjmallett (CVMX_OCT_PCI_MEM1_BASE + CVMX_OCT_PCI_MEM1_SIZE - 1) >> 16, 2); 670213089Sjmallett 671213089Sjmallett octopci_write_config(dev, b, s, f, PCIR_IOBASEL_1, 672213089Sjmallett CVMX_OCT_PCI_IO_BASE >> 8, 1); 673213089Sjmallett octopci_write_config(dev, b, s, f, PCIR_IOBASEH_1, 674213089Sjmallett CVMX_OCT_PCI_IO_BASE >> 16, 2); 675213089Sjmallett 676213089Sjmallett octopci_write_config(dev, b, s, f, PCIR_IOLIMITL_1, 677213089Sjmallett (CVMX_OCT_PCI_IO_BASE + CVMX_OCT_PCI_IO_SIZE - 1) >> 8, 1); 678213089Sjmallett octopci_write_config(dev, b, s, f, PCIR_IOLIMITH_1, 679213089Sjmallett (CVMX_OCT_PCI_IO_BASE + CVMX_OCT_PCI_IO_SIZE - 1) >> 16, 2); 680213089Sjmallett 681213089Sjmallett /* Program prefetchable memory decoder. */ 682213089Sjmallett /* XXX */ 683213089Sjmallett 684213089Sjmallett /* Probe secondary/subordinate buses. */ 685213089Sjmallett octopci_write_config(dev, b, s, f, PCIR_PRIBUS_1, b, 1); 686213089Sjmallett octopci_write_config(dev, b, s, f, PCIR_SECBUS_1, secbus, 1); 687213089Sjmallett octopci_write_config(dev, b, s, f, PCIR_SUBBUS_1, 0xff, 1); 688213089Sjmallett 689213089Sjmallett /* Perform a secondary bus reset. */ 690213089Sjmallett brctl |= PCIB_BCR_SECBUS_RESET; 691213089Sjmallett octopci_write_config(dev, b, s, f, PCIR_BRIDGECTL_1, brctl, 1); 692213089Sjmallett DELAY(100000); 693213089Sjmallett brctl &= ~PCIB_BCR_SECBUS_RESET; 694213089Sjmallett octopci_write_config(dev, b, s, f, PCIR_BRIDGECTL_1, brctl, 1); 695213089Sjmallett 696213089Sjmallett /* Give the bus time to settle now before reading configspace. */ 697213089Sjmallett DELAY(100000); 698213089Sjmallett 699213089Sjmallett secbus = octopci_init_bus(dev, secbus); 700213089Sjmallett 701213089Sjmallett octopci_write_config(dev, b, s, f, PCIR_SUBBUS_1, secbus, 1); 702213089Sjmallett 703213089Sjmallett return (secbus); 704213089Sjmallett} 705213089Sjmallett 706213089Sjmallettstatic unsigned 707213089Sjmallettoctopci_init_bus(device_t dev, unsigned b) 708213089Sjmallett{ 709213089Sjmallett unsigned s, f; 710213089Sjmallett uint8_t hdrtype; 711213089Sjmallett unsigned secbus; 712213089Sjmallett 713213089Sjmallett secbus = b; 714213089Sjmallett 715213089Sjmallett for (s = 0; s <= PCI_SLOTMAX; s++) { 716213089Sjmallett for (f = 0; f <= PCI_FUNCMAX; f++) { 717213089Sjmallett hdrtype = octopci_read_config(dev, b, s, f, PCIR_HDRTYPE, 1); 718213089Sjmallett 719213089Sjmallett if (hdrtype == 0xff) { 720213089Sjmallett if (f == 0) 721213089Sjmallett break; /* Next slot. */ 722213089Sjmallett continue; /* Next function. */ 723213089Sjmallett } 724213089Sjmallett 725213089Sjmallett secbus = octopci_init_device(dev, b, s, f, secbus); 726213089Sjmallett 727213089Sjmallett if (f == 0 && (hdrtype & PCIM_MFDEV) == 0) 728213089Sjmallett break; /* Next slot. */ 729213089Sjmallett } 730213089Sjmallett } 731213089Sjmallett 732213089Sjmallett return (secbus); 733213089Sjmallett} 734213089Sjmallett 735210311Sjmallettstatic uint64_t 736210311Sjmallettoctopci_cs_addr(unsigned bus, unsigned slot, unsigned func, unsigned reg) 737210311Sjmallett{ 738210311Sjmallett octeon_pci_config_space_address_t pci_addr; 739210311Sjmallett 740210311Sjmallett pci_addr.u64 = 0; 741210311Sjmallett pci_addr.s.upper = 2; 742210311Sjmallett pci_addr.s.io = 1; 743210311Sjmallett pci_addr.s.did = 3; 744210311Sjmallett pci_addr.s.subdid = CVMX_OCT_SUBDID_PCI_CFG; 745210311Sjmallett pci_addr.s.endian_swap = 1; 746210311Sjmallett pci_addr.s.bus = bus; 747210311Sjmallett pci_addr.s.dev = slot; 748210311Sjmallett pci_addr.s.func = func; 749210311Sjmallett pci_addr.s.reg = reg; 750210311Sjmallett 751210311Sjmallett return (pci_addr.u64); 752210311Sjmallett} 753210311Sjmallett 754217254Sjmallettstatic void 755217254Sjmallettoctopci_init_pci(device_t dev) 756217254Sjmallett{ 757217254Sjmallett cvmx_npi_mem_access_subid_t npi_mem_access_subid; 758217254Sjmallett cvmx_npi_pci_int_arb_cfg_t npi_pci_int_arb_cfg; 759217254Sjmallett cvmx_npi_ctl_status_t npi_ctl_status; 760217254Sjmallett cvmx_pci_ctl_status_2_t pci_ctl_status_2; 761217254Sjmallett cvmx_pci_cfg56_t pci_cfg56; 762217254Sjmallett cvmx_pci_cfg22_t pci_cfg22; 763217254Sjmallett cvmx_pci_cfg16_t pci_cfg16; 764217254Sjmallett cvmx_pci_cfg19_t pci_cfg19; 765217254Sjmallett cvmx_pci_cfg01_t pci_cfg01; 766217254Sjmallett unsigned i; 767217254Sjmallett 768217254Sjmallett /* 769217254Sjmallett * Reset the PCI bus. 770217254Sjmallett */ 771217254Sjmallett cvmx_write_csr(CVMX_CIU_SOFT_PRST, 0x1); 772217254Sjmallett cvmx_read_csr(CVMX_CIU_SOFT_PRST); 773217254Sjmallett 774217254Sjmallett DELAY(2000); 775217254Sjmallett 776217254Sjmallett npi_ctl_status.u64 = 0; 777217254Sjmallett npi_ctl_status.s.max_word = 1; 778217254Sjmallett npi_ctl_status.s.timer = 1; 779217254Sjmallett cvmx_write_csr(CVMX_NPI_CTL_STATUS, npi_ctl_status.u64); 780217254Sjmallett 781217254Sjmallett /* 782217254Sjmallett * Set host mode. 783217254Sjmallett */ 784217254Sjmallett switch (cvmx_sysinfo_get()->board_type) { 785217254Sjmallett#if defined(OCTEON_VENDOR_LANNER) 786217254Sjmallett case CVMX_BOARD_TYPE_CUST_LANNER_MR320: 787217254Sjmallett case CVMX_BOARD_TYPE_CUST_LANNER_MR955: 788217254Sjmallett /* 32-bit PCI-X */ 789217254Sjmallett cvmx_write_csr(CVMX_CIU_SOFT_PRST, 0x0); 790217254Sjmallett break; 791217254Sjmallett#endif 792217254Sjmallett default: 793217254Sjmallett /* 64-bit PCI-X */ 794217254Sjmallett cvmx_write_csr(CVMX_CIU_SOFT_PRST, 0x4); 795217254Sjmallett break; 796217254Sjmallett } 797217254Sjmallett cvmx_read_csr(CVMX_CIU_SOFT_PRST); 798217254Sjmallett 799217254Sjmallett DELAY(2000); 800217254Sjmallett 801217254Sjmallett /* 802217254Sjmallett * Enable BARs and configure big BAR mode. 803217254Sjmallett */ 804217254Sjmallett pci_ctl_status_2.u32 = 0; 805217254Sjmallett pci_ctl_status_2.s.bb1_hole = 5; /* 256MB hole in BAR1 */ 806217254Sjmallett pci_ctl_status_2.s.bb1_siz = 1; /* BAR1 is 2GB */ 807217254Sjmallett pci_ctl_status_2.s.bb_ca = 1; /* Bypass cache for big BAR */ 808217254Sjmallett pci_ctl_status_2.s.bb_es = 1; /* Do big BAR byte-swapping */ 809217254Sjmallett pci_ctl_status_2.s.bb1 = 1; /* BAR1 is big */ 810217254Sjmallett pci_ctl_status_2.s.bb0 = 1; /* BAR0 is big */ 811217254Sjmallett pci_ctl_status_2.s.bar2pres = 1; /* BAR2 present */ 812217254Sjmallett pci_ctl_status_2.s.pmo_amod = 1; /* Round-robin priority */ 813217254Sjmallett pci_ctl_status_2.s.tsr_hwm = 1; 814217254Sjmallett pci_ctl_status_2.s.bar2_enb = 1; /* Enable BAR2 */ 815217254Sjmallett pci_ctl_status_2.s.bar2_esx = 1; /* Do BAR2 byte-swapping */ 816217254Sjmallett pci_ctl_status_2.s.bar2_cax = 1; /* Bypass cache for BAR2 */ 817217254Sjmallett 818217254Sjmallett NPI_WRITE(CVMX_NPI_PCI_CTL_STATUS_2, pci_ctl_status_2.u32); 819217254Sjmallett 820217254Sjmallett DELAY(2000); 821217254Sjmallett 822217254Sjmallett pci_ctl_status_2.u32 = NPI_READ(CVMX_NPI_PCI_CTL_STATUS_2); 823217254Sjmallett 824217254Sjmallett device_printf(dev, "%u-bit PCI%s bus.\n", 825217254Sjmallett pci_ctl_status_2.s.ap_64ad ? 64 : 32, 826217254Sjmallett pci_ctl_status_2.s.ap_pcix ? "-X" : ""); 827217254Sjmallett 828217254Sjmallett /* 829217254Sjmallett * Set up transaction splitting, etc., parameters. 830217254Sjmallett */ 831217254Sjmallett pci_cfg19.u32 = 0; 832217254Sjmallett pci_cfg19.s.mrbcm = 1; 833217254Sjmallett if (pci_ctl_status_2.s.ap_pcix) { 834217254Sjmallett pci_cfg19.s.mdrrmc = 0; 835217254Sjmallett pci_cfg19.s.tdomc = 4; 836217254Sjmallett } else { 837217254Sjmallett pci_cfg19.s.mdrrmc = 2; 838217254Sjmallett pci_cfg19.s.tdomc = 1; 839217254Sjmallett } 840217254Sjmallett NPI_WRITE(CVMX_NPI_PCI_CFG19, pci_cfg19.u32); 841217254Sjmallett NPI_READ(CVMX_NPI_PCI_CFG19); 842217254Sjmallett 843217254Sjmallett /* 844217254Sjmallett * Set up PCI error handling and memory access. 845217254Sjmallett */ 846217254Sjmallett pci_cfg01.u32 = 0; 847217254Sjmallett pci_cfg01.s.fbbe = 1; 848217254Sjmallett pci_cfg01.s.see = 1; 849217254Sjmallett pci_cfg01.s.pee = 1; 850217254Sjmallett pci_cfg01.s.me = 1; 851217254Sjmallett pci_cfg01.s.msae = 1; 852217254Sjmallett if (pci_ctl_status_2.s.ap_pcix) { 853217254Sjmallett pci_cfg01.s.fbb = 0; 854217254Sjmallett } else { 855217254Sjmallett pci_cfg01.s.fbb = 1; 856217254Sjmallett } 857217254Sjmallett NPI_WRITE(CVMX_NPI_PCI_CFG01, pci_cfg01.u32); 858217254Sjmallett NPI_READ(CVMX_NPI_PCI_CFG01); 859217254Sjmallett 860217254Sjmallett /* 861217254Sjmallett * Enable the Octeon bus arbiter. 862217254Sjmallett */ 863217254Sjmallett npi_pci_int_arb_cfg.u64 = 0; 864217254Sjmallett npi_pci_int_arb_cfg.s.en = 1; 865217254Sjmallett cvmx_write_csr(CVMX_NPI_PCI_INT_ARB_CFG, npi_pci_int_arb_cfg.u64); 866217254Sjmallett 867217254Sjmallett /* 868217254Sjmallett * Disable master latency timer. 869217254Sjmallett */ 870217254Sjmallett pci_cfg16.u32 = 0; 871217254Sjmallett pci_cfg16.s.mltd = 1; 872217254Sjmallett NPI_WRITE(CVMX_NPI_PCI_CFG16, pci_cfg16.u32); 873217254Sjmallett NPI_READ(CVMX_NPI_PCI_CFG16); 874217254Sjmallett 875217254Sjmallett /* 876217254Sjmallett * Configure master arbiter. 877217254Sjmallett */ 878217254Sjmallett pci_cfg22.u32 = 0; 879217254Sjmallett pci_cfg22.s.flush = 1; 880217254Sjmallett pci_cfg22.s.mrv = 255; 881217254Sjmallett NPI_WRITE(CVMX_NPI_PCI_CFG22, pci_cfg22.u32); 882217254Sjmallett NPI_READ(CVMX_NPI_PCI_CFG22); 883217254Sjmallett 884217254Sjmallett /* 885217254Sjmallett * Set up PCI-X capabilities. 886217254Sjmallett */ 887217254Sjmallett if (pci_ctl_status_2.s.ap_pcix) { 888217254Sjmallett pci_cfg56.u32 = 0; 889217254Sjmallett pci_cfg56.s.most = 3; 890217254Sjmallett pci_cfg56.s.roe = 1; /* Enable relaxed ordering */ 891217254Sjmallett pci_cfg56.s.dpere = 1; 892217254Sjmallett pci_cfg56.s.ncp = 0xe8; 893217254Sjmallett pci_cfg56.s.pxcid = 7; 894217254Sjmallett NPI_WRITE(CVMX_NPI_PCI_CFG56, pci_cfg56.u32); 895217254Sjmallett NPI_READ(CVMX_NPI_PCI_CFG56); 896217254Sjmallett } 897217254Sjmallett 898217254Sjmallett NPI_WRITE(CVMX_NPI_PCI_READ_CMD_6, 0x22); 899217254Sjmallett NPI_READ(CVMX_NPI_PCI_READ_CMD_6); 900217254Sjmallett NPI_WRITE(CVMX_NPI_PCI_READ_CMD_C, 0x33); 901217254Sjmallett NPI_READ(CVMX_NPI_PCI_READ_CMD_C); 902217254Sjmallett NPI_WRITE(CVMX_NPI_PCI_READ_CMD_E, 0x33); 903217254Sjmallett NPI_READ(CVMX_NPI_PCI_READ_CMD_E); 904217254Sjmallett 905217254Sjmallett /* 906217254Sjmallett * Configure MEM1 sub-DID access. 907217254Sjmallett */ 908217254Sjmallett npi_mem_access_subid.u64 = 0; 909217254Sjmallett npi_mem_access_subid.s.esr = 1; /* Byte-swap on read */ 910217254Sjmallett npi_mem_access_subid.s.esw = 1; /* Byte-swap on write */ 911217254Sjmallett switch (cvmx_sysinfo_get()->board_type) { 912217254Sjmallett#if defined(OCTEON_VENDOR_LANNER) 913217254Sjmallett case CVMX_BOARD_TYPE_CUST_LANNER_MR955: 914217254Sjmallett npi_mem_access_subid.s.shortl = 1; 915217254Sjmallett break; 916217254Sjmallett#endif 917217254Sjmallett default: 918217254Sjmallett break; 919217254Sjmallett } 920217254Sjmallett cvmx_write_csr(CVMX_NPI_MEM_ACCESS_SUBID3, npi_mem_access_subid.u64); 921217254Sjmallett 922217254Sjmallett /* 923217254Sjmallett * Configure BAR2. Linux says this has to come first. 924217254Sjmallett */ 925217254Sjmallett NPI_WRITE(CVMX_NPI_PCI_CFG08, 0x00000000); 926217254Sjmallett NPI_READ(CVMX_NPI_PCI_CFG08); 927217254Sjmallett NPI_WRITE(CVMX_NPI_PCI_CFG09, 0x00000080); 928217254Sjmallett NPI_READ(CVMX_NPI_PCI_CFG09); 929217254Sjmallett 930217254Sjmallett /* 931217254Sjmallett * Disable BAR1 IndexX. 932217254Sjmallett */ 933217254Sjmallett for (i = 0; i < 32; i++) { 934217254Sjmallett NPI_WRITE(CVMX_NPI_PCI_BAR1_INDEXX(i), 0); 935217254Sjmallett NPI_READ(CVMX_NPI_PCI_BAR1_INDEXX(i)); 936217254Sjmallett } 937217254Sjmallett 938217254Sjmallett /* 939217254Sjmallett * Configure BAR0 and BAR1. 940217254Sjmallett */ 941217254Sjmallett NPI_WRITE(CVMX_NPI_PCI_CFG04, 0x00000000); 942217254Sjmallett NPI_READ(CVMX_NPI_PCI_CFG04); 943217254Sjmallett NPI_WRITE(CVMX_NPI_PCI_CFG05, 0x00000000); 944217254Sjmallett NPI_READ(CVMX_NPI_PCI_CFG05); 945217254Sjmallett 946217254Sjmallett NPI_WRITE(CVMX_NPI_PCI_CFG06, 0x80000000); 947217254Sjmallett NPI_READ(CVMX_NPI_PCI_CFG06); 948217254Sjmallett NPI_WRITE(CVMX_NPI_PCI_CFG07, 0x00000000); 949217254Sjmallett NPI_READ(CVMX_NPI_PCI_CFG07); 950217254Sjmallett 951217254Sjmallett /* 952217254Sjmallett * Clear PCI interrupts. 953217254Sjmallett */ 954217254Sjmallett cvmx_write_csr(CVMX_NPI_PCI_INT_SUM2, 0xffffffffffffffffull); 955217254Sjmallett} 956217254Sjmallett 957210311Sjmallettstatic device_method_t octopci_methods[] = { 958210311Sjmallett /* Device interface */ 959210311Sjmallett DEVMETHOD(device_identify, octopci_identify), 960210311Sjmallett DEVMETHOD(device_probe, octopci_probe), 961210311Sjmallett DEVMETHOD(device_attach, octopci_attach), 962210311Sjmallett 963210311Sjmallett /* Bus interface */ 964210311Sjmallett DEVMETHOD(bus_read_ivar, octopci_read_ivar), 965210311Sjmallett DEVMETHOD(bus_alloc_resource, octopci_alloc_resource), 966210311Sjmallett DEVMETHOD(bus_release_resource, bus_generic_release_resource), 967210311Sjmallett DEVMETHOD(bus_activate_resource,octopci_activate_resource), 968210311Sjmallett DEVMETHOD(bus_deactivate_resource,bus_generic_deactivate_resource), 969210311Sjmallett DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), 970213090Sjmallett DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), 971210311Sjmallett 972212843Sjmallett DEVMETHOD(bus_add_child, bus_generic_add_child), 973212843Sjmallett 974210311Sjmallett /* pcib interface */ 975210311Sjmallett DEVMETHOD(pcib_maxslots, octopci_maxslots), 976210311Sjmallett DEVMETHOD(pcib_read_config, octopci_read_config), 977210311Sjmallett DEVMETHOD(pcib_write_config, octopci_write_config), 978210311Sjmallett DEVMETHOD(pcib_route_interrupt, octopci_route_interrupt), 979210311Sjmallett 980229093Shselasky DEVMETHOD_END 981210311Sjmallett}; 982210311Sjmallett 983210311Sjmallettstatic driver_t octopci_driver = { 984210311Sjmallett "pcib", 985210311Sjmallett octopci_methods, 986210311Sjmallett sizeof(struct octopci_softc), 987210311Sjmallett}; 988210311Sjmallettstatic devclass_t octopci_devclass; 989210311SjmallettDRIVER_MODULE(octopci, ciu, octopci_driver, octopci_devclass, 0, 0); 990