1 /* 2 * QEMU model of the SiFive SPI Controller 3 * 4 * Copyright (c) 2021 Wind River Systems, Inc. 5 * 6 * Author: 7 * Bin Meng <bin.meng@windriver.com> 8 * 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. 12 * 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 16 * more details. 17 * 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/>. 20 */ 21 22 #include "qemu/osdep.h" 23 #include "hw/irq.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" 29 #include "qemu/log.h" 30 #include "qemu/module.h" 31 #include "hw/ssi/sifive_spi.h" 32 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) 49 50 #define FMT_DIR (1 << 3) 51 52 #define TXDATA_FULL (1 << 31) 53 #define RXDATA_EMPTY (1 << 31) 54 55 #define IE_TXWM (1 << 0) 56 #define IE_RXWM (1 << 1) 57 58 #define IP_TXWM (1 << 0) 59 #define IP_RXWM (1 << 1) 60 61 #define FIFO_CAPACITY 8 62 63 static void sifive_spi_txfifo_reset(SiFiveSPIState *s) 64 { 65 fifo8_reset(&s->tx_fifo); 66 67 s->regs[R_TXDATA] &= ~TXDATA_FULL; 68 s->regs[R_IP] &= ~IP_TXWM; 69 } 70 71 static void sifive_spi_rxfifo_reset(SiFiveSPIState *s) 72 { 73 fifo8_reset(&s->rx_fifo); 74 75 s->regs[R_RXDATA] |= RXDATA_EMPTY; 76 s->regs[R_IP] &= ~IP_RXWM; 77 } 78 79 static void sifive_spi_update_cs(SiFiveSPIState *s) 80 { 81 int i; 82 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])); 86 } 87 } 88 } 89 90 static void sifive_spi_update_irq(SiFiveSPIState *s) 91 { 92 int level; 93 94 if (fifo8_num_used(&s->tx_fifo) < s->regs[R_TXMARK]) { 95 s->regs[R_IP] |= IP_TXWM; 96 } else { 97 s->regs[R_IP] &= ~IP_TXWM; 98 } 99 100 if (fifo8_num_used(&s->rx_fifo) > s->regs[R_RXMARK]) { 101 s->regs[R_IP] |= IP_RXWM; 102 } else { 103 s->regs[R_IP] &= ~IP_RXWM; 104 } 105 106 level = s->regs[R_IP] & s->regs[R_IE] ? 1 : 0; 107 qemu_set_irq(s->irq, level); 108 } 109 110 static void sifive_spi_reset(DeviceState *d) 111 { 112 SiFiveSPIState *s = SIFIVE_SPI(d); 113 114 memset(s->regs, 0, sizeof(s->regs)); 115 116 /* The reset value is high for all implemented CS pins */ 117 s->regs[R_CSDEF] = (1 << s->num_cs) - 1; 118 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; 123 124 sifive_spi_txfifo_reset(s); 125 sifive_spi_rxfifo_reset(s); 126 127 sifive_spi_update_cs(s); 128 sifive_spi_update_irq(s); 129 } 130 131 static void sifive_spi_flush_txfifo(SiFiveSPIState *s) 132 { 133 uint8_t tx; 134 uint8_t rx; 135 136 while (!fifo8_is_empty(&s->tx_fifo)) { 137 tx = fifo8_pop(&s->tx_fifo); 138 rx = ssi_transfer(s->spi, tx); 139 140 if (!fifo8_is_full(&s->rx_fifo)) { 141 if (!(s->regs[R_FMT] & FMT_DIR)) { 142 fifo8_push(&s->rx_fifo, rx); 143 } 144 } 145 } 146 } 147 148 static bool sifive_spi_is_bad_reg(hwaddr addr, bool allow_reserved) 149 { 150 bool bad; 151 152 switch (addr) { 153 /* reserved offsets */ 154 case 0x08: 155 case 0x0C: 156 case 0x1C: 157 case 0x20: 158 case 0x24: 159 case 0x30: 160 case 0x34: 161 case 0x38: 162 case 0x3C: 163 case 0x44: 164 case 0x58: 165 case 0x5C: 166 case 0x68: 167 case 0x6C: 168 bad = allow_reserved ? false : true; 169 break; 170 default: 171 bad = false; 172 } 173 174 if (addr >= (SIFIVE_SPI_REG_NUM << 2)) { 175 bad = true; 176 } 177 178 return bad; 179 } 180 181 static uint64_t sifive_spi_read(void *opaque, hwaddr addr, unsigned int size) 182 { 183 SiFiveSPIState *s = opaque; 184 uint32_t r; 185 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); 189 return 0; 190 } 191 192 addr >>= 2; 193 switch (addr) { 194 case R_TXDATA: 195 if (fifo8_is_full(&s->tx_fifo)) { 196 return TXDATA_FULL; 197 } 198 r = 0; 199 break; 200 201 case R_RXDATA: 202 if (fifo8_is_empty(&s->rx_fifo)) { 203 return RXDATA_EMPTY; 204 } 205 r = fifo8_pop(&s->rx_fifo); 206 break; 207 208 default: 209 r = s->regs[addr]; 210 break; 211 } 212 213 sifive_spi_update_irq(s); 214 215 return r; 216 } 217 218 static void sifive_spi_write(void *opaque, hwaddr addr, 219 uint64_t val64, unsigned int size) 220 { 221 SiFiveSPIState *s = opaque; 222 uint32_t value = val64; 223 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); 227 return; 228 } 229 230 addr >>= 2; 231 switch (addr) { 232 case R_CSID: 233 if (value >= s->num_cs) { 234 qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid csid %d\n", 235 __func__, value); 236 } else { 237 s->regs[R_CSID] = value; 238 sifive_spi_update_cs(s); 239 } 240 break; 241 242 case R_CSDEF: 243 if (value >= (1 << s->num_cs)) { 244 qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid csdef %x\n", 245 __func__, value); 246 } else { 247 s->regs[R_CSDEF] = value; 248 } 249 break; 250 251 case R_CSMODE: 252 if (value > 3) { 253 qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid csmode %x\n", 254 __func__, value); 255 } else { 256 s->regs[R_CSMODE] = value; 257 sifive_spi_update_cs(s); 258 } 259 break; 260 261 case R_TXDATA: 262 if (!fifo8_is_full(&s->tx_fifo)) { 263 fifo8_push(&s->tx_fifo, (uint8_t)value); 264 sifive_spi_flush_txfifo(s); 265 } 266 break; 267 268 case R_RXDATA: 269 case R_IP: 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); 273 break; 274 275 case R_TXMARK: 276 case R_RXMARK: 277 if (value >= FIFO_CAPACITY) { 278 qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid watermark %d\n", 279 __func__, value); 280 } else { 281 s->regs[addr] = value; 282 } 283 break; 284 285 case R_FCTRL: 286 case R_FFMT: 287 qemu_log_mask(LOG_UNIMP, 288 "%s: direct-map flash interface unimplemented\n", 289 __func__); 290 break; 291 292 default: 293 s->regs[addr] = value; 294 break; 295 } 296 297 sifive_spi_update_irq(s); 298 } 299 300 static const MemoryRegionOps sifive_spi_ops = { 301 .read = sifive_spi_read, 302 .write = sifive_spi_write, 303 .endianness = DEVICE_LITTLE_ENDIAN, 304 .valid = { 305 .min_access_size = 4, 306 .max_access_size = 4 307 } 308 }; 309 310 static void sifive_spi_realize(DeviceState *dev, Error **errp) 311 { 312 SysBusDevice *sbd = SYS_BUS_DEVICE(dev); 313 SiFiveSPIState *s = SIFIVE_SPI(dev); 314 int i; 315 316 s->spi = ssi_create_bus(dev, "spi"); 317 sysbus_init_irq(sbd, &s->irq); 318 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]); 322 } 323 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); 327 328 fifo8_create(&s->tx_fifo, FIFO_CAPACITY); 329 fifo8_create(&s->rx_fifo, FIFO_CAPACITY); 330 } 331 332 static Property sifive_spi_properties[] = { 333 DEFINE_PROP_UINT32("num-cs", SiFiveSPIState, num_cs, 1), 334 DEFINE_PROP_END_OF_LIST(), 335 }; 336 337 static void sifive_spi_class_init(ObjectClass *klass, void *data) 338 { 339 DeviceClass *dc = DEVICE_CLASS(klass); 340 341 device_class_set_props(dc, sifive_spi_properties); 342 dc->reset = sifive_spi_reset; 343 dc->realize = sifive_spi_realize; 344 } 345 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, 351 }; 352 353 static void sifive_spi_register_types(void) 354 { 355 type_register_static(&sifive_spi_info); 356 } 357 358 type_init(sifive_spi_register_types) 359