132d1354aSWojciech Macek /*- 232d1354aSWojciech Macek * Copyright (c) 2015 Nathan Whitehorn 332d1354aSWojciech Macek * All rights reserved. 432d1354aSWojciech Macek * 532d1354aSWojciech Macek * Redistribution and use in source and binary forms, with or without 632d1354aSWojciech Macek * modification, are permitted provided that the following conditions 732d1354aSWojciech Macek * are met: 832d1354aSWojciech Macek * 1. Redistributions of source code must retain the above copyright 932d1354aSWojciech Macek * notice, this list of conditions and the following disclaimer. 1032d1354aSWojciech Macek * 2. Redistributions in binary form must reproduce the above copyright 1132d1354aSWojciech Macek * notice, this list of conditions and the following disclaimer in the 1232d1354aSWojciech Macek * documentation and/or other materials provided with the distribution. 1332d1354aSWojciech Macek * 1432d1354aSWojciech Macek * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1532d1354aSWojciech Macek * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1632d1354aSWojciech Macek * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1732d1354aSWojciech Macek * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1832d1354aSWojciech Macek * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1932d1354aSWojciech Macek * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2032d1354aSWojciech Macek * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2132d1354aSWojciech Macek * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2232d1354aSWojciech Macek * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2332d1354aSWojciech Macek * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2432d1354aSWojciech Macek * SUCH DAMAGE. 2532d1354aSWojciech Macek */ 2632d1354aSWojciech Macek 2732d1354aSWojciech Macek #include <sys/cdefs.h> 2832d1354aSWojciech Macek __FBSDID("$FreeBSD$"); 2932d1354aSWojciech Macek 3032d1354aSWojciech Macek #include <sys/param.h> 3132d1354aSWojciech Macek #include <sys/systm.h> 3232d1354aSWojciech Macek #include <sys/module.h> 3332d1354aSWojciech Macek #include <sys/bus.h> 3432d1354aSWojciech Macek #include <sys/conf.h> 3532d1354aSWojciech Macek #include <sys/clock.h> 3632d1354aSWojciech Macek #include <sys/cpu.h> 3732d1354aSWojciech Macek #include <sys/kernel.h> 38*911a9260SJustin Hibbits #include <sys/kthread.h> 3932d1354aSWojciech Macek #include <sys/reboot.h> 4032d1354aSWojciech Macek #include <sys/sysctl.h> 41504d9b60SWojciech Macek #include <sys/endian.h> 42504d9b60SWojciech Macek 43504d9b60SWojciech Macek #include <vm/vm.h> 44504d9b60SWojciech Macek #include <vm/pmap.h> 4532d1354aSWojciech Macek 4632d1354aSWojciech Macek #include <dev/ofw/ofw_bus.h> 4732d1354aSWojciech Macek #include <dev/ofw/ofw_bus_subr.h> 4832d1354aSWojciech Macek #include <dev/ofw/openfirm.h> 4932d1354aSWojciech Macek 5032d1354aSWojciech Macek #include "clock_if.h" 5132d1354aSWojciech Macek #include "opal.h" 5232d1354aSWojciech Macek 5332d1354aSWojciech Macek static int opaldev_probe(device_t); 5432d1354aSWojciech Macek static int opaldev_attach(device_t); 5532d1354aSWojciech Macek /* clock interface */ 5632d1354aSWojciech Macek static int opal_gettime(device_t dev, struct timespec *ts); 5732d1354aSWojciech Macek static int opal_settime(device_t dev, struct timespec *ts); 5832d1354aSWojciech Macek /* ofw bus interface */ 5932d1354aSWojciech Macek static const struct ofw_bus_devinfo *opaldev_get_devinfo(device_t dev, 6032d1354aSWojciech Macek device_t child); 6132d1354aSWojciech Macek 6232d1354aSWojciech Macek static void opal_shutdown(void *arg, int howto); 63*911a9260SJustin Hibbits static void opal_handle_shutdown_message(void *unused, 64*911a9260SJustin Hibbits struct opal_msg *msg); 65504d9b60SWojciech Macek static void opal_intr(void *); 6632d1354aSWojciech Macek 6732d1354aSWojciech Macek static device_method_t opaldev_methods[] = { 6832d1354aSWojciech Macek /* Device interface */ 6932d1354aSWojciech Macek DEVMETHOD(device_probe, opaldev_probe), 7032d1354aSWojciech Macek DEVMETHOD(device_attach, opaldev_attach), 7132d1354aSWojciech Macek 7232d1354aSWojciech Macek /* clock interface */ 7332d1354aSWojciech Macek DEVMETHOD(clock_gettime, opal_gettime), 7432d1354aSWojciech Macek DEVMETHOD(clock_settime, opal_settime), 7532d1354aSWojciech Macek 7627ef2ca8SJustin Hibbits /* Bus interface */ 7727ef2ca8SJustin Hibbits DEVMETHOD(bus_child_pnpinfo_str, ofw_bus_gen_child_pnpinfo_str), 7827ef2ca8SJustin Hibbits 7932d1354aSWojciech Macek /* ofw_bus interface */ 8032d1354aSWojciech Macek DEVMETHOD(ofw_bus_get_devinfo, opaldev_get_devinfo), 8132d1354aSWojciech Macek DEVMETHOD(ofw_bus_get_compat, ofw_bus_gen_get_compat), 8232d1354aSWojciech Macek DEVMETHOD(ofw_bus_get_model, ofw_bus_gen_get_model), 8332d1354aSWojciech Macek DEVMETHOD(ofw_bus_get_name, ofw_bus_gen_get_name), 8432d1354aSWojciech Macek DEVMETHOD(ofw_bus_get_node, ofw_bus_gen_get_node), 8532d1354aSWojciech Macek DEVMETHOD(ofw_bus_get_type, ofw_bus_gen_get_type), 8632d1354aSWojciech Macek 8732d1354aSWojciech Macek DEVMETHOD_END 8832d1354aSWojciech Macek }; 8932d1354aSWojciech Macek 9032d1354aSWojciech Macek static driver_t opaldev_driver = { 9132d1354aSWojciech Macek "opal", 9232d1354aSWojciech Macek opaldev_methods, 9332d1354aSWojciech Macek 0 9432d1354aSWojciech Macek }; 9532d1354aSWojciech Macek 9632d1354aSWojciech Macek static devclass_t opaldev_devclass; 9732d1354aSWojciech Macek 9832d1354aSWojciech Macek DRIVER_MODULE(opaldev, ofwbus, opaldev_driver, opaldev_devclass, 0, 0); 9932d1354aSWojciech Macek 100*911a9260SJustin Hibbits static void opal_heartbeat(void); 101*911a9260SJustin Hibbits static void opal_handle_messages(void); 102*911a9260SJustin Hibbits 103*911a9260SJustin Hibbits static struct proc *opal_hb_proc; 104*911a9260SJustin Hibbits static struct kproc_desc opal_heartbeat_kp = { 105*911a9260SJustin Hibbits "opal_heartbeat", 106*911a9260SJustin Hibbits opal_heartbeat, 107*911a9260SJustin Hibbits &opal_hb_proc 108*911a9260SJustin Hibbits }; 109*911a9260SJustin Hibbits 110*911a9260SJustin Hibbits SYSINIT(opal_heartbeat_setup, SI_SUB_KTHREAD_IDLE, SI_ORDER_ANY, kproc_start, 111*911a9260SJustin Hibbits &opal_heartbeat_kp); 112*911a9260SJustin Hibbits 113*911a9260SJustin Hibbits static int opal_heartbeat_ms; 114*911a9260SJustin Hibbits EVENTHANDLER_LIST_DEFINE(OPAL_ASYNC_COMP); 115*911a9260SJustin Hibbits EVENTHANDLER_LIST_DEFINE(OPAL_EPOW); 116*911a9260SJustin Hibbits EVENTHANDLER_LIST_DEFINE(OPAL_SHUTDOWN); 117*911a9260SJustin Hibbits EVENTHANDLER_LIST_DEFINE(OPAL_HMI_EVT); 118*911a9260SJustin Hibbits EVENTHANDLER_LIST_DEFINE(OPAL_DPO); 119*911a9260SJustin Hibbits EVENTHANDLER_LIST_DEFINE(OPAL_OCC); 120*911a9260SJustin Hibbits 121*911a9260SJustin Hibbits #define OPAL_SOFT_OFF 0 122*911a9260SJustin Hibbits #define OPAL_SOFT_REBOOT 1 123*911a9260SJustin Hibbits 124*911a9260SJustin Hibbits static void 125*911a9260SJustin Hibbits opal_heartbeat(void) 126*911a9260SJustin Hibbits { 127*911a9260SJustin Hibbits uint64_t events; 128*911a9260SJustin Hibbits 129*911a9260SJustin Hibbits if (opal_heartbeat_ms == 0) 130*911a9260SJustin Hibbits kproc_exit(0); 131*911a9260SJustin Hibbits 132*911a9260SJustin Hibbits while (1) { 133*911a9260SJustin Hibbits events = 0; 134*911a9260SJustin Hibbits /* Turn the OPAL state crank */ 135*911a9260SJustin Hibbits opal_call(OPAL_POLL_EVENTS, vtophys(&events)); 136*911a9260SJustin Hibbits if (events & OPAL_EVENT_MSG_PENDING) 137*911a9260SJustin Hibbits opal_handle_messages(); 138*911a9260SJustin Hibbits tsleep(opal_hb_proc, 0, "opal", 139*911a9260SJustin Hibbits MSEC_2_TICKS(opal_heartbeat_ms)); 140*911a9260SJustin Hibbits } 141*911a9260SJustin Hibbits } 142*911a9260SJustin Hibbits 14332d1354aSWojciech Macek static int 14432d1354aSWojciech Macek opaldev_probe(device_t dev) 14532d1354aSWojciech Macek { 146504d9b60SWojciech Macek phandle_t iparent; 147504d9b60SWojciech Macek pcell_t *irqs; 148504d9b60SWojciech Macek int i, n_irqs; 14932d1354aSWojciech Macek 15032d1354aSWojciech Macek if (!ofw_bus_is_compatible(dev, "ibm,opal-v3")) 15132d1354aSWojciech Macek return (ENXIO); 15232d1354aSWojciech Macek if (opal_check() != 0) 15332d1354aSWojciech Macek return (ENXIO); 15432d1354aSWojciech Macek 15532d1354aSWojciech Macek device_set_desc(dev, "OPAL Abstraction Firmware"); 156504d9b60SWojciech Macek 157504d9b60SWojciech Macek /* Manually add IRQs before attaching */ 158504d9b60SWojciech Macek if (OF_hasprop(ofw_bus_get_node(dev), "opal-interrupts")) { 159504d9b60SWojciech Macek iparent = OF_finddevice("/interrupt-controller@0"); 160504d9b60SWojciech Macek iparent = OF_xref_from_node(iparent); 161504d9b60SWojciech Macek 162504d9b60SWojciech Macek n_irqs = OF_getproplen(ofw_bus_get_node(dev), 163504d9b60SWojciech Macek "opal-interrupts") / sizeof(*irqs); 164504d9b60SWojciech Macek irqs = malloc(n_irqs * sizeof(*irqs), M_DEVBUF, M_WAITOK); 165504d9b60SWojciech Macek OF_getencprop(ofw_bus_get_node(dev), "opal-interrupts", irqs, 166504d9b60SWojciech Macek n_irqs * sizeof(*irqs)); 167504d9b60SWojciech Macek for (i = 0; i < n_irqs; i++) 168504d9b60SWojciech Macek bus_set_resource(dev, SYS_RES_IRQ, i, 169504d9b60SWojciech Macek ofw_bus_map_intr(dev, iparent, 1, &irqs[i]), 1); 170504d9b60SWojciech Macek free(irqs, M_DEVBUF); 171504d9b60SWojciech Macek } 172504d9b60SWojciech Macek 173504d9b60SWojciech Macek 17432d1354aSWojciech Macek return (BUS_PROBE_SPECIFIC); 17532d1354aSWojciech Macek } 17632d1354aSWojciech Macek 17732d1354aSWojciech Macek static int 17832d1354aSWojciech Macek opaldev_attach(device_t dev) 17932d1354aSWojciech Macek { 18032d1354aSWojciech Macek phandle_t child; 18132d1354aSWojciech Macek device_t cdev; 182504d9b60SWojciech Macek uint64_t junk; 183504d9b60SWojciech Macek int i, rv; 184dac618a6SJustin Hibbits uint32_t async_count; 18532d1354aSWojciech Macek struct ofw_bus_devinfo *dinfo; 186504d9b60SWojciech Macek struct resource *irq; 18732d1354aSWojciech Macek 188504d9b60SWojciech Macek /* Test for RTC support and register clock if it works */ 189504d9b60SWojciech Macek rv = opal_call(OPAL_RTC_READ, vtophys(&junk), vtophys(&junk)); 190504d9b60SWojciech Macek do { 191504d9b60SWojciech Macek rv = opal_call(OPAL_RTC_READ, vtophys(&junk), vtophys(&junk)); 192504d9b60SWojciech Macek if (rv == OPAL_BUSY_EVENT) 193504d9b60SWojciech Macek rv = opal_call(OPAL_POLL_EVENTS, 0); 194504d9b60SWojciech Macek } while (rv == OPAL_BUSY_EVENT); 195504d9b60SWojciech Macek 196504d9b60SWojciech Macek if (rv == OPAL_SUCCESS) 19732d1354aSWojciech Macek clock_register(dev, 2000); 19832d1354aSWojciech Macek 199*911a9260SJustin Hibbits EVENTHANDLER_REGISTER(OPAL_SHUTDOWN, opal_handle_shutdown_message, 200*911a9260SJustin Hibbits NULL, EVENTHANDLER_PRI_ANY); 20132d1354aSWojciech Macek EVENTHANDLER_REGISTER(shutdown_final, opal_shutdown, NULL, 20232d1354aSWojciech Macek SHUTDOWN_PRI_LAST); 20332d1354aSWojciech Macek 204*911a9260SJustin Hibbits OF_getencprop(ofw_bus_get_node(dev), "ibm,heartbeat-ms", 205*911a9260SJustin Hibbits &opal_heartbeat_ms, sizeof(opal_heartbeat_ms)); 206504d9b60SWojciech Macek /* Bind to interrupts */ 207504d9b60SWojciech Macek for (i = 0; (irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &i, 208504d9b60SWojciech Macek RF_ACTIVE)) != NULL; i++) 209504d9b60SWojciech Macek bus_setup_intr(dev, irq, INTR_TYPE_TTY | INTR_MPSAFE | 210504d9b60SWojciech Macek INTR_ENTROPY, NULL, opal_intr, (void *)rman_get_start(irq), 211504d9b60SWojciech Macek NULL); 212504d9b60SWojciech Macek 213dac618a6SJustin Hibbits OF_getencprop(ofw_bus_get_node(dev), "opal-msg-async-num", 214dac618a6SJustin Hibbits &async_count, sizeof(async_count)); 215dac618a6SJustin Hibbits opal_init_async_tokens(async_count); 216dac618a6SJustin Hibbits 21732d1354aSWojciech Macek for (child = OF_child(ofw_bus_get_node(dev)); child != 0; 21832d1354aSWojciech Macek child = OF_peer(child)) { 21932d1354aSWojciech Macek dinfo = malloc(sizeof(*dinfo), M_DEVBUF, M_WAITOK | M_ZERO); 22032d1354aSWojciech Macek if (ofw_bus_gen_setup_devinfo(dinfo, child) != 0) { 22132d1354aSWojciech Macek free(dinfo, M_DEVBUF); 22232d1354aSWojciech Macek continue; 22332d1354aSWojciech Macek } 22432d1354aSWojciech Macek cdev = device_add_child(dev, NULL, -1); 22532d1354aSWojciech Macek if (cdev == NULL) { 22632d1354aSWojciech Macek device_printf(dev, "<%s>: device_add_child failed\n", 22732d1354aSWojciech Macek dinfo->obd_name); 22832d1354aSWojciech Macek ofw_bus_gen_destroy_devinfo(dinfo); 22932d1354aSWojciech Macek free(dinfo, M_DEVBUF); 23032d1354aSWojciech Macek continue; 23132d1354aSWojciech Macek } 23232d1354aSWojciech Macek device_set_ivars(cdev, dinfo); 23332d1354aSWojciech Macek } 23432d1354aSWojciech Macek 23532d1354aSWojciech Macek return (bus_generic_attach(dev)); 23632d1354aSWojciech Macek } 23732d1354aSWojciech Macek 23832d1354aSWojciech Macek static int 239504d9b60SWojciech Macek bcd2bin32(int bcd) 240504d9b60SWojciech Macek { 241504d9b60SWojciech Macek int out = 0; 242504d9b60SWojciech Macek 243504d9b60SWojciech Macek out += bcd2bin(bcd & 0xff); 244504d9b60SWojciech Macek out += 100*bcd2bin((bcd & 0x0000ff00) >> 8); 245504d9b60SWojciech Macek out += 10000*bcd2bin((bcd & 0x00ff0000) >> 16); 246504d9b60SWojciech Macek out += 1000000*bcd2bin((bcd & 0xffff0000) >> 24); 247504d9b60SWojciech Macek 248504d9b60SWojciech Macek return (out); 249504d9b60SWojciech Macek } 250504d9b60SWojciech Macek 251504d9b60SWojciech Macek static int 252eb96cc13SWojciech Macek bin2bcd32(int bin) 253eb96cc13SWojciech Macek { 254eb96cc13SWojciech Macek int out = 0; 255eb96cc13SWojciech Macek int tmp; 256eb96cc13SWojciech Macek 257eb96cc13SWojciech Macek tmp = bin % 100; 258eb96cc13SWojciech Macek out += bin2bcd(tmp) * 1; 259eb96cc13SWojciech Macek bin = bin / 100; 260eb96cc13SWojciech Macek 261eb96cc13SWojciech Macek tmp = bin % 100; 262eb96cc13SWojciech Macek out += bin2bcd(tmp) * 100; 263eb96cc13SWojciech Macek bin = bin / 100; 264eb96cc13SWojciech Macek 265eb96cc13SWojciech Macek tmp = bin % 100; 266eb96cc13SWojciech Macek out += bin2bcd(tmp) * 10000; 267eb96cc13SWojciech Macek 268eb96cc13SWojciech Macek return (out); 269eb96cc13SWojciech Macek } 270eb96cc13SWojciech Macek 271eb96cc13SWojciech Macek static int 272504d9b60SWojciech Macek opal_gettime(device_t dev, struct timespec *ts) 273504d9b60SWojciech Macek { 274504d9b60SWojciech Macek int rv; 275504d9b60SWojciech Macek struct clocktime ct; 276504d9b60SWojciech Macek uint32_t ymd; 277504d9b60SWojciech Macek uint64_t hmsm; 278504d9b60SWojciech Macek 279504d9b60SWojciech Macek rv = opal_call(OPAL_RTC_READ, vtophys(&ymd), vtophys(&hmsm)); 28078f4e2feSBreno Leitao while (rv == OPAL_BUSY_EVENT) { 28178f4e2feSBreno Leitao opal_call(OPAL_POLL_EVENTS, 0); 282504d9b60SWojciech Macek pause("opalrtc", 1); 28378f4e2feSBreno Leitao rv = opal_call(OPAL_RTC_READ, vtophys(&ymd), vtophys(&hmsm)); 284504d9b60SWojciech Macek } 285504d9b60SWojciech Macek 286504d9b60SWojciech Macek if (rv != OPAL_SUCCESS) 28732d1354aSWojciech Macek return (ENXIO); 288504d9b60SWojciech Macek 289504d9b60SWojciech Macek hmsm = be64toh(hmsm); 290504d9b60SWojciech Macek ymd = be32toh(ymd); 291504d9b60SWojciech Macek 292504d9b60SWojciech Macek ct.nsec = bcd2bin32((hmsm & 0x000000ffffff0000) >> 16) * 1000; 293504d9b60SWojciech Macek ct.sec = bcd2bin((hmsm & 0x0000ff0000000000) >> 40); 294504d9b60SWojciech Macek ct.min = bcd2bin((hmsm & 0x00ff000000000000) >> 48); 295504d9b60SWojciech Macek ct.hour = bcd2bin((hmsm & 0xff00000000000000) >> 56); 296504d9b60SWojciech Macek 297504d9b60SWojciech Macek ct.day = bcd2bin((ymd & 0x000000ff) >> 0); 298504d9b60SWojciech Macek ct.mon = bcd2bin((ymd & 0x0000ff00) >> 8); 299504d9b60SWojciech Macek ct.year = bcd2bin32((ymd & 0xffff0000) >> 16); 300504d9b60SWojciech Macek 301504d9b60SWojciech Macek return (clock_ct_to_ts(&ct, ts)); 30232d1354aSWojciech Macek } 30332d1354aSWojciech Macek 30432d1354aSWojciech Macek static int 30532d1354aSWojciech Macek opal_settime(device_t dev, struct timespec *ts) 30632d1354aSWojciech Macek { 307eb96cc13SWojciech Macek int rv; 308eb96cc13SWojciech Macek struct clocktime ct; 309eb96cc13SWojciech Macek uint32_t ymd = 0; 310eb96cc13SWojciech Macek uint64_t hmsm = 0; 311eb96cc13SWojciech Macek 312eb96cc13SWojciech Macek clock_ts_to_ct(ts, &ct); 313eb96cc13SWojciech Macek 314eb96cc13SWojciech Macek ymd |= (uint32_t)bin2bcd(ct.day); 315eb96cc13SWojciech Macek ymd |= ((uint32_t)bin2bcd(ct.mon) << 8); 316eb96cc13SWojciech Macek ymd |= ((uint32_t)bin2bcd32(ct.year) << 16); 317eb96cc13SWojciech Macek 318eb96cc13SWojciech Macek hmsm |= ((uint64_t)bin2bcd32(ct.nsec/1000) << 16); 319eb96cc13SWojciech Macek hmsm |= ((uint64_t)bin2bcd(ct.sec) << 40); 320eb96cc13SWojciech Macek hmsm |= ((uint64_t)bin2bcd(ct.min) << 48); 321eb96cc13SWojciech Macek hmsm |= ((uint64_t)bin2bcd(ct.hour) << 56); 322eb96cc13SWojciech Macek 323eb96cc13SWojciech Macek hmsm = htobe64(hmsm); 324eb96cc13SWojciech Macek ymd = htobe32(ymd); 325eb96cc13SWojciech Macek 326eb96cc13SWojciech Macek do { 327eb96cc13SWojciech Macek rv = opal_call(OPAL_RTC_WRITE, vtophys(&ymd), vtophys(&hmsm)); 328eb96cc13SWojciech Macek if (rv == OPAL_BUSY_EVENT) { 329eb96cc13SWojciech Macek rv = opal_call(OPAL_POLL_EVENTS, 0); 330eb96cc13SWojciech Macek pause("opalrtc", 1); 331eb96cc13SWojciech Macek } 332eb96cc13SWojciech Macek } while (rv == OPAL_BUSY_EVENT); 333eb96cc13SWojciech Macek 334eb96cc13SWojciech Macek if (rv != OPAL_SUCCESS) 335eb96cc13SWojciech Macek return (ENXIO); 336504d9b60SWojciech Macek 33732d1354aSWojciech Macek return (0); 33832d1354aSWojciech Macek } 33932d1354aSWojciech Macek 34032d1354aSWojciech Macek static const struct ofw_bus_devinfo * 34132d1354aSWojciech Macek opaldev_get_devinfo(device_t dev, device_t child) 34232d1354aSWojciech Macek { 34332d1354aSWojciech Macek return (device_get_ivars(child)); 34432d1354aSWojciech Macek } 34532d1354aSWojciech Macek 34632d1354aSWojciech Macek static void 34732d1354aSWojciech Macek opal_shutdown(void *arg, int howto) 34832d1354aSWojciech Macek { 34932d1354aSWojciech Macek 35032d1354aSWojciech Macek if (howto & RB_HALT) 35132d1354aSWojciech Macek opal_call(OPAL_CEC_POWER_DOWN, 0 /* Normal power off */); 35232d1354aSWojciech Macek else 35332d1354aSWojciech Macek opal_call(OPAL_CEC_REBOOT); 354504d9b60SWojciech Macek 355504d9b60SWojciech Macek opal_call(OPAL_RETURN_CPU); 356504d9b60SWojciech Macek } 357504d9b60SWojciech Macek 358504d9b60SWojciech Macek static void 359*911a9260SJustin Hibbits opal_handle_shutdown_message(void *unused, struct opal_msg *msg) 360*911a9260SJustin Hibbits { 361*911a9260SJustin Hibbits int howto; 362*911a9260SJustin Hibbits 363*911a9260SJustin Hibbits switch (be64toh(msg->params[0])) { 364*911a9260SJustin Hibbits case OPAL_SOFT_OFF: 365*911a9260SJustin Hibbits howto = RB_POWEROFF; 366*911a9260SJustin Hibbits break; 367*911a9260SJustin Hibbits case OPAL_SOFT_REBOOT: 368*911a9260SJustin Hibbits howto = RB_REROOT; 369*911a9260SJustin Hibbits break; 370*911a9260SJustin Hibbits } 371*911a9260SJustin Hibbits shutdown_nice(howto); 372*911a9260SJustin Hibbits } 373*911a9260SJustin Hibbits 374*911a9260SJustin Hibbits static void 375*911a9260SJustin Hibbits opal_handle_messages(void) 376*911a9260SJustin Hibbits { 377*911a9260SJustin Hibbits static struct opal_msg msg; 378*911a9260SJustin Hibbits uint64_t rv; 379*911a9260SJustin Hibbits uint32_t type; 380*911a9260SJustin Hibbits 381*911a9260SJustin Hibbits rv = opal_call(OPAL_GET_MSG, vtophys(&msg), sizeof(msg)); 382*911a9260SJustin Hibbits 383*911a9260SJustin Hibbits if (rv != OPAL_SUCCESS) 384*911a9260SJustin Hibbits return; 385*911a9260SJustin Hibbits 386*911a9260SJustin Hibbits type = be32toh(msg.msg_type); 387*911a9260SJustin Hibbits switch (type) { 388*911a9260SJustin Hibbits case OPAL_MSG_ASYNC_COMP: 389*911a9260SJustin Hibbits EVENTHANDLER_DIRECT_INVOKE(OPAL_ASYNC_COMP, &msg); 390*911a9260SJustin Hibbits break; 391*911a9260SJustin Hibbits case OPAL_MSG_EPOW: 392*911a9260SJustin Hibbits EVENTHANDLER_DIRECT_INVOKE(OPAL_EPOW, &msg); 393*911a9260SJustin Hibbits break; 394*911a9260SJustin Hibbits case OPAL_MSG_SHUTDOWN: 395*911a9260SJustin Hibbits EVENTHANDLER_DIRECT_INVOKE(OPAL_SHUTDOWN, &msg); 396*911a9260SJustin Hibbits break; 397*911a9260SJustin Hibbits case OPAL_MSG_HMI_EVT: 398*911a9260SJustin Hibbits EVENTHANDLER_DIRECT_INVOKE(OPAL_HMI_EVT, &msg); 399*911a9260SJustin Hibbits break; 400*911a9260SJustin Hibbits case OPAL_MSG_DPO: 401*911a9260SJustin Hibbits EVENTHANDLER_DIRECT_INVOKE(OPAL_DPO, &msg); 402*911a9260SJustin Hibbits break; 403*911a9260SJustin Hibbits case OPAL_MSG_OCC: 404*911a9260SJustin Hibbits EVENTHANDLER_DIRECT_INVOKE(OPAL_OCC, &msg); 405*911a9260SJustin Hibbits break; 406*911a9260SJustin Hibbits default: 407*911a9260SJustin Hibbits printf("Unknown OPAL message type %d\n", type); 408*911a9260SJustin Hibbits } 409*911a9260SJustin Hibbits } 410*911a9260SJustin Hibbits 411*911a9260SJustin Hibbits static void 412504d9b60SWojciech Macek opal_intr(void *xintr) 413504d9b60SWojciech Macek { 414504d9b60SWojciech Macek uint64_t events = 0; 415504d9b60SWojciech Macek 416504d9b60SWojciech Macek opal_call(OPAL_HANDLE_INTERRUPT, (uint32_t)(uint64_t)xintr, 417504d9b60SWojciech Macek vtophys(&events)); 418*911a9260SJustin Hibbits /* Wake up the heartbeat, if it's been setup. */ 419*911a9260SJustin Hibbits if (events != 0 && opal_hb_proc != NULL) 420*911a9260SJustin Hibbits wakeup(opal_hb_proc); 421504d9b60SWojciech Macek 42232d1354aSWojciech Macek } 42332d1354aSWojciech Macek 424