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 /* The RTC allows to set/read an alarm */
16 #define RTC_ALARM_FEATURE BIT(1)
17 /* The RTC can wake-up the platform through alarm */
18 #define RTC_WAKEUP_ALARM BIT(2)
19
20 #define MS_PER_SEC 1000
21 #define MS_PER_MIN (60 * MS_PER_SEC)
22 #define MS_PER_HOUR (60 * MS_PER_MIN)
23 #define MS_PER_DAY (24 * MS_PER_HOUR)
24
25 #define RTC_TIME(year, mon, mday, wday, hour, min, sec, ms) \
26 { \
27 .tm_year = (year), \
28 .tm_mon = (mon), \
29 .tm_mday = (mday), \
30 .tm_wday = (wday), \
31 .tm_hour = (hour), \
32 .tm_min = (min), \
33 .tm_sec = (sec), \
34 .tm_ms = (ms), \
35 }
36
37 /*
38 * struct optee_rtc_time - Time in Gregorian calendar
39 *
40 * @tm_year: Absolute year
41 * @tm_mon: Month: 0=January, 1=February, ..., 11=December
42 * @tm_mday: Month day start from 1
43 * @tm_wday: Week day: 0=Sunday, 1=Monday, ..., 6=Saturday
44 * @tm_hour: Hour in range [0 23]
45 * @tm_min: Minute in range [0 59]
46 * @tm_sec: Second in range [0 59]
47 * @tm_ms: Millisecond in range [0 999] or 0 if no applicable
48 */
49 struct optee_rtc_time {
50 uint32_t tm_year;
51 uint32_t tm_mon;
52 uint32_t tm_mday;
53 uint32_t tm_wday;
54 uint32_t tm_hour;
55 uint32_t tm_min;
56 uint32_t tm_sec;
57 uint32_t tm_ms;
58 };
59
60 struct rtc {
61 const struct rtc_ops *ops;
62 struct optee_rtc_time range_min;
63 struct optee_rtc_time range_max;
64 bool is_wakeup_source;
65 };
66
67 /*
68 * struct optee_rtc_alarm - The RTC alarm
69 * @enabled: 1 if the alarm is enabled, 0 otherwise
70 * @pending: 1 if the alarm is pending, 0 otherwise
71 * @time: The alarm time
72 */
73 struct optee_rtc_alarm {
74 bool enabled;
75 bool pending;
76 struct optee_rtc_time time;
77 };
78
79 /*
80 * enum rtc_wait_alarm_status - Return status wait_alarm ops
81 * @RTC_WAIT_ALARM_RESET: Reset the wait for the RTC alarm
82 * @RTC_WAIT_ALARM_ALARM_OCCURRED: The RTC alarm occurred
83 * @RTC_WAIT_ALARM_CANCELED: The wait for the RTC alarm was canceled
84 */
85 enum rtc_wait_alarm_status {
86 RTC_WAIT_ALARM_RESET,
87 RTC_WAIT_ALARM_ALARM_OCCURRED,
88 RTC_WAIT_ALARM_CANCELED,
89 };
90
91 /*
92 * struct rtc_ops - The RTC device operations
93 *
94 * @get_time: Get the RTC time.
95 * @set_time: Set the RTC time.
96 * @get_offset: Get the RTC offset.
97 * @set_offset: Set the RTC offset
98 * @read_alarm: Read the RTC alarm
99 * @set_alarm: Set the RTC alarm
100 * @enable_alarm: Enable the RTC alarm
101 * @wait_alarm: Wait for the RTC alarm
102 * @cancel_wait: Cancel the wait for the RTC alarm
103 * @set_alarm_wakeup_status: Set the wakeup capability of the alarm
104 */
105 struct rtc_ops {
106 TEE_Result (*get_time)(struct rtc *rtc, struct optee_rtc_time *tm);
107 TEE_Result (*set_time)(struct rtc *rtc, struct optee_rtc_time *tm);
108 TEE_Result (*get_offset)(struct rtc *rtc, long *offset);
109 TEE_Result (*set_offset)(struct rtc *rtc, long offset);
110 TEE_Result (*read_alarm)(struct rtc *rtc, struct optee_rtc_alarm *alrm);
111 TEE_Result (*set_alarm)(struct rtc *rtc, struct optee_rtc_alarm *alrm);
112 TEE_Result (*enable_alarm)(struct rtc *rtc, bool enable);
113 TEE_Result (*wait_alarm)(struct rtc *rtc,
114 enum rtc_wait_alarm_status *status);
115 TEE_Result (*cancel_wait)(struct rtc *rtc);
116 TEE_Result (*set_alarm_wakeup_status)(struct rtc *rtc, bool status);
117 };
118
119 #ifdef CFG_DRIVERS_RTC
120 extern struct rtc *rtc_device;
121
122 /* Register a RTC device as the system RTC */
123 void rtc_register(struct rtc *rtc);
124
125 /**
126 * rtc_is_a_leap_year() - Check if a year is a leap year
127 * @year: The year to check
128 *
129 * Return: true if the year is a leap year, false otherwise
130 */
131 bool rtc_is_a_leap_year(uint32_t year);
132
133 /**
134 * rtc_get_month_days() - Get the number of days in a month
135 * @month: The month to know the number of days
136 * @year: The year of the month
137 *
138 * Return: Number of days in the month
139 */
140 uint8_t rtc_get_month_days(uint32_t month, uint32_t year);
141
142 /**
143 * rtc_timecmp() - Compare two RTC time structures
144 * @a: First RTC time
145 * @b: Second RTC time
146 *
147 * Return a negative value if @a < @b
148 * Return 0 if @a == @b
149 * Return a positive value if @a > @b
150 */
151 int rtc_timecmp(struct optee_rtc_time *a, struct optee_rtc_time *b);
152
153 /**
154 * rtc_diff_calendar_ms() - Return the difference in milliseconds between
155 * two times captures.
156 * @ref1: First time capture
157 * @ref2: Second time capture
158 *
159 * Return @ref1 - @ref2 in milliseconds or LLONG_MAX in case of overflow
160 */
161 signed long long rtc_diff_calendar_ms(struct optee_rtc_time *ref1,
162 struct optee_rtc_time *ref2);
163
164 /**
165 * rtc_diff_calendar_tick() - Return the difference in number of ticks between
166 * two times captures.
167 * @ref1: First time capture
168 * @ref2: Second time capture
169 * @tick_rate: Tick rate
170 *
171 * Return @ref1 - @ref2 in number of ticks. In case of tick computation
172 * overflow, return LLONG_MAX
173 */
174 signed long long rtc_diff_calendar_tick(struct optee_rtc_time *ref1,
175 struct optee_rtc_time *ref2,
176 unsigned long long tick_rate);
177
rtc_get_info(uint64_t * features,struct optee_rtc_time * range_min,struct optee_rtc_time * range_max)178 static inline TEE_Result rtc_get_info(uint64_t *features,
179 struct optee_rtc_time *range_min,
180 struct optee_rtc_time *range_max)
181 {
182 if (!rtc_device)
183 return TEE_ERROR_NOT_SUPPORTED;
184
185 if (rtc_device->ops->set_offset)
186 *features = RTC_CORRECTION_FEATURE;
187 *range_min = rtc_device->range_min;
188 *range_max = rtc_device->range_max;
189
190 if (rtc_device->ops->set_alarm)
191 *features |= RTC_ALARM_FEATURE;
192
193 if (rtc_device->is_wakeup_source)
194 *features |= RTC_WAKEUP_ALARM;
195
196 return TEE_SUCCESS;
197 }
198
rtc_get_time(struct optee_rtc_time * tm)199 static inline TEE_Result rtc_get_time(struct optee_rtc_time *tm)
200 {
201 if (!rtc_device)
202 return TEE_ERROR_NOT_SUPPORTED;
203
204 return rtc_device->ops->get_time(rtc_device, tm);
205 }
206
rtc_set_time(struct optee_rtc_time * tm)207 static inline TEE_Result rtc_set_time(struct optee_rtc_time *tm)
208 {
209 if (!rtc_device || !rtc_device->ops->set_time)
210 return TEE_ERROR_NOT_SUPPORTED;
211
212 if (tm->tm_mon >= 12 ||
213 tm->tm_mday > rtc_get_month_days(tm->tm_mon, tm->tm_year) ||
214 tm->tm_wday >= 7 || tm->tm_hour >= 24 || tm->tm_min >= 60 ||
215 tm->tm_sec >= 60 || tm->tm_ms >= 1000 ||
216 rtc_timecmp(tm, &rtc_device->range_min) < 0 ||
217 rtc_timecmp(tm, &rtc_device->range_max) > 0)
218 return TEE_ERROR_BAD_PARAMETERS;
219
220 return rtc_device->ops->set_time(rtc_device, tm);
221 }
222
rtc_get_offset(long * offset)223 static inline TEE_Result rtc_get_offset(long *offset)
224 {
225 if (!rtc_device || !rtc_device->ops->get_offset)
226 return TEE_ERROR_NOT_SUPPORTED;
227
228 return rtc_device->ops->get_offset(rtc_device, offset);
229 }
230
rtc_set_offset(long offset)231 static inline TEE_Result rtc_set_offset(long offset)
232 {
233 if (!rtc_device || !rtc_device->ops->set_offset)
234 return TEE_ERROR_NOT_SUPPORTED;
235
236 return rtc_device->ops->set_offset(rtc_device, offset);
237 }
238
rtc_read_alarm(struct optee_rtc_alarm * alarm)239 static inline TEE_Result rtc_read_alarm(struct optee_rtc_alarm *alarm)
240 {
241 if (!rtc_device || !rtc_device->ops->read_alarm)
242 return TEE_ERROR_NOT_SUPPORTED;
243
244 return rtc_device->ops->read_alarm(rtc_device, alarm);
245 }
246
rtc_set_alarm(struct optee_rtc_alarm * alarm)247 static inline TEE_Result rtc_set_alarm(struct optee_rtc_alarm *alarm)
248 {
249 if (!rtc_device || !rtc_device->ops->set_alarm)
250 return TEE_ERROR_NOT_SUPPORTED;
251
252 return rtc_device->ops->set_alarm(rtc_device, alarm);
253 }
254
rtc_enable_alarm(bool enable)255 static inline TEE_Result rtc_enable_alarm(bool enable)
256 {
257 if (!rtc_device || !rtc_device->ops->enable_alarm)
258 return TEE_ERROR_NOT_SUPPORTED;
259
260 return rtc_device->ops->enable_alarm(rtc_device, enable);
261 }
262
rtc_wait_alarm(enum rtc_wait_alarm_status * status)263 static inline TEE_Result rtc_wait_alarm(enum rtc_wait_alarm_status *status)
264 {
265 if (!rtc_device || !rtc_device->ops->wait_alarm)
266 return TEE_ERROR_NOT_SUPPORTED;
267
268 return rtc_device->ops->wait_alarm(rtc_device, status);
269 }
270
rtc_cancel_wait_alarm(void)271 static inline TEE_Result rtc_cancel_wait_alarm(void)
272 {
273 if (!rtc_device || !rtc_device->ops->cancel_wait)
274 return TEE_ERROR_NOT_SUPPORTED;
275
276 return rtc_device->ops->cancel_wait(rtc_device);
277 }
278
rtc_set_alarm_wakeup_status(bool status)279 static inline TEE_Result rtc_set_alarm_wakeup_status(bool status)
280 {
281 if (!rtc_device || !rtc_device->ops->set_alarm_wakeup_status)
282 return TEE_ERROR_NOT_SUPPORTED;
283
284 return rtc_device->ops->set_alarm_wakeup_status(rtc_device, status);
285 }
286 #else
287
rtc_register(struct rtc * rtc __unused)288 static inline void rtc_register(struct rtc *rtc __unused) {}
289
rtc_is_a_leap_year(uint32_t year __unused)290 static inline bool __noreturn rtc_is_a_leap_year(uint32_t year __unused)
291 {
292 panic();
293 }
294
rtc_get_month_days(uint32_t month __unused,uint32_t year __unused)295 static inline uint8_t __noreturn rtc_get_month_days(uint32_t month __unused,
296 uint32_t year __unused)
297 {
298 panic();
299 }
300
rtc_timecmp(struct optee_rtc_time * a __unused,struct optee_rtc_time * b __unused)301 static inline int __noreturn rtc_timecmp(struct optee_rtc_time *a __unused,
302 struct optee_rtc_time *b __unused)
303 {
304 panic();
305 }
306
rtc_get_info(uint64_t * features __unused,struct optee_rtc_time * range_min __unused,struct optee_rtc_time * range_max __unused)307 static inline TEE_Result rtc_get_info(uint64_t *features __unused,
308 struct optee_rtc_time *range_min __unused,
309 struct optee_rtc_time *range_max __unused)
310 {
311 return TEE_ERROR_NOT_SUPPORTED;
312 }
313
rtc_get_time(struct optee_rtc_time * tm __unused)314 static inline TEE_Result rtc_get_time(struct optee_rtc_time *tm __unused)
315 {
316 return TEE_ERROR_NOT_SUPPORTED;
317 }
318
rtc_set_time(struct optee_rtc_time * tm __unused)319 static inline TEE_Result rtc_set_time(struct optee_rtc_time *tm __unused)
320 {
321 return TEE_ERROR_NOT_SUPPORTED;
322 }
323
rtc_get_offset(long * offset __unused)324 static inline TEE_Result rtc_get_offset(long *offset __unused)
325 {
326 return TEE_ERROR_NOT_SUPPORTED;
327 }
328
rtc_set_offset(long offset __unused)329 static inline TEE_Result rtc_set_offset(long offset __unused)
330 {
331 return TEE_ERROR_NOT_SUPPORTED;
332 }
333
334 static inline signed long long
rtc_diff_calendar_ms(struct optee_rtc_time * ref1 __unused,struct optee_rtc_time * ref2 __unused)335 rtc_diff_calendar_ms(struct optee_rtc_time *ref1 __unused,
336 struct optee_rtc_time *ref2 __unused)
337 {
338 return LLONG_MAX;
339 }
340
341 static inline signed long long
rtc_diff_calendar_tick(struct optee_rtc_time * ref1 __unused,struct optee_rtc_time * ref2 __unused,unsigned long long tick_rate __unused)342 rtc_diff_calendar_tick(struct optee_rtc_time *ref1 __unused,
343 struct optee_rtc_time *ref2 __unused,
344 unsigned long long tick_rate __unused)
345 {
346 return LLONG_MAX;
347 }
348
rtc_read_alarm(struct optee_rtc_alarm * alarm __unused)349 static inline TEE_Result rtc_read_alarm(struct optee_rtc_alarm *alarm __unused)
350 {
351 return TEE_ERROR_NOT_SUPPORTED;
352 }
353
rtc_set_alarm(struct optee_rtc_alarm * alarm __unused)354 static inline TEE_Result rtc_set_alarm(struct optee_rtc_alarm *alarm __unused)
355 {
356 return TEE_ERROR_NOT_SUPPORTED;
357 }
358
rtc_enable_alarm(bool enable __unused)359 static inline TEE_Result rtc_enable_alarm(bool enable __unused)
360 {
361 return TEE_ERROR_NOT_SUPPORTED;
362 }
363
364 static inline TEE_Result
rtc_wait_alarm(enum rtc_wait_alarm_status * status __unused)365 rtc_wait_alarm(enum rtc_wait_alarm_status *status __unused)
366 {
367 return TEE_ERROR_NOT_SUPPORTED;
368 }
369
rtc_cancel_wait_alarm(void)370 static inline TEE_Result rtc_cancel_wait_alarm(void)
371 {
372 return TEE_ERROR_NOT_SUPPORTED;
373 }
374
rtc_set_alarm_wakeup_status(bool status __unused)375 static inline TEE_Result rtc_set_alarm_wakeup_status(bool status __unused)
376 {
377 return TEE_ERROR_NOT_SUPPORTED;
378 }
379 #endif
380 #endif /* __DRIVERS_RTC_H */
381