xref: /optee_os/core/drivers/atmel_rtc.c (revision 35abff2f80ed3734a59f7ccf67efdb7d0a36c1bc)
1*35abff2fSClément Léger // SPDX-License-Identifier: BSD-2-Clause
2*35abff2fSClément Léger /*
3*35abff2fSClément Léger  * Copyright 2022 Microchip
4*35abff2fSClément Léger  *
5*35abff2fSClément Léger  * Driver for AT91 RTC
6*35abff2fSClément Léger  */
7*35abff2fSClément Léger 
8*35abff2fSClément Léger #include <assert.h>
9*35abff2fSClément Léger #include <drivers/rtc.h>
10*35abff2fSClément Léger #include <io.h>
11*35abff2fSClément Léger #include <kernel/dt.h>
12*35abff2fSClément Léger #include <matrix.h>
13*35abff2fSClément Léger #include <mm/core_memprot.h>
14*35abff2fSClément Léger #include <sama5d2.h>
15*35abff2fSClément Léger 
16*35abff2fSClément Léger #define RTC_VAL(reg, val)	(((val) >> RTC_## reg ## _SHIFT) & \
17*35abff2fSClément Léger 				 RTC_## reg ##_MASK)
18*35abff2fSClément Léger 
19*35abff2fSClément Léger #define RTC_SET_VAL(reg, val)	SHIFT_U32((val) & RTC_## reg ##_MASK, \
20*35abff2fSClément Léger 					  RTC_## reg ## _SHIFT)
21*35abff2fSClément Léger 
22*35abff2fSClément Léger #define RTC_CR			0x0
23*35abff2fSClément Léger #define RTC_CR_UPDCAL		BIT(1)
24*35abff2fSClément Léger #define RTC_CR_UPDTIM		BIT(0)
25*35abff2fSClément Léger 
26*35abff2fSClément Léger #define RTC_MR			0x4
27*35abff2fSClément Léger #define RTC_MR_HR_MODE		BIT(0)
28*35abff2fSClément Léger #define RTC_MR_PERSIAN		BIT(1)
29*35abff2fSClément Léger #define RTC_MR_UTC		BIT(2)
30*35abff2fSClément Léger #define RTC_MR_NEGPPM		BIT(4)
31*35abff2fSClément Léger #define RTC_MR_CORR_SHIFT	8
32*35abff2fSClément Léger #define RTC_MR_CORR_MASK	GENMASK_32(6, 0)
33*35abff2fSClément Léger #define RTC_MR_CORR(val)	RTC_VAL(val, MR_CORR)
34*35abff2fSClément Léger #define RTC_MR_HIGHPPM		BIT(15)
35*35abff2fSClément Léger 
36*35abff2fSClément Léger #define RTC_TIMR		0x8
37*35abff2fSClément Léger #define RTC_CALR		0xC
38*35abff2fSClément Léger 
39*35abff2fSClément Léger #define RTC_SR			0x18
40*35abff2fSClément Léger #define RTC_SR_ACKUPD		BIT(0)
41*35abff2fSClément Léger #define RTC_SR_SEC		BIT(2)
42*35abff2fSClément Léger 
43*35abff2fSClément Léger #define RTC_SCCR		0x1C
44*35abff2fSClément Léger #define RTC_SCCR_ACKCLR		BIT(0)
45*35abff2fSClément Léger #define RTC_SCCR_SECCLR		BIT(2)
46*35abff2fSClément Léger 
47*35abff2fSClément Léger #define RTC_VER			0x2C
48*35abff2fSClément Léger #define RTC_VER_NVTIM		BIT(0)
49*35abff2fSClément Léger #define RTC_VER_NVCAL		BIT(1)
50*35abff2fSClément Léger 
51*35abff2fSClément Léger #define RTC_TSTR0		0xB0
52*35abff2fSClément Léger #define RTC_TSDR0		0xB4
53*35abff2fSClément Léger 
54*35abff2fSClément Léger #define RTC_TSSR0		0xB8
55*35abff2fSClément Léger #define RTC_TSSR_DET_OFFSET	16
56*35abff2fSClément Léger #define RTC_TSSR_DET_COUNT	8
57*35abff2fSClément Léger #define RTC_TSSR_TST_PIN	BIT(2)
58*35abff2fSClément Léger #define RTC_TSSR_JTAG		BIT(3)
59*35abff2fSClément Léger 
60*35abff2fSClément Léger /* Layout of Time registers */
61*35abff2fSClément Léger #define RTC_TIME_BACKUP	BIT(31)
62*35abff2fSClément Léger #define RTC_TIME_HOUR_SHIFT	16
63*35abff2fSClément Léger #define RTC_TIME_HOUR_MASK	GENMASK_32(5, 0)
64*35abff2fSClément Léger #define RTC_TIME_MIN_SHIFT	8
65*35abff2fSClément Léger #define RTC_TIME_MIN_MASK	GENMASK_32(6, 0)
66*35abff2fSClément Léger #define RTC_TIME_SEC_SHIFT	0
67*35abff2fSClément Léger #define RTC_TIME_SEC_MASK	GENMASK_32(6, 0)
68*35abff2fSClément Léger 
69*35abff2fSClément Léger /* Layout of Calendar registers */
70*35abff2fSClément Léger #define RTC_CAL_DATE_SHIFT	24
71*35abff2fSClément Léger #define RTC_CAL_DATE_MASK	GENMASK_32(5, 0)
72*35abff2fSClément Léger #define RTC_CAL_DAY_SHIFT	21
73*35abff2fSClément Léger #define RTC_CAL_DAY_MASK	GENMASK_32(2, 0)
74*35abff2fSClément Léger #define RTC_CAL_MONTH_SHIFT	16
75*35abff2fSClément Léger #define RTC_CAL_MONTH_MASK	GENMASK_32(4, 0)
76*35abff2fSClément Léger #define RTC_CAL_YEAR_SHIFT	8
77*35abff2fSClément Léger #define RTC_CAL_YEAR_MASK	GENMASK_32(7, 0)
78*35abff2fSClément Léger #define RTC_CAL_CENT_SHIFT	0
79*35abff2fSClément Léger #define RTC_CAL_CENT_MASK	GENMASK_32(6, 0)
80*35abff2fSClément Léger 
81*35abff2fSClément Léger #define ATMEL_RTC_CORR_DIVIDEND		3906000
82*35abff2fSClément Léger #define ATMEL_RTC_CORR_LOW_RATIO	20
83*35abff2fSClément Léger 
84*35abff2fSClément Léger static vaddr_t rtc_base;
85*35abff2fSClément Léger 
86*35abff2fSClément Léger static uint8_t bcd_decode(uint8_t dcb_val)
87*35abff2fSClément Léger {
88*35abff2fSClément Léger 	return (dcb_val & 0xF) + (dcb_val >> 4) * 10;
89*35abff2fSClément Léger }
90*35abff2fSClément Léger 
91*35abff2fSClément Léger static uint8_t bcd_encode(uint32_t value)
92*35abff2fSClément Léger {
93*35abff2fSClément Léger 	return ((value / 10) << 4) + value % 10;
94*35abff2fSClément Léger }
95*35abff2fSClément Léger 
96*35abff2fSClément Léger static uint32_t atmel_rtc_read(unsigned int offset)
97*35abff2fSClément Léger {
98*35abff2fSClément Léger 	return io_read32(rtc_base + offset);
99*35abff2fSClément Léger }
100*35abff2fSClément Léger 
101*35abff2fSClément Léger static void atmel_rtc_write(unsigned int offset, uint32_t val)
102*35abff2fSClément Léger {
103*35abff2fSClément Léger 	return io_write32(rtc_base + offset, val);
104*35abff2fSClément Léger }
105*35abff2fSClément Léger 
106*35abff2fSClément Léger static void atmel_decode_date(unsigned int time_reg, unsigned int cal_reg,
107*35abff2fSClément Léger 			      struct optee_rtc_time *tm)
108*35abff2fSClément Léger {
109*35abff2fSClément Léger 	uint32_t time = 0;
110*35abff2fSClément Léger 	uint32_t date = 0;
111*35abff2fSClément Léger 
112*35abff2fSClément Léger 	/* Must read twice in case it changes */
113*35abff2fSClément Léger 	do {
114*35abff2fSClément Léger 		time = atmel_rtc_read(time_reg);
115*35abff2fSClément Léger 		date = atmel_rtc_read(cal_reg);
116*35abff2fSClément Léger 	} while ((time != atmel_rtc_read(time_reg)) ||
117*35abff2fSClément Léger 		 (date != atmel_rtc_read(cal_reg)));
118*35abff2fSClément Léger 
119*35abff2fSClément Léger 	tm->tm_wday = bcd_decode(RTC_VAL(CAL_DAY, date)) - 1;
120*35abff2fSClément Léger 	tm->tm_mday = bcd_decode(RTC_VAL(CAL_DATE, date));
121*35abff2fSClément Léger 	tm->tm_mon = bcd_decode(RTC_VAL(CAL_MONTH, date)) - 1;
122*35abff2fSClément Léger 	tm->tm_year = bcd_decode(RTC_VAL(CAL_CENT, date)) * 100;
123*35abff2fSClément Léger 	tm->tm_year += bcd_decode(RTC_VAL(CAL_YEAR, date));
124*35abff2fSClément Léger 
125*35abff2fSClément Léger 	tm->tm_hour = bcd_decode(RTC_VAL(TIME_HOUR, time));
126*35abff2fSClément Léger 	tm->tm_min = bcd_decode(RTC_VAL(TIME_MIN, time));
127*35abff2fSClément Léger 	tm->tm_sec = bcd_decode(RTC_VAL(TIME_SEC, time));
128*35abff2fSClément Léger }
129*35abff2fSClément Léger 
130*35abff2fSClément Léger static TEE_Result atmel_rtc_get_time(struct rtc *rtc __unused,
131*35abff2fSClément Léger 				     struct optee_rtc_time *tm)
132*35abff2fSClément Léger {
133*35abff2fSClément Léger 	atmel_decode_date(RTC_TIMR, RTC_CALR, tm);
134*35abff2fSClément Léger 
135*35abff2fSClément Léger 	return TEE_SUCCESS;
136*35abff2fSClément Léger }
137*35abff2fSClément Léger 
138*35abff2fSClément Léger static TEE_Result atmel_rtc_set_time(struct rtc *rtc __unused,
139*35abff2fSClément Léger 				     struct optee_rtc_time *tm)
140*35abff2fSClément Léger {
141*35abff2fSClément Léger 	uint32_t cr = 0;
142*35abff2fSClément Léger 	uint32_t sr = 0;
143*35abff2fSClément Léger 	uint32_t err = 0;
144*35abff2fSClément Léger 
145*35abff2fSClément Léger 	/* First, wait for UPDCAL/UPDTIM to be 0 */
146*35abff2fSClément Léger 	do {
147*35abff2fSClément Léger 		cr = atmel_rtc_read(RTC_CR);
148*35abff2fSClément Léger 	} while (cr & (RTC_CR_UPDCAL | RTC_CR_UPDTIM));
149*35abff2fSClément Léger 
150*35abff2fSClément Léger 	/* Stop Time/Calendar for update */
151*35abff2fSClément Léger 	atmel_rtc_write(RTC_CR, cr | RTC_CR_UPDCAL | RTC_CR_UPDTIM);
152*35abff2fSClément Léger 
153*35abff2fSClément Léger 	do {
154*35abff2fSClément Léger 		sr = atmel_rtc_read(RTC_SR);
155*35abff2fSClément Léger 	} while (!(sr & RTC_SR_ACKUPD));
156*35abff2fSClément Léger 
157*35abff2fSClément Léger 	atmel_rtc_write(RTC_SCCR, RTC_SCCR_ACKCLR);
158*35abff2fSClément Léger 
159*35abff2fSClément Léger 	atmel_rtc_write(RTC_TIMR,
160*35abff2fSClément Léger 			RTC_SET_VAL(TIME_SEC, bcd_encode(tm->tm_sec)) |
161*35abff2fSClément Léger 			RTC_SET_VAL(TIME_MIN, bcd_encode(tm->tm_min)) |
162*35abff2fSClément Léger 			RTC_SET_VAL(TIME_HOUR, bcd_encode(tm->tm_hour)));
163*35abff2fSClément Léger 
164*35abff2fSClément Léger 	atmel_rtc_write(RTC_CALR,
165*35abff2fSClément Léger 			RTC_SET_VAL(CAL_CENT,
166*35abff2fSClément Léger 				    bcd_encode(tm->tm_year / 100)) |
167*35abff2fSClément Léger 			RTC_SET_VAL(CAL_YEAR, bcd_encode(tm->tm_year % 100)) |
168*35abff2fSClément Léger 			RTC_SET_VAL(CAL_MONTH, bcd_encode(tm->tm_mon + 1)) |
169*35abff2fSClément Léger 			RTC_SET_VAL(CAL_DAY, bcd_encode(tm->tm_wday + 1)) |
170*35abff2fSClément Léger 			RTC_SET_VAL(CAL_DATE, bcd_encode(tm->tm_mday)));
171*35abff2fSClément Léger 
172*35abff2fSClément Léger 	err = atmel_rtc_read(RTC_VER);
173*35abff2fSClément Léger 	if (err) {
174*35abff2fSClément Léger 		if (err & RTC_VER_NVTIM)
175*35abff2fSClément Léger 			DMSG("Invalid time programmed");
176*35abff2fSClément Léger 		if (err & RTC_VER_NVCAL)
177*35abff2fSClément Léger 			DMSG("Invalid date programmed");
178*35abff2fSClément Léger 
179*35abff2fSClément Léger 		return TEE_ERROR_BAD_PARAMETERS;
180*35abff2fSClément Léger 	}
181*35abff2fSClément Léger 
182*35abff2fSClément Léger 	/* Restart Time/Calendar */
183*35abff2fSClément Léger 	atmel_rtc_write(RTC_CR, cr);
184*35abff2fSClément Léger 
185*35abff2fSClément Léger 	return TEE_SUCCESS;
186*35abff2fSClément Léger }
187*35abff2fSClément Léger 
188*35abff2fSClément Léger static TEE_Result atmel_rtc_get_offset(struct rtc *rtc __unused, long *offset)
189*35abff2fSClément Léger {
190*35abff2fSClément Léger 	uint32_t mr = atmel_rtc_read(RTC_MR);
191*35abff2fSClément Léger 	long val = RTC_VAL(MR_CORR, mr);
192*35abff2fSClément Léger 
193*35abff2fSClément Léger 	if (!val) {
194*35abff2fSClément Léger 		*offset = 0;
195*35abff2fSClément Léger 		return TEE_SUCCESS;
196*35abff2fSClément Léger 	}
197*35abff2fSClément Léger 
198*35abff2fSClément Léger 	val++;
199*35abff2fSClément Léger 
200*35abff2fSClément Léger 	if (!(mr & RTC_MR_HIGHPPM))
201*35abff2fSClément Léger 		val *= ATMEL_RTC_CORR_LOW_RATIO;
202*35abff2fSClément Léger 
203*35abff2fSClément Léger 	val = UDIV_ROUND_NEAREST(ATMEL_RTC_CORR_DIVIDEND, val);
204*35abff2fSClément Léger 
205*35abff2fSClément Léger 	if (!(mr & RTC_MR_NEGPPM))
206*35abff2fSClément Léger 		val = -val;
207*35abff2fSClément Léger 
208*35abff2fSClément Léger 	*offset = val;
209*35abff2fSClément Léger 
210*35abff2fSClément Léger 	return TEE_SUCCESS;
211*35abff2fSClément Léger }
212*35abff2fSClément Léger 
213*35abff2fSClément Léger static TEE_Result atmel_rtc_set_offset(struct rtc *rtc  __unused, long offset)
214*35abff2fSClément Léger {
215*35abff2fSClément Léger 	long corr = 0;
216*35abff2fSClément Léger 	uint32_t mr = 0;
217*35abff2fSClément Léger 
218*35abff2fSClément Léger 	if (offset > ATMEL_RTC_CORR_DIVIDEND / 2)
219*35abff2fSClément Léger 		return TEE_ERROR_BAD_PARAMETERS;
220*35abff2fSClément Léger 	if (offset < -ATMEL_RTC_CORR_DIVIDEND / 2)
221*35abff2fSClément Léger 		return TEE_ERROR_BAD_PARAMETERS;
222*35abff2fSClément Léger 
223*35abff2fSClément Léger 	mr = atmel_rtc_read(RTC_MR);
224*35abff2fSClément Léger 	mr &= ~(RTC_MR_NEGPPM | RTC_MR_CORR_MASK | RTC_MR_HIGHPPM);
225*35abff2fSClément Léger 
226*35abff2fSClément Léger 	if (offset > 0)
227*35abff2fSClément Léger 		mr |= RTC_MR_NEGPPM;
228*35abff2fSClément Léger 	else
229*35abff2fSClément Léger 		offset = -offset;
230*35abff2fSClément Léger 
231*35abff2fSClément Léger 	/* offset less than 764 ppb, disable correction */
232*35abff2fSClément Léger 	if (offset < 764) {
233*35abff2fSClément Léger 		atmel_rtc_write(RTC_MR, mr & ~RTC_MR_NEGPPM);
234*35abff2fSClément Léger 
235*35abff2fSClément Léger 		return TEE_SUCCESS;
236*35abff2fSClément Léger 	}
237*35abff2fSClément Léger 
238*35abff2fSClément Léger 	/*
239*35abff2fSClément Léger 	 * 29208 ppb is the perfect cutoff between low range and high range
240*35abff2fSClément Léger 	 * low range values are never better than high range value after that.
241*35abff2fSClément Léger 	 */
242*35abff2fSClément Léger 	if (offset < 29208) {
243*35abff2fSClément Léger 		corr = UDIV_ROUND_NEAREST(ATMEL_RTC_CORR_DIVIDEND,
244*35abff2fSClément Léger 					  offset * ATMEL_RTC_CORR_LOW_RATIO);
245*35abff2fSClément Léger 	} else {
246*35abff2fSClément Léger 		corr = UDIV_ROUND_NEAREST(ATMEL_RTC_CORR_DIVIDEND, offset);
247*35abff2fSClément Léger 		mr |= RTC_MR_HIGHPPM;
248*35abff2fSClément Léger 	}
249*35abff2fSClément Léger 
250*35abff2fSClément Léger 	corr = MIN(corr, 128);
251*35abff2fSClément Léger 
252*35abff2fSClément Léger 	mr |= ((corr - 1) & RTC_MR_CORR_MASK) << RTC_MR_CORR_SHIFT;
253*35abff2fSClément Léger 
254*35abff2fSClément Léger 	atmel_rtc_write(RTC_MR, mr);
255*35abff2fSClément Léger 
256*35abff2fSClément Léger 	return TEE_SUCCESS;
257*35abff2fSClément Léger }
258*35abff2fSClément Léger 
259*35abff2fSClément Léger static const struct rtc_ops atmel_rtc_ops = {
260*35abff2fSClément Léger 	.get_time = atmel_rtc_get_time,
261*35abff2fSClément Léger 	.set_time = atmel_rtc_set_time,
262*35abff2fSClément Léger 	.get_offset = atmel_rtc_get_offset,
263*35abff2fSClément Léger 	.set_offset = atmel_rtc_set_offset,
264*35abff2fSClément Léger };
265*35abff2fSClément Léger 
266*35abff2fSClément Léger static struct rtc atmel_rtc = {
267*35abff2fSClément Léger 	.ops = &atmel_rtc_ops,
268*35abff2fSClément Léger 	.range_min = { 1900, 1, 1, 0, 0, 0, 0 },
269*35abff2fSClément Léger 	.range_max = { 2099, 12, 31, 23, 59, 59, 0 },
270*35abff2fSClément Léger };
271*35abff2fSClément Léger 
272*35abff2fSClément Léger static TEE_Result atmel_rtc_probe(const void *fdt, int node,
273*35abff2fSClément Léger 				  const void *compat_data __unused)
274*35abff2fSClément Léger {
275*35abff2fSClément Léger 	size_t size = 0;
276*35abff2fSClément Léger 
277*35abff2fSClément Léger 	if (rtc_base)
278*35abff2fSClément Léger 		return TEE_ERROR_GENERIC;
279*35abff2fSClément Léger 
280*35abff2fSClément Léger 	if (_fdt_get_status(fdt, node) != DT_STATUS_OK_SEC)
281*35abff2fSClément Léger 		return TEE_ERROR_BAD_PARAMETERS;
282*35abff2fSClément Léger 
283*35abff2fSClément Léger 	matrix_configure_periph_secure(AT91C_ID_SYS);
284*35abff2fSClément Léger 
285*35abff2fSClément Léger 	if (dt_map_dev(fdt, node, &rtc_base, &size) < 0)
286*35abff2fSClément Léger 		return TEE_ERROR_GENERIC;
287*35abff2fSClément Léger 
288*35abff2fSClément Léger 	atmel_rtc_write(RTC_CR, 0);
289*35abff2fSClément Léger 	/* Enable 24 hours Gregorian mode (this is a clear bits operation !) */
290*35abff2fSClément Léger 	io_clrbits32(rtc_base + RTC_MR, RTC_MR_PERSIAN | RTC_MR_UTC |
291*35abff2fSClément Léger 		     RTC_MR_HR_MODE);
292*35abff2fSClément Léger 
293*35abff2fSClément Léger 	rtc_register(&atmel_rtc);
294*35abff2fSClément Léger 
295*35abff2fSClément Léger 	return TEE_SUCCESS;
296*35abff2fSClément Léger }
297*35abff2fSClément Léger 
298*35abff2fSClément Léger static const struct dt_device_match atmel_rtc_match_table[] = {
299*35abff2fSClément Léger 	{ .compatible = "atmel,sama5d2-rtc" },
300*35abff2fSClément Léger 	{ }
301*35abff2fSClément Léger };
302*35abff2fSClément Léger 
303*35abff2fSClément Léger DEFINE_DT_DRIVER(atmel_rtc_dt_driver) = {
304*35abff2fSClément Léger 	.name = "atmel_rtc",
305*35abff2fSClément Léger 	.type = DT_DRIVER_NOTYPE,
306*35abff2fSClément Léger 	.match_table = atmel_rtc_match_table,
307*35abff2fSClément Léger 	.probe = atmel_rtc_probe,
308*35abff2fSClément Léger };
309*35abff2fSClément Léger 
310