admpci.c revision 180332
1/* $NetBSD: admpci.c,v 1.1 2007/03/20 08:52:02 dyoung Exp $ */ 2 3/*- 4 * Copyright (c) 2007 David Young. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or 7 * without modification, are permitted provided that the following 8 * conditions are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above 12 * copyright notice, this list of conditions and the following 13 * disclaimer in the documentation and/or other materials provided 14 * with the distribution. 15 * 3. The name of the author may not be used to endorse or promote 16 * products derived from this software without specific prior 17 * written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY 20 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 21 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 22 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 24 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 25 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 26 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 28 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 29 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 30 * OF SUCH DAMAGE. 31 */ 32/*- 33 * Copyright (c) 2006 Itronix Inc. 34 * All rights reserved. 35 * 36 * Written by Garrett D'Amore for Itronix Inc. 37 * 38 * Redistribution and use in source and binary forms, with or without 39 * modification, are permitted provided that the following conditions 40 * are met: 41 * 1. Redistributions of source code must retain the above copyright 42 * notice, this list of conditions and the following disclaimer. 43 * 2. Redistributions in binary form must reproduce the above copyright 44 * notice, this list of conditions and the following disclaimer in the 45 * documentation and/or other materials provided with the distribution. 46 * 3. The name of Itronix Inc. may not be used to endorse 47 * or promote products derived from this software without specific 48 * prior written permission. 49 * 50 * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND 51 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 52 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 53 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY 54 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 55 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 56 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 57 * ON ANY THEORY OF LIABILITY, WHETHER IN 58 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 59 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 60 * POSSIBILITY OF SUCH DAMAGE. 61 */ 62 63#include <sys/cdefs.h> 64__FBSDID("$FreeBSD: head/sys/mips/adm5120/admpci.c 178173 2008-04-13 07:44:55Z imp $"); 65 66#include <sys/param.h> 67#include <sys/systm.h> 68 69#include <sys/bus.h> 70#include <sys/interrupt.h> 71#include <sys/malloc.h> 72#include <sys/kernel.h> 73#include <sys/module.h> 74#include <sys/rman.h> 75 76#include <vm/vm.h> 77#include <vm/pmap.h> 78#include <vm/vm_extern.h> 79 80#include <machine/bus.h> 81#include <machine/cpu.h> 82#include <machine/pmap.h> 83 84#include <dev/pci/pcivar.h> 85#include <dev/pci/pcireg.h> 86 87#include <dev/pci/pcib_private.h> 88#include "pcib_if.h" 89 90#include <mips/mips32/adm5120/adm5120reg.h> 91 92#ifdef ADMPCI_DEBUG 93int admpci_debug = 1; 94#define ADMPCI_DPRINTF(__fmt, ...) \ 95do { \ 96 if (admpci_debug) \ 97 printf((__fmt), __VA_ARGS__); \ 98} while (/*CONSTCOND*/0) 99#else /* !ADMPCI_DEBUG */ 100#define ADMPCI_DPRINTF(__fmt, ...) do { } while (/*CONSTCOND*/0) 101#endif /* ADMPCI_DEBUG */ 102 103#define ADMPCI_TAG_BUS_MASK __BITS(23, 16) 104/* Bit 11 is reserved. It selects the AHB-PCI bridge. Let device 0 105 * be the bridge. For all other device numbers, let bit[11] == 0. 106 */ 107#define ADMPCI_TAG_DEVICE_MASK __BITS(15, 11) 108#define ADMPCI_TAG_DEVICE_SUBMASK __BITS(15, 12) 109#define ADMPCI_TAG_DEVICE_BRIDGE __BIT(11) 110#define ADMPCI_TAG_FUNCTION_MASK __BITS(10, 8) 111#define ADMPCI_TAG_REGISTER_MASK __BITS(7, 0) 112 113#define ADMPCI_MAX_DEVICE 114 115struct admpci_softc { 116 device_t sc_dev; 117 bus_space_tag_t sc_st; 118 119 /* Access to PCI config registers */ 120 bus_space_handle_t sc_addrh; 121 bus_space_handle_t sc_datah; 122 123 int sc_busno; 124 struct rman sc_mem_rman; 125 struct rman sc_io_rman; 126 struct rman sc_irq_rman; 127 uint32_t sc_mem; 128 uint32_t sc_io; 129}; 130 131static int 132admpci_probe(device_t dev) 133{ 134 135 return (0); 136} 137 138static int 139admpci_attach(device_t dev) 140{ 141 int busno = 0; 142 struct admpci_softc *sc = device_get_softc(dev); 143 144 sc->sc_dev = dev; 145 sc->sc_busno = busno; 146 147 /* Use KSEG1 to access IO ports for it is uncached */ 148 sc->sc_io = MIPS_PHYS_TO_KSEG1(ADM5120_BASE_PCI_IO); 149 sc->sc_io_rman.rm_type = RMAN_ARRAY; 150 sc->sc_io_rman.rm_descr = "ADMPCI I/O Ports"; 151 if (rman_init(&sc->sc_io_rman) != 0 || 152 rman_manage_region(&sc->sc_io_rman, 0, 0xffff) != 0) { 153 panic("admpci_attach: failed to set up I/O rman"); 154 } 155 156 /* Use KSEG1 to access PCI memory for it is uncached */ 157 sc->sc_mem = MIPS_PHYS_TO_KSEG1(ADM5120_BASE_PCI_MEM); 158 sc->sc_mem_rman.rm_type = RMAN_ARRAY; 159 sc->sc_mem_rman.rm_descr = "ADMPCI PCI Memory"; 160 if (rman_init(&sc->sc_mem_rman) != 0 || 161 rman_manage_region(&sc->sc_mem_rman, 162 sc->sc_mem, sc->sc_mem + 0x100000) != 0) { 163 panic("admpci_attach: failed to set up memory rman"); 164 } 165 166 sc->sc_irq_rman.rm_type = RMAN_ARRAY; 167 sc->sc_irq_rman.rm_descr = "ADMPCI PCI IRQs"; 168 if (rman_init(&sc->sc_irq_rman) != 0 || 169 rman_manage_region(&sc->sc_irq_rman, 1, 31) != 0) 170 panic("admpci_attach: failed to set up IRQ rman"); 171 172 if (bus_space_map(sc->sc_st, ADM5120_BASE_PCI_CONFADDR, 4, 0, 173 &sc->sc_addrh) != 0) { 174 device_printf(sc->sc_dev, "unable to address space\n"); 175 panic("bus_space_map failed"); 176 } 177 178 if (bus_space_map(sc->sc_st, ADM5120_BASE_PCI_CONFDATA, 4, 0, 179 &sc->sc_datah) != 0) { 180 device_printf(sc->sc_dev, "unable to address space\n"); 181 panic("bus_space_map failed"); 182 } 183 184 device_add_child(dev, "pci", busno); 185 return (bus_generic_attach(dev)); 186} 187 188static int 189admpci_maxslots(device_t dev) 190{ 191 192 return (PCI_SLOTMAX); 193} 194 195static uint32_t 196admpci_make_addr(int bus, int slot, int func, int reg) 197{ 198 199 return (0x80000000 | (bus << 16) | (slot << 11) | (func << 8) | reg); 200} 201 202static uint32_t 203admpci_read_config(device_t dev, int bus, int slot, int func, int reg, 204 int bytes) 205{ 206 struct admpci_softc *sc = device_get_softc(dev); 207 uint32_t data; 208 uint32_t shift, mask; 209 bus_addr_t addr; 210 211 ADMPCI_DPRINTF("%s: sc %p tag (%x, %x, %x) reg %d\n", __func__, 212 (void *)sc, bus, slot, func, reg); 213 214 addr = admpci_make_addr(bus, slot, func, reg); 215 216 ADMPCI_DPRINTF("%s: sc_addrh %p sc_datah %p addr %p\n", __func__, 217 (void *)sc->sc_addrh, (void *)sc->sc_datah, (void *)addr); 218 219 bus_space_write_4(sc->sc_io, sc->sc_addrh, 0, addr); 220 data = bus_space_read_4(sc->sc_io, sc->sc_datah, 0); 221 222 switch (reg % 4) { 223 case 3: 224 shift = 24; 225 break; 226 case 2: 227 shift = 16; 228 break; 229 case 1: 230 shift = 8; 231 break; 232 default: 233 shift = 0; 234 break; 235 } 236 237 switch (bytes) { 238 case 1: 239 mask = 0xff; 240 data = (data >> shift) & mask; 241 break; 242 case 2: 243 mask = 0xffff; 244 if (reg % 4 == 0) 245 data = data & mask; 246 else 247 data = (data >> 16) & mask; 248 break; 249 case 4: 250 break; 251 default: 252 panic("%s: wrong bytes count", __func__); 253 break; 254 } 255 256 ADMPCI_DPRINTF("%s: read 0x%x\n", __func__, data); 257 return (data); 258} 259 260static void 261admpci_write_config(device_t dev, int bus, int slot, int func, int reg, 262 uint32_t data, int bytes) 263{ 264 struct admpci_softc *sc = device_get_softc(dev); 265 bus_addr_t addr; 266 uint32_t reg_data; 267 uint32_t shift, mask; 268 269 ADMPCI_DPRINTF("%s: sc %p tag (%x, %x, %x) reg %d\n", __func__, 270 (void *)sc, bus, slot, func, reg); 271 272 if (bytes != 4) { 273 reg_data = admpci_read_config(dev, bus, slot, func, reg, 4); 274 275 switch (reg % 4) { 276 case 3: 277 shift = 24; 278 break; 279 case 2: 280 shift = 16; 281 break; 282 case 1: 283 shift = 8; 284 break; 285 default: 286 shift = 0; 287 break; 288 } 289 290 switch (bytes) { 291 case 1: 292 mask = 0xff; 293 data = (reg_data & ~ (mask << shift)) | (data << shift); 294 break; 295 case 2: 296 mask = 0xffff; 297 if (reg % 4 == 0) 298 data = (reg_data & ~mask) | data; 299 else 300 data = (reg_data & ~ (mask << shift)) | 301 (data << shift); 302 break; 303 case 4: 304 break; 305 default: 306 panic("%s: wrong bytes count", __func__); 307 break; 308 } 309 } 310 311 addr = admpci_make_addr(bus, slot, func, reg); 312 313 ADMPCI_DPRINTF("%s: sc_addrh %p sc_datah %p addr %p\n", __func__, 314 (void *)sc->sc_addrh, (void *)sc->sc_datah, (void *)addr); 315 316 bus_space_write_4(sc->sc_io, sc->sc_addrh, 0, addr); 317 bus_space_write_4(sc->sc_io, sc->sc_datah, 0, data); 318} 319 320static int 321admpci_route_interrupt(device_t pcib, device_t dev, int pin) 322{ 323 /* TODO: implement */ 324 return (0); 325} 326 327static int 328admpci_read_ivar(device_t dev, device_t child, int which, uintptr_t *result) 329{ 330 struct admpci_softc *sc = device_get_softc(dev); 331 332 switch (which) { 333 case PCIB_IVAR_DOMAIN: 334 *result = 0; 335 return (0); 336 case PCIB_IVAR_BUS: 337 *result = sc->sc_busno; 338 return (0); 339 } 340 341 return (ENOENT); 342} 343 344static int 345admpci_write_ivar(device_t dev, device_t child, int which, uintptr_t result) 346{ 347 struct admpci_softc * sc = device_get_softc(dev); 348 349 switch (which) { 350 case PCIB_IVAR_BUS: 351 sc->sc_busno = result; 352 return (0); 353 } 354 return (ENOENT); 355} 356 357static struct resource * 358admpci_alloc_resource(device_t bus, device_t child, int type, int *rid, 359 u_long start, u_long end, u_long count, u_int flags) 360{ 361 362 return (NULL); 363#if 0 364 struct admpci_softc *sc = device_get_softc(bus); 365 struct resource *rv = NULL; 366 struct rman *rm; 367 bus_space_handle_t bh = 0; 368 369 switch (type) { 370 case SYS_RES_IRQ: 371 rm = &sc->sc_irq_rman; 372 break; 373 case SYS_RES_MEMORY: 374 rm = &sc->sc_mem_rman; 375 bh = sc->sc_mem; 376 break; 377 case SYS_RES_IOPORT: 378 rm = &sc->sc_io_rman; 379 bh = sc->sc_io; 380 break; 381 default: 382 return (NULL); 383 } 384 385 rv = rman_reserve_resource(rm, start, end, count, flags, child); 386 if (rv == NULL) 387 return (NULL); 388 rman_set_rid(rv, *rid); 389 if (type != SYS_RES_IRQ) { 390 bh += (rman_get_start(rv)); 391 392 rman_set_bustag(rv, sc->sc_st); 393 rman_set_bushandle(rv, bh); 394 if (flags & RF_ACTIVE) { 395 if (bus_activate_resource(child, type, *rid, rv)) { 396 rman_release_resource(rv); 397 return (NULL); 398 } 399 } 400 } 401 return (rv); 402#endif 403} 404 405static int 406admpci_activate_resource(device_t bus, device_t child, int type, int rid, 407 struct resource *r) 408{ 409 bus_space_handle_t p; 410 int error; 411 412 if ((type == SYS_RES_MEMORY) || (type == SYS_RES_IOPORT)) { 413 error = bus_space_map(rman_get_bustag(r), 414 rman_get_bushandle(r), rman_get_size(r), 0, &p); 415 if (error) 416 return (error); 417 rman_set_bushandle(r, p); 418 } 419 return (rman_activate_resource(r)); 420} 421 422static int 423admpci_setup_intr(device_t dev, device_t child, struct resource *ires, 424 int flags, driver_filter_t *filt, driver_intr_t *handler, 425 void *arg, void **cookiep) 426{ 427 428#if 0 429 struct admpci_softc *sc = device_get_softc(dev); 430 struct intr_event *event; 431 int irq, error; 432 433 irq = rman_get_start(ires); 434 if (irq >= ICU_LEN || irq == 2) 435 panic("%s: bad irq or type", __func__); 436 437 event = sc->sc_eventstab[irq]; 438 if (event == NULL) { 439 error = intr_event_create(&event, (void *)irq, 0, 440 (void (*)(void *))NULL, "admpci intr%d:", irq); 441 if (error) 442 return 0; 443 sc->sc_eventstab[irq] = event; 444 } 445 446 intr_event_add_handler(event, device_get_nameunit(child), filt, 447 handler, arg, intr_priority(flags), flags, cookiep); 448 449 /* Enable it, set trigger mode. */ 450 sc->sc_imask &= ~(1 << irq); 451 sc->sc_elcr &= ~(1 << irq); 452 453 admpci_set_icus(sc); 454#endif 455 456 return (0); 457} 458 459static int 460admpci_teardown_intr(device_t dev, device_t child, struct resource *res, 461 void *cookie) 462{ 463 464 return (intr_event_remove_handler(cookie)); 465} 466 467static device_method_t admpci_methods[] = { 468 /* Device interface */ 469 DEVMETHOD(device_probe, admpci_probe), 470 DEVMETHOD(device_attach, admpci_attach), 471 DEVMETHOD(device_shutdown, bus_generic_shutdown), 472 DEVMETHOD(device_suspend, bus_generic_suspend), 473 DEVMETHOD(device_resume, bus_generic_resume), 474 475 /* Bus interface */ 476 DEVMETHOD(bus_print_child, bus_generic_print_child), 477 DEVMETHOD(bus_read_ivar, admpci_read_ivar), 478 DEVMETHOD(bus_write_ivar, admpci_write_ivar), 479 DEVMETHOD(bus_alloc_resource, admpci_alloc_resource), 480 DEVMETHOD(bus_release_resource, bus_generic_release_resource), 481 DEVMETHOD(bus_activate_resource, admpci_activate_resource), 482 DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), 483 DEVMETHOD(bus_setup_intr, admpci_setup_intr), 484 DEVMETHOD(bus_teardown_intr, admpci_teardown_intr), 485 486 /* pcib interface */ 487 DEVMETHOD(pcib_maxslots, admpci_maxslots), 488 DEVMETHOD(pcib_read_config, admpci_read_config), 489 DEVMETHOD(pcib_write_config, admpci_write_config), 490 DEVMETHOD(pcib_route_interrupt, admpci_route_interrupt), 491 492 {0, 0} 493}; 494 495static driver_t admpci_driver = { 496 "pcib", 497 admpci_methods, 498 sizeof(struct admpci_softc), 499}; 500 501static devclass_t admpci_devclass; 502 503DRIVER_MODULE(admpci, obio, admpci_driver, admpci_devclass, 0, 0); 504