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