| // 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" }, |
| ], |
| alert_list: [ |
| { name: "fatal_fault", |
| desc: ''' |
| This fatal alert is triggered when a fatal TL-UL bus integrity fault is detected. |
| ''' |
| } |
| ], |
| 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. |
| ''' |
| }, |
| }, |
| ] |
| } |