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