xref: /optee_os/core/include/drivers/rtc.h (revision a83e616ee6962603e0bb6aa0ad668aed8810c6eb)
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 	return rtc_device->ops->set_time(rtc_device, tm);
165 }
166 
167 static inline TEE_Result rtc_get_offset(long *offset)
168 {
169 	if (!rtc_device || !rtc_device->ops->get_offset)
170 		return TEE_ERROR_NOT_SUPPORTED;
171 
172 	return rtc_device->ops->get_offset(rtc_device, offset);
173 }
174 
175 static inline TEE_Result rtc_set_offset(long offset)
176 {
177 	if (!rtc_device || !rtc_device->ops->set_offset)
178 		return TEE_ERROR_NOT_SUPPORTED;
179 
180 	return rtc_device->ops->set_offset(rtc_device, offset);
181 }
182 
183 #else
184 
185 static inline void rtc_register(struct rtc *rtc __unused) {}
186 
187 static inline bool __noreturn rtc_is_a_leap_year(uint32_t year __unused)
188 {
189 	panic();
190 }
191 
192 static inline uint8_t __noreturn rtc_get_month_days(uint32_t month __unused,
193 						    uint32_t year __unused)
194 {
195 	panic();
196 }
197 
198 static inline int __noreturn rtc_timecmp(struct optee_rtc_time *a __unused,
199 					 struct optee_rtc_time *b __unused)
200 {
201 	panic();
202 }
203 
204 static inline TEE_Result rtc_get_info(uint64_t *features __unused,
205 				      struct optee_rtc_time *range_min __unused,
206 				      struct optee_rtc_time *range_max __unused)
207 {
208 	return TEE_ERROR_NOT_SUPPORTED;
209 }
210 
211 static inline TEE_Result rtc_get_time(struct optee_rtc_time *tm __unused)
212 {
213 	return TEE_ERROR_NOT_SUPPORTED;
214 }
215 
216 static inline TEE_Result rtc_set_time(struct optee_rtc_time *tm __unused)
217 {
218 	return TEE_ERROR_NOT_SUPPORTED;
219 }
220 
221 static inline TEE_Result rtc_get_offset(long *offset __unused)
222 {
223 	return TEE_ERROR_NOT_SUPPORTED;
224 }
225 
226 static inline TEE_Result rtc_set_offset(long offset __unused)
227 {
228 	return TEE_ERROR_NOT_SUPPORTED;
229 }
230 
231 static inline signed long long
232 rtc_diff_calendar_ms(struct optee_rtc_time *ref1 __unused,
233 		     struct optee_rtc_time *ref2 __unused)
234 {
235 	return LLONG_MAX;
236 }
237 
238 static inline signed long long
239 rtc_diff_calendar_tick(struct optee_rtc_time *ref1 __unused,
240 		       struct optee_rtc_time *ref2 __unused,
241 		       unsigned long long tick_rate __unused)
242 {
243 	return LLONG_MAX;
244 }
245 #endif
246 #endif /* __DRIVERS_RTC_H */
247