xref: /freebsd/sys/powerpc/powernv/opal_dev.c (revision 32d1354a39d70153f6070f3b1cf94ea2ad8dd0d9)
1*32d1354aSWojciech Macek /*-
2*32d1354aSWojciech Macek  * Copyright (c) 2015 Nathan Whitehorn
3*32d1354aSWojciech Macek  * All rights reserved.
4*32d1354aSWojciech Macek  *
5*32d1354aSWojciech Macek  * Redistribution and use in source and binary forms, with or without
6*32d1354aSWojciech Macek  * modification, are permitted provided that the following conditions
7*32d1354aSWojciech Macek  * are met:
8*32d1354aSWojciech Macek  * 1. Redistributions of source code must retain the above copyright
9*32d1354aSWojciech Macek  *    notice, this list of conditions and the following disclaimer.
10*32d1354aSWojciech Macek  * 2. Redistributions in binary form must reproduce the above copyright
11*32d1354aSWojciech Macek  *    notice, this list of conditions and the following disclaimer in the
12*32d1354aSWojciech Macek  *    documentation and/or other materials provided with the distribution.
13*32d1354aSWojciech Macek  *
14*32d1354aSWojciech Macek  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15*32d1354aSWojciech Macek  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16*32d1354aSWojciech Macek  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17*32d1354aSWojciech Macek  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18*32d1354aSWojciech Macek  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19*32d1354aSWojciech Macek  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20*32d1354aSWojciech Macek  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21*32d1354aSWojciech Macek  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22*32d1354aSWojciech Macek  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23*32d1354aSWojciech Macek  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24*32d1354aSWojciech Macek  * SUCH DAMAGE.
25*32d1354aSWojciech Macek  */
26*32d1354aSWojciech Macek 
27*32d1354aSWojciech Macek #include <sys/cdefs.h>
28*32d1354aSWojciech Macek __FBSDID("$FreeBSD$");
29*32d1354aSWojciech Macek 
30*32d1354aSWojciech Macek #include <sys/param.h>
31*32d1354aSWojciech Macek #include <sys/systm.h>
32*32d1354aSWojciech Macek #include <sys/module.h>
33*32d1354aSWojciech Macek #include <sys/bus.h>
34*32d1354aSWojciech Macek #include <sys/conf.h>
35*32d1354aSWojciech Macek #include <sys/clock.h>
36*32d1354aSWojciech Macek #include <sys/cpu.h>
37*32d1354aSWojciech Macek #include <sys/kernel.h>
38*32d1354aSWojciech Macek #include <sys/reboot.h>
39*32d1354aSWojciech Macek #include <sys/sysctl.h>
40*32d1354aSWojciech Macek 
41*32d1354aSWojciech Macek #include <dev/ofw/ofw_bus.h>
42*32d1354aSWojciech Macek #include <dev/ofw/ofw_bus_subr.h>
43*32d1354aSWojciech Macek #include <dev/ofw/openfirm.h>
44*32d1354aSWojciech Macek 
45*32d1354aSWojciech Macek #include "clock_if.h"
46*32d1354aSWojciech Macek #include "opal.h"
47*32d1354aSWojciech Macek 
48*32d1354aSWojciech Macek static int	opaldev_probe(device_t);
49*32d1354aSWojciech Macek static int	opaldev_attach(device_t);
50*32d1354aSWojciech Macek /* clock interface */
51*32d1354aSWojciech Macek static int	opal_gettime(device_t dev, struct timespec *ts);
52*32d1354aSWojciech Macek static int	opal_settime(device_t dev, struct timespec *ts);
53*32d1354aSWojciech Macek /* ofw bus interface */
54*32d1354aSWojciech Macek static const struct ofw_bus_devinfo *opaldev_get_devinfo(device_t dev,
55*32d1354aSWojciech Macek     device_t child);
56*32d1354aSWojciech Macek 
57*32d1354aSWojciech Macek static void	opal_shutdown(void *arg, int howto);
58*32d1354aSWojciech Macek 
59*32d1354aSWojciech Macek static device_method_t  opaldev_methods[] = {
60*32d1354aSWojciech Macek 	/* Device interface */
61*32d1354aSWojciech Macek 	DEVMETHOD(device_probe,		opaldev_probe),
62*32d1354aSWojciech Macek 	DEVMETHOD(device_attach,	opaldev_attach),
63*32d1354aSWojciech Macek 
64*32d1354aSWojciech Macek 	/* clock interface */
65*32d1354aSWojciech Macek 	DEVMETHOD(clock_gettime,	opal_gettime),
66*32d1354aSWojciech Macek 	DEVMETHOD(clock_settime,	opal_settime),
67*32d1354aSWojciech Macek 
68*32d1354aSWojciech Macek         /* ofw_bus interface */
69*32d1354aSWojciech Macek 	DEVMETHOD(ofw_bus_get_devinfo,	opaldev_get_devinfo),
70*32d1354aSWojciech Macek 	DEVMETHOD(ofw_bus_get_compat,	ofw_bus_gen_get_compat),
71*32d1354aSWojciech Macek 	DEVMETHOD(ofw_bus_get_model,	ofw_bus_gen_get_model),
72*32d1354aSWojciech Macek 	DEVMETHOD(ofw_bus_get_name,	ofw_bus_gen_get_name),
73*32d1354aSWojciech Macek 	DEVMETHOD(ofw_bus_get_node,	ofw_bus_gen_get_node),
74*32d1354aSWojciech Macek 	DEVMETHOD(ofw_bus_get_type,	ofw_bus_gen_get_type),
75*32d1354aSWojciech Macek 
76*32d1354aSWojciech Macek 	DEVMETHOD_END
77*32d1354aSWojciech Macek };
78*32d1354aSWojciech Macek 
79*32d1354aSWojciech Macek static driver_t opaldev_driver = {
80*32d1354aSWojciech Macek 	"opal",
81*32d1354aSWojciech Macek 	opaldev_methods,
82*32d1354aSWojciech Macek 	0
83*32d1354aSWojciech Macek };
84*32d1354aSWojciech Macek 
85*32d1354aSWojciech Macek static devclass_t opaldev_devclass;
86*32d1354aSWojciech Macek 
87*32d1354aSWojciech Macek DRIVER_MODULE(opaldev, ofwbus, opaldev_driver, opaldev_devclass, 0, 0);
88*32d1354aSWojciech Macek 
89*32d1354aSWojciech Macek static int
90*32d1354aSWojciech Macek opaldev_probe(device_t dev)
91*32d1354aSWojciech Macek {
92*32d1354aSWojciech Macek 
93*32d1354aSWojciech Macek 	if (!ofw_bus_is_compatible(dev, "ibm,opal-v3"))
94*32d1354aSWojciech Macek 		return (ENXIO);
95*32d1354aSWojciech Macek 	if (opal_check() != 0)
96*32d1354aSWojciech Macek 		return (ENXIO);
97*32d1354aSWojciech Macek 
98*32d1354aSWojciech Macek 	device_set_desc(dev, "OPAL Abstraction Firmware");
99*32d1354aSWojciech Macek 	return (BUS_PROBE_SPECIFIC);
100*32d1354aSWojciech Macek }
101*32d1354aSWojciech Macek 
102*32d1354aSWojciech Macek static int
103*32d1354aSWojciech Macek opaldev_attach(device_t dev)
104*32d1354aSWojciech Macek {
105*32d1354aSWojciech Macek 	phandle_t child;
106*32d1354aSWojciech Macek 	device_t cdev;
107*32d1354aSWojciech Macek 	struct ofw_bus_devinfo *dinfo;
108*32d1354aSWojciech Macek 
109*32d1354aSWojciech Macek 	if (0 /* XXX NOT YET TEST FOR RTC */)
110*32d1354aSWojciech Macek 		clock_register(dev, 2000);
111*32d1354aSWojciech Macek 
112*32d1354aSWojciech Macek 	EVENTHANDLER_REGISTER(shutdown_final, opal_shutdown, NULL,
113*32d1354aSWojciech Macek 	    SHUTDOWN_PRI_LAST);
114*32d1354aSWojciech Macek 
115*32d1354aSWojciech Macek 	for (child = OF_child(ofw_bus_get_node(dev)); child != 0;
116*32d1354aSWojciech Macek 	    child = OF_peer(child)) {
117*32d1354aSWojciech Macek 		dinfo = malloc(sizeof(*dinfo), M_DEVBUF, M_WAITOK | M_ZERO);
118*32d1354aSWojciech Macek 		if (ofw_bus_gen_setup_devinfo(dinfo, child) != 0) {
119*32d1354aSWojciech Macek 			free(dinfo, M_DEVBUF);
120*32d1354aSWojciech Macek 			continue;
121*32d1354aSWojciech Macek 		}
122*32d1354aSWojciech Macek 		cdev = device_add_child(dev, NULL, -1);
123*32d1354aSWojciech Macek 		if (cdev == NULL) {
124*32d1354aSWojciech Macek 			device_printf(dev, "<%s>: device_add_child failed\n",
125*32d1354aSWojciech Macek 			    dinfo->obd_name);
126*32d1354aSWojciech Macek 			ofw_bus_gen_destroy_devinfo(dinfo);
127*32d1354aSWojciech Macek 			free(dinfo, M_DEVBUF);
128*32d1354aSWojciech Macek 			continue;
129*32d1354aSWojciech Macek 		}
130*32d1354aSWojciech Macek 		device_set_ivars(cdev, dinfo);
131*32d1354aSWojciech Macek 	}
132*32d1354aSWojciech Macek 
133*32d1354aSWojciech Macek 	return (bus_generic_attach(dev));
134*32d1354aSWojciech Macek }
135*32d1354aSWojciech Macek 
136*32d1354aSWojciech Macek static int
137*32d1354aSWojciech Macek opal_gettime(device_t dev, struct timespec *ts) {
138*32d1354aSWojciech Macek 	return (ENXIO);
139*32d1354aSWojciech Macek }
140*32d1354aSWojciech Macek 
141*32d1354aSWojciech Macek static int
142*32d1354aSWojciech Macek opal_settime(device_t dev, struct timespec *ts)
143*32d1354aSWojciech Macek {
144*32d1354aSWojciech Macek 	return (0);
145*32d1354aSWojciech Macek }
146*32d1354aSWojciech Macek 
147*32d1354aSWojciech Macek static const struct ofw_bus_devinfo *
148*32d1354aSWojciech Macek opaldev_get_devinfo(device_t dev, device_t child)
149*32d1354aSWojciech Macek {
150*32d1354aSWojciech Macek 	return (device_get_ivars(child));
151*32d1354aSWojciech Macek }
152*32d1354aSWojciech Macek 
153*32d1354aSWojciech Macek static void
154*32d1354aSWojciech Macek opal_shutdown(void *arg, int howto)
155*32d1354aSWojciech Macek {
156*32d1354aSWojciech Macek 
157*32d1354aSWojciech Macek 	if (howto & RB_HALT)
158*32d1354aSWojciech Macek 		opal_call(OPAL_CEC_POWER_DOWN, 0 /* Normal power off */);
159*32d1354aSWojciech Macek 	else
160*32d1354aSWojciech Macek 		opal_call(OPAL_CEC_REBOOT);
161*32d1354aSWojciech Macek }
162*32d1354aSWojciech Macek 
163