summaryrefslogtreecommitdiff
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
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>
-rw-r--r--common/timer.c95
-rw-r--r--include/config.h10
-rw-r--r--include/hwtimer.h37
3 files changed, 112 insertions, 30 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);
}
}
diff --git a/include/config.h b/include/config.h
index c71d79461e..ed7acaa0ad 100644
--- a/include/config.h
+++ b/include/config.h
@@ -2111,6 +2111,16 @@
*/
#undef CONFIG_HIBERNATE_PSL
+/*
+ * Chip supports a 64-bit hardware timer and implements
+ * __hw_clock_source_read64 and __hw_clock_source_set64.
+ *
+ * Chips with this config enabled may optionally define
+ * __hw_clock_source_read as a 32-bit set function for
+ * latency-sensitive situations.
+ */
+#undef CONFIG_HWTIMER_64BIT
+
/* Use a hardware specific udelay(). */
#undef CONFIG_HW_SPECIFIC_UDELAY
diff --git a/include/hwtimer.h b/include/hwtimer.h
index b83fcc8e76..3c0e9aaf8a 100644
--- a/include/hwtimer.h
+++ b/include/hwtimer.h
@@ -25,16 +25,19 @@ uint32_t __hw_clock_event_get(void);
void __hw_clock_event_clear(void);
/**
- * Get the value of the free-running counter used as clock
+ * Get the lower 32-bits of the free-running counter used as clock
*
* The counter resolution must be 1us, since udelay() relies on this.
*
* @return current counter value
*/
+#ifdef CONFIG_HWTIMER_64BIT
+__override_proto
+#endif
uint32_t __hw_clock_source_read(void);
/**
- * Override the current value of the hardware counter
+ * Override the lower 32-bits of the hardware counter
*
* The new value takes effect immediately and the counter continues counting
* from there, assuming it is enabled
@@ -44,6 +47,25 @@ uint32_t __hw_clock_source_read(void);
void __hw_clock_source_set(uint32_t ts);
/**
+ * Get the 64-bit value of the free-running counter used as clock,
+ * only available when CONFIG_HWTIMER_64BIT is enabled.
+ *
+ * This function should only be used by common/timer.c or
+ * chip-specific code, as get_time() abstracts the config option away.
+ */
+uint64_t __hw_clock_source_read64(void);
+
+/**
+ * Override the 64-bit value of the free-running counter used as
+ * clock, only available when CONFIG_HWTIMER_64BIT is enabled.
+ *
+ * This function should only be used by common/timer.c or
+ * chip-specific code, as force_time() abstracts the config option
+ * away.
+ */
+void __hw_clock_source_set64(uint64_t timestamp);
+
+/**
* Enable clock to a timer.
*
* @param n Timer number to enable/disable
@@ -60,9 +82,18 @@ void __hw_timer_enable_clock(int n, int enable);
int __hw_clock_source_init(uint32_t start_t);
/**
+ * Initializes the hardware timer used to provide clock services, using the
+ * specified start timer value (CONFIG_HWTIMER_64BIT enabled).
+ *
+ * It returns the IRQ number of the timer routine.
+ */
+int __hw_clock_source_init64(uint64_t start_t);
+
+/**
* Searches the next deadline and program it in the timer hardware.
*
- * overflow: if true, the 32-bit counter as overflowed since the last call.
+ * overflow: if true, the 32-bit counter as overflowed since the last
+ * call. Goes unused if CONFIG_HWTIMER_64BIT is enabled.
*
* This function is exported from the common timers code as an helper for the
* hardware timer interrupt routine.