summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRandall Spangler <rspangler@chromium.org>2013-10-11 14:53:27 -0700
committerchrome-internal-fetch <chrome-internal-fetch@google.com>2013-10-14 23:27:31 +0000
commit193f2298bd1a078f1ac07aacf9dc50132cbb39d3 (patch)
tree77f100d3f4b966ffe57de25bb44d5ec7bf31758e
parent1049bbbad81ab404c48cbc757c015cc8a373049b (diff)
downloadchrome-ec-193f2298bd1a078f1ac07aacf9dc50132cbb39d3.tar.gz
Enforce a minimum number of clocks between keyboard scans
When the EC CPU is running at a decreased clock frequency, frequent keyboard scans can starve other EC tasks of CPU and lead to dropped data or watchdog timeouts. Enforce a minimum number of EC clocks between keyboard scans to prevent this from happening. The default chosen (16000 clocks) is equal to the shortest post-scan delay (1 ms) of any current board when the AP is in S0, so this should have no effect when the AP is in S0. When the AP is in S3 or S5, we don't need to scan the keyboard as frequently anyway. This can be overridden on a per-board basis for future boards if needed. BUG=chrome-os-partner:23247 BRANCH=pit TEST=apshutdown, then hold down a key for 10 seconds. Should not see a watchdog reset. Change-Id: I228f53a32ad4769f6a137a9ab06903111bea115d Signed-off-by: Randall Spangler <rspangler@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/172895 Reviewed-by: Vic Yang <victoryang@chromium.org>
-rw-r--r--chip/host/build.mk3
-rw-r--r--chip/host/clock.c13
-rw-r--r--common/keyboard_scan.c27
-rw-r--r--include/config.h7
4 files changed, 49 insertions, 1 deletions
diff --git a/chip/host/build.mk b/chip/host/build.mk
index 177246a925..56b091b8cf 100644
--- a/chip/host/build.mk
+++ b/chip/host/build.mk
@@ -8,5 +8,6 @@
CORE:=host
-chip-y=system.o gpio.o uart.o persistence.o flash.o lpc.o reboot.o i2c.o
+chip-y=system.o gpio.o uart.o persistence.o flash.o lpc.o reboot.o i2c.o \
+ clock.o
chip-$(HAS_TASK_KEYSCAN)+=keyboard_raw.o
diff --git a/chip/host/clock.c b/chip/host/clock.c
new file mode 100644
index 0000000000..89391c0028
--- /dev/null
+++ b/chip/host/clock.c
@@ -0,0 +1,13 @@
+/* Copyright (c) 2013 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.
+ *
+ * Dummy clock driver for unit test.
+ */
+
+#include "clock.h"
+
+int clock_get_freq(void)
+{
+ return 16000000;
+}
diff --git a/common/keyboard_scan.c b/common/keyboard_scan.c
index 8214d7c415..9641ff6ca9 100644
--- a/common/keyboard_scan.c
+++ b/common/keyboard_scan.c
@@ -6,6 +6,7 @@
/* Keyboard scanner module for Chrome EC */
#include "chipset.h"
+#include "clock.h"
#include "common.h"
#include "console.h"
#include "hooks.h"
@@ -27,6 +28,15 @@
#define SCAN_TIME_COUNT 32 /* Number of last scan times to track */
+#ifndef CONFIG_KEYBOARD_POST_SCAN_CLOCKS
+/*
+ * Default delay in clocks; this was experimentally determined to be long
+ * enough to avoid watchdog warnings or I2C errors on a typical notebook
+ * config on STM32.
+ */
+#define CONFIG_KEYBOARD_POST_SCAN_CLOCKS 16000
+#endif
+
#ifndef CONFIG_KEYBOARD_BOARD_CONFIG
/* Use default keyboard scan config, because board didn't supply one */
struct keyboard_scan_config keyscan_config = {
@@ -62,9 +72,13 @@ static uint8_t simulated_key[KEYBOARD_COLS]; /* Keys simulated-pressed */
static uint32_t scan_time[SCAN_TIME_COUNT]; /* Times of last scans */
static int scan_time_index; /* Current scan_time[] index */
+
/* Index into scan_time[] when each key started debouncing */
static uint8_t scan_edge_index[KEYBOARD_COLS][KEYBOARD_ROWS];
+/* Minimum delay between keyboard scans based on current clock frequency */
+static uint32_t post_scan_clock_us;
+
/*
* Print all keyboard scan state changes? Off by default because it generates
* a lot of debug output, which makes the saved EC console data less useful.
@@ -443,6 +457,13 @@ static enum boot_key check_boot_key(const uint8_t *state)
return BOOT_KEY_OTHER;
}
+static void keyboard_freq_change(void)
+{
+ post_scan_clock_us = (CONFIG_KEYBOARD_POST_SCAN_CLOCKS * 1000) /
+ (clock_get_freq() / 1000);
+}
+DECLARE_HOOK(HOOK_FREQ_CHANGE, keyboard_freq_change, HOOK_PRIO_DEFAULT);
+
/*****************************************************************************/
/* Interface */
@@ -490,6 +511,9 @@ void keyboard_scan_task(void)
keyboard_raw_task_start();
+ /* Set initial clock frequency-based minimum delay between scans */
+ keyboard_freq_change();
+
while (1) {
/* Enable all outputs */
CPRINTF("[%T KB wait]\n");
@@ -534,6 +558,9 @@ void keyboard_scan_task(void)
wait_time =
keyscan_config.min_post_scan_delay_us;
+ if (wait_time < post_scan_clock_us)
+ wait_time = post_scan_clock_us;
+
usleep(wait_time);
}
}
diff --git a/include/config.h b/include/config.h
index ce1147a9d6..72dffe49c2 100644
--- a/include/config.h
+++ b/include/config.h
@@ -451,6 +451,13 @@
#undef CONFIG_KEYBOARD_BOARD_CONFIG
/*
+ * Minimum CPU clocks between scans. This ensures that keyboard scanning
+ * doesn't starve the other EC tasks of CPU when running at a decreased system
+ * clock.
+ */
+#undef CONFIG_KEYBOARD_POST_SCAN_CLOCKS
+
+/*
* Call board-supplied keyboard_suppress_noise() function when the debounced
* keyboard state changes. Some boards use this to send a signal to the audio
* codec to suppress typing noise picked up by the microphone.