diff options
author | Jack Rosenthal <jrosenth@chromium.org> | 2019-06-19 15:30:06 -0600 |
---|---|---|
committer | Commit Bot <commit-bot@chromium.org> | 2019-06-24 22:45:16 +0000 |
commit | c6aa7a384d179128339068531f79baed3a42ceef (patch) | |
tree | 5478f45a9a5f51e3889a6b317a9655515cfb8ee5 /common | |
parent | e9144509b437218de7092ad4340bb9821ec4ae21 (diff) | |
download | chrome-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')
-rw-r--r-- | common/timer.c | 95 |
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); } } |