summaryrefslogtreecommitdiff
path: root/chip
diff options
context:
space:
mode:
authorTinghan Shen <tinghan.shen@mediatek.com>2022-01-24 17:06:27 +0800
committerCommit Bot <commit-bot@chromium.org>2022-01-26 09:43:26 +0000
commite894b1be353b521e5c1e8fc0d8e81f71720ad116 (patch)
tree3153d59b7c4f7f7c881da99ec5c1eda81875b642 /chip
parent982408e4d09c163370d68f7e8107a861a187c85d (diff)
downloadchrome-ec-e894b1be353b521e5c1e8fc0d8e81f71720ad116.tar.gz
chip/mt_scp: rv32i: improve mt8195 handling suspend/resume
The original suspend/resume flow of SCP doesn't know when will the 26M clock source be suspended by SPM. SCP has to disable watchdog once receiving host suspend command and enable watchdog after receiving host resume command. The drawback is that SCP has to run without the protection of watchdog in the period between host suspend command and host resume command. In order to solve this, we can star a timer with 26M clock source, so that SCP can detect the timing by snooping the 26M timer counter. The improved flow allows SCP to disable watchdog and irq after detecting 26M is off and re-enable immediately when 26M available again. BRANCH=None BUG=b:189356151 BUG=b:202754468 TEST=suspend_stress_test on 5 DUTs overnight Signed-off-by: Tinghan Shen <tinghan.shen@mediatek.com> Change-Id: I85d29d68af4d2108bf31f7cc2fd0f6c0bc4f9a5d Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/3411688 Reviewed-by: Rong Chang <rongchang@chromium.org> Commit-Queue: Rong Chang <rongchang@chromium.org>
Diffstat (limited to 'chip')
-rw-r--r--chip/mt_scp/mt8195/clock.c72
-rw-r--r--chip/mt_scp/rv32i_common/hrtimer.c14
-rw-r--r--chip/mt_scp/rv32i_common/scp_timer.h16
3 files changed, 94 insertions, 8 deletions
diff --git a/chip/mt_scp/mt8195/clock.c b/chip/mt_scp/mt8195/clock.c
index eac6436a46..f3b32ab52e 100644
--- a/chip/mt_scp/mt8195/clock.c
+++ b/chip/mt_scp/mt8195/clock.c
@@ -15,12 +15,24 @@
#include "ec_commands.h"
#include "power.h"
#include "registers.h"
+#include "scp_timer.h"
#include "scp_watchdog.h"
+#include "task.h"
#include "timer.h"
#define CPRINTF(format, args...) cprintf(CC_CLOCK, format, ##args)
#define CPRINTS(format, args...) cprints(CC_CLOCK, format, ##args)
+#define TASK_EVENT_SUSPEND TASK_EVENT_CUSTOM_BIT(4)
+#define TASK_EVENT_RESUME TASK_EVENT_CUSTOM_BIT(5)
+#define CHECK_26M_PERIOD_US 50000
+
+enum scp_sr_state {
+ SR_S0,
+ SR_S02S3,
+ SR_S3,
+};
+
enum scp_clock_source {
SCP_CLK_SYSTEM,
SCP_CLK_32K,
@@ -377,13 +389,61 @@ power_chipset_handle_host_sleep_event(enum host_sleep_event state,
struct host_sleep_event_context *ctx)
{
if (state == HOST_SLEEP_EVENT_S3_SUSPEND) {
- CPRINTS("AP suspend");
- watchdog_disable();
- clock_select_clock(SCP_CLK_SYSTEM);
+ task_set_event(TASK_ID_SR, TASK_EVENT_SUSPEND);
} else if (state == HOST_SLEEP_EVENT_S3_RESUME) {
- clock_select_clock(SCP_CLK_ULPOSC2_HIGH_SPEED);
- watchdog_enable();
- CPRINTS("AP resume");
+ task_set_event(TASK_ID_SR, TASK_EVENT_RESUME);
+ }
+}
+
+void sr_task(void *u)
+{
+ enum scp_sr_state state = SR_S0;
+ uint32_t event;
+ uint32_t prev, now;
+
+ while(1) {
+ switch (state) {
+ case SR_S0:
+ event = task_wait_event(-1);
+ if (event & TASK_EVENT_SUSPEND) {
+ timer_enable(TIMER_SR);
+ prev = timer_read_raw_sr();
+ state = SR_S02S3;
+ }
+ break;
+ case SR_S02S3:
+ event = task_wait_event(CHECK_26M_PERIOD_US);
+ if (event & TASK_EVENT_RESUME) {
+ /* suspend is aborted */
+ timer_disable(TIMER_SR);
+ state = SR_S0;
+ } else if (event & TASK_EVENT_TIMER) {
+ now = timer_read_raw_sr();
+ if (now != prev) {
+ /* 26M is still on */
+ prev = now;
+ } else {
+ /* 26M is off */
+ state = SR_S3;
+ }
+ }
+ break;
+ case SR_S3:
+ interrupt_disable();
+ watchdog_disable();
+
+ /* change to 26M to stop core at here */
+ clock_select_clock(SCP_CLK_SYSTEM);
+
+ /* 26M is back */
+ clock_select_clock(SCP_CLK_ULPOSC2_HIGH_SPEED);
+
+ watchdog_enable();
+ interrupt_enable();
+ timer_disable(TIMER_SR);
+ state = SR_S0;
+ break;
+ }
}
}
diff --git a/chip/mt_scp/rv32i_common/hrtimer.c b/chip/mt_scp/rv32i_common/hrtimer.c
index 89ffaa2fca..a844527494 100644
--- a/chip/mt_scp/rv32i_common/hrtimer.c
+++ b/chip/mt_scp/rv32i_common/hrtimer.c
@@ -15,6 +15,7 @@
#include "common.h"
#include "hwtimer.h"
#include "registers.h"
+#include "scp_timer.h"
#include "task.h"
#define TIMER_SYSTEM 5
@@ -27,20 +28,25 @@ static uint8_t sys_high;
/* High 32-bit for event timer. */
static uint8_t event_high;
-static void timer_enable(int n)
+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)
+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;
}
+uint32_t timer_read_raw_sr(void)
+{
+ return SCP_CORE0_TIMER_CUR_VAL(TIMER_SR);
+}
+
static int timer_is_irq(int n)
{
return SCP_CORE0_TIMER_IRQ_CTRL(n) & TIMER_IRQ_STATUS;
@@ -139,6 +145,10 @@ int __hw_clock_source_init(uint32_t start_t)
timer_set_clock(TIMER_EVENT, TIMER_CLK_SRC_BCLK);
task_enable_irq(SCP_IRQ_TIMER(TIMER_EVENT));
+ /* SR timer */
+ timer_set_clock(TIMER_SR, TIMER_CLK_SRC_26M);
+ task_disable_irq(SCP_IRQ_TIMER(TIMER_SR));
+
return SCP_IRQ_TIMER(TIMER_SYSTEM);
}
diff --git a/chip/mt_scp/rv32i_common/scp_timer.h b/chip/mt_scp/rv32i_common/scp_timer.h
new file mode 100644
index 0000000000..5c0650f913
--- /dev/null
+++ b/chip/mt_scp/rv32i_common/scp_timer.h
@@ -0,0 +1,16 @@
+/* Copyright 2022 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef __SCP_TIMER_H
+#define __SCP_TIMER_H
+
+/* detect existance of 26m clock in S3 stage */
+#define TIMER_SR 4
+
+void timer_enable(int n);
+void timer_disable(int n);
+uint32_t timer_read_raw_sr(void);
+
+#endif /* __SCP_TIMER_H */