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 "qemu/fifo8.h"
29 #include "qemu/module.h"
30 #include "hw/ssi/sifive_spi.h"
32 #define R_SCKDIV (0x00 / 4)
33 #define R_SCKMODE (0x04 / 4)
34 #define R_CSID (0x10 / 4)
35 #define R_CSDEF (0x14 / 4)
36 #define R_CSMODE (0x18 / 4)
37 #define R_DELAY0 (0x28 / 4)
38 #define R_DELAY1 (0x2C / 4)
39 #define R_FMT (0x40 / 4)
40 #define R_TXDATA (0x48 / 4)
41 #define R_RXDATA (0x4C / 4)
42 #define R_TXMARK (0x50 / 4)
43 #define R_RXMARK (0x54 / 4)
44 #define R_FCTRL (0x60 / 4)
45 #define R_FFMT (0x64 / 4)
46 #define R_IE (0x70 / 4)
47 #define R_IP (0x74 / 4)
49 #define FMT_DIR (1 << 3)
51 #define TXDATA_FULL (1 << 31)
52 #define RXDATA_EMPTY (1 << 31)
54 #define IE_TXWM (1 << 0)
55 #define IE_RXWM (1 << 1)
57 #define IP_TXWM (1 << 0)
58 #define IP_RXWM (1 << 1)
60 #define FIFO_CAPACITY 8
62 static void sifive_spi_txfifo_reset(SiFiveSPIState
*s
)
64 fifo8_reset(&s
->tx_fifo
);
66 s
->regs
[R_TXDATA
] &= ~TXDATA_FULL
;
67 s
->regs
[R_IP
] &= ~IP_TXWM
;
70 static void sifive_spi_rxfifo_reset(SiFiveSPIState
*s
)
72 fifo8_reset(&s
->rx_fifo
);
74 s
->regs
[R_RXDATA
] |= RXDATA_EMPTY
;
75 s
->regs
[R_IP
] &= ~IP_RXWM
;
78 static void sifive_spi_update_cs(SiFiveSPIState
*s
)
82 for (i
= 0; i
< s
->num_cs
; i
++) {
83 if (s
->regs
[R_CSDEF
] & (1 << i
)) {
84 qemu_set_irq(s
->cs_lines
[i
], !(s
->regs
[R_CSMODE
]));
89 static void sifive_spi_update_irq(SiFiveSPIState
*s
)
93 if (fifo8_num_used(&s
->tx_fifo
) < s
->regs
[R_TXMARK
]) {
94 s
->regs
[R_IP
] |= IP_TXWM
;
96 s
->regs
[R_IP
] &= ~IP_TXWM
;
99 if (fifo8_num_used(&s
->rx_fifo
) > s
->regs
[R_RXMARK
]) {
100 s
->regs
[R_IP
] |= IP_RXWM
;
102 s
->regs
[R_IP
] &= ~IP_RXWM
;
105 level
= s
->regs
[R_IP
] & s
->regs
[R_IE
] ? 1 : 0;
106 qemu_set_irq(s
->irq
, level
);
109 static void sifive_spi_reset(DeviceState
*d
)
111 SiFiveSPIState
*s
= SIFIVE_SPI(d
);
113 memset(s
->regs
, 0, sizeof(s
->regs
));
115 /* The reset value is high for all implemented CS pins */
116 s
->regs
[R_CSDEF
] = (1 << s
->num_cs
) - 1;
118 /* Populate register with their default value */
119 s
->regs
[R_SCKDIV
] = 0x03;
120 s
->regs
[R_DELAY0
] = 0x1001;
121 s
->regs
[R_DELAY1
] = 0x01;
123 sifive_spi_txfifo_reset(s
);
124 sifive_spi_rxfifo_reset(s
);
126 sifive_spi_update_cs(s
);
127 sifive_spi_update_irq(s
);
130 static void sifive_spi_flush_txfifo(SiFiveSPIState
*s
)
135 while (!fifo8_is_empty(&s
->tx_fifo
)) {
136 tx
= fifo8_pop(&s
->tx_fifo
);
137 rx
= ssi_transfer(s
->spi
, tx
);
139 if (!fifo8_is_full(&s
->rx_fifo
)) {
140 if (!(s
->regs
[R_FMT
] & FMT_DIR
)) {
141 fifo8_push(&s
->rx_fifo
, rx
);
147 static bool sifive_spi_is_bad_reg(hwaddr addr
, bool allow_reserved
)
152 /* reserved offsets */
167 bad
= allow_reserved
? false : true;
173 if (addr
>= (SIFIVE_SPI_REG_NUM
<< 2)) {
180 static uint64_t sifive_spi_read(void *opaque
, hwaddr addr
, unsigned int size
)
182 SiFiveSPIState
*s
= opaque
;
185 if (sifive_spi_is_bad_reg(addr
, true)) {
186 qemu_log_mask(LOG_GUEST_ERROR
, "%s: bad read at address 0x%"
187 HWADDR_PRIx
"\n", __func__
, addr
);
194 if (fifo8_is_full(&s
->tx_fifo
)) {
201 if (fifo8_is_empty(&s
->rx_fifo
)) {
204 r
= fifo8_pop(&s
->rx_fifo
);
212 sifive_spi_update_irq(s
);
217 static void sifive_spi_write(void *opaque
, hwaddr addr
,
218 uint64_t val64
, unsigned int size
)
220 SiFiveSPIState
*s
= opaque
;
221 uint32_t value
= val64
;
223 if (sifive_spi_is_bad_reg(addr
, false)) {
224 qemu_log_mask(LOG_GUEST_ERROR
, "%s: bad write at addr=0x%"
225 HWADDR_PRIx
" value=0x%x\n", __func__
, addr
, value
);
232 if (value
>= s
->num_cs
) {
233 qemu_log_mask(LOG_GUEST_ERROR
, "%s: invalid csid %d\n",
236 s
->regs
[R_CSID
] = value
;
237 sifive_spi_update_cs(s
);
242 if (value
>= (1 << s
->num_cs
)) {
243 qemu_log_mask(LOG_GUEST_ERROR
, "%s: invalid csdef %x\n",
246 s
->regs
[R_CSDEF
] = value
;
252 qemu_log_mask(LOG_GUEST_ERROR
, "%s: invalid csmode %x\n",
255 s
->regs
[R_CSMODE
] = value
;
256 sifive_spi_update_cs(s
);
261 if (!fifo8_is_full(&s
->tx_fifo
)) {
262 fifo8_push(&s
->tx_fifo
, (uint8_t)value
);
263 sifive_spi_flush_txfifo(s
);
269 qemu_log_mask(LOG_GUEST_ERROR
,
270 "%s: invalid write to read-only reigster 0x%"
271 HWADDR_PRIx
" with 0x%x\n", __func__
, addr
<< 2, value
);
276 if (value
>= FIFO_CAPACITY
) {
277 qemu_log_mask(LOG_GUEST_ERROR
, "%s: invalid watermark %d\n",
280 s
->regs
[addr
] = value
;
286 qemu_log_mask(LOG_UNIMP
,
287 "%s: direct-map flash interface unimplemented\n",
292 s
->regs
[addr
] = value
;
296 sifive_spi_update_irq(s
);
299 static const MemoryRegionOps sifive_spi_ops
= {
300 .read
= sifive_spi_read
,
301 .write
= sifive_spi_write
,
302 .endianness
= DEVICE_LITTLE_ENDIAN
,
304 .min_access_size
= 4,
309 static void sifive_spi_realize(DeviceState
*dev
, Error
**errp
)
311 SysBusDevice
*sbd
= SYS_BUS_DEVICE(dev
);
312 SiFiveSPIState
*s
= SIFIVE_SPI(dev
);
315 s
->spi
= ssi_create_bus(dev
, "spi");
316 sysbus_init_irq(sbd
, &s
->irq
);
318 s
->cs_lines
= g_new0(qemu_irq
, s
->num_cs
);
319 for (i
= 0; i
< s
->num_cs
; i
++) {
320 sysbus_init_irq(sbd
, &s
->cs_lines
[i
]);
323 memory_region_init_io(&s
->mmio
, OBJECT(s
), &sifive_spi_ops
, s
,
324 TYPE_SIFIVE_SPI
, 0x1000);
325 sysbus_init_mmio(sbd
, &s
->mmio
);
327 fifo8_create(&s
->tx_fifo
, FIFO_CAPACITY
);
328 fifo8_create(&s
->rx_fifo
, FIFO_CAPACITY
);
331 static Property sifive_spi_properties
[] = {
332 DEFINE_PROP_UINT32("num-cs", SiFiveSPIState
, num_cs
, 1),
333 DEFINE_PROP_END_OF_LIST(),
336 static void sifive_spi_class_init(ObjectClass
*klass
, void *data
)
338 DeviceClass
*dc
= DEVICE_CLASS(klass
);
340 device_class_set_props(dc
, sifive_spi_properties
);
341 dc
->reset
= sifive_spi_reset
;
342 dc
->realize
= sifive_spi_realize
;
345 static const TypeInfo sifive_spi_info
= {
346 .name
= TYPE_SIFIVE_SPI
,
347 .parent
= TYPE_SYS_BUS_DEVICE
,
348 .instance_size
= sizeof(SiFiveSPIState
),
349 .class_init
= sifive_spi_class_init
,
352 static void sifive_spi_register_types(void)
354 type_register_static(&sifive_spi_info
);
357 type_init(sifive_spi_register_types
)