1255643Snwhitehorn/*- 2255643Snwhitehorn * Copyright (c) 2011 Nathan Whitehorn 3255643Snwhitehorn * All rights reserved. 4255643Snwhitehorn * 5255643Snwhitehorn * Redistribution and use in source and binary forms, with or without 6255643Snwhitehorn * modification, are permitted provided that the following conditions 7255643Snwhitehorn * are met: 8255643Snwhitehorn * 1. Redistributions of source code must retain the above copyright 9255643Snwhitehorn * notice, this list of conditions and the following disclaimer. 10255643Snwhitehorn * 2. Redistributions in binary form must reproduce the above copyright 11255643Snwhitehorn * notice, this list of conditions and the following disclaimer in the 12255643Snwhitehorn * documentation and/or other materials provided with the distribution. 13255643Snwhitehorn * 14255643Snwhitehorn * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15255643Snwhitehorn * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16255643Snwhitehorn * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17255643Snwhitehorn * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18255643Snwhitehorn * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19255643Snwhitehorn * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20255643Snwhitehorn * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21255643Snwhitehorn * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22255643Snwhitehorn * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23255643Snwhitehorn * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24255643Snwhitehorn * SUCH DAMAGE. 25255643Snwhitehorn */ 26255643Snwhitehorn 27255643Snwhitehorn#include <sys/cdefs.h> 28255643Snwhitehorn__FBSDID("$FreeBSD$"); 29255643Snwhitehorn 30255643Snwhitehorn#include <sys/param.h> 31255643Snwhitehorn#include <sys/systm.h> 32255643Snwhitehorn#include <sys/module.h> 33255643Snwhitehorn#include <sys/bus.h> 34255643Snwhitehorn#include <sys/conf.h> 35255643Snwhitehorn#include <sys/clock.h> 36255643Snwhitehorn#include <sys/cpu.h> 37255643Snwhitehorn#include <sys/kernel.h> 38255643Snwhitehorn#include <sys/reboot.h> 39255643Snwhitehorn#include <sys/sysctl.h> 40255643Snwhitehorn 41255643Snwhitehorn#include <dev/ofw/ofw_bus.h> 42255643Snwhitehorn#include <dev/ofw/openfirm.h> 43255643Snwhitehorn 44255643Snwhitehorn#include <machine/rtas.h> 45255643Snwhitehorn 46255643Snwhitehorn#include "clock_if.h" 47255643Snwhitehorn 48255643Snwhitehornstatic int rtasdev_probe(device_t); 49255643Snwhitehornstatic int rtasdev_attach(device_t); 50255643Snwhitehorn/* clock interface */ 51255643Snwhitehornstatic int rtas_gettime(device_t dev, struct timespec *ts); 52255643Snwhitehornstatic int rtas_settime(device_t dev, struct timespec *ts); 53255643Snwhitehorn 54255643Snwhitehornstatic void rtas_shutdown(void *arg, int howto); 55255643Snwhitehorn 56255643Snwhitehornstatic device_method_t rtasdev_methods[] = { 57255643Snwhitehorn /* Device interface */ 58255643Snwhitehorn DEVMETHOD(device_probe, rtasdev_probe), 59255643Snwhitehorn DEVMETHOD(device_attach, rtasdev_attach), 60255643Snwhitehorn 61255643Snwhitehorn /* clock interface */ 62255643Snwhitehorn DEVMETHOD(clock_gettime, rtas_gettime), 63255643Snwhitehorn DEVMETHOD(clock_settime, rtas_settime), 64255643Snwhitehorn 65255643Snwhitehorn { 0, 0 }, 66255643Snwhitehorn}; 67255643Snwhitehorn 68255643Snwhitehornstatic driver_t rtasdev_driver = { 69255643Snwhitehorn "rtas", 70255643Snwhitehorn rtasdev_methods, 71255643Snwhitehorn 0 72255643Snwhitehorn}; 73255643Snwhitehorn 74255643Snwhitehornstatic devclass_t rtasdev_devclass; 75255643Snwhitehorn 76266160SianDRIVER_MODULE(rtasdev, ofwbus, rtasdev_driver, rtasdev_devclass, 0, 0); 77255643Snwhitehorn 78255643Snwhitehornstatic int 79255643Snwhitehornrtasdev_probe(device_t dev) 80255643Snwhitehorn{ 81255643Snwhitehorn const char *name = ofw_bus_get_name(dev); 82255643Snwhitehorn 83255643Snwhitehorn if (strcmp(name, "rtas") != 0) 84255643Snwhitehorn return (ENXIO); 85255643Snwhitehorn if (!rtas_exists()) 86255643Snwhitehorn return (ENXIO); 87255643Snwhitehorn 88255643Snwhitehorn device_set_desc(dev, "Run-Time Abstraction Services"); 89255643Snwhitehorn return (0); 90255643Snwhitehorn} 91255643Snwhitehorn 92255643Snwhitehornstatic int 93255643Snwhitehornrtasdev_attach(device_t dev) 94255643Snwhitehorn{ 95255643Snwhitehorn if (rtas_token_lookup("get-time-of-day") != -1) 96255643Snwhitehorn clock_register(dev, 2000); 97255643Snwhitehorn 98255643Snwhitehorn EVENTHANDLER_REGISTER(shutdown_final, rtas_shutdown, NULL, 99255643Snwhitehorn SHUTDOWN_PRI_LAST); 100255643Snwhitehorn 101255643Snwhitehorn return (0); 102255643Snwhitehorn} 103255643Snwhitehorn 104255643Snwhitehornstatic int 105255643Snwhitehornrtas_gettime(device_t dev, struct timespec *ts) { 106255643Snwhitehorn struct clocktime ct; 107255643Snwhitehorn cell_t tod[8]; 108255643Snwhitehorn cell_t token; 109255643Snwhitehorn int error; 110255643Snwhitehorn 111255643Snwhitehorn token = rtas_token_lookup("get-time-of-day"); 112255643Snwhitehorn if (token == -1) 113255643Snwhitehorn return (ENXIO); 114255643Snwhitehorn error = rtas_call_method(token, 0, 8, &tod[0], &tod[1], &tod[2], 115255643Snwhitehorn &tod[3], &tod[4], &tod[5], &tod[6], &tod[7]); 116255643Snwhitehorn if (error < 0) 117255643Snwhitehorn return (ENXIO); 118255643Snwhitehorn if (tod[0] != 0) 119255643Snwhitehorn return ((tod[0] == -1) ? ENXIO : EAGAIN); 120255643Snwhitehorn 121255643Snwhitehorn ct.year = tod[1]; 122255643Snwhitehorn ct.mon = tod[2]; 123255643Snwhitehorn ct.day = tod[3]; 124255643Snwhitehorn ct.hour = tod[4]; 125255643Snwhitehorn ct.min = tod[5]; 126255643Snwhitehorn ct.sec = tod[6]; 127255643Snwhitehorn ct.nsec = tod[7]; 128255643Snwhitehorn 129255643Snwhitehorn return (clock_ct_to_ts(&ct, ts)); 130255643Snwhitehorn} 131255643Snwhitehorn 132255643Snwhitehornstatic int 133255643Snwhitehornrtas_settime(device_t dev, struct timespec *ts) 134255643Snwhitehorn{ 135255643Snwhitehorn struct clocktime ct; 136255643Snwhitehorn cell_t token, status; 137255643Snwhitehorn int error; 138255643Snwhitehorn 139255643Snwhitehorn token = rtas_token_lookup("set-time-of-day"); 140255643Snwhitehorn if (token == -1) 141255643Snwhitehorn return (ENXIO); 142255643Snwhitehorn 143255643Snwhitehorn clock_ts_to_ct(ts, &ct); 144255643Snwhitehorn error = rtas_call_method(token, 7, 1, ct.year, ct.mon, ct.day, ct.hour, 145255643Snwhitehorn ct.min, ct.sec, ct.nsec, &status); 146255643Snwhitehorn if (error < 0) 147255643Snwhitehorn return (ENXIO); 148255643Snwhitehorn if (status != 0) 149255643Snwhitehorn return (((int)status < 0) ? ENXIO : EAGAIN); 150255643Snwhitehorn 151255643Snwhitehorn return (0); 152255643Snwhitehorn} 153255643Snwhitehorn 154255643Snwhitehornstatic void 155255643Snwhitehornrtas_shutdown(void *arg, int howto) 156255643Snwhitehorn{ 157255643Snwhitehorn cell_t token, status; 158255643Snwhitehorn 159255643Snwhitehorn if (howto & RB_HALT) { 160255643Snwhitehorn token = rtas_token_lookup("power-off"); 161255643Snwhitehorn if (token == -1) 162255643Snwhitehorn return; 163255643Snwhitehorn 164255643Snwhitehorn rtas_call_method(token, 2, 1, 0, 0, &status); 165255643Snwhitehorn } else { 166255643Snwhitehorn token = rtas_token_lookup("system-reboot"); 167255643Snwhitehorn if (token == -1) 168255643Snwhitehorn return; 169255643Snwhitehorn 170255643Snwhitehorn rtas_call_method(token, 0, 1, &status); 171255643Snwhitehorn } 172255643Snwhitehorn} 173255643Snwhitehorn 174