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