xref: /optee_os/core/include/drivers/rtc.h (revision 45fecab081173ef58b1cb14b6ddf6892b0b9d3f6)
1 /* SPDX-License-Identifier: BSD-2-Clause */
2 /*
3  * Copyright 2022 Microchip.
4  */
5 
6 #ifndef __DRIVERS_RTC_H
7 #define __DRIVERS_RTC_H
8 
9 #include <kernel/panic.h>
10 #include <tee_api_types.h>
11 #include <util.h>
12 
13 /* The RTC allows to set/get offset for correction */
14 #define RTC_CORRECTION_FEATURE	BIT(0)
15 
16 #define MS_PER_SEC		1000
17 #define MS_PER_MIN		(60 * MS_PER_SEC)
18 #define MS_PER_HOUR		(60 * MS_PER_MIN)
19 #define MS_PER_DAY		(24 * MS_PER_HOUR)
20 
21 #define RTC_TIME(year, mon, mday, wday, hour, min, sec, ms)		\
22 	{								\
23 		.tm_year = (year),					\
24 		.tm_mon = (mon),					\
25 		.tm_mday = (mday),					\
26 		.tm_wday = (wday),					\
27 		.tm_hour = (hour),					\
28 		.tm_min = (min),					\
29 		.tm_sec = (sec),					\
30 		.tm_ms = (ms),						\
31 	}
32 
33 /*
34  * struct optee_rtc_time - Time in Gregorian calendar
35  *
36  * @tm_year: Absolute year
37  * @tm_mon: Month: 0=January, 1=February, ..., 11=December
38  * @tm_mday: Month day start from 1
39  * @tm_wday: Week day: 0=Sunday, 1=Monday, ..., 6=Saturday
40  * @tm_hour: Hour in range [0 23]
41  * @tm_min: Minute in range [0 59]
42  * @tm_sec: Second in range [0 59]
43  * @tm_ms: Millisecond in range [0 999] or 0 if no applicable
44  */
45 struct optee_rtc_time {
46 	uint32_t tm_year;
47 	uint32_t tm_mon;
48 	uint32_t tm_mday;
49 	uint32_t tm_wday;
50 	uint32_t tm_hour;
51 	uint32_t tm_min;
52 	uint32_t tm_sec;
53 	uint32_t tm_ms;
54 };
55 
56 struct rtc {
57 	const struct rtc_ops *ops;
58 	struct optee_rtc_time range_min;
59 	struct optee_rtc_time range_max;
60 };
61 
62 /*
63  * struct rtc_ops - The RTC device operations
64  *
65  * @get_time:	Get the RTC time.
66  * @set_time:	Set the RTC time.
67  * @get_offset:	Get the RTC offset.
68  * @set_offset: Set the RTC offset
69  */
70 struct rtc_ops {
71 	TEE_Result (*get_time)(struct rtc *rtc, struct optee_rtc_time *tm);
72 	TEE_Result (*set_time)(struct rtc *rtc, struct optee_rtc_time *tm);
73 	TEE_Result (*get_offset)(struct rtc *rtc, long *offset);
74 	TEE_Result (*set_offset)(struct rtc *rtc, long offset);
75 };
76 
77 #ifdef CFG_DRIVERS_RTC
78 extern struct rtc *rtc_device;
79 
80 /* Register a RTC device as the system RTC */
81 void rtc_register(struct rtc *rtc);
82 
83 /**
84  * rtc_is_a_leap_year() - Check if a year is a leap year
85  * @year:	The year to check
86  *
87  * Return:	true if the year is a leap year, false otherwise
88  */
89 bool rtc_is_a_leap_year(uint32_t year);
90 
91 /**
92  * rtc_get_month_days() - Get the number of days in a month
93  * @month:	The month to know the number of days
94  * @year:	The year of the month
95  *
96  * Return:	Number of days in the month
97  */
98 uint8_t rtc_get_month_days(uint32_t month, uint32_t year);
99 
100 /**
101  * rtc_timecmp() - Compare two RTC time structures
102  * @a:		First RTC time
103  * @b:		Second RTC time
104  *
105  * Return a negative value if @a < @b
106  * Return 0 if @a == @b
107  * Return a positive value if @a > @b
108  */
109 int rtc_timecmp(struct optee_rtc_time *a, struct optee_rtc_time *b);
110 
111 /**
112  * rtc_diff_calendar_ms() - Return the difference in milliseconds between
113  * two times captures.
114  * @ref1: First time capture
115  * @ref2: Second time capture
116  *
117  * Return @ref1 - @ref2 in milliseconds or LLONG_MAX in case of overflow
118  */
119 signed long long rtc_diff_calendar_ms(struct optee_rtc_time *ref1,
120 				      struct optee_rtc_time *ref2);
121 
122 /**
123  * rtc_diff_calendar_tick() - Return the difference in number of ticks between
124  * two times captures.
125  * @ref1: First time capture
126  * @ref2: Second time capture
127  * @tick_rate: Tick rate
128  *
129  * Return @ref1 - @ref2 in number of ticks. In case of tick computation
130  * overflow, return LLONG_MAX
131  */
132 signed long long rtc_diff_calendar_tick(struct optee_rtc_time *ref1,
133 					struct optee_rtc_time *ref2,
134 					unsigned long long tick_rate);
135 
136 static inline TEE_Result rtc_get_info(uint64_t *features,
137 				      struct optee_rtc_time *range_min,
138 				      struct optee_rtc_time *range_max)
139 {
140 	if (!rtc_device)
141 		return TEE_ERROR_NOT_SUPPORTED;
142 
143 	if (rtc_device->ops->set_offset)
144 		*features = RTC_CORRECTION_FEATURE;
145 	*range_min = rtc_device->range_min;
146 	*range_max = rtc_device->range_max;
147 
148 	return TEE_SUCCESS;
149 }
150 
151 static inline TEE_Result rtc_get_time(struct optee_rtc_time *tm)
152 {
153 	if (!rtc_device)
154 		return TEE_ERROR_NOT_SUPPORTED;
155 
156 	return rtc_device->ops->get_time(rtc_device, tm);
157 }
158 
159 static inline TEE_Result rtc_set_time(struct optee_rtc_time *tm)
160 {
161 	if (!rtc_device || !rtc_device->ops->set_time)
162 		return TEE_ERROR_NOT_SUPPORTED;
163 
164 	if (tm->tm_mon >= 12 ||
165 	    tm->tm_mday > rtc_get_month_days(tm->tm_mon, tm->tm_year) ||
166 	    tm->tm_wday >= 7 || tm->tm_hour >= 24 || tm->tm_min >= 60 ||
167 	    tm->tm_sec >= 60 || tm->tm_ms >= 1000 ||
168 	    rtc_timecmp(tm, &rtc_device->range_min) < 0 ||
169 	    rtc_timecmp(tm, &rtc_device->range_max) > 0)
170 		return TEE_ERROR_BAD_PARAMETERS;
171 
172 	return rtc_device->ops->set_time(rtc_device, tm);
173 }
174 
175 static inline TEE_Result rtc_get_offset(long *offset)
176 {
177 	if (!rtc_device || !rtc_device->ops->get_offset)
178 		return TEE_ERROR_NOT_SUPPORTED;
179 
180 	return rtc_device->ops->get_offset(rtc_device, offset);
181 }
182 
183 static inline TEE_Result rtc_set_offset(long offset)
184 {
185 	if (!rtc_device || !rtc_device->ops->set_offset)
186 		return TEE_ERROR_NOT_SUPPORTED;
187 
188 	return rtc_device->ops->set_offset(rtc_device, offset);
189 }
190 
191 #else
192 
193 static inline void rtc_register(struct rtc *rtc __unused) {}
194 
195 static inline bool __noreturn rtc_is_a_leap_year(uint32_t year __unused)
196 {
197 	panic();
198 }
199 
200 static inline uint8_t __noreturn rtc_get_month_days(uint32_t month __unused,
201 						    uint32_t year __unused)
202 {
203 	panic();
204 }
205 
206 static inline int __noreturn rtc_timecmp(struct optee_rtc_time *a __unused,
207 					 struct optee_rtc_time *b __unused)
208 {
209 	panic();
210 }
211 
212 static inline TEE_Result rtc_get_info(uint64_t *features __unused,
213 				      struct optee_rtc_time *range_min __unused,
214 				      struct optee_rtc_time *range_max __unused)
215 {
216 	return TEE_ERROR_NOT_SUPPORTED;
217 }
218 
219 static inline TEE_Result rtc_get_time(struct optee_rtc_time *tm __unused)
220 {
221 	return TEE_ERROR_NOT_SUPPORTED;
222 }
223 
224 static inline TEE_Result rtc_set_time(struct optee_rtc_time *tm __unused)
225 {
226 	return TEE_ERROR_NOT_SUPPORTED;
227 }
228 
229 static inline TEE_Result rtc_get_offset(long *offset __unused)
230 {
231 	return TEE_ERROR_NOT_SUPPORTED;
232 }
233 
234 static inline TEE_Result rtc_set_offset(long offset __unused)
235 {
236 	return TEE_ERROR_NOT_SUPPORTED;
237 }
238 
239 static inline signed long long
240 rtc_diff_calendar_ms(struct optee_rtc_time *ref1 __unused,
241 		     struct optee_rtc_time *ref2 __unused)
242 {
243 	return LLONG_MAX;
244 }
245 
246 static inline signed long long
247 rtc_diff_calendar_tick(struct optee_rtc_time *ref1 __unused,
248 		       struct optee_rtc_time *ref2 __unused,
249 		       unsigned long long tick_rate __unused)
250 {
251 	return LLONG_MAX;
252 }
253 #endif
254 #endif /* __DRIVERS_RTC_H */
255