From b058bfe50707f0387891a892baaecb3625480e7b Mon Sep 17 00:00:00 2001 From: Robert Schilling Date: Fri, 22 Nov 2024 21:48:57 +0100 Subject: [PATCH] [hw,spi_host,rtl] Increase command length to 20-bit Currently the SPI host only supports a 9-bit command length, meaning a SPI transaction can only transfer 512b. This especially problematic, for integrated devices, where large FW blobs (>5MB) need to be fetched from the external SPI flash. When using in conjunction with the DMA (hardware-handshake mode), only a few chunks can be transferred before needing to re-program the SPI host and DMA. To overcome this problem, extend the command length to 20-bit. Signed-off-by: Robert Schilling --- hw/ip/spi_host/data/spi_host.hjson | 34 ++++++------- hw/ip/spi_host/doc/registers.md | 38 +++++++------- hw/ip/spi_host/dv/README.md | 2 +- hw/ip/spi_host/dv/env/spi_host_env_pkg.sv | 2 +- hw/ip/spi_host/rtl/spi_host_cmd_pkg.sv | 12 ++--- hw/ip/spi_host/rtl/spi_host_fsm.sv | 20 ++++---- hw/ip/spi_host/rtl/spi_host_reg_pkg.sv | 30 +++++------ hw/ip/spi_host/rtl/spi_host_reg_top.sv | 62 +++++++++++------------ 8 files changed, 100 insertions(+), 100 deletions(-) diff --git a/hw/ip/spi_host/data/spi_host.hjson b/hw/ip/spi_host/data/spi_host.hjson index 86699399ef185..d0dab3059776b 100644 --- a/hw/ip/spi_host/data/spi_host.hjson +++ b/hw/ip/spi_host/data/spi_host.hjson @@ -419,20 +419,34 @@ hwext: "true", hwqe: "true", fields: [ - { bits: "13:12", + { bits: "24:5", + name: "LEN", + desc: '''Segment Length. + + For read or write segments, this field controls the + number of 1-byte bursts to transmit and or receive in + this command segment. The number of cyles required + to send or received a byte will depend on !!COMMAND.SPEED. + For dummy segments, (!!COMMAND.DIRECTION == 0), this register + controls the number of dummy cycles to issue. + The number of bytes (or dummy cycles) in the segment will be + equal to !!COMMAND.LEN + 1.''', + resval: "0x0" + }, + { bits: "4:3", name: "DIRECTION", desc: '''The direction for the following command: "0" = Dummy cycles (no TX/RX). "1" = Rx only, "2" = Tx only, "3" = Bidirectional Tx/Rx (Standard SPI mode only).''' resval: "0x0" } - { bits: "11:10", + { bits: "2:1", name: "SPEED", desc: '''The speed for this command segment: "0" = Standard SPI. "1" = Dual SPI. "2"=Quad SPI, "3": RESERVED.''', resval: "0x0" }, - { bits: "9", + { bits: "0", name: "CSAAT", desc: '''**C**hip **S**elect **A**ctive **A**fter **T**ransaction. If !!COMMAND.CSAAT = 0, the chip select line is raised immediately @@ -445,20 +459,6 @@ the device.''', resval: "0x0" }, - { bits: "8:0", - name: "LEN", - desc: '''Segment Length. - - For read or write segments, this field controls the - number of 1-byte bursts to transmit and or receive in - this command segment. The number of cyles required - to send or received a byte will depend on !!COMMAND.SPEED. - For dummy segments, (!!COMMAND.DIRECTION == 0), this register - controls the number of dummy cycles to issue. - The number of bytes (or dummy cycles) in the segment will be - equal to !!COMMAND.LEN + 1.''', - resval: "0x0" - }, ], tags: [// Triggers exceptions if registers are improperly configured // Exclude from RW tests diff --git a/hw/ip/spi_host/doc/registers.md b/hw/ip/spi_host/doc/registers.md index df17ebc3a29d1..b833a4b374ba5 100644 --- a/hw/ip/spi_host/doc/registers.md +++ b/hw/ip/spi_host/doc/registers.md @@ -276,21 +276,33 @@ Command Register there is only one command register for controlling all attached SPI devices - Offset: `0x20` - Reset default: `0x0` -- Reset mask: `0x3fff` +- Reset mask: `0x1ffffff` ### Fields ```wavejson -{"reg": [{"name": "LEN", "bits": 9, "attr": ["wo"], "rotate": 0}, {"name": "CSAAT", "bits": 1, "attr": ["wo"], "rotate": -90}, {"name": "SPEED", "bits": 2, "attr": ["wo"], "rotate": -90}, {"name": "DIRECTION", "bits": 2, "attr": ["wo"], "rotate": -90}, {"bits": 18}], "config": {"lanes": 1, "fontsize": 10, "vspace": 110}} +{"reg": [{"name": "CSAAT", "bits": 1, "attr": ["wo"], "rotate": -90}, {"name": "SPEED", "bits": 2, "attr": ["wo"], "rotate": -90}, {"name": "DIRECTION", "bits": 2, "attr": ["wo"], "rotate": -90}, {"name": "LEN", "bits": 20, "attr": ["wo"], "rotate": 0}, {"bits": 7}], "config": {"lanes": 1, "fontsize": 10, "vspace": 110}} ``` | Bits | Type | Reset | Name | |:------:|:------:|:-------:|:---------------------------------| -| 31:14 | | | Reserved | -| 13:12 | wo | 0x0 | [DIRECTION](#command--direction) | -| 11:10 | wo | 0x0 | [SPEED](#command--speed) | -| 9 | wo | 0x0 | [CSAAT](#command--csaat) | -| 8:0 | wo | 0x0 | [LEN](#command--len) | +| 31:25 | | | Reserved | +| 24:5 | wo | 0x0 | [LEN](#command--len) | +| 4:3 | wo | 0x0 | [DIRECTION](#command--direction) | +| 2:1 | wo | 0x0 | [SPEED](#command--speed) | +| 0 | wo | 0x0 | [CSAAT](#command--csaat) | + +### COMMAND . LEN +Segment Length. + + For read or write segments, this field controls the + number of 1-byte bursts to transmit and or receive in + this command segment. The number of cyles required + to send or received a byte will depend on [`COMMAND.SPEED.`](#command) + For dummy segments, ([`COMMAND.DIRECTION`](#command) == 0), this register + controls the number of dummy cycles to issue. + The number of bytes (or dummy cycles) in the segment will be + equal to [`COMMAND.LEN`](#command) + 1. ### COMMAND . DIRECTION The direction for the following command: "0" = Dummy cycles @@ -312,18 +324,6 @@ The speed for this command segment: "0" = Standard SPI. "1" = Dual SPI. pausing for dummy cycles, and transmitting or receiving data from the device. -### COMMAND . LEN -Segment Length. - - For read or write segments, this field controls the - number of 1-byte bursts to transmit and or receive in - this command segment. The number of cyles required - to send or received a byte will depend on [`COMMAND.SPEED.`](#command) - For dummy segments, ([`COMMAND.DIRECTION`](#command) == 0), this register - controls the number of dummy cycles to issue. - The number of bytes (or dummy cycles) in the segment will be - equal to [`COMMAND.LEN`](#command) + 1. - ## RXDATA SPI Receive Data. diff --git a/hw/ip/spi_host/dv/README.md b/hw/ip/spi_host/dv/README.md index 5fc7c9974cde2..653f63fc0a80a 100644 --- a/hw/ip/spi_host/dv/README.md +++ b/hw/ip/spi_host/dv/README.md @@ -104,7 +104,7 @@ All common types and methods defined at the package level can be found in rand spi_mode_e mode; rand spi_dir_e direction; rand bit csaat; - rand bit [8:0] len; + rand bit [19:0] len; } spi_host_command_t; typedef struct packed { diff --git a/hw/ip/spi_host/dv/env/spi_host_env_pkg.sv b/hw/ip/spi_host/dv/env/spi_host_env_pkg.sv index c582cda61205a..c035f53683c03 100644 --- a/hw/ip/spi_host/dv/env/spi_host_env_pkg.sv +++ b/hw/ip/spi_host/dv/env/spi_host_env_pkg.sv @@ -31,7 +31,7 @@ package spi_host_env_pkg; parameter uint SPI_HOST_RX_FIFO_END = (SPI_HOST_RX_FIFO_START - 1) + spi_host_reg_pkg::SPI_HOST_RXDATA_SIZE; - parameter uint SPI_HOST_COMMAND_LEN_SIZE_BITS = 9; + parameter uint SPI_HOST_COMMAND_LEN_SIZE_BITS = 20; // macro includes `include "uvm_macros.svh" `include "dv_macros.svh" diff --git a/hw/ip/spi_host/rtl/spi_host_cmd_pkg.sv b/hw/ip/spi_host/rtl/spi_host_cmd_pkg.sv index c0eb40be1572a..b72154021e684 100644 --- a/hw/ip/spi_host/rtl/spi_host_cmd_pkg.sv +++ b/hw/ip/spi_host/rtl/spi_host_cmd_pkg.sv @@ -8,7 +8,7 @@ package spi_host_cmd_pkg; parameter int CSW = prim_util_pkg::vbits(spi_host_reg_pkg::NumCS); - parameter int CmdSize = CSW + 45; + parameter int CmdSize = CSW + 56; // For decoding the direction register typedef enum logic [1:0] { @@ -37,11 +37,11 @@ package spi_host_cmd_pkg; } configopts_t; typedef struct packed { - logic [1:0] speed; - logic cmd_wr_en; - logic cmd_rd_en; - logic [8:0] len; - logic csaat; + logic [1:0] speed; + logic cmd_wr_en; + logic cmd_rd_en; + logic [19:0] len; + logic csaat; } segment_t; typedef struct packed { diff --git a/hw/ip/spi_host/rtl/spi_host_fsm.sv b/hw/ip/spi_host/rtl/spi_host_fsm.sv index 6c8df111c0235..266e484a22089 100644 --- a/hw/ip/spi_host/rtl/spi_host_fsm.sv +++ b/hw/ip/spi_host/rtl/spi_host_fsm.sv @@ -62,13 +62,13 @@ module spi_host_fsm logic [1:0] cmd_speed_d, cmd_speed_q; logic cmd_wr_en_d, cmd_wr_en_q; logic cmd_rd_en_d, cmd_rd_en_q; - logic [8:0] cmd_len_d, cmd_len_q; + logic [19:0] cmd_len_d, cmd_len_q; logic csaat; logic csaat_q; logic [2:0] bit_cntr_d, bit_cntr_q; - logic [8:0] byte_cntr_cpha0_d, byte_cntr_cpha1_d, byte_cntr_cpha0_q, byte_cntr_cpha1_q; - logic [8:0] byte_cntr_early, byte_cntr_late; + logic [19:0] byte_cntr_cpha0_d, byte_cntr_cpha1_d, byte_cntr_cpha0_q, byte_cntr_cpha1_q; + logic [19:0] byte_cntr_early, byte_cntr_late; logic [3:0] wait_cntr_d, wait_cntr_q; logic last_bit, last_byte; @@ -157,7 +157,7 @@ module spi_host_fsm cmd_rd_en_q <= 1'b0; cmd_wr_en_q <= 1'b0; cmd_speed_q <= 2'b00; - cmd_len_q <= 9'h0; + cmd_len_q <= 20'h0; end else begin csid_q <= (new_command && !stall) ? csid : csid_q; cpol_q <= (new_command && !stall) ? cpol : cpol_q; @@ -442,21 +442,21 @@ module spi_host_fsm // always_comb begin if (cpha_q) begin - last_byte = (byte_cntr_cpha1_q == 9'h0); + last_byte = (byte_cntr_cpha1_q == 20'h0); end else begin - last_byte = (byte_cntr_cpha0_q == 9'h0); + last_byte = (byte_cntr_cpha0_q == 20'h0); end end // Note: when updating the byte_cntr in CPHA=0 mode with a new command value, the length must // be pulled in directly from the command bus, cmd_len_d; - assign byte_cntr_cpha0_d = sw_rst_i ? 9'h0 : + assign byte_cntr_cpha0_d = sw_rst_i ? 20'h0 : !fsm_en ? byte_cntr_cpha0_q : new_command ? cmd_len_d : byte_ending_cpha0 ? byte_cntr_cpha0_q - 1 : byte_cntr_cpha0_q; - assign byte_cntr_cpha1_d = sw_rst_i ? 9'h0 : + assign byte_cntr_cpha1_d = sw_rst_i ? 20'h0 : !fsm_en ? byte_cntr_cpha1_q : new_command ? cmd_len_d : byte_ending_cpha1 ? byte_cntr_cpha1_q - 1 : @@ -497,8 +497,8 @@ module spi_host_fsm always_ff @(posedge clk_i or negedge rst_ni) begin if (!rst_ni) begin bit_cntr_q <= 3'h0; - byte_cntr_cpha0_q <= 9'h0; - byte_cntr_cpha1_q <= 9'h0; + byte_cntr_cpha0_q <= 20'h0; + byte_cntr_cpha1_q <= 20'h0; wait_cntr_q <= 4'h0; end else begin bit_cntr_q <= stall ? bit_cntr_q : bit_cntr_d; diff --git a/hw/ip/spi_host/rtl/spi_host_reg_pkg.sv b/hw/ip/spi_host/rtl/spi_host_reg_pkg.sv index 97e30acf97af3..bf2b032c71d1d 100644 --- a/hw/ip/spi_host/rtl/spi_host_reg_pkg.sv +++ b/hw/ip/spi_host/rtl/spi_host_reg_pkg.sv @@ -102,6 +102,10 @@ package spi_host_reg_pkg; } spi_host_reg2hw_csid_reg_t; typedef struct packed { + struct packed { + logic [19:0] q; + logic qe; + } len; struct packed { logic [1:0] q; logic qe; @@ -114,10 +118,6 @@ package spi_host_reg_pkg; logic q; logic qe; } csaat; - struct packed { - logic [8:0] q; - logic qe; - } len; } spi_host_reg2hw_command_reg_t; typedef struct packed { @@ -279,14 +279,14 @@ package spi_host_reg_pkg; // Register -> HW type typedef struct packed { - spi_host_reg2hw_intr_state_reg_t intr_state; // [126:125] - spi_host_reg2hw_intr_enable_reg_t intr_enable; // [124:123] - spi_host_reg2hw_intr_test_reg_t intr_test; // [122:119] - spi_host_reg2hw_alert_test_reg_t alert_test; // [118:117] - spi_host_reg2hw_control_reg_t control; // [116:98] - spi_host_reg2hw_configopts_mreg_t [0:0] configopts; // [97:67] - spi_host_reg2hw_csid_reg_t csid; // [66:35] - spi_host_reg2hw_command_reg_t command; // [34:17] + spi_host_reg2hw_intr_state_reg_t intr_state; // [137:136] + spi_host_reg2hw_intr_enable_reg_t intr_enable; // [135:134] + spi_host_reg2hw_intr_test_reg_t intr_test; // [133:130] + spi_host_reg2hw_alert_test_reg_t alert_test; // [129:128] + spi_host_reg2hw_control_reg_t control; // [127:109] + spi_host_reg2hw_configopts_mreg_t [0:0] configopts; // [108:78] + spi_host_reg2hw_csid_reg_t csid; // [77:46] + spi_host_reg2hw_command_reg_t command; // [45:17] spi_host_reg2hw_error_enable_reg_t error_enable; // [16:12] spi_host_reg2hw_error_status_reg_t error_status; // [11:6] spi_host_reg2hw_event_enable_reg_t event_enable; // [5:0] @@ -319,11 +319,11 @@ package spi_host_reg_pkg; parameter logic [0:0] SPI_HOST_INTR_TEST_SPI_EVENT_RESVAL = 1'h 0; parameter logic [0:0] SPI_HOST_ALERT_TEST_RESVAL = 1'h 0; parameter logic [0:0] SPI_HOST_ALERT_TEST_FATAL_FAULT_RESVAL = 1'h 0; - parameter logic [13:0] SPI_HOST_COMMAND_RESVAL = 14'h 0; - parameter logic [8:0] SPI_HOST_COMMAND_LEN_RESVAL = 9'h 0; + parameter logic [24:0] SPI_HOST_COMMAND_RESVAL = 25'h 0; parameter logic [0:0] SPI_HOST_COMMAND_CSAAT_RESVAL = 1'h 0; parameter logic [1:0] SPI_HOST_COMMAND_SPEED_RESVAL = 2'h 0; parameter logic [1:0] SPI_HOST_COMMAND_DIRECTION_RESVAL = 2'h 0; + parameter logic [19:0] SPI_HOST_COMMAND_LEN_RESVAL = 20'h 0; // Window parameters parameter logic [BlockAw-1:0] SPI_HOST_RXDATA_OFFSET = 6'h 24; @@ -359,7 +359,7 @@ package spi_host_reg_pkg; 4'b 1111, // index[ 5] SPI_HOST_STATUS 4'b 1111, // index[ 6] SPI_HOST_CONFIGOPTS 4'b 1111, // index[ 7] SPI_HOST_CSID - 4'b 0011, // index[ 8] SPI_HOST_COMMAND + 4'b 1111, // index[ 8] SPI_HOST_COMMAND 4'b 0001, // index[ 9] SPI_HOST_ERROR_ENABLE 4'b 0001, // index[10] SPI_HOST_ERROR_STATUS 4'b 0001 // index[11] SPI_HOST_EVENT_ENABLE diff --git a/hw/ip/spi_host/rtl/spi_host_reg_top.sv b/hw/ip/spi_host/rtl/spi_host_reg_top.sv index 75ce27dc226d2..c22f9ea75f104 100644 --- a/hw/ip/spi_host/rtl/spi_host_reg_top.sv +++ b/hw/ip/spi_host/rtl/spi_host_reg_top.sv @@ -231,10 +231,10 @@ module spi_host_reg_top ( logic [31:0] csid_qs; logic [31:0] csid_wd; logic command_we; - logic [8:0] command_len_wd; logic command_csaat_wd; logic [1:0] command_speed_wd; logic [1:0] command_direction_wd; + logic [19:0] command_len_wd; logic error_enable_we; logic error_enable_cmdbusy_qs; logic error_enable_cmdbusy_wd; @@ -1184,23 +1184,7 @@ module spi_host_reg_top ( logic command_qe; logic [3:0] command_flds_we; assign command_qe = &command_flds_we; - // F[len]: 8:0 - prim_subreg_ext #( - .DW (9) - ) u_command_len ( - .re (1'b0), - .we (command_we), - .wd (command_len_wd), - .d ('0), - .qre (), - .qe (command_flds_we[0]), - .q (reg2hw.command.len.q), - .ds (), - .qs () - ); - assign reg2hw.command.len.qe = command_qe; - - // F[csaat]: 9:9 + // F[csaat]: 0:0 prim_subreg_ext #( .DW (1) ) u_command_csaat ( @@ -1209,14 +1193,14 @@ module spi_host_reg_top ( .wd (command_csaat_wd), .d ('0), .qre (), - .qe (command_flds_we[1]), + .qe (command_flds_we[0]), .q (reg2hw.command.csaat.q), .ds (), .qs () ); assign reg2hw.command.csaat.qe = command_qe; - // F[speed]: 11:10 + // F[speed]: 2:1 prim_subreg_ext #( .DW (2) ) u_command_speed ( @@ -1225,14 +1209,14 @@ module spi_host_reg_top ( .wd (command_speed_wd), .d ('0), .qre (), - .qe (command_flds_we[2]), + .qe (command_flds_we[1]), .q (reg2hw.command.speed.q), .ds (), .qs () ); assign reg2hw.command.speed.qe = command_qe; - // F[direction]: 13:12 + // F[direction]: 4:3 prim_subreg_ext #( .DW (2) ) u_command_direction ( @@ -1241,13 +1225,29 @@ module spi_host_reg_top ( .wd (command_direction_wd), .d ('0), .qre (), - .qe (command_flds_we[3]), + .qe (command_flds_we[2]), .q (reg2hw.command.direction.q), .ds (), .qs () ); assign reg2hw.command.direction.qe = command_qe; + // F[len]: 24:5 + prim_subreg_ext #( + .DW (20) + ) u_command_len ( + .re (1'b0), + .we (command_we), + .wd (command_len_wd), + .d ('0), + .qre (), + .qe (command_flds_we[3]), + .q (reg2hw.command.len.q), + .ds (), + .qs () + ); + assign reg2hw.command.len.qe = command_qe; + // R[error_enable]: V(False) // F[cmdbusy]: 0:0 @@ -1799,13 +1799,13 @@ module spi_host_reg_top ( assign csid_wd = reg_wdata[31:0]; assign command_we = addr_hit[8] & reg_we & !reg_error; - assign command_len_wd = reg_wdata[8:0]; + assign command_csaat_wd = reg_wdata[0]; - assign command_csaat_wd = reg_wdata[9]; + assign command_speed_wd = reg_wdata[2:1]; - assign command_speed_wd = reg_wdata[11:10]; + assign command_direction_wd = reg_wdata[4:3]; - assign command_direction_wd = reg_wdata[13:12]; + assign command_len_wd = reg_wdata[24:5]; assign error_enable_we = addr_hit[9] & reg_we & !reg_error; assign error_enable_cmdbusy_wd = reg_wdata[0]; @@ -1924,10 +1924,10 @@ module spi_host_reg_top ( end addr_hit[8]: begin - reg_rdata_next[8:0] = '0; - reg_rdata_next[9] = '0; - reg_rdata_next[11:10] = '0; - reg_rdata_next[13:12] = '0; + reg_rdata_next[0] = '0; + reg_rdata_next[2:1] = '0; + reg_rdata_next[4:3] = '0; + reg_rdata_next[24:5] = '0; end addr_hit[9]: begin