cr50: notify chipset hooks when the AP state changes

Cr50 monitors UART1 RX to sense the state of the AP. This signal can be
used to tell if it is in S0. If the signal is pulled up then the AP is
on. If it is not pulled up then the AP is not in S0. This change
notifies HOOK_CHIPSET_SUSPEND when UART1 RX is not pulled up, and then
notifies HOOK_CHIPSET_RESUME when the signal is high again.

The AP usb can be disabled during suspend, so this change changes the
hook that triggers disabling the AP usb to be attached to
HOOK_CHIPSET_SUSPEND instead of HOOK_CHIPSET_RESUME.

BUG=chrome-os-partner:55747
BRANCH=none
TEST=buildall

Change-Id: I47fb38a4bbcd72424ec2535d61e87f820cf1bcd7
Signed-off-by: Mary Ruthven <mruthven@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/383978
Reviewed-by: Bill Richardson <wfrichar@chromium.org>
This commit is contained in:
Mary Ruthven
2016-08-18 18:35:45 -07:00
parent b9f5a3d6ba
commit 96b7e491e8
4 changed files with 34 additions and 79 deletions

View File

@@ -139,7 +139,6 @@ void pmu_wakeup_interrupt(void)
/* Trigger timer1 interrupt */
if (wakeup_src & GC_PMU_EXITPD_SRC_TIMELS0_PD_EXIT_TIMER1_MASK)
task_trigger_irq(GC_IRQNUM_TIMELS0_TIMINT1);
}
DECLARE_IRQ(GC_IRQNUM_PMU_INTR_WAKEUP_INT, pmu_wakeup_interrupt, 1);
@@ -402,15 +401,19 @@ void nvmem_compute_sha(uint8_t *p_buf, int num_bytes,
memcpy(p_sha, sha1_digest, sha_len);
}
static void device_state_changed(enum device_type device,
static int device_state_changed(enum device_type device,
enum device_state state)
{
int state_changed = state != device_states[device].last_known_state;
device_set_state(device, state);
/*
* We've determined the device state, so cancel any deferred callbacks.
*/
hook_call_deferred(device_states[device].deferred, -1);
return state_changed;
}
/*
@@ -426,12 +429,13 @@ static int servo_state_unknown(void)
return 0;
}
static void device_powered_off(enum device_type device, int uart)
static int device_powered_off(enum device_type device, int uart)
{
if (device_get_state(device) == DEVICE_STATE_ON)
return;
return EC_ERROR_UNKNOWN;
device_state_changed(device, DEVICE_STATE_OFF);
if (!device_state_changed(device, DEVICE_STATE_OFF))
return EC_ERROR_UNKNOWN;
if (uart) {
/* Disable RX and TX on the UART peripheral */
@@ -440,6 +444,7 @@ static void device_powered_off(enum device_type device, int uart)
/* Disconnect the TX pin from the UART peripheral */
uartn_tx_disconnect(uart);
}
return EC_SUCCESS;
}
static void servo_deferred(void)
@@ -453,7 +458,8 @@ DECLARE_DEFERRED(servo_deferred);
static void ap_deferred(void)
{
device_powered_off(DEVICE_AP, UART_AP);
if (device_powered_off(DEVICE_AP, UART_AP) == EC_SUCCESS)
hook_notify(HOOK_CHIPSET_SHUTDOWN);
}
DECLARE_DEFERRED(ap_deferred);
@@ -482,10 +488,12 @@ struct device_config device_states[] = {
};
BUILD_ASSERT(ARRAY_SIZE(device_states) == DEVICE_COUNT);
static void device_powered_on(enum device_type device, int uart)
/* Returns EC_SUCCESS if the device state changed to on */
static int device_powered_on(enum device_type device, int uart)
{
/* Update the device state */
device_state_changed(device, DEVICE_STATE_ON);
if (!device_state_changed(device, DEVICE_STATE_ON))
return EC_ERROR_UNKNOWN;
/* Enable RX and TX on the UART peripheral */
uartn_enable(uart);
@@ -494,6 +502,8 @@ static void device_powered_on(enum device_type device, int uart)
if (device_get_state(DEVICE_SERVO) != DEVICE_STATE_ON &&
!uartn_enabled(uart))
uartn_tx_connect(uart);
return EC_SUCCESS;
}
static void servo_attached(void)
@@ -515,7 +525,8 @@ void device_state_on(enum gpio_signal signal)
switch (signal) {
case GPIO_DETECT_AP:
device_powered_on(DEVICE_AP, UART_AP);
if (device_powered_on(DEVICE_AP, UART_AP) == EC_SUCCESS)
hook_notify(HOOK_CHIPSET_RESUME);
break;
case GPIO_DETECT_EC:
device_powered_on(DEVICE_EC, UART_EC);
@@ -546,10 +557,13 @@ void board_update_device_state(enum device_type device)
gpio_enable_interrupt(device_states[device].detect);
/*
* Wait a bit. If cr50 detects this device is ever powered on
* during this time then the status wont be set to powered off.
* The signal is low now, but the detect signals are on UART RX
* which may be receiving something. Wait long enough for an
* entire data chunk to be sent to declare that the device is
* off. If the detect signal remains low for 100us then the
* signal is low because the device is off.
*/
hook_call_deferred(device_states[device].deferred, 50);
hook_call_deferred(device_states[device].deferred, 100);
}
}

