summaryrefslogtreecommitdiff
path: root/common/timer.c
diff options
context:
space:
mode:
authorJack Rosenthal <jrosenth@chromium.org>2019-06-19 15:30:06 -0600
committerCommit Bot <commit-bot@chromium.org>2019-06-24 22:45:16 +0000
commitc6aa7a384d179128339068531f79baed3a42ceef (patch)
tree5478f45a9a5f51e3889a6b317a9655515cfb8ee5 /common/timer.c
parente9144509b437218de7092ad4340bb9821ec4ae21 (diff)
downloadchrome-ec-c6aa7a384d179128339068531f79baed3a42ceef.tar.gz
common: provide config option for 64-bit hwtimer
This adds a config option, CONFIG_HWTIMER_64BIT, which when enabled expects the chip implementation to define __hw_clock_source_read64 and __hw_clock_source_set64. This allows for support of native 64-bit hardware clock when available on hardware instead of a rollover interrupt style. BUG=chromium:976804 BRANCH=none TEST=made implementation of 64-bit hardware timer for ISH (child CL), and working great Change-Id: Idb2c3bb8f804e6c83a33901c953ddd5f1ae89784 Signed-off-by: Jack Rosenthal <jrosenth@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/1668055 Reviewed-by: Yuval Peress <peress@chromium.org> Reviewed-by: Denis Brockus <dbrockus@chromium.org>
Diffstat (limited to 'common/timer.c')
-rw-r--r--common/timer.c95
1 files changed, 68 insertions, 27 deletions
diff --git a/common/timer.c b/common/timer.c
index 525fc4a27d..7ed3af25bf 100644
--- a/common/timer.c
+++ b/common/timer.c
@@ -17,8 +17,16 @@
#define TIMER_SYSJUMP_TAG 0x4d54 /* "TM" */
-/* High word of the 64-bit timestamp counter */
+/*
+ * High word of the 64-bit timestamp counter. Not used if
+ * CONFIG_HWTIMER_64BIT is enabled.
+ */
+#ifdef CONFIG_HWTIMER_64BIT
+/* Declaring as extern will cause linker errors if used */
+extern uint32_t clksrc_high;
+#else
static volatile uint32_t clksrc_high;
+#endif /* CONFIG_HWTIMER_64BIT */
/* Bitmap of currently running timers */
static uint32_t timer_running;
@@ -56,7 +64,7 @@ void process_timers(int overflow)
timestamp_t next;
timestamp_t now;
- if (overflow)
+ if (!IS_ENABLED(CONFIG_HWTIMER_64BIT) && overflow)
clksrc_high++;
do {
@@ -114,19 +122,21 @@ void udelay(unsigned us)
}
#endif
-int timer_arm(timestamp_t tstamp, task_id_t tskid)
+int timer_arm(timestamp_t event, task_id_t tskid)
{
+ timestamp_t now = get_time();
+
ASSERT(tskid < TASK_ID_COUNT);
- if (timer_running & (1<<tskid))
+ if (timer_running & BIT(tskid))
return EC_ERROR_BUSY;
- timer_deadline[tskid] = tstamp;
- atomic_or(&timer_running, 1<<tskid);
+ timer_deadline[tskid] = event;
+ atomic_or(&timer_running, BIT(tskid));
/* Modify the next event if needed */
- if ((tstamp.le.hi < clksrc_high) ||
- ((tstamp.le.hi == clksrc_high) && (tstamp.le.lo <= next_deadline)))
+ if ((event.le.hi < now.le.hi) ||
+ ((event.le.hi == now.le.hi) && (event.le.lo <= next_deadline)))
task_trigger_irq(timer_irq);
return EC_SUCCESS;
@@ -136,7 +146,7 @@ void timer_cancel(task_id_t tskid)
{
ASSERT(tskid < TASK_ID_COUNT);
- atomic_clear(&timer_running, 1 << tskid);
+ atomic_clear(&timer_running, BIT(tskid));
/*
* Don't need to cancel the hardware timer interrupt, instead do
* timer-related housekeeping when the next timer interrupt fires.
@@ -175,12 +185,18 @@ void usleep(unsigned us)
timestamp_t get_time(void)
{
timestamp_t ts;
- ts.le.hi = clksrc_high;
- ts.le.lo = __hw_clock_source_read();
- if (ts.le.hi != clksrc_high) {
+
+ if (IS_ENABLED(CONFIG_HWTIMER_64BIT)) {
+ ts.val = __hw_clock_source_read64();
+ } else {
ts.le.hi = clksrc_high;
ts.le.lo = __hw_clock_source_read();
+ if (ts.le.hi != clksrc_high) {
+ ts.le.hi = clksrc_high;
+ ts.le.lo = __hw_clock_source_read();
+ }
}
+
return ts;
}
@@ -192,38 +208,57 @@ clock_t clock(void)
void force_time(timestamp_t ts)
{
- clksrc_high = ts.le.hi;
- __hw_clock_source_set(ts.le.lo);
+ if (IS_ENABLED(CONFIG_HWTIMER_64BIT)) {
+ __hw_clock_source_set64(ts.val);
+ } else {
+ clksrc_high = ts.le.hi;
+ __hw_clock_source_set(ts.le.lo);
+ }
+
/* some timers might be already expired : process them */
task_trigger_irq(timer_irq);
}
-#ifdef CONFIG_CMD_TIMERINFO
+/*
+ * Define versions of __hw_clock_source_read and __hw_clock_source_set
+ * that wrap the 64-bit versions for chips with CONFIG_HWTIMER_64BIT.
+ */
+#ifdef CONFIG_HWTIMER_64BIT
+__overridable uint32_t __hw_clock_source_read(void)
+{
+ return (uint32_t)__hw_clock_source_read64();
+}
+
+void __hw_clock_source_set(uint32_t ts)
+{
+ uint64_t current = __hw_clock_source_read64();
+
+ __hw_clock_source_set64(((current >> 32) << 32) | ts);
+}
+#endif /* CONFIG_HWTIMER_64BIT */
+
void timer_print_info(void)
{
- uint64_t t = get_time().val;
- uint64_t deadline = (uint64_t)clksrc_high << 32 |
+ timestamp_t t = get_time();
+ uint64_t deadline = (uint64_t)t.le.hi << 32 |
__hw_clock_event_get();
int tskid;
ccprintf("Time: 0x%016lx us, %11.6ld s\n"
"Deadline: 0x%016lx -> %11.6ld s from now\n"
"Active timers:\n",
- t, t, deadline, deadline - t);
+ t.val, t.val, deadline, deadline - t.val);
cflush();
for (tskid = 0; tskid < TASK_ID_COUNT; tskid++) {
- if (timer_running & (1<<tskid)) {
+ if (timer_running & BIT(tskid)) {
ccprintf(" Tsk %2d 0x%016lx -> %11.6ld\n", tskid,
timer_deadline[tskid].val,
- timer_deadline[tskid].val - t);
+ timer_deadline[tskid].val - t.val);
cflush();
}
}
}
-#else
-void timer_print_info(void) { }
-#endif
void timer_init(void)
{
@@ -236,11 +271,17 @@ void timer_init(void)
ts = (const timestamp_t *)system_get_jump_tag(TIMER_SYSJUMP_TAG,
&version, &size);
if (ts && version == 1 && size == sizeof(timestamp_t)) {
- clksrc_high = ts->le.hi;
- timer_irq = __hw_clock_source_init(ts->le.lo);
+ if (IS_ENABLED(CONFIG_HWTIMER_64BIT)) {
+ timer_irq = __hw_clock_source_init64(ts->val);
+ } else {
+ clksrc_high = ts->le.hi;
+ timer_irq = __hw_clock_source_init(ts->le.lo);
+ }
} else {
- clksrc_high = 0;
- timer_irq = __hw_clock_source_init(0);
+ if (IS_ENABLED(CONFIG_HWTIMER_64BIT))
+ timer_irq = __hw_clock_source_init64(0);
+ else
+ timer_irq = __hw_clock_source_init(0);
}
}