qemu with hax to log dma reads & writes jcs.org/2018/11/12/vfio

msf2: Add Smartfusion2 SPI controller

Modelled Microsemi's Smartfusion2 SPI controller.

Signed-off-by: Subbaraya Sundeep <sundeep.lkml@gmail.com>
Reviewed-by: Alistair Francis <alistair.francis@xilinx.com>
Tested-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
Message-id: 20170920201737.25723-4-f4bug@amsat.org
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>

authored by

Subbaraya Sundeep and committed by
Peter Maydell
268ee7de 0ee1e1f4

+463
+1
hw/ssi/Makefile.objs
··· 4 4 common-obj-$(CONFIG_XILINX_SPIPS) += xilinx_spips.o 5 5 common-obj-$(CONFIG_ASPEED_SOC) += aspeed_smc.o 6 6 common-obj-$(CONFIG_STM32F2XX_SPI) += stm32f2xx_spi.o 7 + common-obj-$(CONFIG_MSF2) += mss-spi.o 7 8 8 9 obj-$(CONFIG_OMAP) += omap_spi.o 9 10 obj-$(CONFIG_IMX) += imx_spi.o
+404
hw/ssi/mss-spi.c
··· 1 + /* 2 + * Block model of SPI controller present in 3 + * Microsemi's SmartFusion2 and SmartFusion SoCs. 4 + * 5 + * Copyright (C) 2017 Subbaraya Sundeep <sundeep.lkml@gmail.com> 6 + * 7 + * Permission is hereby granted, free of charge, to any person obtaining a copy 8 + * of this software and associated documentation files (the "Software"), to deal 9 + * in the Software without restriction, including without limitation the rights 10 + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 + * copies of the Software, and to permit persons to whom the Software is 12 + * furnished to do so, subject to the following conditions: 13 + * 14 + * The above copyright notice and this permission notice shall be included in 15 + * all copies or substantial portions of the Software. 16 + * 17 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 + * THE SOFTWARE. 24 + */ 25 + 26 + #include "qemu/osdep.h" 27 + #include "hw/ssi/mss-spi.h" 28 + #include "qemu/log.h" 29 + 30 + #ifndef MSS_SPI_ERR_DEBUG 31 + #define MSS_SPI_ERR_DEBUG 0 32 + #endif 33 + 34 + #define DB_PRINT_L(lvl, fmt, args...) do { \ 35 + if (MSS_SPI_ERR_DEBUG >= lvl) { \ 36 + qemu_log("%s: " fmt "\n", __func__, ## args); \ 37 + } \ 38 + } while (0); 39 + 40 + #define DB_PRINT(fmt, args...) DB_PRINT_L(1, fmt, ## args) 41 + 42 + #define FIFO_CAPACITY 32 43 + 44 + #define R_SPI_CONTROL 0 45 + #define R_SPI_DFSIZE 1 46 + #define R_SPI_STATUS 2 47 + #define R_SPI_INTCLR 3 48 + #define R_SPI_RX 4 49 + #define R_SPI_TX 5 50 + #define R_SPI_CLKGEN 6 51 + #define R_SPI_SS 7 52 + #define R_SPI_MIS 8 53 + #define R_SPI_RIS 9 54 + 55 + #define S_TXDONE (1 << 0) 56 + #define S_RXRDY (1 << 1) 57 + #define S_RXCHOVRF (1 << 2) 58 + #define S_RXFIFOFUL (1 << 4) 59 + #define S_RXFIFOFULNXT (1 << 5) 60 + #define S_RXFIFOEMP (1 << 6) 61 + #define S_RXFIFOEMPNXT (1 << 7) 62 + #define S_TXFIFOFUL (1 << 8) 63 + #define S_TXFIFOFULNXT (1 << 9) 64 + #define S_TXFIFOEMP (1 << 10) 65 + #define S_TXFIFOEMPNXT (1 << 11) 66 + #define S_FRAMESTART (1 << 12) 67 + #define S_SSEL (1 << 13) 68 + #define S_ACTIVE (1 << 14) 69 + 70 + #define C_ENABLE (1 << 0) 71 + #define C_MODE (1 << 1) 72 + #define C_INTRXDATA (1 << 4) 73 + #define C_INTTXDATA (1 << 5) 74 + #define C_INTRXOVRFLO (1 << 6) 75 + #define C_SPS (1 << 26) 76 + #define C_BIGFIFO (1 << 29) 77 + #define C_RESET (1 << 31) 78 + 79 + #define FRAMESZ_MASK 0x1F 80 + #define FMCOUNT_MASK 0x00FFFF00 81 + #define FMCOUNT_SHIFT 8 82 + 83 + static void txfifo_reset(MSSSpiState *s) 84 + { 85 + fifo32_reset(&s->tx_fifo); 86 + 87 + s->regs[R_SPI_STATUS] &= ~S_TXFIFOFUL; 88 + s->regs[R_SPI_STATUS] |= S_TXFIFOEMP; 89 + } 90 + 91 + static void rxfifo_reset(MSSSpiState *s) 92 + { 93 + fifo32_reset(&s->rx_fifo); 94 + 95 + s->regs[R_SPI_STATUS] &= ~S_RXFIFOFUL; 96 + s->regs[R_SPI_STATUS] |= S_RXFIFOEMP; 97 + } 98 + 99 + static void set_fifodepth(MSSSpiState *s) 100 + { 101 + unsigned int size = s->regs[R_SPI_DFSIZE] & FRAMESZ_MASK; 102 + 103 + if (size <= 8) { 104 + s->fifo_depth = 32; 105 + } else if (size <= 16) { 106 + s->fifo_depth = 16; 107 + } else if (size <= 32) { 108 + s->fifo_depth = 8; 109 + } else { 110 + s->fifo_depth = 4; 111 + } 112 + } 113 + 114 + static void update_mis(MSSSpiState *s) 115 + { 116 + uint32_t reg = s->regs[R_SPI_CONTROL]; 117 + uint32_t tmp; 118 + 119 + /* 120 + * form the Control register interrupt enable bits 121 + * same as RIS, MIS and Interrupt clear registers for simplicity 122 + */ 123 + tmp = ((reg & C_INTRXOVRFLO) >> 4) | ((reg & C_INTRXDATA) >> 3) | 124 + ((reg & C_INTTXDATA) >> 5); 125 + s->regs[R_SPI_MIS] |= tmp & s->regs[R_SPI_RIS]; 126 + } 127 + 128 + static void spi_update_irq(MSSSpiState *s) 129 + { 130 + int irq; 131 + 132 + update_mis(s); 133 + irq = !!(s->regs[R_SPI_MIS]); 134 + 135 + qemu_set_irq(s->irq, irq); 136 + } 137 + 138 + static void mss_spi_reset(DeviceState *d) 139 + { 140 + MSSSpiState *s = MSS_SPI(d); 141 + 142 + memset(s->regs, 0, sizeof s->regs); 143 + s->regs[R_SPI_CONTROL] = 0x80000102; 144 + s->regs[R_SPI_DFSIZE] = 0x4; 145 + s->regs[R_SPI_STATUS] = S_SSEL | S_TXFIFOEMP | S_RXFIFOEMP; 146 + s->regs[R_SPI_CLKGEN] = 0x7; 147 + s->regs[R_SPI_RIS] = 0x0; 148 + 149 + s->fifo_depth = 4; 150 + s->frame_count = 1; 151 + s->enabled = false; 152 + 153 + rxfifo_reset(s); 154 + txfifo_reset(s); 155 + } 156 + 157 + static uint64_t 158 + spi_read(void *opaque, hwaddr addr, unsigned int size) 159 + { 160 + MSSSpiState *s = opaque; 161 + uint32_t ret = 0; 162 + 163 + addr >>= 2; 164 + switch (addr) { 165 + case R_SPI_RX: 166 + s->regs[R_SPI_STATUS] &= ~S_RXFIFOFUL; 167 + s->regs[R_SPI_STATUS] &= ~S_RXCHOVRF; 168 + ret = fifo32_pop(&s->rx_fifo); 169 + if (fifo32_is_empty(&s->rx_fifo)) { 170 + s->regs[R_SPI_STATUS] |= S_RXFIFOEMP; 171 + } 172 + break; 173 + 174 + case R_SPI_MIS: 175 + update_mis(s); 176 + ret = s->regs[R_SPI_MIS]; 177 + break; 178 + 179 + default: 180 + if (addr < ARRAY_SIZE(s->regs)) { 181 + ret = s->regs[addr]; 182 + } else { 183 + qemu_log_mask(LOG_GUEST_ERROR, 184 + "%s: Bad offset 0x%" HWADDR_PRIx "\n", __func__, 185 + addr * 4); 186 + return ret; 187 + } 188 + break; 189 + } 190 + 191 + DB_PRINT("addr=0x%" HWADDR_PRIx " = 0x%" PRIx32, addr * 4, ret); 192 + spi_update_irq(s); 193 + return ret; 194 + } 195 + 196 + static void assert_cs(MSSSpiState *s) 197 + { 198 + qemu_set_irq(s->cs_line, 0); 199 + } 200 + 201 + static void deassert_cs(MSSSpiState *s) 202 + { 203 + qemu_set_irq(s->cs_line, 1); 204 + } 205 + 206 + static void spi_flush_txfifo(MSSSpiState *s) 207 + { 208 + uint32_t tx; 209 + uint32_t rx; 210 + bool sps = !!(s->regs[R_SPI_CONTROL] & C_SPS); 211 + 212 + /* 213 + * Chip Select(CS) is automatically controlled by this controller. 214 + * If SPS bit is set in Control register then CS is asserted 215 + * until all the frames set in frame count of Control register are 216 + * transferred. If SPS is not set then CS pulses between frames. 217 + * Note that Slave Select register specifies which of the CS line 218 + * has to be controlled automatically by controller. Bits SS[7:1] are for 219 + * masters in FPGA fabric since we model only Microcontroller subsystem 220 + * of Smartfusion2 we control only one CS(SS[0]) line. 221 + */ 222 + while (!fifo32_is_empty(&s->tx_fifo) && s->frame_count) { 223 + assert_cs(s); 224 + 225 + s->regs[R_SPI_STATUS] &= ~(S_TXDONE | S_RXRDY); 226 + 227 + tx = fifo32_pop(&s->tx_fifo); 228 + DB_PRINT("data tx:0x%" PRIx32, tx); 229 + rx = ssi_transfer(s->spi, tx); 230 + DB_PRINT("data rx:0x%" PRIx32, rx); 231 + 232 + if (fifo32_num_used(&s->rx_fifo) == s->fifo_depth) { 233 + s->regs[R_SPI_STATUS] |= S_RXCHOVRF; 234 + s->regs[R_SPI_RIS] |= S_RXCHOVRF; 235 + } else { 236 + fifo32_push(&s->rx_fifo, rx); 237 + s->regs[R_SPI_STATUS] &= ~S_RXFIFOEMP; 238 + if (fifo32_num_used(&s->rx_fifo) == (s->fifo_depth - 1)) { 239 + s->regs[R_SPI_STATUS] |= S_RXFIFOFULNXT; 240 + } else if (fifo32_num_used(&s->rx_fifo) == s->fifo_depth) { 241 + s->regs[R_SPI_STATUS] |= S_RXFIFOFUL; 242 + } 243 + } 244 + s->frame_count--; 245 + if (!sps) { 246 + deassert_cs(s); 247 + } 248 + } 249 + 250 + if (!s->frame_count) { 251 + s->frame_count = (s->regs[R_SPI_CONTROL] & FMCOUNT_MASK) >> 252 + FMCOUNT_SHIFT; 253 + deassert_cs(s); 254 + s->regs[R_SPI_RIS] |= S_TXDONE | S_RXRDY; 255 + s->regs[R_SPI_STATUS] |= S_TXDONE | S_RXRDY; 256 + } 257 + } 258 + 259 + static void spi_write(void *opaque, hwaddr addr, 260 + uint64_t val64, unsigned int size) 261 + { 262 + MSSSpiState *s = opaque; 263 + uint32_t value = val64; 264 + 265 + DB_PRINT("addr=0x%" HWADDR_PRIx " =0x%" PRIx32, addr, value); 266 + addr >>= 2; 267 + 268 + switch (addr) { 269 + case R_SPI_TX: 270 + /* adding to already full FIFO */ 271 + if (fifo32_num_used(&s->tx_fifo) == s->fifo_depth) { 272 + break; 273 + } 274 + s->regs[R_SPI_STATUS] &= ~S_TXFIFOEMP; 275 + fifo32_push(&s->tx_fifo, value); 276 + if (fifo32_num_used(&s->tx_fifo) == (s->fifo_depth - 1)) { 277 + s->regs[R_SPI_STATUS] |= S_TXFIFOFULNXT; 278 + } else if (fifo32_num_used(&s->tx_fifo) == s->fifo_depth) { 279 + s->regs[R_SPI_STATUS] |= S_TXFIFOFUL; 280 + } 281 + if (s->enabled) { 282 + spi_flush_txfifo(s); 283 + } 284 + break; 285 + 286 + case R_SPI_CONTROL: 287 + s->regs[R_SPI_CONTROL] = value; 288 + if (value & C_BIGFIFO) { 289 + set_fifodepth(s); 290 + } else { 291 + s->fifo_depth = 4; 292 + } 293 + s->enabled = value & C_ENABLE; 294 + s->frame_count = (value & FMCOUNT_MASK) >> FMCOUNT_SHIFT; 295 + if (value & C_RESET) { 296 + mss_spi_reset(DEVICE(s)); 297 + } 298 + break; 299 + 300 + case R_SPI_DFSIZE: 301 + if (s->enabled) { 302 + break; 303 + } 304 + s->regs[R_SPI_DFSIZE] = value; 305 + break; 306 + 307 + case R_SPI_INTCLR: 308 + s->regs[R_SPI_INTCLR] = value; 309 + if (value & S_TXDONE) { 310 + s->regs[R_SPI_RIS] &= ~S_TXDONE; 311 + } 312 + if (value & S_RXRDY) { 313 + s->regs[R_SPI_RIS] &= ~S_RXRDY; 314 + } 315 + if (value & S_RXCHOVRF) { 316 + s->regs[R_SPI_RIS] &= ~S_RXCHOVRF; 317 + } 318 + break; 319 + 320 + case R_SPI_MIS: 321 + case R_SPI_STATUS: 322 + case R_SPI_RIS: 323 + qemu_log_mask(LOG_GUEST_ERROR, 324 + "%s: Write to read only register 0x%" HWADDR_PRIx "\n", 325 + __func__, addr * 4); 326 + break; 327 + 328 + default: 329 + if (addr < ARRAY_SIZE(s->regs)) { 330 + s->regs[addr] = value; 331 + } else { 332 + qemu_log_mask(LOG_GUEST_ERROR, 333 + "%s: Bad offset 0x%" HWADDR_PRIx "\n", __func__, 334 + addr * 4); 335 + } 336 + break; 337 + } 338 + 339 + spi_update_irq(s); 340 + } 341 + 342 + static const MemoryRegionOps spi_ops = { 343 + .read = spi_read, 344 + .write = spi_write, 345 + .endianness = DEVICE_NATIVE_ENDIAN, 346 + .valid = { 347 + .min_access_size = 1, 348 + .max_access_size = 4 349 + } 350 + }; 351 + 352 + static void mss_spi_realize(DeviceState *dev, Error **errp) 353 + { 354 + MSSSpiState *s = MSS_SPI(dev); 355 + SysBusDevice *sbd = SYS_BUS_DEVICE(dev); 356 + 357 + s->spi = ssi_create_bus(dev, "spi"); 358 + 359 + sysbus_init_irq(sbd, &s->irq); 360 + ssi_auto_connect_slaves(dev, &s->cs_line, s->spi); 361 + sysbus_init_irq(sbd, &s->cs_line); 362 + 363 + memory_region_init_io(&s->mmio, OBJECT(s), &spi_ops, s, 364 + TYPE_MSS_SPI, R_SPI_MAX * 4); 365 + sysbus_init_mmio(sbd, &s->mmio); 366 + 367 + fifo32_create(&s->tx_fifo, FIFO_CAPACITY); 368 + fifo32_create(&s->rx_fifo, FIFO_CAPACITY); 369 + } 370 + 371 + static const VMStateDescription vmstate_mss_spi = { 372 + .name = TYPE_MSS_SPI, 373 + .version_id = 1, 374 + .minimum_version_id = 1, 375 + .fields = (VMStateField[]) { 376 + VMSTATE_FIFO32(tx_fifo, MSSSpiState), 377 + VMSTATE_FIFO32(rx_fifo, MSSSpiState), 378 + VMSTATE_UINT32_ARRAY(regs, MSSSpiState, R_SPI_MAX), 379 + VMSTATE_END_OF_LIST() 380 + } 381 + }; 382 + 383 + static void mss_spi_class_init(ObjectClass *klass, void *data) 384 + { 385 + DeviceClass *dc = DEVICE_CLASS(klass); 386 + 387 + dc->realize = mss_spi_realize; 388 + dc->reset = mss_spi_reset; 389 + dc->vmsd = &vmstate_mss_spi; 390 + } 391 + 392 + static const TypeInfo mss_spi_info = { 393 + .name = TYPE_MSS_SPI, 394 + .parent = TYPE_SYS_BUS_DEVICE, 395 + .instance_size = sizeof(MSSSpiState), 396 + .class_init = mss_spi_class_init, 397 + }; 398 + 399 + static void mss_spi_register_types(void) 400 + { 401 + type_register_static(&mss_spi_info); 402 + } 403 + 404 + type_init(mss_spi_register_types)
+58
include/hw/ssi/mss-spi.h
··· 1 + /* 2 + * Microsemi SmartFusion2 SPI 3 + * 4 + * Copyright (c) 2017 Subbaraya Sundeep <sundeep.lkml@gmail.com> 5 + * 6 + * Permission is hereby granted, free of charge, to any person obtaining a copy 7 + * of this software and associated documentation files (the "Software"), to deal 8 + * in the Software without restriction, including without limitation the rights 9 + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 + * copies of the Software, and to permit persons to whom the Software is 11 + * furnished to do so, subject to the following conditions: 12 + * 13 + * The above copyright notice and this permission notice shall be included in 14 + * all copies or substantial portions of the Software. 15 + * 16 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 + * THE SOFTWARE. 23 + */ 24 + 25 + #ifndef HW_MSS_SPI_H 26 + #define HW_MSS_SPI_H 27 + 28 + #include "hw/sysbus.h" 29 + #include "hw/ssi/ssi.h" 30 + #include "qemu/fifo32.h" 31 + 32 + #define TYPE_MSS_SPI "mss-spi" 33 + #define MSS_SPI(obj) OBJECT_CHECK(MSSSpiState, (obj), TYPE_MSS_SPI) 34 + 35 + #define R_SPI_MAX 16 36 + 37 + typedef struct MSSSpiState { 38 + SysBusDevice parent_obj; 39 + 40 + MemoryRegion mmio; 41 + 42 + qemu_irq irq; 43 + 44 + qemu_irq cs_line; 45 + 46 + SSIBus *spi; 47 + 48 + Fifo32 rx_fifo; 49 + Fifo32 tx_fifo; 50 + 51 + int fifo_depth; 52 + uint32_t frame_count; 53 + bool enabled; 54 + 55 + uint32_t regs[R_SPI_MAX]; 56 + } MSSSpiState; 57 + 58 + #endif /* HW_MSS_SPI_H */