common: Add new recovery mode button combination

This adds new key combination (Left_Shift+Esc+Refresh+Power) that triggers
recovery mode by setting a new host event
EC_HOST_EVENT_KEYBOARD_RECOVERY_HW_REINIT. This host event can be used
whenever user wants to request entry into recovery mode by
reinitializing all the hardware state (e.g. memory retraining).

BUG=chrome-os-partner:56643,chrome-os-partner:59352
BRANCH=None
TEST=Verified that device retrains memory in recovery mode
with (Left_Shift+Esc+Refresh+Power) on reef.

Change-Id: I2e08997acfd9e22270b8ce7a5b589cd5630645f8
Signed-off-by: Furquan Shaikh <furquan@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/407827
Reviewed-by: Randall Spangler <rspangler@chromium.org>
This commit is contained in:
Furquan Shaikh
2016-11-03 23:39:19 -07:00
committed by chrome-bot
parent bf4e1db093
commit 2fc7ba9df1
6 changed files with 71 additions and 49 deletions

View File

@@ -70,12 +70,13 @@ struct boot_key_entry {
uint8_t mask_index;
uint8_t mask_value;
};
static const struct boot_key_entry boot_key_list[] = {
{0, 0x00}, /* (none) */
{KEYBOARD_COL_ESC, KEYBOARD_MASK_ESC}, /* Esc */
{KEYBOARD_COL_DOWN, KEYBOARD_MASK_DOWN}, /* Down-arrow */
{KEYBOARD_COL_LEFT_SHIFT, KEYBOARD_MASK_LEFT_SHIFT}, /* Left-Shift */
};
static enum boot_key boot_key_value = BOOT_KEY_OTHER;
static uint32_t boot_key_value = BOOT_KEY_NONE;
/* Debounced key matrix */
static uint8_t __bss_slow debounced_state[KEYBOARD_COLS];
@@ -516,21 +517,18 @@ static int check_keys_changed(uint8_t *state)
}
/*
* Return non-zero if the specified key is pressed, with at most the keys used
* Returns mask of the boot keys that are pressed, with at most the keys used
* for keyboard-controlled reset also pressed.
*/
static int check_key(const uint8_t *state, int index, int mask)
static uint32_t check_key_list(const uint8_t *state)
{
uint8_t allowed_mask[KEYBOARD_COLS] = {0};
uint8_t curr_state[KEYBOARD_COLS];
int c;
uint32_t boot_key_mask = BOOT_KEY_NONE;
const struct boot_key_entry *k;
/* Check for the key */
if (mask && !(state[index] & mask))
return 0;
/* Check for other allowed keys */
allowed_mask[index] |= mask;
allowed_mask[KEYBOARD_COL_REFRESH] |= KEYBOARD_MASK_REFRESH;
/* Make copy of current debounced state. */
memcpy(curr_state, state, sizeof(curr_state));
#ifdef CONFIG_KEYBOARD_PWRBTN_ASSERTS_KSI2
/*
@@ -539,19 +537,31 @@ static int check_key(const uint8_t *state, int index, int mask)
*/
for (c = 0; c < KEYBOARD_COLS; c++)
if ((keyscan_config.actual_key_mask[c] & KEYBOARD_MASK_KSI2) &&
!(state[c] & KEYBOARD_MASK_KSI2))
!(curr_state[c] & KEYBOARD_MASK_KSI2))
break;
if (c == KEYBOARD_COLS)
for (c = 0; c < KEYBOARD_COLS; c++)
allowed_mask[c] |= KEYBOARD_MASK_KSI2;
curr_state[c] &= ~KEYBOARD_MASK_KSI2;
#endif
for (c = 0; c < KEYBOARD_COLS; c++) {
if (state[c] & ~allowed_mask[c])
return 0; /* Disallowed key pressed */
/* Update mask with all boot keys that were pressed. */
k = boot_key_list;
for (c = 0; c < ARRAY_SIZE(boot_key_list); c++, k++) {
if (curr_state[k->mask_index] & k->mask_value) {
boot_key_mask |= (1 << c);
curr_state[k->mask_index] &= ~k->mask_value;
}
}
return 1;
/* If any other key was pressed, ignore all boot keys. */
for (c = 0; c < KEYBOARD_COLS; c++) {
if (curr_state[c])
return BOOT_KEY_NONE;
}
CPRINTS("KB boot key mask %x", boot_key_mask);
return boot_key_mask;
}
/**
@@ -559,37 +569,26 @@ static int check_key(const uint8_t *state, int index, int mask)
*
* @param state Keyboard state at boot.
*
* @return the key which is down, or BOOT_KEY_OTHER if an unrecognized
* @return the key which is down, or BOOT_KEY_NONE if an unrecognized
* key combination is down or this isn't the right type of boot to look at
* boot keys.
*/
static enum boot_key check_boot_key(const uint8_t *state)
static uint32_t check_boot_key(const uint8_t *state)
{
const struct boot_key_entry *k = boot_key_list;
int i;
/*
* If we jumped to this image, ignore boot keys. This prevents
* re-triggering events in RW firmware that were already processed by
* RO firmware.
*/
if (system_jumped_to_this_image())
return BOOT_KEY_OTHER;
return BOOT_KEY_NONE;
/* If reset was not caused by reset pin, refresh must be held down */
if (!(system_get_reset_flags() & RESET_FLAG_RESET_PIN) &&
!(state[KEYBOARD_COL_REFRESH] & KEYBOARD_MASK_REFRESH))
return BOOT_KEY_OTHER;
return BOOT_KEY_NONE;
/* Check what single key is down */
for (i = 0; i < ARRAY_SIZE(boot_key_list); i++, k++) {
if (check_key(state, k->mask_index, k->mask_value)) {
CPRINTS("KB boot key %d", i);
return i;
}
}
return BOOT_KEY_OTHER;
return check_key_list(state);
}
static void keyboard_freq_change(void)
@@ -607,7 +606,7 @@ struct keyboard_scan_config *keyboard_scan_get_config(void)
return &keyscan_config;
}
enum boot_key keyboard_scan_get_boot_key(void)
uint32_t keyboard_scan_get_boot_keys(void)
{
return boot_key_value;
}
@@ -632,9 +631,19 @@ void keyboard_scan_init(void)
/* Check for keys held down at boot */
boot_key_value = check_boot_key(debounced_state);
/* Trigger event if recovery key was pressed */
if (boot_key_value == BOOT_KEY_ESC)
/*
* If any key other than Esc or Left_Shift was pressed, do not trigger
* recovery.
*/
if (boot_key_value & ~(BOOT_KEY_ESC | BOOT_KEY_LEFT_SHIFT))
return;
if (boot_key_value & BOOT_KEY_ESC) {
host_set_single_event(EC_HOST_EVENT_KEYBOARD_RECOVERY);
if (boot_key_value & BOOT_KEY_LEFT_SHIFT)
host_set_single_event(
EC_HOST_EVENT_KEYBOARD_RECOVERY_HW_REINIT);
}
}
void keyboard_scan_task(void)

