17a8d25c0SNathan Whitehorn /*-
24d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause
371e3c308SPedro F. Giffuni *
47a8d25c0SNathan Whitehorn * Copyright (c) 2011 Nathan Whitehorn
57a8d25c0SNathan Whitehorn * All rights reserved.
67a8d25c0SNathan Whitehorn *
77a8d25c0SNathan Whitehorn * Redistribution and use in source and binary forms, with or without
87a8d25c0SNathan Whitehorn * modification, are permitted provided that the following conditions
97a8d25c0SNathan Whitehorn * are met:
107a8d25c0SNathan Whitehorn * 1. Redistributions of source code must retain the above copyright
117a8d25c0SNathan Whitehorn * notice, this list of conditions and the following disclaimer.
127a8d25c0SNathan Whitehorn * 2. Redistributions in binary form must reproduce the above copyright
137a8d25c0SNathan Whitehorn * notice, this list of conditions and the following disclaimer in the
147a8d25c0SNathan Whitehorn * documentation and/or other materials provided with the distribution.
157a8d25c0SNathan Whitehorn *
167a8d25c0SNathan Whitehorn * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
177a8d25c0SNathan Whitehorn * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
187a8d25c0SNathan Whitehorn * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
197a8d25c0SNathan Whitehorn * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
207a8d25c0SNathan Whitehorn * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
217a8d25c0SNathan Whitehorn * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
227a8d25c0SNathan Whitehorn * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
237a8d25c0SNathan Whitehorn * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
247a8d25c0SNathan Whitehorn * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
257a8d25c0SNathan Whitehorn * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
267a8d25c0SNathan Whitehorn * SUCH DAMAGE.
277a8d25c0SNathan Whitehorn */
287a8d25c0SNathan Whitehorn
297a8d25c0SNathan Whitehorn #include <sys/param.h>
307a8d25c0SNathan Whitehorn #include <sys/systm.h>
317a8d25c0SNathan Whitehorn #include <sys/module.h>
327a8d25c0SNathan Whitehorn #include <sys/bus.h>
337a8d25c0SNathan Whitehorn #include <sys/conf.h>
347a8d25c0SNathan Whitehorn #include <sys/clock.h>
357a8d25c0SNathan Whitehorn #include <sys/cpu.h>
36e2e050c8SConrad Meyer #include <sys/eventhandler.h>
377a8d25c0SNathan Whitehorn #include <sys/kernel.h>
387a8d25c0SNathan Whitehorn #include <sys/reboot.h>
397a8d25c0SNathan Whitehorn #include <sys/sysctl.h>
407a8d25c0SNathan Whitehorn
417a8d25c0SNathan Whitehorn #include <dev/ofw/ofw_bus.h>
427a8d25c0SNathan Whitehorn #include <dev/ofw/openfirm.h>
437a8d25c0SNathan Whitehorn
447a8d25c0SNathan Whitehorn #include <machine/rtas.h>
457a8d25c0SNathan Whitehorn
467a8d25c0SNathan Whitehorn #include "clock_if.h"
477a8d25c0SNathan Whitehorn
487a8d25c0SNathan Whitehorn static int rtasdev_probe(device_t);
497a8d25c0SNathan Whitehorn static int rtasdev_attach(device_t);
507a8d25c0SNathan Whitehorn /* clock interface */
517a8d25c0SNathan Whitehorn static int rtas_gettime(device_t dev, struct timespec *ts);
527a8d25c0SNathan Whitehorn static int rtas_settime(device_t dev, struct timespec *ts);
537a8d25c0SNathan Whitehorn
547a8d25c0SNathan Whitehorn static void rtas_shutdown(void *arg, int howto);
557a8d25c0SNathan Whitehorn
567a8d25c0SNathan Whitehorn static device_method_t rtasdev_methods[] = {
577a8d25c0SNathan Whitehorn /* Device interface */
587a8d25c0SNathan Whitehorn DEVMETHOD(device_probe, rtasdev_probe),
597a8d25c0SNathan Whitehorn DEVMETHOD(device_attach, rtasdev_attach),
607a8d25c0SNathan Whitehorn
617a8d25c0SNathan Whitehorn /* clock interface */
627a8d25c0SNathan Whitehorn DEVMETHOD(clock_gettime, rtas_gettime),
637a8d25c0SNathan Whitehorn DEVMETHOD(clock_settime, rtas_settime),
647a8d25c0SNathan Whitehorn
657a8d25c0SNathan Whitehorn { 0, 0 },
667a8d25c0SNathan Whitehorn };
677a8d25c0SNathan Whitehorn
687a8d25c0SNathan Whitehorn static driver_t rtasdev_driver = {
697a8d25c0SNathan Whitehorn "rtas",
707a8d25c0SNathan Whitehorn rtasdev_methods,
717a8d25c0SNathan Whitehorn 0
727a8d25c0SNathan Whitehorn };
737a8d25c0SNathan Whitehorn
749b9a5327SJohn Baldwin DRIVER_MODULE(rtasdev, ofwbus, rtasdev_driver, 0, 0);
757a8d25c0SNathan Whitehorn
767a8d25c0SNathan Whitehorn static int
rtasdev_probe(device_t dev)777a8d25c0SNathan Whitehorn rtasdev_probe(device_t dev)
787a8d25c0SNathan Whitehorn {
797a8d25c0SNathan Whitehorn const char *name = ofw_bus_get_name(dev);
807a8d25c0SNathan Whitehorn
817a8d25c0SNathan Whitehorn if (strcmp(name, "rtas") != 0)
827a8d25c0SNathan Whitehorn return (ENXIO);
837a8d25c0SNathan Whitehorn if (!rtas_exists())
847a8d25c0SNathan Whitehorn return (ENXIO);
857a8d25c0SNathan Whitehorn
867a8d25c0SNathan Whitehorn device_set_desc(dev, "Run-Time Abstraction Services");
877a8d25c0SNathan Whitehorn return (0);
887a8d25c0SNathan Whitehorn }
897a8d25c0SNathan Whitehorn
907a8d25c0SNathan Whitehorn static int
rtasdev_attach(device_t dev)917a8d25c0SNathan Whitehorn rtasdev_attach(device_t dev)
927a8d25c0SNathan Whitehorn {
937a8d25c0SNathan Whitehorn if (rtas_token_lookup("get-time-of-day") != -1)
947a8d25c0SNathan Whitehorn clock_register(dev, 2000);
957a8d25c0SNathan Whitehorn
967a8d25c0SNathan Whitehorn EVENTHANDLER_REGISTER(shutdown_final, rtas_shutdown, NULL,
977a8d25c0SNathan Whitehorn SHUTDOWN_PRI_LAST);
987a8d25c0SNathan Whitehorn
997a8d25c0SNathan Whitehorn return (0);
1007a8d25c0SNathan Whitehorn }
1017a8d25c0SNathan Whitehorn
1027a8d25c0SNathan Whitehorn static int
rtas_gettime(device_t dev,struct timespec * ts)1037a8d25c0SNathan Whitehorn rtas_gettime(device_t dev, struct timespec *ts) {
1047a8d25c0SNathan Whitehorn struct clocktime ct;
1057a8d25c0SNathan Whitehorn cell_t tod[8];
1067a8d25c0SNathan Whitehorn cell_t token;
1077a8d25c0SNathan Whitehorn int error;
1087a8d25c0SNathan Whitehorn
1097a8d25c0SNathan Whitehorn token = rtas_token_lookup("get-time-of-day");
1107a8d25c0SNathan Whitehorn if (token == -1)
1117a8d25c0SNathan Whitehorn return (ENXIO);
1127a8d25c0SNathan Whitehorn error = rtas_call_method(token, 0, 8, &tod[0], &tod[1], &tod[2],
1137a8d25c0SNathan Whitehorn &tod[3], &tod[4], &tod[5], &tod[6], &tod[7]);
1147a8d25c0SNathan Whitehorn if (error < 0)
1157a8d25c0SNathan Whitehorn return (ENXIO);
1167a8d25c0SNathan Whitehorn if (tod[0] != 0)
1177a8d25c0SNathan Whitehorn return ((tod[0] == -1) ? ENXIO : EAGAIN);
1187a8d25c0SNathan Whitehorn
1197a8d25c0SNathan Whitehorn ct.year = tod[1];
1207a8d25c0SNathan Whitehorn ct.mon = tod[2];
1217a8d25c0SNathan Whitehorn ct.day = tod[3];
1227a8d25c0SNathan Whitehorn ct.hour = tod[4];
1237a8d25c0SNathan Whitehorn ct.min = tod[5];
1247a8d25c0SNathan Whitehorn ct.sec = tod[6];
1257a8d25c0SNathan Whitehorn ct.nsec = tod[7];
1267a8d25c0SNathan Whitehorn
1277a8d25c0SNathan Whitehorn return (clock_ct_to_ts(&ct, ts));
1287a8d25c0SNathan Whitehorn }
1297a8d25c0SNathan Whitehorn
1307a8d25c0SNathan Whitehorn static int
rtas_settime(device_t dev,struct timespec * ts)1317a8d25c0SNathan Whitehorn rtas_settime(device_t dev, struct timespec *ts)
1327a8d25c0SNathan Whitehorn {
1337a8d25c0SNathan Whitehorn struct clocktime ct;
1347a8d25c0SNathan Whitehorn cell_t token, status;
1357a8d25c0SNathan Whitehorn int error;
1367a8d25c0SNathan Whitehorn
1377a8d25c0SNathan Whitehorn token = rtas_token_lookup("set-time-of-day");
1387a8d25c0SNathan Whitehorn if (token == -1)
1397a8d25c0SNathan Whitehorn return (ENXIO);
1407a8d25c0SNathan Whitehorn
1417a8d25c0SNathan Whitehorn clock_ts_to_ct(ts, &ct);
1427a8d25c0SNathan Whitehorn error = rtas_call_method(token, 7, 1, ct.year, ct.mon, ct.day, ct.hour,
1437a8d25c0SNathan Whitehorn ct.min, ct.sec, ct.nsec, &status);
1447a8d25c0SNathan Whitehorn if (error < 0)
1457a8d25c0SNathan Whitehorn return (ENXIO);
1467a8d25c0SNathan Whitehorn if (status != 0)
1477a8d25c0SNathan Whitehorn return (((int)status < 0) ? ENXIO : EAGAIN);
1487a8d25c0SNathan Whitehorn
1497a8d25c0SNathan Whitehorn return (0);
1507a8d25c0SNathan Whitehorn }
1517a8d25c0SNathan Whitehorn
1527a8d25c0SNathan Whitehorn static void
rtas_shutdown(void * arg,int howto)1537a8d25c0SNathan Whitehorn rtas_shutdown(void *arg, int howto)
1547a8d25c0SNathan Whitehorn {
1557a8d25c0SNathan Whitehorn cell_t token, status;
1567a8d25c0SNathan Whitehorn
157*41e26e82SMitchell Horne if ((howto & RB_POWEROFF) != 0) {
1587a8d25c0SNathan Whitehorn token = rtas_token_lookup("power-off");
1597a8d25c0SNathan Whitehorn if (token == -1)
1607a8d25c0SNathan Whitehorn return;
1617a8d25c0SNathan Whitehorn
1627a8d25c0SNathan Whitehorn rtas_call_method(token, 2, 1, 0, 0, &status);
163*41e26e82SMitchell Horne } else if ((howto & RB_HALT) == 0) {
1647a8d25c0SNathan Whitehorn token = rtas_token_lookup("system-reboot");
1657a8d25c0SNathan Whitehorn if (token == -1)
1667a8d25c0SNathan Whitehorn return;
1677a8d25c0SNathan Whitehorn
1687a8d25c0SNathan Whitehorn rtas_call_method(token, 0, 1, &status);
1697a8d25c0SNathan Whitehorn }
1707a8d25c0SNathan Whitehorn }
171