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

bcm2835_sdhost: add bcm2835 sdhost controller

This adds the BCM2835 SDHost controller from Arasan.

Signed-off-by: Clement Deschamps <clement.deschamps@antfield.fr>
Message-id: 20170224164021.9066-2-clement.deschamps@antfield.fr
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>

authored by

Clement Deschamps and committed by
Peter Maydell
43ddc182 5db53e35

+478
+1
hw/sd/Makefile.objs
··· 6 6 obj-$(CONFIG_MILKYMIST) += milkymist-memcard.o 7 7 obj-$(CONFIG_OMAP) += omap_mmc.o 8 8 obj-$(CONFIG_PXA2XX) += pxa2xx_mmci.o 9 + obj-$(CONFIG_RASPI) += bcm2835_sdhost.o
+429
hw/sd/bcm2835_sdhost.c
··· 1 + /* 2 + * Raspberry Pi (BCM2835) SD Host Controller 3 + * 4 + * Copyright (c) 2017 Antfield SAS 5 + * 6 + * Authors: 7 + * Clement Deschamps <clement.deschamps@antfield.fr> 8 + * Luc Michel <luc.michel@antfield.fr> 9 + * 10 + * This work is licensed under the terms of the GNU GPL, version 2 or later. 11 + * See the COPYING file in the top-level directory. 12 + */ 13 + 14 + #include "qemu/osdep.h" 15 + #include "qemu/log.h" 16 + #include "sysemu/blockdev.h" 17 + #include "hw/sd/bcm2835_sdhost.h" 18 + 19 + #define TYPE_BCM2835_SDHOST_BUS "bcm2835-sdhost-bus" 20 + #define BCM2835_SDHOST_BUS(obj) \ 21 + OBJECT_CHECK(SDBus, (obj), TYPE_BCM2835_SDHOST_BUS) 22 + 23 + #define SDCMD 0x00 /* Command to SD card - 16 R/W */ 24 + #define SDARG 0x04 /* Argument to SD card - 32 R/W */ 25 + #define SDTOUT 0x08 /* Start value for timeout counter - 32 R/W */ 26 + #define SDCDIV 0x0c /* Start value for clock divider - 11 R/W */ 27 + #define SDRSP0 0x10 /* SD card rsp (31:0) - 32 R */ 28 + #define SDRSP1 0x14 /* SD card rsp (63:32) - 32 R */ 29 + #define SDRSP2 0x18 /* SD card rsp (95:64) - 32 R */ 30 + #define SDRSP3 0x1c /* SD card rsp (127:96) - 32 R */ 31 + #define SDHSTS 0x20 /* SD host status - 11 R */ 32 + #define SDVDD 0x30 /* SD card power control - 1 R/W */ 33 + #define SDEDM 0x34 /* Emergency Debug Mode - 13 R/W */ 34 + #define SDHCFG 0x38 /* Host configuration - 2 R/W */ 35 + #define SDHBCT 0x3c /* Host byte count (debug) - 32 R/W */ 36 + #define SDDATA 0x40 /* Data to/from SD card - 32 R/W */ 37 + #define SDHBLC 0x50 /* Host block count (SDIO/SDHC) - 9 R/W */ 38 + 39 + #define SDCMD_NEW_FLAG 0x8000 40 + #define SDCMD_FAIL_FLAG 0x4000 41 + #define SDCMD_BUSYWAIT 0x800 42 + #define SDCMD_NO_RESPONSE 0x400 43 + #define SDCMD_LONG_RESPONSE 0x200 44 + #define SDCMD_WRITE_CMD 0x80 45 + #define SDCMD_READ_CMD 0x40 46 + #define SDCMD_CMD_MASK 0x3f 47 + 48 + #define SDCDIV_MAX_CDIV 0x7ff 49 + 50 + #define SDHSTS_BUSY_IRPT 0x400 51 + #define SDHSTS_BLOCK_IRPT 0x200 52 + #define SDHSTS_SDIO_IRPT 0x100 53 + #define SDHSTS_REW_TIME_OUT 0x80 54 + #define SDHSTS_CMD_TIME_OUT 0x40 55 + #define SDHSTS_CRC16_ERROR 0x20 56 + #define SDHSTS_CRC7_ERROR 0x10 57 + #define SDHSTS_FIFO_ERROR 0x08 58 + /* Reserved */ 59 + /* Reserved */ 60 + #define SDHSTS_DATA_FLAG 0x01 61 + 62 + #define SDHCFG_BUSY_IRPT_EN (1 << 10) 63 + #define SDHCFG_BLOCK_IRPT_EN (1 << 8) 64 + #define SDHCFG_SDIO_IRPT_EN (1 << 5) 65 + #define SDHCFG_DATA_IRPT_EN (1 << 4) 66 + #define SDHCFG_SLOW_CARD (1 << 3) 67 + #define SDHCFG_WIDE_EXT_BUS (1 << 2) 68 + #define SDHCFG_WIDE_INT_BUS (1 << 1) 69 + #define SDHCFG_REL_CMD_LINE (1 << 0) 70 + 71 + #define SDEDM_FORCE_DATA_MODE (1 << 19) 72 + #define SDEDM_CLOCK_PULSE (1 << 20) 73 + #define SDEDM_BYPASS (1 << 21) 74 + 75 + #define SDEDM_WRITE_THRESHOLD_SHIFT 9 76 + #define SDEDM_READ_THRESHOLD_SHIFT 14 77 + #define SDEDM_THRESHOLD_MASK 0x1f 78 + 79 + #define SDEDM_FSM_MASK 0xf 80 + #define SDEDM_FSM_IDENTMODE 0x0 81 + #define SDEDM_FSM_DATAMODE 0x1 82 + #define SDEDM_FSM_READDATA 0x2 83 + #define SDEDM_FSM_WRITEDATA 0x3 84 + #define SDEDM_FSM_READWAIT 0x4 85 + #define SDEDM_FSM_READCRC 0x5 86 + #define SDEDM_FSM_WRITECRC 0x6 87 + #define SDEDM_FSM_WRITEWAIT1 0x7 88 + #define SDEDM_FSM_POWERDOWN 0x8 89 + #define SDEDM_FSM_POWERUP 0x9 90 + #define SDEDM_FSM_WRITESTART1 0xa 91 + #define SDEDM_FSM_WRITESTART2 0xb 92 + #define SDEDM_FSM_GENPULSES 0xc 93 + #define SDEDM_FSM_WRITEWAIT2 0xd 94 + #define SDEDM_FSM_STARTPOWDOWN 0xf 95 + 96 + #define SDDATA_FIFO_WORDS 16 97 + 98 + static void bcm2835_sdhost_update_irq(BCM2835SDHostState *s) 99 + { 100 + uint32_t irq = s->status & 101 + (SDHSTS_BUSY_IRPT | SDHSTS_BLOCK_IRPT | SDHSTS_SDIO_IRPT); 102 + qemu_set_irq(s->irq, !!irq); 103 + } 104 + 105 + static void bcm2835_sdhost_send_command(BCM2835SDHostState *s) 106 + { 107 + SDRequest request; 108 + uint8_t rsp[16]; 109 + int rlen; 110 + 111 + request.cmd = s->cmd & SDCMD_CMD_MASK; 112 + request.arg = s->cmdarg; 113 + 114 + rlen = sdbus_do_command(&s->sdbus, &request, rsp); 115 + if (rlen < 0) { 116 + goto error; 117 + } 118 + if (!(s->cmd & SDCMD_NO_RESPONSE)) { 119 + #define RWORD(n) (((uint32_t)rsp[n] << 24) | (rsp[n + 1] << 16) \ 120 + | (rsp[n + 2] << 8) | rsp[n + 3]) 121 + if (rlen == 0 || (rlen == 4 && (s->cmd & SDCMD_LONG_RESPONSE))) { 122 + goto error; 123 + } 124 + if (rlen != 4 && rlen != 16) { 125 + goto error; 126 + } 127 + if (rlen == 4) { 128 + s->rsp[0] = RWORD(0); 129 + s->rsp[1] = s->rsp[2] = s->rsp[3] = 0; 130 + } else { 131 + s->rsp[0] = RWORD(12); 132 + s->rsp[1] = RWORD(8); 133 + s->rsp[2] = RWORD(4); 134 + s->rsp[3] = RWORD(0); 135 + } 136 + #undef RWORD 137 + } 138 + return; 139 + 140 + error: 141 + s->cmd |= SDCMD_FAIL_FLAG; 142 + s->status |= SDHSTS_CMD_TIME_OUT; 143 + } 144 + 145 + static void bcm2835_sdhost_fifo_push(BCM2835SDHostState *s, uint32_t value) 146 + { 147 + int n; 148 + 149 + if (s->fifo_len == BCM2835_SDHOST_FIFO_LEN) { 150 + /* FIFO overflow */ 151 + return; 152 + } 153 + n = (s->fifo_pos + s->fifo_len) & (BCM2835_SDHOST_FIFO_LEN - 1); 154 + s->fifo_len++; 155 + s->fifo[n] = value; 156 + } 157 + 158 + static uint32_t bcm2835_sdhost_fifo_pop(BCM2835SDHostState *s) 159 + { 160 + uint32_t value; 161 + 162 + if (s->fifo_len == 0) { 163 + /* FIFO underflow */ 164 + return 0; 165 + } 166 + value = s->fifo[s->fifo_pos]; 167 + s->fifo_len--; 168 + s->fifo_pos = (s->fifo_pos + 1) & (BCM2835_SDHOST_FIFO_LEN - 1); 169 + return value; 170 + } 171 + 172 + static void bcm2835_sdhost_fifo_run(BCM2835SDHostState *s) 173 + { 174 + uint32_t value = 0; 175 + int n; 176 + int is_read; 177 + 178 + is_read = (s->cmd & SDCMD_READ_CMD) != 0; 179 + if (s->datacnt != 0 && (!is_read || sdbus_data_ready(&s->sdbus))) { 180 + if (is_read) { 181 + n = 0; 182 + while (s->datacnt && s->fifo_len < BCM2835_SDHOST_FIFO_LEN) { 183 + value |= (uint32_t)sdbus_read_data(&s->sdbus) << (n * 8); 184 + s->datacnt--; 185 + n++; 186 + if (n == 4) { 187 + bcm2835_sdhost_fifo_push(s, value); 188 + n = 0; 189 + value = 0; 190 + } 191 + } 192 + if (n != 0) { 193 + bcm2835_sdhost_fifo_push(s, value); 194 + } 195 + } else { /* write */ 196 + n = 0; 197 + while (s->datacnt > 0 && (s->fifo_len > 0 || n > 0)) { 198 + if (n == 0) { 199 + value = bcm2835_sdhost_fifo_pop(s); 200 + n = 4; 201 + } 202 + n--; 203 + s->datacnt--; 204 + sdbus_write_data(&s->sdbus, value & 0xff); 205 + value >>= 8; 206 + } 207 + } 208 + } 209 + if (s->datacnt == 0) { 210 + s->status |= SDHSTS_DATA_FLAG; 211 + 212 + s->edm &= ~0xf; 213 + s->edm |= SDEDM_FSM_DATAMODE; 214 + 215 + if (s->config & SDHCFG_DATA_IRPT_EN) { 216 + s->status |= SDHSTS_SDIO_IRPT; 217 + } 218 + 219 + if ((s->cmd & SDCMD_BUSYWAIT) && (s->config & SDHCFG_BUSY_IRPT_EN)) { 220 + s->status |= SDHSTS_BUSY_IRPT; 221 + } 222 + 223 + if ((s->cmd & SDCMD_WRITE_CMD) && (s->config & SDHCFG_BLOCK_IRPT_EN)) { 224 + s->status |= SDHSTS_BLOCK_IRPT; 225 + } 226 + 227 + bcm2835_sdhost_update_irq(s); 228 + } 229 + 230 + s->edm &= ~(0x1f << 4); 231 + s->edm |= ((s->fifo_len & 0x1f) << 4); 232 + } 233 + 234 + static uint64_t bcm2835_sdhost_read(void *opaque, hwaddr offset, 235 + unsigned size) 236 + { 237 + BCM2835SDHostState *s = (BCM2835SDHostState *)opaque; 238 + uint32_t res = 0; 239 + 240 + switch (offset) { 241 + case SDCMD: 242 + res = s->cmd; 243 + break; 244 + case SDHSTS: 245 + res = s->status; 246 + break; 247 + case SDRSP0: 248 + res = s->rsp[0]; 249 + break; 250 + case SDRSP1: 251 + res = s->rsp[1]; 252 + break; 253 + case SDRSP2: 254 + res = s->rsp[2]; 255 + break; 256 + case SDRSP3: 257 + res = s->rsp[3]; 258 + break; 259 + case SDEDM: 260 + res = s->edm; 261 + break; 262 + case SDVDD: 263 + res = s->vdd; 264 + break; 265 + case SDDATA: 266 + res = bcm2835_sdhost_fifo_pop(s); 267 + bcm2835_sdhost_fifo_run(s); 268 + break; 269 + case SDHBCT: 270 + res = s->hbct; 271 + break; 272 + case SDHBLC: 273 + res = s->hblc; 274 + break; 275 + 276 + default: 277 + qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset %"HWADDR_PRIx"\n", 278 + __func__, offset); 279 + res = 0; 280 + break; 281 + } 282 + 283 + return res; 284 + } 285 + 286 + static void bcm2835_sdhost_write(void *opaque, hwaddr offset, 287 + uint64_t value, unsigned size) 288 + { 289 + BCM2835SDHostState *s = (BCM2835SDHostState *)opaque; 290 + 291 + switch (offset) { 292 + case SDCMD: 293 + s->cmd = value; 294 + if (value & SDCMD_NEW_FLAG) { 295 + bcm2835_sdhost_send_command(s); 296 + bcm2835_sdhost_fifo_run(s); 297 + s->cmd &= ~SDCMD_NEW_FLAG; 298 + } 299 + break; 300 + case SDTOUT: 301 + break; 302 + case SDCDIV: 303 + break; 304 + case SDHSTS: 305 + s->status &= ~value; 306 + bcm2835_sdhost_update_irq(s); 307 + break; 308 + case SDARG: 309 + s->cmdarg = value; 310 + break; 311 + case SDEDM: 312 + if ((value & 0xf) == 0xf) { 313 + /* power down */ 314 + value &= ~0xf; 315 + } 316 + s->edm = value; 317 + break; 318 + case SDHCFG: 319 + s->config = value; 320 + bcm2835_sdhost_fifo_run(s); 321 + break; 322 + case SDVDD: 323 + s->vdd = value; 324 + break; 325 + case SDDATA: 326 + bcm2835_sdhost_fifo_push(s, value); 327 + bcm2835_sdhost_fifo_run(s); 328 + break; 329 + case SDHBCT: 330 + s->hbct = value; 331 + break; 332 + case SDHBLC: 333 + s->hblc = value; 334 + s->datacnt = s->hblc * s->hbct; 335 + bcm2835_sdhost_fifo_run(s); 336 + break; 337 + 338 + default: 339 + qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset %"HWADDR_PRIx"\n", 340 + __func__, offset); 341 + break; 342 + } 343 + } 344 + 345 + static const MemoryRegionOps bcm2835_sdhost_ops = { 346 + .read = bcm2835_sdhost_read, 347 + .write = bcm2835_sdhost_write, 348 + .endianness = DEVICE_NATIVE_ENDIAN, 349 + }; 350 + 351 + static const VMStateDescription vmstate_bcm2835_sdhost = { 352 + .name = TYPE_BCM2835_SDHOST, 353 + .version_id = 1, 354 + .minimum_version_id = 1, 355 + .fields = (VMStateField[]) { 356 + VMSTATE_UINT32(cmd, BCM2835SDHostState), 357 + VMSTATE_UINT32(cmdarg, BCM2835SDHostState), 358 + VMSTATE_UINT32(status, BCM2835SDHostState), 359 + VMSTATE_UINT32_ARRAY(rsp, BCM2835SDHostState, 4), 360 + VMSTATE_UINT32(config, BCM2835SDHostState), 361 + VMSTATE_UINT32(edm, BCM2835SDHostState), 362 + VMSTATE_UINT32(vdd, BCM2835SDHostState), 363 + VMSTATE_UINT32(hbct, BCM2835SDHostState), 364 + VMSTATE_UINT32(hblc, BCM2835SDHostState), 365 + VMSTATE_INT32(fifo_pos, BCM2835SDHostState), 366 + VMSTATE_INT32(fifo_len, BCM2835SDHostState), 367 + VMSTATE_UINT32_ARRAY(fifo, BCM2835SDHostState, BCM2835_SDHOST_FIFO_LEN), 368 + VMSTATE_UINT32(datacnt, BCM2835SDHostState), 369 + VMSTATE_END_OF_LIST() 370 + } 371 + }; 372 + 373 + static void bcm2835_sdhost_init(Object *obj) 374 + { 375 + BCM2835SDHostState *s = BCM2835_SDHOST(obj); 376 + 377 + qbus_create_inplace(&s->sdbus, sizeof(s->sdbus), 378 + TYPE_BCM2835_SDHOST_BUS, DEVICE(s), "sd-bus"); 379 + 380 + memory_region_init_io(&s->iomem, obj, &bcm2835_sdhost_ops, s, 381 + TYPE_BCM2835_SDHOST, 0x1000); 382 + sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->iomem); 383 + sysbus_init_irq(SYS_BUS_DEVICE(s), &s->irq); 384 + } 385 + 386 + static void bcm2835_sdhost_reset(DeviceState *dev) 387 + { 388 + BCM2835SDHostState *s = BCM2835_SDHOST(dev); 389 + 390 + s->cmd = 0; 391 + s->cmdarg = 0; 392 + s->edm = 0x0000c60f; 393 + s->config = 0; 394 + s->hbct = 0; 395 + s->hblc = 0; 396 + s->datacnt = 0; 397 + s->fifo_pos = 0; 398 + s->fifo_len = 0; 399 + } 400 + 401 + static void bcm2835_sdhost_class_init(ObjectClass *klass, void *data) 402 + { 403 + DeviceClass *dc = DEVICE_CLASS(klass); 404 + 405 + dc->reset = bcm2835_sdhost_reset; 406 + dc->vmsd = &vmstate_bcm2835_sdhost; 407 + } 408 + 409 + static TypeInfo bcm2835_sdhost_info = { 410 + .name = TYPE_BCM2835_SDHOST, 411 + .parent = TYPE_SYS_BUS_DEVICE, 412 + .instance_size = sizeof(BCM2835SDHostState), 413 + .class_init = bcm2835_sdhost_class_init, 414 + .instance_init = bcm2835_sdhost_init, 415 + }; 416 + 417 + static const TypeInfo bcm2835_sdhost_bus_info = { 418 + .name = TYPE_BCM2835_SDHOST_BUS, 419 + .parent = TYPE_SD_BUS, 420 + .instance_size = sizeof(SDBus), 421 + }; 422 + 423 + static void bcm2835_sdhost_register_types(void) 424 + { 425 + type_register_static(&bcm2835_sdhost_info); 426 + type_register_static(&bcm2835_sdhost_bus_info); 427 + } 428 + 429 + type_init(bcm2835_sdhost_register_types)
+48
include/hw/sd/bcm2835_sdhost.h
··· 1 + /* 2 + * Raspberry Pi (BCM2835) SD Host Controller 3 + * 4 + * Copyright (c) 2017 Antfield SAS 5 + * 6 + * Authors: 7 + * Clement Deschamps <clement.deschamps@antfield.fr> 8 + * Luc Michel <luc.michel@antfield.fr> 9 + * 10 + * This work is licensed under the terms of the GNU GPL, version 2 or later. 11 + * See the COPYING file in the top-level directory. 12 + */ 13 + 14 + #ifndef BCM2835_SDHOST_H 15 + #define BCM2835_SDHOST_H 16 + 17 + #include "hw/sysbus.h" 18 + #include "hw/sd/sd.h" 19 + 20 + #define TYPE_BCM2835_SDHOST "bcm2835-sdhost" 21 + #define BCM2835_SDHOST(obj) \ 22 + OBJECT_CHECK(BCM2835SDHostState, (obj), TYPE_BCM2835_SDHOST) 23 + 24 + #define BCM2835_SDHOST_FIFO_LEN 16 25 + 26 + typedef struct { 27 + SysBusDevice busdev; 28 + SDBus sdbus; 29 + MemoryRegion iomem; 30 + 31 + uint32_t cmd; 32 + uint32_t cmdarg; 33 + uint32_t status; 34 + uint32_t rsp[4]; 35 + uint32_t config; 36 + uint32_t edm; 37 + uint32_t vdd; 38 + uint32_t hbct; 39 + uint32_t hblc; 40 + int32_t fifo_pos; 41 + int32_t fifo_len; 42 + uint32_t fifo[BCM2835_SDHOST_FIFO_LEN]; 43 + uint32_t datacnt; 44 + 45 + qemu_irq irq; 46 + } BCM2835SDHostState; 47 + 48 + #endif