blob: 3411433e80cb981df54a203c91df7c52ae495367 [file] [log] [blame]
// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
{ name: "spi_host",
clock_primary: "clk_i",
other_clock_list: [ "clk_core_i" ],
reset_primary: "rst_ni",
other_reset_list: [ "rst_core_ni" ],
bus_device: "tlul",
bus_host: "none",
regwidth: "32",
scan: "true",
param_list: [
{ name: "ByteOrder",
desc: '''Byte order to use when transmitting or receiving data. If ByteOrder = 0,
the IP uses a Big-Endian ordering for the bytes in TXDATA and RXDATA.
The most significant byte (MSB) of TXDATA is transmitted first, and
received data is placed in the MSB location of RXDATA. If ByteOrder = 1,
a Little-Endian ordering is used for these registers, and the LSB of each
gets priority for receiving and transmitting data.'''
type: "int",
default: "0"
},
{ name: "MaxCS",
desc: "The number of active-low chip select (cs_n) lines to create.",
type: "int",
default: "1"
},
],
available_output_list: [
{ name: "sck"
desc: "SPI Clock"
},
{ name: "csb"
desc: '''Chip Select# (One hot, active low). The size of this port should match MaxCS.'''
width: "1"
}
],
available_inout_list: [
{ name: "sd",
desc: "SPI data bus",
width: "4"
},
],
interrupt_list: [
{ name: "error",
desc: '''Error-related interrupts, see !!ERROR_ENABLE register for more
information.'''
},
{ name: "spi_event",
desc: '''Event-related interrupts, see !!EVENT_ENABLE register for more
information.'''
}
],
registers: [
{ name: "CONTROL",
desc: "Control register",
swaccess: "rw",
hwaccess: "hro",
fields: [
{ bits: "31",
name: "SPIEN",
desc: '''Enables the SPI host. On reset, this field is 0, meaning
that no transactions can proceed.'''
resval: "0x0"
},
{ bits: "30",
name: "RST_FSM",
desc: '''Holds the control FSM in reset when set to 1. (Must be
explicitly cleared again before commands can be issued.)'''
resval: "0x0",
},
{ bits: "29",
name: "RST_TXFIFO",
desc: '''Holds the TX FIFO in reset when set to 1. (Must be explicitly
cleared again before using the TX FIFO.)'''
resval: "0x0",
},
{ bits: "28",
name: "RST_RXFIFO",
desc: '''Holds the RX FIFO in reset when set to 1. (Must be explicitly
cleared again before using the RX FIFO.)'''
resval: "0x0"
},
{ bits: "27",
name: "PASSTHRU",
desc: '''Enables Pass-through mode, wherein the SPI_HOST IP surrenders
control of the SPI bus to another block. In this mode the
`sck`, `cs_n` and `sd` signals are no longer driven by
the SPI_HOST IP, rather they are multiplexed out to match the
on-chip inputs `pt_sck_i`, `pt_cs_n_i`, `pt_sden_i`, `pt_sdo_i`,
and `pt_sdi_o`. (Since the `sd` bus is bidirectional, there are
separate input, output and tri-state controls for this bus.)''',
resval: "0x0"
},
{ bits: "24:16",
name: "TX_WATERMARK"
desc: '''If !!EVENT_ENABLE.TXWM is set, the IP will send
an interrupt when the depth of the RX FIFO drops below
TX_WATERMARK words (32b each).'''
resval: "0"
},
{ bits: "15:9",
name: "RX_WATERMARK"
desc: '''If !!EVENT_ENABLE.RXWM is set, the IP will send
an interrupt when the depth of the RX FIFO reaches
RX_WATERMARK words (32b each).'''
resval: "127"
},
{ bits: "8",
name: "MANCS_EN",
desc: '''Enable Manual Chip Select. Typically each command
manages the CS lines automatically, issuing a command
to exactly one device, and lowering and raising the
appropriate CS line after transmitting or receiving the
necessary bytes. Asserting this bit overrides this
automatic selection, instead setting the CS lines to
reflect the contents of the !!CONTROL.MANUAL_CS field.'''
resval: "0x0"
},
{ bits: "7:0",
name: "MANUAL_CS"
desc: '''When !!CONTROL.MANCS_EN = 1, the cs_n lines are tied directly to the
value of MANUAL_CS.'''
resval: 0
}
]
},
{ name: "STATUS",
desc: "Status register",
swaccess: "ro",
hwaccess: "hwo",
fields: [
{ bits: "31",
name: "READY",
desc: '''When high, indicates the SPI host is ready to receive
commands. Writing a one to !!COMMAND_0.GO when READY is low is
an error, and will trigger an interrupt.
''',
resval: "0x0"
},
{ bits: "30",
name: "ACTIVE",
desc: '''When high, indicates the SPI host is processing a previously
issued command.'''
resval: "0x0"
},
{ bits: "29",
name: "TXFULL",
desc: '''When high, indicates that the transmit data fifo is full.
Any further writes to !!TXDATA will create an error interrupt.
'''
resval: "0x0"
},
{ bits: "28",
name: "TXEMPTY",
desc: '''When high, indicates that the transmit data fifo is empty.
'''
resval: "0x0"
},
{ bits: "27"
name: "TXSTALL",
desc: '''If high, signifies that an ongoing transaction has stalled
due to lack of data in the TX FIFO''',
resval: "0x0"
},
{ bits: "26",
name: "TXWM",
desc: '''If high, the amount of data in the TX FIFO has fallen below the
level of !!CONTROL.TX_WATERMARK words (32b each).'''
resval: "0x0"
},
{ bits: "25",
name: "RXFULL",
desc: '''When high, indicates that the receive fifo is full. Any
ongoing transactions will stall until firmware reads some
data from !!RXDATA.'''
resval: "0x0"
},
{ bits: "24",
name: "RXEMPTY",
desc: '''When high, indicates that the receive fifo is empty.
Any reads from RX FIFO will cause an error interrupt.
'''
resval: "0x0"
},
{ bits: "23",
name: "RXSTALL",
desc: '''If high, signifies that an ongoing transaction has stalled
due to lack of available space in the RX FIFO''',
resval: "0x0"
},
{ bits: "22",
name: "BYTEORDER",
desc: '''The value of the ByteOrder parameter, provided so that firmware
can confirm proper IP configuration.'''
}
{ bits: "20",
name: "RXWM",
desc: '''If high, the number of 32-bits in the RX FIFO now exceeds the
!!CONTROL.RX_WATERMARK entries (32b each).'''
resval: "0x0"
},
{ bits: "17:9",
name: "RXQD",
desc: '''Receive queue depth. Indicates how many unread entries are currently in the
RX FIFO. When active, this result may an underestimate due
to synchronization delays.
''',
resval: "0x0"
},
{ bits: "8:0",
name: "TXQD",
desc: '''Transmit queue depth. Indicates how many unsent entries are currently
in the TX FIFO. When active, this result may be an
over-estimate due to synchronization delays,
''',
resval: "0x0"
}
]
},
{ multireg: { name: "CONFIGOPTS",
desc: '''Configuration options register.
Contains options for controlling each peripheral. One register per
cs_n line''',
swaccess: "rw",
hwaccess: "hro",
cname: "configopts",
count: "MaxCS",
fields: [
{ bits: "31",
name: "CPOL",
desc: '''The polarity of the sck clock signal. When CPOL is 0,
sck is low when idle, and emits high pulses. When CPOL
is low, sck is high when idle, and emits a series of low
pulses.
'''
resval: "0x0"
},
{ bits: "30",
name: "CPHA",
desc: '''The phase of the sck clock signal relative to the data. When
CPHA = 0, the data changes on the trailing edge of sck
and is typically sampled on the leading edge. Conversely
if CPHA = 1 high, data lines change on the leading edge of
sck and are typically sampled on the trailing edge.
CPHA should be chosen to match the phase of the selected
device. The sampling behavior is modified by the
!!CONFIGOPTS_0.FULLCYC bit.
''',
resval: "0x0"
},
{ bits: "29",
name: "FULLCYC",
desc: '''Full cycle. Modifies the CPHA sampling behaviour to allow
for longer device logic setup times. Rather than sampling the SD
bus a half cycle after shifting out data, the data is sampled
a full cycle after shifting data out. This means that if
CPHA = 0, data is shifted out on the trailing edge, and
sampled a full cycle later. If CPHA = 1, data is shifted and
sampled with the trailing edge, also separated by a
full cycle.''',
resval: 0
},
{ bits: "28",
name: "CSAAT",
desc: '''Chip select active after transaction. If CSAAT = 0, the
chip select line is raised immediately at the end of the
transaction. If CSAAT = 1, the chip select line is left
low at the end of the current sequence. This potentially
allows for the creation of longer or otherwise more
complex sequences.'''
resval: "0x0"
},
{ bits: "27:24",
name: "CSNLEAD",
desc: '''CS_N Leading Time. Indicates the number of half sck cycles,
CSNLEAD+1, to leave between the falling edge of cs_n and
the first edge of sck. Setting this register to zero
corresponds to the minimum delay of one-half sck cycle'''
resval: 0
},
{ bits: "23:20",
name: "CSNTRAIL"
desc: '''CS_N Trailing Time. Indicates the number of half sck cycles,
CSNTRAIL+1, to leave between last edge of sck and the rising
edge of cs_n. Setting this register to zero corresponds
to the minimum delay of one-half sck cycle.'''
resval: 0
},
{ bits: "19:16",
name: "CSNIDLE"
desc: '''Minimum idle time between commands. Indicates the minimum
number of sck half-cycles to hold cs_n high between commands.
Setting this register to zero creates a minimally-wide CS_N-high
pulse of one-half sck cycle.'''
resval: 0
},
{ bits: "15:0",
name: "CLKDIV",
desc: '''Core clock divider. Slows down subsequent SPI transactions by a
factor of (CLKDIV+1) relative to the core clock frequency. The
period of sck, T(sck) then becomes `2*(CLK_DIV+1)*T(core)`'''
resval: 0
},
]
}
},
{ multireg: { name: "COMMAND",
desc: '''Command Register
Parameters specific to each command. One register per cs_n line''',
swaccess: "rw",
hwaccess: "hro",
hwqe: "true",
cname: "command",
count: "MaxCS",
fields: [
{ bits: "3:0",
name: "TX1_CNT",
desc: '''The number of 1-byte bursts to transmit in this command,
at the single-line data width (8 sck clocks per cycle).
All other data lines are high-Z during this command phase.
This field is ignored in full-duplex standard-mode
(i.e. when !!COMMAND_0.FULLDPLX = 1 and !!COMMAND_0.SPEED = 0).
''',
resval: "0x0"
},
{ bits: "12:4",
name: "TXN_CNT",
desc: '''The number of 1-byte bursts to transmit in this command,
at the full-data width (Determined by the !!COMMAND_0.SPEED
field).
''',
resval: "0x0"
},
{ bits: "16:13",
name: "DUMMY_CYCLES",
desc: '''Controls the number of sck dummy cycles inserted between
end of the last TX byte and the beginning of the first RX
byte. No data is transmitted or received and all outputs
are high-Z during this command phase.
This field is ignored in full-duplex standard-mode
(i.e. when !!COMMAND_0.FULLDPLX = 1 and !!COMMAND_0.SPEED = 0).
''',
resval: "0x0"
},
{ bits: "25:17",
name: "RX_CNT",
desc: '''In Dual or Quad mode, this is the number of 1-byte bursts
to receive in this command.
This field is ignored in full-duplex standard-mode
(i.e. when !!COMMAND_0.FULLDPLX = 1 and !!COMMAND_0.SPEED = 0).
''',
resval: "0x0"
},
{ bits: "26",
name: "FULLDPLX",
desc: '''Allows full-duplex operation for this command. In full-duplex
mode, !!COMMAND_0.TXN_CNT bytes are transmitted on 'sd[0]' and
and the same number of bytes are received on 'sd[1]'. This
flag only applies if !!COMMAND_0.SPEED = 0.''',
resval: "0x0"
},
{ bits: "27",
name: "HIGHZ",
desc: '''Forces high-impendance when not transmitting. Typically Standard
Mode commands exclusively transmit on sd[0], and receive on sd[1].
The sd[1] line is always high-impedance, but for half-duplex commands
the sd[0] line is typically held low during dummy and receive cycles.
This bit forces the sd[0] to high-impedance during dummy and receive
cycles.''',
resval: "0x0"
},
{ bits: "30:29",
name: "SPEED",
desc: '''The speed for the following command: "0" = Standard SPI. "1" = Dual SPI.
"2"=Quad SPI, "3": RESERVED.''',
resval: "0x0"
},
{ bits: "31",
name: "GO",
hwaccess: "hrw",
desc: '''Writing a one to this field finalizes the command and submits it to the SPI_HOST core.
This field is self-clearing, so each write to this field only triggers one command.'''
resval: "0x0",
tags: [// Updated by the hw. Exclude from write-checks.
"excl:CsrNonInitTests:CsrExclWriteCheck"]
}
]
}
},
{ window: {
name: "TXDATA",
items: "1",
validbits: "32",
byte-write: "true",
desc: '''SPI Transmit Data.
The serial order of bit transmission
is chosen to match SPI flash devices. Individual bytes
are always transmitted with the most significant bit first.
Multi-byte writes are also supported, and if ByteOrder = 0,
the bits of !!TXDATA are transmitted strictly in order of
decreasing signficance (i.e. most signicant bit first).
For some processor architectures, this could lead to shuffling
of flash data as compared to how it is written in memory.
In which case, choosing ByteOrder = 1 can reverse the
byte-order of multi-byte data writes. (Though within
each byte the most significant bit is always sent first.)
'''
swaccess: "wo",
unusual: "false"
}
},
{ name: "RXDATA",
desc: '''SPI Receive Data.
Received data is expected in the same
order used for the !!TXDATA register. Each individual byte
is expected to arrive most-significant bit first. If
ByteOrder = 0, the first byte received will be transferred to
RXDATA[31:24], and following bytes will be stored in
decreasing byte order. If ByteOrder = 1, incoming bytes will be
stored in the reverse order.''',
swaccess: "ro",
hwaccess: "hwo",
hwext: "true",
fields: [
{ bits: "31:0",
name: "data",
resval: "0x0",
desc: "Data Received"
}
]
},
{ name: "ERROR_ENABLE",
desc: "Controls which classes of errors raise an interrupt."
swaccess: "rw",
hwaccess: "hro",
fields: [
{ bits: "0",
name: "CMDERR",
desc: '''Command Error: If this bit is set, the block sends an error
interrupt whenever a command is issued (i.e. a 1 is
written to COMMAND.GO) while STATUS.READY is
not asserted.''',
resval: "0x1"
},
{ bits: "1",
name: "OVERFLOW",
desc: '''Overflow Errors: If this bit is set, the block sends an
error interrupt whenever the TX FIFO overflows.'''
resval: "0x1"
},
{ bits: "2",
name: "UNDERFLOW",
desc: '''Underflow Errors: If this bit is set, the block sends an
error interrupt whenever there is a read from !!RXDATA
but the RX FIFO is empty.'''
resval: "0x1"
},
]
},
{ name: "ERROR_STATUS",
desc: '''Indicates that any errors that have occurred.
When an error
occurs, the corresponding bit must be cleared here before
issuing any further commands.'''
swaccess: "rw1c",
hwaccess: "hwo",
fields: [
{ bits: "0",
name: "CMDERR",
desc: '''Indicates a write to !!COMMAND_0.GO when
!!STATUS.READY = 0.
'''
resval: "0x0"
},
{ bits: "1",
name: "OVERFLOW",
desc: '''Indicates that firmware has overflowed the TX FIFO'''
resval: "0x0"
},
{ bits: "2",
name: "UNDERFLOW",
desc: '''Indicates that firmware has attempted to read from
!!RXDATA when the RX FIFO is empty.''',
resval: "0x0"
},
]
},
{ name: "EVENT_ENABLE",
desc: "Controls which classes of SPI events raise an interrupt.",
swaccess: "rw",
hwaccess: "hro",
fields: [
{ bits: "2",
name: "RXFULL",
desc: '''Assert to send a spi_event interrupt whenever !!STATUS.RXFULL
goes high''',
resval: "0x0"
},
{ bits: "3",
name: "TXEMPTY",
desc: '''Assert to send a spi_event interrupt whenever !!STATUS.TXEMPTY
goes high''',
resval: "0x0"
},
{ bits: "4",
name: "RXWM",
desc: '''Assert to send a spi_event interrupt whenever the number of 32-bit words in
the RX FIFO is greater than !!CONTROL.RX_WATERMARK. To prevent the
reassertion of this interrupt, read more data from the RX FIFO, or
increase !!CONTROL.RX_WATERMARK.''',
resval: "0x0"
},
{ bits: "5",
name: "TXWM",
desc: '''Assert to send a spi_event interrupt whenever the number of 32-bit words in
the TX FIFO is less than !!CONTROL.TX_WATERMARK. To prevent the
reassertion of this interrupt add more data to the TX FIFO, or
reduce !!CONTROL.TX_WATERMARK.''',
resval: "0x0"
},
{ bits: "6",
name: "READY",
desc: '''Assert to send a spi_event interrupt whenever !!STATUS.READY
goes high''',
resval: "0x0"
},
{ bits: "7",
name: "IDLE",
desc: '''Assert to send a spi_event interrupt whenever !!STATUS.ACTIVE
goes low''',
resval: "0x0"
}
]
}
]
}