-
Notifications
You must be signed in to change notification settings - Fork 13
[WIP] ot_spi_device,ot_spi_host: Refactoring + Passthrough mode implementation
#255
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: ot-9.2.0
Are you sure you want to change the base?
[WIP] ot_spi_device,ot_spi_host: Refactoring + Passthrough mode implementation
#255
Conversation
b7c3b04 to
2e2300b
Compare
2264c77 to
f1a68a2
Compare
| bool loop; /* Keep reading the buffer if end is reached */ | ||
| bool watermark; /* Read watermark hit, used as flip-flop */ | ||
| bool new_cmd; /* New command has been pushed in current SPI transaction */ | ||
| bool cmd_addr_swap_en; /* Passthrough mode - address swap enabled */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe group all the passthrough related value into a structure. (cmd....?)
This would also to clear the whole thing at once in ot_spi_device_passthrough_unmatched_command_params
f1a68a2 to
6e8f034
Compare
e8ef6d7 to
ad5c39c
Compare
ot_spi_device: Refactoring + Passthrough mode implementationot_spi_device,ot_spi_host: Refactoring + Passthrough mode implementation
This commit simplifies command slot definitions and the associated state and control flow. The HW CFG and the HW STA commands have been combined into just HW commands, as in flash mode they are handled in hardware by some way and should therefore share the same data path. For passthrough mode, a subset of these HW commands can be intercepted (all except for WREN and WRDI). As the matched command slot number determines whether the command is a SW or HW command, the `OtSpiFlashCommand` enum has been removed in favour of using `is_sw_command` to return the boolean. Command slot matching has been brought out into its own function, `match_command_slot`, which returns whether an opcode was matched in the command info registers. The decoded slot number is only valid if this returns true. Also a bug is fixed in `ot_spi_device_exec_command` where hardcoded opcodes for read commands were used instead of the opcodes in the associated command slot. Signed-off-by: Alice Ziuziakowska <a.ziuziakowska@lowrisc.org>
Signed-off-by: Alice Ziuziakowska <a.ziuziakowska@lowrisc.org>
... and removes `OtSpiDeviceAddrMode`. `ot_spi_device_get_command_address_size` now returns the size of the address field in the current command, using the value in `cmd_info` and the current 4B enable state. Signed-off-by: Alice Ziuziakowska <a.ziuziakowska@lowrisc.org>
Signed-off-by: Alice Ziuziakowska <a.ziuziakowska@lowrisc.org>
See https://opentitan.org/book/hw/ip/spi_host/doc/theory_of_operation.html#pass-through-mode This commit adds the `passthrough-en` and `passthrough-cs` pins for controlling Passthrough mode behaviour. When `passthrough_en` is asserted (i.e, the upstream OT SPI Device is in Flash Passthrough mode), OT SPI Host is bypassed entirely and OT SPI Device controls the transfers on the SPI bus. This passthrough behaviour is only implemented in OT SPI Host if there is only a single CS pin. See RTL: `spi_host.sv:100` When in Passthrough mode, OT SPI Device can call into the new method `downstream_transfer` to perform SPI transfers. Signed-off-by: Alice Ziuziakowska <a.ziuziakowska@lowrisc.org>
Signed-off-by: Alice Ziuziakowska <a.ziuziakowska@lowrisc.org>
Signed-off-by: Alice Ziuziakowska <a.ziuziakowska@lowrisc.org>
This commit implements the Passthrough mode on SPI Device. Passthrough mode allows the device to act as a proxy for a downstream flash device, optionally intercepting commands to send back its own values, filtering commands sent downstream, or transparently translating address and payload bytes. This also "implements" the Disabled mode, which discards all bytes sent to the device. Signed-off-by: Alice Ziuziakowska <a.ziuziakowska@lowrisc.org>
Signed-off-by: Alice Ziuziakowska <a.ziuziakowska@lowrisc.org>
ca61a08 to
28ffc3c
Compare
|
I have discovered that OT SPI Device is not the only device controlling this SPI bus, the bus is actually shared by OT SPI Host 0 in Earlgrey, and OT SPI Host is bypassed entirely when Passthrough mode is enabled. This seems to only be documented here. As such this PR has been reworked a bit. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
quick review.
|
|
||
| qemu_irq *cs_lines; /* CS output lines */ | ||
| SSIBus *ssi; /* SPI bus */ | ||
| bool passthrough_en; /* Upstream SPI Device Passthrough enable line */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit pick: move it close to on_reset to avoid creating 7 byte padding.
| TxFifo *tx_fifo; | ||
| CmdFifo *cmd_fifo; | ||
|
|
||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
extra empty line added
|
|
||
| uint8_t rx = s->fsm.output_en ? ssi_transfer(s->ssi, tx) : 0xffu; | ||
| uint8_t rx = | ||
| s->fsm.output_en ? ssi_transfer(s->ssi, tx) : SPI_DEFAULT_TX_VALUE; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You need to rename the constant w/o "TX" if you want to use is as RX :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would have expected the SPI host output to be disabled when passthrough_en is true (?)
| ot_spi_host_device_passthrough_en_input(void *opaque, int irq, int level) | ||
| { | ||
| OtSPIHostState *s = opaque; | ||
| (void)irq; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
need to g_assert against expected value (0)
| (void)irq; | ||
|
|
||
| /* Passthrough is not implemented if SPI Host has more than one CS line */ | ||
| if (s->num_cs != 1) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
1u
need to add a trace in this case.
| OtSPIHostClass *sc = OT_SPI_HOST_CLASS(klass); | ||
| sc->downstream_transfer = &ot_spi_host_downstream_transfer; | ||
|
|
||
| ResettableClass *rc = RESETTABLE_CLASS(klass); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
BTW passthrough_* should be reset in reset_enter
| static uint8_t ot_spi_host_downstream_transfer(OtSPIHostState *s, uint8_t tx) | ||
| { | ||
| /* Passthrough is not implemented if SPI Host has more than one CS line */ | ||
| if (s->num_cs != 1) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit pick: 1u
| g_assert(s->ot_id); | ||
|
|
||
| /* CS is active low, Passthrough enable is active high */ | ||
| ibex_qdev_init_irq_default(OBJECT(s), &s->passthrough_cs, "passthrough-cs", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same note as for the other side, needs to be a public constant, and used to connect lines in the machine
| { | ||
| if (s->spihost) { | ||
| OtSPIHostClass *spihostc = | ||
| OBJECT_GET_CLASS(OtSPIHostClass, s->spihost, TYPE_OT_SPI_HOST); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
more idiomatic:
OtSPIHostClass *spihostc = OT_SPI_HOST_GET_CLASS(s->sphihost);
|
|
||
| static uint8_t ot_spi_device_flash_spi_transfer(OtSPIDeviceState *s, uint8_t rx) | ||
| { | ||
| if (s->spihost) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If a SPI Device can exist w/o a SPI host, I think this should be signal as an GUEST_ERROR when passthough is enable, and may discarded before reaching this point? If not, there should be a trace here.
This PR implements the Passthrough mode for OT SPI Device and any required changes in OT SPI Host. Passthrough mode allows for external SPI transfers to be passed through to a downstream device, and optionally intercepted or modified by OT SPI Device.
In HW, OT SPI Device and OT SPI Host are linked by their SPI bus and a wire that represents whether the Device is in Passthrough mode. If Passthrough mode is enabled, the SPI Host is entirely bypassed and SPI Device has full control over the bus, which it uses to talk to the same downstream flash as SPI Host. See Documentation reference, RTL.
This passthrough mechanism is only implemented by OT SPI Host if it has one CS line: RTL
The structure of the PR is as follows:
ot_spi_devicefor the Passthrough implementation.ot_spi_host- two GPIOs are used to communicate Passthrough enabled and the Chip Select as driven by OT SPI Device, OT SPI Device and OT SPI Host are then linked together.ot_spi_device.I have tried to handle most corner-cases I can think of, but some conflicting configuration options might not behave as expected.
The two-stage read pipeline is not yet implemented - we model all transfers as though they are over a single wire, so this would only be used to buffer all read payload bytes by two over the wire for correctness.