admpci.c revision 331722
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: stable/11/sys/mips/adm5120/admpci.c 331722 2018-03-29 02:50:57Z eadler $"); 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 83#include <dev/pci/pcivar.h> 84#include <dev/pci/pcireg.h> 85 86#include <dev/pci/pcib_private.h> 87#include "pcib_if.h" 88 89#include <mips/adm5120/adm5120reg.h> 90 91#ifdef ADMPCI_DEBUG 92int admpci_debug = 1; 93#define ADMPCI_DPRINTF(__fmt, ...) \ 94do { \ 95 if (admpci_debug) \ 96 printf((__fmt), __VA_ARGS__); \ 97} while (/*CONSTCOND*/0) 98#else /* !ADMPCI_DEBUG */ 99#define ADMPCI_DPRINTF(__fmt, ...) do { } while (/*CONSTCOND*/0) 100#endif /* ADMPCI_DEBUG */ 101 102#define ADMPCI_TAG_BUS_MASK __BITS(23, 16) 103/* Bit 11 is reserved. It selects the AHB-PCI bridge. Let device 0 104 * be the bridge. For all other device numbers, let bit[11] == 0. 105 */ 106#define ADMPCI_TAG_DEVICE_MASK __BITS(15, 11) 107#define ADMPCI_TAG_DEVICE_SUBMASK __BITS(15, 12) 108#define ADMPCI_TAG_DEVICE_BRIDGE __BIT(11) 109#define ADMPCI_TAG_FUNCTION_MASK __BITS(10, 8) 110#define ADMPCI_TAG_REGISTER_MASK __BITS(7, 0) 111 112#define ADMPCI_MAX_DEVICE 113 114struct admpci_softc { 115 device_t sc_dev; 116 bus_space_tag_t sc_st; 117 118 /* Access to PCI config registers */ 119 bus_space_handle_t sc_addrh; 120 bus_space_handle_t sc_datah; 121 122 int sc_busno; 123 struct rman sc_mem_rman; 124 struct rman sc_io_rman; 125 struct rman sc_irq_rman; 126 uint32_t sc_mem; 127 uint32_t sc_io; 128}; 129 130static int 131admpci_probe(device_t dev) 132{ 133 134 return (0); 135} 136 137static int 138admpci_attach(device_t dev) 139{ 140 int busno = 0; 141 struct admpci_softc *sc = device_get_softc(dev); 142 143 sc->sc_dev = dev; 144 sc->sc_busno = busno; 145 146 /* Use KSEG1 to access IO ports for it is uncached */ 147 sc->sc_io = MIPS_PHYS_TO_KSEG1(ADM5120_BASE_PCI_IO); 148 sc->sc_io_rman.rm_type = RMAN_ARRAY; 149 sc->sc_io_rman.rm_descr = "ADMPCI I/O Ports"; 150 if (rman_init(&sc->sc_io_rman) != 0 || 151 rman_manage_region(&sc->sc_io_rman, 0, 0xffff) != 0) { 152 panic("admpci_attach: failed to set up I/O rman"); 153 } 154 155 /* Use KSEG1 to access PCI memory for it is uncached */ 156 sc->sc_mem = MIPS_PHYS_TO_KSEG1(ADM5120_BASE_PCI_MEM); 157 sc->sc_mem_rman.rm_type = RMAN_ARRAY; 158 sc->sc_mem_rman.rm_descr = "ADMPCI PCI Memory"; 159 if (rman_init(&sc->sc_mem_rman) != 0 || 160 rman_manage_region(&sc->sc_mem_rman, 161 sc->sc_mem, sc->sc_mem + 0x100000) != 0) { 162 panic("admpci_attach: failed to set up memory rman"); 163 } 164 165 sc->sc_irq_rman.rm_type = RMAN_ARRAY; 166 sc->sc_irq_rman.rm_descr = "ADMPCI PCI IRQs"; 167 if (rman_init(&sc->sc_irq_rman) != 0 || 168 rman_manage_region(&sc->sc_irq_rman, 1, 31) != 0) 169 panic("admpci_attach: failed to set up IRQ rman"); 170 171 if (bus_space_map(sc->sc_st, ADM5120_BASE_PCI_CONFADDR, 4, 0, 172 &sc->sc_addrh) != 0) { 173 device_printf(sc->sc_dev, "unable to address space\n"); 174 panic("bus_space_map failed"); 175 } 176 177 if (bus_space_map(sc->sc_st, ADM5120_BASE_PCI_CONFDATA, 4, 0, 178 &sc->sc_datah) != 0) { 179 device_printf(sc->sc_dev, "unable to address space\n"); 180 panic("bus_space_map failed"); 181 } 182 183 device_add_child(dev, "pci", -1); 184 return (bus_generic_attach(dev)); 185} 186 187static int 188admpci_maxslots(device_t dev) 189{ 190 191 return (PCI_SLOTMAX); 192} 193 194static uint32_t 195admpci_make_addr(int bus, int slot, int func, int reg) 196{ 197 198 return (0x80000000 | (bus << 16) | (slot << 11) | (func << 8) | reg); 199} 200 201static uint32_t 202admpci_read_config(device_t dev, int bus, int slot, int func, int reg, 203 int bytes) 204{ 205 struct admpci_softc *sc = device_get_softc(dev); 206 uint32_t data; 207 uint32_t shift, mask; 208 bus_addr_t addr; 209 210 ADMPCI_DPRINTF("%s: sc %p tag (%x, %x, %x) reg %d\n", __func__, 211 (void *)sc, bus, slot, func, reg); 212 213 addr = admpci_make_addr(bus, slot, func, reg); 214 215 ADMPCI_DPRINTF("%s: sc_addrh %p sc_datah %p addr %p\n", __func__, 216 (void *)sc->sc_addrh, (void *)sc->sc_datah, (void *)addr); 217 218 bus_space_write_4(sc->sc_io, sc->sc_addrh, 0, addr); 219 data = bus_space_read_4(sc->sc_io, sc->sc_datah, 0); 220 221 switch (reg % 4) { 222 case 3: 223 shift = 24; 224 break; 225 case 2: 226 shift = 16; 227 break; 228 case 1: 229 shift = 8; 230 break; 231 default: 232 shift = 0; 233 break; 234 } 235 236 switch (bytes) { 237 case 1: 238 mask = 0xff; 239 data = (data >> shift) & mask; 240 break; 241 case 2: 242 mask = 0xffff; 243 if (reg % 4 == 0) 244 data = data & mask; 245 else 246 data = (data >> 16) & mask; 247 break; 248 case 4: 249 break; 250 default: 251 panic("%s: wrong bytes count", __func__); 252 break; 253 } 254 255 ADMPCI_DPRINTF("%s: read 0x%x\n", __func__, data); 256 return (data); 257} 258 259static void 260admpci_write_config(device_t dev, int bus, int slot, int func, int reg, 261 uint32_t data, int bytes) 262{ 263 struct admpci_softc *sc = device_get_softc(dev); 264 bus_addr_t addr; 265 uint32_t reg_data; 266 uint32_t shift, mask; 267 268 ADMPCI_DPRINTF("%s: sc %p tag (%x, %x, %x) reg %d\n", __func__, 269 (void *)sc, bus, slot, func, reg); 270 271 if (bytes != 4) { 272 reg_data = admpci_read_config(dev, bus, slot, func, reg, 4); 273 274 switch (reg % 4) { 275 case 3: 276 shift = 24; 277 break; 278 case 2: 279 shift = 16; 280 break; 281 case 1: 282 shift = 8; 283 break; 284 default: 285 shift = 0; 286 break; 287 } 288 289 switch (bytes) { 290 case 1: 291 mask = 0xff; 292 data = (reg_data & ~ (mask << shift)) | (data << shift); 293 break; 294 case 2: 295 mask = 0xffff; 296 if (reg % 4 == 0) 297 data = (reg_data & ~mask) | data; 298 else 299 data = (reg_data & ~ (mask << shift)) | 300 (data << shift); 301 break; 302 case 4: 303 break; 304 default: 305 panic("%s: wrong bytes count", __func__); 306 break; 307 } 308 } 309 310 addr = admpci_make_addr(bus, slot, func, reg); 311 312 ADMPCI_DPRINTF("%s: sc_addrh %p sc_datah %p addr %p\n", __func__, 313 (void *)sc->sc_addrh, (void *)sc->sc_datah, (void *)addr); 314 315 bus_space_write_4(sc->sc_io, sc->sc_addrh, 0, addr); 316 bus_space_write_4(sc->sc_io, sc->sc_datah, 0, data); 317} 318 319static int 320admpci_route_interrupt(device_t pcib, device_t dev, int pin) 321{ 322 /* TODO: implement */ 323 return (0); 324} 325 326static int 327admpci_read_ivar(device_t dev, device_t child, int which, uintptr_t *result) 328{ 329 struct admpci_softc *sc = device_get_softc(dev); 330 331 switch (which) { 332 case PCIB_IVAR_DOMAIN: 333 *result = 0; 334 return (0); 335 case PCIB_IVAR_BUS: 336 *result = sc->sc_busno; 337 return (0); 338 } 339 340 return (ENOENT); 341} 342 343static int 344admpci_write_ivar(device_t dev, device_t child, int which, uintptr_t result) 345{ 346 struct admpci_softc * sc = device_get_softc(dev); 347 348 switch (which) { 349 case PCIB_IVAR_BUS: 350 sc->sc_busno = result; 351 return (0); 352 } 353 return (ENOENT); 354} 355 356static struct resource * 357admpci_alloc_resource(device_t bus, device_t child, int type, int *rid, 358 rman_res_t start, rman_res_t end, rman_res_t count, u_int flags) 359{ 360 361 return (NULL); 362#if 0 363 struct admpci_softc *sc = device_get_softc(bus); 364 struct resource *rv = NULL; 365 struct rman *rm; 366 bus_space_handle_t bh = 0; 367 368 switch (type) { 369 case SYS_RES_IRQ: 370 rm = &sc->sc_irq_rman; 371 break; 372 case SYS_RES_MEMORY: 373 rm = &sc->sc_mem_rman; 374 bh = sc->sc_mem; 375 break; 376 case SYS_RES_IOPORT: 377 rm = &sc->sc_io_rman; 378 bh = sc->sc_io; 379 break; 380 default: 381 return (NULL); 382 } 383 384 rv = rman_reserve_resource(rm, start, end, count, flags, child); 385 if (rv == NULL) 386 return (NULL); 387 rman_set_rid(rv, *rid); 388 if (type != SYS_RES_IRQ) { 389 bh += (rman_get_start(rv)); 390 391 rman_set_bustag(rv, sc->sc_st); 392 rman_set_bushandle(rv, bh); 393 if (flags & RF_ACTIVE) { 394 if (bus_activate_resource(child, type, *rid, rv)) { 395 rman_release_resource(rv); 396 return (NULL); 397 } 398 } 399 } 400 return (rv); 401#endif 402} 403 404static int 405admpci_activate_resource(device_t bus, device_t child, int type, int rid, 406 struct resource *r) 407{ 408 bus_space_handle_t p; 409 int error; 410 411 if ((type == SYS_RES_MEMORY) || (type == SYS_RES_IOPORT)) { 412 error = bus_space_map(rman_get_bustag(r), 413 rman_get_bushandle(r), rman_get_size(r), 0, &p); 414 if (error) 415 return (error); 416 rman_set_bushandle(r, p); 417 } 418 return (rman_activate_resource(r)); 419} 420 421static int 422admpci_setup_intr(device_t dev, device_t child, struct resource *ires, 423 int flags, driver_filter_t *filt, driver_intr_t *handler, 424 void *arg, void **cookiep) 425{ 426 427#if 0 428 struct admpci_softc *sc = device_get_softc(dev); 429 struct intr_event *event; 430 int irq, error; 431 432 irq = rman_get_start(ires); 433 if (irq >= ICU_LEN || irq == 2) 434 panic("%s: bad irq or type", __func__); 435 436 event = sc->sc_eventstab[irq]; 437 if (event == NULL) { 438 error = intr_event_create(&event, (void *)irq, 0, 439 (void (*)(void *))NULL, "admpci intr%d:", irq); 440 if (error) 441 return 0; 442 sc->sc_eventstab[irq] = event; 443 } 444 445 intr_event_add_handler(event, device_get_nameunit(child), filt, 446 handler, arg, intr_priority(flags), flags, cookiep); 447 448 /* Enable it, set trigger mode. */ 449 sc->sc_imask &= ~(1 << irq); 450 sc->sc_elcr &= ~(1 << irq); 451 452 admpci_set_icus(sc); 453#endif 454 455 return (0); 456} 457 458static int 459admpci_teardown_intr(device_t dev, device_t child, struct resource *res, 460 void *cookie) 461{ 462 463 return (intr_event_remove_handler(cookie)); 464} 465 466static device_method_t admpci_methods[] = { 467 /* Device interface */ 468 DEVMETHOD(device_probe, admpci_probe), 469 DEVMETHOD(device_attach, admpci_attach), 470 DEVMETHOD(device_shutdown, bus_generic_shutdown), 471 DEVMETHOD(device_suspend, bus_generic_suspend), 472 DEVMETHOD(device_resume, bus_generic_resume), 473 474 /* Bus interface */ 475 DEVMETHOD(bus_read_ivar, admpci_read_ivar), 476 DEVMETHOD(bus_write_ivar, admpci_write_ivar), 477 DEVMETHOD(bus_alloc_resource, admpci_alloc_resource), 478 DEVMETHOD(bus_release_resource, bus_generic_release_resource), 479 DEVMETHOD(bus_activate_resource, admpci_activate_resource), 480 DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), 481 DEVMETHOD(bus_setup_intr, admpci_setup_intr), 482 DEVMETHOD(bus_teardown_intr, admpci_teardown_intr), 483 484 /* pcib interface */ 485 DEVMETHOD(pcib_maxslots, admpci_maxslots), 486 DEVMETHOD(pcib_read_config, admpci_read_config), 487 DEVMETHOD(pcib_write_config, admpci_write_config), 488 DEVMETHOD(pcib_route_interrupt, admpci_route_interrupt), 489 490 DEVMETHOD_END 491}; 492 493static driver_t admpci_driver = { 494 "pcib", 495 admpci_methods, 496 sizeof(struct admpci_softc), 497}; 498 499static devclass_t admpci_devclass; 500 501DRIVER_MODULE(admpci, obio, admpci_driver, admpci_devclass, 0, 0); 502