xref: /openbmc/qemu/hw/ssi/ibex_spi_host.c (revision 28ae3179fc52d2e4d870b635c4a412aab99759e7)
19c4888c9SWilfred Mallawa /*
29c4888c9SWilfred Mallawa  * QEMU model of the Ibex SPI Controller
39c4888c9SWilfred Mallawa  * SPEC Reference: https://docs.opentitan.org/hw/ip/spi_host/doc/
49c4888c9SWilfred Mallawa  *
59c4888c9SWilfred Mallawa  * Copyright (C) 2022 Western Digital
69c4888c9SWilfred Mallawa  *
79c4888c9SWilfred Mallawa  * Permission is hereby granted, free of charge, to any person obtaining a copy
89c4888c9SWilfred Mallawa  * of this software and associated documentation files (the "Software"), to deal
99c4888c9SWilfred Mallawa  * in the Software without restriction, including without limitation the rights
109c4888c9SWilfred Mallawa  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
119c4888c9SWilfred Mallawa  * copies of the Software, and to permit persons to whom the Software is
129c4888c9SWilfred Mallawa  * furnished to do so, subject to the following conditions:
139c4888c9SWilfred Mallawa  *
149c4888c9SWilfred Mallawa  * The above copyright notice and this permission notice shall be included in
159c4888c9SWilfred Mallawa  * all copies or substantial portions of the Software.
169c4888c9SWilfred Mallawa  *
179c4888c9SWilfred Mallawa  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
189c4888c9SWilfred Mallawa  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
199c4888c9SWilfred Mallawa  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
209c4888c9SWilfred Mallawa  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
219c4888c9SWilfred Mallawa  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
229c4888c9SWilfred Mallawa  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
239c4888c9SWilfred Mallawa  * THE SOFTWARE.
249c4888c9SWilfred Mallawa  */
259c4888c9SWilfred Mallawa 
269c4888c9SWilfred Mallawa #include "qemu/osdep.h"
279c4888c9SWilfred Mallawa #include "qemu/log.h"
289c4888c9SWilfred Mallawa #include "qemu/module.h"
298c6631e6SThomas Huth #include "hw/registerfields.h"
309c4888c9SWilfred Mallawa #include "hw/ssi/ibex_spi_host.h"
319c4888c9SWilfred Mallawa #include "hw/irq.h"
329c4888c9SWilfred Mallawa #include "hw/qdev-properties.h"
339c4888c9SWilfred Mallawa #include "hw/qdev-properties-system.h"
349c4888c9SWilfred Mallawa #include "migration/vmstate.h"
359c4888c9SWilfred Mallawa #include "trace.h"
369c4888c9SWilfred Mallawa 
379c4888c9SWilfred Mallawa REG32(INTR_STATE, 0x00)
389c4888c9SWilfred Mallawa     FIELD(INTR_STATE, ERROR, 0, 1)
399c4888c9SWilfred Mallawa     FIELD(INTR_STATE, SPI_EVENT, 1, 1)
409c4888c9SWilfred Mallawa REG32(INTR_ENABLE, 0x04)
419c4888c9SWilfred Mallawa     FIELD(INTR_ENABLE, ERROR, 0, 1)
429c4888c9SWilfred Mallawa     FIELD(INTR_ENABLE, SPI_EVENT, 1, 1)
439c4888c9SWilfred Mallawa REG32(INTR_TEST, 0x08)
449c4888c9SWilfred Mallawa     FIELD(INTR_TEST, ERROR, 0, 1)
459c4888c9SWilfred Mallawa     FIELD(INTR_TEST, SPI_EVENT, 1, 1)
469c4888c9SWilfred Mallawa REG32(ALERT_TEST, 0x0c)
479c4888c9SWilfred Mallawa     FIELD(ALERT_TEST, FETAL_TEST, 0, 1)
489c4888c9SWilfred Mallawa REG32(CONTROL, 0x10)
499c4888c9SWilfred Mallawa     FIELD(CONTROL, RX_WATERMARK, 0, 8)
509c4888c9SWilfred Mallawa     FIELD(CONTROL, TX_WATERMARK, 1, 8)
519c4888c9SWilfred Mallawa     FIELD(CONTROL, OUTPUT_EN, 29, 1)
529c4888c9SWilfred Mallawa     FIELD(CONTROL, SW_RST, 30, 1)
539c4888c9SWilfred Mallawa     FIELD(CONTROL, SPIEN, 31, 1)
549c4888c9SWilfred Mallawa REG32(STATUS, 0x14)
559c4888c9SWilfred Mallawa     FIELD(STATUS, TXQD, 0, 8)
569c4888c9SWilfred Mallawa     FIELD(STATUS, RXQD, 18, 8)
579c4888c9SWilfred Mallawa     FIELD(STATUS, CMDQD, 16, 3)
589c4888c9SWilfred Mallawa     FIELD(STATUS, RXWM, 20, 1)
599c4888c9SWilfred Mallawa     FIELD(STATUS, BYTEORDER, 22, 1)
609c4888c9SWilfred Mallawa     FIELD(STATUS, RXSTALL, 23, 1)
619c4888c9SWilfred Mallawa     FIELD(STATUS, RXEMPTY, 24, 1)
629c4888c9SWilfred Mallawa     FIELD(STATUS, RXFULL, 25, 1)
639c4888c9SWilfred Mallawa     FIELD(STATUS, TXWM, 26, 1)
649c4888c9SWilfred Mallawa     FIELD(STATUS, TXSTALL, 27, 1)
659c4888c9SWilfred Mallawa     FIELD(STATUS, TXEMPTY, 28, 1)
669c4888c9SWilfred Mallawa     FIELD(STATUS, TXFULL, 29, 1)
679c4888c9SWilfred Mallawa     FIELD(STATUS, ACTIVE, 30, 1)
689c4888c9SWilfred Mallawa     FIELD(STATUS, READY, 31, 1)
699c4888c9SWilfred Mallawa REG32(CONFIGOPTS, 0x18)
709c4888c9SWilfred Mallawa     FIELD(CONFIGOPTS, CLKDIV_0, 0, 16)
719c4888c9SWilfred Mallawa     FIELD(CONFIGOPTS, CSNIDLE_0, 16, 4)
729c4888c9SWilfred Mallawa     FIELD(CONFIGOPTS, CSNTRAIL_0, 20, 4)
739c4888c9SWilfred Mallawa     FIELD(CONFIGOPTS, CSNLEAD_0, 24, 4)
749c4888c9SWilfred Mallawa     FIELD(CONFIGOPTS, FULLCYC_0, 29, 1)
759c4888c9SWilfred Mallawa     FIELD(CONFIGOPTS, CPHA_0, 30, 1)
769c4888c9SWilfred Mallawa     FIELD(CONFIGOPTS, CPOL_0, 31, 1)
779c4888c9SWilfred Mallawa REG32(CSID, 0x1c)
789c4888c9SWilfred Mallawa     FIELD(CSID, CSID, 0, 32)
799c4888c9SWilfred Mallawa REG32(COMMAND, 0x20)
809c4888c9SWilfred Mallawa     FIELD(COMMAND, LEN, 0, 8)
819c4888c9SWilfred Mallawa     FIELD(COMMAND, CSAAT, 9, 1)
829c4888c9SWilfred Mallawa     FIELD(COMMAND, SPEED, 10, 2)
839c4888c9SWilfred Mallawa     FIELD(COMMAND, DIRECTION, 12, 2)
849c4888c9SWilfred Mallawa REG32(ERROR_ENABLE, 0x2c)
859c4888c9SWilfred Mallawa     FIELD(ERROR_ENABLE, CMDBUSY, 0, 1)
869c4888c9SWilfred Mallawa     FIELD(ERROR_ENABLE, OVERFLOW, 1, 1)
879c4888c9SWilfred Mallawa     FIELD(ERROR_ENABLE, UNDERFLOW, 2, 1)
889c4888c9SWilfred Mallawa     FIELD(ERROR_ENABLE, CMDINVAL, 3, 1)
899c4888c9SWilfred Mallawa     FIELD(ERROR_ENABLE, CSIDINVAL, 4, 1)
909c4888c9SWilfred Mallawa REG32(ERROR_STATUS, 0x30)
919c4888c9SWilfred Mallawa     FIELD(ERROR_STATUS, CMDBUSY, 0, 1)
929c4888c9SWilfred Mallawa     FIELD(ERROR_STATUS, OVERFLOW, 1, 1)
939c4888c9SWilfred Mallawa     FIELD(ERROR_STATUS, UNDERFLOW, 2, 1)
949c4888c9SWilfred Mallawa     FIELD(ERROR_STATUS, CMDINVAL, 3, 1)
959c4888c9SWilfred Mallawa     FIELD(ERROR_STATUS, CSIDINVAL, 4, 1)
969c4888c9SWilfred Mallawa     FIELD(ERROR_STATUS, ACCESSINVAL, 5, 1)
977a426f83SWilfred Mallawa REG32(EVENT_ENABLE, 0x34)
989c4888c9SWilfred Mallawa     FIELD(EVENT_ENABLE, RXFULL, 0, 1)
999c4888c9SWilfred Mallawa     FIELD(EVENT_ENABLE, TXEMPTY, 1, 1)
1009c4888c9SWilfred Mallawa     FIELD(EVENT_ENABLE, RXWM, 2, 1)
1019c4888c9SWilfred Mallawa     FIELD(EVENT_ENABLE, TXWM, 3, 1)
1029c4888c9SWilfred Mallawa     FIELD(EVENT_ENABLE, READY, 4, 1)
1039c4888c9SWilfred Mallawa     FIELD(EVENT_ENABLE, IDLE, 5, 1)
1049c4888c9SWilfred Mallawa 
div4_round_up(uint8_t dividend)1059c4888c9SWilfred Mallawa static inline uint8_t div4_round_up(uint8_t dividend)
1069c4888c9SWilfred Mallawa {
1079c4888c9SWilfred Mallawa     return (dividend + 3) / 4;
1089c4888c9SWilfred Mallawa }
1099c4888c9SWilfred Mallawa 
ibex_spi_rxfifo_reset(IbexSPIHostState * s)1109c4888c9SWilfred Mallawa static void ibex_spi_rxfifo_reset(IbexSPIHostState *s)
1119c4888c9SWilfred Mallawa {
112ff3809efSWilfred Mallawa     uint32_t data = s->regs[IBEX_SPI_HOST_STATUS];
1139c4888c9SWilfred Mallawa     /* Empty the RX FIFO and assert RXEMPTY */
1149c4888c9SWilfred Mallawa     fifo8_reset(&s->rx_fifo);
115ff3809efSWilfred Mallawa     data = FIELD_DP32(data, STATUS, RXFULL, 0);
116ff3809efSWilfred Mallawa     data = FIELD_DP32(data, STATUS, RXEMPTY, 1);
117ff3809efSWilfred Mallawa     s->regs[IBEX_SPI_HOST_STATUS] = data;
1189c4888c9SWilfred Mallawa }
1199c4888c9SWilfred Mallawa 
ibex_spi_txfifo_reset(IbexSPIHostState * s)1209c4888c9SWilfred Mallawa static void ibex_spi_txfifo_reset(IbexSPIHostState *s)
1219c4888c9SWilfred Mallawa {
122ff3809efSWilfred Mallawa     uint32_t data = s->regs[IBEX_SPI_HOST_STATUS];
1239c4888c9SWilfred Mallawa     /* Empty the TX FIFO and assert TXEMPTY */
1249c4888c9SWilfred Mallawa     fifo8_reset(&s->tx_fifo);
125ff3809efSWilfred Mallawa     data = FIELD_DP32(data, STATUS, TXFULL, 0);
126ff3809efSWilfred Mallawa     data = FIELD_DP32(data, STATUS, TXEMPTY, 1);
127ff3809efSWilfred Mallawa     s->regs[IBEX_SPI_HOST_STATUS] = data;
1289c4888c9SWilfred Mallawa }
1299c4888c9SWilfred Mallawa 
ibex_spi_host_reset(DeviceState * dev)1309c4888c9SWilfred Mallawa static void ibex_spi_host_reset(DeviceState *dev)
1319c4888c9SWilfred Mallawa {
1329c4888c9SWilfred Mallawa     IbexSPIHostState *s = IBEX_SPI_HOST(dev);
1339c4888c9SWilfred Mallawa     trace_ibex_spi_host_reset("Resetting Ibex SPI");
1349c4888c9SWilfred Mallawa 
1359c4888c9SWilfred Mallawa     /* SPI Host Register Reset */
1369c4888c9SWilfred Mallawa     s->regs[IBEX_SPI_HOST_INTR_STATE]   = 0x00;
1379c4888c9SWilfred Mallawa     s->regs[IBEX_SPI_HOST_INTR_ENABLE]  = 0x00;
1389c4888c9SWilfred Mallawa     s->regs[IBEX_SPI_HOST_INTR_TEST]    = 0x00;
1399c4888c9SWilfred Mallawa     s->regs[IBEX_SPI_HOST_ALERT_TEST]   = 0x00;
1409c4888c9SWilfred Mallawa     s->regs[IBEX_SPI_HOST_CONTROL]      = 0x7f;
1419c4888c9SWilfred Mallawa     s->regs[IBEX_SPI_HOST_STATUS]       = 0x00;
1429c4888c9SWilfred Mallawa     s->regs[IBEX_SPI_HOST_CONFIGOPTS]   = 0x00;
1439c4888c9SWilfred Mallawa     s->regs[IBEX_SPI_HOST_CSID]         = 0x00;
1449c4888c9SWilfred Mallawa     s->regs[IBEX_SPI_HOST_COMMAND]      = 0x00;
1459c4888c9SWilfred Mallawa     /* RX/TX Modelled by FIFO */
1469c4888c9SWilfred Mallawa     s->regs[IBEX_SPI_HOST_RXDATA]       = 0x00;
1479c4888c9SWilfred Mallawa     s->regs[IBEX_SPI_HOST_TXDATA]       = 0x00;
1489c4888c9SWilfred Mallawa 
1499c4888c9SWilfred Mallawa     s->regs[IBEX_SPI_HOST_ERROR_ENABLE] = 0x1F;
1509c4888c9SWilfred Mallawa     s->regs[IBEX_SPI_HOST_ERROR_STATUS] = 0x00;
1519c4888c9SWilfred Mallawa     s->regs[IBEX_SPI_HOST_EVENT_ENABLE] = 0x00;
1529c4888c9SWilfred Mallawa 
1539c4888c9SWilfred Mallawa     ibex_spi_rxfifo_reset(s);
1549c4888c9SWilfred Mallawa     ibex_spi_txfifo_reset(s);
1559c4888c9SWilfred Mallawa 
1569c4888c9SWilfred Mallawa     s->init_status = true;
1579c4888c9SWilfred Mallawa     return;
1589c4888c9SWilfred Mallawa }
1599c4888c9SWilfred Mallawa 
1609c4888c9SWilfred Mallawa /*
1619c4888c9SWilfred Mallawa  * Check if we need to trigger an interrupt.
1629c4888c9SWilfred Mallawa  * The two interrupts lines (host_err and event) can
1639c4888c9SWilfred Mallawa  * be enabled separately in 'IBEX_SPI_HOST_INTR_ENABLE'.
1649c4888c9SWilfred Mallawa  *
1659c4888c9SWilfred Mallawa  * Interrupts are triggered based on the ones
1669c4888c9SWilfred Mallawa  * enabled in the `IBEX_SPI_HOST_EVENT_ENABLE` and `IBEX_SPI_HOST_ERROR_ENABLE`.
1679c4888c9SWilfred Mallawa  */
ibex_spi_host_irq(IbexSPIHostState * s)1689c4888c9SWilfred Mallawa static void ibex_spi_host_irq(IbexSPIHostState *s)
1699c4888c9SWilfred Mallawa {
170ff3809efSWilfred Mallawa     uint32_t intr_test_reg = s->regs[IBEX_SPI_HOST_INTR_TEST];
171ff3809efSWilfred Mallawa     uint32_t intr_en_reg = s->regs[IBEX_SPI_HOST_INTR_ENABLE];
172ff3809efSWilfred Mallawa     uint32_t intr_state_reg = s->regs[IBEX_SPI_HOST_INTR_STATE];
173ff3809efSWilfred Mallawa 
174ff3809efSWilfred Mallawa     uint32_t err_en_reg = s->regs[IBEX_SPI_HOST_ERROR_ENABLE];
175ff3809efSWilfred Mallawa     uint32_t event_en_reg = s->regs[IBEX_SPI_HOST_EVENT_ENABLE];
176ff3809efSWilfred Mallawa     uint32_t err_status_reg = s->regs[IBEX_SPI_HOST_ERROR_STATUS];
177ff3809efSWilfred Mallawa     uint32_t status_reg = s->regs[IBEX_SPI_HOST_STATUS];
178ff3809efSWilfred Mallawa 
179ff3809efSWilfred Mallawa 
180ff3809efSWilfred Mallawa     bool error_en = FIELD_EX32(intr_en_reg, INTR_ENABLE, ERROR);
181ff3809efSWilfred Mallawa     bool event_en = FIELD_EX32(intr_en_reg, INTR_ENABLE, SPI_EVENT);
182ff3809efSWilfred Mallawa     bool err_pending = FIELD_EX32(intr_state_reg, INTR_STATE, ERROR);
183ff3809efSWilfred Mallawa     bool status_pending = FIELD_EX32(intr_state_reg, INTR_STATE, SPI_EVENT);
184ff3809efSWilfred Mallawa 
1859c4888c9SWilfred Mallawa     int err_irq = 0, event_irq = 0;
1869c4888c9SWilfred Mallawa 
1879c4888c9SWilfred Mallawa     /* Error IRQ enabled and Error IRQ Cleared */
1889c4888c9SWilfred Mallawa     if (error_en && !err_pending) {
1899c4888c9SWilfred Mallawa         /* Event enabled, Interrupt Test Error */
190ff3809efSWilfred Mallawa         if (FIELD_EX32(intr_test_reg, INTR_TEST,  ERROR)) {
1919c4888c9SWilfred Mallawa             err_irq = 1;
192ff3809efSWilfred Mallawa         } else if (FIELD_EX32(err_en_reg, ERROR_ENABLE,  CMDBUSY) &&
193ff3809efSWilfred Mallawa                    FIELD_EX32(err_status_reg, ERROR_STATUS,  CMDBUSY)) {
1949c4888c9SWilfred Mallawa             /* Wrote to COMMAND when not READY */
1959c4888c9SWilfred Mallawa             err_irq = 1;
196ff3809efSWilfred Mallawa         } else if (FIELD_EX32(err_en_reg, ERROR_ENABLE,  CMDINVAL)  &&
197ff3809efSWilfred Mallawa                    FIELD_EX32(err_status_reg, ERROR_STATUS,  CMDINVAL)) {
1989c4888c9SWilfred Mallawa             /* Invalid command segment */
1999c4888c9SWilfred Mallawa             err_irq = 1;
200ff3809efSWilfred Mallawa         } else if (FIELD_EX32(err_en_reg, ERROR_ENABLE,  CSIDINVAL) &&
201ff3809efSWilfred Mallawa                    FIELD_EX32(err_status_reg, ERROR_STATUS,  CSIDINVAL)) {
2029c4888c9SWilfred Mallawa             /* Invalid value for CSID */
2039c4888c9SWilfred Mallawa             err_irq = 1;
2049c4888c9SWilfred Mallawa         }
2059c4888c9SWilfred Mallawa         if (err_irq) {
2069c4888c9SWilfred Mallawa             s->regs[IBEX_SPI_HOST_INTR_STATE] |= R_INTR_STATE_ERROR_MASK;
2079c4888c9SWilfred Mallawa         }
2089c4888c9SWilfred Mallawa     }
2099c4888c9SWilfred Mallawa 
210d53ead72SAlistair Francis     qemu_set_irq(s->host_err, err_irq);
211d53ead72SAlistair Francis 
2129c4888c9SWilfred Mallawa     /* Event IRQ Enabled and Event IRQ Cleared */
2139c4888c9SWilfred Mallawa     if (event_en && !status_pending) {
214ff3809efSWilfred Mallawa         if (FIELD_EX32(intr_test_reg, INTR_STATE,  SPI_EVENT)) {
2159c4888c9SWilfred Mallawa             /* Event enabled, Interrupt Test Event */
2169c4888c9SWilfred Mallawa             event_irq = 1;
217ff3809efSWilfred Mallawa         } else if (FIELD_EX32(event_en_reg, EVENT_ENABLE,  READY) &&
218ff3809efSWilfred Mallawa                    FIELD_EX32(status_reg, STATUS, READY)) {
2199c4888c9SWilfred Mallawa             /* SPI Host ready for next command */
2209c4888c9SWilfred Mallawa             event_irq = 1;
221ff3809efSWilfred Mallawa         } else if (FIELD_EX32(event_en_reg, EVENT_ENABLE,  TXEMPTY) &&
222ff3809efSWilfred Mallawa                    FIELD_EX32(status_reg, STATUS,  TXEMPTY)) {
2239c4888c9SWilfred Mallawa             /* SPI TXEMPTY, TXFIFO drained */
2249c4888c9SWilfred Mallawa             event_irq = 1;
225ff3809efSWilfred Mallawa         } else if (FIELD_EX32(event_en_reg, EVENT_ENABLE,  RXFULL) &&
226ff3809efSWilfred Mallawa                    FIELD_EX32(status_reg, STATUS,  RXFULL)) {
2279c4888c9SWilfred Mallawa             /* SPI RXFULL, RXFIFO  full */
2289c4888c9SWilfred Mallawa             event_irq = 1;
2299c4888c9SWilfred Mallawa         }
2309c4888c9SWilfred Mallawa         if (event_irq) {
2319c4888c9SWilfred Mallawa             s->regs[IBEX_SPI_HOST_INTR_STATE] |= R_INTR_STATE_SPI_EVENT_MASK;
2329c4888c9SWilfred Mallawa         }
2339c4888c9SWilfred Mallawa     }
234d53ead72SAlistair Francis 
235d53ead72SAlistair Francis     qemu_set_irq(s->event, event_irq);
2369c4888c9SWilfred Mallawa }
2379c4888c9SWilfred Mallawa 
ibex_spi_host_transfer(IbexSPIHostState * s)2389c4888c9SWilfred Mallawa static void ibex_spi_host_transfer(IbexSPIHostState *s)
2399c4888c9SWilfred Mallawa {
240ff3809efSWilfred Mallawa     uint32_t rx, tx, data;
2419c4888c9SWilfred Mallawa     /* Get num of one byte transfers */
242ff3809efSWilfred Mallawa     uint8_t segment_len = FIELD_EX32(s->regs[IBEX_SPI_HOST_COMMAND],
243ff3809efSWilfred Mallawa                                      COMMAND,  LEN);
244ff3809efSWilfred Mallawa 
2459c4888c9SWilfred Mallawa     while (segment_len > 0) {
2469c4888c9SWilfred Mallawa         if (fifo8_is_empty(&s->tx_fifo)) {
2479c4888c9SWilfred Mallawa             /* Assert Stall */
2489c4888c9SWilfred Mallawa             s->regs[IBEX_SPI_HOST_STATUS] |= R_STATUS_TXSTALL_MASK;
2499c4888c9SWilfred Mallawa             break;
2509c4888c9SWilfred Mallawa         } else if (fifo8_is_full(&s->rx_fifo)) {
2519c4888c9SWilfred Mallawa             /* Assert Stall */
2529c4888c9SWilfred Mallawa             s->regs[IBEX_SPI_HOST_STATUS] |= R_STATUS_RXSTALL_MASK;
2539c4888c9SWilfred Mallawa             break;
2549c4888c9SWilfred Mallawa         } else {
2559c4888c9SWilfred Mallawa             tx = fifo8_pop(&s->tx_fifo);
2569c4888c9SWilfred Mallawa         }
2579c4888c9SWilfred Mallawa 
2589c4888c9SWilfred Mallawa         rx = ssi_transfer(s->ssi, tx);
2599c4888c9SWilfred Mallawa 
2609c4888c9SWilfred Mallawa         trace_ibex_spi_host_transfer(tx, rx);
2619c4888c9SWilfred Mallawa 
2629c4888c9SWilfred Mallawa         if (!fifo8_is_full(&s->rx_fifo)) {
2639c4888c9SWilfred Mallawa             fifo8_push(&s->rx_fifo, rx);
2649c4888c9SWilfred Mallawa         } else {
2659c4888c9SWilfred Mallawa             /* Assert RXFULL */
2669c4888c9SWilfred Mallawa             s->regs[IBEX_SPI_HOST_STATUS] |= R_STATUS_RXFULL_MASK;
2679c4888c9SWilfred Mallawa         }
2689c4888c9SWilfred Mallawa         --segment_len;
2699c4888c9SWilfred Mallawa     }
2709c4888c9SWilfred Mallawa 
271ff3809efSWilfred Mallawa     data = s->regs[IBEX_SPI_HOST_STATUS];
2729c4888c9SWilfred Mallawa     /* Assert Ready */
273ff3809efSWilfred Mallawa     data = FIELD_DP32(data, STATUS, READY, 1);
2749c4888c9SWilfred Mallawa     /* Set RXQD */
275ff3809efSWilfred Mallawa     data = FIELD_DP32(data, STATUS, RXQD, div4_round_up(segment_len));
2769c4888c9SWilfred Mallawa     /* Set TXQD */
277ff3809efSWilfred Mallawa     data = FIELD_DP32(data, STATUS, TXQD, fifo8_num_used(&s->tx_fifo) / 4);
2789c4888c9SWilfred Mallawa     /* Clear TXFULL */
279ff3809efSWilfred Mallawa     data = FIELD_DP32(data, STATUS, TXFULL, 0);
2809c4888c9SWilfred Mallawa     /* Reset RXEMPTY */
281ff3809efSWilfred Mallawa     data = FIELD_DP32(data, STATUS, RXEMPTY, 0);
282ff3809efSWilfred Mallawa     /* Update register status */
283ff3809efSWilfred Mallawa     s->regs[IBEX_SPI_HOST_STATUS] = data;
284ff3809efSWilfred Mallawa     /* Drop remaining bytes that exceed segment_len */
285ff3809efSWilfred Mallawa     ibex_spi_txfifo_reset(s);
2869c4888c9SWilfred Mallawa 
2879c4888c9SWilfred Mallawa     ibex_spi_host_irq(s);
2889c4888c9SWilfred Mallawa }
2899c4888c9SWilfred Mallawa 
ibex_spi_host_read(void * opaque,hwaddr addr,unsigned int size)2909c4888c9SWilfred Mallawa static uint64_t ibex_spi_host_read(void *opaque, hwaddr addr,
2919c4888c9SWilfred Mallawa                                      unsigned int size)
2929c4888c9SWilfred Mallawa {
2939c4888c9SWilfred Mallawa     IbexSPIHostState *s = opaque;
2949c4888c9SWilfred Mallawa     uint32_t rc = 0;
2959c4888c9SWilfred Mallawa     uint8_t rx_byte = 0;
2969c4888c9SWilfred Mallawa 
2979c4888c9SWilfred Mallawa     trace_ibex_spi_host_read(addr, size);
2989c4888c9SWilfred Mallawa 
2999c4888c9SWilfred Mallawa     /* Match reg index */
3009c4888c9SWilfred Mallawa     addr = addr >> 2;
3019c4888c9SWilfred Mallawa     switch (addr) {
3029c4888c9SWilfred Mallawa     /* Skipping any W/O registers */
3039c4888c9SWilfred Mallawa     case IBEX_SPI_HOST_INTR_STATE...IBEX_SPI_HOST_INTR_ENABLE:
3049c4888c9SWilfred Mallawa     case IBEX_SPI_HOST_CONTROL...IBEX_SPI_HOST_STATUS:
3059c4888c9SWilfred Mallawa         rc = s->regs[addr];
3069c4888c9SWilfred Mallawa         break;
3079c4888c9SWilfred Mallawa     case IBEX_SPI_HOST_CSID:
3089c4888c9SWilfred Mallawa         rc = s->regs[addr];
3099c4888c9SWilfred Mallawa         break;
3109c4888c9SWilfred Mallawa     case IBEX_SPI_HOST_CONFIGOPTS:
3119c4888c9SWilfred Mallawa         rc = s->config_opts[s->regs[IBEX_SPI_HOST_CSID]];
3129c4888c9SWilfred Mallawa         break;
3139c4888c9SWilfred Mallawa     case IBEX_SPI_HOST_TXDATA:
3149c4888c9SWilfred Mallawa         rc = s->regs[addr];
3159c4888c9SWilfred Mallawa         break;
3169c4888c9SWilfred Mallawa     case IBEX_SPI_HOST_RXDATA:
3179c4888c9SWilfred Mallawa         /* Clear RXFULL */
3189c4888c9SWilfred Mallawa         s->regs[IBEX_SPI_HOST_STATUS] &= ~R_STATUS_RXFULL_MASK;
3199c4888c9SWilfred Mallawa 
3209c4888c9SWilfred Mallawa         for (int i = 0; i < 4; ++i) {
3219c4888c9SWilfred Mallawa             if (fifo8_is_empty(&s->rx_fifo)) {
3229c4888c9SWilfred Mallawa                 /* Assert RXEMPTY, no IRQ */
3239c4888c9SWilfred Mallawa                 s->regs[IBEX_SPI_HOST_STATUS] |= R_STATUS_RXEMPTY_MASK;
3249c4888c9SWilfred Mallawa                 s->regs[IBEX_SPI_HOST_ERROR_STATUS] |=
3259c4888c9SWilfred Mallawa                                                 R_ERROR_STATUS_UNDERFLOW_MASK;
3269c4888c9SWilfred Mallawa                 return rc;
3279c4888c9SWilfred Mallawa             }
3289c4888c9SWilfred Mallawa             rx_byte = fifo8_pop(&s->rx_fifo);
3299c4888c9SWilfred Mallawa             rc |= rx_byte << (i * 8);
3309c4888c9SWilfred Mallawa         }
3319c4888c9SWilfred Mallawa         break;
3329c4888c9SWilfred Mallawa     case IBEX_SPI_HOST_ERROR_ENABLE...IBEX_SPI_HOST_EVENT_ENABLE:
3339c4888c9SWilfred Mallawa         rc = s->regs[addr];
3349c4888c9SWilfred Mallawa         break;
3359c4888c9SWilfred Mallawa     default:
3369c4888c9SWilfred Mallawa         qemu_log_mask(LOG_GUEST_ERROR, "Bad offset 0x%" HWADDR_PRIx "\n",
3379c4888c9SWilfred Mallawa                       addr << 2);
3389c4888c9SWilfred Mallawa     }
3399c4888c9SWilfred Mallawa     return rc;
3409c4888c9SWilfred Mallawa }
3419c4888c9SWilfred Mallawa 
3429c4888c9SWilfred Mallawa 
ibex_spi_host_write(void * opaque,hwaddr addr,uint64_t val64,unsigned int size)3439c4888c9SWilfred Mallawa static void ibex_spi_host_write(void *opaque, hwaddr addr,
3449c4888c9SWilfred Mallawa                                 uint64_t val64, unsigned int size)
3459c4888c9SWilfred Mallawa {
3469c4888c9SWilfred Mallawa     IbexSPIHostState *s = opaque;
3479c4888c9SWilfred Mallawa     uint32_t val32 = val64;
3486c187695SWilfred Mallawa     uint32_t shift_mask = 0xff, status = 0, data = 0;
3499c4888c9SWilfred Mallawa     uint8_t txqd_len;
3509c4888c9SWilfred Mallawa 
3519c4888c9SWilfred Mallawa     trace_ibex_spi_host_write(addr, size, val64);
3529c4888c9SWilfred Mallawa 
3539c4888c9SWilfred Mallawa     /* Match reg index */
3549c4888c9SWilfred Mallawa     addr = addr >> 2;
3559c4888c9SWilfred Mallawa 
3569c4888c9SWilfred Mallawa     switch (addr) {
3579c4888c9SWilfred Mallawa     /* Skipping any R/O registers */
3586c187695SWilfred Mallawa     case IBEX_SPI_HOST_INTR_STATE:
3596c187695SWilfred Mallawa         /* rw1c status register */
3606c187695SWilfred Mallawa         if (FIELD_EX32(val32, INTR_STATE, ERROR)) {
3616c187695SWilfred Mallawa             data = FIELD_DP32(data, INTR_STATE, ERROR, 0);
3626c187695SWilfred Mallawa         }
3636c187695SWilfred Mallawa         if (FIELD_EX32(val32, INTR_STATE, SPI_EVENT)) {
3646c187695SWilfred Mallawa             data = FIELD_DP32(data, INTR_STATE, SPI_EVENT, 0);
3656c187695SWilfred Mallawa         }
3666c187695SWilfred Mallawa         s->regs[addr] = data;
3676c187695SWilfred Mallawa         break;
3686c187695SWilfred Mallawa     case IBEX_SPI_HOST_INTR_ENABLE:
3699c4888c9SWilfred Mallawa         s->regs[addr] = val32;
3709c4888c9SWilfred Mallawa         break;
3719c4888c9SWilfred Mallawa     case IBEX_SPI_HOST_INTR_TEST:
3729c4888c9SWilfred Mallawa         s->regs[addr] = val32;
3739c4888c9SWilfred Mallawa         ibex_spi_host_irq(s);
3749c4888c9SWilfred Mallawa         break;
3759c4888c9SWilfred Mallawa     case IBEX_SPI_HOST_ALERT_TEST:
3769c4888c9SWilfred Mallawa         s->regs[addr] = val32;
3779c4888c9SWilfred Mallawa         qemu_log_mask(LOG_UNIMP,
3789c4888c9SWilfred Mallawa                         "%s: SPI_ALERT_TEST is not supported\n", __func__);
3799c4888c9SWilfred Mallawa         break;
3809c4888c9SWilfred Mallawa     case IBEX_SPI_HOST_CONTROL:
3819c4888c9SWilfred Mallawa         s->regs[addr] = val32;
3829c4888c9SWilfred Mallawa 
3839c4888c9SWilfred Mallawa         if (val32 & R_CONTROL_SW_RST_MASK)  {
3849c4888c9SWilfred Mallawa             ibex_spi_host_reset((DeviceState *)s);
3859c4888c9SWilfred Mallawa             /* Clear active if any */
3869c4888c9SWilfred Mallawa             s->regs[IBEX_SPI_HOST_STATUS] &=  ~R_STATUS_ACTIVE_MASK;
3879c4888c9SWilfred Mallawa         }
3889c4888c9SWilfred Mallawa 
3899c4888c9SWilfred Mallawa         if (val32 & R_CONTROL_OUTPUT_EN_MASK)  {
3909c4888c9SWilfred Mallawa             qemu_log_mask(LOG_UNIMP,
3919c4888c9SWilfred Mallawa                           "%s: CONTROL_OUTPUT_EN is not supported\n", __func__);
3929c4888c9SWilfred Mallawa         }
3939c4888c9SWilfred Mallawa         break;
3949c4888c9SWilfred Mallawa     case IBEX_SPI_HOST_CONFIGOPTS:
3959c4888c9SWilfred Mallawa         /* Update the respective config-opts register based on CSIDth index */
3969c4888c9SWilfred Mallawa         s->config_opts[s->regs[IBEX_SPI_HOST_CSID]] = val32;
3979c4888c9SWilfred Mallawa         qemu_log_mask(LOG_UNIMP,
3989c4888c9SWilfred Mallawa                       "%s: CONFIGOPTS Hardware settings not supported\n",
3999c4888c9SWilfred Mallawa                          __func__);
4009c4888c9SWilfred Mallawa         break;
4019c4888c9SWilfred Mallawa     case IBEX_SPI_HOST_CSID:
4029c4888c9SWilfred Mallawa         if (val32 >= s->num_cs) {
4039c4888c9SWilfred Mallawa             /* CSID exceeds max num_cs */
4049c4888c9SWilfred Mallawa             s->regs[IBEX_SPI_HOST_ERROR_STATUS] |=
4059c4888c9SWilfred Mallawa                                                 R_ERROR_STATUS_CSIDINVAL_MASK;
4069c4888c9SWilfred Mallawa             ibex_spi_host_irq(s);
4079c4888c9SWilfred Mallawa             return;
4089c4888c9SWilfred Mallawa         }
4099c4888c9SWilfred Mallawa         s->regs[addr] = val32;
4109c4888c9SWilfred Mallawa         break;
4119c4888c9SWilfred Mallawa     case IBEX_SPI_HOST_COMMAND:
4129c4888c9SWilfred Mallawa         s->regs[addr] = val32;
4139c4888c9SWilfred Mallawa 
4149c4888c9SWilfred Mallawa         /* STALL, IP not enabled */
415ff3809efSWilfred Mallawa         if (!(FIELD_EX32(s->regs[IBEX_SPI_HOST_CONTROL],
416ff3809efSWilfred Mallawa                          CONTROL, SPIEN))) {
4179c4888c9SWilfred Mallawa             return;
4189c4888c9SWilfred Mallawa         }
4199c4888c9SWilfred Mallawa 
4209c4888c9SWilfred Mallawa         /* SPI not ready, IRQ Error */
421ff3809efSWilfred Mallawa         if (!(FIELD_EX32(s->regs[IBEX_SPI_HOST_STATUS],
422ff3809efSWilfred Mallawa                          STATUS, READY))) {
4239c4888c9SWilfred Mallawa             s->regs[IBEX_SPI_HOST_ERROR_STATUS] |= R_ERROR_STATUS_CMDBUSY_MASK;
4249c4888c9SWilfred Mallawa             ibex_spi_host_irq(s);
4259c4888c9SWilfred Mallawa             return;
4269c4888c9SWilfred Mallawa         }
427ff3809efSWilfred Mallawa 
4289c4888c9SWilfred Mallawa         /* Assert Not Ready */
4299c4888c9SWilfred Mallawa         s->regs[IBEX_SPI_HOST_STATUS] &= ~R_STATUS_READY_MASK;
4309c4888c9SWilfred Mallawa 
431ff3809efSWilfred Mallawa         if (FIELD_EX32(val32, COMMAND, DIRECTION) != BIDIRECTIONAL_TRANSFER) {
4329c4888c9SWilfred Mallawa             qemu_log_mask(LOG_UNIMP,
4339c4888c9SWilfred Mallawa                           "%s: Rx Only/Tx Only are not supported\n", __func__);
4349c4888c9SWilfred Mallawa         }
4359c4888c9SWilfred Mallawa 
4369c4888c9SWilfred Mallawa         if (val32 & R_COMMAND_CSAAT_MASK)  {
4379c4888c9SWilfred Mallawa             qemu_log_mask(LOG_UNIMP,
4389c4888c9SWilfred Mallawa                           "%s: CSAAT is not supported\n", __func__);
4399c4888c9SWilfred Mallawa         }
4409c4888c9SWilfred Mallawa         if (val32 & R_COMMAND_SPEED_MASK)  {
4419c4888c9SWilfred Mallawa             qemu_log_mask(LOG_UNIMP,
4429c4888c9SWilfred Mallawa                           "%s: SPEED is not supported\n", __func__);
4439c4888c9SWilfred Mallawa         }
4449c4888c9SWilfred Mallawa 
4459c4888c9SWilfred Mallawa         /* Set Transfer Callback */
4469c4888c9SWilfred Mallawa         timer_mod(s->fifo_trigger_handle,
4479c4888c9SWilfred Mallawa                     qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
4489c4888c9SWilfred Mallawa                     (TX_INTERRUPT_TRIGGER_DELAY_NS));
4499c4888c9SWilfred Mallawa 
4509c4888c9SWilfred Mallawa         break;
4519c4888c9SWilfred Mallawa     case IBEX_SPI_HOST_TXDATA:
4529c4888c9SWilfred Mallawa         /*
4539c4888c9SWilfred Mallawa          * This is a hardware `feature` where
454a4455863SWilfred Mallawa          * the first word written to TXDATA after init is omitted entirely
4559c4888c9SWilfred Mallawa          */
4569c4888c9SWilfred Mallawa         if (s->init_status) {
4579c4888c9SWilfred Mallawa             s->init_status = false;
4589c4888c9SWilfred Mallawa             return;
4599c4888c9SWilfred Mallawa         }
4609c4888c9SWilfred Mallawa 
4619c4888c9SWilfred Mallawa         for (int i = 0; i < 4; ++i) {
4629c4888c9SWilfred Mallawa             /* Attempting to write when TXFULL */
4639c4888c9SWilfred Mallawa             if (fifo8_is_full(&s->tx_fifo)) {
4649c4888c9SWilfred Mallawa                 /* Assert RXEMPTY, no IRQ */
4659c4888c9SWilfred Mallawa                 s->regs[IBEX_SPI_HOST_STATUS] |= R_STATUS_TXFULL_MASK;
4669c4888c9SWilfred Mallawa                 s->regs[IBEX_SPI_HOST_ERROR_STATUS] |=
4679c4888c9SWilfred Mallawa                                                  R_ERROR_STATUS_OVERFLOW_MASK;
4689c4888c9SWilfred Mallawa                 ibex_spi_host_irq(s);
4699c4888c9SWilfred Mallawa                 return;
4709c4888c9SWilfred Mallawa             }
4719c4888c9SWilfred Mallawa             /* Byte ordering is set by the IP */
472ff3809efSWilfred Mallawa             status = s->regs[IBEX_SPI_HOST_STATUS];
473ff3809efSWilfred Mallawa             if (FIELD_EX32(status, STATUS, BYTEORDER) == 0) {
4749c4888c9SWilfred Mallawa                 /* LE: LSB transmitted first (default for ibex processor) */
4759c4888c9SWilfred Mallawa                 shift_mask = 0xff << (i * 8);
4769c4888c9SWilfred Mallawa             } else {
4779c4888c9SWilfred Mallawa                 /* BE: MSB transmitted first */
4789c4888c9SWilfred Mallawa                 qemu_log_mask(LOG_UNIMP,
4799c4888c9SWilfred Mallawa                              "%s: Big endian is not supported\n", __func__);
4809c4888c9SWilfred Mallawa             }
4819c4888c9SWilfred Mallawa 
4829c4888c9SWilfred Mallawa             fifo8_push(&s->tx_fifo, (val32 & shift_mask) >> (i * 8));
4839c4888c9SWilfred Mallawa         }
484ff3809efSWilfred Mallawa         status = s->regs[IBEX_SPI_HOST_STATUS];
4859c4888c9SWilfred Mallawa         /* Reset TXEMPTY */
486ff3809efSWilfred Mallawa         status = FIELD_DP32(status, STATUS, TXEMPTY, 0);
4879c4888c9SWilfred Mallawa         /* Update TXQD */
488ff3809efSWilfred Mallawa         txqd_len = FIELD_EX32(status, STATUS, TXQD);
4899c4888c9SWilfred Mallawa         /* Partial bytes (size < 4) are padded, in words. */
4909c4888c9SWilfred Mallawa         txqd_len += 1;
491ff3809efSWilfred Mallawa         status = FIELD_DP32(status, STATUS, TXQD, txqd_len);
4929c4888c9SWilfred Mallawa         /* Assert Ready */
493ff3809efSWilfred Mallawa         status = FIELD_DP32(status, STATUS, READY, 1);
494ff3809efSWilfred Mallawa         /* Update register status */
495ff3809efSWilfred Mallawa         s->regs[IBEX_SPI_HOST_STATUS] = status;
4969c4888c9SWilfred Mallawa         break;
4979c4888c9SWilfred Mallawa     case IBEX_SPI_HOST_ERROR_ENABLE:
4989c4888c9SWilfred Mallawa         s->regs[addr] = val32;
4999c4888c9SWilfred Mallawa 
5009c4888c9SWilfred Mallawa         if (val32 & R_ERROR_ENABLE_CMDINVAL_MASK)  {
5019c4888c9SWilfred Mallawa             qemu_log_mask(LOG_UNIMP,
5029c4888c9SWilfred Mallawa                           "%s: Segment Length is not supported\n", __func__);
5039c4888c9SWilfred Mallawa         }
5049c4888c9SWilfred Mallawa         break;
5059c4888c9SWilfred Mallawa     case IBEX_SPI_HOST_ERROR_STATUS:
5069c4888c9SWilfred Mallawa     /*
507a4455863SWilfred Mallawa      *  Indicates any errors that have occurred.
5089c4888c9SWilfred Mallawa      *  When an error occurs, the corresponding bit must be cleared
5099c4888c9SWilfred Mallawa      *  here before issuing any further commands
5109c4888c9SWilfred Mallawa      */
5116c187695SWilfred Mallawa         status = s->regs[addr];
5126c187695SWilfred Mallawa         /* rw1c status register */
5136c187695SWilfred Mallawa         if (FIELD_EX32(val32, ERROR_STATUS, CMDBUSY)) {
5146c187695SWilfred Mallawa             status = FIELD_DP32(status, ERROR_STATUS, CMDBUSY, 0);
5156c187695SWilfred Mallawa         }
5166c187695SWilfred Mallawa         if (FIELD_EX32(val32, ERROR_STATUS, OVERFLOW)) {
5176c187695SWilfred Mallawa             status = FIELD_DP32(status, ERROR_STATUS, OVERFLOW, 0);
5186c187695SWilfred Mallawa         }
5196c187695SWilfred Mallawa         if (FIELD_EX32(val32, ERROR_STATUS, UNDERFLOW)) {
5206c187695SWilfred Mallawa             status = FIELD_DP32(status, ERROR_STATUS, UNDERFLOW, 0);
5216c187695SWilfred Mallawa         }
5226c187695SWilfred Mallawa         if (FIELD_EX32(val32, ERROR_STATUS, CMDINVAL)) {
5236c187695SWilfred Mallawa             status = FIELD_DP32(status, ERROR_STATUS, CMDINVAL, 0);
5246c187695SWilfred Mallawa         }
5256c187695SWilfred Mallawa         if (FIELD_EX32(val32, ERROR_STATUS, CSIDINVAL)) {
5266c187695SWilfred Mallawa             status = FIELD_DP32(status, ERROR_STATUS, CSIDINVAL, 0);
5276c187695SWilfred Mallawa         }
5286c187695SWilfred Mallawa         if (FIELD_EX32(val32, ERROR_STATUS, ACCESSINVAL)) {
5296c187695SWilfred Mallawa             status = FIELD_DP32(status, ERROR_STATUS, ACCESSINVAL, 0);
5306c187695SWilfred Mallawa         }
5316c187695SWilfred Mallawa         s->regs[addr] = status;
5329c4888c9SWilfred Mallawa         break;
5339c4888c9SWilfred Mallawa     case IBEX_SPI_HOST_EVENT_ENABLE:
5349c4888c9SWilfred Mallawa     /* Controls which classes of SPI events raise an interrupt. */
5359c4888c9SWilfred Mallawa         s->regs[addr] = val32;
5369c4888c9SWilfred Mallawa 
5379c4888c9SWilfred Mallawa         if (val32 & R_EVENT_ENABLE_RXWM_MASK)  {
5389c4888c9SWilfred Mallawa             qemu_log_mask(LOG_UNIMP,
5399c4888c9SWilfred Mallawa                           "%s: RXWM is not supported\n", __func__);
5409c4888c9SWilfred Mallawa         }
5419c4888c9SWilfred Mallawa         if (val32 & R_EVENT_ENABLE_TXWM_MASK)  {
5429c4888c9SWilfred Mallawa             qemu_log_mask(LOG_UNIMP,
5439c4888c9SWilfred Mallawa                           "%s: TXWM is not supported\n", __func__);
5449c4888c9SWilfred Mallawa         }
5459c4888c9SWilfred Mallawa 
5469c4888c9SWilfred Mallawa         if (val32 & R_EVENT_ENABLE_IDLE_MASK)  {
5479c4888c9SWilfred Mallawa             qemu_log_mask(LOG_UNIMP,
5489c4888c9SWilfred Mallawa                           "%s: IDLE is not supported\n", __func__);
5499c4888c9SWilfred Mallawa         }
5509c4888c9SWilfred Mallawa         break;
5519c4888c9SWilfred Mallawa     default:
5529c4888c9SWilfred Mallawa         qemu_log_mask(LOG_GUEST_ERROR, "Bad offset 0x%" HWADDR_PRIx "\n",
5539c4888c9SWilfred Mallawa                       addr << 2);
5549c4888c9SWilfred Mallawa     }
5559c4888c9SWilfred Mallawa }
5569c4888c9SWilfred Mallawa 
5579c4888c9SWilfred Mallawa static const MemoryRegionOps ibex_spi_ops = {
5589c4888c9SWilfred Mallawa     .read = ibex_spi_host_read,
5599c4888c9SWilfred Mallawa     .write = ibex_spi_host_write,
5609c4888c9SWilfred Mallawa     /* Ibex default LE */
5619c4888c9SWilfred Mallawa     .endianness = DEVICE_LITTLE_ENDIAN,
5629c4888c9SWilfred Mallawa };
5639c4888c9SWilfred Mallawa 
5649c4888c9SWilfred Mallawa static Property ibex_spi_properties[] = {
5659c4888c9SWilfred Mallawa     DEFINE_PROP_UINT32("num_cs", IbexSPIHostState, num_cs, 1),
5669c4888c9SWilfred Mallawa     DEFINE_PROP_END_OF_LIST(),
5679c4888c9SWilfred Mallawa };
5689c4888c9SWilfred Mallawa 
5699c4888c9SWilfred Mallawa static const VMStateDescription vmstate_ibex = {
5709c4888c9SWilfred Mallawa     .name = TYPE_IBEX_SPI_HOST,
5719c4888c9SWilfred Mallawa     .version_id = 1,
5729c4888c9SWilfred Mallawa     .minimum_version_id = 1,
5730aa6c7dfSRichard Henderson     .fields = (const VMStateField[]) {
5749c4888c9SWilfred Mallawa         VMSTATE_UINT32_ARRAY(regs, IbexSPIHostState, IBEX_SPI_HOST_MAX_REGS),
5759c4888c9SWilfred Mallawa         VMSTATE_VARRAY_UINT32(config_opts, IbexSPIHostState,
5769c4888c9SWilfred Mallawa                               num_cs, 0, vmstate_info_uint32, uint32_t),
5779c4888c9SWilfred Mallawa         VMSTATE_FIFO8(rx_fifo, IbexSPIHostState),
5789c4888c9SWilfred Mallawa         VMSTATE_FIFO8(tx_fifo, IbexSPIHostState),
5799c4888c9SWilfred Mallawa         VMSTATE_TIMER_PTR(fifo_trigger_handle, IbexSPIHostState),
5809c4888c9SWilfred Mallawa         VMSTATE_BOOL(init_status, IbexSPIHostState),
5819c4888c9SWilfred Mallawa         VMSTATE_END_OF_LIST()
5829c4888c9SWilfred Mallawa     }
5839c4888c9SWilfred Mallawa };
5849c4888c9SWilfred Mallawa 
fifo_trigger_update(void * opaque)5859c4888c9SWilfred Mallawa static void fifo_trigger_update(void *opaque)
5869c4888c9SWilfred Mallawa {
5879c4888c9SWilfred Mallawa     IbexSPIHostState *s = opaque;
5889c4888c9SWilfred Mallawa     ibex_spi_host_transfer(s);
5899c4888c9SWilfred Mallawa }
5909c4888c9SWilfred Mallawa 
ibex_spi_host_realize(DeviceState * dev,Error ** errp)5919c4888c9SWilfred Mallawa static void ibex_spi_host_realize(DeviceState *dev, Error **errp)
5929c4888c9SWilfred Mallawa {
5939c4888c9SWilfred Mallawa     IbexSPIHostState *s = IBEX_SPI_HOST(dev);
5949c4888c9SWilfred Mallawa     int i;
5959c4888c9SWilfred Mallawa 
5969c4888c9SWilfred Mallawa     s->ssi = ssi_create_bus(dev, "ssi");
5979c4888c9SWilfred Mallawa     s->cs_lines = g_new0(qemu_irq, s->num_cs);
5989c4888c9SWilfred Mallawa 
5999c4888c9SWilfred Mallawa     for (i = 0; i < s->num_cs; ++i) {
6009c4888c9SWilfred Mallawa         sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->cs_lines[i]);
6019c4888c9SWilfred Mallawa     }
6029c4888c9SWilfred Mallawa 
6039c4888c9SWilfred Mallawa     /* Setup CONFIGOPTS Multi-register */
6049c4888c9SWilfred Mallawa     s->config_opts = g_new0(uint32_t, s->num_cs);
6059c4888c9SWilfred Mallawa 
6069c4888c9SWilfred Mallawa     /* Setup FIFO Interrupt Timer */
6079c4888c9SWilfred Mallawa     s->fifo_trigger_handle = timer_new_ns(QEMU_CLOCK_VIRTUAL,
6089c4888c9SWilfred Mallawa                                           fifo_trigger_update, s);
6099c4888c9SWilfred Mallawa 
6109c4888c9SWilfred Mallawa     /* FIFO sizes as per OT Spec */
6119c4888c9SWilfred Mallawa     fifo8_create(&s->tx_fifo, IBEX_SPI_HOST_TXFIFO_LEN);
6129c4888c9SWilfred Mallawa     fifo8_create(&s->rx_fifo, IBEX_SPI_HOST_RXFIFO_LEN);
6139c4888c9SWilfred Mallawa }
6149c4888c9SWilfred Mallawa 
ibex_spi_host_init(Object * obj)6159c4888c9SWilfred Mallawa static void ibex_spi_host_init(Object *obj)
6169c4888c9SWilfred Mallawa {
6179c4888c9SWilfred Mallawa     IbexSPIHostState *s = IBEX_SPI_HOST(obj);
6189c4888c9SWilfred Mallawa 
6199c4888c9SWilfred Mallawa     sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->host_err);
6209c4888c9SWilfred Mallawa     sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->event);
6219c4888c9SWilfred Mallawa 
6229c4888c9SWilfred Mallawa     memory_region_init_io(&s->mmio, obj, &ibex_spi_ops, s,
6239c4888c9SWilfred Mallawa                           TYPE_IBEX_SPI_HOST, 0x1000);
6249c4888c9SWilfred Mallawa     sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio);
6259c4888c9SWilfred Mallawa }
6269c4888c9SWilfred Mallawa 
ibex_spi_host_class_init(ObjectClass * klass,void * data)6279c4888c9SWilfred Mallawa static void ibex_spi_host_class_init(ObjectClass *klass, void *data)
6289c4888c9SWilfred Mallawa {
6299c4888c9SWilfred Mallawa     DeviceClass *dc = DEVICE_CLASS(klass);
6309c4888c9SWilfred Mallawa     dc->realize = ibex_spi_host_realize;
631*e3d08143SPeter Maydell     device_class_set_legacy_reset(dc, ibex_spi_host_reset);
6329c4888c9SWilfred Mallawa     dc->vmsd = &vmstate_ibex;
6339c4888c9SWilfred Mallawa     device_class_set_props(dc, ibex_spi_properties);
6349c4888c9SWilfred Mallawa }
6359c4888c9SWilfred Mallawa 
6369c4888c9SWilfred Mallawa static const TypeInfo ibex_spi_host_info = {
6379c4888c9SWilfred Mallawa     .name          = TYPE_IBEX_SPI_HOST,
6389c4888c9SWilfred Mallawa     .parent        = TYPE_SYS_BUS_DEVICE,
6399c4888c9SWilfred Mallawa     .instance_size = sizeof(IbexSPIHostState),
6409c4888c9SWilfred Mallawa     .instance_init = ibex_spi_host_init,
6419c4888c9SWilfred Mallawa     .class_init    = ibex_spi_host_class_init,
6429c4888c9SWilfred Mallawa };
6439c4888c9SWilfred Mallawa 
ibex_spi_host_register_types(void)6449c4888c9SWilfred Mallawa static void ibex_spi_host_register_types(void)
6459c4888c9SWilfred Mallawa {
6469c4888c9SWilfred Mallawa     type_register_static(&ibex_spi_host_info);
6479c4888c9SWilfred Mallawa }
6489c4888c9SWilfred Mallawa 
6499c4888c9SWilfred Mallawa type_init(ibex_spi_host_register_types)
650