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