1208747Sraj/*- 2208747Sraj * Copyright (c) 2009-2010 The FreeBSD Foundation 3208747Sraj * All rights reserved. 4208747Sraj * 5208747Sraj * This software was developed by Semihalf under sponsorship from 6208747Sraj * the FreeBSD Foundation. 7208747Sraj * 8208747Sraj * Redistribution and use in source and binary forms, with or without 9208747Sraj * modification, are permitted provided that the following conditions 10208747Sraj * are met: 11208747Sraj * 1. Redistributions of source code must retain the above copyright 12208747Sraj * notice, this list of conditions and the following disclaimer. 13208747Sraj * 2. Redistributions in binary form must reproduce the above copyright 14208747Sraj * notice, this list of conditions and the following disclaimer in the 15208747Sraj * documentation and/or other materials provided with the distribution. 16208747Sraj * 17208747Sraj * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18208747Sraj * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19208747Sraj * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20208747Sraj * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21208747Sraj * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22208747Sraj * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23208747Sraj * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24208747Sraj * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25208747Sraj * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26208747Sraj * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27208747Sraj * SUCH DAMAGE. 28208747Sraj */ 29208747Sraj 30208747Sraj#include <sys/cdefs.h> 31208747Sraj__FBSDID("$FreeBSD$"); 32208747Sraj 33208747Sraj#include <sys/param.h> 34208747Sraj#include <sys/systm.h> 35208747Sraj#include <sys/ktr.h> 36208747Sraj#include <sys/kernel.h> 37208747Sraj#include <sys/module.h> 38208747Sraj#include <sys/bus.h> 39208747Sraj#include <sys/rman.h> 40208747Sraj#include <sys/malloc.h> 41208747Sraj 42218076Smarcel#include <machine/fdt.h> 43218076Smarcel 44208747Sraj#include <dev/ofw/openfirm.h> 45208747Sraj 46208747Sraj#include "fdt_common.h" 47208747Sraj#include "ofw_bus_if.h" 48208747Sraj 49208747Sraj#ifdef DEBUG 50208747Sraj#define debugf(fmt, args...) do { printf("%s(): ", __func__); \ 51208747Sraj printf(fmt,##args); } while (0) 52208747Sraj#else 53208747Sraj#define debugf(fmt, args...) 54208747Sraj#endif 55208747Sraj 56208747Srajstatic MALLOC_DEFINE(M_FDTBUS, "fdtbus", "FDTbus devices information"); 57208747Sraj 58208747Srajstruct fdtbus_devinfo { 59208747Sraj phandle_t di_node; 60208747Sraj char *di_name; 61208747Sraj char *di_type; 62208747Sraj char *di_compat; 63208747Sraj struct resource_list di_res; 64208747Sraj 65208747Sraj /* Interrupts sense-level info for this device */ 66208747Sraj struct fdt_sense_level di_intr_sl[DI_MAX_INTR_NUM]; 67208747Sraj}; 68208747Sraj 69208747Srajstruct fdtbus_softc { 70208747Sraj struct rman sc_irq; 71208747Sraj struct rman sc_mem; 72208747Sraj}; 73208747Sraj 74208747Sraj/* 75208747Sraj * Prototypes. 76208747Sraj */ 77209127Srajstatic void fdtbus_identify(driver_t *, device_t); 78208747Srajstatic int fdtbus_probe(device_t); 79208747Srajstatic int fdtbus_attach(device_t); 80208747Sraj 81208747Srajstatic int fdtbus_print_child(device_t, device_t); 82208747Srajstatic struct resource *fdtbus_alloc_resource(device_t, device_t, int, 83208747Sraj int *, u_long, u_long, u_long, u_int); 84208747Srajstatic int fdtbus_release_resource(device_t, device_t, int, int, 85208747Sraj struct resource *); 86208747Srajstatic int fdtbus_activate_resource(device_t, device_t, int, int, 87208747Sraj struct resource *); 88208747Srajstatic int fdtbus_deactivate_resource(device_t, device_t, int, int, 89208747Sraj struct resource *); 90208747Srajstatic int fdtbus_setup_intr(device_t, device_t, struct resource *, int, 91208747Sraj driver_filter_t *, driver_intr_t *, void *, void **); 92208747Sraj 93208747Srajstatic const char *fdtbus_ofw_get_name(device_t, device_t); 94208747Srajstatic phandle_t fdtbus_ofw_get_node(device_t, device_t); 95208747Srajstatic const char *fdtbus_ofw_get_type(device_t, device_t); 96208747Srajstatic const char *fdtbus_ofw_get_compat(device_t, device_t); 97208747Sraj 98208747Sraj/* 99208747Sraj * Local routines. 100208747Sraj */ 101208747Srajstatic void newbus_device_from_fdt_node(device_t, phandle_t); 102208747Sraj 103208747Sraj/* 104208747Sraj * Bus interface definition. 105208747Sraj */ 106208747Srajstatic device_method_t fdtbus_methods[] = { 107208747Sraj /* Device interface */ 108209127Sraj DEVMETHOD(device_identify, fdtbus_identify), 109208747Sraj DEVMETHOD(device_probe, fdtbus_probe), 110208747Sraj DEVMETHOD(device_attach, fdtbus_attach), 111208747Sraj DEVMETHOD(device_detach, bus_generic_detach), 112208747Sraj DEVMETHOD(device_shutdown, bus_generic_shutdown), 113208747Sraj DEVMETHOD(device_suspend, bus_generic_suspend), 114208747Sraj DEVMETHOD(device_resume, bus_generic_resume), 115208747Sraj 116208747Sraj /* Bus interface */ 117208747Sraj DEVMETHOD(bus_print_child, fdtbus_print_child), 118208747Sraj DEVMETHOD(bus_alloc_resource, fdtbus_alloc_resource), 119208747Sraj DEVMETHOD(bus_release_resource, fdtbus_release_resource), 120208747Sraj DEVMETHOD(bus_activate_resource, fdtbus_activate_resource), 121208747Sraj DEVMETHOD(bus_deactivate_resource, fdtbus_deactivate_resource), 122238043Smarcel DEVMETHOD(bus_config_intr, bus_generic_config_intr), 123208747Sraj DEVMETHOD(bus_setup_intr, fdtbus_setup_intr), 124238043Smarcel DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), 125208747Sraj 126208747Sraj /* OFW bus interface */ 127208747Sraj DEVMETHOD(ofw_bus_get_node, fdtbus_ofw_get_node), 128208747Sraj DEVMETHOD(ofw_bus_get_name, fdtbus_ofw_get_name), 129208747Sraj DEVMETHOD(ofw_bus_get_type, fdtbus_ofw_get_type), 130208747Sraj DEVMETHOD(ofw_bus_get_compat, fdtbus_ofw_get_compat), 131208747Sraj 132208747Sraj { 0, 0 } 133208747Sraj}; 134208747Sraj 135208747Srajstatic driver_t fdtbus_driver = { 136208747Sraj "fdtbus", 137208747Sraj fdtbus_methods, 138208747Sraj sizeof(struct fdtbus_softc) 139208747Sraj}; 140208747Sraj 141208747Srajdevclass_t fdtbus_devclass; 142208747Sraj 143208747SrajDRIVER_MODULE(fdtbus, nexus, fdtbus_driver, fdtbus_devclass, 0, 0); 144208747Sraj 145209127Srajstatic void 146209127Srajfdtbus_identify(driver_t *driver, device_t parent) 147209127Sraj{ 148209127Sraj 149218076Smarcel debugf("%s(driver=%p, parent=%p)\n", __func__, driver, parent); 150218076Smarcel 151209127Sraj if (device_find_child(parent, "fdtbus", -1) == NULL) 152209127Sraj BUS_ADD_CHILD(parent, 0, "fdtbus", -1); 153209127Sraj} 154209127Sraj 155208747Srajstatic int 156208747Srajfdtbus_probe(device_t dev) 157208747Sraj{ 158208747Sraj 159218076Smarcel debugf("%s(dev=%p); pass=%u\n", __func__, dev, bus_current_pass); 160218076Smarcel 161208747Sraj device_set_desc(dev, "FDT main bus"); 162208747Sraj if (!bootverbose) 163208747Sraj device_quiet(dev); 164208747Sraj return (BUS_PROBE_DEFAULT); 165208747Sraj} 166208747Sraj 167208747Srajstatic int 168208747Srajfdtbus_attach(device_t dev) 169208747Sraj{ 170208747Sraj phandle_t root; 171208747Sraj phandle_t child; 172208747Sraj struct fdtbus_softc *sc; 173208747Sraj u_long start, end; 174208747Sraj int error; 175208747Sraj 176228201Sjchandra if ((root = OF_finddevice("/")) == -1) 177208747Sraj panic("fdtbus_attach: no root node."); 178208747Sraj 179208747Sraj sc = device_get_softc(dev); 180208747Sraj 181208747Sraj /* 182208747Sraj * IRQ rman. 183208747Sraj */ 184208747Sraj start = 0; 185208747Sraj end = FDT_INTR_MAX - 1; 186208747Sraj sc->sc_irq.rm_start = start; 187208747Sraj sc->sc_irq.rm_end = end; 188208747Sraj sc->sc_irq.rm_type = RMAN_ARRAY; 189208747Sraj sc->sc_irq.rm_descr = "Interrupt request lines"; 190208747Sraj if ((error = rman_init(&sc->sc_irq)) != 0) { 191208747Sraj device_printf(dev, "could not init IRQ rman, error = %d\n", 192208747Sraj error); 193208747Sraj return (error); 194208747Sraj } 195208747Sraj if ((error = rman_manage_region(&sc->sc_irq, start, end)) != 0) { 196208747Sraj device_printf(dev, "could not manage IRQ region, error = %d\n", 197208747Sraj error); 198208747Sraj return (error); 199208747Sraj } 200208747Sraj 201208747Sraj /* 202208747Sraj * Mem-mapped I/O space rman. 203208747Sraj */ 204208747Sraj start = 0; 205221218Sjhb end = ~0ul; 206208747Sraj sc->sc_mem.rm_start = start; 207208747Sraj sc->sc_mem.rm_end = end; 208208747Sraj sc->sc_mem.rm_type = RMAN_ARRAY; 209208747Sraj sc->sc_mem.rm_descr = "I/O memory"; 210208747Sraj if ((error = rman_init(&sc->sc_mem)) != 0) { 211208747Sraj device_printf(dev, "could not init I/O mem rman, error = %d\n", 212208747Sraj error); 213208747Sraj return (error); 214208747Sraj } 215208747Sraj if ((error = rman_manage_region(&sc->sc_mem, start, end)) != 0) { 216208747Sraj device_printf(dev, "could not manage I/O mem region, " 217208747Sraj "error = %d\n", error); 218208747Sraj return (error); 219208747Sraj } 220208747Sraj 221208747Sraj /* 222208747Sraj * Walk the FDT root node and add top-level devices as our children. 223208747Sraj */ 224208747Sraj for (child = OF_child(root); child != 0; child = OF_peer(child)) { 225208747Sraj /* Check and process 'status' property. */ 226208747Sraj if (!(fdt_is_enabled(child))) 227208747Sraj continue; 228208747Sraj 229208747Sraj newbus_device_from_fdt_node(dev, child); 230208747Sraj } 231208747Sraj 232208747Sraj return (bus_generic_attach(dev)); 233208747Sraj} 234208747Sraj 235208747Srajstatic int 236208747Srajfdtbus_print_child(device_t dev, device_t child) 237208747Sraj{ 238208747Sraj struct fdtbus_devinfo *di; 239208747Sraj struct resource_list *rl; 240208747Sraj int rv; 241208747Sraj 242208747Sraj di = device_get_ivars(child); 243208747Sraj rl = &di->di_res; 244208747Sraj 245208747Sraj rv = 0; 246208747Sraj rv += bus_print_child_header(dev, child); 247208747Sraj rv += resource_list_print_type(rl, "mem", SYS_RES_MEMORY, "%#lx"); 248208747Sraj rv += resource_list_print_type(rl, "irq", SYS_RES_IRQ, "%ld"); 249208747Sraj rv += bus_print_child_footer(dev, child); 250208747Sraj 251208747Sraj return (rv); 252208747Sraj} 253208747Sraj 254208747Srajstatic void 255208747Srajnewbus_device_destroy(device_t dev) 256208747Sraj{ 257208747Sraj struct fdtbus_devinfo *di; 258208747Sraj 259208747Sraj di = device_get_ivars(dev); 260244871Srwatson if (di == NULL) 261244871Srwatson return; 262208747Sraj 263208747Sraj free(di->di_name, M_OFWPROP); 264208747Sraj free(di->di_type, M_OFWPROP); 265208747Sraj free(di->di_compat, M_OFWPROP); 266208747Sraj 267208747Sraj resource_list_free(&di->di_res); 268208747Sraj free(di, M_FDTBUS); 269208747Sraj} 270208747Sraj 271208747Srajstatic device_t 272208747Srajnewbus_device_create(device_t dev_par, phandle_t node, char *name, char *type, 273208747Sraj char *compat) 274208747Sraj{ 275208747Sraj device_t child; 276208747Sraj struct fdtbus_devinfo *di; 277208747Sraj 278208747Sraj child = device_add_child(dev_par, NULL, -1); 279208747Sraj if (child == NULL) { 280208747Sraj free(name, M_OFWPROP); 281208747Sraj free(type, M_OFWPROP); 282208747Sraj free(compat, M_OFWPROP); 283208747Sraj return (NULL); 284208747Sraj } 285208747Sraj 286208747Sraj di = malloc(sizeof(*di), M_FDTBUS, M_WAITOK); 287208747Sraj di->di_node = node; 288208747Sraj di->di_name = name; 289208747Sraj di->di_type = type; 290208747Sraj di->di_compat = compat; 291208747Sraj 292208747Sraj resource_list_init(&di->di_res); 293208747Sraj 294239274Sgonzo if (fdt_reg_to_rl(node, &di->di_res)) { 295208747Sraj device_printf(child, "could not process 'reg' property\n"); 296208747Sraj newbus_device_destroy(child); 297208747Sraj child = NULL; 298208747Sraj goto out; 299208747Sraj } 300208747Sraj 301208747Sraj if (fdt_intr_to_rl(node, &di->di_res, di->di_intr_sl)) { 302208747Sraj device_printf(child, "could not process 'interrupts' " 303208747Sraj "property\n"); 304208747Sraj newbus_device_destroy(child); 305208747Sraj child = NULL; 306208747Sraj goto out; 307208747Sraj } 308208747Sraj 309208747Sraj device_set_ivars(child, di); 310208747Sraj debugf("added child name='%s', node=%p\n", name, (void *)node); 311208747Sraj 312208747Srajout: 313208747Sraj return (child); 314208747Sraj} 315208747Sraj 316208747Srajstatic device_t 317208747Srajnewbus_pci_create(device_t dev_par, phandle_t dt_node, u_long par_base, 318208747Sraj u_long par_size) 319208747Sraj{ 320208747Sraj pcell_t reg[3 + 2]; 321208747Sraj device_t dev_child; 322208747Sraj u_long start, end, count; 323208747Sraj struct fdtbus_devinfo *di; 324208747Sraj char *name, *type, *compat; 325208747Sraj int len; 326208747Sraj 327208747Sraj OF_getprop_alloc(dt_node, "device_type", 1, (void **)&type); 328208747Sraj if (!(type != NULL && strcmp(type, "pci") == 0)) { 329208747Sraj /* Only process 'pci' subnodes. */ 330208747Sraj free(type, M_OFWPROP); 331208747Sraj return (NULL); 332208747Sraj } 333208747Sraj 334208747Sraj OF_getprop_alloc(dt_node, "name", 1, (void **)&name); 335208747Sraj OF_getprop_alloc(OF_parent(dt_node), "compatible", 1, 336208747Sraj (void **)&compat); 337208747Sraj 338208747Sraj dev_child = device_add_child(dev_par, NULL, -1); 339208747Sraj if (dev_child == NULL) { 340208747Sraj free(name, M_OFWPROP); 341208747Sraj free(type, M_OFWPROP); 342208747Sraj free(compat, M_OFWPROP); 343208747Sraj return (NULL); 344208747Sraj } 345208747Sraj 346208747Sraj di = malloc(sizeof(*di), M_FDTBUS, M_WAITOK); 347208747Sraj di->di_node = dt_node; 348208747Sraj di->di_name = name; 349208747Sraj di->di_type = type; 350208747Sraj di->di_compat = compat; 351208747Sraj 352208747Sraj resource_list_init(&di->di_res); 353208747Sraj 354208747Sraj /* 355208747Sraj * Produce and set SYS_RES_MEMORY resources. 356208747Sraj */ 357208747Sraj start = 0; 358208747Sraj count = 0; 359208747Sraj 360208747Sraj len = OF_getprop(dt_node, "reg", ®, sizeof(reg)); 361208747Sraj if (len > 0) { 362208747Sraj if (fdt_data_verify((void *)®[1], 2) != 0) { 363208747Sraj device_printf(dev_child, "'reg' address value out of " 364208747Sraj "range\n"); 365208747Sraj newbus_device_destroy(dev_child); 366208747Sraj dev_child = NULL; 367208747Sraj goto out; 368208747Sraj } 369208747Sraj start = fdt_data_get((void *)®[1], 2); 370208747Sraj 371208747Sraj if (fdt_data_verify((void *)®[3], 2) != 0) { 372208747Sraj device_printf(dev_child, "'reg' size value out of " 373208747Sraj "range\n"); 374208747Sraj newbus_device_destroy(dev_child); 375208747Sraj dev_child = NULL; 376208747Sraj goto out; 377208747Sraj } 378208747Sraj count = fdt_data_get((void *)®[3], 2); 379208747Sraj } 380208747Sraj 381208747Sraj /* Calculate address range relative to base. */ 382208747Sraj par_base &= 0x000ffffful; 383208747Sraj start &= 0x000ffffful; 384208747Sraj start += par_base + fdt_immr_va; 385208747Sraj if (count == 0) 386208747Sraj count = par_size; 387208747Sraj end = start + count - 1; 388208747Sraj 389208747Sraj debugf("start = 0x%08lx, end = 0x%08lx, count = 0x%08lx\n", 390208747Sraj start, end, count); 391208747Sraj 392208747Sraj if (count > par_size) { 393208747Sraj device_printf(dev_child, "'reg' size value out of range\n"); 394208747Sraj newbus_device_destroy(dev_child); 395208747Sraj dev_child = NULL; 396208747Sraj goto out; 397208747Sraj } 398208747Sraj 399208747Sraj resource_list_add(&di->di_res, SYS_RES_MEMORY, 0, start, end, count); 400208747Sraj 401208747Sraj /* 402208747Sraj * Set SYS_RES_IRQ resources. 403208747Sraj */ 404208747Sraj if (fdt_intr_to_rl(OF_parent(dt_node), &di->di_res, di->di_intr_sl)) { 405208747Sraj device_printf(dev_child, "could not process 'interrupts' " 406208747Sraj "property\n"); 407208747Sraj newbus_device_destroy(dev_child); 408208747Sraj dev_child = NULL; 409208747Sraj goto out; 410208747Sraj } 411208747Sraj 412208747Sraj device_set_ivars(dev_child, di); 413208747Sraj debugf("added child name='%s', node=%p\n", name, 414208747Sraj (void *)dt_node); 415208747Sraj 416208747Srajout: 417208747Sraj return (dev_child); 418208747Sraj} 419208747Sraj 420208747Srajstatic void 421208747Srajpci_from_fdt_node(device_t dev_par, phandle_t dt_node, char *name, 422208747Sraj char *type, char *compat) 423208747Sraj{ 424208747Sraj u_long reg_base, reg_size; 425208747Sraj phandle_t dt_child; 426208747Sraj 427208747Sraj /* 428208747Sraj * Retrieve 'reg' property. 429208747Sraj */ 430208747Sraj if (fdt_regsize(dt_node, ®_base, ®_size) != 0) { 431208747Sraj device_printf(dev_par, "could not retrieve 'reg' prop\n"); 432208747Sraj return; 433208747Sraj } 434208747Sraj 435208747Sraj /* 436208747Sraj * Walk the PCI node and instantiate newbus devices representing 437208747Sraj * logical resources (bridges / ports). 438208747Sraj */ 439208747Sraj for (dt_child = OF_child(dt_node); dt_child != 0; 440208747Sraj dt_child = OF_peer(dt_child)) { 441208747Sraj 442208747Sraj if (!(fdt_is_enabled(dt_child))) 443208747Sraj continue; 444208747Sraj 445208747Sraj newbus_pci_create(dev_par, dt_child, reg_base, reg_size); 446208747Sraj } 447208747Sraj} 448208747Sraj 449208747Sraj/* 450208747Sraj * These FDT nodes do not need a corresponding newbus device object. 451208747Sraj */ 452208747Srajstatic char *fdt_devices_skip[] = { 453208747Sraj "aliases", 454208747Sraj "chosen", 455208747Sraj "memory", 456208747Sraj NULL 457208747Sraj}; 458208747Sraj 459208747Srajstatic void 460208747Srajnewbus_device_from_fdt_node(device_t dev_par, phandle_t node) 461208747Sraj{ 462208747Sraj char *name, *type, *compat; 463208747Sraj device_t child; 464208747Sraj int i; 465208747Sraj 466208747Sraj OF_getprop_alloc(node, "name", 1, (void **)&name); 467208747Sraj OF_getprop_alloc(node, "device_type", 1, (void **)&type); 468208747Sraj OF_getprop_alloc(node, "compatible", 1, (void **)&compat); 469208747Sraj 470208747Sraj for (i = 0; fdt_devices_skip[i] != NULL; i++) 471208747Sraj if (name != NULL && strcmp(name, fdt_devices_skip[i]) == 0) { 472208747Sraj debugf("skipping instantiating FDT device='%s'\n", 473208747Sraj name); 474208747Sraj return; 475208747Sraj } 476208747Sraj 477208747Sraj child = newbus_device_create(dev_par, node, name, type, compat); 478218076Smarcel if (type != NULL && strcmp(type, "pci") == 0) 479218076Smarcel pci_from_fdt_node(child, node, name, type, compat); 480208747Sraj} 481208747Sraj 482208747Srajstatic struct resource * 483208747Srajfdtbus_alloc_resource(device_t bus, device_t child, int type, int *rid, 484208747Sraj u_long start, u_long end, u_long count, u_int flags) 485208747Sraj{ 486208747Sraj struct fdtbus_softc *sc; 487208747Sraj struct resource *res; 488208747Sraj struct rman *rm; 489208747Sraj struct fdtbus_devinfo *di; 490208747Sraj struct resource_list_entry *rle; 491208747Sraj int needactivate; 492208747Sraj 493208747Sraj /* 494208747Sraj * Request for the default allocation with a given rid: use resource 495208747Sraj * list stored in the local device info. 496208747Sraj */ 497208747Sraj if ((start == 0UL) && (end == ~0UL)) { 498208747Sraj if ((di = device_get_ivars(child)) == NULL) 499208747Sraj return (NULL); 500208747Sraj 501208747Sraj if (type == SYS_RES_IOPORT) 502208747Sraj type = SYS_RES_MEMORY; 503208747Sraj 504208747Sraj rle = resource_list_find(&di->di_res, type, *rid); 505208747Sraj if (rle == NULL) { 506208747Sraj device_printf(bus, "no default resources for " 507208747Sraj "rid = %d, type = %d\n", *rid, type); 508208747Sraj return (NULL); 509208747Sraj } 510208747Sraj start = rle->start; 511208747Sraj end = rle->end; 512208747Sraj count = rle->count; 513208747Sraj } 514208747Sraj 515208747Sraj sc = device_get_softc(bus); 516208747Sraj 517208747Sraj needactivate = flags & RF_ACTIVE; 518208747Sraj flags &= ~RF_ACTIVE; 519208747Sraj 520208747Sraj switch (type) { 521208747Sraj case SYS_RES_IRQ: 522208747Sraj rm = &sc->sc_irq; 523208747Sraj break; 524208747Sraj 525208747Sraj case SYS_RES_IOPORT: 526208747Sraj case SYS_RES_MEMORY: 527208747Sraj rm = &sc->sc_mem; 528208747Sraj break; 529208747Sraj 530208747Sraj default: 531208747Sraj return (NULL); 532208747Sraj } 533208747Sraj 534208747Sraj res = rman_reserve_resource(rm, start, end, count, flags, child); 535208747Sraj if (res == NULL) { 536208747Sraj device_printf(bus, "failed to reserve resource %#lx - %#lx " 537208747Sraj "(%#lx)\n", start, end, count); 538208747Sraj return (NULL); 539208747Sraj } 540208747Sraj 541208747Sraj rman_set_rid(res, *rid); 542208747Sraj 543208747Sraj if (type == SYS_RES_IOPORT || type == SYS_RES_MEMORY) { 544208747Sraj /* XXX endianess should be set based on SOC node */ 545208747Sraj rman_set_bustag(res, fdtbus_bs_tag); 546208747Sraj rman_set_bushandle(res, rman_get_start(res)); 547208747Sraj } 548208747Sraj 549208747Sraj if (needactivate) 550208747Sraj if (bus_activate_resource(child, type, *rid, res)) { 551208747Sraj device_printf(child, "resource activation failed\n"); 552208747Sraj rman_release_resource(res); 553208747Sraj return (NULL); 554208747Sraj } 555208747Sraj 556208747Sraj return (res); 557208747Sraj} 558208747Sraj 559208747Srajstatic int 560208747Srajfdtbus_release_resource(device_t bus, device_t child, int type, int rid, 561208747Sraj struct resource *res) 562208747Sraj{ 563208747Sraj int err; 564208747Sraj 565208747Sraj if (rman_get_flags(res) & RF_ACTIVE) { 566208747Sraj err = bus_deactivate_resource(child, type, rid, res); 567208747Sraj if (err) 568208747Sraj return (err); 569208747Sraj } 570208747Sraj 571208747Sraj return (rman_release_resource(res)); 572208747Sraj} 573208747Sraj 574208747Srajstatic int 575208747Srajfdtbus_setup_intr(device_t bus, device_t child, struct resource *res, 576208747Sraj int flags, driver_filter_t *filter, driver_intr_t *ihand, void *arg, 577208747Sraj void **cookiep) 578208747Sraj{ 579238043Smarcel struct fdtbus_devinfo *di; 580238043Smarcel enum intr_trigger trig; 581238043Smarcel enum intr_polarity pol; 582238043Smarcel int error, rid; 583208747Sraj 584238043Smarcel if (res == NULL) 585238043Smarcel return (EINVAL); 586208747Sraj 587238043Smarcel /* 588238043Smarcel * We are responsible for configuring the interrupts of our direct 589238043Smarcel * children. 590238043Smarcel */ 591238043Smarcel if (device_get_parent(child) == bus) { 592238043Smarcel di = device_get_ivars(child); 593238043Smarcel if (di == NULL) 594238043Smarcel return (ENXIO); 595208747Sraj 596238043Smarcel rid = rman_get_rid(res); 597238043Smarcel if (rid >= DI_MAX_INTR_NUM) 598238043Smarcel return (ENOENT); 599208747Sraj 600238043Smarcel trig = di->di_intr_sl[rid].trig; 601238043Smarcel pol = di->di_intr_sl[rid].pol; 602238043Smarcel if (trig != INTR_TRIGGER_CONFORM || 603238043Smarcel pol != INTR_POLARITY_CONFORM) { 604238043Smarcel error = bus_generic_config_intr(bus, 605238043Smarcel rman_get_start(res), trig, pol); 606238043Smarcel if (error) 607238043Smarcel return (error); 608238043Smarcel } 609238043Smarcel } 610238043Smarcel 611238043Smarcel error = bus_generic_setup_intr(bus, child, res, flags, filter, ihand, 612238043Smarcel arg, cookiep); 613238043Smarcel return (error); 614208747Sraj} 615208747Sraj 616208747Srajstatic int 617208747Srajfdtbus_activate_resource(device_t bus, device_t child, int type, int rid, 618208747Sraj struct resource *res) 619208747Sraj{ 620248467Sray bus_space_handle_t p; 621248467Sray int error; 622208747Sraj 623248467Sray if (type == SYS_RES_MEMORY || type == SYS_RES_IOPORT) { 624248467Sray error = bus_space_map(rman_get_bustag(res), 625248467Sray rman_get_bushandle(res), rman_get_size(res), 0, &p); 626248467Sray if (error) 627248467Sray return (error); 628248467Sray rman_set_bushandle(res, p); 629248467Sray } 630248467Sray 631208747Sraj return (rman_activate_resource(res)); 632208747Sraj} 633208747Sraj 634208747Srajstatic int 635208747Srajfdtbus_deactivate_resource(device_t bus, device_t child, int type, int rid, 636208747Sraj struct resource *res) 637208747Sraj{ 638208747Sraj 639208747Sraj return (rman_deactivate_resource(res)); 640208747Sraj} 641208747Sraj 642208747Srajstatic const char * 643208747Srajfdtbus_ofw_get_name(device_t bus, device_t dev) 644208747Sraj{ 645208747Sraj struct fdtbus_devinfo *di; 646208747Sraj 647208747Sraj return ((di = device_get_ivars(dev)) == NULL ? NULL : di->di_name); 648208747Sraj} 649208747Sraj 650208747Srajstatic phandle_t 651208747Srajfdtbus_ofw_get_node(device_t bus, device_t dev) 652208747Sraj{ 653208747Sraj struct fdtbus_devinfo *di; 654208747Sraj 655208747Sraj return ((di = device_get_ivars(dev)) == NULL ? 0 : di->di_node); 656208747Sraj} 657208747Sraj 658208747Srajstatic const char * 659208747Srajfdtbus_ofw_get_type(device_t bus, device_t dev) 660208747Sraj{ 661208747Sraj struct fdtbus_devinfo *di; 662208747Sraj 663208747Sraj return ((di = device_get_ivars(dev)) == NULL ? NULL : di->di_type); 664208747Sraj} 665208747Sraj 666208747Srajstatic const char * 667208747Srajfdtbus_ofw_get_compat(device_t bus, device_t dev) 668208747Sraj{ 669208747Sraj struct fdtbus_devinfo *di; 670208747Sraj 671208747Sraj return ((di = device_get_ivars(dev)) == NULL ? NULL : di->di_compat); 672208747Sraj} 673208747Sraj 674208747Sraj 675