diff options
-rw-r--r-- | chip/stm32/usb_spi.c | 87 | ||||
-rw-r--r-- | chip/stm32/usb_spi.h | 28 | ||||
-rw-r--r-- | common/case_closed_debug.c | 9 |
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(); } |