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 #include <sys/param.h> 2932d1354aSWojciech Macek #include <sys/systm.h> 3032d1354aSWojciech Macek #include <sys/module.h> 3132d1354aSWojciech Macek #include <sys/bus.h> 3232d1354aSWojciech Macek #include <sys/conf.h> 3332d1354aSWojciech Macek #include <sys/clock.h> 3432d1354aSWojciech Macek #include <sys/cpu.h> 35e2e050c8SConrad Meyer #include <sys/eventhandler.h> 3632d1354aSWojciech Macek #include <sys/kernel.h> 37911a9260SJustin Hibbits #include <sys/kthread.h> 3832d1354aSWojciech Macek #include <sys/reboot.h> 3932d1354aSWojciech Macek #include <sys/sysctl.h> 40504d9b60SWojciech Macek #include <sys/endian.h> 41504d9b60SWojciech Macek 42504d9b60SWojciech Macek #include <vm/vm.h> 43504d9b60SWojciech Macek #include <vm/pmap.h> 4432d1354aSWojciech Macek 4532d1354aSWojciech Macek #include <dev/ofw/ofw_bus.h> 4632d1354aSWojciech Macek #include <dev/ofw/ofw_bus_subr.h> 4732d1354aSWojciech Macek #include <dev/ofw/openfirm.h> 4832d1354aSWojciech Macek 4932d1354aSWojciech Macek #include "clock_if.h" 5032d1354aSWojciech Macek #include "opal.h" 5132d1354aSWojciech Macek 5232d1354aSWojciech Macek static int opaldev_probe(device_t); 5332d1354aSWojciech Macek static int opaldev_attach(device_t); 5432d1354aSWojciech Macek /* clock interface */ 5532d1354aSWojciech Macek static int opal_gettime(device_t dev, struct timespec *ts); 5632d1354aSWojciech Macek static int opal_settime(device_t dev, struct timespec *ts); 5732d1354aSWojciech Macek /* ofw bus interface */ 5832d1354aSWojciech Macek static const struct ofw_bus_devinfo *opaldev_get_devinfo(device_t dev, 5932d1354aSWojciech Macek device_t child); 6032d1354aSWojciech Macek 6132d1354aSWojciech Macek static void opal_shutdown(void *arg, int howto); 62911a9260SJustin Hibbits static void opal_handle_shutdown_message(void *unused, 63911a9260SJustin Hibbits struct opal_msg *msg); 64504d9b60SWojciech Macek static void opal_intr(void *); 6532d1354aSWojciech Macek 6632d1354aSWojciech Macek static device_method_t opaldev_methods[] = { 6732d1354aSWojciech Macek /* Device interface */ 6832d1354aSWojciech Macek DEVMETHOD(device_probe, opaldev_probe), 6932d1354aSWojciech Macek DEVMETHOD(device_attach, opaldev_attach), 7032d1354aSWojciech Macek 7132d1354aSWojciech Macek /* clock interface */ 7232d1354aSWojciech Macek DEVMETHOD(clock_gettime, opal_gettime), 7332d1354aSWojciech Macek DEVMETHOD(clock_settime, opal_settime), 7432d1354aSWojciech Macek 7527ef2ca8SJustin Hibbits /* Bus interface */ 76ddfc9c4cSWarner Losh DEVMETHOD(bus_child_pnpinfo, ofw_bus_gen_child_pnpinfo), 7727ef2ca8SJustin Hibbits 7832d1354aSWojciech Macek /* ofw_bus interface */ 7932d1354aSWojciech Macek DEVMETHOD(ofw_bus_get_devinfo, opaldev_get_devinfo), 8032d1354aSWojciech Macek DEVMETHOD(ofw_bus_get_compat, ofw_bus_gen_get_compat), 8132d1354aSWojciech Macek DEVMETHOD(ofw_bus_get_model, ofw_bus_gen_get_model), 8232d1354aSWojciech Macek DEVMETHOD(ofw_bus_get_name, ofw_bus_gen_get_name), 8332d1354aSWojciech Macek DEVMETHOD(ofw_bus_get_node, ofw_bus_gen_get_node), 8432d1354aSWojciech Macek DEVMETHOD(ofw_bus_get_type, ofw_bus_gen_get_type), 8532d1354aSWojciech Macek 8632d1354aSWojciech Macek DEVMETHOD_END 8732d1354aSWojciech Macek }; 8832d1354aSWojciech Macek 8932d1354aSWojciech Macek static driver_t opaldev_driver = { 9032d1354aSWojciech Macek "opal", 9132d1354aSWojciech Macek opaldev_methods, 9232d1354aSWojciech Macek 0 9332d1354aSWojciech Macek }; 9432d1354aSWojciech Macek 955edf159fSJohn Baldwin EARLY_DRIVER_MODULE(opaldev, ofwbus, opaldev_driver, 0, 0, BUS_PASS_BUS); 9632d1354aSWojciech Macek 97911a9260SJustin Hibbits static void opal_heartbeat(void); 98911a9260SJustin Hibbits static void opal_handle_messages(void); 99911a9260SJustin Hibbits 100911a9260SJustin Hibbits static struct proc *opal_hb_proc; 101911a9260SJustin Hibbits static struct kproc_desc opal_heartbeat_kp = { 102911a9260SJustin Hibbits "opal_heartbeat", 103911a9260SJustin Hibbits opal_heartbeat, 104911a9260SJustin Hibbits &opal_hb_proc 105911a9260SJustin Hibbits }; 106911a9260SJustin Hibbits 107911a9260SJustin Hibbits SYSINIT(opal_heartbeat_setup, SI_SUB_KTHREAD_IDLE, SI_ORDER_ANY, kproc_start, 108911a9260SJustin Hibbits &opal_heartbeat_kp); 109911a9260SJustin Hibbits 110911a9260SJustin Hibbits static int opal_heartbeat_ms; 111911a9260SJustin Hibbits EVENTHANDLER_LIST_DEFINE(OPAL_ASYNC_COMP); 112911a9260SJustin Hibbits EVENTHANDLER_LIST_DEFINE(OPAL_EPOW); 113911a9260SJustin Hibbits EVENTHANDLER_LIST_DEFINE(OPAL_SHUTDOWN); 114911a9260SJustin Hibbits EVENTHANDLER_LIST_DEFINE(OPAL_HMI_EVT); 115911a9260SJustin Hibbits EVENTHANDLER_LIST_DEFINE(OPAL_DPO); 116911a9260SJustin Hibbits EVENTHANDLER_LIST_DEFINE(OPAL_OCC); 117911a9260SJustin Hibbits 118911a9260SJustin Hibbits #define OPAL_SOFT_OFF 0 119911a9260SJustin Hibbits #define OPAL_SOFT_REBOOT 1 120911a9260SJustin Hibbits 121911a9260SJustin Hibbits static void 122911a9260SJustin Hibbits opal_heartbeat(void) 123911a9260SJustin Hibbits { 124911a9260SJustin Hibbits uint64_t events; 125911a9260SJustin Hibbits 126911a9260SJustin Hibbits if (opal_heartbeat_ms == 0) 127911a9260SJustin Hibbits kproc_exit(0); 128911a9260SJustin Hibbits 129911a9260SJustin Hibbits while (1) { 130911a9260SJustin Hibbits events = 0; 131911a9260SJustin Hibbits /* Turn the OPAL state crank */ 132911a9260SJustin Hibbits opal_call(OPAL_POLL_EVENTS, vtophys(&events)); 133bf933a83SBrandon Bergren if (be64toh(events) & OPAL_EVENT_MSG_PENDING) 134911a9260SJustin Hibbits opal_handle_messages(); 135911a9260SJustin Hibbits tsleep(opal_hb_proc, 0, "opal", 136911a9260SJustin Hibbits MSEC_2_TICKS(opal_heartbeat_ms)); 137911a9260SJustin Hibbits } 138911a9260SJustin Hibbits } 139911a9260SJustin Hibbits 14032d1354aSWojciech Macek static int 14132d1354aSWojciech Macek opaldev_probe(device_t dev) 14232d1354aSWojciech Macek { 143504d9b60SWojciech Macek phandle_t iparent; 144504d9b60SWojciech Macek pcell_t *irqs; 145504d9b60SWojciech Macek int i, n_irqs; 14632d1354aSWojciech Macek 14732d1354aSWojciech Macek if (!ofw_bus_is_compatible(dev, "ibm,opal-v3")) 14832d1354aSWojciech Macek return (ENXIO); 14932d1354aSWojciech Macek if (opal_check() != 0) 15032d1354aSWojciech Macek return (ENXIO); 15132d1354aSWojciech Macek 15232d1354aSWojciech Macek device_set_desc(dev, "OPAL Abstraction Firmware"); 153504d9b60SWojciech Macek 154504d9b60SWojciech Macek /* Manually add IRQs before attaching */ 155504d9b60SWojciech Macek if (OF_hasprop(ofw_bus_get_node(dev), "opal-interrupts")) { 156504d9b60SWojciech Macek iparent = OF_finddevice("/interrupt-controller@0"); 157504d9b60SWojciech Macek iparent = OF_xref_from_node(iparent); 158504d9b60SWojciech Macek 159504d9b60SWojciech Macek n_irqs = OF_getproplen(ofw_bus_get_node(dev), 160504d9b60SWojciech Macek "opal-interrupts") / sizeof(*irqs); 161504d9b60SWojciech Macek irqs = malloc(n_irqs * sizeof(*irqs), M_DEVBUF, M_WAITOK); 162504d9b60SWojciech Macek OF_getencprop(ofw_bus_get_node(dev), "opal-interrupts", irqs, 163504d9b60SWojciech Macek n_irqs * sizeof(*irqs)); 164504d9b60SWojciech Macek for (i = 0; i < n_irqs; i++) 165504d9b60SWojciech Macek bus_set_resource(dev, SYS_RES_IRQ, i, 166504d9b60SWojciech Macek ofw_bus_map_intr(dev, iparent, 1, &irqs[i]), 1); 167504d9b60SWojciech Macek free(irqs, M_DEVBUF); 168504d9b60SWojciech Macek } 169504d9b60SWojciech Macek 17032d1354aSWojciech Macek return (BUS_PROBE_SPECIFIC); 17132d1354aSWojciech Macek } 17232d1354aSWojciech Macek 17332d1354aSWojciech Macek static int 17432d1354aSWojciech Macek opaldev_attach(device_t dev) 17532d1354aSWojciech Macek { 17632d1354aSWojciech Macek phandle_t child; 17732d1354aSWojciech Macek device_t cdev; 178504d9b60SWojciech Macek uint64_t junk; 179504d9b60SWojciech Macek int i, rv; 180dac618a6SJustin Hibbits uint32_t async_count; 18132d1354aSWojciech Macek struct ofw_bus_devinfo *dinfo; 182504d9b60SWojciech Macek struct resource *irq; 18332d1354aSWojciech Macek 184504d9b60SWojciech Macek /* Test for RTC support and register clock if it works */ 185504d9b60SWojciech Macek rv = opal_call(OPAL_RTC_READ, vtophys(&junk), vtophys(&junk)); 186504d9b60SWojciech Macek do { 187504d9b60SWojciech Macek rv = opal_call(OPAL_RTC_READ, vtophys(&junk), vtophys(&junk)); 188504d9b60SWojciech Macek if (rv == OPAL_BUSY_EVENT) 189504d9b60SWojciech Macek rv = opal_call(OPAL_POLL_EVENTS, 0); 190504d9b60SWojciech Macek } while (rv == OPAL_BUSY_EVENT); 191504d9b60SWojciech Macek 192504d9b60SWojciech Macek if (rv == OPAL_SUCCESS) 19332d1354aSWojciech Macek clock_register(dev, 2000); 19432d1354aSWojciech Macek 195911a9260SJustin Hibbits EVENTHANDLER_REGISTER(OPAL_SHUTDOWN, opal_handle_shutdown_message, 196911a9260SJustin Hibbits NULL, EVENTHANDLER_PRI_ANY); 19732d1354aSWojciech Macek EVENTHANDLER_REGISTER(shutdown_final, opal_shutdown, NULL, 19832d1354aSWojciech Macek SHUTDOWN_PRI_LAST); 19932d1354aSWojciech Macek 200911a9260SJustin Hibbits OF_getencprop(ofw_bus_get_node(dev), "ibm,heartbeat-ms", 201911a9260SJustin Hibbits &opal_heartbeat_ms, sizeof(opal_heartbeat_ms)); 202504d9b60SWojciech Macek /* Bind to interrupts */ 203504d9b60SWojciech Macek for (i = 0; (irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &i, 204504d9b60SWojciech Macek RF_ACTIVE)) != NULL; i++) 205504d9b60SWojciech Macek bus_setup_intr(dev, irq, INTR_TYPE_TTY | INTR_MPSAFE | 206504d9b60SWojciech Macek INTR_ENTROPY, NULL, opal_intr, (void *)rman_get_start(irq), 207504d9b60SWojciech Macek NULL); 208504d9b60SWojciech Macek 209dac618a6SJustin Hibbits OF_getencprop(ofw_bus_get_node(dev), "opal-msg-async-num", 210dac618a6SJustin Hibbits &async_count, sizeof(async_count)); 211dac618a6SJustin Hibbits opal_init_async_tokens(async_count); 212dac618a6SJustin Hibbits 21332d1354aSWojciech Macek for (child = OF_child(ofw_bus_get_node(dev)); child != 0; 21432d1354aSWojciech Macek child = OF_peer(child)) { 21532d1354aSWojciech Macek dinfo = malloc(sizeof(*dinfo), M_DEVBUF, M_WAITOK | M_ZERO); 21632d1354aSWojciech Macek if (ofw_bus_gen_setup_devinfo(dinfo, child) != 0) { 21732d1354aSWojciech Macek free(dinfo, M_DEVBUF); 21832d1354aSWojciech Macek continue; 21932d1354aSWojciech Macek } 22032d1354aSWojciech Macek cdev = device_add_child(dev, NULL, -1); 22132d1354aSWojciech Macek if (cdev == NULL) { 22232d1354aSWojciech Macek device_printf(dev, "<%s>: device_add_child failed\n", 22332d1354aSWojciech Macek dinfo->obd_name); 22432d1354aSWojciech Macek ofw_bus_gen_destroy_devinfo(dinfo); 22532d1354aSWojciech Macek free(dinfo, M_DEVBUF); 22632d1354aSWojciech Macek continue; 22732d1354aSWojciech Macek } 22832d1354aSWojciech Macek device_set_ivars(cdev, dinfo); 22932d1354aSWojciech Macek } 23032d1354aSWojciech Macek 23132d1354aSWojciech Macek return (bus_generic_attach(dev)); 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 347*41e26e82SMitchell Horne if ((howto & RB_POWEROFF) != 0) 34832d1354aSWojciech Macek opal_call(OPAL_CEC_POWER_DOWN, 0 /* Normal power off */); 349*41e26e82SMitchell Horne else if ((howto & RB_HALT) == 0) 35032d1354aSWojciech Macek opal_call(OPAL_CEC_REBOOT); 351*41e26e82SMitchell Horne else 352*41e26e82SMitchell 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