1178173Simp/* $NetBSD: admpci.c,v 1.1 2007/03/20 08:52:02 dyoung Exp $ */ 2178173Simp 3178173Simp/*- 4178173Simp * Copyright (c) 2007 David Young. All rights reserved. 5178173Simp * 6178173Simp * Redistribution and use in source and binary forms, with or 7178173Simp * without modification, are permitted provided that the following 8178173Simp * conditions are met: 9178173Simp * 1. Redistributions of source code must retain the above copyright 10178173Simp * notice, this list of conditions and the following disclaimer. 11178173Simp * 2. Redistributions in binary form must reproduce the above 12178173Simp * copyright notice, this list of conditions and the following 13178173Simp * disclaimer in the documentation and/or other materials provided 14178173Simp * with the distribution. 15178173Simp * 3. The name of the author may not be used to endorse or promote 16178173Simp * products derived from this software without specific prior 17178173Simp * written permission. 18178173Simp * 19178173Simp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY 20178173Simp * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 21178173Simp * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 22178173Simp * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR 23178173Simp * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 24178173Simp * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 25178173Simp * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 26178173Simp * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27178173Simp * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 28178173Simp * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 29178173Simp * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 30178173Simp * OF SUCH DAMAGE. 31178173Simp */ 32178173Simp/*- 33178173Simp * Copyright (c) 2006 Itronix Inc. 34178173Simp * All rights reserved. 35178173Simp * 36178173Simp * Written by Garrett D'Amore for Itronix Inc. 37178173Simp * 38178173Simp * Redistribution and use in source and binary forms, with or without 39178173Simp * modification, are permitted provided that the following conditions 40178173Simp * are met: 41178173Simp * 1. Redistributions of source code must retain the above copyright 42178173Simp * notice, this list of conditions and the following disclaimer. 43178173Simp * 2. Redistributions in binary form must reproduce the above copyright 44178173Simp * notice, this list of conditions and the following disclaimer in the 45178173Simp * documentation and/or other materials provided with the distribution. 46178173Simp * 3. The name of Itronix Inc. may not be used to endorse 47178173Simp * or promote products derived from this software without specific 48178173Simp * prior written permission. 49178173Simp * 50178173Simp * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND 51178173Simp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 52178173Simp * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 53178173Simp * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY 54178173Simp * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 55178173Simp * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 56178173Simp * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 57178173Simp * ON ANY THEORY OF LIABILITY, WHETHER IN 58178173Simp * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 59178173Simp * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 60178173Simp * POSSIBILITY OF SUCH DAMAGE. 61178173Simp */ 62178173Simp 63178173Simp#include <sys/cdefs.h> 64178173Simp__FBSDID("$FreeBSD$"); 65178173Simp 66178173Simp#include <sys/param.h> 67178173Simp#include <sys/systm.h> 68178173Simp 69178173Simp#include <sys/bus.h> 70178173Simp#include <sys/interrupt.h> 71178173Simp#include <sys/malloc.h> 72178173Simp#include <sys/kernel.h> 73178173Simp#include <sys/module.h> 74178173Simp#include <sys/rman.h> 75178173Simp 76178173Simp#include <vm/vm.h> 77178173Simp#include <vm/pmap.h> 78178173Simp#include <vm/vm_extern.h> 79178173Simp 80178173Simp#include <machine/bus.h> 81178173Simp#include <machine/cpu.h> 82178173Simp#include <machine/pmap.h> 83178173Simp 84178173Simp#include <dev/pci/pcivar.h> 85178173Simp#include <dev/pci/pcireg.h> 86178173Simp 87178173Simp#include <dev/pci/pcib_private.h> 88178173Simp#include "pcib_if.h" 89178173Simp 90182901Sgonzo#include <mips/adm5120/adm5120reg.h> 91178173Simp 92178173Simp#ifdef ADMPCI_DEBUG 93178173Simpint admpci_debug = 1; 94178173Simp#define ADMPCI_DPRINTF(__fmt, ...) \ 95178173Simpdo { \ 96178173Simp if (admpci_debug) \ 97178173Simp printf((__fmt), __VA_ARGS__); \ 98178173Simp} while (/*CONSTCOND*/0) 99178173Simp#else /* !ADMPCI_DEBUG */ 100178173Simp#define ADMPCI_DPRINTF(__fmt, ...) do { } while (/*CONSTCOND*/0) 101178173Simp#endif /* ADMPCI_DEBUG */ 102178173Simp 103178173Simp#define ADMPCI_TAG_BUS_MASK __BITS(23, 16) 104178173Simp/* Bit 11 is reserved. It selects the AHB-PCI bridge. Let device 0 105178173Simp * be the bridge. For all other device numbers, let bit[11] == 0. 106178173Simp */ 107178173Simp#define ADMPCI_TAG_DEVICE_MASK __BITS(15, 11) 108178173Simp#define ADMPCI_TAG_DEVICE_SUBMASK __BITS(15, 12) 109178173Simp#define ADMPCI_TAG_DEVICE_BRIDGE __BIT(11) 110178173Simp#define ADMPCI_TAG_FUNCTION_MASK __BITS(10, 8) 111178173Simp#define ADMPCI_TAG_REGISTER_MASK __BITS(7, 0) 112178173Simp 113178173Simp#define ADMPCI_MAX_DEVICE 114178173Simp 115178173Simpstruct admpci_softc { 116178173Simp device_t sc_dev; 117178173Simp bus_space_tag_t sc_st; 118178173Simp 119178173Simp /* Access to PCI config registers */ 120178173Simp bus_space_handle_t sc_addrh; 121178173Simp bus_space_handle_t sc_datah; 122178173Simp 123178173Simp int sc_busno; 124178173Simp struct rman sc_mem_rman; 125178173Simp struct rman sc_io_rman; 126178173Simp struct rman sc_irq_rman; 127178173Simp uint32_t sc_mem; 128178173Simp uint32_t sc_io; 129178173Simp}; 130178173Simp 131178173Simpstatic int 132178173Simpadmpci_probe(device_t dev) 133178173Simp{ 134178173Simp 135178173Simp return (0); 136178173Simp} 137178173Simp 138178173Simpstatic int 139178173Simpadmpci_attach(device_t dev) 140178173Simp{ 141178173Simp int busno = 0; 142178173Simp struct admpci_softc *sc = device_get_softc(dev); 143178173Simp 144178173Simp sc->sc_dev = dev; 145178173Simp sc->sc_busno = busno; 146178173Simp 147178173Simp /* Use KSEG1 to access IO ports for it is uncached */ 148178173Simp sc->sc_io = MIPS_PHYS_TO_KSEG1(ADM5120_BASE_PCI_IO); 149178173Simp sc->sc_io_rman.rm_type = RMAN_ARRAY; 150178173Simp sc->sc_io_rman.rm_descr = "ADMPCI I/O Ports"; 151178173Simp if (rman_init(&sc->sc_io_rman) != 0 || 152178173Simp rman_manage_region(&sc->sc_io_rman, 0, 0xffff) != 0) { 153178173Simp panic("admpci_attach: failed to set up I/O rman"); 154178173Simp } 155178173Simp 156178173Simp /* Use KSEG1 to access PCI memory for it is uncached */ 157178173Simp sc->sc_mem = MIPS_PHYS_TO_KSEG1(ADM5120_BASE_PCI_MEM); 158178173Simp sc->sc_mem_rman.rm_type = RMAN_ARRAY; 159178173Simp sc->sc_mem_rman.rm_descr = "ADMPCI PCI Memory"; 160178173Simp if (rman_init(&sc->sc_mem_rman) != 0 || 161178173Simp rman_manage_region(&sc->sc_mem_rman, 162178173Simp sc->sc_mem, sc->sc_mem + 0x100000) != 0) { 163178173Simp panic("admpci_attach: failed to set up memory rman"); 164178173Simp } 165178173Simp 166178173Simp sc->sc_irq_rman.rm_type = RMAN_ARRAY; 167178173Simp sc->sc_irq_rman.rm_descr = "ADMPCI PCI IRQs"; 168178173Simp if (rman_init(&sc->sc_irq_rman) != 0 || 169178173Simp rman_manage_region(&sc->sc_irq_rman, 1, 31) != 0) 170178173Simp panic("admpci_attach: failed to set up IRQ rman"); 171178173Simp 172178173Simp if (bus_space_map(sc->sc_st, ADM5120_BASE_PCI_CONFADDR, 4, 0, 173178173Simp &sc->sc_addrh) != 0) { 174178173Simp device_printf(sc->sc_dev, "unable to address space\n"); 175178173Simp panic("bus_space_map failed"); 176178173Simp } 177178173Simp 178178173Simp if (bus_space_map(sc->sc_st, ADM5120_BASE_PCI_CONFDATA, 4, 0, 179178173Simp &sc->sc_datah) != 0) { 180178173Simp device_printf(sc->sc_dev, "unable to address space\n"); 181178173Simp panic("bus_space_map failed"); 182178173Simp } 183178173Simp 184178173Simp device_add_child(dev, "pci", busno); 185178173Simp return (bus_generic_attach(dev)); 186178173Simp} 187178173Simp 188178173Simpstatic int 189178173Simpadmpci_maxslots(device_t dev) 190178173Simp{ 191178173Simp 192178173Simp return (PCI_SLOTMAX); 193178173Simp} 194178173Simp 195178173Simpstatic uint32_t 196178173Simpadmpci_make_addr(int bus, int slot, int func, int reg) 197178173Simp{ 198178173Simp 199178173Simp return (0x80000000 | (bus << 16) | (slot << 11) | (func << 8) | reg); 200178173Simp} 201178173Simp 202178173Simpstatic uint32_t 203178173Simpadmpci_read_config(device_t dev, int bus, int slot, int func, int reg, 204178173Simp int bytes) 205178173Simp{ 206178173Simp struct admpci_softc *sc = device_get_softc(dev); 207178173Simp uint32_t data; 208178173Simp uint32_t shift, mask; 209178173Simp bus_addr_t addr; 210178173Simp 211178173Simp ADMPCI_DPRINTF("%s: sc %p tag (%x, %x, %x) reg %d\n", __func__, 212178173Simp (void *)sc, bus, slot, func, reg); 213178173Simp 214178173Simp addr = admpci_make_addr(bus, slot, func, reg); 215178173Simp 216178173Simp ADMPCI_DPRINTF("%s: sc_addrh %p sc_datah %p addr %p\n", __func__, 217178173Simp (void *)sc->sc_addrh, (void *)sc->sc_datah, (void *)addr); 218178173Simp 219178173Simp bus_space_write_4(sc->sc_io, sc->sc_addrh, 0, addr); 220178173Simp data = bus_space_read_4(sc->sc_io, sc->sc_datah, 0); 221178173Simp 222178173Simp switch (reg % 4) { 223178173Simp case 3: 224178173Simp shift = 24; 225178173Simp break; 226178173Simp case 2: 227178173Simp shift = 16; 228178173Simp break; 229178173Simp case 1: 230178173Simp shift = 8; 231178173Simp break; 232178173Simp default: 233178173Simp shift = 0; 234178173Simp break; 235178173Simp } 236178173Simp 237178173Simp switch (bytes) { 238178173Simp case 1: 239178173Simp mask = 0xff; 240178173Simp data = (data >> shift) & mask; 241178173Simp break; 242178173Simp case 2: 243178173Simp mask = 0xffff; 244178173Simp if (reg % 4 == 0) 245178173Simp data = data & mask; 246178173Simp else 247178173Simp data = (data >> 16) & mask; 248178173Simp break; 249178173Simp case 4: 250178173Simp break; 251178173Simp default: 252178173Simp panic("%s: wrong bytes count", __func__); 253178173Simp break; 254178173Simp } 255178173Simp 256178173Simp ADMPCI_DPRINTF("%s: read 0x%x\n", __func__, data); 257178173Simp return (data); 258178173Simp} 259178173Simp 260178173Simpstatic void 261178173Simpadmpci_write_config(device_t dev, int bus, int slot, int func, int reg, 262178173Simp uint32_t data, int bytes) 263178173Simp{ 264178173Simp struct admpci_softc *sc = device_get_softc(dev); 265178173Simp bus_addr_t addr; 266178173Simp uint32_t reg_data; 267178173Simp uint32_t shift, mask; 268178173Simp 269178173Simp ADMPCI_DPRINTF("%s: sc %p tag (%x, %x, %x) reg %d\n", __func__, 270178173Simp (void *)sc, bus, slot, func, reg); 271178173Simp 272178173Simp if (bytes != 4) { 273178173Simp reg_data = admpci_read_config(dev, bus, slot, func, reg, 4); 274178173Simp 275178173Simp switch (reg % 4) { 276178173Simp case 3: 277178173Simp shift = 24; 278178173Simp break; 279178173Simp case 2: 280178173Simp shift = 16; 281178173Simp break; 282178173Simp case 1: 283178173Simp shift = 8; 284178173Simp break; 285178173Simp default: 286178173Simp shift = 0; 287178173Simp break; 288178173Simp } 289178173Simp 290178173Simp switch (bytes) { 291178173Simp case 1: 292178173Simp mask = 0xff; 293178173Simp data = (reg_data & ~ (mask << shift)) | (data << shift); 294178173Simp break; 295178173Simp case 2: 296178173Simp mask = 0xffff; 297178173Simp if (reg % 4 == 0) 298178173Simp data = (reg_data & ~mask) | data; 299178173Simp else 300178173Simp data = (reg_data & ~ (mask << shift)) | 301178173Simp (data << shift); 302178173Simp break; 303178173Simp case 4: 304178173Simp break; 305178173Simp default: 306178173Simp panic("%s: wrong bytes count", __func__); 307178173Simp break; 308178173Simp } 309178173Simp } 310178173Simp 311178173Simp addr = admpci_make_addr(bus, slot, func, reg); 312178173Simp 313178173Simp ADMPCI_DPRINTF("%s: sc_addrh %p sc_datah %p addr %p\n", __func__, 314178173Simp (void *)sc->sc_addrh, (void *)sc->sc_datah, (void *)addr); 315178173Simp 316178173Simp bus_space_write_4(sc->sc_io, sc->sc_addrh, 0, addr); 317178173Simp bus_space_write_4(sc->sc_io, sc->sc_datah, 0, data); 318178173Simp} 319178173Simp 320178173Simpstatic int 321178173Simpadmpci_route_interrupt(device_t pcib, device_t dev, int pin) 322178173Simp{ 323178173Simp /* TODO: implement */ 324178173Simp return (0); 325178173Simp} 326178173Simp 327178173Simpstatic int 328178173Simpadmpci_read_ivar(device_t dev, device_t child, int which, uintptr_t *result) 329178173Simp{ 330178173Simp struct admpci_softc *sc = device_get_softc(dev); 331178173Simp 332178173Simp switch (which) { 333178173Simp case PCIB_IVAR_DOMAIN: 334178173Simp *result = 0; 335178173Simp return (0); 336178173Simp case PCIB_IVAR_BUS: 337178173Simp *result = sc->sc_busno; 338178173Simp return (0); 339178173Simp } 340178173Simp 341178173Simp return (ENOENT); 342178173Simp} 343178173Simp 344178173Simpstatic int 345178173Simpadmpci_write_ivar(device_t dev, device_t child, int which, uintptr_t result) 346178173Simp{ 347178173Simp struct admpci_softc * sc = device_get_softc(dev); 348178173Simp 349178173Simp switch (which) { 350178173Simp case PCIB_IVAR_BUS: 351178173Simp sc->sc_busno = result; 352178173Simp return (0); 353178173Simp } 354178173Simp return (ENOENT); 355178173Simp} 356178173Simp 357178173Simpstatic struct resource * 358178173Simpadmpci_alloc_resource(device_t bus, device_t child, int type, int *rid, 359178173Simp u_long start, u_long end, u_long count, u_int flags) 360178173Simp{ 361178173Simp 362178173Simp return (NULL); 363178173Simp#if 0 364178173Simp struct admpci_softc *sc = device_get_softc(bus); 365178173Simp struct resource *rv = NULL; 366178173Simp struct rman *rm; 367178173Simp bus_space_handle_t bh = 0; 368178173Simp 369178173Simp switch (type) { 370178173Simp case SYS_RES_IRQ: 371178173Simp rm = &sc->sc_irq_rman; 372178173Simp break; 373178173Simp case SYS_RES_MEMORY: 374178173Simp rm = &sc->sc_mem_rman; 375178173Simp bh = sc->sc_mem; 376178173Simp break; 377178173Simp case SYS_RES_IOPORT: 378178173Simp rm = &sc->sc_io_rman; 379178173Simp bh = sc->sc_io; 380178173Simp break; 381178173Simp default: 382178173Simp return (NULL); 383178173Simp } 384178173Simp 385178173Simp rv = rman_reserve_resource(rm, start, end, count, flags, child); 386178173Simp if (rv == NULL) 387178173Simp return (NULL); 388178173Simp rman_set_rid(rv, *rid); 389178173Simp if (type != SYS_RES_IRQ) { 390178173Simp bh += (rman_get_start(rv)); 391178173Simp 392178173Simp rman_set_bustag(rv, sc->sc_st); 393178173Simp rman_set_bushandle(rv, bh); 394178173Simp if (flags & RF_ACTIVE) { 395178173Simp if (bus_activate_resource(child, type, *rid, rv)) { 396178173Simp rman_release_resource(rv); 397178173Simp return (NULL); 398178173Simp } 399178173Simp } 400178173Simp } 401178173Simp return (rv); 402178173Simp#endif 403178173Simp} 404178173Simp 405178173Simpstatic int 406178173Simpadmpci_activate_resource(device_t bus, device_t child, int type, int rid, 407178173Simp struct resource *r) 408178173Simp{ 409178173Simp bus_space_handle_t p; 410178173Simp int error; 411178173Simp 412178173Simp if ((type == SYS_RES_MEMORY) || (type == SYS_RES_IOPORT)) { 413178173Simp error = bus_space_map(rman_get_bustag(r), 414178173Simp rman_get_bushandle(r), rman_get_size(r), 0, &p); 415178173Simp if (error) 416178173Simp return (error); 417178173Simp rman_set_bushandle(r, p); 418178173Simp } 419178173Simp return (rman_activate_resource(r)); 420178173Simp} 421178173Simp 422178173Simpstatic int 423178173Simpadmpci_setup_intr(device_t dev, device_t child, struct resource *ires, 424178173Simp int flags, driver_filter_t *filt, driver_intr_t *handler, 425178173Simp void *arg, void **cookiep) 426178173Simp{ 427178173Simp 428178173Simp#if 0 429178173Simp struct admpci_softc *sc = device_get_softc(dev); 430178173Simp struct intr_event *event; 431178173Simp int irq, error; 432178173Simp 433178173Simp irq = rman_get_start(ires); 434178173Simp if (irq >= ICU_LEN || irq == 2) 435178173Simp panic("%s: bad irq or type", __func__); 436178173Simp 437178173Simp event = sc->sc_eventstab[irq]; 438178173Simp if (event == NULL) { 439178173Simp error = intr_event_create(&event, (void *)irq, 0, 440178173Simp (void (*)(void *))NULL, "admpci intr%d:", irq); 441178173Simp if (error) 442178173Simp return 0; 443178173Simp sc->sc_eventstab[irq] = event; 444178173Simp } 445178173Simp 446178173Simp intr_event_add_handler(event, device_get_nameunit(child), filt, 447178173Simp handler, arg, intr_priority(flags), flags, cookiep); 448178173Simp 449178173Simp /* Enable it, set trigger mode. */ 450178173Simp sc->sc_imask &= ~(1 << irq); 451178173Simp sc->sc_elcr &= ~(1 << irq); 452178173Simp 453178173Simp admpci_set_icus(sc); 454178173Simp#endif 455178173Simp 456178173Simp return (0); 457178173Simp} 458178173Simp 459178173Simpstatic int 460178173Simpadmpci_teardown_intr(device_t dev, device_t child, struct resource *res, 461178173Simp void *cookie) 462178173Simp{ 463178173Simp 464178173Simp return (intr_event_remove_handler(cookie)); 465178173Simp} 466178173Simp 467178173Simpstatic device_method_t admpci_methods[] = { 468178173Simp /* Device interface */ 469178173Simp DEVMETHOD(device_probe, admpci_probe), 470178173Simp DEVMETHOD(device_attach, admpci_attach), 471178173Simp DEVMETHOD(device_shutdown, bus_generic_shutdown), 472178173Simp DEVMETHOD(device_suspend, bus_generic_suspend), 473178173Simp DEVMETHOD(device_resume, bus_generic_resume), 474178173Simp 475178173Simp /* Bus interface */ 476178173Simp DEVMETHOD(bus_read_ivar, admpci_read_ivar), 477178173Simp DEVMETHOD(bus_write_ivar, admpci_write_ivar), 478178173Simp DEVMETHOD(bus_alloc_resource, admpci_alloc_resource), 479178173Simp DEVMETHOD(bus_release_resource, bus_generic_release_resource), 480178173Simp DEVMETHOD(bus_activate_resource, admpci_activate_resource), 481178173Simp DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), 482178173Simp DEVMETHOD(bus_setup_intr, admpci_setup_intr), 483178173Simp DEVMETHOD(bus_teardown_intr, admpci_teardown_intr), 484178173Simp 485178173Simp /* pcib interface */ 486178173Simp DEVMETHOD(pcib_maxslots, admpci_maxslots), 487178173Simp DEVMETHOD(pcib_read_config, admpci_read_config), 488178173Simp DEVMETHOD(pcib_write_config, admpci_write_config), 489178173Simp DEVMETHOD(pcib_route_interrupt, admpci_route_interrupt), 490178173Simp 491227843Smarius DEVMETHOD_END 492178173Simp}; 493178173Simp 494178173Simpstatic driver_t admpci_driver = { 495178173Simp "pcib", 496178173Simp admpci_methods, 497178173Simp sizeof(struct admpci_softc), 498178173Simp}; 499178173Simp 500178173Simpstatic devclass_t admpci_devclass; 501178173Simp 502178173SimpDRIVER_MODULE(admpci, obio, admpci_driver, admpci_devclass, 0, 0); 503