summaryrefslogtreecommitdiff
path: root/chip/mt8192_scp
diff options
context:
space:
mode:
authorTzung-Bi Shih <tzungbi@chromium.org>2020-05-13 17:25:08 +0800
committerCommit Bot <commit-bot@chromium.org>2020-06-10 10:37:31 +0000
commitfed72520335e09b9ba401c93342dbd90ba5251d7 (patch)
treee0df3a4b6772ed0ee2fe221d2000d0d84cadf637 /chip/mt8192_scp
parent808042369ae338d3acfb6867f06cab2907c98cd8 (diff)
downloadchrome-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.c188
-rw-r--r--chip/mt8192_scp/intc.c12
-rw-r--r--chip/mt8192_scp/registers.h18
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)