summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnton Staaf <robotboy@chromium.org>2015-03-17 11:49:29 -0700
committerChromeOS Commit Bot <chromeos-commit-bot@chromium.org>2015-03-23 19:23:35 +0000
commita0158dd136b63b2daffd666d51d84a67481cb609 (patch)
treeb3ceb010fbba052fb63825d862a0ef2eae2767a6
parent4002d66297f381c18e1118fa8e2cc156bc5baffd (diff)
downloadchrome-ec-stabilize-6909.B.tar.gz
CCD: Add ability to enable and disable SPI bridgestabilize-6909.B
This required changing the USB-SPI implementation slightly so that all work is done within the deferred callback. In particular, this allows the board specific enable and disable functions to do things that can only be done from a task context, like sleeping. Signed-off-by: Anton Staaf <robotboy@chromium.org> BRANCH=None BUG=None TEST=make buildall -j Change-Id: I3f6a01ed9d6f31a3259ba0a0f6b4e123d6d2e718 Reviewed-on: https://chromium-review.googlesource.com/260964 Trybot-Ready: Anton Staaf <robotboy@chromium.org> Tested-by: Anton Staaf <robotboy@chromium.org> Reviewed-by: Vincent Palatin <vpalatin@chromium.org> Commit-Queue: Anton Staaf <robotboy@chromium.org>
-rw-r--r--chip/stm32/usb_spi.c87
-rw-r--r--chip/stm32/usb_spi.h28
-rw-r--r--common/case_closed_debug.c9
3 files changed, 84 insertions, 40 deletions
diff --git a/chip/stm32/usb_spi.c b/chip/stm32/usb_spi.c
index 24b8a530d7..c81f01ac23 100644
--- a/chip/stm32/usb_spi.c
+++ b/chip/stm32/usb_spi.c
@@ -59,32 +59,53 @@ static void usb_spi_write_packet(struct usb_spi_config const *config,
STM32_TOGGLE_EP(config->endpoint, EP_TX_MASK, EP_TX_VALID, 0);
}
+static int rx_valid(struct usb_spi_config const *config)
+{
+ return (STM32_USB_EP(config->endpoint) & EP_RX_MASK) == EP_RX_VALID;
+}
+
void usb_spi_deferred(struct usb_spi_config const *config)
{
- uint8_t count;
- uint8_t write_count;
- uint8_t read_count;
-
- count = usb_spi_read_packet(config);
- write_count = (config->buffer[0] >> 0) & 0xff;
- read_count = (config->buffer[0] >> 8) & 0xff;
-
- if (config->state->disabled || !config->state->enabled) {
- config->buffer[0] = USB_SPI_DISABLED;
- } else if (write_count > USB_SPI_MAX_WRITE_COUNT ||
- write_count != (count - 2)) {
- config->buffer[0] = USB_SPI_WRITE_COUNT_INVALID;
- } else if (read_count > USB_SPI_MAX_READ_COUNT) {
- config->buffer[0] = USB_SPI_READ_COUNT_INVALID;
- } else {
- config->buffer[0] = usb_spi_map_error(
- spi_transaction((uint8_t *)(config->buffer + 1),
- write_count,
- (uint8_t *)(config->buffer + 1),
- read_count));
+ /*
+ * If our overall enabled state has changed we call the board specific
+ * enable or disable routines and save our new state.
+ */
+ int enabled = (config->state->enabled_host &&
+ config->state->enabled_device);
+
+ if (enabled ^ config->state->enabled) {
+ if (enabled) usb_spi_board_enable(config);
+ else usb_spi_board_disable(config);
+
+ config->state->enabled = enabled;
}
- usb_spi_write_packet(config, read_count + 2);
+ /*
+ * And if there is a USB packet waiting we process it and generate a
+ * response.
+ */
+ if (!rx_valid(config)) {
+ uint8_t count = usb_spi_read_packet(config);
+ uint8_t write_count = (config->buffer[0] >> 0) & 0xff;
+ uint8_t read_count = (config->buffer[0] >> 8) & 0xff;
+
+ if (!config->state->enabled) {
+ config->buffer[0] = USB_SPI_DISABLED;
+ } else if (write_count > USB_SPI_MAX_WRITE_COUNT ||
+ write_count != (count - 2)) {
+ config->buffer[0] = USB_SPI_WRITE_COUNT_INVALID;
+ } else if (read_count > USB_SPI_MAX_READ_COUNT) {
+ config->buffer[0] = USB_SPI_READ_COUNT_INVALID;
+ } else {
+ config->buffer[0] = usb_spi_map_error(
+ spi_transaction((uint8_t *)(config->buffer + 1),
+ write_count,
+ (uint8_t *)(config->buffer + 1),
+ read_count));
+ }
+
+ usb_spi_write_packet(config, read_count + 2);
+ }
}
void usb_spi_tx(struct usb_spi_config const *config)
@@ -134,23 +155,27 @@ int usb_spi_interface(struct usb_spi_config const *config,
setup.wLength != 0)
return 1;
- if (config->state->disabled)
+ if (!config->state->enabled_device)
return 1;
switch (setup.bRequest) {
case USB_SPI_REQ_ENABLE:
- usb_spi_board_enable(config);
- config->state->enabled = 1;
+ config->state->enabled_host = 1;
break;
case USB_SPI_REQ_DISABLE:
- config->state->enabled = 0;
- usb_spi_board_disable(config);
+ config->state->enabled_host = 0;
break;
default: return 1;
}
+ /*
+ * Our state has changed, call the deferred function to handle the
+ * state change.
+ */
+ hook_call_deferred(config->deferred, 0);
+
btable_ep[0].tx_count = 0;
STM32_TOGGLE_EP(0, EP_TX_RX_MASK, EP_TX_RX_VALID, EP_STATUS_OUT);
return 0;
@@ -158,11 +183,7 @@ int usb_spi_interface(struct usb_spi_config const *config,
void usb_spi_enable(struct usb_spi_config const *config, int enabled)
{
- config->state->disabled = !enabled;
+ config->state->enabled_device = enabled;
- if (config->state->disabled &&
- config->state->enabled) {
- config->state->enabled = 0;
- usb_spi_board_disable(config);
- }
+ hook_call_deferred(config->deferred, 0);
}
diff --git a/chip/stm32/usb_spi.h b/chip/stm32/usb_spi.h
index 316c827420..76719c6d2c 100644
--- a/chip/stm32/usb_spi.h
+++ b/chip/stm32/usb_spi.h
@@ -69,12 +69,25 @@ BUILD_ASSERT(USB_MAX_PACKET_SIZE == (2 + USB_SPI_MAX_READ_COUNT));
struct usb_spi_state {
/*
- * The SPI bridge must be both not disabled and enabled to allow access
- * to the SPI device. The disabled bit is dictated by the caller of
- * usb_spi_enable. The enabled bit is set by the USB host, most likely
- * flashrom, by sending a USB_SPI_REQ_ENABLE message to the device.
+ * The SPI bridge must be enabled both locally and by the host to allow
+ * access to the SPI device. The enabled_host flag is set and cleared
+ * by sending USB_SPI_REQ_ENABLE and USB_SPI_REQ_DISABLE to the device
+ * control endpoint. The enabled_device flag is set by calling
+ * usb_spi_enable.
+ */
+ int enabled_host;
+ int enabled_device;
+
+ /*
+ * The current enabled state. This is only updated in the deferred
+ * callback. Whenever either of the host or device specific enable
+ * flags is changed the deferred callback is queued, and it will check
+ * their combined state against this flag. If the combined state is
+ * different, then one of usb_spi_board_enable or usb_spi_board_disable
+ * is called and this flag is updated. This ensures that the board
+ * specific state update routines are only called from the deferred
+ * callback.
*/
- int disabled;
int enabled;
};
@@ -128,8 +141,9 @@ struct usb_spi_config {
static usb_uint CONCAT2(NAME, _ep_tx_buffer_)[USB_MAX_PACKET_SIZE / 2] __usb_ram; \
static void CONCAT2(NAME, _deferred_)(void); \
struct usb_spi_state CONCAT2(NAME, _state_) = { \
- .disabled = 1, \
- .enabled = 0, \
+ .enabled_host = 0, \
+ .enabled_device = 0, \
+ .enabled = 0, \
}; \
struct usb_spi_config const NAME = { \
.state = &CONCAT2(NAME, _state_), \
diff --git a/common/case_closed_debug.c b/common/case_closed_debug.c
index a1f8522ccd..3adc563c4f 100644
--- a/common/case_closed_debug.c
+++ b/common/case_closed_debug.c
@@ -10,6 +10,7 @@
#include "common.h"
#include "usb_api.h"
#include "usb_console.h"
+#include "usb_spi.h"
#if !defined(CONFIG_USB)
#error "CONFIG_USB must be defined to use Case Closed Debugging"
@@ -23,6 +24,10 @@
#error "CONFIG_USB_INHIBIT_INIT must be defined to use Case Closed Debugging"
#endif
+#if defined(CONFIG_USB_SPI)
+USB_SPI_CONFIG(ccd_usb_spi, USB_IFACE_SPI, USB_EP_SPI);
+#endif
+
static enum ccd_mode current_mode = CCD_MODE_DISABLED;
void ccd_set_mode(enum ccd_mode new_mode)
@@ -41,6 +46,10 @@ void ccd_set_mode(enum ccd_mode new_mode)
*/
usb_console_enable(new_mode == CCD_MODE_ENABLED);
+#if defined(CONFIG_USB_SPI)
+ usb_spi_enable(&ccd_usb_spi, new_mode == CCD_MODE_ENABLED);
+#endif
+
if (new_mode != CCD_MODE_DISABLED)
usb_init();
}