fdtbus.c revision 228984
140024Sgibbs/*- 240024Sgibbs * Copyright (c) 2009-2010 The FreeBSD Foundation 340024Sgibbs * All rights reserved. 440024Sgibbs * 540024Sgibbs * This software was developed by Semihalf under sponsorship from 640024Sgibbs * the FreeBSD Foundation. 756979Sgibbs * 840024Sgibbs * Redistribution and use in source and binary forms, with or without 956979Sgibbs * modification, are permitted provided that the following conditions 1040024Sgibbs * are met: 1140024Sgibbs * 1. Redistributions of source code must retain the above copyright 1240024Sgibbs * notice, this list of conditions and the following disclaimer. 1340024Sgibbs * 2. Redistributions in binary form must reproduce the above copyright 1440024Sgibbs * notice, this list of conditions and the following disclaimer in the 1540024Sgibbs * documentation and/or other materials provided with the distribution. 1640024Sgibbs * 1756979Sgibbs * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1840024Sgibbs * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1940024Sgibbs * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2040024Sgibbs * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2140024Sgibbs * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2240024Sgibbs * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2340024Sgibbs * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2440024Sgibbs * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2540024Sgibbs * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2640024Sgibbs * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2740024Sgibbs * SUCH DAMAGE. 2840024Sgibbs */ 2940024Sgibbs 3040024Sgibbs#include <sys/cdefs.h> 3140024Sgibbs__FBSDID("$FreeBSD: head/sys/dev/fdt/fdtbus.c 228984 2011-12-30 04:00:31Z marcel $"); 3240024Sgibbs 3350477Speter#include <sys/param.h> 3440024Sgibbs#include <sys/systm.h> 3540024Sgibbs#include <sys/ktr.h> 3640024Sgibbs#include <sys/kernel.h> 3740024Sgibbs#include <sys/module.h> 3840024Sgibbs#include <sys/bus.h> 3940024Sgibbs#include <sys/rman.h> 4040024Sgibbs#include <sys/malloc.h> 4140024Sgibbs 4240024Sgibbs#include <machine/fdt.h> 4340024Sgibbs 4440024Sgibbs#include <dev/ofw/openfirm.h> 4540024Sgibbs 4640024Sgibbs#include "fdt_common.h" 4740024Sgibbs#include "ofw_bus_if.h" 4840024Sgibbs 4940024Sgibbs#ifdef DEBUG 5040024Sgibbs#define debugf(fmt, args...) do { printf("%s(): ", __func__); \ 5140024Sgibbs printf(fmt,##args); } while (0) 52117126Sscottl#else 53117126Sscottl#define debugf(fmt, args...) 5456979Sgibbs#endif 5540024Sgibbs 5640024Sgibbsstatic MALLOC_DEFINE(M_FDTBUS, "fdtbus", "FDTbus devices information"); 5740024Sgibbs 5840024Sgibbsstruct fdtbus_devinfo { 5956979Sgibbs phandle_t di_node; 6040024Sgibbs char *di_name; 6156979Sgibbs char *di_type; 6256979Sgibbs char *di_compat; 6340024Sgibbs struct resource_list di_res; 6440024Sgibbs 6540024Sgibbs /* Interrupts sense-level info for this device */ 6640024Sgibbs struct fdt_sense_level di_intr_sl[DI_MAX_INTR_NUM]; 6740024Sgibbs}; 6840024Sgibbs 6940024Sgibbsstruct fdtbus_softc { 7040024Sgibbs struct rman sc_irq; 7140024Sgibbs struct rman sc_mem; 7240024Sgibbs}; 7340024Sgibbs 7440024Sgibbs/* 7540024Sgibbs * Prototypes. 7640024Sgibbs */ 7740024Sgibbsstatic void fdtbus_identify(driver_t *, device_t); 7840024Sgibbsstatic int fdtbus_probe(device_t); 7957679Sgibbsstatic int fdtbus_attach(device_t); 8040024Sgibbs 8140024Sgibbsstatic int fdtbus_print_child(device_t, device_t); 8240024Sgibbsstatic struct resource *fdtbus_alloc_resource(device_t, device_t, int, 8340024Sgibbs int *, u_long, u_long, u_long, u_int); 8440024Sgibbsstatic int fdtbus_release_resource(device_t, device_t, int, int, 8540024Sgibbs struct resource *); 8640024Sgibbsstatic int fdtbus_activate_resource(device_t, device_t, int, int, 8740024Sgibbs struct resource *); 8840024Sgibbsstatic int fdtbus_deactivate_resource(device_t, device_t, int, int, 8940024Sgibbs struct resource *); 9040024Sgibbsstatic int fdtbus_setup_intr(device_t, device_t, struct resource *, int, 9140024Sgibbs driver_filter_t *, driver_intr_t *, void *, void **); 9240024Sgibbsstatic int fdtbus_teardown_intr(device_t, device_t, struct resource *, 9340024Sgibbs void *); 9440024Sgibbs 9540024Sgibbsstatic const char *fdtbus_ofw_get_name(device_t, device_t); 9640024Sgibbsstatic phandle_t fdtbus_ofw_get_node(device_t, device_t); 9740024Sgibbsstatic const char *fdtbus_ofw_get_type(device_t, device_t); 9840024Sgibbsstatic const char *fdtbus_ofw_get_compat(device_t, device_t); 9940024Sgibbs 10040024Sgibbs/* 10140024Sgibbs * Local routines. 10240024Sgibbs */ 10357679Sgibbsstatic void newbus_device_from_fdt_node(device_t, phandle_t); 10457679Sgibbs 10557679Sgibbs/* 10657679Sgibbs * Bus interface definition. 10757679Sgibbs */ 10857679Sgibbsstatic device_method_t fdtbus_methods[] = { 10940024Sgibbs /* Device interface */ 11040024Sgibbs DEVMETHOD(device_identify, fdtbus_identify), 11140024Sgibbs DEVMETHOD(device_probe, fdtbus_probe), 11240024Sgibbs DEVMETHOD(device_attach, fdtbus_attach), 11340024Sgibbs DEVMETHOD(device_detach, bus_generic_detach), 11440024Sgibbs DEVMETHOD(device_shutdown, bus_generic_shutdown), 11540024Sgibbs DEVMETHOD(device_suspend, bus_generic_suspend), 11640024Sgibbs DEVMETHOD(device_resume, bus_generic_resume), 11740024Sgibbs 11840024Sgibbs /* Bus interface */ 11940024Sgibbs DEVMETHOD(bus_print_child, fdtbus_print_child), 12040024Sgibbs DEVMETHOD(bus_alloc_resource, fdtbus_alloc_resource), 12140024Sgibbs DEVMETHOD(bus_release_resource, fdtbus_release_resource), 12240024Sgibbs DEVMETHOD(bus_activate_resource, fdtbus_activate_resource), 12340024Sgibbs DEVMETHOD(bus_deactivate_resource, fdtbus_deactivate_resource), 12440024Sgibbs DEVMETHOD(bus_setup_intr, fdtbus_setup_intr), 12540024Sgibbs DEVMETHOD(bus_teardown_intr, fdtbus_teardown_intr), 12640024Sgibbs 12740024Sgibbs /* OFW bus interface */ 12840024Sgibbs DEVMETHOD(ofw_bus_get_node, fdtbus_ofw_get_node), 12940024Sgibbs DEVMETHOD(ofw_bus_get_name, fdtbus_ofw_get_name), 13040024Sgibbs DEVMETHOD(ofw_bus_get_type, fdtbus_ofw_get_type), 13140024Sgibbs DEVMETHOD(ofw_bus_get_compat, fdtbus_ofw_get_compat), 13240024Sgibbs 13340024Sgibbs { 0, 0 } 13440024Sgibbs}; 13540024Sgibbs 13640024Sgibbsstatic driver_t fdtbus_driver = { 13740024Sgibbs "fdtbus", 13840024Sgibbs fdtbus_methods, 13940024Sgibbs sizeof(struct fdtbus_softc) 14040024Sgibbs}; 14140024Sgibbs 14240024Sgibbsdevclass_t fdtbus_devclass; 14340024Sgibbs 14440024SgibbsDRIVER_MODULE(fdtbus, nexus, fdtbus_driver, fdtbus_devclass, 0, 0); 14540024Sgibbs 14640024Sgibbsstatic void 14740024Sgibbsfdtbus_identify(driver_t *driver, device_t parent) 14840024Sgibbs{ 14940024Sgibbs 15040024Sgibbs debugf("%s(driver=%p, parent=%p)\n", __func__, driver, parent); 15140024Sgibbs 15240024Sgibbs if (device_find_child(parent, "fdtbus", -1) == NULL) 15340024Sgibbs BUS_ADD_CHILD(parent, 0, "fdtbus", -1); 15440024Sgibbs} 15540024Sgibbs 15640024Sgibbsstatic int 15740024Sgibbsfdtbus_probe(device_t dev) 15840024Sgibbs{ 15940024Sgibbs 16040024Sgibbs debugf("%s(dev=%p); pass=%u\n", __func__, dev, bus_current_pass); 16140024Sgibbs 16240024Sgibbs device_set_desc(dev, "FDT main bus"); 16340024Sgibbs if (!bootverbose) 16440024Sgibbs device_quiet(dev); 16540024Sgibbs return (BUS_PROBE_DEFAULT); 16640024Sgibbs} 16740024Sgibbs 16840024Sgibbsstatic int 16940024Sgibbsfdtbus_attach(device_t dev) 17040024Sgibbs{ 17140024Sgibbs phandle_t root; 17240024Sgibbs phandle_t child; 17340024Sgibbs struct fdtbus_softc *sc; 17440024Sgibbs u_long start, end; 17540024Sgibbs int error; 17640024Sgibbs 17740024Sgibbs if ((root = OF_finddevice("/")) == -1) 17840024Sgibbs panic("fdtbus_attach: no root node."); 17940024Sgibbs 18040024Sgibbs sc = device_get_softc(dev); 18140024Sgibbs 18240024Sgibbs /* 18340024Sgibbs * IRQ rman. 18440024Sgibbs */ 18540024Sgibbs start = 0; 18640024Sgibbs end = FDT_INTR_MAX - 1; 18740024Sgibbs sc->sc_irq.rm_start = start; 18840024Sgibbs sc->sc_irq.rm_end = end; 18940024Sgibbs sc->sc_irq.rm_type = RMAN_ARRAY; 19040024Sgibbs sc->sc_irq.rm_descr = "Interrupt request lines"; 19140024Sgibbs if ((error = rman_init(&sc->sc_irq)) != 0) { 19240024Sgibbs device_printf(dev, "could not init IRQ rman, error = %d\n", 19340024Sgibbs error); 19440024Sgibbs return (error); 19540024Sgibbs } 19640024Sgibbs if ((error = rman_manage_region(&sc->sc_irq, start, end)) != 0) { 19740024Sgibbs device_printf(dev, "could not manage IRQ region, error = %d\n", 19840024Sgibbs error); 19940024Sgibbs return (error); 20040024Sgibbs } 20140024Sgibbs 20240024Sgibbs /* 20340024Sgibbs * Mem-mapped I/O space rman. 20440024Sgibbs */ 20540024Sgibbs start = 0; 20640024Sgibbs end = ~0ul; 20740024Sgibbs sc->sc_mem.rm_start = start; 20840024Sgibbs sc->sc_mem.rm_end = end; 20940024Sgibbs sc->sc_mem.rm_type = RMAN_ARRAY; 21040024Sgibbs sc->sc_mem.rm_descr = "I/O memory"; 21140024Sgibbs if ((error = rman_init(&sc->sc_mem)) != 0) { 21240024Sgibbs device_printf(dev, "could not init I/O mem rman, error = %d\n", 21340024Sgibbs error); 21440024Sgibbs return (error); 21540024Sgibbs } 21640024Sgibbs if ((error = rman_manage_region(&sc->sc_mem, start, end)) != 0) { 21740024Sgibbs device_printf(dev, "could not manage I/O mem region, " 21856979Sgibbs "error = %d\n", error); 21956979Sgibbs return (error); 22056979Sgibbs } 22156979Sgibbs 22240024Sgibbs /* 22340024Sgibbs * Walk the FDT root node and add top-level devices as our children. 22440024Sgibbs */ 22540024Sgibbs for (child = OF_child(root); child != 0; child = OF_peer(child)) { 22640024Sgibbs /* Check and process 'status' property. */ 22740024Sgibbs if (!(fdt_is_enabled(child))) 22840024Sgibbs continue; 22940024Sgibbs 23040024Sgibbs newbus_device_from_fdt_node(dev, child); 23140024Sgibbs } 23240024Sgibbs 23340024Sgibbs return (bus_generic_attach(dev)); 23440024Sgibbs} 23540024Sgibbs 23640024Sgibbsstatic int 23740024Sgibbsfdtbus_print_child(device_t dev, device_t child) 23840024Sgibbs{ 23940024Sgibbs struct fdtbus_devinfo *di; 24040420Sgibbs struct resource_list *rl; 24140024Sgibbs int rv; 24240024Sgibbs 24340024Sgibbs di = device_get_ivars(child); 24440024Sgibbs rl = &di->di_res; 24540024Sgibbs 24640024Sgibbs rv = 0; 24740024Sgibbs rv += bus_print_child_header(dev, child); 24840024Sgibbs rv += resource_list_print_type(rl, "mem", SYS_RES_MEMORY, "%#lx"); 24940024Sgibbs rv += resource_list_print_type(rl, "irq", SYS_RES_IRQ, "%ld"); 25040024Sgibbs rv += bus_print_child_footer(dev, child); 25140024Sgibbs 25240024Sgibbs return (rv); 25340024Sgibbs} 25440024Sgibbs 25540024Sgibbsstatic void 25640024Sgibbsnewbus_device_destroy(device_t dev) 25740024Sgibbs{ 25840024Sgibbs struct fdtbus_devinfo *di; 25940024Sgibbs 260115343Sscottl di = device_get_ivars(dev); 26140024Sgibbs 26240024Sgibbs free(di->di_name, M_OFWPROP); 26340024Sgibbs free(di->di_type, M_OFWPROP); 26440024Sgibbs free(di->di_compat, M_OFWPROP); 26540024Sgibbs 26640024Sgibbs resource_list_free(&di->di_res); 26740024Sgibbs free(di, M_FDTBUS); 26840024Sgibbs} 26940024Sgibbs 27040024Sgibbsstatic device_t 27140024Sgibbsnewbus_device_create(device_t dev_par, phandle_t node, char *name, char *type, 27240024Sgibbs char *compat) 27340024Sgibbs{ 27440024Sgibbs device_t child; 27540024Sgibbs struct fdtbus_devinfo *di; 27640024Sgibbs 27756979Sgibbs child = device_add_child(dev_par, NULL, -1); 27840024Sgibbs if (child == NULL) { 27940024Sgibbs free(name, M_OFWPROP); 28056979Sgibbs free(type, M_OFWPROP); 28156979Sgibbs free(compat, M_OFWPROP); 28256979Sgibbs return (NULL); 28356979Sgibbs } 28440024Sgibbs 28540024Sgibbs di = malloc(sizeof(*di), M_FDTBUS, M_WAITOK); 28640024Sgibbs di->di_node = node; 28740024Sgibbs di->di_name = name; 28840024Sgibbs di->di_type = type; 28956979Sgibbs di->di_compat = compat; 29056979Sgibbs 29140024Sgibbs resource_list_init(&di->di_res); 29240024Sgibbs 29340024Sgibbs if (fdt_reg_to_rl(node, &di->di_res, fdt_immr_va)) { 29440024Sgibbs device_printf(child, "could not process 'reg' property\n"); 29540024Sgibbs newbus_device_destroy(child); 29640024Sgibbs child = NULL; 29740024Sgibbs goto out; 29840024Sgibbs } 29940024Sgibbs 30040024Sgibbs if (fdt_intr_to_rl(node, &di->di_res, di->di_intr_sl)) { 30140024Sgibbs device_printf(child, "could not process 'interrupts' " 30240024Sgibbs "property\n"); 30340024Sgibbs newbus_device_destroy(child); 30440024Sgibbs child = NULL; 30540024Sgibbs goto out; 30640024Sgibbs } 30740024Sgibbs 30840024Sgibbs device_set_ivars(child, di); 30940024Sgibbs debugf("added child name='%s', node=%p\n", name, (void *)node); 31040024Sgibbs 31140024Sgibbsout: 31240024Sgibbs return (child); 31340024Sgibbs} 31440024Sgibbs 31540024Sgibbsstatic device_t 31640024Sgibbsnewbus_pci_create(device_t dev_par, phandle_t dt_node, u_long par_base, 31740024Sgibbs u_long par_size) 31840024Sgibbs{ 31940024Sgibbs pcell_t reg[3 + 2]; 32040024Sgibbs device_t dev_child; 32140024Sgibbs u_long start, end, count; 32240024Sgibbs struct fdtbus_devinfo *di; 32340024Sgibbs char *name, *type, *compat; 32440024Sgibbs int len; 32540024Sgibbs 32640024Sgibbs OF_getprop_alloc(dt_node, "device_type", 1, (void **)&type); 32740024Sgibbs if (!(type != NULL && strcmp(type, "pci") == 0)) { 32840024Sgibbs /* Only process 'pci' subnodes. */ 32940024Sgibbs free(type, M_OFWPROP); 33040024Sgibbs return (NULL); 33140024Sgibbs } 33257679Sgibbs 33340024Sgibbs OF_getprop_alloc(dt_node, "name", 1, (void **)&name); 33440024Sgibbs OF_getprop_alloc(OF_parent(dt_node), "compatible", 1, 33540024Sgibbs (void **)&compat); 33640024Sgibbs 33740024Sgibbs dev_child = device_add_child(dev_par, NULL, -1); 33840024Sgibbs if (dev_child == NULL) { 33940024Sgibbs free(name, M_OFWPROP); 34056979Sgibbs free(type, M_OFWPROP); 34140024Sgibbs free(compat, M_OFWPROP); 34240024Sgibbs return (NULL); 34340024Sgibbs } 34440024Sgibbs 34540024Sgibbs di = malloc(sizeof(*di), M_FDTBUS, M_WAITOK); 34640024Sgibbs di->di_node = dt_node; 34740024Sgibbs di->di_name = name; 34840024Sgibbs di->di_type = type; 34940024Sgibbs di->di_compat = compat; 35040024Sgibbs 35140024Sgibbs resource_list_init(&di->di_res); 35240024Sgibbs 35340024Sgibbs /* 35440024Sgibbs * Produce and set SYS_RES_MEMORY resources. 35540024Sgibbs */ 35640024Sgibbs start = 0; 35740024Sgibbs count = 0; 35840024Sgibbs 35940024Sgibbs len = OF_getprop(dt_node, "reg", ®, sizeof(reg)); 36040024Sgibbs if (len > 0) { 36140024Sgibbs if (fdt_data_verify((void *)®[1], 2) != 0) { 36240024Sgibbs device_printf(dev_child, "'reg' address value out of " 36340024Sgibbs "range\n"); 36456979Sgibbs newbus_device_destroy(dev_child); 36540024Sgibbs dev_child = NULL; 36640024Sgibbs goto out; 36740024Sgibbs } 36840024Sgibbs start = fdt_data_get((void *)®[1], 2); 36940024Sgibbs 37040024Sgibbs if (fdt_data_verify((void *)®[3], 2) != 0) { 37140024Sgibbs device_printf(dev_child, "'reg' size value out of " 37240024Sgibbs "range\n"); 37340024Sgibbs newbus_device_destroy(dev_child); 37440024Sgibbs dev_child = NULL; 37540024Sgibbs goto out; 37640024Sgibbs } 37740024Sgibbs count = fdt_data_get((void *)®[3], 2); 37840024Sgibbs } 37940024Sgibbs 38040024Sgibbs /* Calculate address range relative to base. */ 38140024Sgibbs par_base &= 0x000ffffful; 38240024Sgibbs start &= 0x000ffffful; 38340024Sgibbs start += par_base + fdt_immr_va; 38456979Sgibbs if (count == 0) 38540024Sgibbs count = par_size; 38640024Sgibbs end = start + count - 1; 38740024Sgibbs 38840024Sgibbs debugf("start = 0x%08lx, end = 0x%08lx, count = 0x%08lx\n", 38940024Sgibbs start, end, count); 39056979Sgibbs 39140024Sgibbs if (count > par_size) { 39240024Sgibbs device_printf(dev_child, "'reg' size value out of range\n"); 39340024Sgibbs newbus_device_destroy(dev_child); 39456979Sgibbs dev_child = NULL; 39540024Sgibbs goto out; 39640024Sgibbs } 39740024Sgibbs 39856979Sgibbs resource_list_add(&di->di_res, SYS_RES_MEMORY, 0, start, end, count); 39956979Sgibbs 40056979Sgibbs /* 40157679Sgibbs * Set SYS_RES_IRQ resources. 40256979Sgibbs */ 40356979Sgibbs if (fdt_intr_to_rl(OF_parent(dt_node), &di->di_res, di->di_intr_sl)) { 40456979Sgibbs device_printf(dev_child, "could not process 'interrupts' " 40556979Sgibbs "property\n"); 40656979Sgibbs newbus_device_destroy(dev_child); 40756979Sgibbs dev_child = NULL; 40856979Sgibbs goto out; 40957679Sgibbs } 41057679Sgibbs 41157679Sgibbs device_set_ivars(dev_child, di); 41256979Sgibbs debugf("added child name='%s', node=%p\n", name, 41356979Sgibbs (void *)dt_node); 41456979Sgibbs 41540024Sgibbsout: 41656979Sgibbs return (dev_child); 41756979Sgibbs} 41840024Sgibbs 41940024Sgibbsstatic void 42040024Sgibbspci_from_fdt_node(device_t dev_par, phandle_t dt_node, char *name, 42140024Sgibbs char *type, char *compat) 42256979Sgibbs{ 42340024Sgibbs u_long reg_base, reg_size; 42440024Sgibbs phandle_t dt_child; 42540024Sgibbs 42640024Sgibbs /* 42740024Sgibbs * Retrieve 'reg' property. 42840024Sgibbs */ 42940024Sgibbs if (fdt_regsize(dt_node, ®_base, ®_size) != 0) { 43040024Sgibbs device_printf(dev_par, "could not retrieve 'reg' prop\n"); 43140024Sgibbs return; 43240024Sgibbs } 43340024Sgibbs 43440024Sgibbs /* 43540024Sgibbs * Walk the PCI node and instantiate newbus devices representing 43640024Sgibbs * logical resources (bridges / ports). 43740024Sgibbs */ 43840024Sgibbs for (dt_child = OF_child(dt_node); dt_child != 0; 43940024Sgibbs dt_child = OF_peer(dt_child)) { 44040024Sgibbs 44140024Sgibbs if (!(fdt_is_enabled(dt_child))) 44240024Sgibbs continue; 44340024Sgibbs 44440024Sgibbs newbus_pci_create(dev_par, dt_child, reg_base, reg_size); 44540024Sgibbs } 44640024Sgibbs} 44740024Sgibbs 44840024Sgibbs/* 44940024Sgibbs * These FDT nodes do not need a corresponding newbus device object. 45040024Sgibbs */ 45140024Sgibbsstatic char *fdt_devices_skip[] = { 45240024Sgibbs "aliases", 45340024Sgibbs "chosen", 45440024Sgibbs "memory", 45540024Sgibbs NULL 45640024Sgibbs}; 45740024Sgibbs 45840024Sgibbsstatic void 45940024Sgibbsnewbus_device_from_fdt_node(device_t dev_par, phandle_t node) 46040024Sgibbs{ 46140024Sgibbs char *name, *type, *compat; 46240024Sgibbs device_t child; 46340024Sgibbs int i; 46440024Sgibbs 46540024Sgibbs OF_getprop_alloc(node, "name", 1, (void **)&name); 46640024Sgibbs OF_getprop_alloc(node, "device_type", 1, (void **)&type); 46740024Sgibbs OF_getprop_alloc(node, "compatible", 1, (void **)&compat); 46840024Sgibbs 46940024Sgibbs for (i = 0; fdt_devices_skip[i] != NULL; i++) 47040024Sgibbs if (name != NULL && strcmp(name, fdt_devices_skip[i]) == 0) { 47140024Sgibbs debugf("skipping instantiating FDT device='%s'\n", 47240024Sgibbs name); 47340024Sgibbs return; 47440024Sgibbs } 47540024Sgibbs 47640024Sgibbs child = newbus_device_create(dev_par, node, name, type, compat); 47740024Sgibbs if (type != NULL && strcmp(type, "pci") == 0) 47840024Sgibbs pci_from_fdt_node(child, node, name, type, compat); 47940024Sgibbs} 48040024Sgibbs 48140024Sgibbsstatic struct resource * 48240024Sgibbsfdtbus_alloc_resource(device_t bus, device_t child, int type, int *rid, 48340024Sgibbs u_long start, u_long end, u_long count, u_int flags) 48440024Sgibbs{ 48540024Sgibbs struct fdtbus_softc *sc; 48640024Sgibbs struct resource *res; 48740024Sgibbs struct rman *rm; 48840024Sgibbs struct fdtbus_devinfo *di; 48940024Sgibbs struct resource_list_entry *rle; 49040024Sgibbs int needactivate; 49140024Sgibbs 49240024Sgibbs /* 49340024Sgibbs * Request for the default allocation with a given rid: use resource 49440024Sgibbs * list stored in the local device info. 49540024Sgibbs */ 49640024Sgibbs if ((start == 0UL) && (end == ~0UL)) { 49740024Sgibbs if ((di = device_get_ivars(child)) == NULL) 49840024Sgibbs return (NULL); 49940024Sgibbs 50040024Sgibbs if (type == SYS_RES_IOPORT) 50140024Sgibbs type = SYS_RES_MEMORY; 50240024Sgibbs 50340024Sgibbs rle = resource_list_find(&di->di_res, type, *rid); 50440024Sgibbs if (rle == NULL) { 50540024Sgibbs device_printf(bus, "no default resources for " 50640024Sgibbs "rid = %d, type = %d\n", *rid, type); 50740024Sgibbs return (NULL); 50840024Sgibbs } 50957679Sgibbs start = rle->start; 51057679Sgibbs end = rle->end; 51140024Sgibbs count = rle->count; 51240024Sgibbs } 51340024Sgibbs 51440024Sgibbs sc = device_get_softc(bus); 51540024Sgibbs 51640024Sgibbs needactivate = flags & RF_ACTIVE; 51740024Sgibbs flags &= ~RF_ACTIVE; 51840024Sgibbs 51940024Sgibbs switch (type) { 52040024Sgibbs case SYS_RES_IRQ: 52140024Sgibbs rm = &sc->sc_irq; 52240024Sgibbs break; 52340024Sgibbs 52440024Sgibbs case SYS_RES_IOPORT: 52540024Sgibbs case SYS_RES_MEMORY: 52640024Sgibbs rm = &sc->sc_mem; 52740024Sgibbs break; 52840024Sgibbs 52940024Sgibbs default: 53040024Sgibbs return (NULL); 53140024Sgibbs } 53240024Sgibbs 53340024Sgibbs res = rman_reserve_resource(rm, start, end, count, flags, child); 53440024Sgibbs if (res == NULL) { 53540024Sgibbs device_printf(bus, "failed to reserve resource %#lx - %#lx " 53640024Sgibbs "(%#lx)\n", start, end, count); 53740024Sgibbs return (NULL); 53856979Sgibbs } 53956979Sgibbs 54056979Sgibbs rman_set_rid(res, *rid); 54140024Sgibbs 54240024Sgibbs if (type == SYS_RES_IOPORT || type == SYS_RES_MEMORY) { 54340024Sgibbs /* XXX endianess should be set based on SOC node */ 54440024Sgibbs rman_set_bustag(res, fdtbus_bs_tag); 54540024Sgibbs rman_set_bushandle(res, rman_get_start(res)); 54640024Sgibbs } 54740024Sgibbs 54840024Sgibbs if (needactivate) 54940024Sgibbs if (bus_activate_resource(child, type, *rid, res)) { 55040024Sgibbs device_printf(child, "resource activation failed\n"); 55140024Sgibbs rman_release_resource(res); 55240024Sgibbs return (NULL); 55340024Sgibbs } 55440024Sgibbs 55540024Sgibbs return (res); 55640024Sgibbs} 55740024Sgibbs 55840024Sgibbsstatic int 55940024Sgibbsfdtbus_release_resource(device_t bus, device_t child, int type, int rid, 56040024Sgibbs struct resource *res) 56140024Sgibbs{ 56240024Sgibbs int err; 56340024Sgibbs 56440024Sgibbs if (rman_get_flags(res) & RF_ACTIVE) { 56540024Sgibbs err = bus_deactivate_resource(child, type, rid, res); 56640024Sgibbs if (err) 56740024Sgibbs return (err); 56840024Sgibbs } 56940024Sgibbs 57040024Sgibbs return (rman_release_resource(res)); 57140024Sgibbs} 57240024Sgibbs 57340024Sgibbsstatic int 57440024Sgibbsfdtbus_setup_intr(device_t bus, device_t child, struct resource *res, 57540024Sgibbs int flags, driver_filter_t *filter, driver_intr_t *ihand, void *arg, 57640024Sgibbs void **cookiep) 57740024Sgibbs{ 57840024Sgibbs int err; 57940024Sgibbs 58040024Sgibbs *cookiep = 0; 58140024Sgibbs if ((rman_get_flags(res) & RF_SHAREABLE) == 0) 58240024Sgibbs flags |= INTR_EXCL; 58340024Sgibbs 58440024Sgibbs err = rman_activate_resource(res); 58540024Sgibbs if (err) 58640024Sgibbs return (err); 58740024Sgibbs 58840024Sgibbs#if defined(__powerpc__) 58940024Sgibbs err = powerpc_setup_intr(device_get_nameunit(child), 59040024Sgibbs rman_get_start(res), filter, ihand, arg, flags, cookiep); 59140024Sgibbs#elif defined(__mips__) 59256979Sgibbs cpu_establish_hardintr(device_get_nameunit(child), 59356979Sgibbs filter, ihand, arg, rman_get_start(res), flags, cookiep); 59456979Sgibbs#elif defined(__arm__) 59556979Sgibbs arm_setup_irqhandler(device_get_nameunit(child), 59656979Sgibbs filter, ihand, arg, rman_get_start(res), flags, cookiep); 59740024Sgibbs arm_unmask_irq(rman_get_start(res)); 59840024Sgibbs err = 0; 59940024Sgibbs#endif 60046581Sken 60146581Sken return (err); 60256979Sgibbs} 60356979Sgibbs 60456979Sgibbsstatic int 60556979Sgibbsfdtbus_activate_resource(device_t bus, device_t child, int type, int rid, 60640024Sgibbs struct resource *res) 60756979Sgibbs{ 60856979Sgibbs 60956979Sgibbs return (rman_activate_resource(res)); 61056979Sgibbs} 61156979Sgibbs 61256979Sgibbsstatic int 61340024Sgibbsfdtbus_deactivate_resource(device_t bus, device_t child, int type, int rid, 61446581Sken struct resource *res) 61546581Sken{ 61646581Sken 61756979Sgibbs return (rman_deactivate_resource(res)); 61856979Sgibbs} 61956979Sgibbs 62040024Sgibbsstatic int 62140024Sgibbsfdtbus_teardown_intr(device_t bus, device_t child, struct resource *res, 62240024Sgibbs void *cookie) 62340024Sgibbs{ 62440024Sgibbs 62556979Sgibbs#if defined(__powerpc__) 62640024Sgibbs return (powerpc_teardown_intr(cookie)); 62740024Sgibbs#elif defined(__mips__) 62856979Sgibbs /* mips does not have a teardown yet */ 62956979Sgibbs return (0); 63056979Sgibbs#elif defined(__arm__) 63156979Sgibbs return (arm_remove_irqhandler(rman_get_start(res), cookie)); 63256979Sgibbs#endif 63356979Sgibbs} 63456979Sgibbs 63556979Sgibbsstatic const char * 63656979Sgibbsfdtbus_ofw_get_name(device_t bus, device_t dev) 63756979Sgibbs{ 63840024Sgibbs struct fdtbus_devinfo *di; 63956979Sgibbs 64040024Sgibbs return ((di = device_get_ivars(dev)) == NULL ? NULL : di->di_name); 64140024Sgibbs} 64256979Sgibbs 64340024Sgibbsstatic phandle_t 64440024Sgibbsfdtbus_ofw_get_node(device_t bus, device_t dev) 64540024Sgibbs{ 64640024Sgibbs struct fdtbus_devinfo *di; 64740024Sgibbs 64840024Sgibbs return ((di = device_get_ivars(dev)) == NULL ? 0 : di->di_node); 64940024Sgibbs} 65040024Sgibbs 65140024Sgibbsstatic const char * 65240024Sgibbsfdtbus_ofw_get_type(device_t bus, device_t dev) 65340024Sgibbs{ 65440024Sgibbs struct fdtbus_devinfo *di; 65540024Sgibbs 65640024Sgibbs return ((di = device_get_ivars(dev)) == NULL ? NULL : di->di_type); 65740024Sgibbs} 65840024Sgibbs 65940024Sgibbsstatic const char * 66056979Sgibbsfdtbus_ofw_get_compat(device_t bus, device_t dev) 66156979Sgibbs{ 66240024Sgibbs struct fdtbus_devinfo *di; 66340024Sgibbs 66440024Sgibbs return ((di = device_get_ivars(dev)) == NULL ? NULL : di->di_compat); 66540024Sgibbs} 66640024Sgibbs 66740024Sgibbs 66840024Sgibbs