xref: /openbsd/sys/dev/fdt/sxirtc.c (revision 097a140d)
1 /*	$OpenBSD: sxirtc.c,v 1.5 2021/04/24 10:15:15 mpi Exp $	*/
2 /*
3  * Copyright (c) 2008 Mark Kettenis
4  * Copyright (c) 2013 Artturi Alm
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 #include <sys/param.h>
20 #include <sys/device.h>
21 #include <sys/malloc.h>
22 #include <sys/systm.h>
23 
24 #include <dev/clock_subr.h>
25 
26 #include <machine/bus.h>
27 #include <machine/fdt.h>
28 
29 #include <dev/fdt/sunxireg.h>
30 
31 #include <dev/ofw/openfirm.h>
32 #include <dev/ofw/fdt.h>
33 #include <dev/ofw/ofw_clock.h>
34 
35 #define SXIRTC_LOSC_CTRL		0x00
36 #define  SXIRTC_LOSC_CTRL_KEY_FIELD	0x16aa0000
37 #define  SXIRTC_LOSC_CTRL_SEL_EXT32K	0x00000001
38 #define SXIRTC_YYMMDD_A10		0x04
39 #define SXIRTC_HHMMSS_A10		0x08
40 #define SXIRTC_YYMMDD_A31		0x10
41 #define SXIRTC_HHMMSS_A31		0x14
42 #define SXIRTC_LOSC_OUT_GATING		0x60
43 
44 #define LEAPYEAR(y)        \
45     (((y) % 4 == 0 &&    \
46     (y) % 100 != 0) ||    \
47     (y) % 400 == 0)
48 
49 
50 extern todr_chip_handle_t todr_handle;
51 
52 struct sxirtc_softc {
53 	struct device		sc_dev;
54 	bus_space_tag_t		sc_iot;
55 	bus_space_handle_t	sc_ioh;
56 
57 	struct clock_device	sc_cd;
58 
59 	bus_size_t		sc_yymmdd;
60 	bus_size_t		sc_hhmmss;
61 	uint32_t		base_year;
62 	uint32_t		year_mask;
63 	uint32_t		leap_shift;
64 };
65 
66 int	sxirtc_match(struct device *, void *, void *);
67 void	sxirtc_attach(struct device *, struct device *, void *);
68 
69 struct cfattach sxirtc_ca = {
70 	sizeof(struct sxirtc_softc), sxirtc_match, sxirtc_attach
71 };
72 
73 struct cfdriver sxirtc_cd = {
74 	NULL, "sxirtc", DV_DULL
75 };
76 
77 uint32_t sxirtc_get_frequency(void *, uint32_t *);
78 void	sxirtc_enable(void *, uint32_t *, int);
79 int	sxirtc_gettime(todr_chip_handle_t, struct timeval *);
80 int	sxirtc_settime(todr_chip_handle_t, struct timeval *);
81 
82 int
83 sxirtc_match(struct device *parent, void *match, void *aux)
84 {
85 	struct fdt_attach_args *faa = aux;
86 
87 	return (OF_is_compatible(faa->fa_node, "allwinner,sun4i-a10-rtc") ||
88 	    OF_is_compatible(faa->fa_node, "allwinner,sun7i-a20-rtc") ||
89 	    OF_is_compatible(faa->fa_node, "allwinner,sun6i-a31-rtc") ||
90 	    OF_is_compatible(faa->fa_node, "allwinner,sun8i-h3-rtc") ||
91 	    OF_is_compatible(faa->fa_node, "allwinner,sun50i-h5-rtc"));
92 }
93 
94 void
95 sxirtc_attach(struct device *parent, struct device *self, void *aux)
96 {
97 	struct sxirtc_softc *sc = (struct sxirtc_softc *)self;
98 	struct fdt_attach_args *faa = aux;
99 	todr_chip_handle_t handle;
100 
101 	if (faa->fa_nreg < 1)
102 		return;
103 
104 	handle = malloc(sizeof(struct todr_chip_handle), M_DEVBUF, M_NOWAIT);
105 	if (handle == NULL)
106 		panic("sxirtc_attach: couldn't allocate todr_handle");
107 
108 	sc->sc_iot = faa->fa_iot;
109 	if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr,
110 	    faa->fa_reg[0].size, 0, &sc->sc_ioh))
111 		panic("sxirtc_attach: bus_space_map failed!");
112 
113 	if (OF_is_compatible(faa->fa_node, "allwinner,sun6i-a31-rtc") ||
114 	    OF_is_compatible(faa->fa_node, "allwinner,sun8i-h3-rtc") ||
115 	    OF_is_compatible(faa->fa_node, "allwinner,sun50i-h5-rtc")) {
116 		sc->sc_yymmdd = SXIRTC_YYMMDD_A31;
117 		sc->sc_hhmmss = SXIRTC_HHMMSS_A31;
118 	} else {
119 		sc->sc_yymmdd = SXIRTC_YYMMDD_A10;
120 		sc->sc_hhmmss = SXIRTC_HHMMSS_A10;
121 	}
122 
123 	if (OF_is_compatible(faa->fa_node, "allwinner,sun7i-a20-rtc")) {
124 		sc->base_year = 1970;
125 		sc->year_mask = 0xff;
126 		sc->leap_shift = 24;
127 	} else {
128 		sc->base_year = 2010;
129 		sc->year_mask = 0x3f;
130 		sc->leap_shift = 22;
131 	}
132 
133 	if (OF_is_compatible(faa->fa_node, "allwinner,sun8i-h3-rtc") ||
134 	    OF_is_compatible(faa->fa_node, "allwinner,sun50i-h5-rtc")) {
135 		/* Switch to external oscillator. */
136 		SXIWRITE4(sc, SXIRTC_LOSC_CTRL,
137 		    SXIRTC_LOSC_CTRL_KEY_FIELD | SXIRTC_LOSC_CTRL_SEL_EXT32K);
138 
139 		sc->sc_cd.cd_node = faa->fa_node;
140 		sc->sc_cd.cd_cookie = sc;
141 		sc->sc_cd.cd_get_frequency = sxirtc_get_frequency;
142 		sc->sc_cd.cd_enable = sxirtc_enable;
143 		clock_register(&sc->sc_cd);
144 	}
145 
146 	handle->cookie = self;
147 	handle->todr_gettime = sxirtc_gettime;
148 	handle->todr_settime = sxirtc_settime;
149 	handle->bus_cookie = NULL;
150 	handle->todr_setwen = NULL;
151 	todr_handle = handle;
152 
153 	printf("\n");
154 }
155 
156 uint32_t
157 sxirtc_get_frequency(void *cookie, uint32_t *cells)
158 {
159 	struct sxirtc_softc *sc = cookie;
160 	uint32_t idx = cells[0];
161 
162 	switch (idx) {
163 	case 0:			/* osc32k */
164 	case 1:			/* osc32k-out */
165 		return clock_get_frequency_idx(sc->sc_cd.cd_node, 0);
166 	case 2:			/* iosc */
167 		return 16000000;
168 	}
169 
170 	printf("%s: 0x%08x\n", __func__, idx);
171 	return 0;
172 }
173 
174 void
175 sxirtc_enable(void *cookie, uint32_t *cells, int on)
176 {
177 	struct sxirtc_softc *sc = cookie;
178 	uint32_t idx = cells[0];
179 
180 	switch (idx) {
181 	case 0:			/* osc32k */
182 		break;
183 	case 1:			/* osc32k-out */
184 		if (on)
185 			SXISET4(sc, SXIRTC_LOSC_OUT_GATING, 1);
186 		else
187 			SXICLR4(sc, SXIRTC_LOSC_OUT_GATING, 1);
188 		break;
189 	case 2:			/* iosc */
190 		break;
191 	default:
192 		printf("%s: 0x%08x\n", __func__, idx);
193 		break;
194 	}
195 }
196 
197 int
198 sxirtc_gettime(todr_chip_handle_t handle, struct timeval *tv)
199 {
200 	struct sxirtc_softc *sc = (struct sxirtc_softc *)handle->cookie;
201 	struct clock_ymdhms dt;
202 	uint32_t reg;
203 
204 	reg = SXIREAD4(sc, sc->sc_hhmmss);
205 	dt.dt_sec = reg & 0x3f;
206 	dt.dt_min = reg >> 8 & 0x3f;
207 	dt.dt_hour = reg >> 16 & 0x1f;
208 	dt.dt_wday = reg >> 29 & 0x07;
209 
210 	reg = SXIREAD4(sc, sc->sc_yymmdd);
211 	dt.dt_day = reg & 0x1f;
212 	dt.dt_mon = reg >> 8 & 0x0f;
213 	dt.dt_year = (reg >> 16 & sc->year_mask) + sc->base_year;
214 
215 	if (dt.dt_sec > 59 || dt.dt_min > 59 ||
216 	    dt.dt_hour > 23 || dt.dt_wday > 6 ||
217 	    dt.dt_day > 31 || dt.dt_day == 0 ||
218 	    dt.dt_mon > 12 || dt.dt_mon == 0)
219 		return 1;
220 
221 	/*
222 	 * Reject the first year that can be represented by the clock.
223 	 * This avoids reporting a bogus time if the RTC isn't battery
224 	 * powered.
225 	 */
226 	if (dt.dt_year == sc->base_year)
227 		return 1;
228 
229 	tv->tv_sec = clock_ymdhms_to_secs(&dt);
230 	tv->tv_usec = 0;
231 	return 0;
232 }
233 
234 int
235 sxirtc_settime(todr_chip_handle_t handle, struct timeval *tv)
236 {
237 	struct sxirtc_softc *sc = (struct sxirtc_softc *)handle->cookie;
238 	struct clock_ymdhms dt;
239 
240 	clock_secs_to_ymdhms(tv->tv_sec, &dt);
241 
242 	if (dt.dt_sec > 59 || dt.dt_min > 59 ||
243 	    dt.dt_hour > 23 || dt.dt_wday > 6 ||
244 	    dt.dt_day > 31 || dt.dt_day == 0 ||
245 	    dt.dt_mon > 12 || dt.dt_mon == 0)
246 		return 1;
247 
248 	SXICMS4(sc, sc->sc_hhmmss, 0xe0000000 | 0x1f0000 | 0x3f00 | 0x3f,
249 	    dt.dt_sec | (dt.dt_min << 8) | (dt.dt_hour << 16) |
250 	    (dt.dt_wday << 29));
251 
252 	SXICMS4(sc, sc->sc_yymmdd, 0x00400000 | (sc->year_mask << 16) |
253 	    0x0f00 | 0x1f, dt.dt_day | (dt.dt_mon << 8) |
254 	    ((dt.dt_year - sc->base_year) << 16) |
255 	    (LEAPYEAR(dt.dt_year) << sc->leap_shift));
256 
257 	return 0;
258 }
259