| // Copyright lowRISC contributors. |
| // Licensed under the Apache License, Version 2.0, see LICENSE for details. |
| // SPDX-License-Identifier: Apache-2.0 |
| { |
| name: "spi_device", |
| human_name: "SPI Device", |
| one_line_desc: "Serial peripheral interface supporting different device modes, suitable for bulk-load of data into and out of the chip", |
| one_paragraph_desc: ''' |
| SPI Device is a configurable, versatile hardware block that implements a generic SPI device mode, plus three additional modes (SPI Flash emulation mode, SPI passthrough mode, and TPM over SPI mode) to support a variety of different applications. |
| For example, generic mode can be used in a raw data transfer protocol termed "Firmware Operation Mode", which is intended to be used to bulk-load data into and out of the chip. |
| TPM over SPI operates in compliance with TPM PC Client Platform, unloading this protocol from a software solution. |
| SPI Flash emulation mode supports many JEDEC standard commands such as Read Status, Read JEDEC ID, Read SFDP, EN4B/EX4B, and multiple other read commands, allowing OpenTitan to provide, for example, verified boot firmware to other external devices. |
| ''' |
| design_spec: "../doc", |
| dv_doc: "../doc/dv", |
| hw_checklist: "../doc/checklist", |
| sw_checklist: "/sw/device/lib/dif/dif_spi_device", |
| revisions: [ |
| { |
| version: "0.5", |
| life_stage: "L1", |
| design_stage: "D1", |
| verification_stage: "V1", |
| dif_stage: "S0", |
| commit_id: "553ca956e0204e5b67b3bbea47f2e067f60b5510", |
| notes: "" |
| } |
| { version: "1.0", |
| life_stage: "L1", |
| design_stage: "D2S", |
| verification_stage: "V2S", |
| dif_stage: "S2", |
| commit_id: "", |
| notes: "" |
| } |
| ] |
| clocking: [ |
| {clock: "clk_i", reset: "rst_ni", primary: true}, |
| // The scan_rst_ni port isn't listed here because it's generated by the |
| // "scan_reset: true" below. |
| {clock: "scan_clk_i"} |
| ] |
| bus_interfaces: [ |
| { protocol: "tlul", direction: "device" } |
| ], |
| available_input_list: [ |
| { name: "sck", desc: "SPI Clock" }, |
| { name: "csb", desc: "Chip Select#" }, |
| { name: "tpm_csb", desc: "TPM Chip Select#"} |
| ], |
| available_output_list: [ |
| ], |
| available_inout_list: [ |
| { name: "sd", |
| width: "4", |
| desc: "SPI IO, IO2/IO3 has multi-purpose (/WP, /HOLD)" |
| } |
| ] |
| interrupt_list: [ |
| { name: "generic_rx_full" |
| desc: "RX SRAM FIFO Full" |
| } |
| { name: "generic_rx_watermark" |
| desc: "RX SRAM FIFO is above the level" |
| } |
| { name: "generic_tx_watermark" |
| desc: "TX SRAM FIFO is under the level" |
| } |
| { name: "generic_rx_error" |
| desc: "SDI in FwMode has error" |
| type: "event" |
| } |
| { name: "generic_rx_overflow" |
| desc: "RX Async FIFO overflow" |
| type: "event" |
| } |
| { name: "generic_tx_underflow" |
| desc: "TX Async FIFO underflow" |
| type: "event" |
| } |
| { name: "upload_cmdfifo_not_empty" |
| desc: "Upload Command FIFO is not empty" |
| } |
| { name: "upload_payload_not_empty" |
| desc: '''Upload payload is not empty. |
| |
| The event occurs after SPI transaction completed |
| ''' |
| } |
| { name: "upload_payload_overflow" |
| desc: '''Upload payload overflow event. |
| |
| When a SPI Host system issues a command with payload more than 256B, |
| this event is reported. When it happens, SW should read the last |
| written payload index CSR to figure out the starting address of the |
| last 256B. |
| ''' |
| type: "event" |
| } |
| { name: "readbuf_watermark" |
| desc: '''Read Buffer Threshold event. |
| |
| The host system accesses greater than or equal to the threshold of a |
| buffer. |
| ''' |
| } |
| { name: "readbuf_flip" |
| desc: '''Read buffer flipped event. |
| |
| The host system accesses other side of buffer. |
| ''' |
| type: "event" |
| } |
| { name: "tpm_header_not_empty" |
| desc: "TPM Header(Command/Address) buffer available" |
| type: "status" |
| } |
| ], |
| 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: "24" |
| local: "true" |
| } |
| { name: "NumLocality" |
| desc: "The number of locality TPM module supports." |
| type: "int unsigned" |
| default: "5" |
| local: "true" |
| } // p: NumLocality |
| { name: "TpmWrFifoPtrW" |
| desc: "TPM WrFIFO Pointer Bit Width. clog2(Depth(64+1))" |
| type: "int unsigned" |
| default: "7" |
| local: "true" |
| } // p: TpmWrFifoPtrW |
| { name: "TpmRdFifoPtrW" |
| desc: "TPM RdFIFO Pointer Bit Width. clog2(Depth(16+1))" |
| type: "int unsigned" |
| default: "5" |
| local: "true" |
| } // p: TpmRdFifoPtrW |
| { name: "TpmRdFifoWidth" |
| desc: "TPM Read FIFO Data Width. (TpmRdFifoWidth/8) shall be power of two" |
| type: "int unsigned" |
| default: "32" |
| } // p: TpmRdFifoWidth |
| ], |
| 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" |
| } |
| { struct: "logic" |
| package: "" |
| type: "uni" |
| name: "sck_monitor" |
| act: "req" |
| } |
| ], |
| countermeasures: [ |
| { name: "BUS.INTEGRITY", |
| desc: "End-to-end bus integrity scheme." |
| } |
| ] |
| regwidth: "32", |
| registers: [ |
| { name: "CONTROL", |
| desc: "Control register", |
| swaccess: "rw", |
| hwaccess: "hro", |
| fields: [ |
| { bits: "0", |
| name: "ABORT", |
| desc: '''Abort pending TX data in Generic mode. |
| |
| If TX_FIFO (Asynchronous) is full, the TXF waits indefinitely to |
| push the next byte into the asynchronous FIFO. SW may reset the |
| Async FIFO along with aborting the current task. SW should update |
| the write pointer of the TXF in order not to push the byte to |
| Asynchronous FIFO again by TXF logic. |
| ''' |
| resval: "0" |
| }, |
| { bits: "5:4", |
| name: "MODE", |
| desc: "SPI Device operation mode. Currently only FwMode is supported.", |
| resval: "1" |
| 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 |
| ''' |
| }, |
| { value: "1" |
| name: "flashmode" |
| desc: '''SPI Flash Emulation mode. |
| |
| In flash mode, SPI Device IP accepts SPI Flash commands and |
| processes internally, then returns data for the read commands. |
| HW processes the Status, JEDEC ID, SFDP commands. |
| |
| The current version does not support Dual/Quad IO and QPI |
| commands. |
| ''' |
| } |
| { value: "2" |
| name: "passthrough" |
| desc: ''' |
| In passthrough mode, SPI Device IP forwards the incoming SPI |
| flash traffics to the attached downstream flash device. HW may |
| processes commands internally and returns data. |
| |
| SW may configure the device to drop inadmissable commands. |
| ''' |
| } |
| ] |
| 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" |
| swaccess: "rw" |
| hwaccess: "hrw" // Updated by EN4B/EX4B |
| 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. It is expected for SW to |
| configure this field at the configuration stage and leave the |
| updation to HW until next reset. |
| |
| 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. |
| ''' |
| } |
| { bits: "24" |
| name: "mailbox_en" |
| desc: '''Mailbox enable. |
| |
| If 1, in the flash and passthrough mode, the IP checks the incoming |
| address and return from the internal Mailbox buffer if the address |
| falls into the MAILBOX range |
| (MAILBOX_ADDR:MAILBOX_ADDR+MAILBOX_SIZE)}. |
| ''' |
| } // f: mailbox_en |
| ] |
| }, |
| { 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. |
| ''' |
| }, |
| { 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. |
| |
| Current version does not implement abort_done logic. It is tied to |
| 1 always. |
| ''' |
| resval: "1" }, |
| { bits: "5", name: "csb", desc: "Direct input of CSb signal", resval: "1" }, |
| { bits: "6" |
| name: "tpm_csb" |
| desc: "Direct input of TPM CSb" |
| resval: "1" |
| tags: [ |
| // the value of tpm_csb is determined by the |
| // value on the pins, hence it cannot be predicted. |
| "excl:CsrAllTests:CsrExclCheck" |
| ] |
| } |
| ] |
| }, |
| { 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", |
| } |
| ], |
| }, |
| //========================================================================= |
| // Flash & Passthrough CSRs |
| { name: "INTERCEPT_EN" |
| desc: '''Intercept Passthrough datapath. |
| |
| ''' |
| swaccess: "rw" |
| hwaccess: "hro" |
| fields: [ |
| { bits: "0" |
| name: "status" |
| desc: "If set, Read Status is processed internally." |
| } // f: status |
| { bits: "1" |
| name: "jedec" |
| desc: "If set, Read JEDEC ID is processed internally." |
| } // f: jedec |
| { bits: "2" |
| name: "sfdp" |
| desc: "If set, Read SFDP is processed internally." |
| } // f: sfdp |
| { bits: "3" |
| name: "mbx" |
| desc: "If set, Read Command to Mailbox region is processed internally." |
| } // f: mailbox |
| ] |
| } // R: INTERCEPT_EN |
| { name: "LAST_READ_ADDR" |
| desc: '''Last Read Address |
| |
| This register shows the last address accessed by the host system. |
| It is updated by the HW when CSb is de-asserted. |
| ''' |
| swaccess: "ro" |
| hwaccess: "hwo" |
| hwext: true |
| fields: [ |
| { bits: "31:0" |
| name: "addr" |
| desc: "Last address" |
| } |
| ] |
| } // R: LAST_READ_ADDR |
| { name: "FLASH_STATUS" |
| desc: '''SPI Flash Status register. |
| |
| This register emulates the SPI Flash Status 3, 2, 1 registers. |
| bit [7:0] is for Status register, bit [15:8] is for Status-2 register, |
| and bit [23:16] is for Status-3 register. It is SW responsibility to |
| maintain this register value up to date. |
| |
| The HW latches the value when SPI Flash transaction begins. Any updates |
| during the transaction will be updated after the transaction is |
| completed. |
| ''' |
| swaccess: "rw" |
| hwaccess: "hrw" |
| hwext: true |
| hwqe: true |
| tags: [ |
| // SW is not able to read back the STATUS register right after write. |
| // The read back value is committed value, which needs at least a SPI |
| // transaction. |
| // So excluded from CSR automation test. |
| "excl:CsrNonInitTests:CsrExclWrite" |
| ] |
| fields: [ |
| { bits: "0" |
| name: "busy" |
| desc: '''BUSY signal is cleared when CSb is high. SW should read |
| back the register to confirm the value is cleared.''' |
| swaccess: "rw0c" |
| hwaccess: "hrw" |
| } // f: busy |
| { bits: "23:1" |
| name: "status" |
| desc: '''Rest of the status register. |
| |
| Fields other than the bit 0 (BUSY) and bit 1 (WEL) fields are |
| SW-maintained fields. HW just reads and returns to the host system. |
| |
| Bit 1 (WEL) is a SW modifiable and HW modifiable field. HW updates |
| the WEL field when `WRDI` or `WREN` command is received. |
| |
| - [ 1]\: WEL |
| - [ 2]\: BP0 |
| - [ 3]\: BP1 |
| - [ 4]\: BP2 |
| - [ 5]\: TB |
| - [ 6]\: SEC |
| - [ 7]\: SRP0 |
| - [ 8]\: SRP1 |
| - [ 9]\: QE |
| - [11]\: LB1 |
| - [12]\: LB2 |
| - [13]\: LB3 |
| - [14]\: CMP |
| - [15]\: SUS |
| - [18]\: WPS |
| - [21]\: DRV0 |
| - [22]\: DRV1 |
| - [23]\: HOLD /RST |
| ''' |
| } // f: status |
| ] |
| } // R: FLASH_STATUS |
| { |
| name: "JEDEC_CC" |
| desc: '''JEDEC Continuation Code configuration register. |
| |
| Read JEDEC ID must return the continuation code if the manufacturer ID |
| is not shown in the first page of JEDEC table. This register controls |
| the Continuation Code. |
| ''' |
| swaccess: "rw" |
| hwaccess: "hro" |
| fields: [ |
| { bits: "15:8" |
| name: "num_cc" |
| desc: "The number that Continuation Code repeats" |
| } // f: num_cc |
| { bits: "7:0" |
| name: "cc" |
| desc: "Continuation Code byte" |
| resval: "0x7F" |
| } // f: cc |
| ] |
| } // R: JEDEC_CC |
| { |
| name: "JEDEC_ID" |
| desc: '''JEDEC ID register. |
| ''' |
| swaccess: "rw" |
| hwaccess: "hro" |
| fields: [ |
| { bits: "23:16" |
| name: "mf" |
| desc: "Manufacturer ID" |
| } // f: manufacturer id |
| { bits: "15:0" |
| name: "id" |
| desc: "Device ID" |
| } // f: device id |
| ] |
| } // R: JEDEC_ID |
| { name: "READ_THRESHOLD" |
| desc: '''Read Buffer threshold register. |
| |
| ''' |
| swaccess: "rw" |
| hwaccess: "hro" |
| fields: [ |
| { bits: "9:0" |
| name: "threshold" |
| desc: '''If 0, disable the watermark. If non-zero, when the host |
| access above or equal to the threshold, it reports an interrupt. |
| The value is byte-granularity not SRAM index. |
| ''' |
| } // f: threshold |
| ] |
| } // R: READ_THRESHOLD |
| { name: "MAILBOX_ADDR" |
| desc: '''Mailbox Base address register. |
| |
| The mailbox size is fixed. In this version of IP, the size is 1kB. |
| Lower 10 bits of the Mailbox address is tied to 0. |
| ''' |
| swaccess: "rw" |
| hwaccess: "hro" |
| fields: [ |
| { bits: "31:0" |
| name: "addr" |
| desc: "Mailbox Address. Lower 10 bits are ignored" |
| } // f: addr |
| ] |
| } // R: MAILBOX_ADDR |
| { name: "UPLOAD_STATUS" |
| desc: '''Upload module status register. |
| ''' |
| swaccess: "ro" |
| hwaccess: "hwo" |
| fields: [ |
| { bits: "4:0" |
| name: "cmdfifo_depth" |
| desc: "Command FIFO Entry" |
| } // f: cmdfifo_depth |
| { bits: "7" |
| name: "cmdfifo_notempty" |
| desc: "Upload Command FIFO Not Empty" |
| } // f: cmdfifo_notempty |
| { bits: "12:8" |
| name: "addrfifo_depth" |
| desc: "Address FIFO Entry" |
| } // f: addrfifo_depth |
| { bits: "15" |
| name: "addrfifo_notempty" |
| desc: "Upload Address FIFO Not Empty" |
| } // f: addrfifo_notempty |
| ] |
| } // R: UPLOAD_STATUS |
| { name: "UPLOAD_STATUS2" |
| desc: '''Upload module status 2 register. |
| |
| This register contains payload related status. payload_depth indicates |
| the payload size (from 0 to 256 bytes). |
| |
| payload_start_idx indicates the start of the 256B. This stays 0 |
| usually. However, when the SPI host system issues more than 256B of |
| payload in a command, this field may not be 0. For example, if the |
| system issues 258B payload, the payload_depth is 256 (as the IP only |
| holds 256B of payload), the payload_start_idx is 2. SW should read from |
| 2 to 255 then 0 and 1. |
| ''' |
| swaccess: "ro" |
| hwaccess: "hwo" |
| fields: [ |
| { bits: "8:0" |
| name: "payload_depth" |
| desc: '''Payload buffer depth |
| ''' |
| } // f: payload_depth |
| { bits: "23:16" |
| name: "payload_start_idx" |
| desc: '''Payload Start Index''' |
| } // f: payload_start_idx |
| ] |
| } // R: UPLOAD_STATUS2 |
| { name: "UPLOAD_CMDFIFO" |
| desc: '''Command Fifo Read Port. |
| ''' |
| swaccess: "ro" |
| hwaccess: "hrw" |
| hwre: "true" |
| hwext: "true" |
| fields: [ |
| { bits: "7:0" |
| name: "data" |
| desc: "read data" |
| } |
| ] |
| } // R: UPLOAD_CMDFIFO |
| { name: "UPLOAD_ADDRFIFO" |
| desc: '''Address Fifo Read Port. |
| ''' |
| swaccess: "ro" |
| hwaccess: "hrw" |
| hwre: "true" |
| hwext: "true" |
| fields: [ |
| { bits: "31:0" |
| name: "data" |
| desc: "read data" |
| } |
| ] |
| } // R: UPLOAD_ADDRFIFO |
| { 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." |
| } |
| ] |
| } |
| { name: "PAYLOAD_SWAP_MASK" |
| desc: '''Write Data Swap in the passthrough mode. |
| |
| PAYLOAD_SWAP_MASK CSR provides the SW to change certain bits in the |
| first 4 bytes of the write payload in the passthrough mode. |
| ''' |
| swaccess: "rw" |
| hwaccess: "hro" |
| fields: [ |
| { bits: "31:0" |
| resval: "0" |
| name: "mask" |
| desc: "byte mask" |
| } // f: mask |
| ] |
| } // R: PAYLOAD_SWAP_MASK |
| { name: "PAYLOAD_SWAP_DATA" |
| desc: '''Write Data Swap in the passthrough mode. |
| |
| PAYLOAD_SWAP_DATA combined with PAYLOAD_SWAP_MASK provides the SW to |
| change certain bits in the first 4 bytes of the write payload in the |
| passthrough mode. |
| |
| The register should be written in Little-Endian order. [7:0] bits are |
| processed in the first received payload byte. [31:24] bits for the 4th |
| byte. |
| ''' |
| swaccess: "rw" |
| hwaccess: "hro" |
| fields: [ |
| { bits: "31:0" |
| resval: "0" |
| name: "data" |
| desc: "replaced data" |
| } // f: data |
| ] |
| } // R: PAYLOAD_SWAP_DATA |
| { 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: "9:8" |
| resval: "0" |
| name: "addr_mode" |
| desc: '''Command address mode |
| |
| A command can have four modes: |
| |
| - 0: Command does not have an address field |
| - 1: CFG.addr_4b_en decides the address size (3B/4B) |
| - 2: Address size is always 3B regardless of CFG.addr_4b_en |
| - 3: Address size is always 4B regardless of CFG.addr_4b_en |
| ''' |
| enum: [ |
| { value: "0" |
| name: "AddrDisabled" |
| desc: "Address field does not exist" |
| } // e: AddrDisabled |
| { value: "1" |
| name: "AddrCfg" |
| desc: "CFG.addr_4b_en determines the address size" |
| } // e: AddrCfg |
| { value: "2" |
| name: "Addr3B" |
| desc: "Address size in the command is always 3B." |
| } // e: Addr3B |
| { value: "3" |
| name: "Addr4B" |
| desc: "Address size in the command is always 4B." |
| } // e: Addr4B |
| ] |
| } // f: addr_mode |
| { bits: "10" |
| 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: "11" |
| name: "mbyte_en" |
| desc: '''If 1, the command has a MByte field following the |
| address field. This is set to 1 for DualIO, QuadIO commands. |
| ''' |
| } |
| { 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. |
| ''' |
| enum: [ |
| { value: "0" |
| name: "PayloadIn" |
| desc: "From host to the downstream flash device" |
| } // e: PayloadIn |
| { value: "1" |
| name: "PayloadOut" |
| desc: "From the downstream flash device to the host" |
| } // e: PayloadOut |
| ] |
| } // f: payload_dir |
| { bits: "21" |
| name: "payload_swap_en" |
| desc: '''Swap the first byte of the write payload. |
| |
| If `payload_swap_en` is set, the passthrough logic swaps the first byte of the write payload with DATA_SWAP CSR. |
| |
| `payload_swap_en` only works with write data and SingleIO mode. `payload_en` must be 4'b 0001 and `paylod_dir` to be PayloadIn. |
| ''' |
| } // f: payload_swap_en |
| { bits: "24" |
| name: "upload" |
| desc: '''Set to 1 to upload the command. |
| |
| If upload field in the command info entry is set, the cmdparse |
| activates the upload submodule when the opcode is received. |
| `addr_en`, `addr_4B_affected`, and `addr_4b_forced` (TBD) affect |
| the upload functionality. The three address related configs |
| defines the command address field size. |
| |
| The logic assumes the following SPI input stream as payload, |
| which max size is 256B. If the command exceeds the maximum |
| payload size 256B, the logic wraps the payload and overwrites. |
| ''' |
| } // f: upload |
| { bits: "25" |
| name: "busy" |
| desc: '''Set to 1 to set the BUSY bit in the FLASH_STATUS when the |
| command is received. This bit is active only when `upload` bit is |
| set. |
| ''' |
| } // f: busy |
| { bits: "31" |
| name: "valid" |
| desc: '''Set to 1 if the config in the register is valid |
| ''' |
| } // f: valid |
| ] |
| } |
| } |
| { name: "CMD_INFO_EN4B" |
| swaccess: "rw" |
| hwaccess: "hro" |
| desc: '''Opcode for EN4B. |
| |
| If the register is active, it affects in flash / passthrough modes. |
| ''' |
| fields: [ |
| { bits: "31" |
| name: "valid" |
| desc: "If 1, Opcode affects" |
| } // f: valid |
| { bits: "7:0" |
| name: "opcode" |
| desc: "EN4B opcode" |
| } // f: opcode |
| ] |
| } // R: CMD_INFO_EN4B |
| { name: "CMD_INFO_EX4B" |
| swaccess: "rw" |
| hwaccess: "hro" |
| desc: '''Opcode for EX4B |
| ''' |
| fields: [ |
| { bits: "31" |
| name: "valid" |
| desc: "If 1, Opcode affects" |
| } // f: valid |
| { bits: "7:0" |
| name: "opcode" |
| desc: "EX4B opcode" |
| } // f: opcode |
| ] |
| } // R: CMD_INFO_EX4B |
| { name: "CMD_INFO_WREN" |
| swaccess: "rw" |
| hwaccess: "hro" |
| desc: '''Opcode for Write Enable (WREN) |
| ''' |
| fields: [ |
| { bits: "31" |
| name: "valid" |
| desc: "If 1, opcode affects" |
| } // f: valid |
| { bits: "7:0" |
| name: "opcode" |
| desc: "WREN opcode" |
| // Leave default value 0 to be consistent |
| } // f: opcode |
| ] |
| } // R: CMD_INFO_WREN |
| { name: "CMD_INFO_WRDI" |
| swaccess: "rw" |
| hwaccess: "hro" |
| desc: '''Opcode for Write Disable (WRDI) |
| ''' |
| fields: [ |
| { bits: "31" |
| name: "valid" |
| desc: "If 1, opcode affects" |
| } // f: valid |
| { bits: "7:0" |
| name: "opcode" |
| desc: "WRDI opcode" |
| // Leave default value 0 to be consistent |
| } // f: opcode |
| ] |
| } // R: CMD_INFO_WRDI |
| |
| //=============================================================== |
| // TPM registers |
| { skipto: "0x800"} |
| { name: "TPM_CAP" |
| desc: '''TPM HWIP Capability register. |
| |
| This register shows the features the current TPM HWIP supports. |
| ''' |
| swaccess: "ro" |
| hwaccess: "hwo" |
| fields: [ |
| { bits: "7:0" |
| name: "rev" |
| desc: "Revision of the TPM submodule" |
| resval: "0" |
| } // f: rev |
| { bits: "8" |
| name: "locality" |
| desc: '''If 1, the TPM submodule supports 5 Locality. |
| If 0, only one Locality is provided |
| ''' |
| resval: "1" |
| } // f: locality |
| { bits: "18:16" |
| name: "max_wr_size" |
| desc: '''The maximum write size in bytes the TPM submodule supports. |
| The value is the exponent of the 2. |
| |
| - 3'b 010: Support up to 4B |
| - 3'b 011: Support up to 8B |
| - 3'b 100: Support up to 16B |
| - 3'b 101: Support up to 32B |
| - 3'b 110: Support up to 64B |
| |
| All other values are reserved. |
| |
| It is not recommended for SW to advertise TPM supporting more than `max_wr_size` to the South Bridge. |
| ''' |
| resval: "6" |
| } // f: max_wr_size |
| { bits: "22:20" |
| name: "max_rd_size" |
| desc: '''The maximum read size in bytes the TPM submodule supports. |
| The value is the exponent of the 2. |
| |
| - 3'b 010: Support up to 4B |
| - 3'b 011: Support up to 8B |
| - 3'b 100: Support up to 16B |
| - 3'b 101: Support up to 32B |
| - 3'b 110: Support up to 64B |
| |
| All other values are reserved. |
| |
| It is not recommended for SW to advertise TPM supporting more than `max_rd_size` to the South Bridge. |
| ''' |
| resval: "6" |
| } // f: max_rd_size |
| ] |
| } // R: TPM_CAP |
| { name: "TPM_CFG" |
| desc: '''TPM Configuration register. |
| ''' |
| swaccess: "rw" |
| hwaccess: "hro" |
| fields: [ |
| { bits: "0" |
| name: "en" |
| desc: "If 1, TPM submodule accepts the transactions over SPI" |
| tags: [ |
| // Enabling TPM could cause an assertion error if CSB isn't disabled properly in chip-level |
| "excl:CsrNonInitTests:CsrExclWrite"] |
| } // f: en |
| { bits: "1" |
| name: "tpm_mode" |
| desc: '''Configure the TPM mode. 1 for CRB, 0 for FIFO. |
| |
| If the SW set this field to 1, the HW logic always pushes the |
| command/addr and write data to buffers. The logic does not compare |
| the incoming address to the list of managed-by-HW register |
| addresses. |
| |
| The invalid locality check still runs based on the invalid_locality |
| configuration. |
| ''' |
| } // f: tpm_mode |
| { bits: "2" |
| name: "hw_reg_dis" |
| desc: '''If 0, TPM submodule directly returns the return-by-HW registers for the read requests. |
| |
| If 1, TPM submodule uploads the TPM command regardless of the address, and the SW may return the value through the read FIFO. |
| ''' |
| } // f: hw_reg_dis |
| { bits: "3" |
| name: "tpm_reg_chk_dis" |
| desc: '''If 1, the logic does not compare the upper 8 bit of the |
| received address with the TpmAddr constant, D4h. |
| |
| If this field is 0, the HW uploads the command, address, and write |
| payload to the buffers in case of address that is not 0xD4_XXXX. |
| ''' |
| } // f: tpm_reg_chk_dis |
| { bits: "4" |
| name: "invalid_locality" |
| desc: '''If 1, TPM submodule returns the invalid data (0xFF) for the |
| out of the max Locality request. |
| If it is a write request, HW still uploads the command and address. |
| SW needs to process the incoming invalid command. |
| |
| If 0, TPM submodule uploads the TPM command and address. The SW may |
| write 0xFF to the read FIFO. |
| |
| Note: The TPM submodule uploads the TPM commands that do not fall |
| into the FIFO registers (0xD4_XXXX) regardless of |
| `invalid_locality` bit. |
| ''' |
| } // f: invalid_locality |
| ] |
| } // R: TPM_CFG |
| { name: "TPM_STATUS" |
| desc: '''TPM submodule state register. |
| |
| The TPM_STATUS CSR provides the current TPM status, mostly the buffer and FIFO status. |
| ''' |
| swaccess: "ro" |
| hwaccess: "hwo" |
| fields: [ |
| { bits: "0" |
| name: "cmdaddr_notempty" |
| desc: "If 1, the TPM_CMD_ADDR has a valid data. This status is reported via the interrupt also." |
| } // f: cmdaddr_notempty |
| { bits: "15+TpmWrFifoPtrW:16" |
| name: "wrfifo_depth" |
| desc: "This field represents the current write FIFO depth." |
| } // f: wrfifo_depth |
| ] |
| } // R: TPM_STATUS |
| { multireg: { |
| cname: "TPM" |
| name: "TPM_ACCESS" |
| desc: '''TPM_ACCESS_x register. |
| ''' |
| count: "NumLocality" |
| compact: true |
| swaccess: "rw" |
| hwaccess: "hro" |
| fields: [ |
| { bits: "7:0" |
| name: "access" |
| desc: "TPM_ACCESS" |
| } |
| ] |
| }} // mr: TPM_ACCESS |
| { name: "TPM_STS" |
| desc: '''TPM_STS_x register. |
| |
| The register is mirrored to all Localities. |
| The value is returned to the host system only when the activeLocality |
| in the TPM_ACCESS_x is matched to the current received Locality. |
| ''' |
| swaccess: "rw" |
| hwaccess: "hro" |
| fields: [ |
| { bits: "31:0" |
| name: "sts" |
| desc: "TPM_STS_x" |
| } |
| ] |
| } // R: TPM_STS |
| { name: "TPM_INTF_CAPABILITY" |
| desc: "TPM_INTF_CAPABILITY" |
| swaccess: "rw" |
| hwaccess: "hro" |
| fields: [ |
| { bits: "31:0" |
| name: "intf_capability" |
| desc: "TPM_INTF_CAPABILITY" |
| } |
| ] |
| } // R: TPM_INTF_CAPABILITY |
| { name: "TPM_INT_ENABLE" |
| desc: "TPM_INT_ENABLE" |
| swaccess: "rw" |
| hwaccess: "hro" |
| fields: [ |
| { bits: "31:0" |
| name: "int_enable" |
| desc: "TPM_INT_ENABLE" |
| } |
| ] |
| } // R: TPM_INT_ENABLE |
| { name: "TPM_INT_VECTOR" |
| desc: "TPM_INT_VECTOR" |
| swaccess: "rw" |
| hwaccess: "hro" |
| fields: [ |
| { bits: "7:0" |
| name: "int_vector" |
| desc: "TPM_INT_VECTOR" |
| } |
| ] |
| } // R: TPM_INT_VECTOR |
| { name: "TPM_INT_STATUS" |
| desc: "TPM_INT_STATUS" |
| swaccess: "rw" |
| hwaccess: "hro" |
| fields: [ |
| { bits: "31:0" |
| name: "int_status" |
| desc: "TPM_INT_STATUS" |
| } |
| ] |
| } // R: TPM_INT_STATUS |
| { name: "TPM_DID_VID" |
| desc: "TPM_DID/ TPM_VID register" |
| swaccess: "rw" |
| hwaccess: "hro" |
| fields: [ |
| { bits: "15:0" |
| name: "vid" |
| desc: "TPM_VID" |
| } // f: vid |
| { bits: "31:16" |
| name: "did" |
| desc: "TPM_DID" |
| } // f: did |
| ] |
| } // R: TPM_DID_VID |
| { name: "TPM_RID" |
| desc: "TPM_RID" |
| swaccess: "rw" |
| hwaccess: "hro" |
| fields: [ |
| { bits: "7:0" |
| name: "rid" |
| desc: "TPM_RID" |
| } |
| ] |
| } // R: TPM_RID |
| { name: "TPM_CMD_ADDR" |
| desc: '''TPM Command and Address buffer |
| |
| The SW may get the received TPM command and address by readin gthis CSR. |
| ''' |
| swaccess: "ro" |
| hwaccess: "hrw" |
| hwext: "true" |
| hwre: "true" |
| hwqe: "true" |
| fields: [ |
| { bits: "23:0" |
| name: "addr" |
| desc: "received address" |
| } // f: addr |
| { bits: "31:24" |
| name: "cmd" |
| desc: "received command" |
| } // f: cmd |
| ] |
| } // R: TPM_CMD_ADDR |
| { name: "TPM_READ_FIFO" |
| desc: '''TPM Read command return data FIFO. |
| |
| The write port of the read command FIFO. |
| ''' |
| swaccess: "wo" |
| hwaccess: "hro" |
| hwqe: "true" |
| hwext: "true" |
| fields: [ |
| { bits: "TpmRdFifoWidth-1:0" |
| name: "value" |
| desc: "write port of the read FIFO" |
| } |
| ] |
| tags: [// Updating FIFO randomly can result in tpm_status value change |
| "excl:CsrNonInitTests:CsrExclWrite"] |
| } // R: TPM_READ_FIFO |
| { name: "TPM_WRITE_FIFO" |
| desc: '''TPM Write command received data FIFO. |
| ''' |
| swaccess: "ro" |
| hwaccess: "hrw" |
| hwext: "true" |
| hwqe: "true" |
| hwre: "true" |
| fields: [ |
| { bits: "7:0" |
| name: "value" |
| desc: "Read only port of the write FIFO" |
| } |
| ] |
| } // R: TPM_WRITE_FIFO |
| //--------------------------------------------------------------- |
| { 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 256B SFDP |
| buffer, 32B of CmdFIFO, 32B of AddrFIFO, and 256B of payload FIFO. |
| ''' |
| }, |
| }, |
| ] |
| } |