Skip to content

Commit c595344

Browse files
committed
[ot] hw/opentitan: ot_spi_host: passthrough mode method and IRQs
This implements a passthrough enable and chip select IRQ and a method to interact with the downstream SPI bus, for use by upstream SPI Device. Signed-off-by: Alice Ziuziakowska <[email protected]>
1 parent e77d018 commit c595344

File tree

3 files changed

+160
-11
lines changed

3 files changed

+160
-11
lines changed

hw/opentitan/ot_spi_host.c

Lines changed: 134 additions & 11 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_RX_VALUE ((uint8_t)0xffu)
261+
260262
/* ------------------------------------------------------------------------ */
261263
/* Types */
262264
/* ------------------------------------------------------------------------ */
@@ -324,12 +326,6 @@ 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

@@ -355,6 +351,16 @@ struct OtSPIHostState {
355351

356352
OtSPIHostFsm fsm;
357353
bool on_reset;
354+
355+
/*
356+
* Upstream SPI Device Passthrough enable and chip select. If we support
357+
* passthrough mode (only one CS), The SPI Host CS is muxed with the
358+
* passthrough CS, controlled by the passthrough enable signal.
359+
*/
360+
bool passthrough_en; /* Upstream SPI Device Passthrough enable line */
361+
bool passthrough_cs; /* Upstream SPI Device Chip Select */
362+
bool host_cs0; /* Our Chip Select 0 */
363+
358364
unsigned pclk; /* Current input clock */
359365
const char *clock_src_name; /* IRQ name once connected */
360366

@@ -524,12 +530,33 @@ static bool ot_spi_host_is_ready(const OtSPIHostState *s)
524530
return !cmdfifo_is_full(s->cmd_fifo);
525531
}
526532

533+
/* Passthrough functionality is only implemented if there is one CS */
534+
static bool ot_spi_host_supports_passthrough(const OtSPIHostState *s)
535+
{
536+
return s->num_cs == 1u;
537+
}
538+
539+
static void ot_spi_host_update_muxed_chip_select(OtSPIHostState *s)
540+
{
541+
if (ot_spi_host_supports_passthrough(s)) {
542+
ibex_irq_set(&s->cs_lines[0],
543+
s->passthrough_en ? s->passthrough_cs : s->host_cs0);
544+
} else {
545+
ibex_irq_set(&s->cs_lines[0], s->host_cs0);
546+
}
547+
}
548+
527549
static void ot_spi_host_chip_select(OtSPIHostState *s, unsigned csid,
528550
bool activate)
529551
{
530552
if (csid < s->num_cs) {
531553
trace_ot_spi_host_cs(s->ot_id, csid, activate ? "" : "de");
532-
ibex_irq_set(&s->cs_lines[csid], !activate);
554+
if (csid == 0u) {
555+
s->host_cs0 = !activate;
556+
ot_spi_host_update_muxed_chip_select(s);
557+
} else {
558+
ibex_irq_set(&s->cs_lines[csid], !activate);
559+
}
533560
}
534561
}
535562

@@ -826,13 +853,31 @@ static void ot_spi_host_step_fsm(OtSPIHostState *s, const char *cause)
826853

827854
if (!s->fsm.transaction) {
828855
s->fsm.transaction = true;
856+
if (ot_spi_host_supports_passthrough(s) && s->active.cmd.cs == 0u &&
857+
s->passthrough_en) {
858+
qemu_log_mask(
859+
LOG_GUEST_ERROR,
860+
"%s: %s: SPI Host active CS while Passthrough is enabled\n",
861+
__func__, s->ot_id);
862+
}
829863
ot_spi_host_chip_select(s, s->active.cmd.cs, s->fsm.transaction);
830864
}
831865

832-
uint8_t tx =
833-
write ? (uint8_t)txfifo_pop(s->tx_fifo, length == 1u) : 0xffu;
866+
uint8_t tx = write ? (uint8_t)txfifo_pop(s->tx_fifo, length == 1u) :
867+
SPI_DEFAULT_TX_RX_VALUE;
834868

