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