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/param.h> 2832d1354aSWojciech Macek #include <sys/systm.h> 2932d1354aSWojciech Macek #include <sys/module.h> 3032d1354aSWojciech Macek #include <sys/bus.h> 3132d1354aSWojciech Macek #include <sys/conf.h> 3232d1354aSWojciech Macek #include <sys/clock.h> 3332d1354aSWojciech Macek #include <sys/cpu.h> 34e2e050c8SConrad Meyer #include <sys/eventhandler.h> 3532d1354aSWojciech Macek #include <sys/kernel.h> 36911a9260SJustin Hibbits #include <sys/kthread.h> 3732d1354aSWojciech Macek #include <sys/reboot.h> 3832d1354aSWojciech Macek #include <sys/sysctl.h> 39504d9b60SWojciech Macek #include <sys/endian.h> 40504d9b60SWojciech Macek 41504d9b60SWojciech Macek #include <vm/vm.h> 42504d9b60SWojciech Macek #include <vm/pmap.h> 4332d1354aSWojciech Macek 4432d1354aSWojciech Macek #include <dev/ofw/ofw_bus.h> 4532d1354aSWojciech Macek #include <dev/ofw/ofw_bus_subr.h> 4632d1354aSWojciech Macek #include <dev/ofw/openfirm.h> 4732d1354aSWojciech Macek 4832d1354aSWojciech Macek #include "clock_if.h" 4932d1354aSWojciech Macek #include "opal.h" 5032d1354aSWojciech Macek 5132d1354aSWojciech Macek static int opaldev_probe(device_t); 5232d1354aSWojciech Macek static int opaldev_attach(device_t); 5332d1354aSWojciech Macek /* clock interface */ 5432d1354aSWojciech Macek static int opal_gettime(device_t dev, struct timespec *ts); 5532d1354aSWojciech Macek static int opal_settime(device_t dev, struct timespec *ts); 5632d1354aSWojciech Macek /* ofw bus interface */ 5732d1354aSWojciech Macek static const struct ofw_bus_devinfo *opaldev_get_devinfo(device_t dev, 5832d1354aSWojciech Macek device_t child); 5932d1354aSWojciech Macek 6032d1354aSWojciech Macek static void opal_shutdown(void *arg, int howto); 61911a9260SJustin Hibbits static void opal_handle_shutdown_message(void *unused, 62911a9260SJustin Hibbits struct opal_msg *msg); 63504d9b60SWojciech Macek static void opal_intr(void *); 6432d1354aSWojciech Macek 6532d1354aSWojciech Macek static device_method_t opaldev_methods[] = { 6632d1354aSWojciech Macek /* Device interface */ 6732d1354aSWojciech Macek DEVMETHOD(device_probe, opaldev_probe), 6832d1354aSWojciech Macek DEVMETHOD(device_attach, opaldev_attach), 6932d1354aSWojciech Macek 7032d1354aSWojciech Macek /* clock interface */ 7132d1354aSWojciech Macek DEVMETHOD(clock_gettime, opal_gettime), 7232d1354aSWojciech Macek DEVMETHOD(clock_settime, opal_settime), 7332d1354aSWojciech Macek 7427ef2ca8SJustin Hibbits /* Bus interface */ 75ddfc9c4cSWarner Losh DEVMETHOD(bus_child_pnpinfo, ofw_bus_gen_child_pnpinfo), 7627ef2ca8SJustin Hibbits 7732d1354aSWojciech Macek /* ofw_bus interface */ 7832d1354aSWojciech Macek DEVMETHOD(ofw_bus_get_devinfo, opaldev_get_devinfo), 7932d1354aSWojciech Macek DEVMETHOD(ofw_bus_get_compat, ofw_bus_gen_get_compat), 8032d1354aSWojciech Macek DEVMETHOD(ofw_bus_get_model, ofw_bus_gen_get_model), 8132d1354aSWojciech Macek DEVMETHOD(ofw_bus_get_name, ofw_bus_gen_get_name), 8232d1354aSWojciech Macek DEVMETHOD(ofw_bus_get_node, ofw_bus_gen_get_node), 8332d1354aSWojciech Macek DEVMETHOD(ofw_bus_get_type, ofw_bus_gen_get_type), 8432d1354aSWojciech Macek 8532d1354aSWojciech Macek DEVMETHOD_END 8632d1354aSWojciech Macek }; 8732d1354aSWojciech Macek 8832d1354aSWojciech Macek static driver_t opaldev_driver = { 8932d1354aSWojciech Macek "opal", 9032d1354aSWojciech Macek opaldev_methods, 9132d1354aSWojciech Macek 0 9232d1354aSWojciech Macek }; 9332d1354aSWojciech Macek 945edf159fSJohn Baldwin EARLY_DRIVER_MODULE(opaldev, ofwbus, opaldev_driver, 0, 0, BUS_PASS_BUS); 9532d1354aSWojciech Macek 96911a9260SJustin Hibbits static void opal_heartbeat(void); 97911a9260SJustin Hibbits static void opal_handle_messages(void); 98911a9260SJustin Hibbits 99911a9260SJustin Hibbits static struct proc *opal_hb_proc; 100911a9260SJustin Hibbits static struct kproc_desc opal_heartbeat_kp = { 101911a9260SJustin Hibbits "opal_heartbeat", 102911a9260SJustin Hibbits opal_heartbeat, 103911a9260SJustin Hibbits &opal_hb_proc 104911a9260SJustin Hibbits }; 105911a9260SJustin Hibbits 106911a9260SJustin Hibbits SYSINIT(opal_heartbeat_setup, SI_SUB_KTHREAD_IDLE, SI_ORDER_ANY, kproc_start, 107911a9260SJustin Hibbits &opal_heartbeat_kp); 108911a9260SJustin Hibbits 109911a9260SJustin Hibbits static int opal_heartbeat_ms; 110911a9260SJustin Hibbits EVENTHANDLER_LIST_DEFINE(OPAL_ASYNC_COMP); 111911a9260SJustin Hibbits EVENTHANDLER_LIST_DEFINE(OPAL_EPOW); 112911a9260SJustin Hibbits EVENTHANDLER_LIST_DEFINE(OPAL_SHUTDOWN); 113911a9260SJustin Hibbits EVENTHANDLER_LIST_DEFINE(OPAL_HMI_EVT); 114911a9260SJustin Hibbits EVENTHANDLER_LIST_DEFINE(OPAL_DPO); 115911a9260SJustin Hibbits EVENTHANDLER_LIST_DEFINE(OPAL_OCC); 116911a9260SJustin Hibbits 117911a9260SJustin Hibbits #define OPAL_SOFT_OFF 0 118911a9260SJustin Hibbits #define OPAL_SOFT_REBOOT 1 119911a9260SJustin Hibbits 120911a9260SJustin Hibbits static void 121911a9260SJustin Hibbits opal_heartbeat(void) 122911a9260SJustin Hibbits { 123911a9260SJustin Hibbits uint64_t events; 124911a9260SJustin Hibbits 125911a9260SJustin Hibbits if (opal_heartbeat_ms == 0) 126911a9260SJustin Hibbits kproc_exit(0); 127911a9260SJustin Hibbits 128911a9260SJustin Hibbits while (1) { 129911a9260SJustin Hibbits events = 0; 130911a9260SJustin Hibbits /* Turn the OPAL state crank */ 131911a9260SJustin Hibbits opal_call(OPAL_POLL_EVENTS, vtophys(&events)); 132bf933a83SBrandon Bergren if (be64toh(events) & OPAL_EVENT_MSG_PENDING) 133911a9260SJustin Hibbits opal_handle_messages(); 134911a9260SJustin Hibbits tsleep(opal_hb_proc, 0, "opal", 135911a9260SJustin Hibbits MSEC_2_TICKS(opal_heartbeat_ms)); 136911a9260SJustin Hibbits } 137911a9260SJustin Hibbits } 138911a9260SJustin Hibbits 13932d1354aSWojciech Macek static int 14032d1354aSWojciech Macek opaldev_probe(device_t dev) 14132d1354aSWojciech Macek { 142504d9b60SWojciech Macek phandle_t iparent; 143504d9b60SWojciech Macek pcell_t *irqs; 144504d9b60SWojciech Macek int i, n_irqs; 14532d1354aSWojciech Macek 14632d1354aSWojciech Macek if (!ofw_bus_is_compatible(dev, "ibm,opal-v3")) 14732d1354aSWojciech Macek return (ENXIO); 14832d1354aSWojciech Macek if (opal_check() != 0) 14932d1354aSWojciech Macek return (ENXIO); 15032d1354aSWojciech Macek 15132d1354aSWojciech Macek device_set_desc(dev, "OPAL Abstraction Firmware"); 152504d9b60SWojciech Macek 153504d9b60SWojciech Macek /* Manually add IRQs before attaching */ 154504d9b60SWojciech Macek if (OF_hasprop(ofw_bus_get_node(dev), "opal-interrupts")) { 155504d9b60SWojciech Macek iparent = OF_finddevice("/interrupt-controller@0"); 156504d9b60SWojciech Macek iparent = OF_xref_from_node(iparent); 157504d9b60SWojciech Macek 158504d9b60SWojciech Macek n_irqs = OF_getproplen(ofw_bus_get_node(dev), 159504d9b60SWojciech Macek "opal-interrupts") / sizeof(*irqs); 160504d9b60SWojciech Macek irqs = malloc(n_irqs * sizeof(*irqs), M_DEVBUF, M_WAITOK); 161504d9b60SWojciech Macek OF_getencprop(ofw_bus_get_node(dev), "opal-interrupts", irqs, 162504d9b60SWojciech Macek n_irqs * sizeof(*irqs)); 163504d9b60SWojciech Macek for (i = 0; i < n_irqs; i++) 164504d9b60SWojciech Macek bus_set_resource(dev, SYS_RES_IRQ, i, 165504d9b60SWojciech Macek ofw_bus_map_intr(dev, iparent, 1, &irqs[i]), 1); 166504d9b60SWojciech Macek free(irqs, M_DEVBUF); 167504d9b60SWojciech Macek } 168504d9b60SWojciech Macek 16932d1354aSWojciech Macek return (BUS_PROBE_SPECIFIC); 17032d1354aSWojciech Macek } 17132d1354aSWojciech Macek 17232d1354aSWojciech Macek static int 17332d1354aSWojciech Macek opaldev_attach(device_t dev) 17432d1354aSWojciech Macek { 17532d1354aSWojciech Macek phandle_t child; 17632d1354aSWojciech Macek device_t cdev; 177504d9b60SWojciech Macek uint64_t junk; 178504d9b60SWojciech Macek int i, rv; 179dac618a6SJustin Hibbits uint32_t async_count; 18032d1354aSWojciech Macek struct ofw_bus_devinfo *dinfo; 181504d9b60SWojciech Macek struct resource *irq; 18232d1354aSWojciech Macek 183504d9b60SWojciech Macek /* Test for RTC support and register clock if it works */ 184504d9b60SWojciech Macek rv = opal_call(OPAL_RTC_READ, vtophys(&junk), vtophys(&junk)); 185504d9b60SWojciech Macek do { 186504d9b60SWojciech Macek rv = opal_call(OPAL_RTC_READ, vtophys(&junk), vtophys(&junk)); 187504d9b60SWojciech Macek if (rv == OPAL_BUSY_EVENT) 188504d9b60SWojciech Macek rv = opal_call(OPAL_POLL_EVENTS, 0); 189504d9b60SWojciech Macek } while (rv == OPAL_BUSY_EVENT); 190504d9b60SWojciech Macek 191504d9b60SWojciech Macek if (rv == OPAL_SUCCESS) 19232d1354aSWojciech Macek clock_register(dev, 2000); 19332d1354aSWojciech Macek 194911a9260SJustin Hibbits EVENTHANDLER_REGISTER(OPAL_SHUTDOWN, opal_handle_shutdown_message, 195911a9260SJustin Hibbits NULL, EVENTHANDLER_PRI_ANY); 19632d1354aSWojciech Macek EVENTHANDLER_REGISTER(shutdown_final, opal_shutdown, NULL, 19732d1354aSWojciech Macek SHUTDOWN_PRI_LAST); 19832d1354aSWojciech Macek 199911a9260SJustin Hibbits OF_getencprop(ofw_bus_get_node(dev), "ibm,heartbeat-ms", 200911a9260SJustin Hibbits &opal_heartbeat_ms, sizeof(opal_heartbeat_ms)); 201504d9b60SWojciech Macek /* Bind to interrupts */ 202504d9b60SWojciech Macek for (i = 0; (irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &i, 203504d9b60SWojciech Macek RF_ACTIVE)) != NULL; i++) 204504d9b60SWojciech Macek bus_setup_intr(dev, irq, INTR_TYPE_TTY | INTR_MPSAFE | 205504d9b60SWojciech Macek INTR_ENTROPY, NULL, opal_intr, (void *)rman_get_start(irq), 206504d9b60SWojciech Macek NULL); 207504d9b60SWojciech Macek 208dac618a6SJustin Hibbits OF_getencprop(ofw_bus_get_node(dev), "opal-msg-async-num", 209dac618a6SJustin Hibbits &async_count, sizeof(async_count)); 210dac618a6SJustin Hibbits opal_init_async_tokens(async_count); 211dac618a6SJustin Hibbits 21232d1354aSWojciech Macek for (child = OF_child(ofw_bus_get_node(dev)); child != 0; 21332d1354aSWojciech Macek child = OF_peer(child)) { 21432d1354aSWojciech Macek dinfo = malloc(sizeof(*dinfo), M_DEVBUF, M_WAITOK | M_ZERO); 21532d1354aSWojciech Macek if (ofw_bus_gen_setup_devinfo(dinfo, child) != 0) { 21632d1354aSWojciech Macek free(dinfo, M_DEVBUF); 21732d1354aSWojciech Macek continue; 21832d1354aSWojciech Macek } 2195b56413dSWarner Losh cdev = device_add_child(dev, NULL, DEVICE_UNIT_ANY); 22032d1354aSWojciech Macek if (cdev == NULL) { 22132d1354aSWojciech Macek device_printf(dev, "<%s>: device_add_child failed\n", 22232d1354aSWojciech Macek dinfo->obd_name); 22332d1354aSWojciech Macek ofw_bus_gen_destroy_devinfo(dinfo); 22432d1354aSWojciech Macek free(dinfo, M_DEVBUF); 22532d1354aSWojciech Macek continue; 22632d1354aSWojciech Macek } 22732d1354aSWojciech Macek device_set_ivars(cdev, dinfo); 22832d1354aSWojciech Macek } 22932d1354aSWojciech Macek 230*18250ec6SJohn Baldwin bus_attach_children(dev); 231*18250ec6SJohn Baldwin return (0); 23232d1354aSWojciech Macek } 23332d1354aSWojciech Macek 23432d1354aSWojciech Macek static int 235504d9b60SWojciech Macek bcd2bin32(int bcd) 236504d9b60SWojciech Macek { 237504d9b60SWojciech Macek int out = 0; 238504d9b60SWojciech Macek 239504d9b60SWojciech Macek out += bcd2bin(bcd & 0xff); 240504d9b60SWojciech Macek out += 100*bcd2bin((bcd & 0x0000ff00) >> 8); 241504d9b60SWojciech Macek out += 10000*bcd2bin((bcd & 0x00ff0000) >> 16); 242504d9b60SWojciech Macek out += 1000000*bcd2bin((bcd & 0xffff0000) >> 24); 243504d9b60SWojciech Macek 244504d9b60SWojciech Macek return (out); 245504d9b60SWojciech Macek } 246504d9b60SWojciech Macek 247504d9b60SWojciech Macek static int 248eb96cc13SWojciech Macek bin2bcd32(int bin) 249eb96cc13SWojciech Macek { 250eb96cc13SWojciech Macek int out = 0; 251eb96cc13SWojciech Macek int tmp; 252eb96cc13SWojciech Macek 253eb96cc13SWojciech Macek tmp = bin % 100; 2545c74d551SBrandon Bergren out += bin2bcd(tmp) * 0x1; 255eb96cc13SWojciech Macek bin = bin / 100; 256eb96cc13SWojciech Macek 257eb96cc13SWojciech Macek tmp = bin % 100; 2585c74d551SBrandon Bergren out += bin2bcd(tmp) * 0x100; 259eb96cc13SWojciech Macek bin = bin / 100; 260eb96cc13SWojciech Macek 261eb96cc13SWojciech Macek tmp = bin % 100; 2625c74d551SBrandon Bergren out += bin2bcd(tmp) * 0x10000; 263eb96cc13SWojciech Macek 264eb96cc13SWojciech Macek return (out); 265eb96cc13SWojciech Macek } 266eb96cc13SWojciech Macek 267eb96cc13SWojciech Macek static int 268504d9b60SWojciech Macek opal_gettime(device_t dev, struct timespec *ts) 269504d9b60SWojciech Macek { 270504d9b60SWojciech Macek int rv; 271504d9b60SWojciech Macek struct clocktime ct; 272504d9b60SWojciech Macek uint32_t ymd; 273504d9b60SWojciech Macek uint64_t hmsm; 274504d9b60SWojciech Macek 275504d9b60SWojciech Macek rv = opal_call(OPAL_RTC_READ, vtophys(&ymd), vtophys(&hmsm)); 27678f4e2feSBreno Leitao while (rv == OPAL_BUSY_EVENT) { 27778f4e2feSBreno Leitao opal_call(OPAL_POLL_EVENTS, 0); 278504d9b60SWojciech Macek pause("opalrtc", 1); 27978f4e2feSBreno Leitao rv = opal_call(OPAL_RTC_READ, vtophys(&ymd), vtophys(&hmsm)); 280504d9b60SWojciech Macek } 281504d9b60SWojciech Macek 282504d9b60SWojciech Macek if (rv != OPAL_SUCCESS) 28332d1354aSWojciech Macek return (ENXIO); 284504d9b60SWojciech Macek 285504d9b60SWojciech Macek hmsm = be64toh(hmsm); 286504d9b60SWojciech Macek ymd = be32toh(ymd); 287504d9b60SWojciech Macek 288504d9b60SWojciech Macek ct.nsec = bcd2bin32((hmsm & 0x000000ffffff0000) >> 16) * 1000; 289504d9b60SWojciech Macek ct.sec = bcd2bin((hmsm & 0x0000ff0000000000) >> 40); 290504d9b60SWojciech Macek ct.min = bcd2bin((hmsm & 0x00ff000000000000) >> 48); 291504d9b60SWojciech Macek ct.hour = bcd2bin((hmsm & 0xff00000000000000) >> 56); 292504d9b60SWojciech Macek 293504d9b60SWojciech Macek ct.day = bcd2bin((ymd & 0x000000ff) >> 0); 294504d9b60SWojciech Macek ct.mon = bcd2bin((ymd & 0x0000ff00) >> 8); 295504d9b60SWojciech Macek ct.year = bcd2bin32((ymd & 0xffff0000) >> 16); 296504d9b60SWojciech Macek 297504d9b60SWojciech Macek return (clock_ct_to_ts(&ct, ts)); 29832d1354aSWojciech Macek } 29932d1354aSWojciech Macek 30032d1354aSWojciech Macek static int 30132d1354aSWojciech Macek opal_settime(device_t dev, struct timespec *ts) 30232d1354aSWojciech Macek { 303eb96cc13SWojciech Macek int rv; 304eb96cc13SWojciech Macek struct clocktime ct; 305eb96cc13SWojciech Macek uint32_t ymd = 0; 306eb96cc13SWojciech Macek uint64_t hmsm = 0; 307eb96cc13SWojciech Macek 308eb96cc13SWojciech Macek clock_ts_to_ct(ts, &ct); 309eb96cc13SWojciech Macek 310eb96cc13SWojciech Macek ymd |= (uint32_t)bin2bcd(ct.day); 311eb96cc13SWojciech Macek ymd |= ((uint32_t)bin2bcd(ct.mon) << 8); 312eb96cc13SWojciech Macek ymd |= ((uint32_t)bin2bcd32(ct.year) << 16); 313eb96cc13SWojciech Macek 314eb96cc13SWojciech Macek hmsm |= ((uint64_t)bin2bcd32(ct.nsec/1000) << 16); 315eb96cc13SWojciech Macek hmsm |= ((uint64_t)bin2bcd(ct.sec) << 40); 316eb96cc13SWojciech Macek hmsm |= ((uint64_t)bin2bcd(ct.min) << 48); 317eb96cc13SWojciech Macek hmsm |= ((uint64_t)bin2bcd(ct.hour) << 56); 318eb96cc13SWojciech Macek 3195c74d551SBrandon Bergren /* 3205c74d551SBrandon Bergren * We do NOT swap endian here, because the values are being sent 3215c74d551SBrandon Bergren * via registers instead of indirect via memory. 3225c74d551SBrandon Bergren */ 323eb96cc13SWojciech Macek do { 3245c74d551SBrandon Bergren rv = opal_call(OPAL_RTC_WRITE, ymd, hmsm); 325eb96cc13SWojciech Macek if (rv == OPAL_BUSY_EVENT) { 326eb96cc13SWojciech Macek rv = opal_call(OPAL_POLL_EVENTS, 0); 327eb96cc13SWojciech Macek pause("opalrtc", 1); 328eb96cc13SWojciech Macek } 329eb96cc13SWojciech Macek } while (rv == OPAL_BUSY_EVENT); 330eb96cc13SWojciech Macek 331eb96cc13SWojciech Macek if (rv != OPAL_SUCCESS) 332eb96cc13SWojciech Macek return (ENXIO); 333504d9b60SWojciech Macek 33432d1354aSWojciech Macek return (0); 33532d1354aSWojciech Macek } 33632d1354aSWojciech Macek 33732d1354aSWojciech Macek static const struct ofw_bus_devinfo * 33832d1354aSWojciech Macek opaldev_get_devinfo(device_t dev, device_t child) 33932d1354aSWojciech Macek { 34032d1354aSWojciech Macek return (device_get_ivars(child)); 34132d1354aSWojciech Macek } 34232d1354aSWojciech Macek 34332d1354aSWojciech Macek static void 34432d1354aSWojciech Macek opal_shutdown(void *arg, int howto) 34532d1354aSWojciech Macek { 34632d1354aSWojciech Macek 34741e26e82SMitchell Horne if ((howto & RB_POWEROFF) != 0) 34832d1354aSWojciech Macek opal_call(OPAL_CEC_POWER_DOWN, 0 /* Normal power off */); 34941e26e82SMitchell Horne else if ((howto & RB_HALT) == 0) 35032d1354aSWojciech Macek opal_call(OPAL_CEC_REBOOT); 35141e26e82SMitchell Horne else 35241e26e82SMitchell Horne return; 353504d9b60SWojciech Macek 354504d9b60SWojciech Macek opal_call(OPAL_RETURN_CPU); 355504d9b60SWojciech Macek } 356504d9b60SWojciech Macek 357504d9b60SWojciech Macek static void 358911a9260SJustin Hibbits opal_handle_shutdown_message(void *unused, struct opal_msg *msg) 359911a9260SJustin Hibbits { 360911a9260SJustin Hibbits int howto; 361911a9260SJustin Hibbits 362911a9260SJustin Hibbits switch (be64toh(msg->params[0])) { 363911a9260SJustin Hibbits case OPAL_SOFT_OFF: 364911a9260SJustin Hibbits howto = RB_POWEROFF; 365911a9260SJustin Hibbits break; 366911a9260SJustin Hibbits case OPAL_SOFT_REBOOT: 367911a9260SJustin Hibbits howto = RB_REROOT; 368911a9260SJustin Hibbits break; 369911a9260SJustin Hibbits } 370911a9260SJustin Hibbits shutdown_nice(howto); 371911a9260SJustin Hibbits } 372911a9260SJustin Hibbits 373911a9260SJustin Hibbits static void 374911a9260SJustin Hibbits opal_handle_messages(void) 375911a9260SJustin Hibbits { 376911a9260SJustin Hibbits static struct opal_msg msg; 377911a9260SJustin Hibbits uint64_t rv; 378911a9260SJustin Hibbits uint32_t type; 379911a9260SJustin Hibbits 380911a9260SJustin Hibbits rv = opal_call(OPAL_GET_MSG, vtophys(&msg), sizeof(msg)); 381911a9260SJustin Hibbits 3826d2254bcSAlfredo Dal'Ava Junior switch (rv) { 3836d2254bcSAlfredo Dal'Ava Junior case OPAL_SUCCESS: 3846d2254bcSAlfredo Dal'Ava Junior break; 3856d2254bcSAlfredo Dal'Ava Junior case OPAL_RESOURCE: 3866d2254bcSAlfredo Dal'Ava Junior /* no available messages - return */ 387911a9260SJustin Hibbits return; 3886d2254bcSAlfredo Dal'Ava Junior case OPAL_PARAMETER: 3896d2254bcSAlfredo Dal'Ava Junior printf("%s error: invalid buffer. Please file a bug report.\n", __func__); 3906d2254bcSAlfredo Dal'Ava Junior return; 3916d2254bcSAlfredo Dal'Ava Junior case OPAL_PARTIAL: 3926d2254bcSAlfredo Dal'Ava Junior printf("%s error: buffer is too small and messages was discarded. Please file a bug report.\n", __func__); 3936d2254bcSAlfredo Dal'Ava Junior return; 3946d2254bcSAlfredo Dal'Ava Junior default: 3956d2254bcSAlfredo Dal'Ava Junior printf("%s opal_call returned unknown result <%lu>\n", __func__, rv); 3966d2254bcSAlfredo Dal'Ava Junior return; 3976d2254bcSAlfredo Dal'Ava Junior } 398911a9260SJustin Hibbits 399911a9260SJustin Hibbits type = be32toh(msg.msg_type); 400911a9260SJustin Hibbits switch (type) { 401911a9260SJustin Hibbits case OPAL_MSG_ASYNC_COMP: 402911a9260SJustin Hibbits EVENTHANDLER_DIRECT_INVOKE(OPAL_ASYNC_COMP, &msg); 403911a9260SJustin Hibbits break; 404911a9260SJustin Hibbits case OPAL_MSG_EPOW: 405911a9260SJustin Hibbits EVENTHANDLER_DIRECT_INVOKE(OPAL_EPOW, &msg); 406911a9260SJustin Hibbits break; 407911a9260SJustin Hibbits case OPAL_MSG_SHUTDOWN: 408911a9260SJustin Hibbits EVENTHANDLER_DIRECT_INVOKE(OPAL_SHUTDOWN, &msg); 409911a9260SJustin Hibbits break; 410911a9260SJustin Hibbits case OPAL_MSG_HMI_EVT: 411911a9260SJustin Hibbits EVENTHANDLER_DIRECT_INVOKE(OPAL_HMI_EVT, &msg); 412911a9260SJustin Hibbits break; 413911a9260SJustin Hibbits case OPAL_MSG_DPO: 414911a9260SJustin Hibbits EVENTHANDLER_DIRECT_INVOKE(OPAL_DPO, &msg); 415911a9260SJustin Hibbits break; 416911a9260SJustin Hibbits case OPAL_MSG_OCC: 417911a9260SJustin Hibbits EVENTHANDLER_DIRECT_INVOKE(OPAL_OCC, &msg); 418911a9260SJustin Hibbits break; 419911a9260SJustin Hibbits default: 4206d2254bcSAlfredo Dal'Ava Junior printf("%s Unknown OPAL message type %d\n", __func__, type); 421911a9260SJustin Hibbits } 422911a9260SJustin Hibbits } 423911a9260SJustin Hibbits 424911a9260SJustin Hibbits static void 425504d9b60SWojciech Macek opal_intr(void *xintr) 426504d9b60SWojciech Macek { 427504d9b60SWojciech Macek uint64_t events = 0; 428504d9b60SWojciech Macek 429504d9b60SWojciech Macek opal_call(OPAL_HANDLE_INTERRUPT, (uint32_t)(uint64_t)xintr, 430504d9b60SWojciech Macek vtophys(&events)); 431911a9260SJustin Hibbits /* Wake up the heartbeat, if it's been setup. */ 4326d2254bcSAlfredo Dal'Ava Junior if (be64toh(events) != 0 && opal_hb_proc != NULL) 433911a9260SJustin Hibbits wakeup(opal_hb_proc); 434504d9b60SWojciech Macek 43532d1354aSWojciech Macek } 436