summaryrefslogtreecommitdiff
path: root/chip
diff options
context:
space:
mode:
Diffstat (limited to 'chip')
-rw-r--r--chip/host/clock.c4
-rw-r--r--chip/ish/clock.c4
-rw-r--r--chip/it83xx/clock.c4
-rw-r--r--chip/max32660/clock_chip.c4
-rw-r--r--chip/mchp/clock.c4
-rw-r--r--chip/mt_scp/mt818x/clock_mt8183.c4
-rw-r--r--chip/mt_scp/mt818x/clock_mt8186.c4
-rw-r--r--chip/mt_scp/mt8192/clock.c4
-rw-r--r--chip/mt_scp/mt8195/clock.c4
-rw-r--r--chip/npcx/clock.c11
-rw-r--r--chip/stm32/trng.c2
-rw-r--r--chip/stm32/usb_spi.c227
-rw-r--r--chip/stm32/usb_spi.h220
13 files changed, 395 insertions, 101 deletions
diff --git a/chip/host/clock.c b/chip/host/clock.c
index 4f90067f3a..defb12f4f0 100644
--- a/chip/host/clock.c
+++ b/chip/host/clock.c
@@ -11,3 +11,7 @@ int clock_get_freq(void)
{
return 16000000;
}
+
+void clock_enable_module(enum module_id module, int enable)
+{
+}
diff --git a/chip/ish/clock.c b/chip/ish/clock.c
index f9fec0b7d2..2fefa11c2f 100644
--- a/chip/ish/clock.c
+++ b/chip/ish/clock.c
@@ -29,3 +29,7 @@ void clock_refresh_console_in_use(void)
*/
ish_pm_refresh_console_in_use();
}
+
+void clock_enable_module(enum module_id module, int enable)
+{
+}
diff --git a/chip/it83xx/clock.c b/chip/it83xx/clock.c
index fccc62eee7..abbbcf3b58 100644
--- a/chip/it83xx/clock.c
+++ b/chip/it83xx/clock.c
@@ -701,3 +701,7 @@ DECLARE_CONSOLE_COMMAND(idlestats, command_idle_stats, "",
#endif /* CONFIG_CMD_IDLE_STATS */
#endif /* CONFIG_LOW_POWER_IDLE */
+
+void clock_enable_module(enum module_id module, int enable)
+{
+}
diff --git a/chip/max32660/clock_chip.c b/chip/max32660/clock_chip.c
index 26225401ba..8e497c846b 100644
--- a/chip/max32660/clock_chip.c
+++ b/chip/max32660/clock_chip.c
@@ -139,3 +139,7 @@ void clock_init(void)
}
}
}
+
+void clock_enable_module(enum module_id module, int enable)
+{
+}
diff --git a/chip/mchp/clock.c b/chip/mchp/clock.c
index 0323d16f8f..8732e21117 100644
--- a/chip/mchp/clock.c
+++ b/chip/mchp/clock.c
@@ -750,3 +750,7 @@ DECLARE_CONSOLE_COMMAND(
"Give a timeout value for the console in use timeout.\n"
"See also 'sleep mask'.");
#endif /* CONFIG_LOW_POWER_IDLE */
+
+void clock_enable_module(enum module_id module, int enable)
+{
+}
diff --git a/chip/mt_scp/mt818x/clock_mt8183.c b/chip/mt_scp/mt818x/clock_mt8183.c
index fca89cd2a5..a48eee952a 100644
--- a/chip/mt_scp/mt818x/clock_mt8183.c
+++ b/chip/mt_scp/mt818x/clock_mt8183.c
@@ -370,3 +370,7 @@ static int command_ulposc(int argc, const char *argv[])
}
DECLARE_CONSOLE_COMMAND(ulposc, command_ulposc, "[calibrate]",
"Calibrate ULPOSC frequency");
+
+void clock_enable_module(enum module_id module, int enable)
+{
+}
diff --git a/chip/mt_scp/mt818x/clock_mt8186.c b/chip/mt_scp/mt818x/clock_mt8186.c
index cb0d339b5f..eafc5992fd 100644
--- a/chip/mt_scp/mt818x/clock_mt8186.c
+++ b/chip/mt_scp/mt818x/clock_mt8186.c
@@ -376,3 +376,7 @@ static int command_ulposc(int argc, const char *argv[])
}
DECLARE_CONSOLE_COMMAND(ulposc, command_ulposc, "[calibrate]",
"Calibrate ULPOSC frequency");
+
+void clock_enable_module(enum module_id module, int enable)
+{
+}
diff --git a/chip/mt_scp/mt8192/clock.c b/chip/mt_scp/mt8192/clock.c
index 21d07d410a..ec6e3f2537 100644
--- a/chip/mt_scp/mt8192/clock.c
+++ b/chip/mt_scp/mt8192/clock.c
@@ -381,3 +381,7 @@ int command_ulposc(int argc, const char *argv[])
DECLARE_CONSOLE_COMMAND(ulposc, command_ulposc, "[ulposc]",
"Measure ULPOSC frequency");
#endif
+
+void clock_enable_module(enum module_id module, int enable)
+{
+}
diff --git a/chip/mt_scp/mt8195/clock.c b/chip/mt_scp/mt8195/clock.c
index 779f356bab..e41a360ae8 100644
--- a/chip/mt_scp/mt8195/clock.c
+++ b/chip/mt_scp/mt8195/clock.c
@@ -501,3 +501,7 @@ int command_ulposc(int argc, const char *argv[])
DECLARE_CONSOLE_COMMAND(ulposc, command_ulposc, "[ulposc]",
"Measure ULPOSC frequency");
#endif
+
+void clock_enable_module(enum module_id module, int enable)
+{
+}
diff --git a/chip/npcx/clock.c b/chip/npcx/clock.c
index 1ab4d1063a..992fc1b628 100644
--- a/chip/npcx/clock.c
+++ b/chip/npcx/clock.c
@@ -162,6 +162,11 @@ void clock_turbo(void)
*/
NPCX_HFCBCD = NPCX_HFCBCD & 0xF3;
}
+
+void clock_enable_module(enum module_id module, int enable)
+{
+}
+
#elif NPCX_FAMILY_VERSION >= NPCX_FAMILY_NPCX7
void clock_turbo(void)
{
@@ -200,6 +205,12 @@ void clock_enable_module(enum module_id module, int enable)
}
}
+#else
+
+void clock_enable_module(enum module_id module, int enable)
+{
+}
+
#endif
/**
diff --git a/chip/stm32/trng.c b/chip/stm32/trng.c
index aafc0e89c1..67d3700cf1 100644
--- a/chip/stm32/trng.c
+++ b/chip/stm32/trng.c
@@ -16,7 +16,7 @@
#include "trng.h"
#include "util.h"
-uint32_t trng_rand(void)
+static uint32_t trng_rand(void)
{
int tries = 300;
/* Wait for a valid random number */
diff --git a/chip/stm32/usb_spi.c b/chip/stm32/usb_spi.c
index c45ea3520d..0ddde1b0d8 100644
--- a/chip/stm32/usb_spi.c
+++ b/chip/stm32/usb_spi.c
@@ -8,11 +8,18 @@
#include "link_defs.h"
#include "registers.h"
#include "spi.h"
+#include "timer.h"
#include "usb_descriptor.h"
#include "usb_hw.h"
#include "usb_spi.h"
#include "util.h"
+/* How long to wait for a flash page programming. */
+#define FLASH_BUSY_POLL_TIMEOUT_USEC (1000 * MSEC)
+
+const uint8_t JEDEC_READ_STATUS = 0x05;
+const uint8_t JEDEC_STATUS_BUSY = 0x01;
+
/* Forward declare platform specific functions. */
static bool usb_spi_received_packet(void);
static bool usb_spi_transmitted_packet(void);
@@ -164,6 +171,9 @@ static void setup_transfer_response(uint16_t status_code)
*/
static void create_spi_config_response(struct usb_spi_packet_ctx *packet)
{
+ const struct spi_device_t *current_device =
+ &spi_devices[usb_spi_state.current_spi_device_idx];
+
/* Construct the response packet. */
packet->rsp_config.packet_id = USB_SPI_PKT_ID_RSP_USB_SPI_CONFIG;
packet->rsp_config.max_write_count = USB_SPI_MAX_WRITE_COUNT;
@@ -174,6 +184,23 @@ static void create_spi_config_response(struct usb_spi_packet_ctx *packet)
packet->rsp_config.feature_bitmap |=
USB_SPI_FEATURE_FULL_DUPLEX_SUPPORTED;
#endif
+#ifdef CONFIG_USB_SPI_FLASH_EXTENSIONS
+ packet->rsp_config.feature_bitmap |= USB_SPI_FEATURE_FLASH_EXTENSIONS;
+ if (current_device->usb_flags & USB_SPI_FLASH_DUAL_SUPPORT)
+ packet->rsp_config.feature_bitmap |=
+ USB_SPI_FEATURE_DUAL_MODE_SUPPORTED;
+ if (current_device->usb_flags & USB_SPI_FLASH_QUAD_SUPPORT)
+ packet->rsp_config.feature_bitmap |=
+ USB_SPI_FEATURE_QUAD_MODE_SUPPORTED;
+ if (current_device->usb_flags & USB_SPI_FLASH_OCTO_SUPPORT)
+ packet->rsp_config.feature_bitmap |=
+ USB_SPI_FEATURE_OCTO_MODE_SUPPORTED;
+ if (current_device->usb_flags & USB_SPI_FLASH_DTR_SUPPORT)
+ packet->rsp_config.feature_bitmap |=
+ USB_SPI_FEATURE_DTR_SUPPORTED;
+#else
+ (void)current_device; /* Avoid warning about unused variable. */
+#endif
packet->packet_size = sizeof(struct usb_spi_response_configuration_v2);
}
@@ -231,6 +258,45 @@ usb_spi_create_spi_transfer_response(struct usb_spi_packet_ctx *transmit_packet)
}
}
+#ifdef CONFIG_USB_SPI_FLASH_EXTENSIONS
+/*
+ * Decodes the header fields of a Flash Command Start Packet, and sets up the
+ * transaction depending on if it is read or write.
+ */
+static void setup_flash_transfer(struct usb_spi_packet_ctx *packet)
+{
+ const uint32_t flags = packet->cmd_flash_start.flags;
+ usb_spi_state.flash_flags = flags;
+ const uint8_t opcode_count = (flags & FLASH_FLAG_OPCODE_LEN_MSK) >>
+ FLASH_FLAG_OPCODE_LEN_POS;
+ const uint8_t addr_count = (flags & FLASH_FLAG_ADDR_LEN_MSK) >>
+ FLASH_FLAG_ADDR_LEN_POS;
+ const bool write_enable = !!(flags & FLASH_FLAG_WRITE_ENABLE);
+ if ((packet->cmd_flash_start.flags & FLASH_FLAG_READ_WRITE_MSK) ==
+ FLASH_FLAG_READ_WRITE_WRITE) {
+ size_t write_count = packet->cmd_flash_start.count;
+ if (write_count > USB_SPI_MAX_WRITE_COUNT) {
+ usb_spi_state.status_code = USB_SPI_WRITE_COUNT_INVALID;
+ return;
+ }
+ usb_spi_setup_transfer(write_enable + opcode_count +
+ addr_count + write_count,
+ 0);
+ } else {
+ size_t read_count = packet->cmd_flash_start.count;
+ if (read_count > USB_SPI_MAX_READ_COUNT) {
+ usb_spi_state.status_code = USB_SPI_WRITE_COUNT_INVALID;
+ return;
+ }
+ usb_spi_setup_transfer(write_enable + opcode_count + addr_count,
+ read_count);
+ }
+ packet->header_size = offsetof(struct usb_spi_flash_command, data);
+ usb_spi_state.status_code =
+ usb_spi_read_usb_packet(&usb_spi_state.spi_write_ctx, packet);
+}
+#endif
+
/*
* Process the rx packet.
*
@@ -266,6 +332,7 @@ static void usb_spi_process_rx_packet(struct usb_spi_packet_ctx *packet)
/* The host started a new USB SPI transfer */
size_t write_count = packet->cmd_start.write_count;
size_t read_count = packet->cmd_start.read_count;
+ usb_spi_state.flash_flags = 0;
if (!usb_spi_state.enabled) {
setup_transfer_response(USB_SPI_DISABLED);
@@ -302,6 +369,30 @@ static void usb_spi_process_rx_packet(struct usb_spi_packet_ctx *packet)
break;
}
+#ifdef CONFIG_USB_SPI_FLASH_EXTENSIONS
+ case USB_SPI_PKT_ID_CMD_FLASH_TRANSFER_START: {
+ /* The host started a new USB serial flash SPI transfer */
+ if (!usb_spi_state.enabled) {
+ setup_transfer_response(USB_SPI_DISABLED);
+ } else {
+ setup_flash_transfer(packet);
+ }
+
+ /* Send responses if we encountered an error. */
+ if (usb_spi_state.status_code != USB_SPI_SUCCESS) {
+ setup_transfer_response(usb_spi_state.status_code);
+ break;
+ }
+
+ /* Start the SPI transfer when we've read all data. */
+ if (usb_spi_state.spi_write_ctx.transfer_index ==
+ usb_spi_state.spi_write_ctx.transfer_size) {
+ usb_spi_state.mode = USB_SPI_MODE_START_SPI;
+ }
+
+ break;
+ }
+#endif
case USB_SPI_PKT_ID_CMD_TRANSFER_CONTINUE: {
/*
* The host has sent a continue packet for the SPI transfer
@@ -355,6 +446,107 @@ static void usb_spi_process_rx_packet(struct usb_spi_packet_ctx *packet)
}
}
+/*
+ * Perform a SPI write-then-read transaction, optionally preceded by a single
+ * byte "write enable" (separated by deasserting chip select), and optionally
+ * followed by polling the "busy bit" until clear.
+ */
+static uint16_t do_spi_transfer(void)
+{
+ const struct spi_device_t *current_device =
+ &spi_devices[usb_spi_state.current_spi_device_idx];
+ bool custom_board_driver = current_device->usb_flags &
+ USB_SPI_CUSTOM_SPI_DEVICE;
+ /*
+ * If CONFIG_USB_SPI_FLASH_EXTENSIONS is not enabled, then the below
+ * value being zero will allow the compiler to optimize away several
+ * large if-blocks in this function.
+ */
+ const uint32_t flash_flags =
+ IS_ENABLED(CONFIG_USB_SPI_FLASH_EXTENSIONS) ?
+ usb_spi_state.flash_flags :
+ 0;
+ uint16_t status_code = EC_SUCCESS;
+ int read_count = usb_spi_state.spi_read_ctx.transfer_size;
+ const char *write_data_ptr = usb_spi_state.spi_write_ctx.buffer;
+ int write_count = usb_spi_state.spi_write_ctx.transfer_size;
+#ifndef CONFIG_SPI_HALFDUPLEX
+ /*
+ * Handle the full duplex mode on supported platforms.
+ * The read count is equal to the write count.
+ */
+ if (read_count == USB_SPI_FULL_DUPLEX_ENABLED) {
+ usb_spi_state.spi_read_ctx.transfer_size =
+ usb_spi_state.spi_write_ctx.transfer_size;
+ read_count = SPI_READBACK_ALL;
+ }
+#endif
+
+ if (!custom_board_driver &&
+ (flash_flags & FLASH_FLAGS_REQUIRING_SUPPORT)) {
+ /*
+ * The standard spi_transaction() does not support
+ * any multi-lane modes.
+ */
+ return USB_SPI_UNSUPPORTED_FLASH_MODE;
+ }
+
+ if (status_code == EC_SUCCESS &&
+ flash_flags & FLASH_FLAG_WRITE_ENABLE) {
+ /* Precede main transaction with one-byte "write enable". */
+ if (custom_board_driver) {
+ status_code = usb_spi_board_transaction(
+ current_device, 0, write_data_ptr, 1, NULL, 0);
+ } else {
+ status_code = spi_transaction(
+ current_device, write_data_ptr, 1, NULL, 0);
+ }
+ write_data_ptr += 1;
+ write_count -= 1;
+ }
+
+ if (status_code == EC_SUCCESS) {
+ if (custom_board_driver) {
+ status_code = usb_spi_board_transaction(
+ current_device, flash_flags, write_data_ptr,
+ write_count, usb_spi_state.spi_read_ctx.buffer,
+ read_count);
+ } else {
+ status_code = spi_transaction(
+ current_device, write_data_ptr, write_count,
+ usb_spi_state.spi_read_ctx.buffer, read_count);
+ }
+ }
+
+ if (flash_flags & FLASH_FLAG_POLL) {
+ /* After main transaction, poll until no longer "busy". */
+ static timestamp_t deadline;
+ deadline.val = get_time().val + FLASH_BUSY_POLL_TIMEOUT_USEC;
+
+ while (status_code == EC_SUCCESS) {
+ timestamp_t now;
+ uint8_t status_byte;
+ if (custom_board_driver) {
+ status_code = usb_spi_board_transaction(
+ current_device, 0, &JEDEC_READ_STATUS,
+ 1, &status_byte, 1);
+ } else {
+ status_code = spi_transaction(
+ current_device, &JEDEC_READ_STATUS, 1,
+ &status_byte, 1);
+ }
+ if ((status_byte & JEDEC_STATUS_BUSY) == 0)
+ break;
+ now = get_time();
+ if (timestamp_expired(deadline, &now)) {
+ status_code = EC_ERROR_TIMEOUT;
+ break;
+ }
+ }
+ }
+ return usb_spi_map_error(status_code);
+}
+
/* Deferred function to handle state changes, process USB SPI packets,
* and construct responses.
*
@@ -412,40 +604,7 @@ void usb_spi_deferred(void)
/* Start a new SPI transfer. */
if (usb_spi_state.mode == USB_SPI_MODE_START_SPI) {
- const struct spi_device_t *current_device =
- &spi_devices[usb_spi_state.current_spi_device_idx];
- bool custom_board_driver = current_device->usb_flags &
- USB_SPI_CUSTOM_SPI_DEVICE;
- uint16_t status_code;
- int read_count = usb_spi_state.spi_read_ctx.transfer_size;
-#ifndef CONFIG_SPI_HALFDUPLEX
- /*
- * Handle the full duplex mode on supported platforms.
- * The read count is equal to the write count.
- */
- if (read_count == USB_SPI_FULL_DUPLEX_ENABLED) {
- usb_spi_state.spi_read_ctx.transfer_size =
- usb_spi_state.spi_write_ctx.transfer_size;
- read_count = SPI_READBACK_ALL;
- }
-#endif
-
- if (custom_board_driver) {
- status_code = usb_spi_board_transaction(
- current_device, 0 /* flash_flags */,
- usb_spi_state.spi_write_ctx.buffer,
- usb_spi_state.spi_write_ctx.transfer_size,
- usb_spi_state.spi_read_ctx.buffer, read_count);
- } else {
- status_code = spi_transaction(
- current_device,
- usb_spi_state.spi_write_ctx.buffer,
- usb_spi_state.spi_write_ctx.transfer_size,
- usb_spi_state.spi_read_ctx.buffer, read_count);
- }
-
- /* Cast the EC status code to USB SPI and start the response. */
- status_code = usb_spi_map_error(status_code);
+ uint16_t status_code = do_spi_transfer();
setup_transfer_response(status_code);
}
diff --git a/chip/stm32/usb_spi.h b/chip/stm32/usb_spi.h
index 385aaaf730..e0dfd34b18 100644
--- a/chip/stm32/usb_spi.h
+++ b/chip/stm32/usb_spi.h
@@ -146,6 +146,7 @@
* 0x0008: An unexpected packet arrived that the device could not
* process.
* 0x0009: The device does not support full duplex mode.
+ * 0x000A: Requested serial flash mode not supported
* 0x8000: Unknown error mask
* The bottom 15 bits will contain the bottom 15 bits from the EC
* error code.
@@ -218,7 +219,12 @@
*
* feature bitmap: Bitmap of supported features.
* BIT(0): Full duplex SPI mode is supported
- * BIT(1:15): Reserved for future use
+ * BIT(1): Serial flash extensions are supported
+ * BIT(2): Dual mode flash supported
+ * BIT(3): Quad mode flash supported
+ * BIT(4): Octo mode flash supported
+ * BIT(5): Double transfer rate supported
+ * BIT(6:15): Reserved for future use
*
* Command Restart Response Packet (Host to Device):
*
@@ -256,6 +262,64 @@
* 0x0000: Success
* others: Error
*
+ * Flash Command Start Packet (Host to Device):
+ *
+ * Start of the USB serial flash SPI command, contains the number of
+ * bytes to write or read on SPI and up to the first 58 bytes of write
+ * payload. Longer writes will use the continue packets with packet id
+ * USB_SPI_PKT_ID_CMD_TRANSFER_CONTINUE to transmit the remaining data.
+ *
+ * The reading or writing of the "main" data will be preceded by an
+ * short sequence of opcode, optional address, optional "alternate data",
+ * and optional 'dummy cycles" on the SPI bus. Flags indicate how many
+ * bytes of each stage to send, and whether to use advanced features such
+ * as dual or quad signal lanes for each stage of the transfer".
+ *
+ * The indicated number of opcode, address and alternate bytes will be
+ * the first in the "write payload". The "count" field will contain the
+ * number of data bytes to be written/read after the opcode, address and
+ * alternate bytes.
+ *
+ * This request is only supported if bit 1 of the "feature bitmap"
+ * indicates that serial flash extensions are supported. Implementations
+ * will further advertise whether they support dual, quad or octo modes, if
+ * none of these are supported, then support for "dummy cycles" is not
+ * guaranteed either, and callers should use one or two bytes of "extra
+ * address data" for dummy cycles, address length can be up to 7 bytes for
+ * this reason.
+ *
+ * +----------------+------------+------------+---------------+
+ * | packet id : 2B | count : 2B | flags : 4B | w.p. : <= 56B |
+ * +----------------+------------+------------+---------------+
+ *
+ * packet id: 2 byte enum defined by packet_id_type
+ * Valid values packet id =
+ * USB_SPI_PKT_ID_CMD_FLASH_TRANSFER_START
+ *
+ * count: 2 byte, zero based count of bytes to read or write
+ *
+ * flags: 4 byte, flags
+ * bits 0:1 opcode length in bytes (0-3)
+ * bits 2:4 address length in bytes (0-7)
+ * bits 5:6 mode (0: 1-1-1, 1: 1-1-N, 2: 1-N-N, 3: N-N-N)
+ * bits 7:8 width (0: N=1, 1: N=2, 2: N=4, 3: N=8)
+ * bit 9 double transfer rate (in phases marked as N)
+ * bits 10:14 number of dummy cycles (0-31)
+ * bits 15:27 reserved, must be zero
+ * bit 28 write to be preceded by "write enable"
+ * bit 29 write to be followed by polling of JEDEC "busy bit"
+ * bit 30 reserved, must be zero
+ * bit 31 read (0) / write (1)
+ *
+ * write payload: Up to 56 bytes of data to write to SPI, the total length
+ * of all TX packets must match: write enable length (zero or
+ * one, depending on bit 27) + opcode length + address length
+ * + count, (the last one only if bit 31 indicates a write
+ * operation). Due to data alignment constraints, this must
+ * be an even number of bytes unless this is the final
+ * packet.
+ *
+ *
* USB Error Codes:
*
* send_command return codes have the following format:
@@ -278,6 +342,8 @@
#define USB_SPI_PAYLOAD_SIZE_V2_ERROR (60)
+#define USB_SPI_PAYLOAD_SIZE_FLASH_START (56)
+
#define USB_SPI_MIN_PACKET_SIZE (2)
/*
@@ -294,6 +360,8 @@
#define USB_SPI_FLASH_QUAD_SUPPORT BIT(3)
/* This SPI device supports eight lane mode. */
#define USB_SPI_FLASH_OCTO_SUPPORT BIT(4)
+/* This SPI device supports double transfer rate (data on both clock edges). */
+#define USB_SPI_FLASH_DTR_SUPPORT BIT(5)
enum packet_id_type {
/* Request USB SPI configuration data from device. */
@@ -325,11 +393,34 @@ enum packet_id_type {
USB_SPI_PKT_ID_CMD_CHIP_SELECT = 7,
/* Response to above request. */
USB_SPI_PKT_ID_RSP_CHIP_SELECT = 8,
+ /*
+ * Start a USB serial flash SPI transfer.
+ */
+ USB_SPI_PKT_ID_CMD_FLASH_TRANSFER_START = 9,
};
enum feature_bitmap {
/* Indicates the platform supports full duplex mode. */
- USB_SPI_FEATURE_FULL_DUPLEX_SUPPORTED = BIT(0)
+ USB_SPI_FEATURE_FULL_DUPLEX_SUPPORTED = BIT(0),
+ /* Indicates support for USB_SPI_PKT_ID_CMD_FLASH_TRANSFER_START. */
+ USB_SPI_FEATURE_FLASH_EXTENSIONS = BIT(1),
+ /*
+ * Indicates that chip and any MUXes support bidirectional data on the
+ * two SPI data lines.
+ */
+ USB_SPI_FEATURE_DUAL_MODE_SUPPORTED = BIT(2),
+ /*
+ * Indicates that chip and any MUXes support bidirectional data on the
+ * "hold" and "write protect" lines.
+ */
+ USB_SPI_FEATURE_QUAD_MODE_SUPPORTED = BIT(3),
+ /* Indicates support for eight-line bidirectional data. */
+ USB_SPI_FEATURE_OCTO_MODE_SUPPORTED = BIT(4),
+ /*
+ * Indicates support for double transfer rate, i.e. data bit shift on
+ * both rising and falling clock edges.
+ */
+ USB_SPI_FEATURE_DTR_SUPPORTED = BIT(5),
};
struct usb_spi_response_configuration_v2 {
@@ -374,11 +465,36 @@ struct usb_spi_chip_select_response {
uint16_t status_code;
} __packed;
+struct usb_spi_flash_command {
+ uint16_t packet_id;
+ uint16_t count;
+ uint32_t flags;
+ uint8_t data[USB_SPI_PAYLOAD_SIZE_FLASH_START];
+} __packed;
+
+/*
+ * Mask of the flags that are handled by logic in sub_spi.c, and not passed to
+ * SPI drivers through usb_spi_board_transaction().
+ */
+#define FLASH_FLAGS_NONBOARD 0xF0000000UL
+
+#define FLASH_FLAG_WRITE_ENABLE_POS 28U
+#define FLASH_FLAG_WRITE_ENABLE (0x1UL << FLASH_FLAG_WRITE_ENABLE_POS)
+
+#define FLASH_FLAG_POLL_POS 29U
+#define FLASH_FLAG_POLL (0x1UL << FLASH_FLAG_POLL_POS)
+
+#define FLASH_FLAG_READ_WRITE_POS 31U
+#define FLASH_FLAG_READ_WRITE_MSK (0x1UL << FLASH_FLAG_READ_WRITE_POS)
+#define FLASH_FLAG_READ_WRITE_READ 0
+#define FLASH_FLAG_READ_WRITE_WRITE (0x1UL << FLASH_FLAG_READ_WRITE_POS)
+
struct usb_spi_packet_ctx {
union {
uint8_t bytes[USB_MAX_PACKET_SIZE];
uint16_t packet_id;
struct usb_spi_command_v2 cmd_start;
+ struct usb_spi_flash_command cmd_flash_start;
struct usb_spi_continue_v2 cmd_continue;
struct usb_spi_response_configuration_v2 rsp_config;
struct usb_spi_response_v2 rsp_start;
@@ -412,6 +528,8 @@ enum usb_spi_error {
USB_SPI_RX_UNEXPECTED_PACKET = 0x0008,
/* The device does not support full duplex mode. */
USB_SPI_UNSUPPORTED_FULL_DUPLEX = 0x0009,
+ /* The device does not support dual/quad wire mode. */
+ USB_SPI_UNSUPPORTED_FLASH_MODE = 0x000A,
USB_SPI_UNKNOWN_ERROR = 0x8000,
};
@@ -508,6 +626,12 @@ struct usb_spi_state {
struct usb_spi_packet_ctx transmit_packet;
/*
+ * Flags describing if and how multi-lane (dual/quad), double transfer
+ * rate, and other advanced flash protocol features are to be used.
+ */
+ uint32_t flash_flags;
+
+ /*
* Context structures representing the progress receiving the SPI
* write data and transmitting the SPI read data.
*/
@@ -666,70 +790,38 @@ int usb_spi_board_transaction(const struct spi_device_t *spi_device,
* communication, when supported.
*/
-/* Data width during the opcode stage. */
-#define FLASH_FLAG_OPCODE_WIDTH_POS 0
-#define FLASH_FLAG_OPCODE_WIDTH_MSK (0x3U << FLASH_FLAG_OPCODE_WIDTH_POS)
-#define FLASH_FLAG_OPCODE_WIDTH_1WIRE (0x0U << FLASH_FLAG_OPCODE_WIDTH_POS)
-#define FLASH_FLAG_OPCODE_WIDTH_2WIRE (0x1U << FLASH_FLAG_OPCODE_WIDTH_POS)
-#define FLASH_FLAG_OPCODE_WIDTH_4WIRE (0x2U << FLASH_FLAG_OPCODE_WIDTH_POS)
-#define FLASH_FLAG_OPCODE_WIDTH_8WIRE (0x3U << FLASH_FLAG_OPCODE_WIDTH_POS)
-
-/* Transmit opcode bits at both rising and falling clock edges. */
-#define FLASH_FLAG_OPCODE_DTR_POS 2
-#define FLASH_FLAG_OPCODE_DTR (0x1U << FLASH_FLAG_OPCODE_DTR_POS)
-
-/* Number of bytes of opcode (0-4). */
-#define FLASH_FLAG_OPCODE_LEN_POS 3
-#define FLASH_FLAG_OPCODE_LEN_MSK (0x7U << FLASH_FLAG_OPCODE_LEN_POS)
-
-/* Data width during the address stage. */
-#define FLASH_FLAG_ADDR_WIDTH_POS 6
-#define FLASH_FLAG_ADDR_WIDTH_MSK (0x3U << FLASH_FLAG_ADDR_WIDTH_POS)
-#define FLASH_FLAG_ADDR_WIDTH_1WIRE (0x0U << FLASH_FLAG_ADDR_WIDTH_POS)
-#define FLASH_FLAG_ADDR_WIDTH_2WIRE (0x1U << FLASH_FLAG_ADDR_WIDTH_POS)
-#define FLASH_FLAG_ADDR_WIDTH_4WIRE (0x2U << FLASH_FLAG_ADDR_WIDTH_POS)
-#define FLASH_FLAG_ADDR_WIDTH_8WIRE (0x3U << FLASH_FLAG_ADDR_WIDTH_POS)
-
-/* Transmit address bits at both rising and falling clock edges. */
-#define FLASH_FLAG_ADDR_DTR_POS 8
-#define FLASH_FLAG_ADDR_DTR (0x1U << FLASH_FLAG_ADDR_DTR_POS)
-
-/* Number of bytes of address (0-4). */
-#define FLASH_FLAG_ADDR_LEN_POS 9
-#define FLASH_FLAG_ADDR_LEN_MSK (0x7U << FLASH_FLAG_ADDR_LEN_POS)
-
-/* Data width during the "alternate bytes" stage. */
-#define FLASH_FLAG_ALT_WIDTH_POS 12
-#define FLASH_FLAG_ALT_WIDTH_MSK (0x3U << FLASH_FLAG_ALT_WIDTH_POS)
-#define FLASH_FLAG_ALT_WIDTH_1WIRE (0x0U << FLASH_FLAG_ALT_WIDTH_POS)
-#define FLASH_FLAG_ALT_WIDTH_2WIRE (0x1U << FLASH_FLAG_ALT_WIDTH_POS)
-#define FLASH_FLAG_ALT_WIDTH_4WIRE (0x2U << FLASH_FLAG_ALT_WIDTH_POS)
-#define FLASH_FLAG_ALT_WIDTH_8WIRE (0x3U << FLASH_FLAG_ALT_WIDTH_POS)
+/* Number of bytes of opcode (0-3). */
+#define FLASH_FLAG_OPCODE_LEN_POS 0
+#define FLASH_FLAG_OPCODE_LEN_MSK (0x3U << FLASH_FLAG_OPCODE_LEN_POS)
-/* Transmit alternate bits at both rising and falling clock edges. */
-#define FLASH_FLAG_ALT_DTR_POS 14
-#define FLASH_FLAG_ALT_DTR (0x1U << FLASH_FLAG_ALT_DTR_POS)
+/* Number of bytes of address plus additional data bytes (0-7). */
+#define FLASH_FLAG_ADDR_LEN_POS 2
+#define FLASH_FLAG_ADDR_LEN_MSK (0x7U << FLASH_FLAG_ADDR_LEN_POS)
-/* Number of bytes of alternate data (0-4). */
-#define FLASH_FLAG_ALT_LEN_POS 15
-#define FLASH_FLAG_ALT_LEN_MSK (0x7U << FLASH_FLAG_ALT_LEN_POS)
+/* At what stage to switch to multi-lane mode (if any). */
+#define FLASH_FLAG_MODE_POS 5
+#define FLASH_FLAG_MODE_MSK (0x3U << FLASH_FLAG_MODE_POS)
+#define FLASH_FLAG_MODE_111 (0x0U << FLASH_FLAG_MODE_POS)
+#define FLASH_FLAG_MODE_11N (0x1U << FLASH_FLAG_MODE_POS)
+#define FLASH_FLAG_MODE_1NN (0x2U << FLASH_FLAG_MODE_POS)
+#define FLASH_FLAG_MODE_NNN (0x3U << FLASH_FLAG_MODE_POS)
+
+/* Data width during the later stages (value of N, above). */
+#define FLASH_FLAG_WIDTH_POS 7
+#define FLASH_FLAG_WIDTH_MSK (0x3U << FLASH_FLAG_WIDTH_POS)
+#define FLASH_FLAG_WIDTH_1WIRE (0x0U << FLASH_FLAG_WIDTH_POS)
+#define FLASH_FLAG_WIDTH_2WIRE (0x1U << FLASH_FLAG_WIDTH_POS)
+#define FLASH_FLAG_WIDTH_4WIRE (0x2U << FLASH_FLAG_WIDTH_POS)
+#define FLASH_FLAG_WIDTH_8WIRE (0x3U << FLASH_FLAG_WIDTH_POS)
+
+/* Transmit opcode bits at both clock edges in later stages. */
+#define FLASH_FLAG_DTR_POS 9
+#define FLASH_FLAG_DTR (0x1U << FLASH_FLAG_DTR_POS)
/* Number of dummy clock cycles (0-31). */
-#define FLASH_FLAG_DUMMY_CYCLES_POS 18
+#define FLASH_FLAG_DUMMY_CYCLES_POS 10
#define FLASH_FLAG_DUMMY_CYCLES_MSK (0x1FU << FLASH_FLAG_DUMMY_CYCLES_POS)
-/* Data width during the data stage. */
-#define FLASH_FLAG_DATA_WIDTH_POS 23
-#define FLASH_FLAG_DATA_WIDTH_MSK (0x3U << FLASH_FLAG_DATA_WIDTH_POS)
-#define FLASH_FLAG_DATA_WIDTH_1WIRE (0x0U << FLASH_FLAG_DATA_WIDTH_POS)
-#define FLASH_FLAG_DATA_WIDTH_2WIRE (0x1U << FLASH_FLAG_DATA_WIDTH_POS)
-#define FLASH_FLAG_DATA_WIDTH_4WIRE (0x2U << FLASH_FLAG_DATA_WIDTH_POS)
-#define FLASH_FLAG_DATA_WIDTH_8WIRE (0x3U << FLASH_FLAG_DATA_WIDTH_POS)
-
-/* Transmit data bits at both rising and falling clock edges. */
-#define FLASH_FLAG_DATA_DTR_POS 25
-#define FLASH_FLAG_DATA_DTR (0x1U << FLASH_FLAG_DATA_DTR_POS)
-
/*
* Mask of the flags that cannot be ignored. This is basically any flags
* which call for wires to switch direction, or data being clocked on both
@@ -739,11 +831,7 @@ int usb_spi_board_transaction(const struct spi_device_t *spi_device,
* the controller knowing which parts are to be interpreted as
* opcode/address/data.
*/
-#define FLASH_FLAGS_REQUIRING_SUPPORT \
- (FLASH_FLAG_OPCODE_WIDTH_MSK | FLASH_FLAG_OPCODE_DTR | \
- FLASH_FLAG_ADDR_WIDTH_MSK | FLASH_FLAG_ADDR_DTR | \
- FLASH_FLAG_ALT_WIDTH_MSK | FLASH_FLAG_ALT_DTR | \
- FLASH_FLAG_DUMMY_CYCLES_MSK | FLASH_FLAG_DATA_WIDTH_MSK | \
- FLASH_FLAG_DATA_DTR)
+#define FLASH_FLAGS_REQUIRING_SUPPORT \
+ (FLASH_FLAG_MODE_MSK | FLASH_FLAG_DTR | FLASH_FLAG_DUMMY_CYCLES_MSK)
#endif /* __CROS_EC_USB_SPI_H */