Skip to content

Commit da2a35d

Browse files
committed
[ot] hw/opentitan: ot_spi_host: create GPIOs & method for Passthrough
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 <[email protected]>
1 parent 0dc9276 commit da2a35d

File tree

2 files changed

+80
-9
lines changed

2 files changed

+80
-9
lines changed

hw/opentitan/ot_spi_host.c

Lines changed: 68 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,8 @@ typedef struct {
257257
} TraceCache;
258258
#endif /* DISCARD_REPEATED_STATUS_TRACES */
259259

260+
#define SPI_DEFAULT_TX_VALUE ((uint8_t)0xffu)
261+
260262
/* ------------------------------------------------------------------------ */
261263
/* Types */
262264
/* ------------------------------------------------------------------------ */
@@ -324,26 +326,22 @@ typedef struct {
324326
unsigned size;
325327
} OtSPIHostCmd;
326328

327-
/* this class is only required to manage on-hold reset */
328-
struct OtSPIHostClass {
329-
SysBusDeviceClass parent_class;
330-
ResettablePhases parent_phases;
331-
};
332-
333329
struct OtSPIHostState {
334330
SysBusDevice parent_obj;
335331

336332
MemoryRegion mmio;
337333

338334
qemu_irq *cs_lines; /* CS output lines */
339335
SSIBus *ssi; /* SPI bus */
336+
bool passthrough_en; /* Upstream SPI Device Passthrough enable line */
340337

341338
uint32_t *regs; /* Registers (except. fifos) */
342339

343340
RxFifo *rx_fifo;
344341
TxFifo *tx_fifo;
345342
CmdFifo *cmd_fifo;
346343

344+
347345
QEMUTimer *fsm_delay; /* Simulate delayed SPI transfer completion */
348346

349347
IbexIRQ irqs[2u]; /* System bus IRQs */
@@ -829,10 +827,11 @@ static void ot_spi_host_step_fsm(OtSPIHostState *s, const char *cause)
829827
ot_spi_host_chip_select(s, s->active.cmd.cs, s->fsm.transaction);
830828
}
831829

832-
uint8_t tx =
833-
write ? (uint8_t)txfifo_pop(s->tx_fifo, length == 1u) : 0xffu;
830+
uint8_t tx = write ? (uint8_t)txfifo_pop(s->tx_fifo, length == 1u) :
831+
SPI_DEFAULT_TX_VALUE;
834832

835-
uint8_t rx = s->fsm.output_en ? ssi_transfer(s->ssi, tx) : 0xffu;
833+
uint8_t rx =
834+
s->fsm.output_en ? ssi_transfer(s->ssi, tx) : SPI_DEFAULT_TX_VALUE;
836835

837836
if (multi && read && write) {
838837
/* invalid command, lets corrupt input data */
@@ -1293,6 +1292,61 @@ static void ot_spi_host_io_write(void *opaque, hwaddr addr, uint64_t val64,
12931292
}
12941293
}
12951294

1295+
static uint8_t ot_spi_host_downstream_transfer(OtSPIHostState *s, uint8_t tx)
1296+
{
1297+
/* Passthrough is not implemented if SPI Host has more than one CS line */
1298+
if (s->num_cs != 1) {
1299+
return SPI_DEFAULT_TX_VALUE;
1300+
}
1301+
1302+
if (!s->passthrough_en) {
1303+
return SPI_DEFAULT_TX_VALUE;
1304+
}
1305+
1306+
/* Forward to downstream flash */
1307+
return (uint8_t)ssi_transfer(s->ssi, (uint32_t)tx);
1308+
}
1309+
1310+
static void
1311+
ot_spi_host_device_passthrough_en_input(void *opaque, int irq, int level)
1312+
{
1313+
OtSPIHostState *s = opaque;
1314+
(void)irq;
1315+
1316+
/* Passthrough is not implemented if SPI Host has more than one CS line */
1317+
if (s->num_cs != 1) {
1318+
return;
1319+
}
1320+
1321+
s->passthrough_en = (bool)level;
1322+
1323+
/*
1324+
* Real HW muxes the CS line based on Passthrough Enable, but it doesn't
1325+
* make sense for a transfer to be handled by both SPI Host and SPI Device,
1326+
* so we just deassert CS on any change.
1327+
*/
1328+
qemu_irq_raise(s->cs_lines[0]);
1329+
}
1330+
1331+
static void
1332+
ot_spi_host_device_passthrough_cs_input(void *opaque, int irq, int level)
1333+
{
1334+
OtSPIHostState *s = opaque;
1335+
(void)irq;
1336+
1337+
/* Passthrough is not implemented if SPI Host has more than one CS line */
1338+
if (s->num_cs != 1) {
1339+
return;
1340+
}
1341+
1342+
if (!s->passthrough_en) {
1343+
return;
1344+
}
1345+
1346+
/* Passthrough enabled, SPI Device is driving this CS */
1347+
qemu_set_irq(s->cs_lines[0], level);
1348+
}
1349+
12961350
/* ------------------------------------------------------------------------ */
12971351
/* Device description/instanciation */
12981352
/* ------------------------------------------------------------------------ */
@@ -1390,6 +1444,11 @@ static void ot_spi_host_realize(DeviceState *dev, Error **errp)
13901444
(int)s->num_cs);
13911445
qdev_init_gpio_in_named(DEVICE(s), &ot_spi_host_clock_input, "clock-in", 1);
13921446

1447+
qdev_init_gpio_in_named(DEVICE(s), &ot_spi_host_device_passthrough_en_input,
1448+
"passthrough-en", 1);
1449+
qdev_init_gpio_in_named(DEVICE(s), &ot_spi_host_device_passthrough_cs_input,
1450+
"passthrough-cs", 1);
1451+
13931452
char busname[16u];
13941453
if (snprintf(busname, sizeof(busname), "spi%u", s->bus_num) >=
13951454
sizeof(busname)) {

include/hw/opentitan/ot_spi_host.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,23 @@
3131
#ifndef HW_OPENTITAN_OT_SPI_HOST_H
3232
#define HW_OPENTITAN_OT_SPI_HOST_H
3333

34+
#include "qemu/osdep.h"
3435
#include "qom/object.h"
36+
#include "hw/resettable.h"
37+
#include "hw/sysbus.h"
3538

3639
#define TYPE_OT_SPI_HOST "ot-spi_host"
3740
OBJECT_DECLARE_TYPE(OtSPIHostState, OtSPIHostClass, OT_SPI_HOST)
3841

42+
/* this class is only required to manage on-hold reset */
43+
struct OtSPIHostClass {
44+
SysBusDeviceClass parent_class;
45+
46+
uint8_t (*downstream_transfer)(OtSPIHostState *, uint8_t);
47+
48+
ResettablePhases parent_phases;
49+
};
50+
3951
/* Supported SPI Host versions */
4052
typedef enum {
4153
OT_SPI_HOST_VERSION_EG_1_0_0,

0 commit comments

Comments
 (0)