summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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();
}