diff options
author | Tzung-Bi Shih <tzungbi@chromium.org> | 2020-05-13 17:25:08 +0800 |
---|---|---|
committer | Commit Bot <commit-bot@chromium.org> | 2020-06-10 10:37:31 +0000 |
commit | fed72520335e09b9ba401c93342dbd90ba5251d7 (patch) | |
tree | e0df3a4b6772ed0ee2fe221d2000d0d84cadf637 /chip/mt8192_scp | |
parent | 808042369ae338d3acfb6867f06cab2907c98cd8 (diff) | |
download | chrome-ec-fed72520335e09b9ba401c93342dbd90ba5251d7.tar.gz |
chip/mt8192_scp: add system tick timers
BRANCH=none
BUG=b:146213943
BUG=b:156220843
TEST=make BOARD=asurada_scp
Signed-off-by: Tzung-Bi Shih <tzungbi@chromium.org>
Change-Id: I1c04d1df9c12b2834f0a7a2b29fe0c259ef6a195
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/2198822
Reviewed-by: Eric Yilun Lin <yllin@chromium.org>
Diffstat (limited to 'chip/mt8192_scp')
-rw-r--r-- | chip/mt8192_scp/hrtimer.c | 188 | ||||
-rw-r--r-- | chip/mt8192_scp/intc.c | 12 | ||||
-rw-r--r-- | chip/mt8192_scp/registers.h | 18 |
3 files changed, 209 insertions, 9 deletions
diff --git a/chip/mt8192_scp/hrtimer.c b/chip/mt8192_scp/hrtimer.c index 22c68177be..29088120ef 100644 --- a/chip/mt8192_scp/hrtimer.c +++ b/chip/mt8192_scp/hrtimer.c @@ -14,26 +14,208 @@ #include "common.h" #include "hwtimer.h" +#include "registers.h" +#include "task.h" -int __hw_clock_source_init(uint32_t start_t) +#define TIMER_SYSTEM 5 +#define TIMER_EVENT 3 +#define TIMER_CLOCK_MHZ 26 +#define OVERFLOW_TICKS (TIMER_CLOCK_MHZ * 0x100000000 - 1) + +/* High 32-bit for system timer. */ +static uint8_t sys_high; +/* High 32-bit for event timer. */ +static uint8_t event_high; + +static void timer_enable(int n) +{ + /* cannot be changed when timer is enabled */ + SCP_CORE0_TIMER_IRQ_CTRL(n) |= TIMER_IRQ_EN; + SCP_CORE0_TIMER_EN(n) |= TIMER_EN; +} + +static void timer_disable(int n) +{ + SCP_CORE0_TIMER_EN(n) &= ~TIMER_EN; + /* cannot be changed when timer is enabled */ + SCP_CORE0_TIMER_IRQ_CTRL(n) &= ~TIMER_IRQ_EN; +} + +static int timer_is_irq(int n) +{ + return SCP_CORE0_TIMER_IRQ_CTRL(n) & TIMER_IRQ_STATUS; +} + +static void timer_ack_irq(int n) +{ + SCP_CORE0_TIMER_IRQ_CTRL(n) |= TIMER_IRQ_CLR; +} + +static void timer_set_reset_value(int n, uint32_t reset_value) +{ + /* cannot be changed when timer is enabled */ + SCP_CORE0_TIMER_RST_VAL(n) = reset_value; +} + +static void timer_set_clock(int n, uint32_t clock_source) +{ + SCP_CORE0_TIMER_EN(n) = + (SCP_CORE0_TIMER_EN(n) & ~TIMER_CLK_SRC_MASK) | clock_source; +} + +static void timer_reset(int n) +{ + timer_disable(n); + timer_ack_irq(n); + timer_set_reset_value(n, 0xffffffff); + timer_set_clock(n, TIMER_CLK_SRC_32K); +} + +/* Convert hardware countdown timer to 64bit countup ticks. */ +static uint64_t timer_read_raw_system(void) +{ + uint32_t timer_ctrl = SCP_CORE0_TIMER_IRQ_CTRL(TIMER_SYSTEM); + uint32_t sys_high_adj = sys_high; + + /* + * If an IRQ is pending, but has not been serviced yet, adjust the + * sys_high value. + */ + if (timer_ctrl & TIMER_IRQ_STATUS) + sys_high_adj = sys_high ? (sys_high - 1) + : (TIMER_CLOCK_MHZ - 1); + + return OVERFLOW_TICKS - (((uint64_t)sys_high_adj << 32) | + SCP_CORE0_TIMER_CUR_VAL(TIMER_SYSTEM)); +} + +static uint64_t timer_read_raw_event(void) { + return OVERFLOW_TICKS - (((uint64_t)event_high << 32) | + SCP_CORE0_TIMER_CUR_VAL(TIMER_EVENT)); +} + +static void timer_reload(int n, uint32_t value) +{ + timer_disable(n); + timer_set_reset_value(n, value); + timer_enable(n); +} + +static int timer_reload_event_high(void) +{ + if (event_high) { + if (SCP_CORE0_TIMER_RST_VAL(TIMER_EVENT) == 0xffffffff) + timer_enable(TIMER_EVENT); + else + timer_reload(TIMER_EVENT, 0xffffffff); + event_high--; + return 1; + } + + timer_disable(TIMER_EVENT); return 0; } +int __hw_clock_source_init(uint32_t start_t) +{ + int t; + + /* enable clock gate */ + SCP_SET_CLK_CG |= CG_TIMER_MCLK | CG_TIMER_BCLK; + + /* reset all timer, select 32768Hz clock source */ + for (t = 0; t < NUM_TIMERS; ++t) + timer_reset(t); + + /* System timestamp timer */ + timer_set_clock(TIMER_SYSTEM, TIMER_CLK_SRC_26M); + sys_high = TIMER_CLOCK_MHZ - 1; + timer_set_reset_value(TIMER_SYSTEM, 0xffffffff); + task_enable_irq(SCP_IRQ_TIMER(TIMER_SYSTEM)); + timer_enable(TIMER_SYSTEM); + + /* Event tick timer */ + timer_set_clock(TIMER_EVENT, TIMER_CLK_SRC_26M); + task_enable_irq(SCP_IRQ_TIMER(TIMER_EVENT)); + + return SCP_IRQ_TIMER(TIMER_SYSTEM); +} + uint32_t __hw_clock_source_read(void) { - return 0; + return timer_read_raw_system() / TIMER_CLOCK_MHZ; } uint32_t __hw_clock_event_get(void) { - return 0; + return (timer_read_raw_event() + timer_read_raw_system()) + / TIMER_CLOCK_MHZ; } void __hw_clock_event_clear(void) { + /* c1ea4, magic number for clear state */ + timer_disable(TIMER_EVENT); + timer_set_reset_value(TIMER_EVENT, 0x0000c1ea4); + event_high = 0; } void __hw_clock_event_set(uint32_t deadline) { + uint64_t deadline_raw = (uint64_t)deadline * TIMER_CLOCK_MHZ; + uint64_t now_raw = timer_read_raw_system(); + uint32_t event_deadline; + + if (deadline_raw > now_raw) { + deadline_raw -= now_raw; + event_deadline = (uint32_t)deadline_raw; + event_high = deadline_raw >> 32; + } else { + event_deadline = 1; + event_high = 0; + } + + if (event_deadline) + timer_reload(TIMER_EVENT, event_deadline); + else + timer_reload_event_high(); +} + +static void irq_group6_handler(void) +{ + extern volatile int ec_int; + + switch (ec_int) { + case SCP_IRQ_TIMER(TIMER_EVENT): + if (timer_is_irq(TIMER_EVENT)) { + timer_ack_irq(TIMER_EVENT); + + if (!timer_reload_event_high()) + process_timers(0); + + task_clear_pending_irq(ec_int); + } + break; + case SCP_IRQ_TIMER(TIMER_SYSTEM): + /* If this is a hardware irq, check overflow */ + if (timer_is_irq(TIMER_SYSTEM)) { + timer_ack_irq(TIMER_SYSTEM); + + if (sys_high) { + --sys_high; + process_timers(0); + } else { + /* Overflow, reload system timer */ + sys_high = TIMER_CLOCK_MHZ - 1; + process_timers(1); + } + + task_clear_pending_irq(ec_int); + } else { + process_timers(0); + } + break; + } } +DECLARE_IRQ(6, irq_group6_handler, 2); diff --git a/chip/mt8192_scp/intc.c b/chip/mt8192_scp/intc.c index c8f68fd40e..4b9c1aa9a9 100644 --- a/chip/mt8192_scp/intc.c +++ b/chip/mt8192_scp/intc.c @@ -54,14 +54,14 @@ static struct { [SCP_IRQ_BUS_DBG_TRACKER] = { INTC_GRP_0 }, [SCP_IRQ_CLK_CTRL] = { INTC_GRP_0 }, [SCP_IRQ_VOW] = { INTC_GRP_0 }, - [SCP_IRQ_TIMER0] = { INTC_GRP_0 }, + [SCP_IRQ_TIMER0] = { INTC_GRP_6 }, /* 16 */ - [SCP_IRQ_TIMER1] = { INTC_GRP_0 }, - [SCP_IRQ_TIMER2] = { INTC_GRP_0 }, - [SCP_IRQ_TIMER3] = { INTC_GRP_0 }, - [SCP_IRQ_TIMER4] = { INTC_GRP_0 }, + [SCP_IRQ_TIMER1] = { INTC_GRP_6 }, + [SCP_IRQ_TIMER2] = { INTC_GRP_6 }, + [SCP_IRQ_TIMER3] = { INTC_GRP_6 }, + [SCP_IRQ_TIMER4] = { INTC_GRP_6 }, /* 20 */ - [SCP_IRQ_TIMER5] = { INTC_GRP_0 }, + [SCP_IRQ_TIMER5] = { INTC_GRP_6 }, [SCP_IRQ_OS_TIMER] = { INTC_GRP_0 }, [SCP_IRQ_UART0_RX] = { INTC_GRP_12 }, [SCP_IRQ_UART1_RX] = { INTC_GRP_12 }, diff --git a/chip/mt8192_scp/registers.h b/chip/mt8192_scp/registers.h index 1cfc7a6bcc..d646c18ef4 100644 --- a/chip/mt8192_scp/registers.h +++ b/chip/mt8192_scp/registers.h @@ -104,6 +104,24 @@ #define SCP_CORE0_INTC_UART1_RX_IRQ REG32(SCP_CORE0_INTC_IRQ_BASE + 0x025C) #define SCP_CORE0_INTC_UART_RX_IRQ(n) CONCAT3(SCP_CORE0_INTC_UART, n, _RX_IRQ) +/* XGPT (general purpose timer) */ +#define NUM_TIMERS 6 +#define SCP_CORE0_TIMER_BASE(n) (SCP_REG_BASE + 0x33000 + (0x10 * (n))) +#define SCP_CORE0_TIMER_EN(n) REG32(SCP_CORE0_TIMER_BASE(n) + 0x0000) +#define TIMER_EN BIT(0) +#define TIMER_CLK_SRC_32K (0 << 4) +#define TIMER_CLK_SRC_26M (1 << 4) +#define TIMER_CLK_SRC_BCLK (2 << 4) +#define TIMER_CLK_SRC_MCLK (3 << 4) +#define TIMER_CLK_SRC_MASK (3 << 4) +#define SCP_CORE0_TIMER_RST_VAL(n) REG32(SCP_CORE0_TIMER_BASE(n) + 0x0004) +#define SCP_CORE0_TIMER_CUR_VAL(n) REG32(SCP_CORE0_TIMER_BASE(n) + 0x0008) +#define SCP_CORE0_TIMER_IRQ_CTRL(n) REG32(SCP_CORE0_TIMER_BASE(n) + 0x000C) +#define TIMER_IRQ_EN BIT(0) +#define TIMER_IRQ_STATUS BIT(4) +#define TIMER_IRQ_CLR BIT(5) +#define SCP_IRQ_TIMER(n) CONCAT2(SCP_IRQ_TIMER, n) + /* memory remap */ #define SCP_R_REMAP_0X0123 REG32(SCP_REG_BASE + 0xA5060) #define SCP_R_REMAP_0X4567 REG32(SCP_REG_BASE + 0xA5064) |