@@ -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-
333329struct 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+
527549static 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 );
0 commit comments