1 /* $OpenBSD: prtc.c,v 1.7 2022/10/12 13:39:50 kettenis Exp $ */
2
3 /*
4 * Copyright (c) 2008 Mark Kettenis
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19 /*
20 * Driver to get the time-of-day from the PROM for machines that don't
21 * have a hardware real-time clock, like the Enterprise 10000,
22 * Fire 12K and Fire 15K.
23 */
24
25 #include <sys/param.h>
26 #include <sys/device.h>
27 #include <sys/malloc.h>
28 #include <sys/systm.h>
29
30 #include <machine/autoconf.h>
31 #include <machine/openfirm.h>
32 #include <machine/sparc64.h>
33
34 #include <dev/clock_subr.h>
35
36 extern todr_chip_handle_t todr_handle;
37
38 struct prtc_softc {
39 struct device sc_dev;
40 struct todr_chip_handle
41 sc_todr_chip;
42 };
43
44 int prtc_match(struct device *, void *, void *);
45 void prtc_attach(struct device *, struct device *, void *);
46
47 const struct cfattach prtc_ca = {
48 sizeof(struct prtc_softc), prtc_match, prtc_attach
49 };
50
51 struct cfdriver prtc_cd = {
52 NULL, "prtc", DV_DULL
53 };
54
55 int prtc_gettime(todr_chip_handle_t, struct timeval *);
56 int prtc_settime(todr_chip_handle_t, struct timeval *);
57
58 int prtc_opl_gettime(todr_chip_handle_t, struct timeval *);
59 int prtc_opl_settime(todr_chip_handle_t, struct timeval *);
60
61 int
prtc_match(struct device * parent,void * match,void * aux)62 prtc_match(struct device *parent, void *match, void *aux)
63 {
64 struct mainbus_attach_args *ma = aux;
65
66 if (strcmp(ma->ma_name, "prtc") == 0)
67 return (1);
68
69 return (0);
70 }
71
72 void
prtc_attach(struct device * parent,struct device * self,void * aux)73 prtc_attach(struct device *parent, struct device *self, void *aux)
74 {
75 struct prtc_softc *sc = (struct prtc_softc *)self;
76 todr_chip_handle_t handle = &sc->sc_todr_chip;
77 char buf[32];
78 int opl;
79
80 opl = OF_getprop(findroot(), "name", buf, sizeof(buf)) > 0 &&
81 strcmp(buf, "SUNW,SPARC-Enterprise") == 0;
82
83 if (opl)
84 printf(": OPL");
85
86 printf("\n");
87
88 handle->cookie = sc;
89 if (opl) {
90 handle->todr_gettime = prtc_opl_gettime;
91 handle->todr_settime = prtc_opl_settime;
92 } else {
93 handle->todr_gettime = prtc_gettime;
94 handle->todr_settime = prtc_settime;
95 }
96
97 handle->bus_cookie = NULL;
98 handle->todr_setwen = NULL;
99 handle->todr_quality = 0;
100 todr_handle = handle;
101 }
102
103 int
prtc_gettime(todr_chip_handle_t handle,struct timeval * tv)104 prtc_gettime(todr_chip_handle_t handle, struct timeval *tv)
105 {
106 char buf[32];
107 u_int32_t tod = 0;
108
109 snprintf(buf, sizeof(buf), "h# %08lx unix-gettod", (long)&tod);
110 OF_interpret(buf, 0);
111
112 tv->tv_sec = tod;
113 tv->tv_usec = 0;
114 return (0);
115 }
116
117 int
prtc_settime(todr_chip_handle_t handle,struct timeval * tv)118 prtc_settime(todr_chip_handle_t handle, struct timeval *tv)
119 {
120 return (0);
121 }
122
123 int
prtc_opl_gettime(todr_chip_handle_t handle,struct timeval * tv)124 prtc_opl_gettime(todr_chip_handle_t handle, struct timeval *tv)
125 {
126 struct {
127 cell_t name;
128 cell_t nargs;
129 cell_t nrets;
130 cell_t stick;
131 cell_t time;
132 } args = {
133 .name = ADR2CELL("FJSV,get-tod"),
134 .nargs = 0,
135 .nrets = 2,
136 };
137
138 if (openfirmware(&args) == -1)
139 return (-1);
140
141 tv->tv_sec = args.time;
142 tv->tv_usec = 0;
143
144 return (0);
145 }
146
147 int
prtc_opl_settime(todr_chip_handle_t handle,struct timeval * tv)148 prtc_opl_settime(todr_chip_handle_t handle, struct timeval *tv)
149 {
150 struct timeval otv;
151 struct {
152 cell_t name;
153 cell_t nargs;
154 cell_t nrets;
155 cell_t diff;
156 } args = {
157 .name = ADR2CELL("FJSV,set-domain-time"),
158 .nargs = 1,
159 .nrets = 0,
160 };
161
162 if (prtc_opl_gettime(handle, &otv) == -1)
163 return (-1);
164
165 args.diff = tv->tv_sec - otv.tv_sec;
166 if (args.diff == 0)
167 return (0);
168
169 if (openfirmware(&args) == -1)
170 return (-1);
171
172 return (0);
173 }
174