2 * QEMU model of the SiFive SPI Controller
4 * Copyright (c) 2021 Wind River Systems, Inc.
7 * Bin Meng <bin.meng@windriver.com>
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms and conditions of the GNU General Public License,
11 * version 2 or later, as published by the Free Software Foundation.
13 * This program is distributed in the hope it will be useful, but WITHOUT
14 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
18 * You should have received a copy of the GNU General Public License along with
19 * this program. If not, see <http://www.gnu.org/licenses/>.
22 #include "qemu/osdep.h"
24 #include "hw/qdev-properties.h"
25 #include "hw/sysbus.h"
26 #include "hw/ssi/ssi.h"
27 #include "sysemu/sysemu.h"
28 #include "qemu/fifo8.h"
30 #include "qemu/module.h"
31 #include "hw/ssi/sifive_spi.h"
33 #define R_SCKDIV (0x00 / 4)
34 #define R_SCKMODE (0x04 / 4)
35 #define R_CSID (0x10 / 4)
36 #define R_CSDEF (0x14 / 4)
37 #define R_CSMODE (0x18 / 4)
38 #define R_DELAY0 (0x28 / 4)
39 #define R_DELAY1 (0x2C / 4)
40 #define R_FMT (0x40 / 4)
41 #define R_TXDATA (0x48 / 4)
42 #define R_RXDATA (0x4C / 4)
43 #define R_TXMARK (0x50 / 4)
44 #define R_RXMARK (0x54 / 4)
45 #define R_FCTRL (0x60 / 4)
46 #define R_FFMT (0x64 / 4)
47 #define R_IE (0x70 / 4)
48 #define R_IP (0x74 / 4)
50 #define FMT_DIR (1 << 3)
52 #define TXDATA_FULL (1 << 31)
53 #define RXDATA_EMPTY (1 << 31)
55 #define IE_TXWM (1 << 0)
56 #define IE_RXWM (1 << 1)
58 #define IP_TXWM (1 << 0)
59 #define IP_RXWM (1 << 1)
61 #define FIFO_CAPACITY 8
63 static void sifive_spi_txfifo_reset(SiFiveSPIState
*s
)
65 fifo8_reset(&s
->tx_fifo
);
67 s
->regs
[R_TXDATA
] &= ~TXDATA_FULL
;
68 s
->regs
[R_IP
] &= ~IP_TXWM
;
71 static void sifive_spi_rxfifo_reset(SiFiveSPIState
*s
)
73 fifo8_reset(&s
->rx_fifo
);
75 s
->regs
[R_RXDATA
] |= RXDATA_EMPTY
;
76 s
->regs
[R_IP
] &= ~IP_RXWM
;
79 static void sifive_spi_update_cs(SiFiveSPIState
*s
)
83 for (i
= 0; i
< s
->num_cs
; i
++) {
84 if (s
->regs
[R_CSDEF
] & (1 << i
)) {
85 qemu_set_irq(s
->cs_lines
[i
], !(s
->regs
[R_CSMODE
]));
90 static void sifive_spi_update_irq(SiFiveSPIState
*s
)
94 if (fifo8_num_used(&s
->tx_fifo
) < s
->regs
[R_TXMARK
]) {
95 s
->regs
[R_IP
] |= IP_TXWM
;
97 s
->regs
[R_IP
] &= ~IP_TXWM
;
100 if (fifo8_num_used(&s
->rx_fifo
) > s
->regs
[R_RXMARK
]) {
101 s
->regs
[R_IP
] |= IP_RXWM
;
103 s
->regs
[R_IP
] &= ~IP_RXWM
;
106 level
= s
->regs
[R_IP
] & s
->regs
[R_IE
] ? 1 : 0;
107 qemu_set_irq(s
->irq
, level
);
110 static void sifive_spi_reset(DeviceState
*d
)
112 SiFiveSPIState
*s
= SIFIVE_SPI(d
);
114 memset(s
->regs
, 0, sizeof(s
->regs
));
116 /* The reset value is high for all implemented CS pins */
117 s
->regs
[R_CSDEF
] = (1 << s
->num_cs
) - 1;
119 /* Populate register with their default value */
120 s
->regs
[R_SCKDIV
] = 0x03;
121 s
->regs
[R_DELAY0
] = 0x1001;
122 s
->regs
[R_DELAY1
] = 0x01;
124 sifive_spi_txfifo_reset(s
);
125 sifive_spi_rxfifo_reset(s
);
127 sifive_spi_update_cs(s
);
128 sifive_spi_update_irq(s
);
131 static void sifive_spi_flush_txfifo(SiFiveSPIState
*s
)
136 while (!fifo8_is_empty(&s
->tx_fifo
)) {
137 tx
= fifo8_pop(&s
->tx_fifo
);
138 rx
= ssi_transfer(s
->spi
, tx
);
140 if (!fifo8_is_full(&s
->rx_fifo
)) {
141 if (!(s
->regs
[R_FMT
] & FMT_DIR
)) {
142 fifo8_push(&s
->rx_fifo
, rx
);
148 static bool sifive_spi_is_bad_reg(hwaddr addr
, bool allow_reserved
)
153 /* reserved offsets */
168 bad
= allow_reserved
? false : true;
174 if (addr
>= (SIFIVE_SPI_REG_NUM
<< 2)) {
181 static uint64_t sifive_spi_read(void *opaque
, hwaddr addr
, unsigned int size
)
183 SiFiveSPIState
*s
= opaque
;
186 if (sifive_spi_is_bad_reg(addr
, true)) {
187 qemu_log_mask(LOG_GUEST_ERROR
, "%s: bad read at address 0x%"
188 HWADDR_PRIx
"\n", __func__
, addr
);
195 if (fifo8_is_full(&s
->tx_fifo
)) {
202 if (fifo8_is_empty(&s
->rx_fifo
)) {
205 r
= fifo8_pop(&s
->rx_fifo
);
213 sifive_spi_update_irq(s
);
218 static void sifive_spi_write(void *opaque
, hwaddr addr
,
219 uint64_t val64
, unsigned int size
)
221 SiFiveSPIState
*s
= opaque
;
222 uint32_t value
= val64
;
224 if (sifive_spi_is_bad_reg(addr
, false)) {
225 qemu_log_mask(LOG_GUEST_ERROR
, "%s: bad write at addr=0x%"
226 HWADDR_PRIx
" value=0x%x\n", __func__
, addr
, value
);
233 if (value
>= s
->num_cs
) {
234 qemu_log_mask(LOG_GUEST_ERROR
, "%s: invalid csid %d\n",
237 s
->regs
[R_CSID
] = value
;
238 sifive_spi_update_cs(s
);
243 if (value
>= (1 << s
->num_cs
)) {
244 qemu_log_mask(LOG_GUEST_ERROR
, "%s: invalid csdef %x\n",
247 s
->regs
[R_CSDEF
] = value
;
253 qemu_log_mask(LOG_GUEST_ERROR
, "%s: invalid csmode %x\n",
256 s
->regs
[R_CSMODE
] = value
;
257 sifive_spi_update_cs(s
);
262 if (!fifo8_is_full(&s
->tx_fifo
)) {
263 fifo8_push(&s
->tx_fifo
, (uint8_t)value
);
264 sifive_spi_flush_txfifo(s
);
270 qemu_log_mask(LOG_GUEST_ERROR
,
271 "%s: invalid write to read-only reigster 0x%"
272 HWADDR_PRIx
" with 0x%x\n", __func__
, addr
<< 2, value
);
277 if (value
>= FIFO_CAPACITY
) {
278 qemu_log_mask(LOG_GUEST_ERROR
, "%s: invalid watermark %d\n",
281 s
->regs
[addr
] = value
;
287 qemu_log_mask(LOG_UNIMP
,
288 "%s: direct-map flash interface unimplemented\n",
293 s
->regs
[addr
] = value
;
297 sifive_spi_update_irq(s
);
300 static const MemoryRegionOps sifive_spi_ops
= {
301 .read
= sifive_spi_read
,
302 .write
= sifive_spi_write
,
303 .endianness
= DEVICE_LITTLE_ENDIAN
,
305 .min_access_size
= 4,
310 static void sifive_spi_realize(DeviceState
*dev
, Error
**errp
)
312 SysBusDevice
*sbd
= SYS_BUS_DEVICE(dev
);
313 SiFiveSPIState
*s
= SIFIVE_SPI(dev
);
316 s
->spi
= ssi_create_bus(dev
, "spi");
317 sysbus_init_irq(sbd
, &s
->irq
);
319 s
->cs_lines
= g_new0(qemu_irq
, s
->num_cs
);
320 for (i
= 0; i
< s
->num_cs
; i
++) {
321 sysbus_init_irq(sbd
, &s
->cs_lines
[i
]);
324 memory_region_init_io(&s
->mmio
, OBJECT(s
), &sifive_spi_ops
, s
,
325 TYPE_SIFIVE_SPI
, 0x1000);
326 sysbus_init_mmio(sbd
, &s
->mmio
);
328 fifo8_create(&s
->tx_fifo
, FIFO_CAPACITY
);
329 fifo8_create(&s
->rx_fifo
, FIFO_CAPACITY
);
332 static Property sifive_spi_properties
[] = {
333 DEFINE_PROP_UINT32("num-cs", SiFiveSPIState
, num_cs
, 1),
334 DEFINE_PROP_END_OF_LIST(),
337 static void sifive_spi_class_init(ObjectClass
*klass
, void *data
)
339 DeviceClass
*dc
= DEVICE_CLASS(klass
);
341 device_class_set_props(dc
, sifive_spi_properties
);
342 dc
->reset
= sifive_spi_reset
;
343 dc
->realize
= sifive_spi_realize
;
346 static const TypeInfo sifive_spi_info
= {
347 .name
= TYPE_SIFIVE_SPI
,
348 .parent
= TYPE_SYS_BUS_DEVICE
,
349 .instance_size
= sizeof(SiFiveSPIState
),
350 .class_init
= sifive_spi_class_init
,
353 static void sifive_spi_register_types(void)
355 type_register_static(&sifive_spi_info
);
358 type_init(sifive_spi_register_types
)