@@ -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-
333329struct 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 )) {
0 commit comments