xref: /openbsd/sys/arch/armv7/marvell/mvortc.c (revision d415bd75)
1 /*	$OpenBSD: mvortc.c,v 1.1 2023/03/02 09:57:43 jmatthew Exp $	*/
2 /*
3  * Copyright (c) 2022 Jonathan Matthew <jmatthew@openbsd.org>
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 
18 #include <sys/param.h>
19 #include <sys/systm.h>
20 #include <sys/device.h>
21 
22 #include <machine/intr.h>
23 #include <machine/bus.h>
24 #include <machine/fdt.h>
25 
26 #include <dev/ofw/openfirm.h>
27 #include <dev/ofw/fdt.h>
28 
29 #include <dev/clock_subr.h>
30 
31 extern todr_chip_handle_t todr_handle;
32 
33 /* Registers. */
34 #define RTC_STATUS		0x0000
35 #define RTC_TIME		0x000c
36 #define RTC_CONF_TEST		0x001c
37 
38 #define RTC_TIMING_CTL		0x0000
39 #define  RTC_PERIOD_SHIFT	0
40 #define  RTC_PERIOD_MASK	(0x3ff << RTC_PERIOD_SHIFT)
41 #define  RTC_READ_DELAY_SHIFT 	26
42 #define  RTC_READ_DELAY_MASK 	(0x1f << RTC_READ_DELAY_SHIFT)
43 
44 
45 #define HREAD4(sc, reg)							\
46 	(bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg)))
47 #define HWRITE4(sc, reg, val)						\
48 	bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val))
49 
50 struct mvortc_softc {
51 	struct device		sc_dev;
52 	bus_space_tag_t		sc_iot;
53 	bus_space_handle_t	sc_ioh;
54 	bus_space_handle_t	sc_soc_ioh;
55 
56 	struct todr_chip_handle sc_todr;
57 };
58 
59 int mvortc_match(struct device *, void *, void *);
60 void mvortc_attach(struct device *, struct device *, void *);
61 
62 const struct cfattach	mvortc_ca = {
63 	sizeof (struct mvortc_softc), mvortc_match, mvortc_attach
64 };
65 
66 struct cfdriver mvortc_cd = {
67 	NULL, "mvortc", DV_DULL
68 };
69 
70 int	mvortc_gettime(struct todr_chip_handle *, struct timeval *);
71 int	mvortc_settime(struct todr_chip_handle *, struct timeval *);
72 
73 int
74 mvortc_match(struct device *parent, void *match, void *aux)
75 {
76 	struct fdt_attach_args *faa = aux;
77 
78 	return OF_is_compatible(faa->fa_node, "marvell,armada-380-rtc");
79 }
80 
81 void
82 mvortc_attach(struct device *parent, struct device *self, void *aux)
83 {
84 	struct mvortc_softc *sc = (struct mvortc_softc *)self;
85 	struct fdt_attach_args *faa = aux;
86 	uint32_t reg;
87 
88 	if (faa->fa_nreg < 2) {
89 		printf(": no registers\n");
90 		return;
91 	}
92 
93 	sc->sc_iot = faa->fa_iot;
94 
95 	if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr,
96 	    faa->fa_reg[0].size, 0, &sc->sc_ioh)) {
97 		printf(": can't map registers\n");
98 		return;
99 	}
100 
101 	if (bus_space_map(sc->sc_iot, faa->fa_reg[1].addr,
102 	    faa->fa_reg[1].size, 0, &sc->sc_soc_ioh)) {
103 		bus_space_unmap(sc->sc_iot, sc->sc_ioh, faa->fa_reg[0].size);
104 		printf(": can't map soc registers\n");
105 		return;
106 	}
107 
108 	/* Magic to make bus access actually work. */
109 	reg = bus_space_read_4(sc->sc_iot, sc->sc_soc_ioh, RTC_TIMING_CTL);
110 	reg &= ~RTC_PERIOD_MASK;
111 	reg |= (0x3ff << RTC_PERIOD_SHIFT);
112 	reg &= ~RTC_READ_DELAY_MASK;
113 	reg |= (0x1f << RTC_READ_DELAY_SHIFT);
114 	bus_space_write_4(sc->sc_iot, sc->sc_soc_ioh, RTC_TIMING_CTL, reg);
115 	printf("\n");
116 
117 	sc->sc_todr.cookie = sc;
118 	sc->sc_todr.todr_gettime = mvortc_gettime;
119 	sc->sc_todr.todr_settime = mvortc_settime;
120 	todr_handle = &sc->sc_todr;
121 }
122 
123 uint32_t
124 mvortc_read(struct mvortc_softc *sc, int reg)
125 {
126 	uint32_t sample, mode;
127 	uint32_t samples[100];
128 	int counts[100];
129 	int i, j, last;
130 
131 	memset(samples, 0, sizeof(samples));
132 	memset(counts, 0, sizeof(counts));
133 	last = 0;
134 	for (i = 0; i < nitems(samples); i++) {
135 		sample = HREAD4(sc, reg);
136 
137 		for (j = 0; j < last; j++) {
138 			if (samples[j] == sample)
139 				break;
140 		}
141 
142 		if (j < last) {
143 			counts[j]++;
144 		} else {
145 			samples[last] = sample;
146 			counts[last] = 1;
147 			last++;
148 		}
149 	}
150 
151 	j = 0;
152 	mode = 0;
153 	for (i = 0; i < last; i++) {
154 		if (counts[i] > mode) {
155 			mode = counts[i];
156 			j = i;
157 		}
158 	}
159 
160 	return samples[j];
161 }
162 
163 void
164 mvortc_write(struct mvortc_softc *sc, int reg, uint32_t val)
165 {
166 	HWRITE4(sc, RTC_STATUS, 0);
167 	HWRITE4(sc, RTC_STATUS, 0);
168 	HWRITE4(sc, reg, val);
169 	delay(5);
170 }
171 
172 int
173 mvortc_gettime(struct todr_chip_handle *handle, struct timeval *tv)
174 {
175 	struct mvortc_softc *sc = handle->cookie;
176 
177 	tv->tv_sec = mvortc_read(sc, RTC_TIME);
178 	tv->tv_usec = 0;
179 	return 0;
180 }
181 
182 int
183 mvortc_settime(struct todr_chip_handle *handle, struct timeval *tv)
184 {
185 	struct mvortc_softc *sc = handle->cookie;
186 	uint32_t reg;
187 
188 	reg = mvortc_read(sc, RTC_CONF_TEST);
189 	if (reg & 0xff) {
190 		mvortc_write(sc, RTC_CONF_TEST, 0);
191 		delay(500);
192 		mvortc_write(sc, RTC_TIME, 0);
193 		mvortc_write(sc, RTC_STATUS, 0x03);
194 	}
195 
196 	mvortc_write(sc, RTC_TIME, tv->tv_sec);
197 	return 0;
198 }
199