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