xref: /optee_os/core/drivers/stm32_rtc.c (revision 446da993cb4b9f98a53fd938507162b23e09b7ce)
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>
9e419bc7fSGatien Chevallier #include <drivers/stm32_rif.h>
10d60c61e1SGatien Chevallier #include <drivers/stm32_rtc.h>
11e419bc7fSGatien Chevallier #include <io.h>
12e419bc7fSGatien Chevallier #include <kernel/dt.h>
13e419bc7fSGatien Chevallier #include <kernel/dt_driver.h>
14e419bc7fSGatien Chevallier #include <kernel/panic.h>
15d60c61e1SGatien Chevallier #include <kernel/spinlock.h>
16e419bc7fSGatien Chevallier #include <libfdt.h>
17e419bc7fSGatien Chevallier #include <mm/core_memprot.h>
18e419bc7fSGatien Chevallier 
19e419bc7fSGatien Chevallier /*
20e419bc7fSGatien Chevallier  * Registers
21e419bc7fSGatien Chevallier  */
22e419bc7fSGatien Chevallier #define RTC_TR				U(0x00)
23e419bc7fSGatien Chevallier #define RTC_DR				U(0x04)
24e419bc7fSGatien Chevallier #define RTC_SSR				U(0x08)
25e419bc7fSGatien Chevallier #define RTC_ICSR			U(0x0C)
26e419bc7fSGatien Chevallier #define RTC_PRER			U(0x10)
27e419bc7fSGatien Chevallier #define RTC_WUTR			U(0x14)
28e419bc7fSGatien Chevallier #define RTC_CR				U(0x18)
29e419bc7fSGatien Chevallier #define RTC_PRIVCFGR			U(0x1C)
30e419bc7fSGatien Chevallier /* RTC_SMCR is linked to RTC3v1_2 */
31e419bc7fSGatien Chevallier #define RTC_SMCR			U(0x20)
32e419bc7fSGatien Chevallier /* RTC_SECCFGR is linked to RTC3v3_2 and above */
33e419bc7fSGatien Chevallier #define RTC_SECCFGR			U(0x20)
34e419bc7fSGatien Chevallier #define RTC_WPR				U(0x24)
35e419bc7fSGatien Chevallier #define RTC_CALR			U(0x28)
36e419bc7fSGatien Chevallier #define RTC_SHIFTR			U(0x2C)
37e419bc7fSGatien Chevallier #define RTC_TSTR			U(0x30)
38e419bc7fSGatien Chevallier #define RTC_TSDR			U(0x34)
39e419bc7fSGatien Chevallier #define RTC_TSSSR			U(0x38)
40e419bc7fSGatien Chevallier #define RTC_ALRMAR			U(0x40)
41e419bc7fSGatien Chevallier #define RTC_ALRMASSR			U(0x44)
42e419bc7fSGatien Chevallier #define RTC_ALRMBR			U(0x48)
43e419bc7fSGatien Chevallier #define RTC_ALRMBSSR			U(0x4C)
44e419bc7fSGatien Chevallier #define RTC_SR				U(0x50)
45e419bc7fSGatien Chevallier #define RTC_SCR				U(0x5C)
46e419bc7fSGatien Chevallier #define RTC_OR				U(0x60)
47e419bc7fSGatien Chevallier #define RTC_CIDCFGR(x)			(U(0x80) + U(0x4) * (x))
48e419bc7fSGatien Chevallier 
49e419bc7fSGatien Chevallier #define RTC_TR_SU_MASK			GENMASK_32(3, 0)
50e419bc7fSGatien Chevallier #define RTC_TR_ST_MASK			GENMASK_32(6, 4)
51e419bc7fSGatien Chevallier #define RTC_TR_ST_SHIFT			U(4)
52e419bc7fSGatien Chevallier #define RTC_TR_MNU_MASK			GENMASK_32(11, 8)
53e419bc7fSGatien Chevallier #define RTC_TR_MNU_SHIFT		U(8)
54e419bc7fSGatien Chevallier #define RTC_TR_MNT_MASK			GENMASK_32(14, 12)
55e419bc7fSGatien Chevallier #define RTC_TR_MNT_SHIFT		U(12)
56e419bc7fSGatien Chevallier #define RTC_TR_HU_MASK			GENMASK_32(19, 16)
57e419bc7fSGatien Chevallier #define RTC_TR_HU_SHIFT			U(16)
58e419bc7fSGatien Chevallier #define RTC_TR_HT_MASK			GENMASK_32(21, 20)
59e419bc7fSGatien Chevallier #define RTC_TR_HT_SHIFT			U(20)
60e419bc7fSGatien Chevallier #define RTC_TR_PM			BIT(22)
61e419bc7fSGatien Chevallier 
62e419bc7fSGatien Chevallier #define RTC_DR_DU_MASK			GENMASK_32(3, 0)
63e419bc7fSGatien Chevallier #define RTC_DR_DT_MASK			GENMASK_32(5, 4)
64e419bc7fSGatien Chevallier #define RTC_DR_DT_SHIFT			U(4)
65e419bc7fSGatien Chevallier #define RTC_DR_MU_MASK			GENMASK_32(11, 8)
66e419bc7fSGatien Chevallier #define RTC_DR_MU_SHIFT			U(8)
67e419bc7fSGatien Chevallier #define RTC_DR_MT_MASK			BIT(12)
68e419bc7fSGatien Chevallier #define RTC_DR_MT_SHIFT			U(12)
69e419bc7fSGatien Chevallier #define RTC_DR_WDU_MASK			GENMASK_32(15, 13)
70e419bc7fSGatien Chevallier #define RTC_DR_WDU_SHIFT		U(13)
71e419bc7fSGatien Chevallier #define RTC_DR_YU_MASK			GENMASK_32(19, 16)
72e419bc7fSGatien Chevallier #define RTC_DR_YU_SHIFT			U(16)
73e419bc7fSGatien Chevallier #define RTC_DR_YT_MASK			GENMASK_32(23, 20)
74e419bc7fSGatien Chevallier #define RTC_DR_YT_SHIFT			U(20)
75e419bc7fSGatien Chevallier 
76e419bc7fSGatien Chevallier #define RTC_SSR_SS_MASK			GENMASK_32(15, 0)
77e419bc7fSGatien Chevallier 
78e419bc7fSGatien Chevallier #define RTC_ICSR_RSF			BIT(5)
79e419bc7fSGatien Chevallier #define RTC_ICSR_INITF			BIT(6)
80e419bc7fSGatien Chevallier #define RTC_ICSR_INIT			BIT(7)
81e419bc7fSGatien Chevallier 
82*446da993SClément Le Goffic #define RTC_PRER_PREDIV_S_SHIFT		U(0)
83e419bc7fSGatien Chevallier #define RTC_PRER_PREDIV_S_MASK		GENMASK_32(14, 0)
84*446da993SClément Le Goffic #define RTC_PRER_PREDIV_A_SHIFT		U(16)
85*446da993SClément Le Goffic #define RTC_PRER_PREDIV_A_MASK		GENMASK_32(22, 16)
86e419bc7fSGatien Chevallier 
87e419bc7fSGatien Chevallier #define RTC_CR_BYPSHAD			BIT(5)
88e419bc7fSGatien Chevallier #define RTC_CR_BYPSHAD_SHIFT		U(5)
89*446da993SClément Le Goffic #define RTC_CR_FMT			BIT(6)
90e419bc7fSGatien Chevallier #define RTC_CR_TAMPTS			BIT(25)
91e419bc7fSGatien Chevallier 
92e419bc7fSGatien Chevallier #define RTC_PRIVCFGR_VALUES		GENMASK_32(3, 0)
93e419bc7fSGatien Chevallier #define RTC_PRIVCFGR_VALUES_TO_SHIFT	GENMASK_32(5, 4)
94e419bc7fSGatien Chevallier #define RTC_PRIVCFGR_SHIFT		U(9)
95e419bc7fSGatien Chevallier #define RTC_PRIVCFGR_MASK		(GENMASK_32(14, 13) | GENMASK_32(3, 0))
96e419bc7fSGatien Chevallier #define RTC_PRIVCFGR_FULL_PRIV		BIT(15)
97e419bc7fSGatien Chevallier 
98e419bc7fSGatien Chevallier #define RTC_SMCR_TS_DPROT		BIT(3)
99e419bc7fSGatien Chevallier 
100e419bc7fSGatien Chevallier #define RTC_SECCFGR_VALUES		GENMASK_32(3, 0)
101e419bc7fSGatien Chevallier #define RTC_SECCFGR_TS_SEC		BIT(3)
102e419bc7fSGatien Chevallier #define RTC_SECCFGR_VALUES_TO_SHIFT	GENMASK_32(5, 4)
103e419bc7fSGatien Chevallier #define RTC_SECCFGR_SHIFT		U(9)
104e419bc7fSGatien Chevallier #define RTC_SECCFGR_MASK		(GENMASK_32(14, 13) | GENMASK_32(3, 0))
105e419bc7fSGatien Chevallier #define RTC_SECCFGR_FULL_SEC		BIT(15)
106e419bc7fSGatien Chevallier 
107e419bc7fSGatien Chevallier #define RTC_WPR_KEY1			U(0xCA)
108e419bc7fSGatien Chevallier #define RTC_WPR_KEY2			U(0x53)
109e419bc7fSGatien Chevallier #define RTC_WPR_KEY_LOCK		U(0xFF)
110e419bc7fSGatien Chevallier 
111e419bc7fSGatien Chevallier #define RTC_TSDR_MU_MASK		GENMASK_32(11, 8)
112e419bc7fSGatien Chevallier #define RTC_TSDR_MU_SHIFT		U(8)
113e419bc7fSGatien Chevallier #define RTC_TSDR_DT_MASK		GENMASK_32(5, 4)
114e419bc7fSGatien Chevallier #define RTC_TSDR_DT_SHIFT		U(4)
115e419bc7fSGatien Chevallier #define RTC_TSDR_DU_MASK		GENMASK_32(3, 0)
116e419bc7fSGatien Chevallier #define RTC_TSDR_DU_SHIFT		U(0)
117e419bc7fSGatien Chevallier 
118e419bc7fSGatien Chevallier #define RTC_SR_TSF			BIT(3)
119e419bc7fSGatien Chevallier #define RTC_SR_TSOVF			BIT(4)
120e419bc7fSGatien Chevallier 
121e419bc7fSGatien Chevallier #define RTC_SCR_CTSF			BIT(3)
122e419bc7fSGatien Chevallier #define RTC_SCR_CTSOVF			BIT(4)
123e419bc7fSGatien Chevallier 
124e419bc7fSGatien Chevallier #define RTC_CIDCFGR_SCID_MASK		GENMASK_32(6, 4)
125e419bc7fSGatien Chevallier #define RTC_CIDCFGR_SCID_MASK_SHIFT	U(4)
126e419bc7fSGatien Chevallier #define RTC_CIDCFGR_CONF_MASK		(_CIDCFGR_CFEN |	 \
127e419bc7fSGatien Chevallier 					 RTC_CIDCFGR_SCID_MASK)
128e419bc7fSGatien Chevallier 
129e419bc7fSGatien Chevallier /*
130e419bc7fSGatien Chevallier  * RIF miscellaneous
131e419bc7fSGatien Chevallier  */
132e419bc7fSGatien Chevallier #define RTC_NB_RIF_RESOURCES		U(6)
133e419bc7fSGatien Chevallier 
134e419bc7fSGatien Chevallier #define RTC_RIF_FULL_PRIVILEGED		U(0x3F)
135e419bc7fSGatien Chevallier #define RTC_RIF_FULL_SECURED		U(0x3F)
136e419bc7fSGatien Chevallier 
137e419bc7fSGatien Chevallier #define RTC_NB_MAX_CID_SUPPORTED	U(7)
138e419bc7fSGatien Chevallier 
139e419bc7fSGatien Chevallier /*
140e419bc7fSGatien Chevallier  * Driver miscellaneous
141e419bc7fSGatien Chevallier  */
142e419bc7fSGatien Chevallier #define RTC_RES_TIMESTAMP		U(3)
143e419bc7fSGatien Chevallier #define RTC_RES_CALIBRATION		U(4)
144e419bc7fSGatien Chevallier #define RTC_RES_INITIALIZATION		U(5)
145e419bc7fSGatien Chevallier 
146e419bc7fSGatien Chevallier #define RTC_FLAGS_READ_TWICE		BIT(0)
147e419bc7fSGatien Chevallier 
148e419bc7fSGatien Chevallier #define TIMEOUT_US_RTC_SHADOW		U(10000)
149e419bc7fSGatien Chevallier #define TIMEOUT_US_RTC_GENERIC		U(100000)
150e419bc7fSGatien Chevallier 
151e419bc7fSGatien Chevallier #define YEAR_REF			ULL(2000)
152e419bc7fSGatien Chevallier #define YEAR_MAX			(YEAR_REF + ULL(99))
153e419bc7fSGatien Chevallier 
154e419bc7fSGatien Chevallier struct rtc_compat {
155e419bc7fSGatien Chevallier 	bool has_seccfgr;
156e419bc7fSGatien Chevallier 	bool has_rif_support;
157e419bc7fSGatien Chevallier };
158e419bc7fSGatien Chevallier 
159e419bc7fSGatien Chevallier /*
160e419bc7fSGatien Chevallier  * struct rtc_device - RTC device data
161e419bc7fSGatien Chevallier  * @base: RTC IOMEM base address
162e419bc7fSGatien Chevallier  * @compat: RTC compatible data
163e419bc7fSGatien Chevallier  * @pclk: RTC bus clock
164e419bc7fSGatien Chevallier  * @rtc_ck: RTC kernel clock
165e419bc7fSGatien Chevallier  * @conf_data: RTC RIF configuration data, when supported
166e419bc7fSGatien Chevallier  * @nb_res: Number of protectible RTC resources
167d60c61e1SGatien Chevallier  * @ts_lock: Lock used for time stamping events handling
168e419bc7fSGatien Chevallier  * @flags: RTC driver flags
169e419bc7fSGatien Chevallier  * @is_secured: True if the RTC is fully secured
170e419bc7fSGatien Chevallier  */
171e419bc7fSGatien Chevallier struct rtc_device {
172e419bc7fSGatien Chevallier 	struct io_pa_va base;
173e419bc7fSGatien Chevallier 	const struct rtc_compat *compat;
174e419bc7fSGatien Chevallier 	struct clk *pclk;
175e419bc7fSGatien Chevallier 	struct clk *rtc_ck;
176e419bc7fSGatien Chevallier 	struct rif_conf_data *conf_data;
177e419bc7fSGatien Chevallier 	unsigned int nb_res;
178d60c61e1SGatien Chevallier 	unsigned int ts_lock;
179e419bc7fSGatien Chevallier 	uint8_t flags;
180e419bc7fSGatien Chevallier 	bool is_secured;
181e419bc7fSGatien Chevallier };
182e419bc7fSGatien Chevallier 
183e419bc7fSGatien Chevallier /* Expect a single RTC instance */
184e419bc7fSGatien Chevallier static struct rtc_device rtc_dev;
185e419bc7fSGatien Chevallier 
186e419bc7fSGatien Chevallier static vaddr_t get_base(void)
187e419bc7fSGatien Chevallier {
188e419bc7fSGatien Chevallier 	assert(rtc_dev.base.pa);
189e419bc7fSGatien Chevallier 
190e419bc7fSGatien Chevallier 	return io_pa_or_va(&rtc_dev.base, 1);
191e419bc7fSGatien Chevallier }
192e419bc7fSGatien Chevallier 
193e419bc7fSGatien Chevallier static void stm32_rtc_write_unprotect(void)
194e419bc7fSGatien Chevallier {
195e419bc7fSGatien Chevallier 	vaddr_t rtc_base = get_base();
196e419bc7fSGatien Chevallier 
197e419bc7fSGatien Chevallier 	io_write32(rtc_base + RTC_WPR, RTC_WPR_KEY1);
198e419bc7fSGatien Chevallier 	io_write32(rtc_base + RTC_WPR, RTC_WPR_KEY2);
199e419bc7fSGatien Chevallier }
200e419bc7fSGatien Chevallier 
201e419bc7fSGatien Chevallier static void stm32_rtc_write_protect(void)
202e419bc7fSGatien Chevallier {
203e419bc7fSGatien Chevallier 	vaddr_t rtc_base = get_base();
204e419bc7fSGatien Chevallier 
205e419bc7fSGatien Chevallier 	io_write32(rtc_base + RTC_WPR, RTC_WPR_KEY_LOCK);
206e419bc7fSGatien Chevallier }
207e419bc7fSGatien Chevallier 
208e419bc7fSGatien Chevallier static bool stm32_rtc_get_bypshad(void)
209e419bc7fSGatien Chevallier {
210e419bc7fSGatien Chevallier 	return io_read32(get_base() + RTC_CR) & RTC_CR_BYPSHAD;
211e419bc7fSGatien Chevallier }
212e419bc7fSGatien Chevallier 
213e419bc7fSGatien Chevallier /* Get the subsecond value. */
214e419bc7fSGatien Chevallier static uint32_t stm32_rtc_get_subsecond(uint32_t ssr)
215e419bc7fSGatien Chevallier {
216e419bc7fSGatien Chevallier 	uint32_t prediv_s = io_read32(get_base() + RTC_PRER) &
217e419bc7fSGatien Chevallier 			    RTC_PRER_PREDIV_S_MASK;
218e419bc7fSGatien Chevallier 
219e419bc7fSGatien Chevallier 	return prediv_s - ssr;
220e419bc7fSGatien Chevallier }
221e419bc7fSGatien Chevallier 
222e419bc7fSGatien Chevallier /*
223e419bc7fSGatien Chevallier  * Get the subsecond scale.
224e419bc7fSGatien Chevallier  *
225e419bc7fSGatien Chevallier  * Number of subseconds in a second is linked to RTC PREDIV_S value.
226e419bc7fSGatien Chevallier  * The higher PREDIV_S is, the more subsecond is precise.
227e419bc7fSGatien Chevallier  */
228e419bc7fSGatien Chevallier static uint32_t stm32_rtc_get_subsecond_scale(void)
229e419bc7fSGatien Chevallier {
230e419bc7fSGatien Chevallier 	return (io_read32(get_base() + RTC_PRER) & RTC_PRER_PREDIV_S_MASK) + 1;
231e419bc7fSGatien Chevallier }
232e419bc7fSGatien Chevallier 
233e419bc7fSGatien Chevallier static bool cid1_has_access(unsigned int resource)
234e419bc7fSGatien Chevallier {
235e419bc7fSGatien Chevallier 	uint32_t cidcfgr = io_read32(get_base() + RTC_CIDCFGR(resource));
236e419bc7fSGatien Chevallier 
237e419bc7fSGatien Chevallier 	return !(cidcfgr & _CIDCFGR_CFEN) ||
238e419bc7fSGatien Chevallier 	       get_field_u32(cidcfgr, RTC_CIDCFGR_SCID_MASK) == RIF_CID1;
239e419bc7fSGatien Chevallier }
240e419bc7fSGatien Chevallier 
241e419bc7fSGatien Chevallier static TEE_Result check_rif_config(void)
242e419bc7fSGatien Chevallier {
243e419bc7fSGatien Chevallier 	if (!cid1_has_access(RTC_RES_TIMESTAMP) ||
244e419bc7fSGatien Chevallier 	    !cid1_has_access(RTC_RES_CALIBRATION) ||
245e419bc7fSGatien Chevallier 	    !cid1_has_access(RTC_RES_INITIALIZATION))
246e419bc7fSGatien Chevallier 		return TEE_ERROR_ACCESS_DENIED;
247e419bc7fSGatien Chevallier 
248e419bc7fSGatien Chevallier 	return TEE_SUCCESS;
249e419bc7fSGatien Chevallier }
250e419bc7fSGatien Chevallier 
251e419bc7fSGatien Chevallier static void apply_rif_config(bool is_tdcid)
252e419bc7fSGatien Chevallier {
253e419bc7fSGatien Chevallier 	vaddr_t base = get_base();
254e419bc7fSGatien Chevallier 	unsigned int shifted_values = 0;
255e419bc7fSGatien Chevallier 	uint32_t seccfgr = 0;
256e419bc7fSGatien Chevallier 	uint32_t privcfgr = 0;
257e419bc7fSGatien Chevallier 	uint32_t access_mask_reg = 0;
258e419bc7fSGatien Chevallier 	unsigned int i = 0;
259e419bc7fSGatien Chevallier 
260e419bc7fSGatien Chevallier 	if (!rtc_dev.conf_data)
261e419bc7fSGatien Chevallier 		return;
262e419bc7fSGatien Chevallier 
263e419bc7fSGatien Chevallier 	/* Build access mask for RTC_SECCFGR and RTC_PRIVCFGR */
264e419bc7fSGatien Chevallier 	for (i = 0; i < RTC_NB_RIF_RESOURCES; i++) {
265e419bc7fSGatien Chevallier 		if (rtc_dev.conf_data->access_mask[0] & BIT(i)) {
266e419bc7fSGatien Chevallier 			if (i <= RTC_RES_TIMESTAMP)
267e419bc7fSGatien Chevallier 				access_mask_reg |= BIT(i);
268e419bc7fSGatien Chevallier 			else
269e419bc7fSGatien Chevallier 				access_mask_reg |= BIT(i) << RTC_SECCFGR_SHIFT;
270e419bc7fSGatien Chevallier 		}
271e419bc7fSGatien Chevallier 	}
272e419bc7fSGatien Chevallier 
273e419bc7fSGatien Chevallier 	for (i = 0; i < RTC_NB_RIF_RESOURCES; i++) {
274e419bc7fSGatien Chevallier 		if (!(BIT(i) & rtc_dev.conf_data->access_mask[0]))
275e419bc7fSGatien Chevallier 			continue;
276e419bc7fSGatien Chevallier 
277e419bc7fSGatien Chevallier 		/*
278e419bc7fSGatien Chevallier 		 * When TDCID, OP-TEE should be the one to set the CID filtering
279e419bc7fSGatien Chevallier 		 * configuration. Clearing previous configuration prevents
280e419bc7fSGatien Chevallier 		 * undesired events during the only legitimate configuration.
281e419bc7fSGatien Chevallier 		 */
282e419bc7fSGatien Chevallier 		if (is_tdcid)
283e419bc7fSGatien Chevallier 			io_clrbits32(base + RTC_CIDCFGR(i),
284e419bc7fSGatien Chevallier 				     RTC_CIDCFGR_CONF_MASK);
285e419bc7fSGatien Chevallier 	}
286e419bc7fSGatien Chevallier 
287e419bc7fSGatien Chevallier 	/* Security RIF configuration */
288e419bc7fSGatien Chevallier 	seccfgr = rtc_dev.conf_data->sec_conf[0];
289e419bc7fSGatien Chevallier 
290e419bc7fSGatien Chevallier 	/* Check if all resources must be secured */
291e419bc7fSGatien Chevallier 	if (seccfgr == RTC_RIF_FULL_SECURED) {
292e419bc7fSGatien Chevallier 		io_setbits32(base + RTC_SECCFGR, RTC_SECCFGR_FULL_SEC);
293e419bc7fSGatien Chevallier 		rtc_dev.is_secured = true;
294e419bc7fSGatien Chevallier 
295e419bc7fSGatien Chevallier 		if (!(io_read32(base + RTC_SECCFGR) & RTC_SECCFGR_FULL_SEC))
296e419bc7fSGatien Chevallier 			panic("Bad RTC seccfgr configuration");
297e419bc7fSGatien Chevallier 	}
298e419bc7fSGatien Chevallier 
299e419bc7fSGatien Chevallier 	/* Shift some values to align with the register */
300e419bc7fSGatien Chevallier 	shifted_values = SHIFT_U32(seccfgr & RTC_SECCFGR_VALUES_TO_SHIFT,
301e419bc7fSGatien Chevallier 				   RTC_SECCFGR_SHIFT);
302e419bc7fSGatien Chevallier 	seccfgr = (seccfgr & RTC_SECCFGR_VALUES) + shifted_values;
303e419bc7fSGatien Chevallier 
304e419bc7fSGatien Chevallier 	io_clrsetbits32(base + RTC_SECCFGR,
305e419bc7fSGatien Chevallier 			RTC_SECCFGR_MASK & access_mask_reg, seccfgr);
306e419bc7fSGatien Chevallier 
307e419bc7fSGatien Chevallier 	/* Privilege RIF configuration */
308e419bc7fSGatien Chevallier 	privcfgr = rtc_dev.conf_data->priv_conf[0];
309e419bc7fSGatien Chevallier 
310e419bc7fSGatien Chevallier 	/* Check if all resources must be privileged */
311e419bc7fSGatien Chevallier 	if (privcfgr == RTC_RIF_FULL_PRIVILEGED) {
312e419bc7fSGatien Chevallier 		io_setbits32(base + RTC_PRIVCFGR, RTC_PRIVCFGR_FULL_PRIV);
313e419bc7fSGatien Chevallier 
314e419bc7fSGatien Chevallier 		if (!(io_read32(base + RTC_PRIVCFGR) & RTC_PRIVCFGR_FULL_PRIV))
315e419bc7fSGatien Chevallier 			panic("Bad RTC privcfgr configuration");
316e419bc7fSGatien Chevallier 	}
317e419bc7fSGatien Chevallier 
318e419bc7fSGatien Chevallier 	/* Shift some values to align with the register */
319e419bc7fSGatien Chevallier 	shifted_values = SHIFT_U32(privcfgr & RTC_PRIVCFGR_VALUES_TO_SHIFT,
320e419bc7fSGatien Chevallier 				   RTC_PRIVCFGR_SHIFT);
321e419bc7fSGatien Chevallier 	privcfgr = (privcfgr & RTC_PRIVCFGR_VALUES) + shifted_values;
322e419bc7fSGatien Chevallier 
323e419bc7fSGatien Chevallier 	io_clrsetbits32(base + RTC_PRIVCFGR,
324e419bc7fSGatien Chevallier 			RTC_PRIVCFGR_MASK & access_mask_reg, privcfgr);
325e419bc7fSGatien Chevallier 
326e419bc7fSGatien Chevallier 	if (!is_tdcid)
327e419bc7fSGatien Chevallier 		return;
328e419bc7fSGatien Chevallier 
329e419bc7fSGatien Chevallier 	for (i = 0; i < RTC_NB_RIF_RESOURCES; i++) {
330e419bc7fSGatien Chevallier 		if (!(BIT(i) & rtc_dev.conf_data->access_mask[0]))
331e419bc7fSGatien Chevallier 			continue;
332e419bc7fSGatien Chevallier 		/*
333e419bc7fSGatien Chevallier 		 * When at least one resource has CID filtering enabled,
334e419bc7fSGatien Chevallier 		 * the RTC_PRIVCFGR_FULL_PRIV and RTC_SECCFGR_FULL_SEC bits are
335e419bc7fSGatien Chevallier 		 * cleared.
336e419bc7fSGatien Chevallier 		 */
337e419bc7fSGatien Chevallier 		io_clrsetbits32(base + RTC_CIDCFGR(i),
338e419bc7fSGatien Chevallier 				RTC_CIDCFGR_CONF_MASK,
339e419bc7fSGatien Chevallier 				rtc_dev.conf_data->cid_confs[i]);
340e419bc7fSGatien Chevallier 	}
341e419bc7fSGatien Chevallier }
342e419bc7fSGatien Chevallier 
343e419bc7fSGatien Chevallier static TEE_Result parse_dt(const void *fdt, int node)
344e419bc7fSGatien Chevallier {
345e419bc7fSGatien Chevallier 	TEE_Result res = TEE_ERROR_GENERIC;
346e419bc7fSGatien Chevallier 	const fdt32_t *cuint = NULL;
347e419bc7fSGatien Chevallier 	size_t reg_size = 0;
348e419bc7fSGatien Chevallier 	unsigned int i = 0;
349e419bc7fSGatien Chevallier 	int lenp = 0;
350e419bc7fSGatien Chevallier 
351e419bc7fSGatien Chevallier 	if (fdt_reg_info(fdt, node, &rtc_dev.base.pa, &reg_size))
352e419bc7fSGatien Chevallier 		panic();
353e419bc7fSGatien Chevallier 
354e419bc7fSGatien Chevallier 	io_pa_or_va(&rtc_dev.base, reg_size);
355e419bc7fSGatien Chevallier 	assert(rtc_dev.base.va);
356e419bc7fSGatien Chevallier 
357e419bc7fSGatien Chevallier 	res = clk_dt_get_by_name(fdt, node, "pclk", &rtc_dev.pclk);
358e419bc7fSGatien Chevallier 	if (res)
359e419bc7fSGatien Chevallier 		return res;
360e419bc7fSGatien Chevallier 
361e419bc7fSGatien Chevallier 	res = clk_dt_get_by_name(fdt, node, "rtc_ck", &rtc_dev.rtc_ck);
362e419bc7fSGatien Chevallier 	if (res)
363e419bc7fSGatien Chevallier 		return res;
364e419bc7fSGatien Chevallier 
365e419bc7fSGatien Chevallier 	if (!rtc_dev.compat->has_rif_support)
366e419bc7fSGatien Chevallier 		return TEE_SUCCESS;
367e419bc7fSGatien Chevallier 
368e419bc7fSGatien Chevallier 	cuint = fdt_getprop(fdt, node, "st,protreg", &lenp);
369e419bc7fSGatien Chevallier 	if (!cuint) {
370e419bc7fSGatien Chevallier 		DMSG("No RIF configuration available");
371e419bc7fSGatien Chevallier 		return TEE_SUCCESS;
372e419bc7fSGatien Chevallier 	}
373e419bc7fSGatien Chevallier 
374e419bc7fSGatien Chevallier 	rtc_dev.conf_data = calloc(1, sizeof(*rtc_dev.conf_data));
375e419bc7fSGatien Chevallier 	if (!rtc_dev.conf_data)
376e419bc7fSGatien Chevallier 		panic();
377e419bc7fSGatien Chevallier 
378e419bc7fSGatien Chevallier 	rtc_dev.nb_res = (unsigned int)(lenp / sizeof(uint32_t));
379e419bc7fSGatien Chevallier 	assert(rtc_dev.nb_res <= RTC_NB_RIF_RESOURCES);
380e419bc7fSGatien Chevallier 
381e419bc7fSGatien Chevallier 	rtc_dev.conf_data->cid_confs = calloc(RTC_NB_RIF_RESOURCES,
382e419bc7fSGatien Chevallier 					      sizeof(uint32_t));
383e419bc7fSGatien Chevallier 	rtc_dev.conf_data->sec_conf = calloc(1, sizeof(uint32_t));
384e419bc7fSGatien Chevallier 	rtc_dev.conf_data->priv_conf = calloc(1, sizeof(uint32_t));
385e419bc7fSGatien Chevallier 	rtc_dev.conf_data->access_mask = calloc(1, sizeof(uint32_t));
386e419bc7fSGatien Chevallier 	if (!rtc_dev.conf_data->cid_confs || !rtc_dev.conf_data->sec_conf ||
387e419bc7fSGatien Chevallier 	    !rtc_dev.conf_data->priv_conf || !rtc_dev.conf_data->access_mask)
388e419bc7fSGatien Chevallier 		panic("Not enough memory capacity for RTC RIF config");
389e419bc7fSGatien Chevallier 
390e419bc7fSGatien Chevallier 	for (i = 0; i < rtc_dev.nb_res; i++)
391e419bc7fSGatien Chevallier 		stm32_rif_parse_cfg(fdt32_to_cpu(cuint[i]), rtc_dev.conf_data,
392e419bc7fSGatien Chevallier 				    RTC_NB_RIF_RESOURCES);
393e419bc7fSGatien Chevallier 
394e419bc7fSGatien Chevallier 	return TEE_SUCCESS;
395e419bc7fSGatien Chevallier }
396e419bc7fSGatien Chevallier 
397e419bc7fSGatien Chevallier static TEE_Result stm32_rtc_enter_init_mode(void)
398e419bc7fSGatien Chevallier {
399e419bc7fSGatien Chevallier 	vaddr_t base = get_base();
400e419bc7fSGatien Chevallier 	uint32_t icsr = io_read32(base + RTC_ICSR);
401e419bc7fSGatien Chevallier 	uint32_t value = 0;
402e419bc7fSGatien Chevallier 
403e419bc7fSGatien Chevallier 	if (!(icsr & RTC_ICSR_INITF)) {
404e419bc7fSGatien Chevallier 		icsr |= RTC_ICSR_INIT;
405e419bc7fSGatien Chevallier 		io_write32(base + RTC_ICSR, icsr);
406e419bc7fSGatien Chevallier 
407e419bc7fSGatien Chevallier 		if (IO_READ32_POLL_TIMEOUT(base + RTC_ICSR, value,
408e419bc7fSGatien Chevallier 					   value & RTC_ICSR_INITF,
409e419bc7fSGatien Chevallier 					   10, TIMEOUT_US_RTC_GENERIC))
410e419bc7fSGatien Chevallier 			return TEE_ERROR_BUSY;
411e419bc7fSGatien Chevallier 	}
412e419bc7fSGatien Chevallier 
413e419bc7fSGatien Chevallier 	return TEE_SUCCESS;
414e419bc7fSGatien Chevallier }
415e419bc7fSGatien Chevallier 
416*446da993SClément Le Goffic static TEE_Result stm32_rtc_exit_init_mode(void)
417e419bc7fSGatien Chevallier {
418e419bc7fSGatien Chevallier 	vaddr_t base = get_base();
419e419bc7fSGatien Chevallier 	uint32_t value = 0;
420e419bc7fSGatien Chevallier 
421*446da993SClément Le Goffic 	io_clrbits32(base + RTC_ICSR, RTC_ICSR_INIT);
422*446da993SClément Le Goffic 	dsb();
423*446da993SClément Le Goffic 
424e419bc7fSGatien Chevallier 	io_clrbits32(base + RTC_ICSR, RTC_ICSR_RSF);
425e419bc7fSGatien Chevallier 
426e419bc7fSGatien Chevallier 	if (IO_READ32_POLL_TIMEOUT(base + RTC_ICSR, value,
427e419bc7fSGatien Chevallier 				   value & RTC_ICSR_RSF, 10,
428e419bc7fSGatien Chevallier 				   TIMEOUT_US_RTC_GENERIC))
429e419bc7fSGatien Chevallier 		return TEE_ERROR_BUSY;
430e419bc7fSGatien Chevallier 
431e419bc7fSGatien Chevallier 	return TEE_SUCCESS;
432e419bc7fSGatien Chevallier }
433e419bc7fSGatien Chevallier 
434d60c61e1SGatien Chevallier static void stm32_rtc_to_tm(uint32_t ssr, uint32_t tr, uint32_t dr,
435d60c61e1SGatien Chevallier 			    struct optee_rtc_time *tm)
436d60c61e1SGatien Chevallier {
437d60c61e1SGatien Chevallier 	tm->tm_hour = ((tr & RTC_TR_HT_MASK) >> RTC_TR_HT_SHIFT) * 10 +
438d60c61e1SGatien Chevallier 		      ((tr & RTC_TR_HU_MASK) >> RTC_TR_HU_SHIFT);
439d60c61e1SGatien Chevallier 
440d60c61e1SGatien Chevallier 	if (tr & RTC_TR_PM)
441d60c61e1SGatien Chevallier 		tm->tm_hour += 12;
442d60c61e1SGatien Chevallier 
443d60c61e1SGatien Chevallier 	tm->tm_ms = (stm32_rtc_get_subsecond(ssr) * MS_PER_SEC) /
444d60c61e1SGatien Chevallier 		    stm32_rtc_get_subsecond_scale();
445d60c61e1SGatien Chevallier 
446d60c61e1SGatien Chevallier 	tm->tm_sec = ((tr & RTC_TR_ST_MASK) >> RTC_TR_ST_SHIFT) * 10 +
447d60c61e1SGatien Chevallier 		     (tr & RTC_TR_SU_MASK);
448d60c61e1SGatien Chevallier 
449d60c61e1SGatien Chevallier 	tm->tm_min = ((tr & RTC_TR_MNT_MASK) >> RTC_TR_MNT_SHIFT) * 10 +
450d60c61e1SGatien Chevallier 		     ((tr & RTC_TR_MNU_MASK) >> RTC_TR_MNU_SHIFT);
451d60c61e1SGatien Chevallier 
452d60c61e1SGatien Chevallier 	tm->tm_wday = ((dr & RTC_DR_WDU_MASK) >> RTC_DR_WDU_SHIFT) % 7;
453d60c61e1SGatien Chevallier 
454d60c61e1SGatien Chevallier 	tm->tm_mday = ((dr & RTC_DR_DT_MASK) >> RTC_DR_DT_SHIFT) * 10 +
455d60c61e1SGatien Chevallier 		      (dr & RTC_DR_DU_MASK);
456d60c61e1SGatien Chevallier 
457d60c61e1SGatien Chevallier 	tm->tm_mon = ((dr & RTC_DR_MT_MASK) >> RTC_DR_MT_SHIFT) * 10 +
458d60c61e1SGatien Chevallier 		     ((dr & RTC_DR_MU_MASK) >> RTC_DR_MU_SHIFT) - 1;
459d60c61e1SGatien Chevallier 
460d60c61e1SGatien Chevallier 	tm->tm_year = ((dr & RTC_DR_YT_MASK) >> RTC_DR_YT_SHIFT) * 10 +
461d60c61e1SGatien Chevallier 		      ((dr & RTC_DR_YU_MASK) >> RTC_DR_YU_SHIFT) + YEAR_REF;
462d60c61e1SGatien Chevallier }
463d60c61e1SGatien Chevallier 
464*446da993SClément Le Goffic static TEE_Result stm32_rtc_init(void)
465*446da993SClément Le Goffic {
466*446da993SClément Le Goffic 	uint32_t pred_a_max = RTC_PRER_PREDIV_A_MASK >> RTC_PRER_PREDIV_A_SHIFT;
467*446da993SClément Le Goffic 	uint32_t pred_s_max = RTC_PRER_PREDIV_S_MASK >> RTC_PRER_PREDIV_S_SHIFT;
468*446da993SClément Le Goffic 	unsigned long rate = clk_get_rate(rtc_dev.rtc_ck);
469*446da993SClément Le Goffic 	TEE_Result res = TEE_ERROR_GENERIC;
470*446da993SClément Le Goffic 	vaddr_t base = get_base();
471*446da993SClément Le Goffic 	uint32_t pred_a = 0;
472*446da993SClément Le Goffic 	uint32_t pred_s = 0;
473*446da993SClément Le Goffic 	uint32_t prer = io_read32(base + RTC_PRER);
474*446da993SClément Le Goffic 	uint32_t cr = io_read32(base + RTC_CR);
475*446da993SClément Le Goffic 
476*446da993SClément Le Goffic 	if (rate > (pred_a_max + 1) * (pred_s_max + 1))
477*446da993SClément Le Goffic 		panic("rtc_ck rate is too high");
478*446da993SClément Le Goffic 
479*446da993SClément Le Goffic 	if (cr & RTC_CR_FMT && !IS_ENABLED(CFG_STM32_RTC_HIGH_ACCURACY))
480*446da993SClément Le Goffic 		return TEE_SUCCESS;
481*446da993SClément Le Goffic 
482*446da993SClément Le Goffic 	if (IS_ENABLED(CFG_STM32_RTC_HIGH_ACCURACY)) {
483*446da993SClément Le Goffic 		/*
484*446da993SClément Le Goffic 		 * Compute the prescaler values whom divides the clock in order
485*446da993SClément Le Goffic 		 * to get a * 1 Hz output by maximizing accuracy
486*446da993SClément Le Goffic 		 * (maximizing PREDIV_S).
487*446da993SClément Le Goffic 		 */
488*446da993SClément Le Goffic 		for (pred_a = 0; pred_a <= pred_a_max; pred_a++) {
489*446da993SClément Le Goffic 			pred_s = (rate / (pred_a + 1)) - 1;
490*446da993SClément Le Goffic 			if (pred_s <= pred_s_max &&
491*446da993SClément Le Goffic 			    ((pred_s + 1) * (pred_a + 1)) == rate)
492*446da993SClément Le Goffic 				break;
493*446da993SClément Le Goffic 		}
494*446da993SClément Le Goffic 
495*446da993SClément Le Goffic 		/*
496*446da993SClément Le Goffic 		 * 1 Hz output not possible, give priority to RTC power
497*446da993SClément Le Goffic 		 * consumption by choosing the higher possible value for
498*446da993SClément Le Goffic 		 * prediv_a
499*446da993SClément Le Goffic 		 */
500*446da993SClément Le Goffic 		if (pred_s > pred_s_max || pred_a > pred_a_max) {
501*446da993SClément Le Goffic 			pred_a = pred_a_max;
502*446da993SClément Le Goffic 			pred_s = (rate / (pred_a + 1)) - 1;
503*446da993SClément Le Goffic 
504*446da993SClément Le Goffic 			DMSG("rtc_ck is %s",
505*446da993SClément Le Goffic 			     (rate < ((pred_a + 1) * (pred_s + 1))) ?
506*446da993SClément Le Goffic 			     "fast" : "slow");
507*446da993SClément Le Goffic 		}
508*446da993SClément Le Goffic 
509*446da993SClément Le Goffic 		prer &= RTC_PRER_PREDIV_S_MASK | RTC_PRER_PREDIV_A_MASK;
510*446da993SClément Le Goffic 		pred_s = SHIFT_U32(pred_s, RTC_PRER_PREDIV_S_SHIFT) &
511*446da993SClément Le Goffic 			 RTC_PRER_PREDIV_S_MASK;
512*446da993SClément Le Goffic 		pred_a = SHIFT_U32(pred_a, RTC_PRER_PREDIV_A_SHIFT) &
513*446da993SClément Le Goffic 			 RTC_PRER_PREDIV_A_MASK;
514*446da993SClément Le Goffic 
515*446da993SClément Le Goffic 		/* Return if there is nothing to initialize */
516*446da993SClément Le Goffic 		if (cr & RTC_CR_FMT && prer == (pred_s | pred_a))
517*446da993SClément Le Goffic 			return TEE_SUCCESS;
518*446da993SClément Le Goffic 	}
519*446da993SClément Le Goffic 
520*446da993SClément Le Goffic 	stm32_rtc_write_unprotect();
521*446da993SClément Le Goffic 
522*446da993SClément Le Goffic 	res = stm32_rtc_enter_init_mode();
523*446da993SClément Le Goffic 	if (res) {
524*446da993SClément Le Goffic 		EMSG("Can't enter init mode. Fail to initialize RTC.");
525*446da993SClément Le Goffic 		stm32_rtc_write_protect();
526*446da993SClément Le Goffic 		return res;
527*446da993SClément Le Goffic 	}
528*446da993SClément Le Goffic 
529*446da993SClément Le Goffic 	if (IS_ENABLED(CFG_STM32_RTC_HIGH_ACCURACY)) {
530*446da993SClément Le Goffic 		io_write32(base + RTC_PRER, pred_s);
531*446da993SClément Le Goffic 		io_write32(base + RTC_PRER, pred_a | pred_s);
532*446da993SClément Le Goffic 	}
533*446da993SClément Le Goffic 
534*446da993SClément Le Goffic 	/* Force 24h time format */
535*446da993SClément Le Goffic 	cr &= ~RTC_CR_FMT;
536*446da993SClément Le Goffic 	io_write32(base + RTC_CR, cr);
537*446da993SClément Le Goffic 
538*446da993SClément Le Goffic 	res = stm32_rtc_exit_init_mode();
539*446da993SClément Le Goffic 	if (res)
540*446da993SClément Le Goffic 		EMSG("Can't exit init mode. Fail to initialize RTC.");
541*446da993SClément Le Goffic 
542*446da993SClément Le Goffic 	stm32_rtc_write_protect();
543*446da993SClément Le Goffic 
544*446da993SClément Le Goffic 	return res;
545*446da993SClément Le Goffic }
546*446da993SClément Le Goffic 
547e419bc7fSGatien Chevallier static TEE_Result stm32_rtc_get_time(struct rtc *rtc __unused,
548e419bc7fSGatien Chevallier 				     struct optee_rtc_time *tm)
549e419bc7fSGatien Chevallier {
550e419bc7fSGatien Chevallier 	vaddr_t base = get_base();
551e419bc7fSGatien Chevallier 	uint32_t ssr = 0;
552e419bc7fSGatien Chevallier 	uint32_t dr = 0;
553e419bc7fSGatien Chevallier 	uint32_t tr = 0;
554e419bc7fSGatien Chevallier 
555e419bc7fSGatien Chevallier 	if (!stm32_rtc_get_bypshad()) {
556e419bc7fSGatien Chevallier 		uint32_t icsr = 0;
557e419bc7fSGatien Chevallier 
558e419bc7fSGatien Chevallier 		/* Wait calendar registers are ready */
559e419bc7fSGatien Chevallier 		io_clrbits32(base + RTC_ICSR, RTC_ICSR_RSF);
560e419bc7fSGatien Chevallier 
561e419bc7fSGatien Chevallier 		if (IO_READ32_POLL_TIMEOUT(base + RTC_ICSR, icsr,
562e419bc7fSGatien Chevallier 					   icsr & RTC_ICSR_RSF, 0,
563e419bc7fSGatien Chevallier 					   TIMEOUT_US_RTC_SHADOW))
564e419bc7fSGatien Chevallier 			panic();
565e419bc7fSGatien Chevallier 	}
566e419bc7fSGatien Chevallier 
567e419bc7fSGatien Chevallier 	/*
568e419bc7fSGatien Chevallier 	 * In our RTC we start :
569e419bc7fSGatien Chevallier 	 * - year at 0
570e419bc7fSGatien Chevallier 	 * - month at 1
571e419bc7fSGatien Chevallier 	 * - day at 1
572e419bc7fSGatien Chevallier 	 * - weekday at Monday = 1
573e419bc7fSGatien Chevallier 	 * Change month value so it becomes 0=January, 1 = February, ...
574e419bc7fSGatien Chevallier 	 * Change week day value so it becomes 0=Sunday, 1 = Monday, ...
575e419bc7fSGatien Chevallier 	 */
576e419bc7fSGatien Chevallier 
577e419bc7fSGatien Chevallier 	ssr = io_read32(base + RTC_SSR);
578e419bc7fSGatien Chevallier 	tr = io_read32(base + RTC_TR);
579e419bc7fSGatien Chevallier 	dr = io_read32(base + RTC_DR);
580e419bc7fSGatien Chevallier 
581d60c61e1SGatien Chevallier 	stm32_rtc_to_tm(ssr, tr, dr, tm);
582e419bc7fSGatien Chevallier 
583e419bc7fSGatien Chevallier 	return TEE_SUCCESS;
584e419bc7fSGatien Chevallier }
585e419bc7fSGatien Chevallier 
586e419bc7fSGatien Chevallier static TEE_Result stm32_rtc_set_time(struct rtc *rtc, struct optee_rtc_time *tm)
587e419bc7fSGatien Chevallier {
588e419bc7fSGatien Chevallier 	TEE_Result res = TEE_ERROR_GENERIC;
589e419bc7fSGatien Chevallier 	vaddr_t rtc_base = get_base();
590e419bc7fSGatien Chevallier 	uint32_t tr = 0;
591e419bc7fSGatien Chevallier 	uint32_t dr = 0;
592e419bc7fSGatien Chevallier 
593e419bc7fSGatien Chevallier 	/*
594e419bc7fSGatien Chevallier 	 * In our RTC we start :
595e419bc7fSGatien Chevallier 	 * - year at 0
596e419bc7fSGatien Chevallier 	 * - month at 1
597e419bc7fSGatien Chevallier 	 * - day at 1
598e419bc7fSGatien Chevallier 	 * - weekday at Monday = 1
599e419bc7fSGatien Chevallier 	 * Change month value so it becomes 1=January, 2 = February, ...
600e419bc7fSGatien Chevallier 	 * Change week day value so it becomes 7=Sunday, 1 = Monday, ...
601e419bc7fSGatien Chevallier 	 */
602e419bc7fSGatien Chevallier 	tr = ((tm->tm_sec % 10) & RTC_TR_SU_MASK) |
603e419bc7fSGatien Chevallier 	     (SHIFT_U32(tm->tm_sec / 10, RTC_TR_ST_SHIFT) & RTC_TR_ST_MASK) |
604e419bc7fSGatien Chevallier 	     (SHIFT_U32(tm->tm_min % 10, RTC_TR_MNU_SHIFT) & RTC_TR_MNU_MASK) |
605e419bc7fSGatien Chevallier 	     (SHIFT_U32(tm->tm_min / 10, RTC_TR_MNT_SHIFT) & RTC_TR_MNT_MASK) |
606e419bc7fSGatien Chevallier 	     (SHIFT_U32(tm->tm_hour % 10, RTC_TR_HU_SHIFT) & RTC_TR_HU_MASK) |
607e419bc7fSGatien Chevallier 	     (SHIFT_U32(tm->tm_hour / 10, RTC_TR_HT_SHIFT) & RTC_TR_HT_MASK);
608e419bc7fSGatien Chevallier 
609e419bc7fSGatien Chevallier 	dr = ((tm->tm_mday % 10) & RTC_DR_DU_MASK) |
610e419bc7fSGatien Chevallier 	     (SHIFT_U32(tm->tm_mday / 10, RTC_DR_DT_SHIFT) & RTC_DR_DT_MASK) |
611e419bc7fSGatien Chevallier 	     (SHIFT_U32((tm->tm_mon + 1) % 10, RTC_DR_MU_SHIFT) &
612e419bc7fSGatien Chevallier 	      RTC_DR_MU_MASK) |
613e419bc7fSGatien Chevallier 	     (SHIFT_U32((tm->tm_mon + 1) / 10, RTC_DR_MT_SHIFT) &
614e419bc7fSGatien Chevallier 	      RTC_DR_MT_MASK) |
615e419bc7fSGatien Chevallier 	     (SHIFT_U32(tm->tm_wday ? tm->tm_wday : 7, RTC_DR_WDU_SHIFT) &
616e419bc7fSGatien Chevallier 	      RTC_DR_WDU_MASK) |
617e419bc7fSGatien Chevallier 	     (SHIFT_U32((tm->tm_year - rtc->range_min.tm_year) % 10,
618e419bc7fSGatien Chevallier 			RTC_DR_YU_SHIFT) & RTC_DR_YU_MASK) |
619e419bc7fSGatien Chevallier 	     (SHIFT_U32((tm->tm_year - rtc->range_min.tm_year) / 10,
620e419bc7fSGatien Chevallier 			RTC_DR_YT_SHIFT) & RTC_DR_YT_MASK);
621e419bc7fSGatien Chevallier 
622e419bc7fSGatien Chevallier 	stm32_rtc_write_unprotect();
623e419bc7fSGatien Chevallier 
624e419bc7fSGatien Chevallier 	res = stm32_rtc_enter_init_mode();
625e419bc7fSGatien Chevallier 	if (res)
626e419bc7fSGatien Chevallier 		goto end;
627e419bc7fSGatien Chevallier 
628e419bc7fSGatien Chevallier 	io_write32(rtc_base + RTC_TR, tr);
629e419bc7fSGatien Chevallier 	io_write32(rtc_base + RTC_DR, dr);
630e419bc7fSGatien Chevallier 
631*446da993SClément Le Goffic 	res = stm32_rtc_exit_init_mode();
632e419bc7fSGatien Chevallier end:
633e419bc7fSGatien Chevallier 	stm32_rtc_write_protect();
634e419bc7fSGatien Chevallier 
635e419bc7fSGatien Chevallier 	return res;
636e419bc7fSGatien Chevallier }
637e419bc7fSGatien Chevallier 
638d60c61e1SGatien Chevallier TEE_Result stm32_rtc_get_timestamp(struct optee_rtc_time *tm)
639d60c61e1SGatien Chevallier {
640d60c61e1SGatien Chevallier 	vaddr_t base = get_base();
641d60c61e1SGatien Chevallier 	uint32_t exceptions = 0;
642d60c61e1SGatien Chevallier 	uint32_t value = 0;
643d60c61e1SGatien Chevallier 	uint32_t ssr = 0;
644d60c61e1SGatien Chevallier 	uint32_t dr = 0;
645d60c61e1SGatien Chevallier 	uint32_t tr = 0;
646d60c61e1SGatien Chevallier 
647d60c61e1SGatien Chevallier 	exceptions = cpu_spin_lock_xsave(&rtc_dev.ts_lock);
648d60c61e1SGatien Chevallier 
649d60c61e1SGatien Chevallier 	if (IO_READ32_POLL_TIMEOUT(base + RTC_SR, value,
650d60c61e1SGatien Chevallier 				   value & RTC_SR_TSF,
651d60c61e1SGatien Chevallier 				   10, TIMEOUT_US_RTC_GENERIC)) {
652d60c61e1SGatien Chevallier 		cpu_spin_unlock_xrestore(&rtc_dev.ts_lock, exceptions);
653d60c61e1SGatien Chevallier 		return TEE_ERROR_NO_DATA;
654d60c61e1SGatien Chevallier 	}
655d60c61e1SGatien Chevallier 
656d60c61e1SGatien Chevallier 	ssr = io_read32(base + RTC_TSSSR);
657d60c61e1SGatien Chevallier 	tr = io_read32(base + RTC_TSTR);
658d60c61e1SGatien Chevallier 	dr = io_read32(base + RTC_TSDR);
659d60c61e1SGatien Chevallier 
660d60c61e1SGatien Chevallier 	io_setbits32(base + RTC_SCR, RTC_SCR_CTSF);
661d60c61e1SGatien Chevallier 
662d60c61e1SGatien Chevallier 	/* Tamper event overflow detection */
663d60c61e1SGatien Chevallier 	if (io_read32(base + RTC_SR) & RTC_SR_TSOVF) {
664d60c61e1SGatien Chevallier 		io_setbits32(base + RTC_SCR, RTC_SCR_CTSOVF);
665d60c61e1SGatien Chevallier 		DMSG("A timestamp event occurred while handling current event");
666d60c61e1SGatien Chevallier 	}
667d60c61e1SGatien Chevallier 
668d60c61e1SGatien Chevallier 	cpu_spin_unlock_xrestore(&rtc_dev.ts_lock, exceptions);
669d60c61e1SGatien Chevallier 
670d60c61e1SGatien Chevallier 	stm32_rtc_to_tm(ssr, tr, dr, tm);
671d60c61e1SGatien Chevallier 
672d60c61e1SGatien Chevallier 	/* No year timestamp available */
673d60c61e1SGatien Chevallier 	tm->tm_year = 0;
674d60c61e1SGatien Chevallier 
675d60c61e1SGatien Chevallier 	return TEE_SUCCESS;
676d60c61e1SGatien Chevallier }
677d60c61e1SGatien Chevallier 
678d60c61e1SGatien Chevallier TEE_Result stm32_rtc_set_tamper_timestamp(void)
679d60c61e1SGatien Chevallier {
680d60c61e1SGatien Chevallier 	vaddr_t base = get_base();
681d60c61e1SGatien Chevallier 
682d60c61e1SGatien Chevallier 	stm32_rtc_write_unprotect();
683d60c61e1SGatien Chevallier 
684d60c61e1SGatien Chevallier 	/* Secure Timestamp bit */
685d60c61e1SGatien Chevallier 	if (!rtc_dev.compat->has_seccfgr) {
686d60c61e1SGatien Chevallier 		/* Inverted logic */
687d60c61e1SGatien Chevallier 		io_clrbits32(base + RTC_SMCR, RTC_SMCR_TS_DPROT);
688d60c61e1SGatien Chevallier 	} else {
689d60c61e1SGatien Chevallier 		io_setbits32(base + RTC_SECCFGR, RTC_SECCFGR_TS_SEC);
690d60c61e1SGatien Chevallier 	}
691d60c61e1SGatien Chevallier 
692d60c61e1SGatien Chevallier 	/* Enable tamper timestamper */
693d60c61e1SGatien Chevallier 	io_setbits32(base + RTC_CR, RTC_CR_TAMPTS);
694d60c61e1SGatien Chevallier 
695d60c61e1SGatien Chevallier 	stm32_rtc_write_protect();
696d60c61e1SGatien Chevallier 
697d60c61e1SGatien Chevallier 	return TEE_SUCCESS;
698d60c61e1SGatien Chevallier }
699d60c61e1SGatien Chevallier 
700d60c61e1SGatien Chevallier TEE_Result stm32_rtc_is_timestamp_enabled(bool *ret)
701d60c61e1SGatien Chevallier {
702d60c61e1SGatien Chevallier 	*ret = io_read32(get_base() + RTC_CR) & RTC_CR_TAMPTS;
703d60c61e1SGatien Chevallier 
704d60c61e1SGatien Chevallier 	return TEE_SUCCESS;
705d60c61e1SGatien Chevallier }
706d60c61e1SGatien Chevallier 
707d60c61e1SGatien Chevallier TEE_Result stm32_rtc_driver_is_initialized(void)
708d60c61e1SGatien Chevallier {
709d60c61e1SGatien Chevallier 	if (rtc_dev.pclk)
710d60c61e1SGatien Chevallier 		return TEE_SUCCESS;
711d60c61e1SGatien Chevallier 
712d60c61e1SGatien Chevallier 	return TEE_ERROR_DEFER_DRIVER_INIT;
713d60c61e1SGatien Chevallier }
714d60c61e1SGatien Chevallier 
715e419bc7fSGatien Chevallier static const struct rtc_ops stm32_rtc_ops = {
716e419bc7fSGatien Chevallier 	.get_time = stm32_rtc_get_time,
717e419bc7fSGatien Chevallier 	.set_time = stm32_rtc_set_time,
718e419bc7fSGatien Chevallier };
719e419bc7fSGatien Chevallier 
720e419bc7fSGatien Chevallier static struct rtc stm32_rtc = {
721e419bc7fSGatien Chevallier 	.ops = &stm32_rtc_ops,
722e419bc7fSGatien Chevallier 	.range_min = RTC_TIME(YEAR_REF, 0, 1, 0, 0, 0, 0, 0),
723e419bc7fSGatien Chevallier 	.range_max = RTC_TIME(YEAR_MAX, 11, 31, 4, 23, 59, 59, 999),
724e419bc7fSGatien Chevallier };
725e419bc7fSGatien Chevallier 
726e419bc7fSGatien Chevallier static TEE_Result stm32_rtc_probe(const void *fdt, int node,
727e419bc7fSGatien Chevallier 				  const void *compat_data)
728e419bc7fSGatien Chevallier {
729e419bc7fSGatien Chevallier 	TEE_Result res = TEE_ERROR_GENERIC;
730e419bc7fSGatien Chevallier 	bool is_tdcid = false;
731e419bc7fSGatien Chevallier 
732e419bc7fSGatien Chevallier 	rtc_dev.compat = compat_data;
733e419bc7fSGatien Chevallier 
734e419bc7fSGatien Chevallier 	if (rtc_dev.compat->has_rif_support) {
735e419bc7fSGatien Chevallier 		res = stm32_rifsc_check_tdcid(&is_tdcid);
736e419bc7fSGatien Chevallier 		if (res)
737e419bc7fSGatien Chevallier 			return res;
738e419bc7fSGatien Chevallier 	}
739e419bc7fSGatien Chevallier 
740e419bc7fSGatien Chevallier 	res = parse_dt(fdt, node);
741e419bc7fSGatien Chevallier 	if (res) {
742e419bc7fSGatien Chevallier 		memset(&rtc_dev, 0, sizeof(rtc_dev));
743e419bc7fSGatien Chevallier 		return res;
744e419bc7fSGatien Chevallier 	}
745e419bc7fSGatien Chevallier 
746e419bc7fSGatien Chevallier 	/* Unbalanced clock enable to ensure RTC core clock is always on */
747e419bc7fSGatien Chevallier 	res = clk_enable(rtc_dev.rtc_ck);
748e419bc7fSGatien Chevallier 	if (res)
749e419bc7fSGatien Chevallier 		panic("Couldn't enable RTC clock");
750e419bc7fSGatien Chevallier 
751e419bc7fSGatien Chevallier 	if (clk_get_rate(rtc_dev.pclk) < (clk_get_rate(rtc_dev.rtc_ck) * 7))
752e419bc7fSGatien Chevallier 		rtc_dev.flags |= RTC_FLAGS_READ_TWICE;
753e419bc7fSGatien Chevallier 
754e419bc7fSGatien Chevallier 	if (rtc_dev.compat->has_rif_support) {
755e419bc7fSGatien Chevallier 		res = clk_enable(rtc_dev.pclk);
756e419bc7fSGatien Chevallier 		if (res)
757e419bc7fSGatien Chevallier 			panic("Could not enable RTC bus clock");
758e419bc7fSGatien Chevallier 
759e419bc7fSGatien Chevallier 		apply_rif_config(is_tdcid);
760e419bc7fSGatien Chevallier 
761e419bc7fSGatien Chevallier 		/*
762e419bc7fSGatien Chevallier 		 * Verify if applied RIF config will not disable
763e419bc7fSGatien Chevallier 		 * other functionalities of this driver.
764e419bc7fSGatien Chevallier 		 */
765e419bc7fSGatien Chevallier 		res = check_rif_config();
766e419bc7fSGatien Chevallier 		if (res)
767e419bc7fSGatien Chevallier 			panic("Incompatible RTC RIF configuration");
768e419bc7fSGatien Chevallier 
769e419bc7fSGatien Chevallier 		clk_disable(rtc_dev.pclk);
770e419bc7fSGatien Chevallier 	}
771e419bc7fSGatien Chevallier 
772*446da993SClément Le Goffic 	res = stm32_rtc_init();
773*446da993SClément Le Goffic 	if (res)
774*446da993SClément Le Goffic 		return res;
775e419bc7fSGatien Chevallier 	rtc_register(&stm32_rtc);
776e419bc7fSGatien Chevallier 
777e419bc7fSGatien Chevallier 	return res;
778e419bc7fSGatien Chevallier }
779e419bc7fSGatien Chevallier 
780e419bc7fSGatien Chevallier static const struct rtc_compat mp25_compat = {
781e419bc7fSGatien Chevallier 	.has_seccfgr = true,
782e419bc7fSGatien Chevallier 	.has_rif_support = true,
783e419bc7fSGatien Chevallier };
784e419bc7fSGatien Chevallier 
785e419bc7fSGatien Chevallier static const struct rtc_compat mp15_compat = {
786e419bc7fSGatien Chevallier 	.has_seccfgr = false,
787e419bc7fSGatien Chevallier 	.has_rif_support = false,
788e419bc7fSGatien Chevallier };
789e419bc7fSGatien Chevallier 
790e419bc7fSGatien Chevallier static const struct rtc_compat mp13_compat = {
791e419bc7fSGatien Chevallier 	.has_seccfgr = true,
792e419bc7fSGatien Chevallier 	.has_rif_support = false,
793e419bc7fSGatien Chevallier };
794e419bc7fSGatien Chevallier 
795e419bc7fSGatien Chevallier static const struct dt_device_match stm32_rtc_match_table[] = {
796e419bc7fSGatien Chevallier 	{
797e419bc7fSGatien Chevallier 		.compatible = "st,stm32mp25-rtc",
798e419bc7fSGatien Chevallier 		.compat_data = &mp25_compat,
799e419bc7fSGatien Chevallier 	},
800e419bc7fSGatien Chevallier 	{
801e419bc7fSGatien Chevallier 		.compatible = "st,stm32mp1-rtc",
802e419bc7fSGatien Chevallier 		.compat_data = &mp15_compat,
803e419bc7fSGatien Chevallier 	},
804e419bc7fSGatien Chevallier 	{
805e419bc7fSGatien Chevallier 		.compatible = "st,stm32mp13-rtc",
806e419bc7fSGatien Chevallier 		.compat_data = &mp13_compat,
807e419bc7fSGatien Chevallier 	},
808e419bc7fSGatien Chevallier 	{ }
809e419bc7fSGatien Chevallier };
810e419bc7fSGatien Chevallier 
811e419bc7fSGatien Chevallier DEFINE_DT_DRIVER(stm32_rtc_dt_driver) = {
812e419bc7fSGatien Chevallier 	.name = "stm32-rtc",
813e419bc7fSGatien Chevallier 	.match_table = stm32_rtc_match_table,
814e419bc7fSGatien Chevallier 	.probe = stm32_rtc_probe,
815e419bc7fSGatien Chevallier };
816