xref: /optee_os/core/drivers/stm32_rtc.c (revision 6aa8d320052102fdf83be925ef5a7013e4dbeacb)
1e419bc7fSGatien Chevallier // SPDX-License-Identifier: BSD-2-Clause
2e419bc7fSGatien Chevallier /*
3d60c61e1SGatien Chevallier  * Copyright (C) 2018-2025, STMicroelectronics
4e419bc7fSGatien Chevallier  */
5e419bc7fSGatien Chevallier #include <assert.h>
6e419bc7fSGatien Chevallier #include <drivers/clk.h>
7e419bc7fSGatien Chevallier #include <drivers/clk_dt.h>
8e419bc7fSGatien Chevallier #include <drivers/rtc.h>
963000677SClément Le Goffic #include <drivers/stm32_rtc.h>
10e419bc7fSGatien Chevallier #include <drivers/stm32_rif.h>
11d60c61e1SGatien Chevallier #include <drivers/stm32_rtc.h>
12e419bc7fSGatien Chevallier #include <io.h>
137818ae9bSClément Le Goffic #include <keep.h>
14e419bc7fSGatien Chevallier #include <kernel/dt.h>
15e419bc7fSGatien Chevallier #include <kernel/dt_driver.h>
167818ae9bSClément Le Goffic #include <kernel/interrupt.h>
177818ae9bSClément Le Goffic #include <kernel/notif.h>
18e419bc7fSGatien Chevallier #include <kernel/panic.h>
1963000677SClément Le Goffic #include <kernel/pm.h>
20d60c61e1SGatien Chevallier #include <kernel/spinlock.h>
21e419bc7fSGatien Chevallier #include <libfdt.h>
22e419bc7fSGatien Chevallier #include <mm/core_memprot.h>
23e419bc7fSGatien Chevallier 
24e419bc7fSGatien Chevallier /*
25e419bc7fSGatien Chevallier  * Registers
26e419bc7fSGatien Chevallier  */
27e419bc7fSGatien Chevallier #define RTC_TR				U(0x00)
28e419bc7fSGatien Chevallier #define RTC_DR				U(0x04)
29e419bc7fSGatien Chevallier #define RTC_SSR				U(0x08)
30e419bc7fSGatien Chevallier #define RTC_ICSR			U(0x0C)
31e419bc7fSGatien Chevallier #define RTC_PRER			U(0x10)
32e419bc7fSGatien Chevallier #define RTC_WUTR			U(0x14)
33e419bc7fSGatien Chevallier #define RTC_CR				U(0x18)
34e419bc7fSGatien Chevallier #define RTC_PRIVCFGR			U(0x1C)
35e419bc7fSGatien Chevallier /* RTC_SMCR is linked to RTC3v1_2 */
36e419bc7fSGatien Chevallier #define RTC_SMCR			U(0x20)
37e419bc7fSGatien Chevallier /* RTC_SECCFGR is linked to RTC3v3_2 and above */
38e419bc7fSGatien Chevallier #define RTC_SECCFGR			U(0x20)
39e419bc7fSGatien Chevallier #define RTC_WPR				U(0x24)
40e419bc7fSGatien Chevallier #define RTC_CALR			U(0x28)
41e419bc7fSGatien Chevallier #define RTC_SHIFTR			U(0x2C)
42e419bc7fSGatien Chevallier #define RTC_TSTR			U(0x30)
43e419bc7fSGatien Chevallier #define RTC_TSDR			U(0x34)
44e419bc7fSGatien Chevallier #define RTC_TSSSR			U(0x38)
45e419bc7fSGatien Chevallier #define RTC_ALRMAR			U(0x40)
46e419bc7fSGatien Chevallier #define RTC_ALRMASSR			U(0x44)
47e419bc7fSGatien Chevallier #define RTC_ALRMBR			U(0x48)
48e419bc7fSGatien Chevallier #define RTC_ALRMBSSR			U(0x4C)
49e419bc7fSGatien Chevallier #define RTC_SR				U(0x50)
50e419bc7fSGatien Chevallier #define RTC_SCR				U(0x5C)
51e419bc7fSGatien Chevallier #define RTC_OR				U(0x60)
52e419bc7fSGatien Chevallier #define RTC_CIDCFGR(x)			(U(0x80) + U(0x4) * (x))
53e419bc7fSGatien Chevallier 
54e419bc7fSGatien Chevallier #define RTC_TR_SU_MASK			GENMASK_32(3, 0)
55e419bc7fSGatien Chevallier #define RTC_TR_ST_MASK			GENMASK_32(6, 4)
56e419bc7fSGatien Chevallier #define RTC_TR_ST_SHIFT			U(4)
57e419bc7fSGatien Chevallier #define RTC_TR_MNU_MASK			GENMASK_32(11, 8)
58e419bc7fSGatien Chevallier #define RTC_TR_MNU_SHIFT		U(8)
59e419bc7fSGatien Chevallier #define RTC_TR_MNT_MASK			GENMASK_32(14, 12)
60e419bc7fSGatien Chevallier #define RTC_TR_MNT_SHIFT		U(12)
61e419bc7fSGatien Chevallier #define RTC_TR_HU_MASK			GENMASK_32(19, 16)
62e419bc7fSGatien Chevallier #define RTC_TR_HU_SHIFT			U(16)
63e419bc7fSGatien Chevallier #define RTC_TR_HT_MASK			GENMASK_32(21, 20)
64e419bc7fSGatien Chevallier #define RTC_TR_HT_SHIFT			U(20)
65e419bc7fSGatien Chevallier #define RTC_TR_PM			BIT(22)
66e419bc7fSGatien Chevallier 
67e419bc7fSGatien Chevallier #define RTC_DR_DU_MASK			GENMASK_32(3, 0)
68e419bc7fSGatien Chevallier #define RTC_DR_DT_MASK			GENMASK_32(5, 4)
69e419bc7fSGatien Chevallier #define RTC_DR_DT_SHIFT			U(4)
70e419bc7fSGatien Chevallier #define RTC_DR_MU_MASK			GENMASK_32(11, 8)
71e419bc7fSGatien Chevallier #define RTC_DR_MU_SHIFT			U(8)
72e419bc7fSGatien Chevallier #define RTC_DR_MT_MASK			BIT(12)
73e419bc7fSGatien Chevallier #define RTC_DR_MT_SHIFT			U(12)
74e419bc7fSGatien Chevallier #define RTC_DR_WDU_MASK			GENMASK_32(15, 13)
75e419bc7fSGatien Chevallier #define RTC_DR_WDU_SHIFT		U(13)
76e419bc7fSGatien Chevallier #define RTC_DR_YU_MASK			GENMASK_32(19, 16)
77e419bc7fSGatien Chevallier #define RTC_DR_YU_SHIFT			U(16)
78e419bc7fSGatien Chevallier #define RTC_DR_YT_MASK			GENMASK_32(23, 20)
79e419bc7fSGatien Chevallier #define RTC_DR_YT_SHIFT			U(20)
80e419bc7fSGatien Chevallier 
81e419bc7fSGatien Chevallier #define RTC_SSR_SS_MASK			GENMASK_32(15, 0)
82e419bc7fSGatien Chevallier 
83e419bc7fSGatien Chevallier #define RTC_ICSR_RSF			BIT(5)
84e419bc7fSGatien Chevallier #define RTC_ICSR_INITF			BIT(6)
85e419bc7fSGatien Chevallier #define RTC_ICSR_INIT			BIT(7)
86e419bc7fSGatien Chevallier 
87446da993SClément Le Goffic #define RTC_PRER_PREDIV_S_SHIFT		U(0)
88e419bc7fSGatien Chevallier #define RTC_PRER_PREDIV_S_MASK		GENMASK_32(14, 0)
89446da993SClément Le Goffic #define RTC_PRER_PREDIV_A_SHIFT		U(16)
90446da993SClément Le Goffic #define RTC_PRER_PREDIV_A_MASK		GENMASK_32(22, 16)
91e419bc7fSGatien Chevallier 
92e419bc7fSGatien Chevallier #define RTC_CR_BYPSHAD			BIT(5)
93e419bc7fSGatien Chevallier #define RTC_CR_BYPSHAD_SHIFT		U(5)
94446da993SClément Le Goffic #define RTC_CR_FMT			BIT(6)
957818ae9bSClément Le Goffic #define RTC_CR_ALRAE			BIT(8)
967818ae9bSClément Le Goffic #define RTC_CR_ALRAIE			BIT(12)
97e419bc7fSGatien Chevallier #define RTC_CR_TAMPTS			BIT(25)
98e419bc7fSGatien Chevallier 
99e419bc7fSGatien Chevallier #define RTC_PRIVCFGR_VALUES		GENMASK_32(3, 0)
100e419bc7fSGatien Chevallier #define RTC_PRIVCFGR_VALUES_TO_SHIFT	GENMASK_32(5, 4)
101e419bc7fSGatien Chevallier #define RTC_PRIVCFGR_SHIFT		U(9)
102e419bc7fSGatien Chevallier #define RTC_PRIVCFGR_MASK		(GENMASK_32(14, 13) | GENMASK_32(3, 0))
103e419bc7fSGatien Chevallier #define RTC_PRIVCFGR_FULL_PRIV		BIT(15)
104e419bc7fSGatien Chevallier 
105e419bc7fSGatien Chevallier #define RTC_SMCR_TS_DPROT		BIT(3)
106e419bc7fSGatien Chevallier 
107e419bc7fSGatien Chevallier #define RTC_SECCFGR_VALUES		GENMASK_32(3, 0)
108e419bc7fSGatien Chevallier #define RTC_SECCFGR_TS_SEC		BIT(3)
109e419bc7fSGatien Chevallier #define RTC_SECCFGR_VALUES_TO_SHIFT	GENMASK_32(5, 4)
110e419bc7fSGatien Chevallier #define RTC_SECCFGR_SHIFT		U(9)
111e419bc7fSGatien Chevallier #define RTC_SECCFGR_MASK		(GENMASK_32(14, 13) | GENMASK_32(3, 0))
112e419bc7fSGatien Chevallier #define RTC_SECCFGR_FULL_SEC		BIT(15)
113e419bc7fSGatien Chevallier 
114e419bc7fSGatien Chevallier #define RTC_WPR_KEY1			U(0xCA)
115e419bc7fSGatien Chevallier #define RTC_WPR_KEY2			U(0x53)
116e419bc7fSGatien Chevallier #define RTC_WPR_KEY_LOCK		U(0xFF)
117e419bc7fSGatien Chevallier 
118e419bc7fSGatien Chevallier #define RTC_TSDR_MU_MASK		GENMASK_32(11, 8)
119e419bc7fSGatien Chevallier #define RTC_TSDR_MU_SHIFT		U(8)
120e419bc7fSGatien Chevallier #define RTC_TSDR_DT_MASK		GENMASK_32(5, 4)
121e419bc7fSGatien Chevallier #define RTC_TSDR_DT_SHIFT		U(4)
122e419bc7fSGatien Chevallier #define RTC_TSDR_DU_MASK		GENMASK_32(3, 0)
123e419bc7fSGatien Chevallier #define RTC_TSDR_DU_SHIFT		U(0)
124e419bc7fSGatien Chevallier 
1257818ae9bSClément Le Goffic #define RTC_ALRMXR_SEC_UNITS_MASK	GENMASK_32(3, 0)
1267818ae9bSClément Le Goffic #define RTC_ALRMXR_SEC_UNITS_SHIFT	U(0)
1277818ae9bSClément Le Goffic #define RTC_ALRMXR_SEC_TENS_MASK	GENMASK_32(6, 4)
1287818ae9bSClément Le Goffic #define RTC_ALRMXR_SEC_TENS_SHIFT	U(4)
1297818ae9bSClément Le Goffic #define RTC_ALRMXR_SEC_MASK		BIT(7)
1307818ae9bSClément Le Goffic #define RTC_ALRMXR_MIN_UNITS_MASK	GENMASK_32(11, 8)
1317818ae9bSClément Le Goffic #define RTC_ALRMXR_MIN_UNITS_SHIFT	U(8)
1327818ae9bSClément Le Goffic #define RTC_ALRMXR_MIN_TENS_MASK	GENMASK_32(14, 12)
1337818ae9bSClément Le Goffic #define RTC_ALRMXR_MIN_TENS_SHIFT	U(12)
1347818ae9bSClément Le Goffic #define RTC_ALRMXR_MIN_MASK		BIT(15)
1357818ae9bSClément Le Goffic #define RTC_ALRMXR_HOUR_UNITS_MASK	GENMASK_32(19, 16)
1367818ae9bSClément Le Goffic #define RTC_ALRMXR_HOUR_UNITS_SHIFT	U(16)
1377818ae9bSClément Le Goffic #define RTC_ALRMXR_HOUR_TENS_MASK	GENMASK_32(21, 20)
1387818ae9bSClément Le Goffic #define RTC_ALRMXR_HOUR_TENS_SHIFT	U(20)
1397818ae9bSClément Le Goffic #define RTC_ALRMXR_PM			BIT(22)
1407818ae9bSClément Le Goffic #define RTC_ALRMXR_HOUR_MASK		BIT(23)
1417818ae9bSClément Le Goffic #define RTC_ALRMXR_DATE_UNITS_MASK	GENMASK_32(27, 24)
1427818ae9bSClément Le Goffic #define RTC_ALRMXR_DATE_UNITS_SHIFT	U(24)
1437818ae9bSClément Le Goffic #define RTC_ALRMXR_DATE_TENS_MASK	GENMASK_32(29, 28)
1447818ae9bSClément Le Goffic #define RTC_ALRMXR_DATE_TENS_SHIFT	U(28)
1457818ae9bSClément Le Goffic 
1467818ae9bSClément Le Goffic #define RTC_SR_ALRAF			BIT(0)
147e419bc7fSGatien Chevallier #define RTC_SR_TSF			BIT(3)
148e419bc7fSGatien Chevallier #define RTC_SR_TSOVF			BIT(4)
149e419bc7fSGatien Chevallier 
1507818ae9bSClément Le Goffic #define RTC_SCR_CALRAF			BIT(0)
151e419bc7fSGatien Chevallier #define RTC_SCR_CTSF			BIT(3)
152e419bc7fSGatien Chevallier #define RTC_SCR_CTSOVF			BIT(4)
153e419bc7fSGatien Chevallier 
154e419bc7fSGatien Chevallier #define RTC_CIDCFGR_SCID_MASK		GENMASK_32(6, 4)
155e419bc7fSGatien Chevallier #define RTC_CIDCFGR_SCID_MASK_SHIFT	U(4)
156e419bc7fSGatien Chevallier #define RTC_CIDCFGR_CONF_MASK		(_CIDCFGR_CFEN |	 \
157e419bc7fSGatien Chevallier 					 RTC_CIDCFGR_SCID_MASK)
158e419bc7fSGatien Chevallier 
159e419bc7fSGatien Chevallier /*
160e419bc7fSGatien Chevallier  * RIF miscellaneous
161e419bc7fSGatien Chevallier  */
162e419bc7fSGatien Chevallier #define RTC_NB_RIF_RESOURCES		U(6)
163e419bc7fSGatien Chevallier 
164e419bc7fSGatien Chevallier #define RTC_RIF_FULL_PRIVILEGED		U(0x3F)
165e419bc7fSGatien Chevallier #define RTC_RIF_FULL_SECURED		U(0x3F)
166e419bc7fSGatien Chevallier 
167e419bc7fSGatien Chevallier #define RTC_NB_MAX_CID_SUPPORTED	U(7)
168e419bc7fSGatien Chevallier 
169e419bc7fSGatien Chevallier /*
170e419bc7fSGatien Chevallier  * Driver miscellaneous
171e419bc7fSGatien Chevallier  */
172e419bc7fSGatien Chevallier #define RTC_RES_TIMESTAMP		U(3)
173e419bc7fSGatien Chevallier #define RTC_RES_CALIBRATION		U(4)
174e419bc7fSGatien Chevallier #define RTC_RES_INITIALIZATION		U(5)
175e419bc7fSGatien Chevallier 
176e419bc7fSGatien Chevallier #define RTC_FLAGS_READ_TWICE		BIT(0)
177e419bc7fSGatien Chevallier 
178e419bc7fSGatien Chevallier #define TIMEOUT_US_RTC_SHADOW		U(10000)
179e419bc7fSGatien Chevallier #define TIMEOUT_US_RTC_GENERIC		U(100000)
180e419bc7fSGatien Chevallier 
181e419bc7fSGatien Chevallier #define YEAR_REF			ULL(2000)
182e419bc7fSGatien Chevallier #define YEAR_MAX			(YEAR_REF + ULL(99))
183e419bc7fSGatien Chevallier 
184e419bc7fSGatien Chevallier struct rtc_compat {
185e419bc7fSGatien Chevallier 	bool has_seccfgr;
186e419bc7fSGatien Chevallier 	bool has_rif_support;
187e419bc7fSGatien Chevallier };
188e419bc7fSGatien Chevallier 
189e419bc7fSGatien Chevallier /*
190e419bc7fSGatien Chevallier  * struct rtc_device - RTC device data
191e419bc7fSGatien Chevallier  * @base: RTC IOMEM base address
192e419bc7fSGatien Chevallier  * @compat: RTC compatible data
193e419bc7fSGatien Chevallier  * @pclk: RTC bus clock
194e419bc7fSGatien Chevallier  * @rtc_ck: RTC kernel clock
195e419bc7fSGatien Chevallier  * @conf_data: RTC RIF configuration data, when supported
196e419bc7fSGatien Chevallier  * @nb_res: Number of protectible RTC resources
197d60c61e1SGatien Chevallier  * @ts_lock: Lock used for time stamping events handling
198e419bc7fSGatien Chevallier  * @flags: RTC driver flags
199e419bc7fSGatien Chevallier  * @is_secured: True if the RTC is fully secured
2007818ae9bSClément Le Goffic  * @itr_chip: Interrupt chip
2017818ae9bSClément Le Goffic  * @itr_num: Interrupt number
2027818ae9bSClément Le Goffic  * @itr_handler: Interrupt handler
2037818ae9bSClément Le Goffic  * @notif_id: Notification ID
2047818ae9bSClément Le Goffic  * @wait_alarm_return_status: Status of the wait alarm thread
20563000677SClément Le Goffic  * @rtc: information for OP-TEE RTC device
206e419bc7fSGatien Chevallier  */
207e419bc7fSGatien Chevallier struct rtc_device {
208e419bc7fSGatien Chevallier 	struct io_pa_va base;
209e419bc7fSGatien Chevallier 	const struct rtc_compat *compat;
210e419bc7fSGatien Chevallier 	struct clk *pclk;
211e419bc7fSGatien Chevallier 	struct clk *rtc_ck;
212e419bc7fSGatien Chevallier 	struct rif_conf_data *conf_data;
213e419bc7fSGatien Chevallier 	unsigned int nb_res;
214d60c61e1SGatien Chevallier 	unsigned int ts_lock;
215e419bc7fSGatien Chevallier 	uint8_t flags;
216e419bc7fSGatien Chevallier 	bool is_secured;
2177818ae9bSClément Le Goffic 	struct itr_chip *itr_chip;
2187818ae9bSClément Le Goffic 	size_t itr_num;
2197818ae9bSClément Le Goffic 	struct itr_handler *itr_handler;
2207818ae9bSClément Le Goffic 	uint32_t notif_id;
2217818ae9bSClément Le Goffic 	enum rtc_wait_alarm_status wait_alarm_return_status;
22263000677SClément Le Goffic 	struct rtc *rtc;
223e419bc7fSGatien Chevallier };
224e419bc7fSGatien Chevallier 
225e419bc7fSGatien Chevallier /* Expect a single RTC instance */
226e419bc7fSGatien Chevallier static struct rtc_device rtc_dev;
227e419bc7fSGatien Chevallier 
get_base(void)228e419bc7fSGatien Chevallier static vaddr_t get_base(void)
229e419bc7fSGatien Chevallier {
230e419bc7fSGatien Chevallier 	assert(rtc_dev.base.pa);
231e419bc7fSGatien Chevallier 
232e419bc7fSGatien Chevallier 	return io_pa_or_va(&rtc_dev.base, 1);
233e419bc7fSGatien Chevallier }
234e419bc7fSGatien Chevallier 
stm32_rtc_write_unprotect(void)235e419bc7fSGatien Chevallier static void stm32_rtc_write_unprotect(void)
236e419bc7fSGatien Chevallier {
237e419bc7fSGatien Chevallier 	vaddr_t rtc_base = get_base();
238e419bc7fSGatien Chevallier 
239e419bc7fSGatien Chevallier 	io_write32(rtc_base + RTC_WPR, RTC_WPR_KEY1);
240e419bc7fSGatien Chevallier 	io_write32(rtc_base + RTC_WPR, RTC_WPR_KEY2);
241e419bc7fSGatien Chevallier }
242e419bc7fSGatien Chevallier 
stm32_rtc_write_protect(void)243e419bc7fSGatien Chevallier static void stm32_rtc_write_protect(void)
244e419bc7fSGatien Chevallier {
245e419bc7fSGatien Chevallier 	vaddr_t rtc_base = get_base();
246e419bc7fSGatien Chevallier 
247e419bc7fSGatien Chevallier 	io_write32(rtc_base + RTC_WPR, RTC_WPR_KEY_LOCK);
248e419bc7fSGatien Chevallier }
249e419bc7fSGatien Chevallier 
stm32_rtc_get_bypshad(void)250e419bc7fSGatien Chevallier static bool stm32_rtc_get_bypshad(void)
251e419bc7fSGatien Chevallier {
252e419bc7fSGatien Chevallier 	return io_read32(get_base() + RTC_CR) & RTC_CR_BYPSHAD;
253e419bc7fSGatien Chevallier }
254e419bc7fSGatien Chevallier 
255e419bc7fSGatien Chevallier /* Get the subsecond value. */
stm32_rtc_get_subsecond(uint32_t ssr)256e419bc7fSGatien Chevallier static uint32_t stm32_rtc_get_subsecond(uint32_t ssr)
257e419bc7fSGatien Chevallier {
258e419bc7fSGatien Chevallier 	uint32_t prediv_s = io_read32(get_base() + RTC_PRER) &
259e419bc7fSGatien Chevallier 			    RTC_PRER_PREDIV_S_MASK;
260e419bc7fSGatien Chevallier 
261e419bc7fSGatien Chevallier 	return prediv_s - ssr;
262e419bc7fSGatien Chevallier }
263e419bc7fSGatien Chevallier 
264e419bc7fSGatien Chevallier /*
265e419bc7fSGatien Chevallier  * Get the subsecond scale.
266e419bc7fSGatien Chevallier  *
267e419bc7fSGatien Chevallier  * Number of subseconds in a second is linked to RTC PREDIV_S value.
268e419bc7fSGatien Chevallier  * The higher PREDIV_S is, the more subsecond is precise.
269e419bc7fSGatien Chevallier  */
stm32_rtc_get_subsecond_scale(void)270e419bc7fSGatien Chevallier static uint32_t stm32_rtc_get_subsecond_scale(void)
271e419bc7fSGatien Chevallier {
272e419bc7fSGatien Chevallier 	return (io_read32(get_base() + RTC_PRER) & RTC_PRER_PREDIV_S_MASK) + 1;
273e419bc7fSGatien Chevallier }
274e419bc7fSGatien Chevallier 
cid1_has_access(unsigned int resource)275e419bc7fSGatien Chevallier static bool cid1_has_access(unsigned int resource)
276e419bc7fSGatien Chevallier {
277e419bc7fSGatien Chevallier 	uint32_t cidcfgr = io_read32(get_base() + RTC_CIDCFGR(resource));
278e419bc7fSGatien Chevallier 
279e419bc7fSGatien Chevallier 	return !(cidcfgr & _CIDCFGR_CFEN) ||
280e419bc7fSGatien Chevallier 	       get_field_u32(cidcfgr, RTC_CIDCFGR_SCID_MASK) == RIF_CID1;
281e419bc7fSGatien Chevallier }
282e419bc7fSGatien Chevallier 
check_rif_config(void)283e419bc7fSGatien Chevallier static TEE_Result check_rif_config(void)
284e419bc7fSGatien Chevallier {
285e419bc7fSGatien Chevallier 	if (!cid1_has_access(RTC_RES_TIMESTAMP) ||
286e419bc7fSGatien Chevallier 	    !cid1_has_access(RTC_RES_CALIBRATION) ||
287e419bc7fSGatien Chevallier 	    !cid1_has_access(RTC_RES_INITIALIZATION))
288e419bc7fSGatien Chevallier 		return TEE_ERROR_ACCESS_DENIED;
289e419bc7fSGatien Chevallier 
290e419bc7fSGatien Chevallier 	return TEE_SUCCESS;
291e419bc7fSGatien Chevallier }
292e419bc7fSGatien Chevallier 
apply_rif_config(bool is_tdcid)293e419bc7fSGatien Chevallier static void apply_rif_config(bool is_tdcid)
294e419bc7fSGatien Chevallier {
295e419bc7fSGatien Chevallier 	vaddr_t base = get_base();
296e419bc7fSGatien Chevallier 	unsigned int shifted_values = 0;
297e419bc7fSGatien Chevallier 	uint32_t seccfgr = 0;
298e419bc7fSGatien Chevallier 	uint32_t privcfgr = 0;
299e419bc7fSGatien Chevallier 	uint32_t access_mask_reg = 0;
300e419bc7fSGatien Chevallier 	unsigned int i = 0;
301e419bc7fSGatien Chevallier 
302e419bc7fSGatien Chevallier 	if (!rtc_dev.conf_data)
303e419bc7fSGatien Chevallier 		return;
304e419bc7fSGatien Chevallier 
305e419bc7fSGatien Chevallier 	/* Build access mask for RTC_SECCFGR and RTC_PRIVCFGR */
306e419bc7fSGatien Chevallier 	for (i = 0; i < RTC_NB_RIF_RESOURCES; i++) {
307e419bc7fSGatien Chevallier 		if (rtc_dev.conf_data->access_mask[0] & BIT(i)) {
308e419bc7fSGatien Chevallier 			if (i <= RTC_RES_TIMESTAMP)
309e419bc7fSGatien Chevallier 				access_mask_reg |= BIT(i);
310e419bc7fSGatien Chevallier 			else
311e419bc7fSGatien Chevallier 				access_mask_reg |= BIT(i) << RTC_SECCFGR_SHIFT;
312e419bc7fSGatien Chevallier 		}
313e419bc7fSGatien Chevallier 	}
314e419bc7fSGatien Chevallier 
315e419bc7fSGatien Chevallier 	for (i = 0; i < RTC_NB_RIF_RESOURCES; i++) {
316e419bc7fSGatien Chevallier 		if (!(BIT(i) & rtc_dev.conf_data->access_mask[0]))
317e419bc7fSGatien Chevallier 			continue;
318e419bc7fSGatien Chevallier 
319e419bc7fSGatien Chevallier 		/*
320e419bc7fSGatien Chevallier 		 * When TDCID, OP-TEE should be the one to set the CID filtering
321e419bc7fSGatien Chevallier 		 * configuration. Clearing previous configuration prevents
322e419bc7fSGatien Chevallier 		 * undesired events during the only legitimate configuration.
323e419bc7fSGatien Chevallier 		 */
324e419bc7fSGatien Chevallier 		if (is_tdcid)
325e419bc7fSGatien Chevallier 			io_clrbits32(base + RTC_CIDCFGR(i),
326e419bc7fSGatien Chevallier 				     RTC_CIDCFGR_CONF_MASK);
327e419bc7fSGatien Chevallier 	}
328e419bc7fSGatien Chevallier 
329e419bc7fSGatien Chevallier 	/* Security RIF configuration */
330e419bc7fSGatien Chevallier 	seccfgr = rtc_dev.conf_data->sec_conf[0];
331e419bc7fSGatien Chevallier 
332e419bc7fSGatien Chevallier 	/* Check if all resources must be secured */
333e419bc7fSGatien Chevallier 	if (seccfgr == RTC_RIF_FULL_SECURED) {
334e419bc7fSGatien Chevallier 		io_setbits32(base + RTC_SECCFGR, RTC_SECCFGR_FULL_SEC);
335e419bc7fSGatien Chevallier 
336e419bc7fSGatien Chevallier 		if (!(io_read32(base + RTC_SECCFGR) & RTC_SECCFGR_FULL_SEC))
337e419bc7fSGatien Chevallier 			panic("Bad RTC seccfgr configuration");
338e419bc7fSGatien Chevallier 	}
339e419bc7fSGatien Chevallier 
340e419bc7fSGatien Chevallier 	/* Shift some values to align with the register */
341e419bc7fSGatien Chevallier 	shifted_values = SHIFT_U32(seccfgr & RTC_SECCFGR_VALUES_TO_SHIFT,
342e419bc7fSGatien Chevallier 				   RTC_SECCFGR_SHIFT);
343e419bc7fSGatien Chevallier 	seccfgr = (seccfgr & RTC_SECCFGR_VALUES) + shifted_values;
344e419bc7fSGatien Chevallier 
345e419bc7fSGatien Chevallier 	io_clrsetbits32(base + RTC_SECCFGR,
346e419bc7fSGatien Chevallier 			RTC_SECCFGR_MASK & access_mask_reg, seccfgr);
347e419bc7fSGatien Chevallier 
348e419bc7fSGatien Chevallier 	/* Privilege RIF configuration */
349e419bc7fSGatien Chevallier 	privcfgr = rtc_dev.conf_data->priv_conf[0];
350e419bc7fSGatien Chevallier 
351e419bc7fSGatien Chevallier 	/* Check if all resources must be privileged */
352e419bc7fSGatien Chevallier 	if (privcfgr == RTC_RIF_FULL_PRIVILEGED) {
353e419bc7fSGatien Chevallier 		io_setbits32(base + RTC_PRIVCFGR, RTC_PRIVCFGR_FULL_PRIV);
354e419bc7fSGatien Chevallier 
355e419bc7fSGatien Chevallier 		if (!(io_read32(base + RTC_PRIVCFGR) & RTC_PRIVCFGR_FULL_PRIV))
356e419bc7fSGatien Chevallier 			panic("Bad RTC privcfgr configuration");
357e419bc7fSGatien Chevallier 	}
358e419bc7fSGatien Chevallier 
359e419bc7fSGatien Chevallier 	/* Shift some values to align with the register */
360e419bc7fSGatien Chevallier 	shifted_values = SHIFT_U32(privcfgr & RTC_PRIVCFGR_VALUES_TO_SHIFT,
361e419bc7fSGatien Chevallier 				   RTC_PRIVCFGR_SHIFT);
362e419bc7fSGatien Chevallier 	privcfgr = (privcfgr & RTC_PRIVCFGR_VALUES) + shifted_values;
363e419bc7fSGatien Chevallier 
364e419bc7fSGatien Chevallier 	io_clrsetbits32(base + RTC_PRIVCFGR,
365e419bc7fSGatien Chevallier 			RTC_PRIVCFGR_MASK & access_mask_reg, privcfgr);
366e419bc7fSGatien Chevallier 
367e419bc7fSGatien Chevallier 	if (!is_tdcid)
368e419bc7fSGatien Chevallier 		return;
369e419bc7fSGatien Chevallier 
370e419bc7fSGatien Chevallier 	for (i = 0; i < RTC_NB_RIF_RESOURCES; i++) {
371e419bc7fSGatien Chevallier 		if (!(BIT(i) & rtc_dev.conf_data->access_mask[0]))
372e419bc7fSGatien Chevallier 			continue;
373e419bc7fSGatien Chevallier 		/*
374e419bc7fSGatien Chevallier 		 * When at least one resource has CID filtering enabled,
375e419bc7fSGatien Chevallier 		 * the RTC_PRIVCFGR_FULL_PRIV and RTC_SECCFGR_FULL_SEC bits are
376e419bc7fSGatien Chevallier 		 * cleared.
377e419bc7fSGatien Chevallier 		 */
378e419bc7fSGatien Chevallier 		io_clrsetbits32(base + RTC_CIDCFGR(i),
379e419bc7fSGatien Chevallier 				RTC_CIDCFGR_CONF_MASK,
380e419bc7fSGatien Chevallier 				rtc_dev.conf_data->cid_confs[i]);
381e419bc7fSGatien Chevallier 	}
382e419bc7fSGatien Chevallier }
383e419bc7fSGatien Chevallier 
stm32_rtc_clear_events(uint32_t flags)3847818ae9bSClément Le Goffic static void stm32_rtc_clear_events(uint32_t flags)
3857818ae9bSClément Le Goffic {
3867818ae9bSClément Le Goffic 	io_write32(get_base() + RTC_SCR, flags);
3877818ae9bSClément Le Goffic }
3887818ae9bSClément Le Goffic 
stm32_rtc_it_handler(struct itr_handler * h __unused)3897818ae9bSClément Le Goffic static enum itr_return stm32_rtc_it_handler(struct itr_handler *h __unused)
3907818ae9bSClément Le Goffic {
3917818ae9bSClément Le Goffic 	vaddr_t rtc_base = get_base();
3927818ae9bSClément Le Goffic 	uint32_t status = io_read32(rtc_base + RTC_SR);
3937818ae9bSClément Le Goffic 	uint32_t cr = io_read32(rtc_base + RTC_CR);
3947818ae9bSClément Le Goffic 
3957818ae9bSClément Le Goffic 	if ((status & RTC_SR_ALRAF) && (cr & RTC_CR_ALRAIE)) {
3967818ae9bSClément Le Goffic 		DMSG("Alarm occurred");
3977818ae9bSClément Le Goffic 		/* Clear event's flags */
3987818ae9bSClément Le Goffic 		stm32_rtc_clear_events(RTC_SCR_CALRAF);
3997818ae9bSClément Le Goffic 		/*
4007818ae9bSClément Le Goffic 		 * Notify the caller of 'stm32_rtc_wait_alarm' to re-schedule
4017818ae9bSClément Le Goffic 		 * the calling thread.
4027818ae9bSClément Le Goffic 		 */
4037818ae9bSClément Le Goffic 		notif_send_async(rtc_dev.notif_id, 0);
4047818ae9bSClément Le Goffic 	}
4057818ae9bSClément Le Goffic 
4067818ae9bSClément Le Goffic 	return ITRR_HANDLED;
4077818ae9bSClément Le Goffic }
4087818ae9bSClément Le Goffic DECLARE_KEEP_PAGER(stm32_rtc_it_handler);
4097818ae9bSClément Le Goffic 
parse_dt(const void * fdt,int node)410e419bc7fSGatien Chevallier static TEE_Result parse_dt(const void *fdt, int node)
411e419bc7fSGatien Chevallier {
412e419bc7fSGatien Chevallier 	TEE_Result res = TEE_ERROR_GENERIC;
413e419bc7fSGatien Chevallier 	const fdt32_t *cuint = NULL;
414e419bc7fSGatien Chevallier 	size_t reg_size = 0;
415e419bc7fSGatien Chevallier 	unsigned int i = 0;
416e419bc7fSGatien Chevallier 	int lenp = 0;
417e419bc7fSGatien Chevallier 
418e419bc7fSGatien Chevallier 	if (fdt_reg_info(fdt, node, &rtc_dev.base.pa, &reg_size))
419e419bc7fSGatien Chevallier 		panic();
420e419bc7fSGatien Chevallier 
421e419bc7fSGatien Chevallier 	io_pa_or_va(&rtc_dev.base, reg_size);
422e419bc7fSGatien Chevallier 	assert(rtc_dev.base.va);
423e419bc7fSGatien Chevallier 
424e419bc7fSGatien Chevallier 	res = clk_dt_get_by_name(fdt, node, "pclk", &rtc_dev.pclk);
425e419bc7fSGatien Chevallier 	if (res)
426e419bc7fSGatien Chevallier 		return res;
427e419bc7fSGatien Chevallier 
428e419bc7fSGatien Chevallier 	res = clk_dt_get_by_name(fdt, node, "rtc_ck", &rtc_dev.rtc_ck);
429e419bc7fSGatien Chevallier 	if (res)
430e419bc7fSGatien Chevallier 		return res;
431e419bc7fSGatien Chevallier 
432*6aa8d320SThomas Bourgoin 	if (rtc_dev.compat->has_rif_support)
433e419bc7fSGatien Chevallier 		cuint = fdt_getprop(fdt, node, "st,protreg", &lenp);
434e419bc7fSGatien Chevallier 
435*6aa8d320SThomas Bourgoin 	if (cuint) {
436e419bc7fSGatien Chevallier 		rtc_dev.conf_data = calloc(1, sizeof(*rtc_dev.conf_data));
437e419bc7fSGatien Chevallier 		if (!rtc_dev.conf_data)
438e419bc7fSGatien Chevallier 			panic();
439e419bc7fSGatien Chevallier 
440e419bc7fSGatien Chevallier 		rtc_dev.nb_res = (unsigned int)(lenp / sizeof(uint32_t));
441e419bc7fSGatien Chevallier 		assert(rtc_dev.nb_res <= RTC_NB_RIF_RESOURCES);
442e419bc7fSGatien Chevallier 
443e419bc7fSGatien Chevallier 		rtc_dev.conf_data->cid_confs = calloc(RTC_NB_RIF_RESOURCES,
444e419bc7fSGatien Chevallier 						      sizeof(uint32_t));
445e419bc7fSGatien Chevallier 		rtc_dev.conf_data->sec_conf = calloc(1, sizeof(uint32_t));
446e419bc7fSGatien Chevallier 		rtc_dev.conf_data->priv_conf = calloc(1, sizeof(uint32_t));
447e419bc7fSGatien Chevallier 		rtc_dev.conf_data->access_mask = calloc(1, sizeof(uint32_t));
448*6aa8d320SThomas Bourgoin 		if (!rtc_dev.conf_data->cid_confs ||
449*6aa8d320SThomas Bourgoin 		    !rtc_dev.conf_data->sec_conf ||
450*6aa8d320SThomas Bourgoin 		    !rtc_dev.conf_data->priv_conf ||
451*6aa8d320SThomas Bourgoin 		    !rtc_dev.conf_data->access_mask)
452e419bc7fSGatien Chevallier 			panic("Not enough memory capacity for RTC RIF config");
453e419bc7fSGatien Chevallier 
454e419bc7fSGatien Chevallier 		for (i = 0; i < rtc_dev.nb_res; i++)
455*6aa8d320SThomas Bourgoin 			stm32_rif_parse_cfg(fdt32_to_cpu(cuint[i]),
456*6aa8d320SThomas Bourgoin 					    rtc_dev.conf_data,
457e419bc7fSGatien Chevallier 					    RTC_NB_RIF_RESOURCES);
458e419bc7fSGatien Chevallier 
459*6aa8d320SThomas Bourgoin 		if (rtc_dev.conf_data->sec_conf[0] == RTC_RIF_FULL_SECURED)
460*6aa8d320SThomas Bourgoin 			rtc_dev.is_secured = true;
461*6aa8d320SThomas Bourgoin 	}
462*6aa8d320SThomas Bourgoin 
463*6aa8d320SThomas Bourgoin 	cuint = fdt_getprop(fdt, node, "wakeup-source", NULL);
464*6aa8d320SThomas Bourgoin 	/*
465*6aa8d320SThomas Bourgoin 	 * if the wakeup-source property is not present in the DT
466*6aa8d320SThomas Bourgoin 	 *    AND
467*6aa8d320SThomas Bourgoin 	 *    the RTC_PTA is disable or ASYNC_NOTIF are disable
468*6aa8d320SThomas Bourgoin 	 *    or the RTC is not secured.
469*6aa8d320SThomas Bourgoin 	 * Then we should not register the interrupt line.
470*6aa8d320SThomas Bourgoin 	 */
471*6aa8d320SThomas Bourgoin 	if (!cuint && !(IS_ENABLED(CFG_RTC_PTA) &&
472*6aa8d320SThomas Bourgoin 			IS_ENABLED(CFG_CORE_ASYNC_NOTIF) && rtc_dev.is_secured))
473e419bc7fSGatien Chevallier 		return TEE_SUCCESS;
474*6aa8d320SThomas Bourgoin 
475*6aa8d320SThomas Bourgoin 	res = interrupt_dt_get(fdt, node, &rtc_dev.itr_chip, &rtc_dev.itr_num);
476*6aa8d320SThomas Bourgoin 	if (res)
477*6aa8d320SThomas Bourgoin 		goto err;
478*6aa8d320SThomas Bourgoin 
479*6aa8d320SThomas Bourgoin 	if (cuint) {
480*6aa8d320SThomas Bourgoin 		if (!interrupt_can_set_wake(rtc_dev.itr_chip)) {
481*6aa8d320SThomas Bourgoin 			EMSG("%s does not have wakeup capabilities",
482*6aa8d320SThomas Bourgoin 			     rtc_dev.itr_chip->name);
483*6aa8d320SThomas Bourgoin 			res = TEE_ERROR_NOT_SUPPORTED;
484*6aa8d320SThomas Bourgoin 			goto err;
485*6aa8d320SThomas Bourgoin 		}
486*6aa8d320SThomas Bourgoin 		rtc_dev.rtc->is_wakeup_source = true;
487*6aa8d320SThomas Bourgoin 	}
488*6aa8d320SThomas Bourgoin 
489*6aa8d320SThomas Bourgoin 	return TEE_SUCCESS;
490*6aa8d320SThomas Bourgoin 
491*6aa8d320SThomas Bourgoin err:
492*6aa8d320SThomas Bourgoin 	if (rtc_dev.conf_data) {
493*6aa8d320SThomas Bourgoin 		free(rtc_dev.conf_data->cid_confs);
494*6aa8d320SThomas Bourgoin 		free(rtc_dev.conf_data->sec_conf);
495*6aa8d320SThomas Bourgoin 		free(rtc_dev.conf_data->priv_conf);
496*6aa8d320SThomas Bourgoin 		free(rtc_dev.conf_data->access_mask);
497*6aa8d320SThomas Bourgoin 		free(rtc_dev.conf_data);
498*6aa8d320SThomas Bourgoin 	}
499*6aa8d320SThomas Bourgoin 
500*6aa8d320SThomas Bourgoin 	return res;
501e419bc7fSGatien Chevallier }
502e419bc7fSGatien Chevallier 
stm32_rtc_enter_init_mode(void)503e419bc7fSGatien Chevallier static TEE_Result stm32_rtc_enter_init_mode(void)
504e419bc7fSGatien Chevallier {
505e419bc7fSGatien Chevallier 	vaddr_t base = get_base();
506e419bc7fSGatien Chevallier 	uint32_t icsr = io_read32(base + RTC_ICSR);
507e419bc7fSGatien Chevallier 	uint32_t value = 0;
508e419bc7fSGatien Chevallier 
509e419bc7fSGatien Chevallier 	if (!(icsr & RTC_ICSR_INITF)) {
510e419bc7fSGatien Chevallier 		icsr |= RTC_ICSR_INIT;
511e419bc7fSGatien Chevallier 		io_write32(base + RTC_ICSR, icsr);
512e419bc7fSGatien Chevallier 
513e419bc7fSGatien Chevallier 		if (IO_READ32_POLL_TIMEOUT(base + RTC_ICSR, value,
514e419bc7fSGatien Chevallier 					   value & RTC_ICSR_INITF,
515e419bc7fSGatien Chevallier 					   10, TIMEOUT_US_RTC_GENERIC))
516e419bc7fSGatien Chevallier 			return TEE_ERROR_BUSY;
517e419bc7fSGatien Chevallier 	}
518e419bc7fSGatien Chevallier 
519e419bc7fSGatien Chevallier 	return TEE_SUCCESS;
520e419bc7fSGatien Chevallier }
521e419bc7fSGatien Chevallier 
stm32_rtc_exit_init_mode(void)522446da993SClément Le Goffic static TEE_Result stm32_rtc_exit_init_mode(void)
523e419bc7fSGatien Chevallier {
524e419bc7fSGatien Chevallier 	vaddr_t base = get_base();
525e419bc7fSGatien Chevallier 	uint32_t value = 0;
526e419bc7fSGatien Chevallier 
527446da993SClément Le Goffic 	io_clrbits32(base + RTC_ICSR, RTC_ICSR_INIT);
528446da993SClément Le Goffic 	dsb();
529446da993SClément Le Goffic 
530e419bc7fSGatien Chevallier 	io_clrbits32(base + RTC_ICSR, RTC_ICSR_RSF);
531e419bc7fSGatien Chevallier 
532e419bc7fSGatien Chevallier 	if (IO_READ32_POLL_TIMEOUT(base + RTC_ICSR, value,
533e419bc7fSGatien Chevallier 				   value & RTC_ICSR_RSF, 10,
534e419bc7fSGatien Chevallier 				   TIMEOUT_US_RTC_GENERIC))
535e419bc7fSGatien Chevallier 		return TEE_ERROR_BUSY;
536e419bc7fSGatien Chevallier 
537e419bc7fSGatien Chevallier 	return TEE_SUCCESS;
538e419bc7fSGatien Chevallier }
539e419bc7fSGatien Chevallier 
stm32_rtc_to_tm(uint32_t ssr,uint32_t tr,uint32_t dr,struct optee_rtc_time * tm)540d60c61e1SGatien Chevallier static void stm32_rtc_to_tm(uint32_t ssr, uint32_t tr, uint32_t dr,
541d60c61e1SGatien Chevallier 			    struct optee_rtc_time *tm)
542d60c61e1SGatien Chevallier {
543d60c61e1SGatien Chevallier 	tm->tm_hour = ((tr & RTC_TR_HT_MASK) >> RTC_TR_HT_SHIFT) * 10 +
544d60c61e1SGatien Chevallier 		      ((tr & RTC_TR_HU_MASK) >> RTC_TR_HU_SHIFT);
545d60c61e1SGatien Chevallier 
546d60c61e1SGatien Chevallier 	if (tr & RTC_TR_PM)
547d60c61e1SGatien Chevallier 		tm->tm_hour += 12;
548d60c61e1SGatien Chevallier 
549d60c61e1SGatien Chevallier 	tm->tm_ms = (stm32_rtc_get_subsecond(ssr) * MS_PER_SEC) /
550d60c61e1SGatien Chevallier 		    stm32_rtc_get_subsecond_scale();
551d60c61e1SGatien Chevallier 
552d60c61e1SGatien Chevallier 	tm->tm_sec = ((tr & RTC_TR_ST_MASK) >> RTC_TR_ST_SHIFT) * 10 +
553d60c61e1SGatien Chevallier 		     (tr & RTC_TR_SU_MASK);
554d60c61e1SGatien Chevallier 
555d60c61e1SGatien Chevallier 	tm->tm_min = ((tr & RTC_TR_MNT_MASK) >> RTC_TR_MNT_SHIFT) * 10 +
556d60c61e1SGatien Chevallier 		     ((tr & RTC_TR_MNU_MASK) >> RTC_TR_MNU_SHIFT);
557d60c61e1SGatien Chevallier 
558d60c61e1SGatien Chevallier 	tm->tm_wday = ((dr & RTC_DR_WDU_MASK) >> RTC_DR_WDU_SHIFT) % 7;
559d60c61e1SGatien Chevallier 
560d60c61e1SGatien Chevallier 	tm->tm_mday = ((dr & RTC_DR_DT_MASK) >> RTC_DR_DT_SHIFT) * 10 +
561d60c61e1SGatien Chevallier 		      (dr & RTC_DR_DU_MASK);
562d60c61e1SGatien Chevallier 
563d60c61e1SGatien Chevallier 	tm->tm_mon = ((dr & RTC_DR_MT_MASK) >> RTC_DR_MT_SHIFT) * 10 +
564d60c61e1SGatien Chevallier 		     ((dr & RTC_DR_MU_MASK) >> RTC_DR_MU_SHIFT) - 1;
565d60c61e1SGatien Chevallier 
566d60c61e1SGatien Chevallier 	tm->tm_year = ((dr & RTC_DR_YT_MASK) >> RTC_DR_YT_SHIFT) * 10 +
567d60c61e1SGatien Chevallier 		      ((dr & RTC_DR_YU_MASK) >> RTC_DR_YU_SHIFT) + YEAR_REF;
568d60c61e1SGatien Chevallier }
569d60c61e1SGatien Chevallier 
stm32_rtc_init(void)570446da993SClément Le Goffic static TEE_Result stm32_rtc_init(void)
571446da993SClément Le Goffic {
572446da993SClément Le Goffic 	uint32_t pred_a_max = RTC_PRER_PREDIV_A_MASK >> RTC_PRER_PREDIV_A_SHIFT;
573446da993SClément Le Goffic 	uint32_t pred_s_max = RTC_PRER_PREDIV_S_MASK >> RTC_PRER_PREDIV_S_SHIFT;
574446da993SClément Le Goffic 	unsigned long rate = clk_get_rate(rtc_dev.rtc_ck);
575446da993SClément Le Goffic 	TEE_Result res = TEE_ERROR_GENERIC;
576446da993SClément Le Goffic 	vaddr_t base = get_base();
577446da993SClément Le Goffic 	uint32_t pred_a = 0;
578446da993SClément Le Goffic 	uint32_t pred_s = 0;
579446da993SClément Le Goffic 	uint32_t prer = io_read32(base + RTC_PRER);
580446da993SClément Le Goffic 	uint32_t cr = io_read32(base + RTC_CR);
581446da993SClément Le Goffic 
582446da993SClément Le Goffic 	if (rate > (pred_a_max + 1) * (pred_s_max + 1))
583446da993SClément Le Goffic 		panic("rtc_ck rate is too high");
584446da993SClément Le Goffic 
585446da993SClément Le Goffic 	if (cr & RTC_CR_FMT && !IS_ENABLED(CFG_STM32_RTC_HIGH_ACCURACY))
586446da993SClément Le Goffic 		return TEE_SUCCESS;
587446da993SClément Le Goffic 
588446da993SClément Le Goffic 	if (IS_ENABLED(CFG_STM32_RTC_HIGH_ACCURACY)) {
589446da993SClément Le Goffic 		/*
590446da993SClément Le Goffic 		 * Compute the prescaler values whom divides the clock in order
591446da993SClément Le Goffic 		 * to get a * 1 Hz output by maximizing accuracy
592446da993SClément Le Goffic 		 * (maximizing PREDIV_S).
593446da993SClément Le Goffic 		 */
594446da993SClément Le Goffic 		for (pred_a = 0; pred_a <= pred_a_max; pred_a++) {
595446da993SClément Le Goffic 			pred_s = (rate / (pred_a + 1)) - 1;
596446da993SClément Le Goffic 			if (pred_s <= pred_s_max &&
597446da993SClément Le Goffic 			    ((pred_s + 1) * (pred_a + 1)) == rate)
598446da993SClément Le Goffic 				break;
599446da993SClément Le Goffic 		}
600446da993SClément Le Goffic 
601446da993SClément Le Goffic 		/*
602446da993SClément Le Goffic 		 * 1 Hz output not possible, give priority to RTC power
603446da993SClément Le Goffic 		 * consumption by choosing the higher possible value for
604446da993SClément Le Goffic 		 * prediv_a
605446da993SClément Le Goffic 		 */
606446da993SClément Le Goffic 		if (pred_s > pred_s_max || pred_a > pred_a_max) {
607446da993SClément Le Goffic 			pred_a = pred_a_max;
608446da993SClément Le Goffic 			pred_s = (rate / (pred_a + 1)) - 1;
609446da993SClément Le Goffic 
610446da993SClément Le Goffic 			DMSG("rtc_ck is %s",
611446da993SClément Le Goffic 			     (rate < ((pred_a + 1) * (pred_s + 1))) ?
612446da993SClément Le Goffic 			     "fast" : "slow");
613446da993SClément Le Goffic 		}
614446da993SClément Le Goffic 
615446da993SClément Le Goffic 		prer &= RTC_PRER_PREDIV_S_MASK | RTC_PRER_PREDIV_A_MASK;
616446da993SClément Le Goffic 		pred_s = SHIFT_U32(pred_s, RTC_PRER_PREDIV_S_SHIFT) &
617446da993SClément Le Goffic 			 RTC_PRER_PREDIV_S_MASK;
618446da993SClément Le Goffic 		pred_a = SHIFT_U32(pred_a, RTC_PRER_PREDIV_A_SHIFT) &
619446da993SClément Le Goffic 			 RTC_PRER_PREDIV_A_MASK;
620446da993SClément Le Goffic 
621446da993SClément Le Goffic 		/* Return if there is nothing to initialize */
622446da993SClément Le Goffic 		if (cr & RTC_CR_FMT && prer == (pred_s | pred_a))
623446da993SClément Le Goffic 			return TEE_SUCCESS;
624446da993SClément Le Goffic 	}
625446da993SClément Le Goffic 
626446da993SClément Le Goffic 	stm32_rtc_write_unprotect();
627446da993SClément Le Goffic 
628446da993SClément Le Goffic 	res = stm32_rtc_enter_init_mode();
629446da993SClément Le Goffic 	if (res) {
630446da993SClément Le Goffic 		EMSG("Can't enter init mode. Fail to initialize RTC.");
631446da993SClément Le Goffic 		stm32_rtc_write_protect();
632446da993SClément Le Goffic 		return res;
633446da993SClément Le Goffic 	}
634446da993SClément Le Goffic 
635446da993SClément Le Goffic 	if (IS_ENABLED(CFG_STM32_RTC_HIGH_ACCURACY)) {
636446da993SClément Le Goffic 		io_write32(base + RTC_PRER, pred_s);
637446da993SClément Le Goffic 		io_write32(base + RTC_PRER, pred_a | pred_s);
638446da993SClément Le Goffic 	}
639446da993SClément Le Goffic 
640446da993SClément Le Goffic 	/* Force 24h time format */
641446da993SClément Le Goffic 	cr &= ~RTC_CR_FMT;
642446da993SClément Le Goffic 	io_write32(base + RTC_CR, cr);
643446da993SClément Le Goffic 
644446da993SClément Le Goffic 	res = stm32_rtc_exit_init_mode();
645446da993SClément Le Goffic 	if (res)
646446da993SClément Le Goffic 		EMSG("Can't exit init mode. Fail to initialize RTC.");
647446da993SClément Le Goffic 
648446da993SClément Le Goffic 	stm32_rtc_write_protect();
649446da993SClément Le Goffic 
650446da993SClément Le Goffic 	return res;
651446da993SClément Le Goffic }
652446da993SClément Le Goffic 
stm32_rtc_get_time(struct rtc * rtc __unused,struct optee_rtc_time * tm)653e419bc7fSGatien Chevallier static TEE_Result stm32_rtc_get_time(struct rtc *rtc __unused,
654e419bc7fSGatien Chevallier 				     struct optee_rtc_time *tm)
655e419bc7fSGatien Chevallier {
656e419bc7fSGatien Chevallier 	vaddr_t base = get_base();
657e419bc7fSGatien Chevallier 	uint32_t ssr = 0;
658e419bc7fSGatien Chevallier 	uint32_t dr = 0;
659e419bc7fSGatien Chevallier 	uint32_t tr = 0;
660e419bc7fSGatien Chevallier 
661e419bc7fSGatien Chevallier 	if (!stm32_rtc_get_bypshad()) {
662e419bc7fSGatien Chevallier 		uint32_t icsr = 0;
663e419bc7fSGatien Chevallier 
664e419bc7fSGatien Chevallier 		/* Wait calendar registers are ready */
665e419bc7fSGatien Chevallier 		io_clrbits32(base + RTC_ICSR, RTC_ICSR_RSF);
666e419bc7fSGatien Chevallier 
667e419bc7fSGatien Chevallier 		if (IO_READ32_POLL_TIMEOUT(base + RTC_ICSR, icsr,
668e419bc7fSGatien Chevallier 					   icsr & RTC_ICSR_RSF, 0,
669e419bc7fSGatien Chevallier 					   TIMEOUT_US_RTC_SHADOW))
670e419bc7fSGatien Chevallier 			panic();
671e419bc7fSGatien Chevallier 	}
672e419bc7fSGatien Chevallier 
673e419bc7fSGatien Chevallier 	/*
674e419bc7fSGatien Chevallier 	 * In our RTC we start :
675e419bc7fSGatien Chevallier 	 * - year at 0
676e419bc7fSGatien Chevallier 	 * - month at 1
677e419bc7fSGatien Chevallier 	 * - day at 1
678e419bc7fSGatien Chevallier 	 * - weekday at Monday = 1
679e419bc7fSGatien Chevallier 	 * Change month value so it becomes 0=January, 1 = February, ...
680e419bc7fSGatien Chevallier 	 * Change week day value so it becomes 0=Sunday, 1 = Monday, ...
681e419bc7fSGatien Chevallier 	 */
682e419bc7fSGatien Chevallier 
683e419bc7fSGatien Chevallier 	ssr = io_read32(base + RTC_SSR);
684e419bc7fSGatien Chevallier 	tr = io_read32(base + RTC_TR);
685e419bc7fSGatien Chevallier 	dr = io_read32(base + RTC_DR);
686e419bc7fSGatien Chevallier 
687d60c61e1SGatien Chevallier 	stm32_rtc_to_tm(ssr, tr, dr, tm);
688e419bc7fSGatien Chevallier 
689e419bc7fSGatien Chevallier 	return TEE_SUCCESS;
690e419bc7fSGatien Chevallier }
691e419bc7fSGatien Chevallier 
stm32_rtc_set_time(struct rtc * rtc,struct optee_rtc_time * tm)692e419bc7fSGatien Chevallier static TEE_Result stm32_rtc_set_time(struct rtc *rtc, struct optee_rtc_time *tm)
693e419bc7fSGatien Chevallier {
694e419bc7fSGatien Chevallier 	TEE_Result res = TEE_ERROR_GENERIC;
695e419bc7fSGatien Chevallier 	vaddr_t rtc_base = get_base();
696e419bc7fSGatien Chevallier 	uint32_t tr = 0;
697e419bc7fSGatien Chevallier 	uint32_t dr = 0;
698e419bc7fSGatien Chevallier 
699e419bc7fSGatien Chevallier 	/*
700e419bc7fSGatien Chevallier 	 * In our RTC we start :
701e419bc7fSGatien Chevallier 	 * - year at 0
702e419bc7fSGatien Chevallier 	 * - month at 1
703e419bc7fSGatien Chevallier 	 * - day at 1
704e419bc7fSGatien Chevallier 	 * - weekday at Monday = 1
705e419bc7fSGatien Chevallier 	 * Change month value so it becomes 1=January, 2 = February, ...
706e419bc7fSGatien Chevallier 	 * Change week day value so it becomes 7=Sunday, 1 = Monday, ...
707e419bc7fSGatien Chevallier 	 */
708e419bc7fSGatien Chevallier 	tr = ((tm->tm_sec % 10) & RTC_TR_SU_MASK) |
709e419bc7fSGatien Chevallier 	     (SHIFT_U32(tm->tm_sec / 10, RTC_TR_ST_SHIFT) & RTC_TR_ST_MASK) |
710e419bc7fSGatien Chevallier 	     (SHIFT_U32(tm->tm_min % 10, RTC_TR_MNU_SHIFT) & RTC_TR_MNU_MASK) |
711e419bc7fSGatien Chevallier 	     (SHIFT_U32(tm->tm_min / 10, RTC_TR_MNT_SHIFT) & RTC_TR_MNT_MASK) |
712e419bc7fSGatien Chevallier 	     (SHIFT_U32(tm->tm_hour % 10, RTC_TR_HU_SHIFT) & RTC_TR_HU_MASK) |
713e419bc7fSGatien Chevallier 	     (SHIFT_U32(tm->tm_hour / 10, RTC_TR_HT_SHIFT) & RTC_TR_HT_MASK);
714e419bc7fSGatien Chevallier 
715e419bc7fSGatien Chevallier 	dr = ((tm->tm_mday % 10) & RTC_DR_DU_MASK) |
716e419bc7fSGatien Chevallier 	     (SHIFT_U32(tm->tm_mday / 10, RTC_DR_DT_SHIFT) & RTC_DR_DT_MASK) |
717e419bc7fSGatien Chevallier 	     (SHIFT_U32((tm->tm_mon + 1) % 10, RTC_DR_MU_SHIFT) &
718e419bc7fSGatien Chevallier 	      RTC_DR_MU_MASK) |
719e419bc7fSGatien Chevallier 	     (SHIFT_U32((tm->tm_mon + 1) / 10, RTC_DR_MT_SHIFT) &
720e419bc7fSGatien Chevallier 	      RTC_DR_MT_MASK) |
721e419bc7fSGatien Chevallier 	     (SHIFT_U32(tm->tm_wday ? tm->tm_wday : 7, RTC_DR_WDU_SHIFT) &
722e419bc7fSGatien Chevallier 	      RTC_DR_WDU_MASK) |
723e419bc7fSGatien Chevallier 	     (SHIFT_U32((tm->tm_year - rtc->range_min.tm_year) % 10,
724e419bc7fSGatien Chevallier 			RTC_DR_YU_SHIFT) & RTC_DR_YU_MASK) |
725e419bc7fSGatien Chevallier 	     (SHIFT_U32((tm->tm_year - rtc->range_min.tm_year) / 10,
726e419bc7fSGatien Chevallier 			RTC_DR_YT_SHIFT) & RTC_DR_YT_MASK);
727e419bc7fSGatien Chevallier 
728e419bc7fSGatien Chevallier 	stm32_rtc_write_unprotect();
729e419bc7fSGatien Chevallier 
730e419bc7fSGatien Chevallier 	res = stm32_rtc_enter_init_mode();
731e419bc7fSGatien Chevallier 	if (res)
732e419bc7fSGatien Chevallier 		goto end;
733e419bc7fSGatien Chevallier 
734e419bc7fSGatien Chevallier 	io_write32(rtc_base + RTC_TR, tr);
735e419bc7fSGatien Chevallier 	io_write32(rtc_base + RTC_DR, dr);
736e419bc7fSGatien Chevallier 
737446da993SClément Le Goffic 	res = stm32_rtc_exit_init_mode();
738e419bc7fSGatien Chevallier end:
739e419bc7fSGatien Chevallier 	stm32_rtc_write_protect();
740e419bc7fSGatien Chevallier 
741e419bc7fSGatien Chevallier 	return res;
742e419bc7fSGatien Chevallier }
743e419bc7fSGatien Chevallier 
stm32_rtc_get_timestamp(struct optee_rtc_time * tm)744d60c61e1SGatien Chevallier TEE_Result stm32_rtc_get_timestamp(struct optee_rtc_time *tm)
745d60c61e1SGatien Chevallier {
746d60c61e1SGatien Chevallier 	vaddr_t base = get_base();
747d60c61e1SGatien Chevallier 	uint32_t exceptions = 0;
748d60c61e1SGatien Chevallier 	uint32_t value = 0;
749d60c61e1SGatien Chevallier 	uint32_t ssr = 0;
750d60c61e1SGatien Chevallier 	uint32_t dr = 0;
751d60c61e1SGatien Chevallier 	uint32_t tr = 0;
752d60c61e1SGatien Chevallier 
753d60c61e1SGatien Chevallier 	exceptions = cpu_spin_lock_xsave(&rtc_dev.ts_lock);
754d60c61e1SGatien Chevallier 
755d60c61e1SGatien Chevallier 	if (IO_READ32_POLL_TIMEOUT(base + RTC_SR, value,
756d60c61e1SGatien Chevallier 				   value & RTC_SR_TSF,
757d60c61e1SGatien Chevallier 				   10, TIMEOUT_US_RTC_GENERIC)) {
758d60c61e1SGatien Chevallier 		cpu_spin_unlock_xrestore(&rtc_dev.ts_lock, exceptions);
759d60c61e1SGatien Chevallier 		return TEE_ERROR_NO_DATA;
760d60c61e1SGatien Chevallier 	}
761d60c61e1SGatien Chevallier 
762d60c61e1SGatien Chevallier 	ssr = io_read32(base + RTC_TSSSR);
763d60c61e1SGatien Chevallier 	tr = io_read32(base + RTC_TSTR);
764d60c61e1SGatien Chevallier 	dr = io_read32(base + RTC_TSDR);
765d60c61e1SGatien Chevallier 
766d60c61e1SGatien Chevallier 	io_setbits32(base + RTC_SCR, RTC_SCR_CTSF);
767d60c61e1SGatien Chevallier 
768d60c61e1SGatien Chevallier 	/* Tamper event overflow detection */
769d60c61e1SGatien Chevallier 	if (io_read32(base + RTC_SR) & RTC_SR_TSOVF) {
770d60c61e1SGatien Chevallier 		io_setbits32(base + RTC_SCR, RTC_SCR_CTSOVF);
771d60c61e1SGatien Chevallier 		DMSG("A timestamp event occurred while handling current event");
772d60c61e1SGatien Chevallier 	}
773d60c61e1SGatien Chevallier 
774d60c61e1SGatien Chevallier 	cpu_spin_unlock_xrestore(&rtc_dev.ts_lock, exceptions);
775d60c61e1SGatien Chevallier 
776d60c61e1SGatien Chevallier 	stm32_rtc_to_tm(ssr, tr, dr, tm);
777d60c61e1SGatien Chevallier 
778d60c61e1SGatien Chevallier 	/* No year timestamp available */
779d60c61e1SGatien Chevallier 	tm->tm_year = 0;
780d60c61e1SGatien Chevallier 
781d60c61e1SGatien Chevallier 	return TEE_SUCCESS;
782d60c61e1SGatien Chevallier }
783d60c61e1SGatien Chevallier 
stm32_rtc_set_tamper_timestamp(void)784d60c61e1SGatien Chevallier TEE_Result stm32_rtc_set_tamper_timestamp(void)
785d60c61e1SGatien Chevallier {
786d60c61e1SGatien Chevallier 	vaddr_t base = get_base();
787d60c61e1SGatien Chevallier 
788d60c61e1SGatien Chevallier 	stm32_rtc_write_unprotect();
789d60c61e1SGatien Chevallier 
790d60c61e1SGatien Chevallier 	/* Secure Timestamp bit */
791d60c61e1SGatien Chevallier 	if (!rtc_dev.compat->has_seccfgr) {
792d60c61e1SGatien Chevallier 		/* Inverted logic */
793d60c61e1SGatien Chevallier 		io_clrbits32(base + RTC_SMCR, RTC_SMCR_TS_DPROT);
794d60c61e1SGatien Chevallier 	} else {
795d60c61e1SGatien Chevallier 		io_setbits32(base + RTC_SECCFGR, RTC_SECCFGR_TS_SEC);
796d60c61e1SGatien Chevallier 	}
797d60c61e1SGatien Chevallier 
798d60c61e1SGatien Chevallier 	/* Enable tamper timestamper */
799d60c61e1SGatien Chevallier 	io_setbits32(base + RTC_CR, RTC_CR_TAMPTS);
800d60c61e1SGatien Chevallier 
801d60c61e1SGatien Chevallier 	stm32_rtc_write_protect();
802d60c61e1SGatien Chevallier 
803d60c61e1SGatien Chevallier 	return TEE_SUCCESS;
804d60c61e1SGatien Chevallier }
805d60c61e1SGatien Chevallier 
stm32_rtc_is_timestamp_enabled(bool * ret)806d60c61e1SGatien Chevallier TEE_Result stm32_rtc_is_timestamp_enabled(bool *ret)
807d60c61e1SGatien Chevallier {
808d60c61e1SGatien Chevallier 	*ret = io_read32(get_base() + RTC_CR) & RTC_CR_TAMPTS;
809d60c61e1SGatien Chevallier 
810d60c61e1SGatien Chevallier 	return TEE_SUCCESS;
811d60c61e1SGatien Chevallier }
812d60c61e1SGatien Chevallier 
stm32_rtc_driver_is_initialized(void)813d60c61e1SGatien Chevallier TEE_Result stm32_rtc_driver_is_initialized(void)
814d60c61e1SGatien Chevallier {
815d60c61e1SGatien Chevallier 	if (rtc_dev.pclk)
816d60c61e1SGatien Chevallier 		return TEE_SUCCESS;
817d60c61e1SGatien Chevallier 
818d60c61e1SGatien Chevallier 	return TEE_ERROR_DEFER_DRIVER_INIT;
819d60c61e1SGatien Chevallier }
820d60c61e1SGatien Chevallier 
stm32_rtc_read_alarm(struct rtc * rtc,struct optee_rtc_alarm * alarm)8217818ae9bSClément Le Goffic static TEE_Result stm32_rtc_read_alarm(struct rtc *rtc,
8227818ae9bSClément Le Goffic 				       struct optee_rtc_alarm *alarm)
8237818ae9bSClément Le Goffic {
8247818ae9bSClément Le Goffic 	struct optee_rtc_time *alarm_tm = NULL;
8257818ae9bSClément Le Goffic 	struct optee_rtc_time current_tm = { };
8267818ae9bSClément Le Goffic 	TEE_Result res = TEE_ERROR_GENERIC;
8277818ae9bSClément Le Goffic 	vaddr_t rtc_base = get_base();
8287818ae9bSClément Le Goffic 	uint32_t alrmar = io_read32(rtc_base + RTC_ALRMAR);
8297818ae9bSClément Le Goffic 	uint32_t cr = io_read32(rtc_base + RTC_CR);
8307818ae9bSClément Le Goffic 	uint32_t status = io_read32(rtc_base + RTC_SR);
8317818ae9bSClément Le Goffic 
8327818ae9bSClément Le Goffic 	alarm_tm = &alarm->time;
8337818ae9bSClément Le Goffic 
8347818ae9bSClément Le Goffic 	res = stm32_rtc_get_time(rtc, &current_tm);
8357818ae9bSClément Le Goffic 	if (res)
8367818ae9bSClément Le Goffic 		return res;
8377818ae9bSClément Le Goffic 
8387818ae9bSClément Le Goffic 	alarm_tm->tm_year = current_tm.tm_year;
8397818ae9bSClément Le Goffic 	alarm_tm->tm_mon = current_tm.tm_mon;
8407818ae9bSClément Le Goffic 	alarm_tm->tm_mday = ((alrmar & RTC_ALRMXR_DATE_UNITS_MASK) >>
8417818ae9bSClément Le Goffic 			    RTC_ALRMXR_DATE_UNITS_SHIFT) +
8427818ae9bSClément Le Goffic 			    ((alrmar & RTC_ALRMXR_DATE_TENS_MASK) >>
8437818ae9bSClément Le Goffic 			    RTC_ALRMXR_DATE_TENS_SHIFT) * 10;
8447818ae9bSClément Le Goffic 	alarm_tm->tm_hour = ((alrmar & RTC_ALRMXR_HOUR_UNITS_MASK) >>
8457818ae9bSClément Le Goffic 			    RTC_ALRMXR_HOUR_UNITS_SHIFT) +
8467818ae9bSClément Le Goffic 			    ((alrmar & RTC_ALRMXR_HOUR_TENS_MASK) >>
8477818ae9bSClément Le Goffic 			    RTC_ALRMXR_HOUR_TENS_SHIFT) * 10;
8487818ae9bSClément Le Goffic 	alarm_tm->tm_min = ((alrmar & RTC_ALRMXR_MIN_UNITS_MASK) >>
8497818ae9bSClément Le Goffic 			    RTC_ALRMXR_MIN_UNITS_SHIFT) +
8507818ae9bSClément Le Goffic 			   ((alrmar & RTC_ALRMXR_MIN_TENS_MASK) >>
8517818ae9bSClément Le Goffic 			    RTC_ALRMXR_MIN_TENS_SHIFT) * 10;
8527818ae9bSClément Le Goffic 	alarm_tm->tm_sec = ((alrmar & RTC_ALRMXR_MIN_UNITS_MASK) >>
8537818ae9bSClément Le Goffic 			    RTC_ALRMXR_MIN_UNITS_SHIFT) +
8547818ae9bSClément Le Goffic 			   ((alrmar & RTC_ALRMXR_MIN_TENS_MASK) >>
8557818ae9bSClément Le Goffic 			    RTC_ALRMXR_MIN_TENS_SHIFT) * 10;
8567818ae9bSClément Le Goffic 
8577818ae9bSClément Le Goffic 	if (rtc_timecmp(alarm_tm, &current_tm) < 0) {
8587818ae9bSClément Le Goffic 		if (current_tm.tm_mon == 11) {
8597818ae9bSClément Le Goffic 			alarm_tm->tm_mon = 0;
8607818ae9bSClément Le Goffic 			alarm_tm->tm_year += 1;
8617818ae9bSClément Le Goffic 		} else {
8627818ae9bSClément Le Goffic 			alarm_tm->tm_mon += 1;
8637818ae9bSClément Le Goffic 		}
8647818ae9bSClément Le Goffic 	}
8657818ae9bSClément Le Goffic 
8667818ae9bSClément Le Goffic 	alarm->enabled = cr & RTC_CR_ALRAE;
8677818ae9bSClément Le Goffic 	alarm->pending = status & RTC_SR_ALRAF;
8687818ae9bSClément Le Goffic 
8697818ae9bSClément Le Goffic 	return TEE_SUCCESS;
8707818ae9bSClément Le Goffic }
8717818ae9bSClément Le Goffic 
stm32_rtc_enable_alarm(struct rtc * rtc __unused,bool enabled)8727818ae9bSClément Le Goffic static TEE_Result stm32_rtc_enable_alarm(struct rtc *rtc __unused, bool enabled)
8737818ae9bSClément Le Goffic {
8747818ae9bSClément Le Goffic 	vaddr_t rtc_base = get_base();
8757818ae9bSClément Le Goffic 
8767818ae9bSClément Le Goffic 	stm32_rtc_write_unprotect();
8777818ae9bSClément Le Goffic 
8787818ae9bSClément Le Goffic 	if (enabled)
8797818ae9bSClément Le Goffic 		io_setbits32(rtc_base + RTC_CR, RTC_CR_ALRAIE | RTC_CR_ALRAE);
8807818ae9bSClément Le Goffic 	else
8817818ae9bSClément Le Goffic 		io_clrbits32(rtc_base + RTC_CR, RTC_CR_ALRAIE | RTC_CR_ALRAE);
8827818ae9bSClément Le Goffic 
8837818ae9bSClément Le Goffic 	stm32_rtc_clear_events(RTC_SCR_CALRAF);
8847818ae9bSClément Le Goffic 
8857818ae9bSClément Le Goffic 	stm32_rtc_write_protect();
8867818ae9bSClément Le Goffic 
8877818ae9bSClément Le Goffic 	return TEE_SUCCESS;
8887818ae9bSClément Le Goffic }
8897818ae9bSClément Le Goffic 
stm32_rtc_add_one_month(struct optee_rtc_time * tm)8907818ae9bSClément Le Goffic static void stm32_rtc_add_one_month(struct optee_rtc_time *tm)
8917818ae9bSClément Le Goffic {
8927818ae9bSClément Le Goffic 	tm->tm_mon++;
8937818ae9bSClément Le Goffic 	if (tm->tm_mon > 11) {
8947818ae9bSClément Le Goffic 		tm->tm_mon = 0;
8957818ae9bSClément Le Goffic 		tm->tm_year++;
8967818ae9bSClément Le Goffic 	}
8977818ae9bSClément Le Goffic 
8987818ae9bSClément Le Goffic 	/* Saturate to the next month last day */
8997818ae9bSClément Le Goffic 	tm->tm_mday = MIN(tm->tm_mday,
9007818ae9bSClément Le Goffic 			  rtc_get_month_days(tm->tm_mon, tm->tm_year));
9017818ae9bSClément Le Goffic }
9027818ae9bSClément Le Goffic 
stm32_rtc_valid_alarm_time(struct rtc * rtc,struct optee_rtc_time * tm)9037818ae9bSClément Le Goffic static TEE_Result stm32_rtc_valid_alarm_time(struct rtc *rtc,
9047818ae9bSClément Le Goffic 					     struct optee_rtc_time *tm)
9057818ae9bSClément Le Goffic {
9067818ae9bSClément Le Goffic 	struct optee_rtc_time current_tm = { };
9077818ae9bSClément Le Goffic 	TEE_Result res = TEE_ERROR_GENERIC;
9087818ae9bSClément Le Goffic 	struct optee_rtc_time *max = NULL;
9097818ae9bSClément Le Goffic 
9107818ae9bSClément Le Goffic 	/*
9117818ae9bSClément Le Goffic 	 * Assuming current date is M-D-Y H:M:S.
9127818ae9bSClément Le Goffic 	 * RTC alarm can't be set on a specific month and year.
9137818ae9bSClément Le Goffic 	 * So the valid alarm range is:
9147818ae9bSClément Le Goffic 	 *	M-D-Y H:M:S < alarm <= (M+1)-D-Y H:M:S
9157818ae9bSClément Le Goffic 	 */
9167818ae9bSClément Le Goffic 
9177818ae9bSClément Le Goffic 	res = stm32_rtc_get_time(rtc, &current_tm);
9187818ae9bSClément Le Goffic 	if (res)
9197818ae9bSClément Le Goffic 		return res;
9207818ae9bSClément Le Goffic 
9217818ae9bSClément Le Goffic 	/* Don't allow alarm to be set in the past. */
9227818ae9bSClément Le Goffic 	if (rtc_timecmp(&current_tm, tm) >= 0)
9237818ae9bSClément Le Goffic 		return TEE_ERROR_BAD_PARAMETERS;
9247818ae9bSClément Le Goffic 
9257818ae9bSClément Le Goffic 	max = &current_tm;
9267818ae9bSClément Le Goffic 
9277818ae9bSClément Le Goffic 	stm32_rtc_add_one_month(max);
9287818ae9bSClément Le Goffic 
9297818ae9bSClément Le Goffic 	if (rtc_timecmp(max, tm) <= 0)
9307818ae9bSClément Le Goffic 		return TEE_ERROR_BAD_PARAMETERS;
9317818ae9bSClément Le Goffic 
9327818ae9bSClément Le Goffic 	return TEE_SUCCESS;
9337818ae9bSClément Le Goffic }
9347818ae9bSClément Le Goffic 
stm32_rtc_set_alarm(struct rtc * rtc,struct optee_rtc_alarm * alarm)9357818ae9bSClément Le Goffic static TEE_Result stm32_rtc_set_alarm(struct rtc *rtc,
9367818ae9bSClément Le Goffic 				      struct optee_rtc_alarm *alarm)
9377818ae9bSClément Le Goffic {
9387818ae9bSClément Le Goffic 	struct optee_rtc_time *alarm_time = &alarm->time;
9397818ae9bSClément Le Goffic 	TEE_Result res = TEE_ERROR_GENERIC;
9407818ae9bSClément Le Goffic 	vaddr_t rtc_base = get_base();
9417818ae9bSClément Le Goffic 	uint32_t alrmar = 0;
9427818ae9bSClément Le Goffic 	uint32_t cr = io_read32(rtc_base + RTC_CR);
9437818ae9bSClément Le Goffic 	uint32_t prer = io_read32(rtc_base + RTC_PRER);
9447818ae9bSClément Le Goffic 	uint32_t prediv_s = prer & RTC_PRER_PREDIV_S_MASK;
9457818ae9bSClément Le Goffic 
9467818ae9bSClément Le Goffic 	/* tm_year and tm_mon are not used because not supported by RTC */
9477818ae9bSClément Le Goffic 	alrmar |= ((alarm_time->tm_mday / 10) << RTC_ALRMXR_DATE_TENS_SHIFT) &
9487818ae9bSClément Le Goffic 		  RTC_ALRMXR_DATE_TENS_MASK;
9497818ae9bSClément Le Goffic 	alrmar |= ((alarm_time->tm_mday % 10) << RTC_ALRMXR_DATE_UNITS_SHIFT) &
9507818ae9bSClément Le Goffic 		  RTC_ALRMXR_DATE_UNITS_MASK;
9517818ae9bSClément Le Goffic 	/* 24-hour format */
9527818ae9bSClément Le Goffic 	alrmar &= ~RTC_ALRMXR_PM;
9537818ae9bSClément Le Goffic 	alrmar |= ((alarm_time->tm_hour / 10) << RTC_ALRMXR_HOUR_TENS_SHIFT) &
9547818ae9bSClément Le Goffic 		  RTC_ALRMXR_HOUR_TENS_MASK;
9557818ae9bSClément Le Goffic 	alrmar |= ((alarm_time->tm_hour % 10) << RTC_ALRMXR_HOUR_UNITS_SHIFT) &
9567818ae9bSClément Le Goffic 		  RTC_ALRMXR_HOUR_UNITS_MASK;
9577818ae9bSClément Le Goffic 	alrmar |= ((alarm_time->tm_min / 10) << RTC_ALRMXR_MIN_TENS_SHIFT) &
9587818ae9bSClément Le Goffic 		  RTC_ALRMXR_MIN_TENS_MASK;
9597818ae9bSClément Le Goffic 	alrmar |= ((alarm_time->tm_min % 10) << RTC_ALRMXR_MIN_UNITS_SHIFT) &
9607818ae9bSClément Le Goffic 		  RTC_ALRMXR_MIN_UNITS_MASK;
9617818ae9bSClément Le Goffic 	alrmar |= ((alarm_time->tm_sec / 10) << RTC_ALRMXR_SEC_TENS_SHIFT) &
9627818ae9bSClément Le Goffic 		  RTC_ALRMXR_SEC_TENS_MASK;
9637818ae9bSClément Le Goffic 	alrmar |= ((alarm_time->tm_sec % 10) << RTC_ALRMXR_SEC_UNITS_SHIFT) &
9647818ae9bSClément Le Goffic 		  RTC_ALRMXR_SEC_UNITS_MASK;
9657818ae9bSClément Le Goffic 
9667818ae9bSClément Le Goffic 	if ((alrmar & !RTC_ALRMXR_SEC_MASK) && prediv_s < 3) {
9677818ae9bSClément Le Goffic 		EMSG("RTC Alarm conditions not met");
9687818ae9bSClément Le Goffic 		return TEE_ERROR_BAD_STATE;
9697818ae9bSClément Le Goffic 	}
9707818ae9bSClément Le Goffic 
9717818ae9bSClément Le Goffic 	stm32_rtc_write_unprotect();
9727818ae9bSClément Le Goffic 
9737818ae9bSClément Le Goffic 	res = stm32_rtc_valid_alarm_time(rtc, alarm_time);
9747818ae9bSClément Le Goffic 	if (res) {
9757818ae9bSClément Le Goffic 		stm32_rtc_write_unprotect();
9767818ae9bSClément Le Goffic 		return res;
9777818ae9bSClément Le Goffic 	}
9787818ae9bSClément Le Goffic 
9797818ae9bSClément Le Goffic 	/* Disable Alarm */
9807818ae9bSClément Le Goffic 	cr &= ~RTC_CR_ALRAE;
9817818ae9bSClément Le Goffic 	io_write32(rtc_base + RTC_CR, cr);
9827818ae9bSClément Le Goffic 
9837818ae9bSClément Le Goffic 	io_write32(rtc_base + RTC_ALRMAR, alrmar);
9847818ae9bSClément Le Goffic 
9857818ae9bSClément Le Goffic 	stm32_rtc_enable_alarm(rtc, alarm->enabled);
9867818ae9bSClément Le Goffic 
9877818ae9bSClément Le Goffic 	stm32_rtc_write_protect();
9887818ae9bSClément Le Goffic 
9897818ae9bSClément Le Goffic 	return TEE_SUCCESS;
9907818ae9bSClément Le Goffic }
9917818ae9bSClément Le Goffic 
stm32_rtc_cancel_wait_alarm(struct rtc * rtc __unused)9927818ae9bSClément Le Goffic static TEE_Result stm32_rtc_cancel_wait_alarm(struct rtc *rtc __unused)
9937818ae9bSClément Le Goffic {
9947818ae9bSClément Le Goffic 	rtc_dev.wait_alarm_return_status = RTC_WAIT_ALARM_CANCELED;
9957818ae9bSClément Le Goffic 	notif_send_async(rtc_dev.notif_id, 0);
9967818ae9bSClément Le Goffic 
9977818ae9bSClément Le Goffic 	return TEE_SUCCESS;
9987818ae9bSClément Le Goffic }
9997818ae9bSClément Le Goffic 
10007818ae9bSClément Le Goffic static TEE_Result
stm32_rtc_wait_alarm(struct rtc * rtc __unused,enum rtc_wait_alarm_status * return_status)10017818ae9bSClément Le Goffic stm32_rtc_wait_alarm(struct rtc *rtc __unused,
10027818ae9bSClément Le Goffic 		     enum rtc_wait_alarm_status *return_status)
10037818ae9bSClément Le Goffic {
10047818ae9bSClément Le Goffic 	TEE_Result res = TEE_ERROR_GENERIC;
10057818ae9bSClément Le Goffic 
10067818ae9bSClément Le Goffic 	rtc_dev.wait_alarm_return_status = RTC_WAIT_ALARM_RESET;
10077818ae9bSClément Le Goffic 
10087818ae9bSClément Le Goffic 	/* Wait until a notification arrives - blocking */
10097818ae9bSClément Le Goffic 	res = notif_wait(rtc_dev.notif_id);
10107818ae9bSClément Le Goffic 	if (res)
10117818ae9bSClément Le Goffic 		return res;
10127818ae9bSClément Le Goffic 
10137818ae9bSClément Le Goffic 	if (rtc_dev.wait_alarm_return_status ==
10147818ae9bSClément Le Goffic 		RTC_WAIT_ALARM_CANCELED) {
10157818ae9bSClément Le Goffic 		*return_status = RTC_WAIT_ALARM_CANCELED;
10167818ae9bSClément Le Goffic 		stm32_rtc_enable_alarm(rtc, 0);
10177818ae9bSClément Le Goffic 	} else {
10187818ae9bSClément Le Goffic 		*return_status = RTC_WAIT_ALARM_ALARM_OCCURRED;
10197818ae9bSClément Le Goffic 	}
10207818ae9bSClément Le Goffic 
10217818ae9bSClément Le Goffic 	return TEE_SUCCESS;
10227818ae9bSClément Le Goffic }
10237818ae9bSClément Le Goffic 
stm32_rtc_set_alarm_wakeup_status(struct rtc * rtc __unused,bool status)102463000677SClément Le Goffic static TEE_Result stm32_rtc_set_alarm_wakeup_status(struct rtc *rtc __unused,
102563000677SClément Le Goffic 						    bool status)
102663000677SClément Le Goffic {
102763000677SClément Le Goffic 	if (!rtc_dev.rtc->is_wakeup_source)
102863000677SClément Le Goffic 		return TEE_ERROR_NOT_SUPPORTED;
102963000677SClément Le Goffic 
103063000677SClément Le Goffic 	interrupt_set_wake(rtc_dev.itr_chip, rtc_dev.itr_num, status);
103163000677SClément Le Goffic 
103263000677SClément Le Goffic 	return TEE_SUCCESS;
103363000677SClément Le Goffic }
103463000677SClément Le Goffic 
1035e419bc7fSGatien Chevallier static const struct rtc_ops stm32_rtc_ops = {
1036e419bc7fSGatien Chevallier 	.get_time = stm32_rtc_get_time,
1037e419bc7fSGatien Chevallier 	.set_time = stm32_rtc_set_time,
10387818ae9bSClément Le Goffic 	.read_alarm = stm32_rtc_read_alarm,
10397818ae9bSClément Le Goffic 	.set_alarm = stm32_rtc_set_alarm,
10407818ae9bSClément Le Goffic 	.enable_alarm = stm32_rtc_enable_alarm,
10417818ae9bSClément Le Goffic 	.wait_alarm = stm32_rtc_wait_alarm,
10427818ae9bSClément Le Goffic 	.cancel_wait = stm32_rtc_cancel_wait_alarm,
104363000677SClément Le Goffic 	.set_alarm_wakeup_status = stm32_rtc_set_alarm_wakeup_status,
1044e419bc7fSGatien Chevallier };
1045e419bc7fSGatien Chevallier 
1046e419bc7fSGatien Chevallier static struct rtc stm32_rtc = {
1047e419bc7fSGatien Chevallier 	.ops = &stm32_rtc_ops,
1048e419bc7fSGatien Chevallier 	.range_min = RTC_TIME(YEAR_REF, 0, 1, 0, 0, 0, 0, 0),
1049e419bc7fSGatien Chevallier 	.range_max = RTC_TIME(YEAR_MAX, 11, 31, 4, 23, 59, 59, 999),
1050e419bc7fSGatien Chevallier };
1051e419bc7fSGatien Chevallier 
stm32_rtc_probe(const void * fdt,int node,const void * compat_data)1052e419bc7fSGatien Chevallier static TEE_Result stm32_rtc_probe(const void *fdt, int node,
1053e419bc7fSGatien Chevallier 				  const void *compat_data)
1054e419bc7fSGatien Chevallier {
1055e419bc7fSGatien Chevallier 	TEE_Result res = TEE_ERROR_GENERIC;
1056e419bc7fSGatien Chevallier 	bool is_tdcid = false;
1057e419bc7fSGatien Chevallier 
1058e419bc7fSGatien Chevallier 	rtc_dev.compat = compat_data;
105963000677SClément Le Goffic 	rtc_dev.rtc = &stm32_rtc;
1060e419bc7fSGatien Chevallier 
1061e419bc7fSGatien Chevallier 	if (rtc_dev.compat->has_rif_support) {
1062e419bc7fSGatien Chevallier 		res = stm32_rifsc_check_tdcid(&is_tdcid);
1063e419bc7fSGatien Chevallier 		if (res)
1064e419bc7fSGatien Chevallier 			return res;
1065e419bc7fSGatien Chevallier 	}
1066e419bc7fSGatien Chevallier 
1067e419bc7fSGatien Chevallier 	res = parse_dt(fdt, node);
1068e419bc7fSGatien Chevallier 	if (res) {
1069e419bc7fSGatien Chevallier 		memset(&rtc_dev, 0, sizeof(rtc_dev));
1070e419bc7fSGatien Chevallier 		return res;
1071e419bc7fSGatien Chevallier 	}
1072e419bc7fSGatien Chevallier 
1073e419bc7fSGatien Chevallier 	/* Unbalanced clock enable to ensure RTC core clock is always on */
1074e419bc7fSGatien Chevallier 	res = clk_enable(rtc_dev.rtc_ck);
1075e419bc7fSGatien Chevallier 	if (res)
1076e419bc7fSGatien Chevallier 		panic("Couldn't enable RTC clock");
1077e419bc7fSGatien Chevallier 
1078e419bc7fSGatien Chevallier 	if (clk_get_rate(rtc_dev.pclk) < (clk_get_rate(rtc_dev.rtc_ck) * 7))
1079e419bc7fSGatien Chevallier 		rtc_dev.flags |= RTC_FLAGS_READ_TWICE;
1080e419bc7fSGatien Chevallier 
1081e419bc7fSGatien Chevallier 	if (rtc_dev.compat->has_rif_support) {
1082e419bc7fSGatien Chevallier 		res = clk_enable(rtc_dev.pclk);
1083e419bc7fSGatien Chevallier 		if (res)
1084e419bc7fSGatien Chevallier 			panic("Could not enable RTC bus clock");
1085e419bc7fSGatien Chevallier 
1086e419bc7fSGatien Chevallier 		apply_rif_config(is_tdcid);
1087e419bc7fSGatien Chevallier 
1088e419bc7fSGatien Chevallier 		/*
1089e419bc7fSGatien Chevallier 		 * Verify if applied RIF config will not disable
1090e419bc7fSGatien Chevallier 		 * other functionalities of this driver.
1091e419bc7fSGatien Chevallier 		 */
1092e419bc7fSGatien Chevallier 		res = check_rif_config();
1093e419bc7fSGatien Chevallier 		if (res)
1094e419bc7fSGatien Chevallier 			panic("Incompatible RTC RIF configuration");
1095e419bc7fSGatien Chevallier 
1096e419bc7fSGatien Chevallier 		clk_disable(rtc_dev.pclk);
1097e419bc7fSGatien Chevallier 	}
1098e419bc7fSGatien Chevallier 
1099446da993SClément Le Goffic 	res = stm32_rtc_init();
1100446da993SClément Le Goffic 	if (res)
1101446da993SClément Le Goffic 		return res;
11027818ae9bSClément Le Goffic 
1103e419bc7fSGatien Chevallier 	rtc_register(&stm32_rtc);
1104e419bc7fSGatien Chevallier 
11057818ae9bSClément Le Goffic 	if (IS_ENABLED(CFG_RTC_PTA) && IS_ENABLED(CFG_CORE_ASYNC_NOTIF) &&
110663000677SClément Le Goffic 	    rtc_dev.is_secured && rtc_dev.itr_chip) {
11077818ae9bSClément Le Goffic 		res = notif_alloc_async_value(&rtc_dev.notif_id);
11087818ae9bSClément Le Goffic 		if (res)
1109e419bc7fSGatien Chevallier 			return res;
11107818ae9bSClément Le Goffic 
111163000677SClément Le Goffic 		res = interrupt_create_handler(rtc_dev.itr_chip,
111263000677SClément Le Goffic 					       rtc_dev.itr_num,
111363000677SClément Le Goffic 					       stm32_rtc_it_handler,
111463000677SClément Le Goffic 					       &rtc_dev, 0,
111563000677SClément Le Goffic 					       &rtc_dev.itr_handler);
111663000677SClément Le Goffic 		if (res)
111763000677SClément Le Goffic 			goto out_rtc_secured_and_itr_chip;
111863000677SClément Le Goffic 
11197818ae9bSClément Le Goffic 		/* Unbalanced clock enable to ensure IRQ interface is alive */
11207818ae9bSClément Le Goffic 		res = clk_enable(rtc_dev.pclk);
11217818ae9bSClément Le Goffic 		if (res)
112263000677SClément Le Goffic 			goto out_rtc_secured_and_itr_chip;
11237818ae9bSClément Le Goffic 
11247818ae9bSClément Le Goffic 		interrupt_enable(rtc_dev.itr_chip, rtc_dev.itr_num);
11257818ae9bSClément Le Goffic 
11267818ae9bSClément Le Goffic 		return TEE_SUCCESS;
11277818ae9bSClément Le Goffic 
112863000677SClément Le Goffic out_rtc_secured_and_itr_chip:
112963000677SClément Le Goffic 		interrupt_remove_handler(rtc_dev.itr_handler);
11307818ae9bSClément Le Goffic 		notif_free_async_value(rtc_dev.notif_id);
11317818ae9bSClément Le Goffic 		return res;
11327818ae9bSClément Le Goffic 	}
11337818ae9bSClément Le Goffic 
11347818ae9bSClément Le Goffic 	return TEE_SUCCESS;
1135e419bc7fSGatien Chevallier }
1136e419bc7fSGatien Chevallier 
1137e419bc7fSGatien Chevallier static const struct rtc_compat mp25_compat = {
1138e419bc7fSGatien Chevallier 	.has_seccfgr = true,
1139e419bc7fSGatien Chevallier 	.has_rif_support = true,
1140e419bc7fSGatien Chevallier };
1141e419bc7fSGatien Chevallier 
1142e419bc7fSGatien Chevallier static const struct rtc_compat mp15_compat = {
1143e419bc7fSGatien Chevallier 	.has_seccfgr = false,
1144e419bc7fSGatien Chevallier 	.has_rif_support = false,
1145e419bc7fSGatien Chevallier };
1146e419bc7fSGatien Chevallier 
1147e419bc7fSGatien Chevallier static const struct rtc_compat mp13_compat = {
1148e419bc7fSGatien Chevallier 	.has_seccfgr = true,
1149e419bc7fSGatien Chevallier 	.has_rif_support = false,
1150e419bc7fSGatien Chevallier };
1151e419bc7fSGatien Chevallier 
1152e419bc7fSGatien Chevallier static const struct dt_device_match stm32_rtc_match_table[] = {
1153e419bc7fSGatien Chevallier 	{
1154e419bc7fSGatien Chevallier 		.compatible = "st,stm32mp25-rtc",
1155e419bc7fSGatien Chevallier 		.compat_data = &mp25_compat,
1156e419bc7fSGatien Chevallier 	},
1157e419bc7fSGatien Chevallier 	{
1158e419bc7fSGatien Chevallier 		.compatible = "st,stm32mp1-rtc",
1159e419bc7fSGatien Chevallier 		.compat_data = &mp15_compat,
1160e419bc7fSGatien Chevallier 	},
1161e419bc7fSGatien Chevallier 	{
1162e419bc7fSGatien Chevallier 		.compatible = "st,stm32mp13-rtc",
1163e419bc7fSGatien Chevallier 		.compat_data = &mp13_compat,
1164e419bc7fSGatien Chevallier 	},
1165e419bc7fSGatien Chevallier 	{ }
1166e419bc7fSGatien Chevallier };
1167e419bc7fSGatien Chevallier 
1168e419bc7fSGatien Chevallier DEFINE_DT_DRIVER(stm32_rtc_dt_driver) = {
1169e419bc7fSGatien Chevallier 	.name = "stm32-rtc",
1170e419bc7fSGatien Chevallier 	.match_table = stm32_rtc_match_table,
1171e419bc7fSGatien Chevallier 	.probe = stm32_rtc_probe,
1172e419bc7fSGatien Chevallier };
1173