| // Copyright lowRISC contributors. | |
| // Licensed under the Apache License, Version 2.0, see LICENSE for details. | |
| // SPDX-License-Identifier: Apache-2.0 | |
| { name: "SPI_DEVICE", | |
| clock_primary: "clk_i", | |
| other_clock_list: [ | |
| "scan_clk_i" | |
| ], | |
| bus_interfaces: [ | |
| { protocol: "tlul", direction: "device" } | |
| ], | |
| available_input_list: [ | |
| { name: "sck", desc: "SPI Clock" }, | |
| { name: "csb", desc: "Chip Enable#" }, | |
| ], | |
| available_output_list: [ | |
| ], | |
| available_inout_list: [ | |
| { name: "sd", | |
| width: "4", | |
| desc: "SPI IO, IO2/IO3 has multi-purpose (/WP, /HOLD)" | |
| } | |
| ] | |
| interrupt_list: [ | |
| { name: "rxf", desc: "RX SRAM FIFO Full" }, | |
| { name: "rxlvl", desc: "RX SRAM FIFO is above the level" }, | |
| { name: "txlvl", desc: "TX SRAM FIFO is under the level" }, | |
| { name: "rxerr", desc: "SDI in FwMode has error" }, | |
| { name: "rxoverflow", desc: "RX Async FIFO overflow" }, | |
| { name: "txunderflow", desc: "TX Async FIFO underflow" }, | |
| ], | |
| scan: "true", // Enable `scanmode_i` port | |
| scan_reset: "true", // Enable `scan_rst_ni` port | |
| param_list: [ | |
| { name: "SramDepth" | |
| desc: "Sram Entries. Word size is 32bit width." | |
| type: "int unsigned" | |
| default: "1024" | |
| local: "true" | |
| } | |
| { name: "NumCmdInfo" | |
| desc: "Define the number of Command Info slots." | |
| type: "int unsigned" | |
| default: "16" | |
| local: "true" | |
| } | |
| ], | |
| inter_signal_list: [ | |
| { struct: "ram_2p_cfg", | |
| package: "prim_ram_2p_pkg", | |
| type: "uni", | |
| name: "ram_cfg", | |
| act: "rcv" | |
| } | |
| { struct: "passthrough", | |
| package: "spi_device_pkg" | |
| type: "req_rsp" | |
| name: "passthrough", | |
| act: "req" | |
| } | |
| { struct: "logic" | |
| package: "" | |
| type: "uni" | |
| name: "mbist_en" | |
| act: "rcv" | |
| } | |
| ], | |
| regwidth: "32", | |
| registers: [ | |
| { name: "CONTROL", | |
| desc: "Control register", | |
| swaccess: "rw", | |
| hwaccess: "hro", | |
| fields: [ | |
| { bits: "0", | |
| name: "ABORT", | |
| desc: ''' | |
| Abort pending jobs. If TX_FIFO (async) is full, | |
| this command can let TXF Control logic back to Idle state | |
| ''' | |
| resval: "0" | |
| }, | |
| { bits: "5:4", | |
| name: "MODE", | |
| desc: "SPI Device operation mode. Currently only FwMode is supported.", | |
| enum: [ | |
| { value: "0", | |
| name: "fwmode", | |
| desc: ''' | |
| FW operation mode. | |
| HW just dumps incoming data to SRAM and reads from SRAM and | |
| sends to SDO. This mode doesn't support Dual or Quad mode | |
| ''' | |
| }, | |
| ] | |
| tags: [// Changing modes randomly can result in unknown values being | |
| // passed between spi_dev/host due to passthrough | |
| "excl:CsrNonInitTests:CsrExclWrite"] | |
| }, | |
| { bits: "16", | |
| name: "rst_txfifo", | |
| desc: ''' | |
| Reset Async TX_FIFO. | |
| This only resets asynchronous fifo. If firmware wants to reset SRAM | |
| FIFO, it should write 0 into read/write pointers. | |
| _Note_: This value should be controlled only when SPI interface is | |
| in Idle state as this reset signal doesn't have reset synchronizer. | |
| ''' | |
| resval: "0", | |
| }, | |
| { bits: "17", | |
| name: "rst_rxfifo", | |
| desc: ''' | |
| Reset Async RX_FIFO. | |
| This only resets asynchronous fifo. If firmware wants to reset SRAM | |
| FIFO, it should write 0 into read pointer and write pointer. | |
| _Note_: This value should be controlled only when SPI interface is | |
| in Idle state as this reset signal doesn't have reset synchronizer. | |
| ''' | |
| resval: "0", | |
| }, | |
| { bits: "31" | |
| name: "sram_clk_en", | |
| desc: '''SRAM Clock Enable. | |
| This controls the clock gating cell lying on DP SRAM clock. As the | |
| nature of absent of SPI_CLK in idle state, the clock mux for SRAM | |
| B port cannot be glitch-free MUX. So, it is up to SW to change the | |
| clock safely. | |
| Programming sequence: | |
| 1. Check if SPI line is idle | |
| 2. Clear sram_clk_en to 0. | |
| 3. Change mode to FwMode for peri clk, FlashMode or PassThrough | |
| for SPI_CLK. | |
| 4. Set sram_clk_en to 1. | |
| ''' | |
| resval: "1" | |
| } | |
| ] | |
| }, | |
| { name: "CFG", | |
| desc: "Configuration Register", | |
| swaccess: "rw", | |
| hwaccess: "hro", | |
| fields: [ | |
| { bits: "0", | |
| name: "CPOL", | |
| desc: "Clock polarity. 0 for normal SPI, 1 for negative edge latch", | |
| resval: "0", | |
| }, | |
| { bits: "1", | |
| name: "CPHA", | |
| desc: "Data phase. 0 for negative edge change, 1 for positive edge change", | |
| resval: "0", | |
| }, | |
| { bits: "2", | |
| name: "tx_order", | |
| desc: "TX bit order on SDO. 0 for MSB to LSB, 1 for LSB to MSB", | |
| resval: "0", | |
| }, | |
| { bits: "3", | |
| name: "rx_order", | |
| desc: "RX bit order on SDI. Module stores bitstream from MSB to LSB if value is 0.", | |
| resval: "0", | |
| }, | |
| { bits: "15:8", | |
| name: "timer_v", | |
| desc: ''' | |
| number of clocks for RXF to wait. | |
| To reduce traffic to SRAM, RXF control module waits given clock cycle | |
| if it doesn't fill SRAM data width even if Async RX FIFO is empty. | |
| ''' | |
| resval: "0x7F", | |
| }, | |
| { bits: "16" | |
| name: "addr_4b_en" | |
| desc: '''4B Address Mode enable. | |
| This field configures the internal module to receive 32 bits of the SPI commands. The affected commands are the SPI read commands except QPI, and program commands. | |
| Even though Read SFDP command has address fields, the SFDP command | |
| is not affected by this field. The command always parse 24 bits on | |
| the SPI line 0 following the SPI command as the address field. | |
| ''' | |
| } | |
| ] | |
| }, | |
| { name: "FIFO_LEVEL", | |
| desc: "RX/ TX FIFO levels.", | |
| swaccess: "rw", | |
| hwaccess: "hro", | |
| fields: [ | |
| { bits: "15:0", | |
| name: "rxlvl", | |
| resval: "0x80", | |
| desc: ''' | |
| RX FIFO level. | |
| If RX SRAM FIFO level exceeds this value, it triggers interrupt. | |
| ''' | |
| }, | |
| { bits: "31:16", | |
| name: "txlvl", | |
| resval: "0x0", | |
| desc: ''' | |
| TX FIFO level. | |
| If TX SRAM FIFO level drops below this value, it triggers interrupt. | |
| ''' | |
| }, | |
| ], | |
| }, | |
| { name: "ASYNC_FIFO_LEVEL", | |
| desc: "RX/ TX Async FIFO levels between main clk and spi clock", | |
| swaccess: "ro", | |
| hwaccess: "hwo", | |
| hwext: "true", | |
| fields: [ | |
| { bits: "23:16", | |
| name: "txlvl", | |
| desc: ''' | |
| TX Async FIFO level. | |
| This value shows the number of available entry in TX Async FIFO. | |
| If the software writes message into SRAM FIFO and update FIFO write pointer | |
| but no clock from the host is given, the data stuck at this async fifo waiting | |
| host toggles SCK. This value represents the number of bytes. | |
| ''' | |
| tags: [// HW modifies async_fifo_level.txlvl when txf_ptr.wptr is updated. | |
| "excl:CsrNonInitTests:CsrExclWriteCheck"] | |
| }, | |
| { bits: "7:0", | |
| name: "rxlvl", | |
| desc: ''' | |
| RX Async FIFO level. | |
| This value shows the number of available entry in RX Async FIFO. | |
| ''' | |
| } | |
| ] | |
| }, | |
| { name: "STATUS", | |
| desc: "SPI Device status register", | |
| swaccess: "ro", | |
| hwaccess: "hwo", | |
| hwext: "true", | |
| fields: [ | |
| { bits: "0", name: "rxf_full", desc: "RX FIFO full" }, | |
| { bits: "1", name: "rxf_empty", desc: "RX FIFO empty", resval: "1"}, | |
| { bits: "2", name: "txf_full", desc: "TX FIFO full"}, | |
| { bits: "3", name: "txf_empty", desc: "TX FIFO empty", resval: "1"}, | |
| { bits: "4", name: "abort_done", desc: "Abort process is completed", resval: "1" }, | |
| { bits: "5", name: "csb", desc: "Direct input of CSb signal", resval: "1" }, | |
| ] | |
| tags: [// Status reads back unexpected values due to writes to other CSRs. | |
| "excl:CsrNonInitTests:CsrExclWriteCheck"] | |
| }, | |
| { name: "RXF_PTR", | |
| desc: "Receiver FIFO (SRAM) pointers", | |
| swaccess: "rw", | |
| hwaccess: "hrw", | |
| fields: [ | |
| { bits: "15:0", | |
| name: "RPTR", | |
| desc: "Read pointer. bit x is for phase bit. check circular fifo description", | |
| swaccess: "rw", | |
| hwaccess: "hro", | |
| resval: "0", | |
| tags: [// Updating rptr will cause unexpected interrupts. These interrupts may take a | |
| // while to generate and cip_base_vseq::clear_all_interrupts may not be able to | |
| // clear them in time. Leftover interrupts will cause sim error | |
| "excl:CsrNonInitTests:CsrExclWrite"] | |
| }, | |
| { bits: "31:16", | |
| name: "WPTR", | |
| desc: "Write pointer. Bit x is phase bit.", | |
| swaccess: "ro", | |
| hwaccess: "hwo", | |
| resval: "0", | |
| } | |
| ] | |
| }, | |
| { name: "TXF_PTR", | |
| desc: "Transmitter FIFO (SRAM) pointers", | |
| swaccess: "rw", | |
| hwaccess: "hrw", | |
| fields: [ | |
| { bits: "15:0", | |
| name: "RPTR", | |
| desc: "Read pointer. bit x is for phase bit. check circular fifo description", | |
| swaccess: "ro", | |
| hwaccess: "hwo", | |
| resval: "0", | |
| }, | |
| { bits: "31:16", | |
| name: "WPTR", | |
| desc: "Write pointer. Bit x is phase bit.", | |
| swaccess: "rw", | |
| hwaccess: "hro", | |
| resval: "0", | |
| tags: [// Updating rptr will cause unexpected interrupts. These interrupts may take a | |
| // while to generate and cip_base_vseq::clear_all_interrupts may not be able to | |
| // clear them in time. Leftover interrupts will cause sim error | |
| "excl:CsrNonInitTests:CsrExclWrite"] | |
| } | |
| ] | |
| }, | |
| { name: "RXF_ADDR", | |
| desc: "Receiver FIFO (SRAM) Addresses", | |
| swaccess: "rw", | |
| hwaccess: "hro", | |
| fields: [ | |
| { bits: "15:0", | |
| name: "base", | |
| desc: "Base offset in bytes in the SRAM. Lower 2 bits are ignored.", | |
| resval: "0", | |
| }, | |
| { bits: "31:16", | |
| name: "limit", | |
| desc: "Limit offset in bytes in the SRAM. Lower 2 bits are ignored.", | |
| resval: "0x1FC", | |
| } | |
| ], | |
| }, | |
| { name: "TXF_ADDR", | |
| desc: "Transmitter FIFO (SRAM) Addresses", | |
| swaccess: "rw", | |
| hwaccess: "hro", | |
| fields: [ | |
| { bits: "15:0", | |
| name: "base", | |
| desc: "Base offset in bytes in the SRAM. Lower 2 bits are ignored.", | |
| resval: "0x200", | |
| }, | |
| { bits: "31:16", | |
| name: "limit", | |
| desc: "Limit offset in bytes in the SRAM. Lower 2 bits are ignored.", | |
| resval: "0x3FC", | |
| } | |
| ], | |
| }, | |
| { multireg: { | |
| cname: "SPI_DEVICE" | |
| name: "CMD_FILTER" | |
| desc: '''Command Filter | |
| If a bit in this CSR is 1, then corresponding SPI command w.r.t the | |
| bit position among 256 bit is dropped in SPI Passthrough mode. | |
| ''' | |
| count: "256" | |
| swaccess: "rw" | |
| hwaccess: "hro" | |
| compact: true | |
| fields: [ | |
| { bits: "0" | |
| name: "filter" | |
| resval: "0" | |
| desc: "If 1, command will be filtered" | |
| } | |
| ] | |
| } | |
| } | |
| { name: "ADDR_SWAP_MASK" | |
| desc: '''Address Swap Mask register. | |
| This register is used in the SPI passthrough mode. If any of bits in | |
| this register is set, the corresponding address bit in the SPI Read | |
| commands is replaced with the data from !!ADDR_SWAP_DATA. | |
| If 3B address mode is active, upper 8bit [31:24] is ignored. | |
| ''' | |
| swaccess: "rw" | |
| hwaccess: "hro" | |
| fields: [ | |
| { bits: "31:0" | |
| resval: "0", | |
| name: "mask" | |
| desc: '''When a bit is 1, the SPI read address to the downstream SPI | |
| Flash device is swapped to !!ADDR_SWAP_DATA. | |
| ''' | |
| } | |
| ] | |
| } | |
| { name: "ADDR_SWAP_DATA" | |
| desc: '''The address value for the address swap feature. | |
| ''' | |
| swaccess: "rw" | |
| hwaccess: "hro" | |
| fields: [ | |
| { bits: "31:0" | |
| resval: "0" | |
| name: "data" | |
| desc: "Desired value to be swapped for the SPI read commands." | |
| } | |
| ] | |
| } | |
| { multireg: { | |
| cname: "SPI_DEVICE" | |
| name: "CMD_INFO" | |
| desc: '''Command Info register. | |
| ''' | |
| count: "NumCmdInfo" | |
| swaccess: "rw" | |
| hwaccess: "hro" | |
| fields: [ | |
| { bits: "7:0" | |
| resval: "0" | |
| name: "opcode" | |
| desc: '''Command Opcode | |
| ''' | |
| } | |
| { bits: "8" | |
| resval: "0" | |
| name: "addr_en" | |
| desc: "If 1, the command has an address field following the opcode" | |
| } | |
| { bits: "9" | |
| resval: "0" | |
| name: "addr_swap_en" | |
| desc: '''This field is used in the passthrough logic. | |
| If this field is set to 1, the address in the passthrough command | |
| is replaced to the preconfigured value. | |
| ''' | |
| } | |
| { bits: "10" | |
| name: "addr_4b_affected" | |
| desc: '''If 1, the address size is affected by `cfg_addr_4b_en`. | |
| If not, the address size of the command is always 3B. | |
| ''' | |
| } | |
| { bits: "14:12" | |
| resval: "7" | |
| name: "dummy_size" | |
| desc: "The number of dummy cycles -1 for the command" | |
| } | |
| { bits: "15" | |
| name: "dummy_en" | |
| desc: "Set to 1 if the command has a dummy cycle following the address field." | |
| } | |
| { bits: "19:16" | |
| name: "payload_en" | |
| desc: '''Payload Enable per SPI lane. | |
| Set to non-zero if the command has payload at the end of the | |
| protocol. This field has four bits. Each bit represents the SPI | |
| line. If a command is a Single IO command and returns data to the | |
| host system, the data is returned on the MISO line (IO[1]). In | |
| this case, SW sets payload_en to 4'b 0010. | |
| ''' | |
| } | |
| { bits: "20" | |
| name: "payload_dir" | |
| desc: "Set to 1 if the command returns data. If 0, the payload sends to the downstream Flash device." | |
| } | |
| ] | |
| } | |
| } | |
| { skipto: "0x1000" } | |
| { window: { | |
| name: "buffer", | |
| items: "SramDepth", | |
| validbits: "32", | |
| byte-write: "false", | |
| unusual: "false" | |
| swaccess: "rw", | |
| desc: ''' | |
| SPI internal buffer. | |
| In Generic mode, this buffer is used for RX/TX buffer. In Flash & | |
| Passthrough mode, lower 2kB is for Read content emulating eFlash. | |
| next 1kB is for Mailbox read/write buffer. The rest is 64B of | |
| CmdFIFO, 64B of AddrFIFO, and 256B of payload FIFO. | |
| ''' | |
| }, | |
| }, | |
| ] | |
| } |