1cb0c98fcSMarcin Wojtas /*-
2cb0c98fcSMarcin Wojtas * Copyright (c) 2015 Semihalf.
3cb0c98fcSMarcin Wojtas * Copyright (c) 2015 Stormshield.
4cb0c98fcSMarcin Wojtas * All rights reserved.
5cb0c98fcSMarcin Wojtas *
6cb0c98fcSMarcin Wojtas * Redistribution and use in source and binary forms, with or without
7cb0c98fcSMarcin Wojtas * modification, are permitted provided that the following conditions
8cb0c98fcSMarcin Wojtas * are met:
9cb0c98fcSMarcin Wojtas * 1. Redistributions of source code must retain the above copyright
10cb0c98fcSMarcin Wojtas * notice, this list of conditions and the following disclaimer.
11cb0c98fcSMarcin Wojtas * 2. Redistributions in binary form must reproduce the above copyright
12cb0c98fcSMarcin Wojtas * notice, this list of conditions and the following disclaimer in the
13cb0c98fcSMarcin Wojtas * documentation and/or other materials provided with the distribution.
14cb0c98fcSMarcin Wojtas *
15cb0c98fcSMarcin Wojtas * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16cb0c98fcSMarcin Wojtas * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17cb0c98fcSMarcin Wojtas * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18cb0c98fcSMarcin Wojtas * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19cb0c98fcSMarcin Wojtas * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20cb0c98fcSMarcin Wojtas * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21cb0c98fcSMarcin Wojtas * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22cb0c98fcSMarcin Wojtas * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23cb0c98fcSMarcin Wojtas * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24cb0c98fcSMarcin Wojtas * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25cb0c98fcSMarcin Wojtas * SUCH DAMAGE.
26cb0c98fcSMarcin Wojtas */
27cb0c98fcSMarcin Wojtas
28cb0c98fcSMarcin Wojtas #include <sys/param.h>
29cb0c98fcSMarcin Wojtas #include <sys/bus.h>
30cb0c98fcSMarcin Wojtas #include <sys/lock.h>
31cb0c98fcSMarcin Wojtas #include <sys/time.h>
32cb0c98fcSMarcin Wojtas #include <sys/proc.h>
33cb0c98fcSMarcin Wojtas #include <sys/conf.h>
34cb0c98fcSMarcin Wojtas #include <sys/rman.h>
35cb0c98fcSMarcin Wojtas #include <sys/clock.h>
36cb0c98fcSMarcin Wojtas #include <sys/systm.h>
37cb0c98fcSMarcin Wojtas #include <sys/mutex.h>
38cb0c98fcSMarcin Wojtas #include <sys/types.h>
39cb0c98fcSMarcin Wojtas #include <sys/kernel.h>
40cb0c98fcSMarcin Wojtas #include <sys/module.h>
41cb0c98fcSMarcin Wojtas #include <sys/resource.h>
42cb0c98fcSMarcin Wojtas
43cb0c98fcSMarcin Wojtas #include <machine/bus.h>
44cb0c98fcSMarcin Wojtas #include <machine/resource.h>
45cb0c98fcSMarcin Wojtas
46cb0c98fcSMarcin Wojtas #include <dev/ofw/ofw_bus.h>
47cb0c98fcSMarcin Wojtas #include <dev/ofw/ofw_bus_subr.h>
48cb0c98fcSMarcin Wojtas
49cb0c98fcSMarcin Wojtas #include "clock_if.h"
50cb0c98fcSMarcin Wojtas
51cb0c98fcSMarcin Wojtas #define RTC_RES_US 1000000
52cb0c98fcSMarcin Wojtas #define HALF_OF_SEC_NS 500000000
53cb0c98fcSMarcin Wojtas
54cb0c98fcSMarcin Wojtas #define RTC_STATUS 0x0
55cb0c98fcSMarcin Wojtas #define RTC_TIME 0xC
56cb0c98fcSMarcin Wojtas #define RTC_TEST_CONFIG 0x1C
57cb0c98fcSMarcin Wojtas #define RTC_IRQ_1_CONFIG 0x4
58cb0c98fcSMarcin Wojtas #define RTC_IRQ_2_CONFIG 0x8
59cb0c98fcSMarcin Wojtas #define RTC_ALARM_1 0x10
60cb0c98fcSMarcin Wojtas #define RTC_ALARM_2 0x14
61cb0c98fcSMarcin Wojtas #define RTC_CLOCK_CORR 0x18
62cb0c98fcSMarcin Wojtas
63cb0c98fcSMarcin Wojtas #define RTC_NOMINAL_TIMING 0x2000
64cb0c98fcSMarcin Wojtas #define RTC_NOMINAL_TIMING_MASK 0x7fff
65cb0c98fcSMarcin Wojtas
66cb0c98fcSMarcin Wojtas #define RTC_STATUS_ALARM1_MASK 0x1
67cb0c98fcSMarcin Wojtas #define RTC_STATUS_ALARM2_MASK 0x2
68cb0c98fcSMarcin Wojtas
69cb0c98fcSMarcin Wojtas #define MV_RTC_LOCK(sc) mtx_lock_spin(&(sc)->mutex)
70cb0c98fcSMarcin Wojtas #define MV_RTC_UNLOCK(sc) mtx_unlock_spin(&(sc)->mutex)
71cb0c98fcSMarcin Wojtas
72d5d4dd38SMichal Meloun #define A38X_RTC_BRIDGE_TIMING_CTRL 0x0
73d5d4dd38SMichal Meloun #define A38X_RTC_WRCLK_PERIOD_SHIFT 0
74d5d4dd38SMichal Meloun #define A38X_RTC_WRCLK_PERIOD_MASK 0x00000003FF
75d5d4dd38SMichal Meloun #define A38X_RTC_WRCLK_PERIOD_MAX 0x3FF
76d5d4dd38SMichal Meloun #define A38X_RTC_READ_OUTPUT_DELAY_SHIFT 26
77d5d4dd38SMichal Meloun #define A38X_RTC_READ_OUTPUT_DELAY_MASK 0x007C000000
78d5d4dd38SMichal Meloun #define A38X_RTC_READ_OUTPUT_DELAY_MAX 0x1F
79d5d4dd38SMichal Meloun
80d5d4dd38SMichal Meloun #define A8K_RTC_BRIDGE_TIMING_CTRL0 0x0
81d5d4dd38SMichal Meloun #define A8K_RTC_WRCLK_PERIOD_SHIFT 0
82d5d4dd38SMichal Meloun #define A8K_RTC_WRCLK_PERIOD_MASK 0x000000FFFF
83d5d4dd38SMichal Meloun #define A8K_RTC_WRCLK_PERIOD_VAL 0x3FF
84d5d4dd38SMichal Meloun #define A8K_RTC_WRCLK_SETUP_SHIFT 16
85d5d4dd38SMichal Meloun #define A8K_RTC_WRCLK_SETUP_MASK 0x00FFFF0000
86d5d4dd38SMichal Meloun #define A8K_RTC_WRCLK_SETUP_VAL 29
87d5d4dd38SMichal Meloun #define A8K_RTC_BRIDGE_TIMING_CTRL1 0x4
88d5d4dd38SMichal Meloun #define A8K_RTC_READ_OUTPUT_DELAY_SHIFT 0
89d5d4dd38SMichal Meloun #define A8K_RTC_READ_OUTPUT_DELAY_MASK 0x000000FFFF
90d5d4dd38SMichal Meloun #define A8K_RTC_READ_OUTPUT_DELAY_VAL 0x3F
91d5d4dd38SMichal Meloun
92cb0c98fcSMarcin Wojtas #define RTC_RES 0
93cb0c98fcSMarcin Wojtas #define RTC_SOC_RES 1
94cb0c98fcSMarcin Wojtas
95cb0c98fcSMarcin Wojtas static struct resource_spec res_spec[] = {
96cb0c98fcSMarcin Wojtas { SYS_RES_MEMORY, 0, RF_ACTIVE },
97cb0c98fcSMarcin Wojtas { SYS_RES_MEMORY, 1, RF_ACTIVE },
98cb0c98fcSMarcin Wojtas { -1, 0 }
99cb0c98fcSMarcin Wojtas };
100cb0c98fcSMarcin Wojtas
101cb0c98fcSMarcin Wojtas struct mv_rtc_softc {
102cb0c98fcSMarcin Wojtas device_t dev;
103cb0c98fcSMarcin Wojtas struct resource *res[2];
104cb0c98fcSMarcin Wojtas struct mtx mutex;
105d5d4dd38SMichal Meloun int rtc_type;
106cb0c98fcSMarcin Wojtas };
107cb0c98fcSMarcin Wojtas
108cb0c98fcSMarcin Wojtas static int mv_rtc_probe(device_t dev);
109cb0c98fcSMarcin Wojtas static int mv_rtc_attach(device_t dev);
110cb0c98fcSMarcin Wojtas static int mv_rtc_detach(device_t dev);
111cb0c98fcSMarcin Wojtas
112cb0c98fcSMarcin Wojtas static int mv_rtc_gettime(device_t dev, struct timespec *ts);
113cb0c98fcSMarcin Wojtas static int mv_rtc_settime(device_t dev, struct timespec *ts);
114cb0c98fcSMarcin Wojtas
115cb0c98fcSMarcin Wojtas static inline uint32_t mv_rtc_reg_read(struct mv_rtc_softc *sc,
116cb0c98fcSMarcin Wojtas bus_size_t off);
117cb0c98fcSMarcin Wojtas static inline int mv_rtc_reg_write(struct mv_rtc_softc *sc, bus_size_t off,
118cb0c98fcSMarcin Wojtas uint32_t val);
119d5d4dd38SMichal Meloun static inline void mv_rtc_configure_bus_a38x(struct mv_rtc_softc *sc);
120d5d4dd38SMichal Meloun static inline void mv_rtc_configure_bus_a8k(struct mv_rtc_softc *sc);
121cb0c98fcSMarcin Wojtas
122cb0c98fcSMarcin Wojtas static device_method_t mv_rtc_methods[] = {
123cb0c98fcSMarcin Wojtas DEVMETHOD(device_probe, mv_rtc_probe),
124cb0c98fcSMarcin Wojtas DEVMETHOD(device_attach, mv_rtc_attach),
125cb0c98fcSMarcin Wojtas DEVMETHOD(device_detach, mv_rtc_detach),
126cb0c98fcSMarcin Wojtas
127cb0c98fcSMarcin Wojtas DEVMETHOD(clock_gettime, mv_rtc_gettime),
128cb0c98fcSMarcin Wojtas DEVMETHOD(clock_settime, mv_rtc_settime),
129cb0c98fcSMarcin Wojtas
130cb0c98fcSMarcin Wojtas { 0, 0 },
131cb0c98fcSMarcin Wojtas };
132cb0c98fcSMarcin Wojtas
133cb0c98fcSMarcin Wojtas static driver_t mv_rtc_driver = {
134cb0c98fcSMarcin Wojtas "rtc",
135cb0c98fcSMarcin Wojtas mv_rtc_methods,
136cb0c98fcSMarcin Wojtas sizeof(struct mv_rtc_softc),
137cb0c98fcSMarcin Wojtas };
138cb0c98fcSMarcin Wojtas
139d5d4dd38SMichal Meloun #define RTC_A38X 1
140d5d4dd38SMichal Meloun #define RTC_A8K 2
141d5d4dd38SMichal Meloun
142ee1c891dSMarcin Wojtas static struct ofw_compat_data mv_rtc_compat[] = {
143d5d4dd38SMichal Meloun {"marvell,armada-380-rtc", RTC_A38X},
144d5d4dd38SMichal Meloun {"marvell,armada-8k-rtc", RTC_A8K},
145d5d4dd38SMichal Meloun {NULL, 0},
146ee1c891dSMarcin Wojtas };
147ee1c891dSMarcin Wojtas
148*a3b866cbSJohn Baldwin DRIVER_MODULE(a38x_rtc, simplebus, mv_rtc_driver, 0, 0);
149cb0c98fcSMarcin Wojtas
150cb0c98fcSMarcin Wojtas static void
mv_rtc_reset(device_t dev)151cb0c98fcSMarcin Wojtas mv_rtc_reset(device_t dev)
152cb0c98fcSMarcin Wojtas {
153cb0c98fcSMarcin Wojtas struct mv_rtc_softc *sc;
154cb0c98fcSMarcin Wojtas
155cb0c98fcSMarcin Wojtas sc = device_get_softc(dev);
156cb0c98fcSMarcin Wojtas
157cb0c98fcSMarcin Wojtas /* Reset Test register */
158cb0c98fcSMarcin Wojtas mv_rtc_reg_write(sc, RTC_TEST_CONFIG, 0);
159cb0c98fcSMarcin Wojtas DELAY(500000);
160cb0c98fcSMarcin Wojtas
161cb0c98fcSMarcin Wojtas /* Reset Time register */
162cb0c98fcSMarcin Wojtas mv_rtc_reg_write(sc, RTC_TIME, 0);
163cb0c98fcSMarcin Wojtas DELAY(62);
164cb0c98fcSMarcin Wojtas
165cb0c98fcSMarcin Wojtas /* Reset Status register */
166cb0c98fcSMarcin Wojtas mv_rtc_reg_write(sc, RTC_STATUS, (RTC_STATUS_ALARM1_MASK | RTC_STATUS_ALARM2_MASK));
167cb0c98fcSMarcin Wojtas DELAY(62);
168cb0c98fcSMarcin Wojtas
169cb0c98fcSMarcin Wojtas /* Turn off Int1 and Int2 sources & clear the Alarm count */
170cb0c98fcSMarcin Wojtas mv_rtc_reg_write(sc, RTC_IRQ_1_CONFIG, 0);
171cb0c98fcSMarcin Wojtas mv_rtc_reg_write(sc, RTC_IRQ_2_CONFIG, 0);
172cb0c98fcSMarcin Wojtas mv_rtc_reg_write(sc, RTC_ALARM_1, 0);
173cb0c98fcSMarcin Wojtas mv_rtc_reg_write(sc, RTC_ALARM_2, 0);
174cb0c98fcSMarcin Wojtas
175cb0c98fcSMarcin Wojtas /* Setup nominal register access timing */
176cb0c98fcSMarcin Wojtas mv_rtc_reg_write(sc, RTC_CLOCK_CORR, RTC_NOMINAL_TIMING);
177cb0c98fcSMarcin Wojtas
178cb0c98fcSMarcin Wojtas /* Reset Time register */
179cb0c98fcSMarcin Wojtas mv_rtc_reg_write(sc, RTC_TIME, 0);
180cb0c98fcSMarcin Wojtas DELAY(10);
181cb0c98fcSMarcin Wojtas
182cb0c98fcSMarcin Wojtas /* Reset Status register */
183cb0c98fcSMarcin Wojtas mv_rtc_reg_write(sc, RTC_STATUS, (RTC_STATUS_ALARM1_MASK | RTC_STATUS_ALARM2_MASK));
184cb0c98fcSMarcin Wojtas DELAY(50);
185cb0c98fcSMarcin Wojtas }
186cb0c98fcSMarcin Wojtas
187cb0c98fcSMarcin Wojtas static int
mv_rtc_probe(device_t dev)188cb0c98fcSMarcin Wojtas mv_rtc_probe(device_t dev)
189cb0c98fcSMarcin Wojtas {
190cb0c98fcSMarcin Wojtas
191cb0c98fcSMarcin Wojtas if (!ofw_bus_status_okay(dev))
192cb0c98fcSMarcin Wojtas return (ENXIO);
193cb0c98fcSMarcin Wojtas
194ee1c891dSMarcin Wojtas if (!ofw_bus_search_compatible(dev, mv_rtc_compat)->ocd_data)
195cb0c98fcSMarcin Wojtas return (ENXIO);
196cb0c98fcSMarcin Wojtas
197cb0c98fcSMarcin Wojtas device_set_desc(dev, "Marvell Integrated RTC");
198cb0c98fcSMarcin Wojtas
199cb0c98fcSMarcin Wojtas return (BUS_PROBE_DEFAULT);
200cb0c98fcSMarcin Wojtas }
201cb0c98fcSMarcin Wojtas
202cb0c98fcSMarcin Wojtas static int
mv_rtc_attach(device_t dev)203cb0c98fcSMarcin Wojtas mv_rtc_attach(device_t dev)
204cb0c98fcSMarcin Wojtas {
205cb0c98fcSMarcin Wojtas struct mv_rtc_softc *sc;
206b20f0f72SWarner Losh int ret;
207cb0c98fcSMarcin Wojtas
208cb0c98fcSMarcin Wojtas sc = device_get_softc(dev);
209cb0c98fcSMarcin Wojtas sc->dev = dev;
210d5d4dd38SMichal Meloun sc->rtc_type = ofw_bus_search_compatible(dev, mv_rtc_compat)->ocd_data;
211cb0c98fcSMarcin Wojtas
212cb0c98fcSMarcin Wojtas mtx_init(&sc->mutex, device_get_nameunit(dev), NULL, MTX_SPIN);
213cb0c98fcSMarcin Wojtas
214cb0c98fcSMarcin Wojtas ret = bus_alloc_resources(dev, res_spec, sc->res);
215cb0c98fcSMarcin Wojtas if (ret != 0) {
216cb0c98fcSMarcin Wojtas device_printf(dev, "could not allocate resources\n");
217cb0c98fcSMarcin Wojtas mtx_destroy(&sc->mutex);
218cb0c98fcSMarcin Wojtas return (ENXIO);
219cb0c98fcSMarcin Wojtas }
220d5d4dd38SMichal Meloun
221d5d4dd38SMichal Meloun switch (sc->rtc_type) {
222d5d4dd38SMichal Meloun case RTC_A38X:
223d5d4dd38SMichal Meloun mv_rtc_configure_bus_a38x(sc);
224d5d4dd38SMichal Meloun break;
225d5d4dd38SMichal Meloun case RTC_A8K:
226d5d4dd38SMichal Meloun mv_rtc_configure_bus_a8k(sc);
227d5d4dd38SMichal Meloun break;
228d5d4dd38SMichal Meloun default:
229d5d4dd38SMichal Meloun panic("Unknown RTC type: %d", sc->rtc_type);
230d5d4dd38SMichal Meloun }
231d5d4dd38SMichal Meloun clock_register(dev, RTC_RES_US);
232cb0c98fcSMarcin Wojtas
233cb0c98fcSMarcin Wojtas return (0);
234cb0c98fcSMarcin Wojtas }
235cb0c98fcSMarcin Wojtas
236cb0c98fcSMarcin Wojtas static int
mv_rtc_detach(device_t dev)237cb0c98fcSMarcin Wojtas mv_rtc_detach(device_t dev)
238cb0c98fcSMarcin Wojtas {
239cb0c98fcSMarcin Wojtas struct mv_rtc_softc *sc;
240cb0c98fcSMarcin Wojtas
241cb0c98fcSMarcin Wojtas sc = device_get_softc(dev);
242cb0c98fcSMarcin Wojtas
243cb0c98fcSMarcin Wojtas mtx_destroy(&sc->mutex);
244cb0c98fcSMarcin Wojtas
245cb0c98fcSMarcin Wojtas bus_release_resources(dev, res_spec, sc->res);
246cb0c98fcSMarcin Wojtas
247cb0c98fcSMarcin Wojtas return (0);
248cb0c98fcSMarcin Wojtas }
249cb0c98fcSMarcin Wojtas
250cb0c98fcSMarcin Wojtas static int
mv_rtc_gettime(device_t dev,struct timespec * ts)251cb0c98fcSMarcin Wojtas mv_rtc_gettime(device_t dev, struct timespec *ts)
252cb0c98fcSMarcin Wojtas {
253cb0c98fcSMarcin Wojtas struct mv_rtc_softc *sc;
254cb0c98fcSMarcin Wojtas uint32_t val, val_check;
255cb0c98fcSMarcin Wojtas
256cb0c98fcSMarcin Wojtas sc = device_get_softc(dev);
257cb0c98fcSMarcin Wojtas
258cb0c98fcSMarcin Wojtas MV_RTC_LOCK(sc);
259cb0c98fcSMarcin Wojtas /*
260d5d4dd38SMichal Meloun * According to HW Errata, if more than one second is detected
261d5d4dd38SMichal Meloun * between two time reads, then at least one of the reads gave
262d5d4dd38SMichal Meloun * an invalid value.
263cb0c98fcSMarcin Wojtas */
264d5d4dd38SMichal Meloun do {
265cb0c98fcSMarcin Wojtas val = mv_rtc_reg_read(sc, RTC_TIME);
266d5d4dd38SMichal Meloun DELAY(100);
267cb0c98fcSMarcin Wojtas val_check = mv_rtc_reg_read(sc, RTC_TIME);
268d5d4dd38SMichal Meloun } while ((val_check - val) > 1);
269cb0c98fcSMarcin Wojtas
270cb0c98fcSMarcin Wojtas MV_RTC_UNLOCK(sc);
271cb0c98fcSMarcin Wojtas
272cb0c98fcSMarcin Wojtas ts->tv_sec = val_check;
273cb0c98fcSMarcin Wojtas /* RTC resolution is 1 sec */
274cb0c98fcSMarcin Wojtas ts->tv_nsec = 0;
275cb0c98fcSMarcin Wojtas
276cb0c98fcSMarcin Wojtas return (0);
277cb0c98fcSMarcin Wojtas }
278cb0c98fcSMarcin Wojtas
279cb0c98fcSMarcin Wojtas static int
mv_rtc_settime(device_t dev,struct timespec * ts)280cb0c98fcSMarcin Wojtas mv_rtc_settime(device_t dev, struct timespec *ts)
281cb0c98fcSMarcin Wojtas {
282cb0c98fcSMarcin Wojtas struct mv_rtc_softc *sc;
283cb0c98fcSMarcin Wojtas
284cb0c98fcSMarcin Wojtas sc = device_get_softc(dev);
285cb0c98fcSMarcin Wojtas
286cb0c98fcSMarcin Wojtas /* RTC resolution is 1 sec */
287cb0c98fcSMarcin Wojtas if (ts->tv_nsec >= HALF_OF_SEC_NS)
288cb0c98fcSMarcin Wojtas ts->tv_sec++;
289cb0c98fcSMarcin Wojtas ts->tv_nsec = 0;
290cb0c98fcSMarcin Wojtas
291cb0c98fcSMarcin Wojtas MV_RTC_LOCK(sc);
292cb0c98fcSMarcin Wojtas
293cb0c98fcSMarcin Wojtas if ((mv_rtc_reg_read(sc, RTC_CLOCK_CORR) & RTC_NOMINAL_TIMING_MASK) !=
294cb0c98fcSMarcin Wojtas RTC_NOMINAL_TIMING) {
295cb0c98fcSMarcin Wojtas /* RTC was not resetted yet */
296cb0c98fcSMarcin Wojtas mv_rtc_reset(dev);
297cb0c98fcSMarcin Wojtas }
298cb0c98fcSMarcin Wojtas
299cb0c98fcSMarcin Wojtas /*
300cb0c98fcSMarcin Wojtas * According to errata FE-3124064, Write to RTC TIME register
301cb0c98fcSMarcin Wojtas * may fail. As a workaround, before writing to RTC TIME register,
302cb0c98fcSMarcin Wojtas * issue a dummy write of 0x0 twice to RTC Status register.
303cb0c98fcSMarcin Wojtas */
304cb0c98fcSMarcin Wojtas mv_rtc_reg_write(sc, RTC_STATUS, 0x0);
305cb0c98fcSMarcin Wojtas mv_rtc_reg_write(sc, RTC_STATUS, 0x0);
306cb0c98fcSMarcin Wojtas mv_rtc_reg_write(sc, RTC_TIME, ts->tv_sec);
307cb0c98fcSMarcin Wojtas MV_RTC_UNLOCK(sc);
308cb0c98fcSMarcin Wojtas
309cb0c98fcSMarcin Wojtas return (0);
310cb0c98fcSMarcin Wojtas }
311cb0c98fcSMarcin Wojtas
312cb0c98fcSMarcin Wojtas static inline uint32_t
mv_rtc_reg_read(struct mv_rtc_softc * sc,bus_size_t off)313cb0c98fcSMarcin Wojtas mv_rtc_reg_read(struct mv_rtc_softc *sc, bus_size_t off)
314cb0c98fcSMarcin Wojtas {
315cb0c98fcSMarcin Wojtas
316cb0c98fcSMarcin Wojtas return (bus_read_4(sc->res[RTC_RES], off));
317cb0c98fcSMarcin Wojtas }
318cb0c98fcSMarcin Wojtas
319cb0c98fcSMarcin Wojtas /*
320cb0c98fcSMarcin Wojtas * According to the datasheet, the OS should wait 5us after every
321cb0c98fcSMarcin Wojtas * register write to the RTC hard macro so that the required update
322cb0c98fcSMarcin Wojtas * can occur without holding off the system bus
323cb0c98fcSMarcin Wojtas */
324cb0c98fcSMarcin Wojtas static inline int
mv_rtc_reg_write(struct mv_rtc_softc * sc,bus_size_t off,uint32_t val)325cb0c98fcSMarcin Wojtas mv_rtc_reg_write(struct mv_rtc_softc *sc, bus_size_t off, uint32_t val)
326cb0c98fcSMarcin Wojtas {
327cb0c98fcSMarcin Wojtas
328cb0c98fcSMarcin Wojtas bus_write_4(sc->res[RTC_RES], off, val);
329cb0c98fcSMarcin Wojtas DELAY(5);
330cb0c98fcSMarcin Wojtas
331cb0c98fcSMarcin Wojtas return (0);
332cb0c98fcSMarcin Wojtas }
333cb0c98fcSMarcin Wojtas
334cb0c98fcSMarcin Wojtas static inline void
mv_rtc_configure_bus_a38x(struct mv_rtc_softc * sc)335d5d4dd38SMichal Meloun mv_rtc_configure_bus_a38x(struct mv_rtc_softc *sc)
336cb0c98fcSMarcin Wojtas {
337cb0c98fcSMarcin Wojtas int val;
338cb0c98fcSMarcin Wojtas
339d5d4dd38SMichal Meloun val = bus_read_4(sc->res[RTC_SOC_RES], A38X_RTC_BRIDGE_TIMING_CTRL);
340d5d4dd38SMichal Meloun val &= ~(A38X_RTC_WRCLK_PERIOD_MASK | A38X_RTC_READ_OUTPUT_DELAY_MASK);
341d5d4dd38SMichal Meloun val |= A38X_RTC_WRCLK_PERIOD_MAX << A38X_RTC_WRCLK_PERIOD_SHIFT;
342d5d4dd38SMichal Meloun val |= A38X_RTC_READ_OUTPUT_DELAY_MAX << A38X_RTC_READ_OUTPUT_DELAY_SHIFT;
343d5d4dd38SMichal Meloun bus_write_4(sc->res[RTC_SOC_RES], A38X_RTC_BRIDGE_TIMING_CTRL, val);
344d5d4dd38SMichal Meloun }
345d5d4dd38SMichal Meloun
346d5d4dd38SMichal Meloun static inline void
mv_rtc_configure_bus_a8k(struct mv_rtc_softc * sc)347d5d4dd38SMichal Meloun mv_rtc_configure_bus_a8k(struct mv_rtc_softc *sc)
348d5d4dd38SMichal Meloun {
349d5d4dd38SMichal Meloun int val;
350d5d4dd38SMichal Meloun
351d5d4dd38SMichal Meloun val = bus_read_4(sc->res[RTC_SOC_RES], A8K_RTC_BRIDGE_TIMING_CTRL0);
352d5d4dd38SMichal Meloun val &= ~(A8K_RTC_WRCLK_PERIOD_MASK | A8K_RTC_WRCLK_SETUP_MASK);
353d5d4dd38SMichal Meloun val |= A8K_RTC_WRCLK_PERIOD_VAL << A8K_RTC_WRCLK_PERIOD_SHIFT;
354d5d4dd38SMichal Meloun val |= A8K_RTC_WRCLK_SETUP_VAL << A8K_RTC_WRCLK_SETUP_SHIFT;
355d5d4dd38SMichal Meloun bus_write_4(sc->res[RTC_SOC_RES], A8K_RTC_BRIDGE_TIMING_CTRL1, val);
356d5d4dd38SMichal Meloun
357d5d4dd38SMichal Meloun val = bus_read_4(sc->res[RTC_SOC_RES], A8K_RTC_BRIDGE_TIMING_CTRL0);
358d5d4dd38SMichal Meloun val &= ~A8K_RTC_READ_OUTPUT_DELAY_MASK;
359d5d4dd38SMichal Meloun val |= A8K_RTC_READ_OUTPUT_DELAY_VAL << A8K_RTC_READ_OUTPUT_DELAY_SHIFT;
360d5d4dd38SMichal Meloun bus_write_4(sc->res[RTC_SOC_RES], A8K_RTC_BRIDGE_TIMING_CTRL1, val);
361cb0c98fcSMarcin Wojtas }
362