1*32d1354aSWojciech Macek /*- 2*32d1354aSWojciech Macek * Copyright (c) 2015 Nathan Whitehorn 3*32d1354aSWojciech Macek * All rights reserved. 4*32d1354aSWojciech Macek * 5*32d1354aSWojciech Macek * Redistribution and use in source and binary forms, with or without 6*32d1354aSWojciech Macek * modification, are permitted provided that the following conditions 7*32d1354aSWojciech Macek * are met: 8*32d1354aSWojciech Macek * 1. Redistributions of source code must retain the above copyright 9*32d1354aSWojciech Macek * notice, this list of conditions and the following disclaimer. 10*32d1354aSWojciech Macek * 2. Redistributions in binary form must reproduce the above copyright 11*32d1354aSWojciech Macek * notice, this list of conditions and the following disclaimer in the 12*32d1354aSWojciech Macek * documentation and/or other materials provided with the distribution. 13*32d1354aSWojciech Macek * 14*32d1354aSWojciech Macek * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15*32d1354aSWojciech Macek * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16*32d1354aSWojciech Macek * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17*32d1354aSWojciech Macek * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18*32d1354aSWojciech Macek * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19*32d1354aSWojciech Macek * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20*32d1354aSWojciech Macek * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21*32d1354aSWojciech Macek * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22*32d1354aSWojciech Macek * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23*32d1354aSWojciech Macek * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24*32d1354aSWojciech Macek * SUCH DAMAGE. 25*32d1354aSWojciech Macek */ 26*32d1354aSWojciech Macek 27*32d1354aSWojciech Macek #include <sys/cdefs.h> 28*32d1354aSWojciech Macek __FBSDID("$FreeBSD$"); 29*32d1354aSWojciech Macek 30*32d1354aSWojciech Macek #include <sys/param.h> 31*32d1354aSWojciech Macek #include <sys/systm.h> 32*32d1354aSWojciech Macek #include <sys/module.h> 33*32d1354aSWojciech Macek #include <sys/bus.h> 34*32d1354aSWojciech Macek #include <sys/conf.h> 35*32d1354aSWojciech Macek #include <sys/clock.h> 36*32d1354aSWojciech Macek #include <sys/cpu.h> 37*32d1354aSWojciech Macek #include <sys/kernel.h> 38*32d1354aSWojciech Macek #include <sys/reboot.h> 39*32d1354aSWojciech Macek #include <sys/sysctl.h> 40*32d1354aSWojciech Macek 41*32d1354aSWojciech Macek #include <dev/ofw/ofw_bus.h> 42*32d1354aSWojciech Macek #include <dev/ofw/ofw_bus_subr.h> 43*32d1354aSWojciech Macek #include <dev/ofw/openfirm.h> 44*32d1354aSWojciech Macek 45*32d1354aSWojciech Macek #include "clock_if.h" 46*32d1354aSWojciech Macek #include "opal.h" 47*32d1354aSWojciech Macek 48*32d1354aSWojciech Macek static int opaldev_probe(device_t); 49*32d1354aSWojciech Macek static int opaldev_attach(device_t); 50*32d1354aSWojciech Macek /* clock interface */ 51*32d1354aSWojciech Macek static int opal_gettime(device_t dev, struct timespec *ts); 52*32d1354aSWojciech Macek static int opal_settime(device_t dev, struct timespec *ts); 53*32d1354aSWojciech Macek /* ofw bus interface */ 54*32d1354aSWojciech Macek static const struct ofw_bus_devinfo *opaldev_get_devinfo(device_t dev, 55*32d1354aSWojciech Macek device_t child); 56*32d1354aSWojciech Macek 57*32d1354aSWojciech Macek static void opal_shutdown(void *arg, int howto); 58*32d1354aSWojciech Macek 59*32d1354aSWojciech Macek static device_method_t opaldev_methods[] = { 60*32d1354aSWojciech Macek /* Device interface */ 61*32d1354aSWojciech Macek DEVMETHOD(device_probe, opaldev_probe), 62*32d1354aSWojciech Macek DEVMETHOD(device_attach, opaldev_attach), 63*32d1354aSWojciech Macek 64*32d1354aSWojciech Macek /* clock interface */ 65*32d1354aSWojciech Macek DEVMETHOD(clock_gettime, opal_gettime), 66*32d1354aSWojciech Macek DEVMETHOD(clock_settime, opal_settime), 67*32d1354aSWojciech Macek 68*32d1354aSWojciech Macek /* ofw_bus interface */ 69*32d1354aSWojciech Macek DEVMETHOD(ofw_bus_get_devinfo, opaldev_get_devinfo), 70*32d1354aSWojciech Macek DEVMETHOD(ofw_bus_get_compat, ofw_bus_gen_get_compat), 71*32d1354aSWojciech Macek DEVMETHOD(ofw_bus_get_model, ofw_bus_gen_get_model), 72*32d1354aSWojciech Macek DEVMETHOD(ofw_bus_get_name, ofw_bus_gen_get_name), 73*32d1354aSWojciech Macek DEVMETHOD(ofw_bus_get_node, ofw_bus_gen_get_node), 74*32d1354aSWojciech Macek DEVMETHOD(ofw_bus_get_type, ofw_bus_gen_get_type), 75*32d1354aSWojciech Macek 76*32d1354aSWojciech Macek DEVMETHOD_END 77*32d1354aSWojciech Macek }; 78*32d1354aSWojciech Macek 79*32d1354aSWojciech Macek static driver_t opaldev_driver = { 80*32d1354aSWojciech Macek "opal", 81*32d1354aSWojciech Macek opaldev_methods, 82*32d1354aSWojciech Macek 0 83*32d1354aSWojciech Macek }; 84*32d1354aSWojciech Macek 85*32d1354aSWojciech Macek static devclass_t opaldev_devclass; 86*32d1354aSWojciech Macek 87*32d1354aSWojciech Macek DRIVER_MODULE(opaldev, ofwbus, opaldev_driver, opaldev_devclass, 0, 0); 88*32d1354aSWojciech Macek 89*32d1354aSWojciech Macek static int 90*32d1354aSWojciech Macek opaldev_probe(device_t dev) 91*32d1354aSWojciech Macek { 92*32d1354aSWojciech Macek 93*32d1354aSWojciech Macek if (!ofw_bus_is_compatible(dev, "ibm,opal-v3")) 94*32d1354aSWojciech Macek return (ENXIO); 95*32d1354aSWojciech Macek if (opal_check() != 0) 96*32d1354aSWojciech Macek return (ENXIO); 97*32d1354aSWojciech Macek 98*32d1354aSWojciech Macek device_set_desc(dev, "OPAL Abstraction Firmware"); 99*32d1354aSWojciech Macek return (BUS_PROBE_SPECIFIC); 100*32d1354aSWojciech Macek } 101*32d1354aSWojciech Macek 102*32d1354aSWojciech Macek static int 103*32d1354aSWojciech Macek opaldev_attach(device_t dev) 104*32d1354aSWojciech Macek { 105*32d1354aSWojciech Macek phandle_t child; 106*32d1354aSWojciech Macek device_t cdev; 107*32d1354aSWojciech Macek struct ofw_bus_devinfo *dinfo; 108*32d1354aSWojciech Macek 109*32d1354aSWojciech Macek if (0 /* XXX NOT YET TEST FOR RTC */) 110*32d1354aSWojciech Macek clock_register(dev, 2000); 111*32d1354aSWojciech Macek 112*32d1354aSWojciech Macek EVENTHANDLER_REGISTER(shutdown_final, opal_shutdown, NULL, 113*32d1354aSWojciech Macek SHUTDOWN_PRI_LAST); 114*32d1354aSWojciech Macek 115*32d1354aSWojciech Macek for (child = OF_child(ofw_bus_get_node(dev)); child != 0; 116*32d1354aSWojciech Macek child = OF_peer(child)) { 117*32d1354aSWojciech Macek dinfo = malloc(sizeof(*dinfo), M_DEVBUF, M_WAITOK | M_ZERO); 118*32d1354aSWojciech Macek if (ofw_bus_gen_setup_devinfo(dinfo, child) != 0) { 119*32d1354aSWojciech Macek free(dinfo, M_DEVBUF); 120*32d1354aSWojciech Macek continue; 121*32d1354aSWojciech Macek } 122*32d1354aSWojciech Macek cdev = device_add_child(dev, NULL, -1); 123*32d1354aSWojciech Macek if (cdev == NULL) { 124*32d1354aSWojciech Macek device_printf(dev, "<%s>: device_add_child failed\n", 125*32d1354aSWojciech Macek dinfo->obd_name); 126*32d1354aSWojciech Macek ofw_bus_gen_destroy_devinfo(dinfo); 127*32d1354aSWojciech Macek free(dinfo, M_DEVBUF); 128*32d1354aSWojciech Macek continue; 129*32d1354aSWojciech Macek } 130*32d1354aSWojciech Macek device_set_ivars(cdev, dinfo); 131*32d1354aSWojciech Macek } 132*32d1354aSWojciech Macek 133*32d1354aSWojciech Macek return (bus_generic_attach(dev)); 134*32d1354aSWojciech Macek } 135*32d1354aSWojciech Macek 136*32d1354aSWojciech Macek static int 137*32d1354aSWojciech Macek opal_gettime(device_t dev, struct timespec *ts) { 138*32d1354aSWojciech Macek return (ENXIO); 139*32d1354aSWojciech Macek } 140*32d1354aSWojciech Macek 141*32d1354aSWojciech Macek static int 142*32d1354aSWojciech Macek opal_settime(device_t dev, struct timespec *ts) 143*32d1354aSWojciech Macek { 144*32d1354aSWojciech Macek return (0); 145*32d1354aSWojciech Macek } 146*32d1354aSWojciech Macek 147*32d1354aSWojciech Macek static const struct ofw_bus_devinfo * 148*32d1354aSWojciech Macek opaldev_get_devinfo(device_t dev, device_t child) 149*32d1354aSWojciech Macek { 150*32d1354aSWojciech Macek return (device_get_ivars(child)); 151*32d1354aSWojciech Macek } 152*32d1354aSWojciech Macek 153*32d1354aSWojciech Macek static void 154*32d1354aSWojciech Macek opal_shutdown(void *arg, int howto) 155*32d1354aSWojciech Macek { 156*32d1354aSWojciech Macek 157*32d1354aSWojciech Macek if (howto & RB_HALT) 158*32d1354aSWojciech Macek opal_call(OPAL_CEC_POWER_DOWN, 0 /* Normal power off */); 159*32d1354aSWojciech Macek else 160*32d1354aSWojciech Macek opal_call(OPAL_CEC_REBOOT); 161*32d1354aSWojciech Macek } 162*32d1354aSWojciech Macek 163