ofwbus.c revision 183882
1161564Smarcel/*- 2161564Smarcel * Copyright 1998 Massachusetts Institute of Technology 3161564Smarcel * 4161564Smarcel * Permission to use, copy, modify, and distribute this software and 5161564Smarcel * its documentation for any purpose and without fee is hereby 6161564Smarcel * granted, provided that both the above copyright notice and this 7161564Smarcel * permission notice appear in all copies, that both the above 8161564Smarcel * copyright notice and this permission notice appear in all 9161564Smarcel * supporting documentation, and that the name of M.I.T. not be used 10161564Smarcel * in advertising or publicity pertaining to distribution of the 11161564Smarcel * software without specific, written prior permission. M.I.T. makes 12161564Smarcel * no representations about the suitability of this software for any 13161564Smarcel * purpose. It is provided "as is" without express or implied 14161564Smarcel * warranty. 15161564Smarcel * 16161564Smarcel * THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''. M.I.T. DISCLAIMS 17161564Smarcel * ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE, 18161564Smarcel * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 19161564Smarcel * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT 20161564Smarcel * SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21161564Smarcel * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22161564Smarcel * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 23161564Smarcel * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 24161564Smarcel * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 25161564Smarcel * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 26161564Smarcel * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27161564Smarcel * SUCH DAMAGE. 28161564Smarcel */ 29161564Smarcel/*- 30161564Smarcel * Copyright 2001 by Thomas Moestl <tmm@FreeBSD.org>. All rights reserved. 31161564Smarcel * 32161564Smarcel * Redistribution and use in source and binary forms, with or without 33161564Smarcel * modification, are permitted provided that the following conditions 34161564Smarcel * are met: 35161564Smarcel * 1. Redistributions of source code must retain the above copyright 36161564Smarcel * notice, this list of conditions and the following disclaimer. 37161564Smarcel * 2. Redistributions in binary form must reproduce the above copyright 38161564Smarcel * notice, this list of conditions and the following disclaimer in the 39161564Smarcel * documentation and/or other materials provided with the distribution. 40161564Smarcel * 41161564Smarcel * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 42161564Smarcel * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 43161564Smarcel * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 44161564Smarcel * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 45161564Smarcel * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 46161564Smarcel * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 47161564Smarcel * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 48161564Smarcel * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 49161564Smarcel * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 50161564Smarcel * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 51161564Smarcel * SUCH DAMAGE. 52161564Smarcel * 53161564Smarcel * from: FreeBSD: src/sys/i386/i386/nexus.c,v 1.43 2001/02/09 54161564Smarcel * 55161564Smarcel * $FreeBSD: head/sys/powerpc/aim/nexus.c 183882 2008-10-14 14:54:14Z nwhitehorn $ 56161564Smarcel */ 57161564Smarcel#include "opt_psim.h" 58161564Smarcel 59161564Smarcel#include <sys/param.h> 60161564Smarcel#include <sys/systm.h> 61161564Smarcel#include <sys/module.h> 62161564Smarcel#include <sys/bus.h> 63161564Smarcel#include <sys/clock.h> 64161564Smarcel#include <sys/cons.h> 65161564Smarcel#include <sys/kernel.h> 66161564Smarcel#include <sys/malloc.h> 67161564Smarcel 68161564Smarcel#include <dev/ofw/openfirm.h> 69161564Smarcel 70161564Smarcel#include <machine/bus.h> 71161564Smarcel#include <machine/frame.h> 72161564Smarcel#include <machine/intr_machdep.h> 73161564Smarcel#include <machine/resource.h> 74161564Smarcel 75161564Smarcel#include <sys/rman.h> 76161564Smarcel 77161564Smarcel#include "clock_if.h" 78161564Smarcel#include "ofw_bus_if.h" 79161564Smarcel#include "pic_if.h" 80161564Smarcel 81161564Smarcel/* 82161564Smarcel * The nexus (which is a pseudo-bus actually) iterates over the nodes that 83161564Smarcel * exist in Open Firmware and adds them as devices to this bus so that drivers 84161564Smarcel * can be attached to them. 85161564Smarcel * 86161564Smarcel * Maybe this code should get into dev/ofw to some extent, as some of it should 87161564Smarcel * work for all Open Firmware based machines... 88161564Smarcel */ 89161564Smarcel 90161564Smarcelstatic MALLOC_DEFINE(M_NEXUS, "nexus", "nexus device information"); 91161564Smarcel 92161564Smarcelenum nexus_ivars { 93161564Smarcel NEXUS_IVAR_NODE, 94161564Smarcel NEXUS_IVAR_NAME, 95161564Smarcel NEXUS_IVAR_DEVICE_TYPE, 96161564Smarcel NEXUS_IVAR_COMPATIBLE, 97161564Smarcel}; 98161564Smarcel 99161564Smarcelstruct nexus_devinfo { 100161564Smarcel phandle_t ndi_node; 101161564Smarcel /* Some common properties. */ 102161564Smarcel const char *ndi_name; 103161564Smarcel const char *ndi_device_type; 104161564Smarcel const char *ndi_compatible; 105161564Smarcel}; 106161564Smarcel 107161564Smarcelstruct nexus_softc { 108161564Smarcel struct rman sc_rman; 109161564Smarcel}; 110161564Smarcel 111161564Smarcel/* 112161564Smarcel * Device interface 113161564Smarcel */ 114161564Smarcelstatic int nexus_probe(device_t); 115161564Smarcelstatic int nexus_attach(device_t); 116161564Smarcel 117161564Smarcel/* 118161564Smarcel * Bus interface 119161564Smarcel */ 120161564Smarcelstatic device_t nexus_add_child(device_t, int, const char *, int); 121161564Smarcelstatic void nexus_probe_nomatch(device_t, device_t); 122161564Smarcelstatic int nexus_read_ivar(device_t, device_t, int, uintptr_t *); 123161564Smarcelstatic int nexus_write_ivar(device_t, device_t, int, uintptr_t); 124161564Smarcelstatic int nexus_setup_intr(device_t, device_t, struct resource *, int, 125161564Smarcel driver_filter_t *, driver_intr_t *, void *, void **); 126161564Smarcelstatic int nexus_teardown_intr(device_t, device_t, struct resource *, 127161564Smarcel void *); 128161564Smarcelstatic struct resource *nexus_alloc_resource(device_t, device_t, int, int *, 129161564Smarcel u_long, u_long, u_long, u_int); 130161564Smarcelstatic int nexus_activate_resource(device_t, device_t, int, int, 131161564Smarcel struct resource *); 132161564Smarcelstatic int nexus_deactivate_resource(device_t, device_t, int, int, 133161564Smarcel struct resource *); 134161564Smarcelstatic int nexus_release_resource(device_t, device_t, int, int, 135161564Smarcel struct resource *); 136161564Smarcel 137161564Smarcel/* 138161564Smarcel * OFW bus interface. 139161564Smarcel */ 140161564Smarcelstatic phandle_t nexus_ofw_get_node(device_t, device_t); 141161564Smarcelstatic const char *nexus_ofw_get_name(device_t, device_t); 142161564Smarcelstatic const char *nexus_ofw_get_type(device_t, device_t); 143161564Smarcelstatic const char *nexus_ofw_get_compat(device_t, device_t); 144161564Smarcel 145161564Smarcel/* 146161564Smarcel * Clock interface. 147161564Smarcel */ 148161564Smarcelstatic int nexus_gettime(device_t, struct timespec *); 149161564Smarcelstatic int nexus_settime(device_t, struct timespec *); 150161564Smarcel 151161564Smarcel/* 152161564Smarcel * Local routines 153161564Smarcel */ 154161564Smarcelstatic device_t nexus_device_from_node(device_t, phandle_t); 155161564Smarcel 156161564Smarcelstatic device_method_t nexus_methods[] = { 157161564Smarcel /* Device interface */ 158161564Smarcel DEVMETHOD(device_probe, nexus_probe), 159161564Smarcel DEVMETHOD(device_attach, nexus_attach), 160161564Smarcel DEVMETHOD(device_detach, bus_generic_detach), 161161564Smarcel DEVMETHOD(device_shutdown, bus_generic_shutdown), 162161564Smarcel DEVMETHOD(device_suspend, bus_generic_suspend), 163161564Smarcel DEVMETHOD(device_resume, bus_generic_resume), 164161564Smarcel 165161564Smarcel /* Bus interface. Resource management is business of the children... */ 166161564Smarcel DEVMETHOD(bus_add_child, nexus_add_child), 167161564Smarcel DEVMETHOD(bus_print_child, bus_generic_print_child), 168161564Smarcel DEVMETHOD(bus_probe_nomatch, nexus_probe_nomatch), 169161564Smarcel DEVMETHOD(bus_read_ivar, nexus_read_ivar), 170161564Smarcel DEVMETHOD(bus_write_ivar, nexus_write_ivar), 171161564Smarcel DEVMETHOD(bus_setup_intr, nexus_setup_intr), 172161564Smarcel DEVMETHOD(bus_teardown_intr, nexus_teardown_intr), 173161564Smarcel DEVMETHOD(bus_alloc_resource, nexus_alloc_resource), 174161564Smarcel DEVMETHOD(bus_activate_resource, nexus_activate_resource), 175161564Smarcel DEVMETHOD(bus_deactivate_resource, nexus_deactivate_resource), 176161564Smarcel DEVMETHOD(bus_release_resource, nexus_release_resource), 177161564Smarcel 178239396Sandreast /* OFW bus interface */ 179161564Smarcel DEVMETHOD(ofw_bus_get_node, nexus_ofw_get_node), 180161564Smarcel DEVMETHOD(ofw_bus_get_name, nexus_ofw_get_name), 181161564Smarcel DEVMETHOD(ofw_bus_get_type, nexus_ofw_get_type), 182161564Smarcel DEVMETHOD(ofw_bus_get_compat, nexus_ofw_get_compat), 183161564Smarcel 184161564Smarcel /* Clock interface */ 185161564Smarcel DEVMETHOD(clock_gettime, nexus_gettime), 186161564Smarcel DEVMETHOD(clock_settime, nexus_settime), 187161564Smarcel 188161564Smarcel { 0, 0 } 189161564Smarcel}; 190161564Smarcel 191161564Smarcelstatic driver_t nexus_driver = { 192161564Smarcel "nexus", 193161564Smarcel nexus_methods, 194161564Smarcel sizeof(struct nexus_softc), 195161564Smarcel}; 196161564Smarcel 197161564Smarcelstatic devclass_t nexus_devclass; 198161564Smarcel 199161564SmarcelDRIVER_MODULE(nexus, root, nexus_driver, nexus_devclass, 0, 0); 200161564Smarcel 201161564Smarcelstatic int 202161564Smarcelnexus_probe(device_t dev) 203161564Smarcel{ 204161564Smarcel bus_generic_probe(dev); 205161564Smarcel device_set_desc(dev, "Open Firmware Nexus device"); 206161564Smarcel return (0); 207161564Smarcel} 208161564Smarcel 209161564Smarcelstatic int 210161564Smarcelnexus_attach(device_t dev) 211161564Smarcel{ 212161564Smarcel phandle_t root; 213161564Smarcel phandle_t child; 214161564Smarcel struct nexus_softc *sc; 215161564Smarcel u_long start, end; 216161564Smarcel 217161564Smarcel if ((root = OF_peer(0)) == -1) 218161564Smarcel panic("nexus_probe: OF_peer failed."); 219161564Smarcel 220161564Smarcel sc = device_get_softc(dev); 221161564Smarcel 222161564Smarcel start = 0; 223161564Smarcel end = INTR_VECTORS - 1; 224161564Smarcel 225161564Smarcel sc->sc_rman.rm_start = start; 226161564Smarcel sc->sc_rman.rm_end = end; 227161564Smarcel sc->sc_rman.rm_type = RMAN_ARRAY; 228161564Smarcel sc->sc_rman.rm_descr = "Interrupt request lines"; 229161564Smarcel if (rman_init(&sc->sc_rman) || 230161564Smarcel rman_manage_region(&sc->sc_rman, start, end)) 231161564Smarcel panic("nexus_probe IRQ rman"); 232161564Smarcel 233161564Smarcel /* 234161564Smarcel * Now walk the OFW tree to locate top-level devices 235161564Smarcel */ 236161564Smarcel for (child = OF_child(root); child != 0; child = OF_peer(child)) { 237161564Smarcel if (child == -1) 238161564Smarcel panic("nexus_probe(): OF_child failed."); 239161564Smarcel (void)nexus_device_from_node(dev, child); 240161564Smarcel 241161564Smarcel } 242161564Smarcel 243161564Smarcel clock_register(dev, 1000); 244161564Smarcel return (bus_generic_attach(dev)); 245161564Smarcel} 246161564Smarcel 247161564Smarcelstatic void 248161564Smarcelnexus_probe_nomatch(device_t dev, device_t child) 249161564Smarcel{ 250161564Smarcel char *name, *type; 251161564Smarcel 252161564Smarcel if (BUS_READ_IVAR(dev, child, NEXUS_IVAR_NAME, 253161564Smarcel (uintptr_t *)&name) != 0 || 254161564Smarcel BUS_READ_IVAR(dev, child, NEXUS_IVAR_DEVICE_TYPE, 255161564Smarcel (uintptr_t *)&type) != 0) 256161564Smarcel return; 257161564Smarcel 258161564Smarcel if (type == NULL) 259161564Smarcel type = "(unknown)"; 260161564Smarcel 261161564Smarcel if (bootverbose) 262161564Smarcel device_printf(dev, "<%s>, type %s (no driver attached)\n", 263161564Smarcel name, type); 264161564Smarcel} 265161564Smarcel 266161564Smarcelstatic device_t 267161564Smarcelnexus_add_child(device_t dev, int order, const char *name, int unit) 268161564Smarcel{ 269161564Smarcel device_t child; 270161564Smarcel struct nexus_devinfo *dinfo; 271161564Smarcel 272161564Smarcel child = device_add_child_ordered(dev, order, name, unit); 273161564Smarcel if (child == NULL) 274161564Smarcel return (NULL); 275161564Smarcel 276161564Smarcel dinfo = malloc(sizeof(struct nexus_devinfo), M_NEXUS, M_NOWAIT|M_ZERO); 277161564Smarcel if (dinfo == NULL) 278161564Smarcel return (NULL); 279161564Smarcel 280161564Smarcel dinfo->ndi_node = -1; 281161564Smarcel dinfo->ndi_name = name; 282161564Smarcel device_set_ivars(child, dinfo); 283161564Smarcel 284161564Smarcel return (child); 285161564Smarcel} 286161564Smarcel 287161564Smarcel 288161564Smarcelstatic int 289161564Smarcelnexus_read_ivar(device_t dev, device_t child, int which, uintptr_t *result) 290161564Smarcel{ 291161564Smarcel struct nexus_devinfo *dinfo; 292161564Smarcel 293161564Smarcel if ((dinfo = device_get_ivars(child)) == 0) 294161564Smarcel return (ENOENT); 295161564Smarcel switch (which) { 296161564Smarcel case NEXUS_IVAR_NODE: 297161564Smarcel *result = dinfo->ndi_node; 298161564Smarcel break; 299161564Smarcel case NEXUS_IVAR_NAME: 300161564Smarcel *result = (uintptr_t)dinfo->ndi_name; 301161564Smarcel break; 302161564Smarcel case NEXUS_IVAR_DEVICE_TYPE: 303161564Smarcel *result = (uintptr_t)dinfo->ndi_device_type; 304161564Smarcel break; 305161564Smarcel case NEXUS_IVAR_COMPATIBLE: 306161564Smarcel *result = (uintptr_t)dinfo->ndi_compatible; 307161564Smarcel break; 308161564Smarcel default: 309161564Smarcel return (ENOENT); 310161564Smarcel } 311161564Smarcel return 0; 312161564Smarcel} 313161564Smarcel 314161564Smarcelstatic int 315161564Smarcelnexus_write_ivar(device_t dev, device_t child, int which, uintptr_t value) 316161564Smarcel{ 317161564Smarcel struct nexus_devinfo *dinfo; 318161564Smarcel 319161564Smarcel if ((dinfo = device_get_ivars(child)) == 0) 320161564Smarcel return (ENOENT); 321161564Smarcel 322161564Smarcel switch (which) { 323161564Smarcel case NEXUS_IVAR_NAME: 324161564Smarcel return (EINVAL); 325161564Smarcel 326161564Smarcel /* Identified devices may want to set these */ 327161564Smarcel case NEXUS_IVAR_NODE: 328161564Smarcel dinfo->ndi_node = (phandle_t)value; 329161564Smarcel break; 330161564Smarcel 331161564Smarcel case NEXUS_IVAR_DEVICE_TYPE: 332161564Smarcel dinfo->ndi_device_type = (char *)value; 333161564Smarcel break; 334161564Smarcel 335161564Smarcel default: 336161564Smarcel return (ENOENT); 337161564Smarcel } 338161564Smarcel return 0; 339161564Smarcel} 340161564Smarcel 341161564Smarcelstatic int 342161564Smarcelnexus_setup_intr(device_t dev, device_t child, struct resource *res, int flags, 343161564Smarcel driver_filter_t *filter, driver_intr_t *ihand, void *arg, void **cookiep) 344161564Smarcel{ 345161564Smarcel driver_t *driver; 346161564Smarcel int error; 347161564Smarcel 348161564Smarcel /* somebody tried to setup an irq that failed to allocate! */ 349161564Smarcel if (res == NULL) 350161564Smarcel panic("nexus_setup_intr: NULL irq resource!"); 351161564Smarcel 352161564Smarcel *cookiep = 0; 353161564Smarcel if ((rman_get_flags(res) & RF_SHAREABLE) == 0) 354161564Smarcel flags |= INTR_EXCL; 355161564Smarcel 356161564Smarcel driver = device_get_driver(child); 357161564Smarcel 358161564Smarcel /* 359161564Smarcel * We depend here on rman_activate_resource() being idempotent. 360161564Smarcel */ 361161564Smarcel error = rman_activate_resource(res); 362161564Smarcel if (error) 363161564Smarcel return (error); 364161564Smarcel 365161564Smarcel error = powerpc_setup_intr(device_get_nameunit(child), 366161564Smarcel rman_get_start(res), filter, ihand, arg, flags, cookiep); 367161564Smarcel 368161564Smarcel return (error); 369161564Smarcel} 370161564Smarcel 371161564Smarcelstatic int 372161564Smarcelnexus_teardown_intr(device_t dev, device_t child, struct resource *res, 373161564Smarcel void *cookie) 374161564Smarcel{ 375161564Smarcel 376161564Smarcel return (powerpc_teardown_intr(cookie)); 377161564Smarcel} 378161564Smarcel 379161564Smarcel/* 380161564Smarcel * Allocate resources at the behest of a child. This only handles interrupts, 381161564Smarcel * since I/O resources are handled by child busses. 382161564Smarcel */ 383161564Smarcelstatic struct resource * 384161564Smarcelnexus_alloc_resource(device_t bus, device_t child, int type, int *rid, 385161564Smarcel u_long start, u_long end, u_long count, u_int flags) 386161564Smarcel{ 387161564Smarcel struct nexus_softc *sc; 388161564Smarcel struct resource *rv; 389161564Smarcel 390161564Smarcel if (type != SYS_RES_IRQ) { 391161564Smarcel device_printf(bus, "unknown resource request from %s\n", 392161564Smarcel device_get_nameunit(child)); 393161564Smarcel return (NULL); 394161564Smarcel } 395161564Smarcel 396161564Smarcel if (count == 0 || start + count - 1 != end) { 397161564Smarcel device_printf(bus, "invalid IRQ allocation from %s\n", 398161564Smarcel device_get_nameunit(child)); 399161564Smarcel return (NULL); 400161564Smarcel } 401161564Smarcel 402161564Smarcel sc = device_get_softc(bus); 403161564Smarcel 404161564Smarcel rv = rman_reserve_resource(&sc->sc_rman, start, end, count, 405161564Smarcel flags, child); 406161564Smarcel if (rv == NULL) { 407161564Smarcel device_printf(bus, "IRQ allocation failed for %s\n", 408161564Smarcel device_get_nameunit(child)); 409161564Smarcel } else 410161564Smarcel rman_set_rid(rv, *rid); 411161564Smarcel 412161564Smarcel return (rv); 413161564Smarcel} 414161564Smarcel 415161564Smarcelstatic int 416161564Smarcelnexus_activate_resource(device_t bus, device_t child, int type, int rid, 417161564Smarcel struct resource *res) 418161564Smarcel{ 419161564Smarcel 420161564Smarcel /* Not much to be done yet... */ 421161564Smarcel return (rman_activate_resource(res)); 422161564Smarcel} 423161564Smarcel 424161564Smarcelstatic int 425161564Smarcelnexus_deactivate_resource(device_t bus, device_t child, int type, int rid, 426161564Smarcel struct resource *res) 427161564Smarcel{ 428161564Smarcel 429161564Smarcel /* Not much to be done yet... */ 430161564Smarcel return (rman_deactivate_resource(res)); 431161564Smarcel} 432161564Smarcel 433161564Smarcelstatic int 434161564Smarcelnexus_release_resource(device_t bus, device_t child, int type, int rid, 435161564Smarcel struct resource *res) 436161564Smarcel{ 437161564Smarcel 438161564Smarcel if (type != SYS_RES_IRQ) { 439161564Smarcel device_printf(bus, "unknown resource request from %s\n", 440161564Smarcel device_get_nameunit(child)); 441161564Smarcel return (EINVAL); 442161564Smarcel } 443161564Smarcel 444161564Smarcel return (rman_release_resource(res)); 445161564Smarcel} 446161564Smarcel 447161564Smarcelstatic device_t 448161564Smarcelnexus_device_from_node(device_t parent, phandle_t node) 449161564Smarcel{ 450161564Smarcel device_t cdev; 451161564Smarcel struct nexus_devinfo *dinfo; 452161564Smarcel char *name, *type, *compatible; 453161564Smarcel 454161564Smarcel OF_getprop_alloc(node, "name", 1, (void **)&name); 455161564Smarcel OF_getprop_alloc(node, "device_type", 1, (void **)&type); 456161564Smarcel OF_getprop_alloc(node, "compatible", 1, (void **)&compatible); 457161564Smarcel cdev = device_add_child(parent, NULL, -1); 458161564Smarcel if (cdev != NULL) { 459161564Smarcel dinfo = malloc(sizeof(*dinfo), M_NEXUS, M_WAITOK); 460161564Smarcel dinfo->ndi_node = node; 461161564Smarcel dinfo->ndi_name = name; 462161564Smarcel dinfo->ndi_device_type = type; 463161564Smarcel dinfo->ndi_compatible = compatible; 464161564Smarcel device_set_ivars(cdev, dinfo); 465161564Smarcel } else 466161564Smarcel free(name, M_OFWPROP); 467161564Smarcel 468161564Smarcel return (cdev); 469161564Smarcel} 470161564Smarcel 471161564Smarcelstatic const char * 472161564Smarcelnexus_ofw_get_name(device_t bus, device_t dev) 473161564Smarcel{ 474161564Smarcel struct nexus_devinfo *dinfo; 475161564Smarcel 476161564Smarcel if ((dinfo = device_get_ivars(dev)) == NULL) 477161564Smarcel return (NULL); 478161564Smarcel 479161564Smarcel return (dinfo->ndi_name); 480161564Smarcel} 481161564Smarcel 482161564Smarcelstatic phandle_t 483161564Smarcelnexus_ofw_get_node(device_t bus, device_t dev) 484161564Smarcel{ 485161564Smarcel struct nexus_devinfo *dinfo; 486161564Smarcel 487161564Smarcel if ((dinfo = device_get_ivars(dev)) == NULL) 488161564Smarcel return (0); 489161564Smarcel 490161564Smarcel return (dinfo->ndi_node); 491161564Smarcel} 492161564Smarcel 493161564Smarcelstatic const char * 494161564Smarcelnexus_ofw_get_type(device_t bus, device_t dev) 495161564Smarcel{ 496161564Smarcel struct nexus_devinfo *dinfo; 497161564Smarcel 498161564Smarcel if ((dinfo = device_get_ivars(dev)) == NULL) 499161564Smarcel return (NULL); 500161564Smarcel 501161564Smarcel return (dinfo->ndi_device_type); 502161564Smarcel} 503161564Smarcel 504161564Smarcelstatic const char * 505161564Smarcelnexus_ofw_get_compat(device_t bus, device_t dev) 506161564Smarcel{ 507161564Smarcel struct nexus_devinfo *dinfo; 508161564Smarcel 509161564Smarcel if ((dinfo = device_get_ivars(dev)) == NULL) 510161564Smarcel return (NULL); 511161564Smarcel 512161564Smarcel return (dinfo->ndi_compatible); 513161564Smarcel} 514161564Smarcel 515161564Smarcel#define DIFF19041970 2082844800 516161564Smarcel 517161564Smarcelstatic int 518161564Smarcelnexus_gettime(device_t dev, struct timespec *ts) 519161564Smarcel{ 520161564Smarcel char path[128]; 521161564Smarcel ihandle_t ih; 522161564Smarcel phandle_t ph; 523161564Smarcel u_int rtc; 524161564Smarcel 525161564Smarcel ph = OF_finddevice("rtc"); 526161564Smarcel if (ph == -1) 527161564Smarcel return (ENOENT); 528161564Smarcel 529161564Smarcel OF_package_to_path(ph, path, sizeof(path)); 530161564Smarcel ih = OF_open(path); 531161564Smarcel if (ih == -1) 532161564Smarcel return (ENXIO); 533161564Smarcel 534161564Smarcel if (OF_call_method("read-rtc", ih, 0, 1, &rtc)) 535161564Smarcel return (EIO); 536161564Smarcel 537161564Smarcel ts->tv_sec = rtc - DIFF19041970; 538161564Smarcel ts->tv_nsec = 0; 539161564Smarcel return (0); 540161564Smarcel} 541161564Smarcel 542161564Smarcelstatic int 543161564Smarcelnexus_settime(device_t dev, struct timespec *ts) 544161564Smarcel{ 545161564Smarcel char path[128]; 546161564Smarcel ihandle_t ih; 547161564Smarcel phandle_t ph; 548161564Smarcel u_int rtc; 549161564Smarcel 550161564Smarcel ph = OF_finddevice("rtc"); 551 if (ph == -1) 552 return (ENOENT); 553 554 OF_package_to_path(ph, path, sizeof(path)); 555 ih = OF_open(path); 556 if (ih == -1) 557 return (ENXIO); 558 559 rtc = ts->tv_sec + DIFF19041970; 560 return ((OF_call_method("write-rtc", ih, 1, 0, rtc) != 0) ? EIO : 0); 561} 562