835-
uint8_t rx = s->fsm.output_en ? ssi_transfer(s->ssi, tx) : 0xffu;
869+
uint8_t rx = SPI_DEFAULT_TX_RX_VALUE;
870+
871+
if (s->fsm.output_en) {
872+
if (!ot_spi_host_supports_passthrough(s) || !s->passthrough_en) {
873+
rx = (uint8_t)ssi_transfer(s->ssi, tx);
874+
} else {
875+
qemu_log_mask(
876+
LOG_GUEST_ERROR,
877+
"%s: %s: Host transfer while Passthrough is enabled\n",
878+
__func__, s->ot_id);
879+
}
880+
}
836881

837882
if (multi && read && write) {
838883
/* invalid command, lets corrupt input data */
@@ -1293,6 +1338,73 @@ static void ot_spi_host_io_write(void *opaque, hwaddr addr, uint64_t val64,
12931338
}
12941339
}
12951340

1341+
static uint8_t ot_spi_host_downstream_transfer(OtSPIHostState *s, uint8_t tx)
1342+
{
1343+
if (!ot_spi_host_supports_passthrough(s)) {
1344+
qemu_log_mask(
1345+
LOG_GUEST_ERROR,
1346+
"%s: %s: SPI Host does not support passthrough: more than one CS\n",
1347+
__func__, s->ot_id);
1348+
return SPI_DEFAULT_TX_RX_VALUE;
1349+
}
1350+
1351+
if (!s->passthrough_en) {
1352+
trace_ot_spi_host_passthrough_disabled(s->ot_id);
1353+
return SPI_DEFAULT_TX_RX_VALUE;
1354+
}
1355+
1356+
/* Forward to downstream flash */
1357+
return (uint8_t)ssi_transfer(s->ssi, (uint32_t)tx);
1358+
}
1359+
1360+
static void
1361+
ot_spi_host_device_passthrough_en_input(void *opaque, int irq, int level)
1362+
{
1363+
OtSPIHostState *s = opaque;
1364+
g_assert(irq == 0u);
1365+
1366+
if (!ot_spi_host_supports_passthrough(s)) {
1367+
qemu_log_mask(
1368+
LOG_GUEST_ERROR,
1369+
"%s: %s: SPI Host does not support passthrough: more than one CS\n",
1370+
__func__, s->ot_id);
1371+
return;
1372+
}
1373+
1374+
if ((bool)level && !s->host_cs0) {
1375+
qemu_log_mask(LOG_GUEST_ERROR,
1376+
"%s: %s: Passthrough enabled while Host CS is active\n",
1377+
__func__, s->ot_id);
1378+
}
1379+
1380+
s->passthrough_en = (bool)level;
1381+
1382+
ot_spi_host_update_muxed_chip_select(s);
1383+
}
1384+
1385+
static void
1386+
ot_spi_host_device_passthrough_cs_input(void *opaque, int irq, int level)
1387+
{
1388+
OtSPIHostState *s = opaque;
1389+
g_assert(irq == 0u);
1390+
1391+
if (!ot_spi_host_supports_passthrough(s)) {
1392+
qemu_log_mask(
1393+
LOG_GUEST_ERROR,
1394+
"%s: %s: SPI Host does not support passthrough: more than one CS\n",
1395+
__func__, s->ot_id);
1396+
return;
1397+
}
1398+
1399+
if (!s->passthrough_en) {
1400+
trace_ot_spi_host_passthrough_disabled(s->ot_id);
1401+
}
1402+
1403+
s->passthrough_cs = (bool)level;
1404+
1405+
ot_spi_host_update_muxed_chip_select(s);
1406+
}
1407+
12961408
/* ------------------------------------------------------------------------ */
12971409
/* Device description/instanciation */
12981410
/* ------------------------------------------------------------------------ */
@@ -1347,6 +1459,10 @@ static void ot_spi_host_reset_enter(Object *obj, ResetType type)
13471459

13481460
s->on_reset = true;
13491461

1462+
s->passthrough_en = false;
1463+
s->passthrough_cs = true;
1464+
s->host_cs0 = true;
1465+
13501466
if (!s->clock_src_name) {
13511467
IbexClockSrcIfClass *ic = IBEX_CLOCK_SRC_IF_GET_CLASS(s->clock_src);
13521468
IbexClockSrcIf *ii = IBEX_CLOCK_SRC_IF(s->clock_src);
@@ -1413,6 +1529,11 @@ static void ot_spi_host_instance_init(Object *obj)
14131529
ARRAY_SIZE(s->irqs));
14141530
ibex_qdev_init_irq(obj, &s->alert, OT_DEVICE_ALERT);
14151531