View File

@@ -102,17 +102,12 @@ void rdd_attached(void)
ccd_set_mode(CCD_MODE_ENABLED);
enable_usb_wakeup = 1;
uartn_tx_connect(UART_AP);
/* Enable device state monitoring */
device_detect_state_enable(1);
uartn_tx_connect(UART_AP);
}
void rdd_detached(void)
{
/* Disable device state monitoring */
device_detect_state_enable(0);
/* Disconnect from AP and EC UART TX peripheral from gpios */
uartn_tx_disconnect(UART_EC);
uartn_tx_disconnect(UART_AP);

View File

@@ -7,8 +7,6 @@
#include "device_state.h"
#include "hooks.h"
static int enabled = 1;
int device_get_state(enum device_type device)
{
return device_states[device].state;
@@ -19,6 +17,9 @@ void device_set_state(enum device_type device, enum device_state state)
if (device_states[device].state == state)
return;
if (state != DEVICE_STATE_UNKNOWN)
device_states[device].last_known_state = state;
device_states[device].state = state;
}
@@ -26,57 +27,11 @@ static void check_device_state(void)
{
int i;
if (!enabled)
return;
for (i = 0; i < DEVICE_COUNT; i++)
board_update_device_state(i);
}
DECLARE_HOOK(HOOK_SECOND, check_device_state, HOOK_PRIO_DEFAULT);
static int device_has_interrupts(enum device_type device)
{
return (device_states[device].deferred &&
device_states[device].detect != GPIO_COUNT);
}
static void disable_interrupts(enum device_type device)
{
if (!device_has_interrupts(device))
return;
/* Cancel any deferred callbacks */
hook_call_deferred(device_states[device].deferred, -1);
/* Disable gpio interrupts */
gpio_disable_interrupt(device_states[device].detect);
}
static void enable_interrupts(enum device_type device)
{
if (!device_has_interrupts(device))
return;
/* Enable gpio interrupts */
gpio_enable_interrupt(device_states[device].detect);
}
void device_detect_state_enable(int enable)
{
int i;
enabled = enable;
for (i = 0; i < DEVICE_COUNT; i++) {
if (enabled) {
enable_interrupts(i);
board_update_device_state(i);
} else {
disable_interrupts(i);
device_set_state(i, DEVICE_STATE_UNKNOWN);
}
}
}
static void print_state(const char *name, enum device_state state)
{
ccprintf("%-9s %s\n", name, state == DEVICE_STATE_ON ? "on" :
@@ -87,12 +42,9 @@ static int command_devices(int argc, char **argv)
{
int i;
if (!enabled)
ccprintf("Device monitoring disabled\n");
else
for (i = 0; i < DEVICE_COUNT; i++)
print_state(device_states[i].name,
device_states[i].state);
for (i = 0; i < DEVICE_COUNT; i++)
print_state(device_states[i].name,
device_states[i].state);
return EC_SUCCESS;
}

View File

@@ -19,6 +19,7 @@ enum device_state {
struct device_config {
const char *name; /* Device name */
enum device_state state; /* Device status */
enum device_state last_known_state; /* Either off or on */
/* Deferred handler to detect power off */
const struct deferred_data *deferred;
enum gpio_signal detect; /* GPIO detecting power on */
@@ -41,11 +42,4 @@ void device_set_state(enum device_type device, enum device_state state);
/* Update the device state based on the device gpios */
void board_update_device_state(enum device_type device);
/**
* Enables or disables all device gpio interrupts
*
* @param enable enable or disable detection
*/
void device_detect_state_enable(int enable);
#endif /* __CROS_DEVICE_STATE_H */