File: rtc.h

package info (click to toggle)
optee-os 4.8.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 31,960 kB
  • sloc: ansic: 444,388; asm: 12,922; python: 3,719; makefile: 1,681; sh: 238
file content (380 lines) | stat: -rw-r--r-- 10,073 bytes parent folder | download
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 */