1532+
qdev_init_gpio_in_named(DEVICE(s), &ot_spi_host_device_passthrough_en_input,
1533+
OT_SPI_HOST_PASSTHROUGH_EN, 1);
1534+
qdev_init_gpio_in_named(DEVICE(s), &ot_spi_host_device_passthrough_cs_input,
1535+
OT_SPI_HOST_PASSTHROUGH_CS, 1);
1536+
14161537
s->regs = g_new0(uint32_t, REGS_COUNT);
14171538

14181539
s->rx_fifo = g_new0(RxFifo, 1u);
@@ -1434,8 +1555,10 @@ static void ot_spi_host_class_init(ObjectClass *klass, void *data)
14341555
dc->realize = ot_spi_host_realize;
14351556
device_class_set_props(dc, ot_spi_host_properties);
14361557

1437-
ResettableClass *rc = RESETTABLE_CLASS(klass);
14381558
OtSPIHostClass *sc = OT_SPI_HOST_CLASS(klass);
1559+
sc->ssi_downstream_transfer = &ot_spi_host_downstream_transfer;
1560+
1561+
ResettableClass *rc = RESETTABLE_CLASS(klass);
14391562
resettable_class_set_parent_phases(rc, &ot_spi_host_reset_enter, NULL,
14401563
&ot_spi_host_reset_exit,
14411564
&sc->parent_phases);

hw/opentitan/trace-events

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -591,6 +591,7 @@ ot_spi_host_io_read_repeat(const char *id, const char * regname, size_t count) "
591591
ot_spi_host_io_write(const char *id, uint32_t addr, const char * regname, uint32_t val, uint32_t pc) "%s: addr:0x%02x (%s), val:0x%08x, pc:0x%x"
592592
ot_spi_host_kick_command(const char *id, unsigned cmdid, bool start) "%s: {%u} start:%u"
593593
ot_spi_host_new_command(const char *id, unsigned cmdid, const char *dir, const char *spd, uint32_t csid, bool active, unsigned len) "%s: {%u} d:%s s:%s cs#:%u csa:%u len:%u"
594+
ot_spi_host_passthrough_disabled(const char *id) "%s: passthrough enable is not asserted"
594595
ot_spi_host_reset(const char *id) "%s"
595596
ot_spi_host_retire_command(const char *id, unsigned cmdid) "%s: {%u}"
596597
ot_spi_host_stall(const char *id, const char *msg, uint32_t val) "%s: %s rem %u"

include/hw/opentitan/ot_spi_host.h

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
* Author(s):
99
* Wilfred Mallawa <[email protected]>
1010
* Emmanuel Blot <[email protected]>
11+
* Alice Ziuziakowska <[email protected]>
1112
*
1213
* Permission is hereby granted, free of charge, to any person obtaining a copy
1314
* of this software and associated documentation files (the "Software"), to deal
@@ -32,10 +33,34 @@
3233
#define HW_OPENTITAN_OT_SPI_HOST_H
3334

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+
/*
47+
* Transfer a byte over this downstream SPI Host's SPI bus.
48+
* If Passthrough Enable is not asserted, or the SPI Host supports more
49+
* than one Chip Select, the transfer does not take place on the bus and a
50+
* default value is returned.
51+
*
52+
* @tx byte to be transferred
53+
* @return received byte from SPI bus, or a default value
54+
*/
55+
uint8_t (*ssi_downstream_transfer)(OtSPIHostState *, uint8_t tx);
56+
57+
ResettablePhases parent_phases;
58+
};
59+
60+
/* IRQ lines from upstream OT SPI Device */
61+
#define OT_SPI_HOST_PASSTHROUGH_EN (TYPE_OT_SPI_HOST "-passthrough-en")
62+
#define OT_SPI_HOST_PASSTHROUGH_CS (TYPE_OT_SPI_HOST "-passthrough-cs")
63+
3964
/* Supported SPI Host versions */
4065
typedef enum {
4166
OT_SPI_HOST_VERSION_EG_1_0_0,

0 commit comments

Comments
 (0)