View File

@@ -208,7 +208,7 @@ static void set_initial_pwrbtn_state(void)
CPRINTS("PB init-jumped");
}
} else if ((reset_flags & RESET_FLAG_AP_OFF) ||
(keyboard_scan_get_boot_key() == BOOT_KEY_DOWN_ARROW)) {
(keyboard_scan_get_boot_keys() == BOOT_KEY_DOWN_ARROW)) {
/*
* Reset triggered by keyboard-controlled reset, and down-arrow
* was held down. Or reset flags request AP off.

View File

@@ -548,6 +548,9 @@ enum host_event_code {
/* TABLET/LAPTOP mode event*/
EC_HOST_EVENT_MODE_CHANGE = 29,
/* Keyboard recovery combo with hardware reinitialization */
EC_HOST_EVENT_KEYBOARD_RECOVERY_HW_REINIT = 30,
/*
* The high bit of the event mask is not used as a host event code. If
* it reads back as set, then the entire event mask should be

View File

@@ -60,5 +60,8 @@
#define KEYBOARD_ROW_KEY_2 6
#define KEYBOARD_MASK_KEY_2 KEYBOARD_ROW_TO_MASK(KEYBOARD_ROW_KEY_2)
#define KEYBOARD_MASK_KSI2 KEYBOARD_ROW_TO_MASK(2)
#define KEYBOARD_COL_LEFT_SHIFT 7
#define KEYBOARD_ROW_LEFT_SHIFT 5
#define KEYBOARD_MASK_LEFT_SHIFT KEYBOARD_ROW_TO_MASK(KEYBOARD_ROW_LEFT_SHIFT)
#endif /* __CROS_EC_KEYBOARD_CONFIG_H */

View File

@@ -49,21 +49,28 @@ extern struct keyboard_scan_config keyscan_config;
/* Key held down at keyboard-controlled reset boot time. */
enum boot_key {
BOOT_KEY_NONE, /* No keys other than keyboard-controlled reset keys */
BOOT_KEY_ESC,
BOOT_KEY_DOWN_ARROW,
BOOT_KEY_OTHER = -1, /* None of the above */
/* No keys other than keyboard-controlled reset keys */
BOOT_KEY_NONE = 0,
BOOT_KEY_ESC = (1 << 0),
BOOT_KEY_DOWN_ARROW = (1 << 1),
BOOT_KEY_LEFT_SHIFT = (1 << 2),
};
#ifdef HAS_TASK_KEYSCAN
/**
* Return the key held down at boot time in addition to the keyboard-controlled
* reset keys. Returns BOOT_KEY_OTHER if none of the keys specifically checked
* was pressed, or reset was not caused by a keyboard-controlled reset.
* Returns mask of all the keys held down at boot time in addition to the
* keyboard-controlled reset keys. If more than one boot key is held, mask bits
* will be set for each of those keys. Since more than one bit can be set,
* caller needs to ensure that boot keys match as intended.
*
* Returns BOOT_NONE if no additional key is held or if none of the keys
* specifically checked was pressed, or reset was not caused by a
* keyboard-controlled reset or if any key *other* than boot keys, power, or
* refresh is also pressed.
*/
enum boot_key keyboard_scan_get_boot_key(void);
uint32_t keyboard_scan_get_boot_keys(void);
#else
static inline enum boot_key keyboard_scan_get_boot_key(void)
static inline uint32_t keyboard_scan_get_boot_keys(void)
{
return BOOT_KEY_NONE;
}

View File

@@ -350,12 +350,12 @@ static int lid_test(void)
static int test_check_boot_esc(void)
{
TEST_CHECK(keyboard_scan_get_boot_key() == BOOT_KEY_ESC);
TEST_CHECK(keyboard_scan_get_boot_keys() == BOOT_KEY_ESC);
}
static int test_check_boot_down(void)
{
TEST_CHECK(keyboard_scan_get_boot_key() == BOOT_KEY_DOWN_ARROW);
TEST_CHECK(keyboard_scan_get_boot_keys() == BOOT_KEY_DOWN_ARROW);
}
void test_init(void)