aml8726_rtc.c revision 303975
1/*-
2 * Copyright 2013-2015 John Wehle <john@feith.com>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27/*
28 * Amlogic aml8726 RTC driver.
29 */
30
31#include <sys/cdefs.h>
32__FBSDID("$FreeBSD: releng/11.0/sys/arm/amlogic/aml8726/aml8726_rtc.c 283181 2015-05-21 07:01:08Z ganbold $");
33
34#include <sys/param.h>
35#include <sys/systm.h>
36#include <sys/bus.h>
37#include <sys/clock.h>
38#include <sys/kernel.h>
39#include <sys/module.h>
40#include <sys/lock.h>
41#include <sys/mutex.h>
42#include <sys/resource.h>
43#include <sys/rman.h>
44
45#include <sys/time.h>
46
47#include <machine/bus.h>
48#include <machine/cpu.h>
49
50#include <dev/fdt/fdt_common.h>
51#include <dev/ofw/ofw_bus.h>
52#include <dev/ofw/ofw_bus_subr.h>
53
54#include <arm/amlogic/aml8726/aml8726_soc.h>
55
56#include "clock_if.h"
57
58/*
59 * The RTC initialization various slightly between the different chips.
60 *
61 *                 aml8726-m1     aml8726-m3     aml8726-m6 (and later)
62 *  init-always    true           true           false
63 *  xo-init        0x0004         0x3c0a         0x180a
64 *  gpo-init       0x100000       0x100000       0x500000
65 */
66
67struct aml8726_rtc_init {
68	boolean_t	always;
69	uint16_t	xo;
70	uint32_t	gpo;
71};
72
73struct aml8726_rtc_softc {
74	device_t		dev;
75	struct aml8726_rtc_init	init;
76	struct resource	*	res[2];
77	struct mtx		mtx;
78};
79
80static struct resource_spec aml8726_rtc_spec[] = {
81	{ SYS_RES_MEMORY,	0,	RF_ACTIVE },
82	{ SYS_RES_IRQ,		0,	RF_ACTIVE },
83	{ -1, 0 }
84};
85
86#define	AML_RTC_LOCK(sc)		mtx_lock_spin(&(sc)->mtx)
87#define	AML_RTC_UNLOCK(sc)		mtx_unlock_spin(&(sc)->mtx)
88#define	AML_RTC_LOCK_INIT(sc)		\
89    mtx_init(&(sc)->mtx, device_get_nameunit((sc)->dev),	\
90    "rtc", MTX_SPIN)
91#define	AML_RTC_LOCK_DESTROY(sc)	mtx_destroy(&(sc)->mtx);
92
93#define	AML_RTC_0_REG			0
94#define	AML_RTC_SCLK			(1 << 0)
95#define	AML_RTC_SDI			(1 << 2)
96#define	AML_RTC_SEN			(1 << 1)
97#define	AML_RTC_AS			(1 << 17)
98#define	AML_RTC_ABSY			(1 << 22)
99#define	AML_RTC_IRQ_DIS			(1 << 12)
100#define	AML_RTC_1_REG			4
101#define	AML_RTC_SDO			(1 << 0)
102#define	AML_RTC_SRDY			(1 << 1)
103#define	AML_RTC_2_REG			8
104#define	AML_RTC_3_REG			12
105#define	AML_RTC_MSR_BUSY		(1 << 20)
106#define	AML_RTC_MSR_CA			(1 << 17)
107#define	AML_RTC_MSR_DURATION_EN		(1 << 16)
108#define	AML_RTC_MSR_DURATION_MASK	0xffff
109#define	AML_RTC_MSR_DURATION_SHIFT	0
110#define	AML_RTC_4_REG			16
111
112#define	AML_RTC_TIME_SREG		0
113#define	AML_RTC_GPO_SREG		1
114#define	AML_RTC_GPO_LEVEL		(1 << 24)
115#define	AML_RTC_GPO_BUSY		(1 << 23)
116#define	AML_RTC_GPO_ACTIVE_HIGH		(1 << 22)
117#define	AML_RTC_GPO_CMD_MASK		(3 << 20)
118#define	AML_RTC_GPO_CMD_SHIFT		20
119#define	AML_RTC_GPO_CMD_NOW		(1 << 20)
120#define	AML_RTC_GPO_CMD_COUNT		(2 << 20)
121#define	AML_RTC_GPO_CMD_PULSE		(3 << 20)
122#define	AML_RTC_GPO_CNT_MASK		0xfffff
123#define	AML_RTC_GPO_CNT_SHIFT		0
124
125#define	CSR_WRITE_4(sc, reg, val)	bus_write_4((sc)->res[0], reg, (val))
126#define	CSR_READ_4(sc, reg)		bus_read_4((sc)->res[0], reg)
127#define	CSR_BARRIER(sc, reg)		bus_barrier((sc)->res[0], reg, 4, \
128    (BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE))
129
130static int
131aml8726_rtc_start_transfer(struct aml8726_rtc_softc *sc)
132{
133	unsigned i;
134
135	/* idle the serial interface */
136	CSR_WRITE_4(sc, AML_RTC_0_REG, (CSR_READ_4(sc, AML_RTC_0_REG) &
137	    ~(AML_RTC_SCLK | AML_RTC_SEN | AML_RTC_SDI)));
138
139	CSR_BARRIER(sc, AML_RTC_0_REG);
140
141	/* see if it is ready for a new cycle */
142	for (i = 40; i; i--) {
143		DELAY(5);
144		if ( (CSR_READ_4(sc, AML_RTC_1_REG) & AML_RTC_SRDY) )
145			break;
146	}
147
148	if (i == 0)
149		return (EIO);
150
151	/* start the cycle */
152	CSR_WRITE_4(sc, AML_RTC_0_REG, (CSR_READ_4(sc, AML_RTC_0_REG) |
153	    AML_RTC_SEN));
154
155	return (0);
156}
157
158static inline void
159aml8726_rtc_sclk_pulse(struct aml8726_rtc_softc *sc)
160{
161
162	DELAY(5);
163
164	CSR_WRITE_4(sc, AML_RTC_0_REG, (CSR_READ_4(sc, AML_RTC_0_REG) |
165	    AML_RTC_SCLK));
166
167	CSR_BARRIER(sc, AML_RTC_0_REG);
168
169	DELAY(5);
170
171	CSR_WRITE_4(sc, AML_RTC_0_REG, (CSR_READ_4(sc, AML_RTC_0_REG) &
172	    ~AML_RTC_SCLK));
173
174	CSR_BARRIER(sc, AML_RTC_0_REG);
175}
176
177static inline void
178aml8726_rtc_send_bit(struct aml8726_rtc_softc *sc, unsigned bit)
179{
180
181	if (bit) {
182		CSR_WRITE_4(sc, AML_RTC_0_REG, (CSR_READ_4(sc, AML_RTC_0_REG) |
183		    AML_RTC_SDI));
184	} else {
185		CSR_WRITE_4(sc, AML_RTC_0_REG, (CSR_READ_4(sc, AML_RTC_0_REG) &
186		    ~AML_RTC_SDI));
187	}
188
189	aml8726_rtc_sclk_pulse(sc);
190}
191
192static inline void
193aml8726_rtc_send_addr(struct aml8726_rtc_softc *sc, u_char addr)
194{
195	unsigned mask;
196
197	for (mask = 1 << 3; mask; mask >>= 1) {
198		if (mask == 1) {
199			/* final bit indicates read / write mode */
200			CSR_WRITE_4(sc, AML_RTC_0_REG,
201			    (CSR_READ_4(sc, AML_RTC_0_REG) & ~AML_RTC_SEN));
202		}
203		aml8726_rtc_send_bit(sc, (addr & mask));
204	}
205}
206
207static inline void
208aml8726_rtc_send_data(struct aml8726_rtc_softc *sc, uint32_t data)
209{
210	unsigned mask;
211
212	for (mask = 1U << 31; mask; mask >>= 1)
213		aml8726_rtc_send_bit(sc, (data & mask));
214}
215
216static inline void
217aml8726_rtc_recv_data(struct aml8726_rtc_softc *sc, uint32_t *dp)
218{
219	uint32_t data;
220	unsigned i;
221
222	data = 0;
223
224	for (i = 0; i < 32; i++) {
225		aml8726_rtc_sclk_pulse(sc);
226		data <<= 1;
227		data |= (CSR_READ_4(sc, AML_RTC_1_REG) & AML_RTC_SDO) ? 1 : 0;
228	}
229
230	*dp = data;
231}
232
233static int
234aml8726_rtc_sreg_read(struct aml8726_rtc_softc *sc, u_char sreg, uint32_t *val)
235{
236	u_char addr;
237	int error;
238
239	/* read is indicated by lsb = 0 */
240	addr = (sreg << 1) | 0;
241
242	error = aml8726_rtc_start_transfer(sc);
243
244	if (error)
245		return (error);
246
247	aml8726_rtc_send_addr(sc, addr);
248	aml8726_rtc_recv_data(sc, val);
249
250	return (0);
251}
252
253static int
254aml8726_rtc_sreg_write(struct aml8726_rtc_softc *sc, u_char sreg, uint32_t val)
255{
256	u_char addr;
257	int error;
258
259	/* write is indicated by lsb = 1 */
260	addr = (sreg << 1) | 1;
261
262	error = aml8726_rtc_start_transfer(sc);
263
264	if (error)
265		return (error);
266
267	aml8726_rtc_send_data(sc, val);
268	aml8726_rtc_send_addr(sc, addr);
269
270	return (0);
271}
272
273static int
274aml8726_rtc_initialize(struct aml8726_rtc_softc *sc)
275{
276	int error;
277	unsigned i;
278
279	/* idle the serial interface */
280	CSR_WRITE_4(sc, AML_RTC_0_REG, (CSR_READ_4(sc, AML_RTC_0_REG) &
281	    ~(AML_RTC_SCLK | AML_RTC_SEN | AML_RTC_SDI)));
282
283	CSR_BARRIER(sc, AML_RTC_0_REG);
284
285	/* see if it is ready for a new cycle */
286	for (i = 40; i; i--) {
287		DELAY(5);
288		if ( (CSR_READ_4(sc, AML_RTC_1_REG) & AML_RTC_SRDY) )
289			break;
290	}
291
292	if (sc->init.always == TRUE || (CSR_READ_4(sc, AML_RTC_1_REG) &
293	    AML_RTC_SRDY) == 0) {
294
295		/*
296		 * The RTC has a 16 bit initialization register.  The upper
297		 * bits can be written directly.  The lower bits are written
298		 * through a shift register.
299		 */
300
301		CSR_WRITE_4(sc, AML_RTC_4_REG, ((sc->init.xo >> 8) & 0xff));
302
303		CSR_WRITE_4(sc, AML_RTC_0_REG,
304		    ((CSR_READ_4(sc, AML_RTC_0_REG) & 0xffffff) |
305		    ((uint32_t)(sc->init.xo & 0xff) << 24) | AML_RTC_AS |
306		    AML_RTC_IRQ_DIS));
307
308		while ((CSR_READ_4(sc, AML_RTC_0_REG) & AML_RTC_ABSY) != 0)
309			cpu_spinwait();
310
311		DELAY(2);
312
313		error = aml8726_rtc_sreg_write(sc, AML_RTC_GPO_SREG,
314		    sc->init.gpo);
315
316		if (error)
317			return (error);
318	}
319
320	return (0);
321}
322
323static int
324aml8726_rtc_check_xo(struct aml8726_rtc_softc *sc)
325{
326	uint32_t now, previous;
327	int i;
328
329	/*
330	 * The RTC is driven by a 32.768khz clock meaning it's period
331	 * is roughly 30.5 us.  Check that it's working (implying the
332	 * RTC could contain a valid value) by enabling count always
333	 * and seeing if the value changes after 200 us (per RTC User
334	 * Guide ... presumably the extra time is to cover XO startup).
335	 */
336
337	CSR_WRITE_4(sc, AML_RTC_3_REG, (CSR_READ_4(sc, AML_RTC_3_REG) |
338	    AML_RTC_MSR_CA));
339
340	previous = CSR_READ_4(sc, AML_RTC_2_REG);
341
342	for (i = 0; i < 4; i++) {
343		DELAY(50);
344		now = CSR_READ_4(sc, AML_RTC_2_REG);
345		if (now != previous)
346			break;
347	}
348
349	CSR_WRITE_4(sc, AML_RTC_3_REG, (CSR_READ_4(sc, AML_RTC_3_REG) &
350	    ~AML_RTC_MSR_CA));
351
352	if (now == previous)
353		return (EINVAL);
354
355	return (0);
356}
357
358static int
359aml8726_rtc_probe(device_t dev)
360{
361
362	if (!ofw_bus_status_okay(dev))
363		return (ENXIO);
364
365	if (!ofw_bus_is_compatible(dev, "amlogic,aml8726-rtc"))
366		return (ENXIO);
367
368	device_set_desc(dev, "Amlogic aml8726 RTC");
369
370	return (BUS_PROBE_DEFAULT);
371}
372
373static int
374aml8726_rtc_attach(device_t dev)
375{
376	struct aml8726_rtc_softc *sc = device_get_softc(dev);
377
378	sc->dev = dev;
379
380	switch (aml8726_soc_hw_rev) {
381	case AML_SOC_HW_REV_M3:
382		sc->init.always = true;
383		sc->init.xo = 0x3c0a;
384		sc->init.gpo = 0x100000;
385		break;
386	case AML_SOC_HW_REV_M6:
387	case AML_SOC_HW_REV_M8:
388	case AML_SOC_HW_REV_M8B:
389		sc->init.always = false;
390		sc->init.xo = 0x180a;
391		sc->init.gpo = 0x500000;
392		break;
393	default:
394		device_printf(dev, "unsupported SoC\n");
395		return (ENXIO);
396		/* NOTREACHED */
397	}
398
399	if (bus_alloc_resources(dev, aml8726_rtc_spec, sc->res)) {
400		device_printf(dev, "can not allocate resources for device\n");
401		return (ENXIO);
402	}
403
404	aml8726_rtc_initialize(sc);
405
406	if (aml8726_rtc_check_xo(sc) != 0) {
407		device_printf(dev, "crystal oscillator check failed\n");
408
409		bus_release_resources(dev, aml8726_rtc_spec, sc->res);
410
411		return (ENXIO);
412	}
413
414	AML_RTC_LOCK_INIT(sc);
415
416	clock_register(dev, 1000000);
417
418	return (0);
419}
420
421static int
422aml8726_rtc_detach(device_t dev)
423{
424
425	return (EBUSY);
426}
427
428static int
429aml8726_rtc_gettime(device_t dev, struct timespec *ts)
430{
431	struct aml8726_rtc_softc *sc = device_get_softc(dev);
432	uint32_t sec;
433	int error;
434
435	AML_RTC_LOCK(sc);
436
437	error = aml8726_rtc_sreg_read(sc, AML_RTC_TIME_SREG, &sec);
438
439	AML_RTC_UNLOCK(sc);
440
441	ts->tv_sec = sec;
442	ts->tv_nsec = 0;
443
444	return (error);
445}
446
447static int
448aml8726_rtc_settime(device_t dev, struct timespec *ts)
449{
450	struct aml8726_rtc_softc *sc = device_get_softc(dev);
451	uint32_t sec;
452	int error;
453
454	sec = ts->tv_sec;
455
456	/* Accuracy is only one second. */
457	if (ts->tv_nsec >= 500000000)
458		sec++;
459
460	AML_RTC_LOCK(sc);
461
462	error = aml8726_rtc_sreg_write(sc, AML_RTC_TIME_SREG, sec);
463
464	AML_RTC_UNLOCK(sc);
465
466	return (error);
467}
468
469static device_method_t aml8726_rtc_methods[] = {
470	/* Device interface */
471	DEVMETHOD(device_probe,		aml8726_rtc_probe),
472	DEVMETHOD(device_attach,	aml8726_rtc_attach),
473	DEVMETHOD(device_detach,	aml8726_rtc_detach),
474
475	/* Clock interface */
476	DEVMETHOD(clock_gettime,	aml8726_rtc_gettime),
477	DEVMETHOD(clock_settime,	aml8726_rtc_settime),
478
479	DEVMETHOD_END
480};
481
482static driver_t aml8726_rtc_driver = {
483	"rtc",
484	aml8726_rtc_methods,
485	sizeof(struct aml8726_rtc_softc),
486};
487
488static devclass_t aml8726_rtc_devclass;
489
490DRIVER_MODULE(rtc, simplebus, aml8726_rtc_driver, aml8726_rtc_devclass, 0, 0);
491