143ddc182SClement Deschamps /* 243ddc182SClement Deschamps * Raspberry Pi (BCM2835) SD Host Controller 343ddc182SClement Deschamps * 443ddc182SClement Deschamps * Copyright (c) 2017 Antfield SAS 543ddc182SClement Deschamps * 643ddc182SClement Deschamps * Authors: 743ddc182SClement Deschamps * Clement Deschamps <clement.deschamps@antfield.fr> 843ddc182SClement Deschamps * Luc Michel <luc.michel@antfield.fr> 943ddc182SClement Deschamps * 1043ddc182SClement Deschamps * This work is licensed under the terms of the GNU GPL, version 2 or later. 1143ddc182SClement Deschamps * See the COPYING file in the top-level directory. 1243ddc182SClement Deschamps */ 1343ddc182SClement Deschamps 1443ddc182SClement Deschamps #include "qemu/osdep.h" 1543ddc182SClement Deschamps #include "qemu/log.h" 1643ddc182SClement Deschamps #include "sysemu/blockdev.h" 1743ddc182SClement Deschamps #include "hw/sd/bcm2835_sdhost.h" 18*b318f326SPeter Maydell #include "trace.h" 1943ddc182SClement Deschamps 2043ddc182SClement Deschamps #define TYPE_BCM2835_SDHOST_BUS "bcm2835-sdhost-bus" 2143ddc182SClement Deschamps #define BCM2835_SDHOST_BUS(obj) \ 2243ddc182SClement Deschamps OBJECT_CHECK(SDBus, (obj), TYPE_BCM2835_SDHOST_BUS) 2343ddc182SClement Deschamps 2443ddc182SClement Deschamps #define SDCMD 0x00 /* Command to SD card - 16 R/W */ 2543ddc182SClement Deschamps #define SDARG 0x04 /* Argument to SD card - 32 R/W */ 2643ddc182SClement Deschamps #define SDTOUT 0x08 /* Start value for timeout counter - 32 R/W */ 2743ddc182SClement Deschamps #define SDCDIV 0x0c /* Start value for clock divider - 11 R/W */ 2843ddc182SClement Deschamps #define SDRSP0 0x10 /* SD card rsp (31:0) - 32 R */ 2943ddc182SClement Deschamps #define SDRSP1 0x14 /* SD card rsp (63:32) - 32 R */ 3043ddc182SClement Deschamps #define SDRSP2 0x18 /* SD card rsp (95:64) - 32 R */ 3143ddc182SClement Deschamps #define SDRSP3 0x1c /* SD card rsp (127:96) - 32 R */ 3243ddc182SClement Deschamps #define SDHSTS 0x20 /* SD host status - 11 R */ 3343ddc182SClement Deschamps #define SDVDD 0x30 /* SD card power control - 1 R/W */ 3443ddc182SClement Deschamps #define SDEDM 0x34 /* Emergency Debug Mode - 13 R/W */ 3543ddc182SClement Deschamps #define SDHCFG 0x38 /* Host configuration - 2 R/W */ 3643ddc182SClement Deschamps #define SDHBCT 0x3c /* Host byte count (debug) - 32 R/W */ 3743ddc182SClement Deschamps #define SDDATA 0x40 /* Data to/from SD card - 32 R/W */ 3843ddc182SClement Deschamps #define SDHBLC 0x50 /* Host block count (SDIO/SDHC) - 9 R/W */ 3943ddc182SClement Deschamps 4043ddc182SClement Deschamps #define SDCMD_NEW_FLAG 0x8000 4143ddc182SClement Deschamps #define SDCMD_FAIL_FLAG 0x4000 4243ddc182SClement Deschamps #define SDCMD_BUSYWAIT 0x800 4343ddc182SClement Deschamps #define SDCMD_NO_RESPONSE 0x400 4443ddc182SClement Deschamps #define SDCMD_LONG_RESPONSE 0x200 4543ddc182SClement Deschamps #define SDCMD_WRITE_CMD 0x80 4643ddc182SClement Deschamps #define SDCMD_READ_CMD 0x40 4743ddc182SClement Deschamps #define SDCMD_CMD_MASK 0x3f 4843ddc182SClement Deschamps 4943ddc182SClement Deschamps #define SDCDIV_MAX_CDIV 0x7ff 5043ddc182SClement Deschamps 5143ddc182SClement Deschamps #define SDHSTS_BUSY_IRPT 0x400 5243ddc182SClement Deschamps #define SDHSTS_BLOCK_IRPT 0x200 5343ddc182SClement Deschamps #define SDHSTS_SDIO_IRPT 0x100 5443ddc182SClement Deschamps #define SDHSTS_REW_TIME_OUT 0x80 5543ddc182SClement Deschamps #define SDHSTS_CMD_TIME_OUT 0x40 5643ddc182SClement Deschamps #define SDHSTS_CRC16_ERROR 0x20 5743ddc182SClement Deschamps #define SDHSTS_CRC7_ERROR 0x10 5843ddc182SClement Deschamps #define SDHSTS_FIFO_ERROR 0x08 5943ddc182SClement Deschamps /* Reserved */ 6043ddc182SClement Deschamps /* Reserved */ 6143ddc182SClement Deschamps #define SDHSTS_DATA_FLAG 0x01 6243ddc182SClement Deschamps 6343ddc182SClement Deschamps #define SDHCFG_BUSY_IRPT_EN (1 << 10) 6443ddc182SClement Deschamps #define SDHCFG_BLOCK_IRPT_EN (1 << 8) 6543ddc182SClement Deschamps #define SDHCFG_SDIO_IRPT_EN (1 << 5) 6643ddc182SClement Deschamps #define SDHCFG_DATA_IRPT_EN (1 << 4) 6743ddc182SClement Deschamps #define SDHCFG_SLOW_CARD (1 << 3) 6843ddc182SClement Deschamps #define SDHCFG_WIDE_EXT_BUS (1 << 2) 6943ddc182SClement Deschamps #define SDHCFG_WIDE_INT_BUS (1 << 1) 7043ddc182SClement Deschamps #define SDHCFG_REL_CMD_LINE (1 << 0) 7143ddc182SClement Deschamps 7243ddc182SClement Deschamps #define SDEDM_FORCE_DATA_MODE (1 << 19) 7343ddc182SClement Deschamps #define SDEDM_CLOCK_PULSE (1 << 20) 7443ddc182SClement Deschamps #define SDEDM_BYPASS (1 << 21) 7543ddc182SClement Deschamps 7643ddc182SClement Deschamps #define SDEDM_WRITE_THRESHOLD_SHIFT 9 7743ddc182SClement Deschamps #define SDEDM_READ_THRESHOLD_SHIFT 14 7843ddc182SClement Deschamps #define SDEDM_THRESHOLD_MASK 0x1f 7943ddc182SClement Deschamps 8043ddc182SClement Deschamps #define SDEDM_FSM_MASK 0xf 8143ddc182SClement Deschamps #define SDEDM_FSM_IDENTMODE 0x0 8243ddc182SClement Deschamps #define SDEDM_FSM_DATAMODE 0x1 8343ddc182SClement Deschamps #define SDEDM_FSM_READDATA 0x2 8443ddc182SClement Deschamps #define SDEDM_FSM_WRITEDATA 0x3 8543ddc182SClement Deschamps #define SDEDM_FSM_READWAIT 0x4 8643ddc182SClement Deschamps #define SDEDM_FSM_READCRC 0x5 8743ddc182SClement Deschamps #define SDEDM_FSM_WRITECRC 0x6 8843ddc182SClement Deschamps #define SDEDM_FSM_WRITEWAIT1 0x7 8943ddc182SClement Deschamps #define SDEDM_FSM_POWERDOWN 0x8 9043ddc182SClement Deschamps #define SDEDM_FSM_POWERUP 0x9 9143ddc182SClement Deschamps #define SDEDM_FSM_WRITESTART1 0xa 9243ddc182SClement Deschamps #define SDEDM_FSM_WRITESTART2 0xb 9343ddc182SClement Deschamps #define SDEDM_FSM_GENPULSES 0xc 9443ddc182SClement Deschamps #define SDEDM_FSM_WRITEWAIT2 0xd 9543ddc182SClement Deschamps #define SDEDM_FSM_STARTPOWDOWN 0xf 9643ddc182SClement Deschamps 9743ddc182SClement Deschamps #define SDDATA_FIFO_WORDS 16 9843ddc182SClement Deschamps 9943ddc182SClement Deschamps static void bcm2835_sdhost_update_irq(BCM2835SDHostState *s) 10043ddc182SClement Deschamps { 10143ddc182SClement Deschamps uint32_t irq = s->status & 10243ddc182SClement Deschamps (SDHSTS_BUSY_IRPT | SDHSTS_BLOCK_IRPT | SDHSTS_SDIO_IRPT); 103*b318f326SPeter Maydell trace_bcm2835_sdhost_update_irq(irq); 10443ddc182SClement Deschamps qemu_set_irq(s->irq, !!irq); 10543ddc182SClement Deschamps } 10643ddc182SClement Deschamps 10743ddc182SClement Deschamps static void bcm2835_sdhost_send_command(BCM2835SDHostState *s) 10843ddc182SClement Deschamps { 10943ddc182SClement Deschamps SDRequest request; 11043ddc182SClement Deschamps uint8_t rsp[16]; 11143ddc182SClement Deschamps int rlen; 11243ddc182SClement Deschamps 11343ddc182SClement Deschamps request.cmd = s->cmd & SDCMD_CMD_MASK; 11443ddc182SClement Deschamps request.arg = s->cmdarg; 11543ddc182SClement Deschamps 11643ddc182SClement Deschamps rlen = sdbus_do_command(&s->sdbus, &request, rsp); 11743ddc182SClement Deschamps if (rlen < 0) { 11843ddc182SClement Deschamps goto error; 11943ddc182SClement Deschamps } 12043ddc182SClement Deschamps if (!(s->cmd & SDCMD_NO_RESPONSE)) { 12143ddc182SClement Deschamps #define RWORD(n) (((uint32_t)rsp[n] << 24) | (rsp[n + 1] << 16) \ 12243ddc182SClement Deschamps | (rsp[n + 2] << 8) | rsp[n + 3]) 12343ddc182SClement Deschamps if (rlen == 0 || (rlen == 4 && (s->cmd & SDCMD_LONG_RESPONSE))) { 12443ddc182SClement Deschamps goto error; 12543ddc182SClement Deschamps } 12643ddc182SClement Deschamps if (rlen != 4 && rlen != 16) { 12743ddc182SClement Deschamps goto error; 12843ddc182SClement Deschamps } 12943ddc182SClement Deschamps if (rlen == 4) { 13043ddc182SClement Deschamps s->rsp[0] = RWORD(0); 13143ddc182SClement Deschamps s->rsp[1] = s->rsp[2] = s->rsp[3] = 0; 13243ddc182SClement Deschamps } else { 13343ddc182SClement Deschamps s->rsp[0] = RWORD(12); 13443ddc182SClement Deschamps s->rsp[1] = RWORD(8); 13543ddc182SClement Deschamps s->rsp[2] = RWORD(4); 13643ddc182SClement Deschamps s->rsp[3] = RWORD(0); 13743ddc182SClement Deschamps } 13843ddc182SClement Deschamps #undef RWORD 13943ddc182SClement Deschamps } 14043ddc182SClement Deschamps return; 14143ddc182SClement Deschamps 14243ddc182SClement Deschamps error: 14343ddc182SClement Deschamps s->cmd |= SDCMD_FAIL_FLAG; 14443ddc182SClement Deschamps s->status |= SDHSTS_CMD_TIME_OUT; 14543ddc182SClement Deschamps } 14643ddc182SClement Deschamps 14743ddc182SClement Deschamps static void bcm2835_sdhost_fifo_push(BCM2835SDHostState *s, uint32_t value) 14843ddc182SClement Deschamps { 14943ddc182SClement Deschamps int n; 15043ddc182SClement Deschamps 15143ddc182SClement Deschamps if (s->fifo_len == BCM2835_SDHOST_FIFO_LEN) { 15243ddc182SClement Deschamps /* FIFO overflow */ 15343ddc182SClement Deschamps return; 15443ddc182SClement Deschamps } 15543ddc182SClement Deschamps n = (s->fifo_pos + s->fifo_len) & (BCM2835_SDHOST_FIFO_LEN - 1); 15643ddc182SClement Deschamps s->fifo_len++; 15743ddc182SClement Deschamps s->fifo[n] = value; 15843ddc182SClement Deschamps } 15943ddc182SClement Deschamps 16043ddc182SClement Deschamps static uint32_t bcm2835_sdhost_fifo_pop(BCM2835SDHostState *s) 16143ddc182SClement Deschamps { 16243ddc182SClement Deschamps uint32_t value; 16343ddc182SClement Deschamps 16443ddc182SClement Deschamps if (s->fifo_len == 0) { 16543ddc182SClement Deschamps /* FIFO underflow */ 16643ddc182SClement Deschamps return 0; 16743ddc182SClement Deschamps } 16843ddc182SClement Deschamps value = s->fifo[s->fifo_pos]; 16943ddc182SClement Deschamps s->fifo_len--; 17043ddc182SClement Deschamps s->fifo_pos = (s->fifo_pos + 1) & (BCM2835_SDHOST_FIFO_LEN - 1); 17143ddc182SClement Deschamps return value; 17243ddc182SClement Deschamps } 17343ddc182SClement Deschamps 17443ddc182SClement Deschamps static void bcm2835_sdhost_fifo_run(BCM2835SDHostState *s) 17543ddc182SClement Deschamps { 17643ddc182SClement Deschamps uint32_t value = 0; 17743ddc182SClement Deschamps int n; 17843ddc182SClement Deschamps int is_read; 17943ddc182SClement Deschamps 18043ddc182SClement Deschamps is_read = (s->cmd & SDCMD_READ_CMD) != 0; 18143ddc182SClement Deschamps if (s->datacnt != 0 && (!is_read || sdbus_data_ready(&s->sdbus))) { 18243ddc182SClement Deschamps if (is_read) { 18343ddc182SClement Deschamps n = 0; 18443ddc182SClement Deschamps while (s->datacnt && s->fifo_len < BCM2835_SDHOST_FIFO_LEN) { 18543ddc182SClement Deschamps value |= (uint32_t)sdbus_read_data(&s->sdbus) << (n * 8); 18643ddc182SClement Deschamps s->datacnt--; 18743ddc182SClement Deschamps n++; 18843ddc182SClement Deschamps if (n == 4) { 18943ddc182SClement Deschamps bcm2835_sdhost_fifo_push(s, value); 19043ddc182SClement Deschamps n = 0; 19143ddc182SClement Deschamps value = 0; 19243ddc182SClement Deschamps } 19343ddc182SClement Deschamps } 19443ddc182SClement Deschamps if (n != 0) { 19543ddc182SClement Deschamps bcm2835_sdhost_fifo_push(s, value); 19643ddc182SClement Deschamps } 19743ddc182SClement Deschamps } else { /* write */ 19843ddc182SClement Deschamps n = 0; 19943ddc182SClement Deschamps while (s->datacnt > 0 && (s->fifo_len > 0 || n > 0)) { 20043ddc182SClement Deschamps if (n == 0) { 20143ddc182SClement Deschamps value = bcm2835_sdhost_fifo_pop(s); 20243ddc182SClement Deschamps n = 4; 20343ddc182SClement Deschamps } 20443ddc182SClement Deschamps n--; 20543ddc182SClement Deschamps s->datacnt--; 20643ddc182SClement Deschamps sdbus_write_data(&s->sdbus, value & 0xff); 20743ddc182SClement Deschamps value >>= 8; 20843ddc182SClement Deschamps } 20943ddc182SClement Deschamps } 21043ddc182SClement Deschamps } 21143ddc182SClement Deschamps if (s->datacnt == 0) { 21243ddc182SClement Deschamps s->status |= SDHSTS_DATA_FLAG; 21343ddc182SClement Deschamps 21443ddc182SClement Deschamps s->edm &= ~0xf; 21543ddc182SClement Deschamps s->edm |= SDEDM_FSM_DATAMODE; 216*b318f326SPeter Maydell trace_bcm2835_sdhost_edm_change("datacnt 0", s->edm); 21743ddc182SClement Deschamps 21843ddc182SClement Deschamps if (s->config & SDHCFG_DATA_IRPT_EN) { 21943ddc182SClement Deschamps s->status |= SDHSTS_SDIO_IRPT; 22043ddc182SClement Deschamps } 22143ddc182SClement Deschamps 22243ddc182SClement Deschamps if ((s->cmd & SDCMD_BUSYWAIT) && (s->config & SDHCFG_BUSY_IRPT_EN)) { 22343ddc182SClement Deschamps s->status |= SDHSTS_BUSY_IRPT; 22443ddc182SClement Deschamps } 22543ddc182SClement Deschamps 22643ddc182SClement Deschamps if ((s->cmd & SDCMD_WRITE_CMD) && (s->config & SDHCFG_BLOCK_IRPT_EN)) { 22743ddc182SClement Deschamps s->status |= SDHSTS_BLOCK_IRPT; 22843ddc182SClement Deschamps } 22943ddc182SClement Deschamps 23043ddc182SClement Deschamps bcm2835_sdhost_update_irq(s); 23143ddc182SClement Deschamps } 23243ddc182SClement Deschamps 23343ddc182SClement Deschamps s->edm &= ~(0x1f << 4); 23443ddc182SClement Deschamps s->edm |= ((s->fifo_len & 0x1f) << 4); 235*b318f326SPeter Maydell trace_bcm2835_sdhost_edm_change("fifo run", s->edm); 23643ddc182SClement Deschamps } 23743ddc182SClement Deschamps 23843ddc182SClement Deschamps static uint64_t bcm2835_sdhost_read(void *opaque, hwaddr offset, 23943ddc182SClement Deschamps unsigned size) 24043ddc182SClement Deschamps { 24143ddc182SClement Deschamps BCM2835SDHostState *s = (BCM2835SDHostState *)opaque; 24243ddc182SClement Deschamps uint32_t res = 0; 24343ddc182SClement Deschamps 24443ddc182SClement Deschamps switch (offset) { 24543ddc182SClement Deschamps case SDCMD: 24643ddc182SClement Deschamps res = s->cmd; 24743ddc182SClement Deschamps break; 24843ddc182SClement Deschamps case SDHSTS: 24943ddc182SClement Deschamps res = s->status; 25043ddc182SClement Deschamps break; 25143ddc182SClement Deschamps case SDRSP0: 25243ddc182SClement Deschamps res = s->rsp[0]; 25343ddc182SClement Deschamps break; 25443ddc182SClement Deschamps case SDRSP1: 25543ddc182SClement Deschamps res = s->rsp[1]; 25643ddc182SClement Deschamps break; 25743ddc182SClement Deschamps case SDRSP2: 25843ddc182SClement Deschamps res = s->rsp[2]; 25943ddc182SClement Deschamps break; 26043ddc182SClement Deschamps case SDRSP3: 26143ddc182SClement Deschamps res = s->rsp[3]; 26243ddc182SClement Deschamps break; 26343ddc182SClement Deschamps case SDEDM: 26443ddc182SClement Deschamps res = s->edm; 26543ddc182SClement Deschamps break; 26643ddc182SClement Deschamps case SDVDD: 26743ddc182SClement Deschamps res = s->vdd; 26843ddc182SClement Deschamps break; 26943ddc182SClement Deschamps case SDDATA: 27043ddc182SClement Deschamps res = bcm2835_sdhost_fifo_pop(s); 27143ddc182SClement Deschamps bcm2835_sdhost_fifo_run(s); 27243ddc182SClement Deschamps break; 27343ddc182SClement Deschamps case SDHBCT: 27443ddc182SClement Deschamps res = s->hbct; 27543ddc182SClement Deschamps break; 27643ddc182SClement Deschamps case SDHBLC: 27743ddc182SClement Deschamps res = s->hblc; 27843ddc182SClement Deschamps break; 27943ddc182SClement Deschamps 28043ddc182SClement Deschamps default: 28143ddc182SClement Deschamps qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset %"HWADDR_PRIx"\n", 28243ddc182SClement Deschamps __func__, offset); 28343ddc182SClement Deschamps res = 0; 28443ddc182SClement Deschamps break; 28543ddc182SClement Deschamps } 28643ddc182SClement Deschamps 287*b318f326SPeter Maydell trace_bcm2835_sdhost_read(offset, res, size); 288*b318f326SPeter Maydell 28943ddc182SClement Deschamps return res; 29043ddc182SClement Deschamps } 29143ddc182SClement Deschamps 29243ddc182SClement Deschamps static void bcm2835_sdhost_write(void *opaque, hwaddr offset, 29343ddc182SClement Deschamps uint64_t value, unsigned size) 29443ddc182SClement Deschamps { 29543ddc182SClement Deschamps BCM2835SDHostState *s = (BCM2835SDHostState *)opaque; 29643ddc182SClement Deschamps 297*b318f326SPeter Maydell trace_bcm2835_sdhost_write(offset, value, size); 298*b318f326SPeter Maydell 29943ddc182SClement Deschamps switch (offset) { 30043ddc182SClement Deschamps case SDCMD: 30143ddc182SClement Deschamps s->cmd = value; 30243ddc182SClement Deschamps if (value & SDCMD_NEW_FLAG) { 30343ddc182SClement Deschamps bcm2835_sdhost_send_command(s); 30443ddc182SClement Deschamps bcm2835_sdhost_fifo_run(s); 30543ddc182SClement Deschamps s->cmd &= ~SDCMD_NEW_FLAG; 30643ddc182SClement Deschamps } 30743ddc182SClement Deschamps break; 30843ddc182SClement Deschamps case SDTOUT: 30943ddc182SClement Deschamps break; 31043ddc182SClement Deschamps case SDCDIV: 31143ddc182SClement Deschamps break; 31243ddc182SClement Deschamps case SDHSTS: 31343ddc182SClement Deschamps s->status &= ~value; 31443ddc182SClement Deschamps bcm2835_sdhost_update_irq(s); 31543ddc182SClement Deschamps break; 31643ddc182SClement Deschamps case SDARG: 31743ddc182SClement Deschamps s->cmdarg = value; 31843ddc182SClement Deschamps break; 31943ddc182SClement Deschamps case SDEDM: 32043ddc182SClement Deschamps if ((value & 0xf) == 0xf) { 32143ddc182SClement Deschamps /* power down */ 32243ddc182SClement Deschamps value &= ~0xf; 32343ddc182SClement Deschamps } 32443ddc182SClement Deschamps s->edm = value; 325*b318f326SPeter Maydell trace_bcm2835_sdhost_edm_change("guest register write", s->edm); 32643ddc182SClement Deschamps break; 32743ddc182SClement Deschamps case SDHCFG: 32843ddc182SClement Deschamps s->config = value; 32943ddc182SClement Deschamps bcm2835_sdhost_fifo_run(s); 33043ddc182SClement Deschamps break; 33143ddc182SClement Deschamps case SDVDD: 33243ddc182SClement Deschamps s->vdd = value; 33343ddc182SClement Deschamps break; 33443ddc182SClement Deschamps case SDDATA: 33543ddc182SClement Deschamps bcm2835_sdhost_fifo_push(s, value); 33643ddc182SClement Deschamps bcm2835_sdhost_fifo_run(s); 33743ddc182SClement Deschamps break; 33843ddc182SClement Deschamps case SDHBCT: 33943ddc182SClement Deschamps s->hbct = value; 34043ddc182SClement Deschamps break; 34143ddc182SClement Deschamps case SDHBLC: 34243ddc182SClement Deschamps s->hblc = value; 34343ddc182SClement Deschamps s->datacnt = s->hblc * s->hbct; 34443ddc182SClement Deschamps bcm2835_sdhost_fifo_run(s); 34543ddc182SClement Deschamps break; 34643ddc182SClement Deschamps 34743ddc182SClement Deschamps default: 34843ddc182SClement Deschamps qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset %"HWADDR_PRIx"\n", 34943ddc182SClement Deschamps __func__, offset); 35043ddc182SClement Deschamps break; 35143ddc182SClement Deschamps } 35243ddc182SClement Deschamps } 35343ddc182SClement Deschamps 35443ddc182SClement Deschamps static const MemoryRegionOps bcm2835_sdhost_ops = { 35543ddc182SClement Deschamps .read = bcm2835_sdhost_read, 35643ddc182SClement Deschamps .write = bcm2835_sdhost_write, 35743ddc182SClement Deschamps .endianness = DEVICE_NATIVE_ENDIAN, 35843ddc182SClement Deschamps }; 35943ddc182SClement Deschamps 36043ddc182SClement Deschamps static const VMStateDescription vmstate_bcm2835_sdhost = { 36143ddc182SClement Deschamps .name = TYPE_BCM2835_SDHOST, 36243ddc182SClement Deschamps .version_id = 1, 36343ddc182SClement Deschamps .minimum_version_id = 1, 36443ddc182SClement Deschamps .fields = (VMStateField[]) { 36543ddc182SClement Deschamps VMSTATE_UINT32(cmd, BCM2835SDHostState), 36643ddc182SClement Deschamps VMSTATE_UINT32(cmdarg, BCM2835SDHostState), 36743ddc182SClement Deschamps VMSTATE_UINT32(status, BCM2835SDHostState), 36843ddc182SClement Deschamps VMSTATE_UINT32_ARRAY(rsp, BCM2835SDHostState, 4), 36943ddc182SClement Deschamps VMSTATE_UINT32(config, BCM2835SDHostState), 37043ddc182SClement Deschamps VMSTATE_UINT32(edm, BCM2835SDHostState), 37143ddc182SClement Deschamps VMSTATE_UINT32(vdd, BCM2835SDHostState), 37243ddc182SClement Deschamps VMSTATE_UINT32(hbct, BCM2835SDHostState), 37343ddc182SClement Deschamps VMSTATE_UINT32(hblc, BCM2835SDHostState), 37443ddc182SClement Deschamps VMSTATE_INT32(fifo_pos, BCM2835SDHostState), 37543ddc182SClement Deschamps VMSTATE_INT32(fifo_len, BCM2835SDHostState), 37643ddc182SClement Deschamps VMSTATE_UINT32_ARRAY(fifo, BCM2835SDHostState, BCM2835_SDHOST_FIFO_LEN), 37743ddc182SClement Deschamps VMSTATE_UINT32(datacnt, BCM2835SDHostState), 37843ddc182SClement Deschamps VMSTATE_END_OF_LIST() 37943ddc182SClement Deschamps } 38043ddc182SClement Deschamps }; 38143ddc182SClement Deschamps 38243ddc182SClement Deschamps static void bcm2835_sdhost_init(Object *obj) 38343ddc182SClement Deschamps { 38443ddc182SClement Deschamps BCM2835SDHostState *s = BCM2835_SDHOST(obj); 38543ddc182SClement Deschamps 38643ddc182SClement Deschamps qbus_create_inplace(&s->sdbus, sizeof(s->sdbus), 38743ddc182SClement Deschamps TYPE_BCM2835_SDHOST_BUS, DEVICE(s), "sd-bus"); 38843ddc182SClement Deschamps 38943ddc182SClement Deschamps memory_region_init_io(&s->iomem, obj, &bcm2835_sdhost_ops, s, 39043ddc182SClement Deschamps TYPE_BCM2835_SDHOST, 0x1000); 39143ddc182SClement Deschamps sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->iomem); 39243ddc182SClement Deschamps sysbus_init_irq(SYS_BUS_DEVICE(s), &s->irq); 39343ddc182SClement Deschamps } 39443ddc182SClement Deschamps 39543ddc182SClement Deschamps static void bcm2835_sdhost_reset(DeviceState *dev) 39643ddc182SClement Deschamps { 39743ddc182SClement Deschamps BCM2835SDHostState *s = BCM2835_SDHOST(dev); 39843ddc182SClement Deschamps 39943ddc182SClement Deschamps s->cmd = 0; 40043ddc182SClement Deschamps s->cmdarg = 0; 40143ddc182SClement Deschamps s->edm = 0x0000c60f; 402*b318f326SPeter Maydell trace_bcm2835_sdhost_edm_change("device reset", s->edm); 40343ddc182SClement Deschamps s->config = 0; 40443ddc182SClement Deschamps s->hbct = 0; 40543ddc182SClement Deschamps s->hblc = 0; 40643ddc182SClement Deschamps s->datacnt = 0; 40743ddc182SClement Deschamps s->fifo_pos = 0; 40843ddc182SClement Deschamps s->fifo_len = 0; 40943ddc182SClement Deschamps } 41043ddc182SClement Deschamps 41143ddc182SClement Deschamps static void bcm2835_sdhost_class_init(ObjectClass *klass, void *data) 41243ddc182SClement Deschamps { 41343ddc182SClement Deschamps DeviceClass *dc = DEVICE_CLASS(klass); 41443ddc182SClement Deschamps 41543ddc182SClement Deschamps dc->reset = bcm2835_sdhost_reset; 41643ddc182SClement Deschamps dc->vmsd = &vmstate_bcm2835_sdhost; 41743ddc182SClement Deschamps } 41843ddc182SClement Deschamps 41943ddc182SClement Deschamps static TypeInfo bcm2835_sdhost_info = { 42043ddc182SClement Deschamps .name = TYPE_BCM2835_SDHOST, 42143ddc182SClement Deschamps .parent = TYPE_SYS_BUS_DEVICE, 42243ddc182SClement Deschamps .instance_size = sizeof(BCM2835SDHostState), 42343ddc182SClement Deschamps .class_init = bcm2835_sdhost_class_init, 42443ddc182SClement Deschamps .instance_init = bcm2835_sdhost_init, 42543ddc182SClement Deschamps }; 42643ddc182SClement Deschamps 42743ddc182SClement Deschamps static const TypeInfo bcm2835_sdhost_bus_info = { 42843ddc182SClement Deschamps .name = TYPE_BCM2835_SDHOST_BUS, 42943ddc182SClement Deschamps .parent = TYPE_SD_BUS, 43043ddc182SClement Deschamps .instance_size = sizeof(SDBus), 43143ddc182SClement Deschamps }; 43243ddc182SClement Deschamps 43343ddc182SClement Deschamps static void bcm2835_sdhost_register_types(void) 43443ddc182SClement Deschamps { 43543ddc182SClement Deschamps type_register_static(&bcm2835_sdhost_info); 43643ddc182SClement Deschamps type_register_static(&bcm2835_sdhost_bus_info); 43743ddc182SClement Deschamps } 43843ddc182SClement Deschamps 43943ddc182SClement Deschamps type_init(bcm2835_sdhost_register_types) 440