1 /*- 2 * SPDX-License-Identifier: BSD-3-Clause 3 * 4 * Copyright 2002 by Peter Grehan. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * 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 copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. The name of the author may not be used to endorse or promote products 15 * derived from this software without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 22 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 24 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 25 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 */ 29 30 /* 31 * PSIM 'iobus' local bus. Should be set up in the device tree like: 32 * 33 * /iobus@0x80000000/name psim-iobus 34 * 35 * Code borrowed from various nexus.c and uninorth.c :-) 36 */ 37 38 #include <sys/param.h> 39 #include <sys/systm.h> 40 #include <sys/kernel.h> 41 #include <sys/malloc.h> 42 #include <sys/module.h> 43 #include <sys/bus.h> 44 #include <machine/bus.h> 45 #include <sys/rman.h> 46 47 #include <dev/ofw/ofw_bus.h> 48 #include <dev/ofw/openfirm.h> 49 50 #include <machine/vmparam.h> 51 #include <vm/vm.h> 52 #include <vm/pmap.h> 53 54 #include <machine/resource.h> 55 56 #include <powerpc/psim/iobusvar.h> 57 58 struct iobus_softc { 59 phandle_t sc_node; 60 vm_offset_t sc_addr; 61 vm_offset_t sc_size; 62 struct rman sc_mem_rman; 63 }; 64 65 static MALLOC_DEFINE(M_IOBUS, "iobus", "iobus device information"); 66 67 static int iobus_probe(device_t); 68 static int iobus_attach(device_t); 69 static int iobus_print_child(device_t dev, device_t child); 70 static void iobus_probe_nomatch(device_t, device_t); 71 static int iobus_read_ivar(device_t, device_t, int, uintptr_t *); 72 static int iobus_write_ivar(device_t, device_t, int, uintptr_t); 73 static struct rman *iobus_get_rman(device_t, int, u_int); 74 static struct resource *iobus_alloc_resource(device_t, device_t, int, int *, 75 rman_res_t, rman_res_t, rman_res_t, 76 u_int); 77 static int iobus_adjust_resource(device_t, device_t, int, struct resource *, 78 rman_res_t, rman_res_t); 79 static int iobus_activate_resource(device_t, device_t, int, int, 80 struct resource *); 81 static int iobus_deactivate_resource(device_t, device_t, int, int, 82 struct resource *); 83 static int iobus_map_resource(device_t, device_t, int, struct resource *, 84 struct resource_map_request *, 85 struct resource_map *); 86 static int iobus_unmap_resource(device_t, device_t, int, struct resource *, 87 struct resource_map *); 88 static int iobus_release_resource(device_t, device_t, int, int, 89 struct resource *); 90 91 /* 92 * Bus interface definition 93 */ 94 static device_method_t iobus_methods[] = { 95 /* Device interface */ 96 DEVMETHOD(device_probe, iobus_probe), 97 DEVMETHOD(device_attach, iobus_attach), 98 DEVMETHOD(device_detach, bus_generic_detach), 99 DEVMETHOD(device_shutdown, bus_generic_shutdown), 100 DEVMETHOD(device_suspend, bus_generic_suspend), 101 DEVMETHOD(device_resume, bus_generic_resume), 102 103 /* Bus interface */ 104 DEVMETHOD(bus_print_child, iobus_print_child), 105 DEVMETHOD(bus_probe_nomatch, iobus_probe_nomatch), 106 DEVMETHOD(bus_read_ivar, iobus_read_ivar), 107 DEVMETHOD(bus_write_ivar, iobus_write_ivar), 108 DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), 109 DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), 110 111 DEVMETHOD(bus_get_rman, iobus_get_rman), 112 DEVMETHOD(bus_alloc_resource, iobus_alloc_resource), 113 DEVMETHOD(bus_adjust_resource, iobus_adjust_resource), 114 DEVMETHOD(bus_release_resource, iobus_release_resource), 115 DEVMETHOD(bus_activate_resource, iobus_activate_resource), 116 DEVMETHOD(bus_deactivate_resource, iobus_deactivate_resource), 117 DEVMETHOD(bus_map_resource, iobus_map_resource), 118 DEVMETHOD(bus_unmap_resource, iobus_unmap_resource), 119 { 0, 0 } 120 }; 121 122 static driver_t iobus_driver = { 123 "iobus", 124 iobus_methods, 125 sizeof(struct iobus_softc) 126 }; 127 128 DRIVER_MODULE(iobus, ofwbus, iobus_driver, 0, 0); 129 130 static int 131 iobus_probe(device_t dev) 132 { 133 const char *type = ofw_bus_get_name(dev); 134 135 if (strcmp(type, "psim-iobus") != 0) 136 return (ENXIO); 137 138 device_set_desc(dev, "PSIM local bus"); 139 return (0); 140 } 141 142 /* 143 * Add interrupt/addr range to the dev's resource list if present 144 */ 145 static void 146 iobus_add_intr(phandle_t devnode, struct iobus_devinfo *dinfo) 147 { 148 u_int intr = -1; 149 150 if (OF_getprop(devnode, "interrupt", &intr, sizeof(intr)) != -1) { 151 resource_list_add(&dinfo->id_resources, 152 SYS_RES_IRQ, 0, intr, intr, 1); 153 } 154 dinfo->id_interrupt = intr; 155 } 156 157 static void 158 iobus_add_reg(phandle_t devnode, struct iobus_devinfo *dinfo, 159 vm_offset_t iobus_off) 160 { 161 u_int size; 162 int i; 163 164 size = OF_getprop(devnode, "reg", dinfo->id_reg,sizeof(dinfo->id_reg)); 165 166 if (size != -1) { 167 dinfo->id_nregs = size / (sizeof(dinfo->id_reg[0])); 168 169 for (i = 0; i < dinfo->id_nregs; i+= 3) { 170 /* 171 * Scale the absolute addresses back to iobus 172 * relative offsets. This is to better simulate 173 * macio 174 */ 175 dinfo->id_reg[i+1] -= iobus_off; 176 177 resource_list_add(&dinfo->id_resources, 178 SYS_RES_MEMORY, 0, 179 dinfo->id_reg[i+1], 180 dinfo->id_reg[i+1] + 181 dinfo->id_reg[i+2], 182 dinfo->id_reg[i+2]); 183 } 184 } 185 } 186 187 static int 188 iobus_attach(device_t dev) 189 { 190 struct iobus_softc *sc; 191 struct iobus_devinfo *dinfo; 192 phandle_t root; 193 phandle_t child; 194 device_t cdev; 195 char *name; 196 u_int reg[2]; 197 int size; 198 199 sc = device_get_softc(dev); 200 sc->sc_node = ofw_bus_get_node(dev); 201 202 /* 203 * Find the base addr/size of the iobus, and initialize the 204 * resource manager 205 */ 206 size = OF_getprop(sc->sc_node, "reg", reg, sizeof(reg)); 207 if (size == sizeof(reg)) { 208 sc->sc_addr = reg[0]; 209 sc->sc_size = reg[1]; 210 } else { 211 return (ENXIO); 212 } 213 214 sc->sc_mem_rman.rm_type = RMAN_ARRAY; 215 sc->sc_mem_rman.rm_descr = "IOBus Device Memory"; 216 if (rman_init(&sc->sc_mem_rman) != 0) { 217 device_printf(dev, 218 "failed to init mem range resources\n"); 219 return (ENXIO); 220 } 221 rman_manage_region(&sc->sc_mem_rman, 0, sc->sc_size); 222 223 /* 224 * Iterate through the sub-devices 225 */ 226 root = sc->sc_node; 227 228 for (child = OF_child(root); child != 0; child = OF_peer(child)) { 229 OF_getprop_alloc(child, "name", (void **)&name); 230 231 cdev = device_add_child(dev, NULL, -1); 232 if (cdev != NULL) { 233 dinfo = malloc(sizeof(*dinfo), M_IOBUS, M_WAITOK); 234 memset(dinfo, 0, sizeof(*dinfo)); 235 resource_list_init(&dinfo->id_resources); 236 dinfo->id_node = child; 237 dinfo->id_name = name; 238 iobus_add_intr(child, dinfo); 239 iobus_add_reg(child, dinfo, sc->sc_addr); 240 device_set_ivars(cdev, dinfo); 241 } else { 242 OF_prop_free(name); 243 } 244 } 245 246 return (bus_generic_attach(dev)); 247 } 248 249 static int 250 iobus_print_child(device_t dev, device_t child) 251 { 252 struct iobus_devinfo *dinfo; 253 struct resource_list *rl; 254 int retval = 0; 255 256 dinfo = device_get_ivars(child); 257 rl = &dinfo->id_resources; 258 259 retval += bus_print_child_header(dev, child); 260 261 retval += printf(" offset 0x%x", dinfo->id_reg[1]); 262 retval += resource_list_print_type(rl, "irq", SYS_RES_IRQ, "%jd"); 263 264 retval += bus_print_child_footer(dev, child); 265 266 return (retval); 267 } 268 269 static void 270 iobus_probe_nomatch(device_t dev, device_t child) 271 { 272 } 273 274 static int 275 iobus_read_ivar(device_t dev, device_t child, int which, uintptr_t *result) 276 { 277 struct iobus_devinfo *dinfo; 278 279 if ((dinfo = device_get_ivars(child)) == NULL) 280 return (ENOENT); 281 282 switch (which) { 283 case IOBUS_IVAR_NODE: 284 *result = dinfo->id_node; 285 break; 286 case IOBUS_IVAR_NAME: 287 *result = (uintptr_t)dinfo->id_name; 288 break; 289 case IOBUS_IVAR_NREGS: 290 *result = dinfo->id_nregs; 291 break; 292 case IOBUS_IVAR_REGS: 293 *result = (uintptr_t)dinfo->id_reg; 294 break; 295 default: 296 return (ENOENT); 297 } 298 299 return (0); 300 } 301 302 static int 303 iobus_write_ivar(device_t dev, device_t child, int which, uintptr_t value) 304 { 305 return (EINVAL); 306 } 307 308 static struct rman * 309 iobus_get_rman(device_t bus, int type, u_int flags) 310 { 311 struct iobus_softc *sc; 312 313 sc = device_get_softc(bus); 314 switch (type) { 315 case SYS_RES_MEMORY: 316 case SYS_RES_IOPORT: 317 return (&sc->sc_mem_rman); 318 default: 319 return (NULL); 320 } 321 } 322 323 static struct resource * 324 iobus_alloc_resource(device_t bus, device_t child, int type, int *rid, 325 rman_res_t start, rman_res_t end, rman_res_t count, 326 u_int flags) 327 { 328 329 switch (type) { 330 case SYS_RES_MEMORY: 331 case SYS_RES_IOPORT: 332 return (bus_generic_rman_alloc_resource(bus, child, type, rid, 333 start, end, count, flags)); 334 case SYS_RES_IRQ: 335 return (bus_alloc_resource(bus, type, rid, start, end, count, 336 flags)); 337 default: 338 device_printf(bus, "unknown resource request from %s\n", 339 device_get_nameunit(child)); 340 return (NULL); 341 } 342 } 343 344 static int 345 iobus_adjust_resource(device_t bus, device_t child, int type, 346 struct resource *r, rman_res_t start, rman_res_t end) 347 { 348 349 switch (type) { 350 case SYS_RES_MEMORY: 351 case SYS_RES_IOPORT: 352 return (bus_generic_rman_adjust_resource(bus, child, type, r, 353 start, end)); 354 case SYS_RES_IRQ: 355 return (bus_adjust_resource(bus, type, r, start, end)); 356 default: 357 return (EINVAL); 358 } 359 } 360 361 static int 362 iobus_release_resource(device_t bus, device_t child, int type, int rid, 363 struct resource *res) 364 { 365 366 switch (type) { 367 case SYS_RES_MEMORY: 368 case SYS_RES_IOPORT: 369 return (bus_generic_rman_release_resource(bus, child, type, rid, 370 res)); 371 case SYS_RES_IRQ: 372 return (bus_release_resource(bus, type, rid, res)); 373 default: 374 return (EINVAL); 375 } 376 } 377 378 static int 379 iobus_activate_resource(device_t bus, device_t child, int type, int rid, 380 struct resource *res) 381 { 382 383 switch (type) { 384 case SYS_RES_IRQ: 385 return (bus_activate_resource(bus, type, rid, res)); 386 case SYS_RES_IOPORT: 387 case SYS_RES_MEMORY: 388 return (bus_generic_rman_activate_resource(bus, child, type, 389 rid, res)); 390 default: 391 return (EINVAL); 392 } 393 } 394 395 static int 396 iobus_deactivate_resource(device_t bus, device_t child, int type, int rid, 397 struct resource *res) 398 { 399 400 switch (type) { 401 case SYS_RES_IRQ: 402 return (bus_deactivate_resource(bus, type, rid, res)); 403 case SYS_RES_IOPORT: 404 case SYS_RES_MEMORY: 405 return (bus_generic_rman_deactivate_resource(bus, child, type, 406 rid, res)); 407 default: 408 return (EINVAL); 409 } 410 } 411 412 static int 413 iobus_map_resource(device_t bus, device_t child, int type, struct resource *r, 414 struct resource_map_request *argsp, struct resource_map *map) 415 { 416 struct resource_map_request args; 417 struct iobus_softc *sc; 418 rman_res_t length, start; 419 int error; 420 421 /* Resources must be active to be mapped. */ 422 if (!(rman_get_flags(r) & RF_ACTIVE)) 423 return (ENXIO); 424 425 /* Mappings are only supported on I/O and memory resources. */ 426 switch (type) { 427 case SYS_RES_IOPORT: 428 case SYS_RES_MEMORY: 429 break; 430 default: 431 return (EINVAL); 432 } 433 434 resource_init_map_request(&args); 435 error = resource_validate_map_request(r, argsp, &args, &start, &length); 436 if (error) 437 return (error); 438 439 sc = device_get_softc(bus); 440 map->r_vaddr = pmap_mapdev_attr((vm_paddr_t)start + sc->sc_addr, 441 (vm_size_t)length, args.memattr); 442 if (map->r_vaddr == NULL) 443 return (ENOMEM); 444 map->r_bustag = &bs_le_tag; 445 map->r_bushandle = (vm_offset_t)map->r_vaddr; 446 map->r_size = length; 447 return (0); 448 } 449 450 static int 451 iobus_unmap_resource(device_t bus, device_t child, int type, struct resource *r, 452 struct resource_map *map) 453 { 454 455 switch (type) { 456 case SYS_RES_IOPORT: 457 case SYS_RES_MEMORY: 458 pmap_unmapdev(map->r_vaddr, map->r_size); 459 return (0); 460 default: 461 return (EINVAL); 462 } 463 } 464