xref: /optee_os/core/include/drivers/rtc.h (revision 73aafcc9aaef33d6ef11497ae5bdab1cb29fb47b)
1f3f9432fSClément Léger /* SPDX-License-Identifier: BSD-2-Clause */
2f3f9432fSClément Léger /*
3f3f9432fSClément Léger  * Copyright 2022 Microchip.
4f3f9432fSClément Léger  */
5f3f9432fSClément Léger 
6d50fee03SEtienne Carriere #ifndef __DRIVERS_RTC_H
7d50fee03SEtienne Carriere #define __DRIVERS_RTC_H
8f3f9432fSClément Léger 
926899ca2SClément Le Goffic #include <kernel/panic.h>
10f3f9432fSClément Léger #include <tee_api_types.h>
11f3f9432fSClément Léger #include <util.h>
12f3f9432fSClément Léger 
13f3f9432fSClément Léger /* The RTC allows to set/get offset for correction */
14f3f9432fSClément Léger #define RTC_CORRECTION_FEATURE	BIT(0)
15f3f9432fSClément Léger 
1626899ca2SClément Le Goffic #define MS_PER_SEC		1000
1726899ca2SClément Le Goffic #define MS_PER_MIN		(60 * MS_PER_SEC)
1826899ca2SClément Le Goffic #define MS_PER_HOUR		(60 * MS_PER_MIN)
1926899ca2SClément Le Goffic #define MS_PER_DAY		(24 * MS_PER_HOUR)
2026899ca2SClément Le Goffic 
21a83e616eSGatien Chevallier #define RTC_TIME(year, mon, mday, wday, hour, min, sec, ms)		\
22a83e616eSGatien Chevallier 	{								\
23a83e616eSGatien Chevallier 		.tm_year = (year),					\
24a83e616eSGatien Chevallier 		.tm_mon = (mon),					\
25a83e616eSGatien Chevallier 		.tm_mday = (mday),					\
26a83e616eSGatien Chevallier 		.tm_wday = (wday),					\
27a83e616eSGatien Chevallier 		.tm_hour = (hour),					\
28a83e616eSGatien Chevallier 		.tm_min = (min),					\
29a83e616eSGatien Chevallier 		.tm_sec = (sec),					\
30a83e616eSGatien Chevallier 		.tm_ms = (ms),						\
31a83e616eSGatien Chevallier 	}
32a83e616eSGatien Chevallier 
3326899ca2SClément Le Goffic /*
3426899ca2SClément Le Goffic  * struct optee_rtc_time - Time in Gregorian calendar
3526899ca2SClément Le Goffic  *
3626899ca2SClément Le Goffic  * @tm_year: Absolute year
3726899ca2SClément Le Goffic  * @tm_mon: Month: 0=January, 1=February, ..., 11=December
3826899ca2SClément Le Goffic  * @tm_mday: Month day start from 1
3926899ca2SClément Le Goffic  * @tm_wday: Week day: 0=Sunday, 1=Monday, ..., 6=Saturday
4026899ca2SClément Le Goffic  * @tm_hour: Hour in range [0 23]
4126899ca2SClément Le Goffic  * @tm_min: Minute in range [0 59]
4226899ca2SClément Le Goffic  * @tm_sec: Second in range [0 59]
4326899ca2SClément Le Goffic  * @tm_ms: Millisecond in range [0 999] or 0 if no applicable
4426899ca2SClément Le Goffic  */
45f3f9432fSClément Léger struct optee_rtc_time {
46f3f9432fSClément Léger 	uint32_t tm_year;
47f3f9432fSClément Léger 	uint32_t tm_mon;
48f3f9432fSClément Léger 	uint32_t tm_mday;
4926899ca2SClément Le Goffic 	uint32_t tm_wday;
50f3f9432fSClément Léger 	uint32_t tm_hour;
51f3f9432fSClément Léger 	uint32_t tm_min;
52f3f9432fSClément Léger 	uint32_t tm_sec;
5326899ca2SClément Le Goffic 	uint32_t tm_ms;
54f3f9432fSClément Léger };
55f3f9432fSClément Léger 
56f3f9432fSClément Léger struct rtc {
57f3f9432fSClément Léger 	const struct rtc_ops *ops;
58f3f9432fSClément Léger 	struct optee_rtc_time range_min;
59f3f9432fSClément Léger 	struct optee_rtc_time range_max;
60f3f9432fSClément Léger };
61f3f9432fSClément Léger 
62f3f9432fSClément Léger /*
63f3f9432fSClément Léger  * struct rtc_ops - The RTC device operations
64f3f9432fSClément Léger  *
65f3f9432fSClément Léger  * @get_time:	Get the RTC time.
66f3f9432fSClément Léger  * @set_time:	Set the RTC time.
67f3f9432fSClément Léger  * @get_offset:	Get the RTC offset.
68f3f9432fSClément Léger  * @set_offset: Set the RTC offset
69f3f9432fSClément Léger  */
70f3f9432fSClément Léger struct rtc_ops {
71f3f9432fSClément Léger 	TEE_Result (*get_time)(struct rtc *rtc, struct optee_rtc_time *tm);
72f3f9432fSClément Léger 	TEE_Result (*set_time)(struct rtc *rtc, struct optee_rtc_time *tm);
73f3f9432fSClément Léger 	TEE_Result (*get_offset)(struct rtc *rtc, long *offset);
74f3f9432fSClément Léger 	TEE_Result (*set_offset)(struct rtc *rtc, long offset);
75f3f9432fSClément Léger };
76f3f9432fSClément Léger 
77f3f9432fSClément Léger #ifdef CFG_DRIVERS_RTC
78f3f9432fSClément Léger extern struct rtc *rtc_device;
79f3f9432fSClément Léger 
80f3f9432fSClément Léger /* Register a RTC device as the system RTC */
81f3f9432fSClément Léger void rtc_register(struct rtc *rtc);
82f3f9432fSClément Léger 
8326899ca2SClément Le Goffic /**
8426899ca2SClément Le Goffic  * rtc_is_a_leap_year() - Check if a year is a leap year
8526899ca2SClément Le Goffic  * @year:	The year to check
8626899ca2SClément Le Goffic  *
8726899ca2SClément Le Goffic  * Return:	true if the year is a leap year, false otherwise
8826899ca2SClément Le Goffic  */
8926899ca2SClément Le Goffic bool rtc_is_a_leap_year(uint32_t year);
9026899ca2SClément Le Goffic 
9126899ca2SClément Le Goffic /**
9226899ca2SClément Le Goffic  * rtc_get_month_days() - Get the number of days in a month
9326899ca2SClément Le Goffic  * @month:	The month to know the number of days
9426899ca2SClément Le Goffic  * @year:	The year of the month
9526899ca2SClément Le Goffic  *
9626899ca2SClément Le Goffic  * Return:	Number of days in the month
9726899ca2SClément Le Goffic  */
9826899ca2SClément Le Goffic uint8_t rtc_get_month_days(uint32_t month, uint32_t year);
9926899ca2SClément Le Goffic 
10026899ca2SClément Le Goffic /**
10126899ca2SClément Le Goffic  * rtc_timecmp() - Compare two RTC time structures
10226899ca2SClément Le Goffic  * @a:		First RTC time
10326899ca2SClément Le Goffic  * @b:		Second RTC time
10426899ca2SClément Le Goffic  *
10526899ca2SClément Le Goffic  * Return a negative value if @a < @b
10626899ca2SClément Le Goffic  * Return 0 if @a == @b
10726899ca2SClément Le Goffic  * Return a positive value if @a > @b
10826899ca2SClément Le Goffic  */
10926899ca2SClément Le Goffic int rtc_timecmp(struct optee_rtc_time *a, struct optee_rtc_time *b);
11026899ca2SClément Le Goffic 
11126899ca2SClément Le Goffic /**
11226899ca2SClément Le Goffic  * rtc_diff_calendar_ms() - Return the difference in milliseconds between
11326899ca2SClément Le Goffic  * two times captures.
11426899ca2SClément Le Goffic  * @ref1: First time capture
11526899ca2SClément Le Goffic  * @ref2: Second time capture
11626899ca2SClément Le Goffic  *
11726899ca2SClément Le Goffic  * Return @ref1 - @ref2 in milliseconds or LLONG_MAX in case of overflow
11826899ca2SClément Le Goffic  */
11926899ca2SClément Le Goffic signed long long rtc_diff_calendar_ms(struct optee_rtc_time *ref1,
12026899ca2SClément Le Goffic 				      struct optee_rtc_time *ref2);
12126899ca2SClément Le Goffic 
12226899ca2SClément Le Goffic /**
12326899ca2SClément Le Goffic  * rtc_diff_calendar_tick() - Return the difference in number of ticks between
12426899ca2SClément Le Goffic  * two times captures.
12526899ca2SClément Le Goffic  * @ref1: First time capture
12626899ca2SClément Le Goffic  * @ref2: Second time capture
12726899ca2SClément Le Goffic  * @tick_rate: Tick rate
12826899ca2SClément Le Goffic  *
12926899ca2SClément Le Goffic  * Return @ref1 - @ref2 in number of ticks. In case of tick computation
13026899ca2SClément Le Goffic  * overflow, return LLONG_MAX
13126899ca2SClément Le Goffic  */
13226899ca2SClément Le Goffic signed long long rtc_diff_calendar_tick(struct optee_rtc_time *ref1,
13326899ca2SClément Le Goffic 					struct optee_rtc_time *ref2,
13426899ca2SClément Le Goffic 					unsigned long long tick_rate);
13526899ca2SClément Le Goffic 
136f3f9432fSClément Léger static inline TEE_Result rtc_get_info(uint64_t *features,
137f3f9432fSClément Léger 				      struct optee_rtc_time *range_min,
138f3f9432fSClément Léger 				      struct optee_rtc_time *range_max)
139f3f9432fSClément Léger {
140f3f9432fSClément Léger 	if (!rtc_device)
141f3f9432fSClément Léger 		return TEE_ERROR_NOT_SUPPORTED;
142f3f9432fSClément Léger 
143f3f9432fSClément Léger 	if (rtc_device->ops->set_offset)
144f3f9432fSClément Léger 		*features = RTC_CORRECTION_FEATURE;
145f3f9432fSClément Léger 	*range_min = rtc_device->range_min;
146f3f9432fSClément Léger 	*range_max = rtc_device->range_max;
147f3f9432fSClément Léger 
148f3f9432fSClément Léger 	return TEE_SUCCESS;
149f3f9432fSClément Léger }
150f3f9432fSClément Léger 
151f3f9432fSClément Léger static inline TEE_Result rtc_get_time(struct optee_rtc_time *tm)
152f3f9432fSClément Léger {
153f3f9432fSClément Léger 	if (!rtc_device)
154f3f9432fSClément Léger 		return TEE_ERROR_NOT_SUPPORTED;
155f3f9432fSClément Léger 
156f3f9432fSClément Léger 	return rtc_device->ops->get_time(rtc_device, tm);
157f3f9432fSClément Léger }
158f3f9432fSClément Léger 
159f3f9432fSClément Léger static inline TEE_Result rtc_set_time(struct optee_rtc_time *tm)
160f3f9432fSClément Léger {
161f3f9432fSClément Léger 	if (!rtc_device || !rtc_device->ops->set_time)
162f3f9432fSClément Léger 		return TEE_ERROR_NOT_SUPPORTED;
163f3f9432fSClément Léger 
164*73aafcc9SGatien Chevallier 	if (tm->tm_mon >= 12 ||
165*73aafcc9SGatien Chevallier 	    tm->tm_mday > rtc_get_month_days(tm->tm_mon, tm->tm_year) ||
166*73aafcc9SGatien Chevallier 	    tm->tm_wday >= 7 || tm->tm_hour >= 24 || tm->tm_min >= 60 ||
167*73aafcc9SGatien Chevallier 	    tm->tm_sec >= 60 || tm->tm_ms >= 1000 ||
168*73aafcc9SGatien Chevallier 	    rtc_timecmp(tm, &rtc_device->range_min) < 0 ||
169*73aafcc9SGatien Chevallier 	    rtc_timecmp(tm, &rtc_device->range_max) > 0)
170*73aafcc9SGatien Chevallier 		return TEE_ERROR_BAD_PARAMETERS;
171*73aafcc9SGatien Chevallier 
172f3f9432fSClément Léger 	return rtc_device->ops->set_time(rtc_device, tm);
173f3f9432fSClément Léger }
174f3f9432fSClément Léger 
175f3f9432fSClément Léger static inline TEE_Result rtc_get_offset(long *offset)
176f3f9432fSClément Léger {
177f3f9432fSClément Léger 	if (!rtc_device || !rtc_device->ops->get_offset)
178f3f9432fSClément Léger 		return TEE_ERROR_NOT_SUPPORTED;
179f3f9432fSClément Léger 
180f3f9432fSClément Léger 	return rtc_device->ops->get_offset(rtc_device, offset);
181f3f9432fSClément Léger }
182f3f9432fSClément Léger 
183f3f9432fSClément Léger static inline TEE_Result rtc_set_offset(long offset)
184f3f9432fSClément Léger {
185f3f9432fSClément Léger 	if (!rtc_device || !rtc_device->ops->set_offset)
186f3f9432fSClément Léger 		return TEE_ERROR_NOT_SUPPORTED;
187f3f9432fSClément Léger 
188f3f9432fSClément Léger 	return rtc_device->ops->set_offset(rtc_device, offset);
189f3f9432fSClément Léger }
190f3f9432fSClément Léger 
191f3f9432fSClément Léger #else
192f3f9432fSClément Léger 
193f3f9432fSClément Léger static inline void rtc_register(struct rtc *rtc __unused) {}
194f3f9432fSClément Léger 
19526899ca2SClément Le Goffic static inline bool __noreturn rtc_is_a_leap_year(uint32_t year __unused)
19626899ca2SClément Le Goffic {
19726899ca2SClément Le Goffic 	panic();
19826899ca2SClément Le Goffic }
19926899ca2SClément Le Goffic 
20026899ca2SClément Le Goffic static inline uint8_t __noreturn rtc_get_month_days(uint32_t month __unused,
20126899ca2SClément Le Goffic 						    uint32_t year __unused)
20226899ca2SClément Le Goffic {
20326899ca2SClément Le Goffic 	panic();
20426899ca2SClément Le Goffic }
20526899ca2SClément Le Goffic 
20626899ca2SClément Le Goffic static inline int __noreturn rtc_timecmp(struct optee_rtc_time *a __unused,
20726899ca2SClément Le Goffic 					 struct optee_rtc_time *b __unused)
20826899ca2SClément Le Goffic {
20926899ca2SClément Le Goffic 	panic();
21026899ca2SClément Le Goffic }
21126899ca2SClément Le Goffic 
212f3f9432fSClément Léger static inline TEE_Result rtc_get_info(uint64_t *features __unused,
213f3f9432fSClément Léger 				      struct optee_rtc_time *range_min __unused,
214f3f9432fSClément Léger 				      struct optee_rtc_time *range_max __unused)
215f3f9432fSClément Léger {
216f3f9432fSClément Léger 	return TEE_ERROR_NOT_SUPPORTED;
217f3f9432fSClément Léger }
218f3f9432fSClément Léger 
219f3f9432fSClément Léger static inline TEE_Result rtc_get_time(struct optee_rtc_time *tm __unused)
220f3f9432fSClément Léger {
221f3f9432fSClément Léger 	return TEE_ERROR_NOT_SUPPORTED;
222f3f9432fSClément Léger }
223f3f9432fSClément Léger 
224f3f9432fSClément Léger static inline TEE_Result rtc_set_time(struct optee_rtc_time *tm __unused)
225f3f9432fSClément Léger {
226f3f9432fSClément Léger 	return TEE_ERROR_NOT_SUPPORTED;
227f3f9432fSClément Léger }
228f3f9432fSClément Léger 
229f3f9432fSClément Léger static inline TEE_Result rtc_get_offset(long *offset __unused)
230f3f9432fSClément Léger {
231f3f9432fSClément Léger 	return TEE_ERROR_NOT_SUPPORTED;
232f3f9432fSClément Léger }
233f3f9432fSClément Léger 
234f3f9432fSClément Léger static inline TEE_Result rtc_set_offset(long offset __unused)
235f3f9432fSClément Léger {
236f3f9432fSClément Léger 	return TEE_ERROR_NOT_SUPPORTED;
237f3f9432fSClément Léger }
23826899ca2SClément Le Goffic 
23926899ca2SClément Le Goffic static inline signed long long
24026899ca2SClément Le Goffic rtc_diff_calendar_ms(struct optee_rtc_time *ref1 __unused,
24126899ca2SClément Le Goffic 		     struct optee_rtc_time *ref2 __unused)
24226899ca2SClément Le Goffic {
24326899ca2SClément Le Goffic 	return LLONG_MAX;
24426899ca2SClément Le Goffic }
24526899ca2SClément Le Goffic 
24626899ca2SClément Le Goffic static inline signed long long
24726899ca2SClément Le Goffic rtc_diff_calendar_tick(struct optee_rtc_time *ref1 __unused,
24826899ca2SClément Le Goffic 		       struct optee_rtc_time *ref2 __unused,
24926899ca2SClément Le Goffic 		       unsigned long long tick_rate __unused)
25026899ca2SClément Le Goffic {
25126899ca2SClément Le Goffic 	return LLONG_MAX;
25226899ca2SClément Le Goffic }
253f3f9432fSClément Léger #endif
254d50fee03SEtienne Carriere #endif /* __DRIVERS_RTC_H */
255