1*82e48382SNiek Linnenbank /* 2*82e48382SNiek Linnenbank * Allwinner (sun4i and above) SD Host Controller emulation 3*82e48382SNiek Linnenbank * 4*82e48382SNiek Linnenbank * Copyright (C) 2019 Niek Linnenbank <nieklinnenbank@gmail.com> 5*82e48382SNiek Linnenbank * 6*82e48382SNiek Linnenbank * This program is free software: you can redistribute it and/or modify 7*82e48382SNiek Linnenbank * it under the terms of the GNU General Public License as published by 8*82e48382SNiek Linnenbank * the Free Software Foundation, either version 2 of the License, or 9*82e48382SNiek Linnenbank * (at your option) any later version. 10*82e48382SNiek Linnenbank * 11*82e48382SNiek Linnenbank * This program is distributed in the hope that it will be useful, 12*82e48382SNiek Linnenbank * but WITHOUT ANY WARRANTY; without even the implied warranty of 13*82e48382SNiek Linnenbank * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14*82e48382SNiek Linnenbank * GNU General Public License for more details. 15*82e48382SNiek Linnenbank * 16*82e48382SNiek Linnenbank * You should have received a copy of the GNU General Public License 17*82e48382SNiek Linnenbank * along with this program. If not, see <http://www.gnu.org/licenses/>. 18*82e48382SNiek Linnenbank */ 19*82e48382SNiek Linnenbank 20*82e48382SNiek Linnenbank #include "qemu/osdep.h" 21*82e48382SNiek Linnenbank #include "qemu/log.h" 22*82e48382SNiek Linnenbank #include "qemu/module.h" 23*82e48382SNiek Linnenbank #include "qemu/units.h" 24*82e48382SNiek Linnenbank #include "sysemu/blockdev.h" 25*82e48382SNiek Linnenbank #include "hw/irq.h" 26*82e48382SNiek Linnenbank #include "hw/sd/allwinner-sdhost.h" 27*82e48382SNiek Linnenbank #include "migration/vmstate.h" 28*82e48382SNiek Linnenbank #include "trace.h" 29*82e48382SNiek Linnenbank 30*82e48382SNiek Linnenbank #define TYPE_AW_SDHOST_BUS "allwinner-sdhost-bus" 31*82e48382SNiek Linnenbank #define AW_SDHOST_BUS(obj) \ 32*82e48382SNiek Linnenbank OBJECT_CHECK(SDBus, (obj), TYPE_AW_SDHOST_BUS) 33*82e48382SNiek Linnenbank 34*82e48382SNiek Linnenbank /* SD Host register offsets */ 35*82e48382SNiek Linnenbank enum { 36*82e48382SNiek Linnenbank REG_SD_GCTL = 0x00, /* Global Control */ 37*82e48382SNiek Linnenbank REG_SD_CKCR = 0x04, /* Clock Control */ 38*82e48382SNiek Linnenbank REG_SD_TMOR = 0x08, /* Timeout */ 39*82e48382SNiek Linnenbank REG_SD_BWDR = 0x0C, /* Bus Width */ 40*82e48382SNiek Linnenbank REG_SD_BKSR = 0x10, /* Block Size */ 41*82e48382SNiek Linnenbank REG_SD_BYCR = 0x14, /* Byte Count */ 42*82e48382SNiek Linnenbank REG_SD_CMDR = 0x18, /* Command */ 43*82e48382SNiek Linnenbank REG_SD_CAGR = 0x1C, /* Command Argument */ 44*82e48382SNiek Linnenbank REG_SD_RESP0 = 0x20, /* Response Zero */ 45*82e48382SNiek Linnenbank REG_SD_RESP1 = 0x24, /* Response One */ 46*82e48382SNiek Linnenbank REG_SD_RESP2 = 0x28, /* Response Two */ 47*82e48382SNiek Linnenbank REG_SD_RESP3 = 0x2C, /* Response Three */ 48*82e48382SNiek Linnenbank REG_SD_IMKR = 0x30, /* Interrupt Mask */ 49*82e48382SNiek Linnenbank REG_SD_MISR = 0x34, /* Masked Interrupt Status */ 50*82e48382SNiek Linnenbank REG_SD_RISR = 0x38, /* Raw Interrupt Status */ 51*82e48382SNiek Linnenbank REG_SD_STAR = 0x3C, /* Status */ 52*82e48382SNiek Linnenbank REG_SD_FWLR = 0x40, /* FIFO Water Level */ 53*82e48382SNiek Linnenbank REG_SD_FUNS = 0x44, /* FIFO Function Select */ 54*82e48382SNiek Linnenbank REG_SD_DBGC = 0x50, /* Debug Enable */ 55*82e48382SNiek Linnenbank REG_SD_A12A = 0x58, /* Auto command 12 argument */ 56*82e48382SNiek Linnenbank REG_SD_NTSR = 0x5C, /* SD NewTiming Set */ 57*82e48382SNiek Linnenbank REG_SD_SDBG = 0x60, /* SD newTiming Set Debug */ 58*82e48382SNiek Linnenbank REG_SD_HWRST = 0x78, /* Hardware Reset Register */ 59*82e48382SNiek Linnenbank REG_SD_DMAC = 0x80, /* Internal DMA Controller Control */ 60*82e48382SNiek Linnenbank REG_SD_DLBA = 0x84, /* Descriptor List Base Address */ 61*82e48382SNiek Linnenbank REG_SD_IDST = 0x88, /* Internal DMA Controller Status */ 62*82e48382SNiek Linnenbank REG_SD_IDIE = 0x8C, /* Internal DMA Controller IRQ Enable */ 63*82e48382SNiek Linnenbank REG_SD_THLDC = 0x100, /* Card Threshold Control */ 64*82e48382SNiek Linnenbank REG_SD_DSBD = 0x10C, /* eMMC DDR Start Bit Detection Control */ 65*82e48382SNiek Linnenbank REG_SD_RES_CRC = 0x110, /* Response CRC from card/eMMC */ 66*82e48382SNiek Linnenbank REG_SD_DATA7_CRC = 0x114, /* CRC Data 7 from card/eMMC */ 67*82e48382SNiek Linnenbank REG_SD_DATA6_CRC = 0x118, /* CRC Data 6 from card/eMMC */ 68*82e48382SNiek Linnenbank REG_SD_DATA5_CRC = 0x11C, /* CRC Data 5 from card/eMMC */ 69*82e48382SNiek Linnenbank REG_SD_DATA4_CRC = 0x120, /* CRC Data 4 from card/eMMC */ 70*82e48382SNiek Linnenbank REG_SD_DATA3_CRC = 0x124, /* CRC Data 3 from card/eMMC */ 71*82e48382SNiek Linnenbank REG_SD_DATA2_CRC = 0x128, /* CRC Data 2 from card/eMMC */ 72*82e48382SNiek Linnenbank REG_SD_DATA1_CRC = 0x12C, /* CRC Data 1 from card/eMMC */ 73*82e48382SNiek Linnenbank REG_SD_DATA0_CRC = 0x130, /* CRC Data 0 from card/eMMC */ 74*82e48382SNiek Linnenbank REG_SD_CRC_STA = 0x134, /* CRC status from card/eMMC during write */ 75*82e48382SNiek Linnenbank REG_SD_FIFO = 0x200, /* Read/Write FIFO */ 76*82e48382SNiek Linnenbank }; 77*82e48382SNiek Linnenbank 78*82e48382SNiek Linnenbank /* SD Host register flags */ 79*82e48382SNiek Linnenbank enum { 80*82e48382SNiek Linnenbank SD_GCTL_FIFO_AC_MOD = (1 << 31), 81*82e48382SNiek Linnenbank SD_GCTL_DDR_MOD_SEL = (1 << 10), 82*82e48382SNiek Linnenbank SD_GCTL_CD_DBC_ENB = (1 << 8), 83*82e48382SNiek Linnenbank SD_GCTL_DMA_ENB = (1 << 5), 84*82e48382SNiek Linnenbank SD_GCTL_INT_ENB = (1 << 4), 85*82e48382SNiek Linnenbank SD_GCTL_DMA_RST = (1 << 2), 86*82e48382SNiek Linnenbank SD_GCTL_FIFO_RST = (1 << 1), 87*82e48382SNiek Linnenbank SD_GCTL_SOFT_RST = (1 << 0), 88*82e48382SNiek Linnenbank }; 89*82e48382SNiek Linnenbank 90*82e48382SNiek Linnenbank enum { 91*82e48382SNiek Linnenbank SD_CMDR_LOAD = (1 << 31), 92*82e48382SNiek Linnenbank SD_CMDR_CLKCHANGE = (1 << 21), 93*82e48382SNiek Linnenbank SD_CMDR_WRITE = (1 << 10), 94*82e48382SNiek Linnenbank SD_CMDR_AUTOSTOP = (1 << 12), 95*82e48382SNiek Linnenbank SD_CMDR_DATA = (1 << 9), 96*82e48382SNiek Linnenbank SD_CMDR_RESPONSE_LONG = (1 << 7), 97*82e48382SNiek Linnenbank SD_CMDR_RESPONSE = (1 << 6), 98*82e48382SNiek Linnenbank SD_CMDR_CMDID_MASK = (0x3f), 99*82e48382SNiek Linnenbank }; 100*82e48382SNiek Linnenbank 101*82e48382SNiek Linnenbank enum { 102*82e48382SNiek Linnenbank SD_RISR_CARD_REMOVE = (1 << 31), 103*82e48382SNiek Linnenbank SD_RISR_CARD_INSERT = (1 << 30), 104*82e48382SNiek Linnenbank SD_RISR_SDIO_INTR = (1 << 16), 105*82e48382SNiek Linnenbank SD_RISR_AUTOCMD_DONE = (1 << 14), 106*82e48382SNiek Linnenbank SD_RISR_DATA_COMPLETE = (1 << 3), 107*82e48382SNiek Linnenbank SD_RISR_CMD_COMPLETE = (1 << 2), 108*82e48382SNiek Linnenbank SD_RISR_NO_RESPONSE = (1 << 1), 109*82e48382SNiek Linnenbank }; 110*82e48382SNiek Linnenbank 111*82e48382SNiek Linnenbank enum { 112*82e48382SNiek Linnenbank SD_STAR_CARD_PRESENT = (1 << 8), 113*82e48382SNiek Linnenbank }; 114*82e48382SNiek Linnenbank 115*82e48382SNiek Linnenbank enum { 116*82e48382SNiek Linnenbank SD_IDST_INT_SUMMARY = (1 << 8), 117*82e48382SNiek Linnenbank SD_IDST_RECEIVE_IRQ = (1 << 1), 118*82e48382SNiek Linnenbank SD_IDST_TRANSMIT_IRQ = (1 << 0), 119*82e48382SNiek Linnenbank SD_IDST_IRQ_MASK = (1 << 1) | (1 << 0) | (1 << 8), 120*82e48382SNiek Linnenbank SD_IDST_WR_MASK = (0x3ff), 121*82e48382SNiek Linnenbank }; 122*82e48382SNiek Linnenbank 123*82e48382SNiek Linnenbank /* SD Host register reset values */ 124*82e48382SNiek Linnenbank enum { 125*82e48382SNiek Linnenbank REG_SD_GCTL_RST = 0x00000300, 126*82e48382SNiek Linnenbank REG_SD_CKCR_RST = 0x0, 127*82e48382SNiek Linnenbank REG_SD_TMOR_RST = 0xFFFFFF40, 128*82e48382SNiek Linnenbank REG_SD_BWDR_RST = 0x0, 129*82e48382SNiek Linnenbank REG_SD_BKSR_RST = 0x00000200, 130*82e48382SNiek Linnenbank REG_SD_BYCR_RST = 0x00000200, 131*82e48382SNiek Linnenbank REG_SD_CMDR_RST = 0x0, 132*82e48382SNiek Linnenbank REG_SD_CAGR_RST = 0x0, 133*82e48382SNiek Linnenbank REG_SD_RESP_RST = 0x0, 134*82e48382SNiek Linnenbank REG_SD_IMKR_RST = 0x0, 135*82e48382SNiek Linnenbank REG_SD_MISR_RST = 0x0, 136*82e48382SNiek Linnenbank REG_SD_RISR_RST = 0x0, 137*82e48382SNiek Linnenbank REG_SD_STAR_RST = 0x00000100, 138*82e48382SNiek Linnenbank REG_SD_FWLR_RST = 0x000F0000, 139*82e48382SNiek Linnenbank REG_SD_FUNS_RST = 0x0, 140*82e48382SNiek Linnenbank REG_SD_DBGC_RST = 0x0, 141*82e48382SNiek Linnenbank REG_SD_A12A_RST = 0x0000FFFF, 142*82e48382SNiek Linnenbank REG_SD_NTSR_RST = 0x00000001, 143*82e48382SNiek Linnenbank REG_SD_SDBG_RST = 0x0, 144*82e48382SNiek Linnenbank REG_SD_HWRST_RST = 0x00000001, 145*82e48382SNiek Linnenbank REG_SD_DMAC_RST = 0x0, 146*82e48382SNiek Linnenbank REG_SD_DLBA_RST = 0x0, 147*82e48382SNiek Linnenbank REG_SD_IDST_RST = 0x0, 148*82e48382SNiek Linnenbank REG_SD_IDIE_RST = 0x0, 149*82e48382SNiek Linnenbank REG_SD_THLDC_RST = 0x0, 150*82e48382SNiek Linnenbank REG_SD_DSBD_RST = 0x0, 151*82e48382SNiek Linnenbank REG_SD_RES_CRC_RST = 0x0, 152*82e48382SNiek Linnenbank REG_SD_DATA_CRC_RST = 0x0, 153*82e48382SNiek Linnenbank REG_SD_CRC_STA_RST = 0x0, 154*82e48382SNiek Linnenbank REG_SD_FIFO_RST = 0x0, 155*82e48382SNiek Linnenbank }; 156*82e48382SNiek Linnenbank 157*82e48382SNiek Linnenbank /* Data transfer descriptor for DMA */ 158*82e48382SNiek Linnenbank typedef struct TransferDescriptor { 159*82e48382SNiek Linnenbank uint32_t status; /* Status flags */ 160*82e48382SNiek Linnenbank uint32_t size; /* Data buffer size */ 161*82e48382SNiek Linnenbank uint32_t addr; /* Data buffer address */ 162*82e48382SNiek Linnenbank uint32_t next; /* Physical address of next descriptor */ 163*82e48382SNiek Linnenbank } TransferDescriptor; 164*82e48382SNiek Linnenbank 165*82e48382SNiek Linnenbank /* Data transfer descriptor flags */ 166*82e48382SNiek Linnenbank enum { 167*82e48382SNiek Linnenbank DESC_STATUS_HOLD = (1 << 31), /* Set when descriptor is in use by DMA */ 168*82e48382SNiek Linnenbank DESC_STATUS_ERROR = (1 << 30), /* Set when DMA transfer error occurred */ 169*82e48382SNiek Linnenbank DESC_STATUS_CHAIN = (1 << 4), /* Indicates chained descriptor. */ 170*82e48382SNiek Linnenbank DESC_STATUS_FIRST = (1 << 3), /* Set on the first descriptor */ 171*82e48382SNiek Linnenbank DESC_STATUS_LAST = (1 << 2), /* Set on the last descriptor */ 172*82e48382SNiek Linnenbank DESC_STATUS_NOIRQ = (1 << 1), /* Skip raising interrupt after transfer */ 173*82e48382SNiek Linnenbank DESC_SIZE_MASK = (0xfffffffc) 174*82e48382SNiek Linnenbank }; 175*82e48382SNiek Linnenbank 176*82e48382SNiek Linnenbank static void allwinner_sdhost_update_irq(AwSdHostState *s) 177*82e48382SNiek Linnenbank { 178*82e48382SNiek Linnenbank uint32_t irq; 179*82e48382SNiek Linnenbank 180*82e48382SNiek Linnenbank if (s->global_ctl & SD_GCTL_INT_ENB) { 181*82e48382SNiek Linnenbank irq = s->irq_status & s->irq_mask; 182*82e48382SNiek Linnenbank } else { 183*82e48382SNiek Linnenbank irq = 0; 184*82e48382SNiek Linnenbank } 185*82e48382SNiek Linnenbank 186*82e48382SNiek Linnenbank trace_allwinner_sdhost_update_irq(irq); 187*82e48382SNiek Linnenbank qemu_set_irq(s->irq, irq); 188*82e48382SNiek Linnenbank } 189*82e48382SNiek Linnenbank 190*82e48382SNiek Linnenbank static void allwinner_sdhost_update_transfer_cnt(AwSdHostState *s, 191*82e48382SNiek Linnenbank uint32_t bytes) 192*82e48382SNiek Linnenbank { 193*82e48382SNiek Linnenbank if (s->transfer_cnt > bytes) { 194*82e48382SNiek Linnenbank s->transfer_cnt -= bytes; 195*82e48382SNiek Linnenbank } else { 196*82e48382SNiek Linnenbank s->transfer_cnt = 0; 197*82e48382SNiek Linnenbank } 198*82e48382SNiek Linnenbank 199*82e48382SNiek Linnenbank if (!s->transfer_cnt) { 200*82e48382SNiek Linnenbank s->irq_status |= SD_RISR_DATA_COMPLETE; 201*82e48382SNiek Linnenbank } 202*82e48382SNiek Linnenbank } 203*82e48382SNiek Linnenbank 204*82e48382SNiek Linnenbank static void allwinner_sdhost_set_inserted(DeviceState *dev, bool inserted) 205*82e48382SNiek Linnenbank { 206*82e48382SNiek Linnenbank AwSdHostState *s = AW_SDHOST(dev); 207*82e48382SNiek Linnenbank 208*82e48382SNiek Linnenbank trace_allwinner_sdhost_set_inserted(inserted); 209*82e48382SNiek Linnenbank 210*82e48382SNiek Linnenbank if (inserted) { 211*82e48382SNiek Linnenbank s->irq_status |= SD_RISR_CARD_INSERT; 212*82e48382SNiek Linnenbank s->irq_status &= ~SD_RISR_CARD_REMOVE; 213*82e48382SNiek Linnenbank s->status |= SD_STAR_CARD_PRESENT; 214*82e48382SNiek Linnenbank } else { 215*82e48382SNiek Linnenbank s->irq_status &= ~SD_RISR_CARD_INSERT; 216*82e48382SNiek Linnenbank s->irq_status |= SD_RISR_CARD_REMOVE; 217*82e48382SNiek Linnenbank s->status &= ~SD_STAR_CARD_PRESENT; 218*82e48382SNiek Linnenbank } 219*82e48382SNiek Linnenbank 220*82e48382SNiek Linnenbank allwinner_sdhost_update_irq(s); 221*82e48382SNiek Linnenbank } 222*82e48382SNiek Linnenbank 223*82e48382SNiek Linnenbank static void allwinner_sdhost_send_command(AwSdHostState *s) 224*82e48382SNiek Linnenbank { 225*82e48382SNiek Linnenbank SDRequest request; 226*82e48382SNiek Linnenbank uint8_t resp[16]; 227*82e48382SNiek Linnenbank int rlen; 228*82e48382SNiek Linnenbank 229*82e48382SNiek Linnenbank /* Auto clear load flag */ 230*82e48382SNiek Linnenbank s->command &= ~SD_CMDR_LOAD; 231*82e48382SNiek Linnenbank 232*82e48382SNiek Linnenbank /* Clock change does not actually interact with the SD bus */ 233*82e48382SNiek Linnenbank if (!(s->command & SD_CMDR_CLKCHANGE)) { 234*82e48382SNiek Linnenbank 235*82e48382SNiek Linnenbank /* Prepare request */ 236*82e48382SNiek Linnenbank request.cmd = s->command & SD_CMDR_CMDID_MASK; 237*82e48382SNiek Linnenbank request.arg = s->command_arg; 238*82e48382SNiek Linnenbank 239*82e48382SNiek Linnenbank /* Send request to SD bus */ 240*82e48382SNiek Linnenbank rlen = sdbus_do_command(&s->sdbus, &request, resp); 241*82e48382SNiek Linnenbank if (rlen < 0) { 242*82e48382SNiek Linnenbank goto error; 243*82e48382SNiek Linnenbank } 244*82e48382SNiek Linnenbank 245*82e48382SNiek Linnenbank /* If the command has a response, store it in the response registers */ 246*82e48382SNiek Linnenbank if ((s->command & SD_CMDR_RESPONSE)) { 247*82e48382SNiek Linnenbank if (rlen == 4 && !(s->command & SD_CMDR_RESPONSE_LONG)) { 248*82e48382SNiek Linnenbank s->response[0] = ldl_be_p(&resp[0]); 249*82e48382SNiek Linnenbank s->response[1] = s->response[2] = s->response[3] = 0; 250*82e48382SNiek Linnenbank 251*82e48382SNiek Linnenbank } else if (rlen == 16 && (s->command & SD_CMDR_RESPONSE_LONG)) { 252*82e48382SNiek Linnenbank s->response[0] = ldl_be_p(&resp[12]); 253*82e48382SNiek Linnenbank s->response[1] = ldl_be_p(&resp[8]); 254*82e48382SNiek Linnenbank s->response[2] = ldl_be_p(&resp[4]); 255*82e48382SNiek Linnenbank s->response[3] = ldl_be_p(&resp[0]); 256*82e48382SNiek Linnenbank } else { 257*82e48382SNiek Linnenbank goto error; 258*82e48382SNiek Linnenbank } 259*82e48382SNiek Linnenbank } 260*82e48382SNiek Linnenbank } 261*82e48382SNiek Linnenbank 262*82e48382SNiek Linnenbank /* Set interrupt status bits */ 263*82e48382SNiek Linnenbank s->irq_status |= SD_RISR_CMD_COMPLETE; 264*82e48382SNiek Linnenbank return; 265*82e48382SNiek Linnenbank 266*82e48382SNiek Linnenbank error: 267*82e48382SNiek Linnenbank s->irq_status |= SD_RISR_NO_RESPONSE; 268*82e48382SNiek Linnenbank } 269*82e48382SNiek Linnenbank 270*82e48382SNiek Linnenbank static void allwinner_sdhost_auto_stop(AwSdHostState *s) 271*82e48382SNiek Linnenbank { 272*82e48382SNiek Linnenbank /* 273*82e48382SNiek Linnenbank * The stop command (CMD12) ensures the SD bus 274*82e48382SNiek Linnenbank * returns to the transfer state. 275*82e48382SNiek Linnenbank */ 276*82e48382SNiek Linnenbank if ((s->command & SD_CMDR_AUTOSTOP) && (s->transfer_cnt == 0)) { 277*82e48382SNiek Linnenbank /* First save current command registers */ 278*82e48382SNiek Linnenbank uint32_t saved_cmd = s->command; 279*82e48382SNiek Linnenbank uint32_t saved_arg = s->command_arg; 280*82e48382SNiek Linnenbank 281*82e48382SNiek Linnenbank /* Prepare stop command (CMD12) */ 282*82e48382SNiek Linnenbank s->command &= ~SD_CMDR_CMDID_MASK; 283*82e48382SNiek Linnenbank s->command |= 12; /* CMD12 */ 284*82e48382SNiek Linnenbank s->command_arg = 0; 285*82e48382SNiek Linnenbank 286*82e48382SNiek Linnenbank /* Put the command on SD bus */ 287*82e48382SNiek Linnenbank allwinner_sdhost_send_command(s); 288*82e48382SNiek Linnenbank 289*82e48382SNiek Linnenbank /* Restore command values */ 290*82e48382SNiek Linnenbank s->command = saved_cmd; 291*82e48382SNiek Linnenbank s->command_arg = saved_arg; 292*82e48382SNiek Linnenbank 293*82e48382SNiek Linnenbank /* Set IRQ status bit for automatic stop done */ 294*82e48382SNiek Linnenbank s->irq_status |= SD_RISR_AUTOCMD_DONE; 295*82e48382SNiek Linnenbank } 296*82e48382SNiek Linnenbank } 297*82e48382SNiek Linnenbank 298*82e48382SNiek Linnenbank static uint32_t allwinner_sdhost_process_desc(AwSdHostState *s, 299*82e48382SNiek Linnenbank hwaddr desc_addr, 300*82e48382SNiek Linnenbank TransferDescriptor *desc, 301*82e48382SNiek Linnenbank bool is_write, uint32_t max_bytes) 302*82e48382SNiek Linnenbank { 303*82e48382SNiek Linnenbank AwSdHostClass *klass = AW_SDHOST_GET_CLASS(s); 304*82e48382SNiek Linnenbank uint32_t num_done = 0; 305*82e48382SNiek Linnenbank uint32_t num_bytes = max_bytes; 306*82e48382SNiek Linnenbank uint8_t buf[1024]; 307*82e48382SNiek Linnenbank 308*82e48382SNiek Linnenbank /* Read descriptor */ 309*82e48382SNiek Linnenbank cpu_physical_memory_read(desc_addr, desc, sizeof(*desc)); 310*82e48382SNiek Linnenbank if (desc->size == 0) { 311*82e48382SNiek Linnenbank desc->size = klass->max_desc_size; 312*82e48382SNiek Linnenbank } else if (desc->size > klass->max_desc_size) { 313*82e48382SNiek Linnenbank qemu_log_mask(LOG_GUEST_ERROR, "%s: DMA descriptor buffer size " 314*82e48382SNiek Linnenbank " is out-of-bounds: %" PRIu32 " > %zu", 315*82e48382SNiek Linnenbank __func__, desc->size, klass->max_desc_size); 316*82e48382SNiek Linnenbank desc->size = klass->max_desc_size; 317*82e48382SNiek Linnenbank } 318*82e48382SNiek Linnenbank if (desc->size < num_bytes) { 319*82e48382SNiek Linnenbank num_bytes = desc->size; 320*82e48382SNiek Linnenbank } 321*82e48382SNiek Linnenbank 322*82e48382SNiek Linnenbank trace_allwinner_sdhost_process_desc(desc_addr, desc->size, 323*82e48382SNiek Linnenbank is_write, max_bytes); 324*82e48382SNiek Linnenbank 325*82e48382SNiek Linnenbank while (num_done < num_bytes) { 326*82e48382SNiek Linnenbank /* Try to completely fill the local buffer */ 327*82e48382SNiek Linnenbank uint32_t buf_bytes = num_bytes - num_done; 328*82e48382SNiek Linnenbank if (buf_bytes > sizeof(buf)) { 329*82e48382SNiek Linnenbank buf_bytes = sizeof(buf); 330*82e48382SNiek Linnenbank } 331*82e48382SNiek Linnenbank 332*82e48382SNiek Linnenbank /* Write to SD bus */ 333*82e48382SNiek Linnenbank if (is_write) { 334*82e48382SNiek Linnenbank cpu_physical_memory_read((desc->addr & DESC_SIZE_MASK) + num_done, 335*82e48382SNiek Linnenbank buf, buf_bytes); 336*82e48382SNiek Linnenbank 337*82e48382SNiek Linnenbank for (uint32_t i = 0; i < buf_bytes; i++) { 338*82e48382SNiek Linnenbank sdbus_write_data(&s->sdbus, buf[i]); 339*82e48382SNiek Linnenbank } 340*82e48382SNiek Linnenbank 341*82e48382SNiek Linnenbank /* Read from SD bus */ 342*82e48382SNiek Linnenbank } else { 343*82e48382SNiek Linnenbank for (uint32_t i = 0; i < buf_bytes; i++) { 344*82e48382SNiek Linnenbank buf[i] = sdbus_read_data(&s->sdbus); 345*82e48382SNiek Linnenbank } 346*82e48382SNiek Linnenbank cpu_physical_memory_write((desc->addr & DESC_SIZE_MASK) + num_done, 347*82e48382SNiek Linnenbank buf, buf_bytes); 348*82e48382SNiek Linnenbank } 349*82e48382SNiek Linnenbank num_done += buf_bytes; 350*82e48382SNiek Linnenbank } 351*82e48382SNiek Linnenbank 352*82e48382SNiek Linnenbank /* Clear hold flag and flush descriptor */ 353*82e48382SNiek Linnenbank desc->status &= ~DESC_STATUS_HOLD; 354*82e48382SNiek Linnenbank cpu_physical_memory_write(desc_addr, desc, sizeof(*desc)); 355*82e48382SNiek Linnenbank 356*82e48382SNiek Linnenbank return num_done; 357*82e48382SNiek Linnenbank } 358*82e48382SNiek Linnenbank 359*82e48382SNiek Linnenbank static void allwinner_sdhost_dma(AwSdHostState *s) 360*82e48382SNiek Linnenbank { 361*82e48382SNiek Linnenbank TransferDescriptor desc; 362*82e48382SNiek Linnenbank hwaddr desc_addr = s->desc_base; 363*82e48382SNiek Linnenbank bool is_write = (s->command & SD_CMDR_WRITE); 364*82e48382SNiek Linnenbank uint32_t bytes_done = 0; 365*82e48382SNiek Linnenbank 366*82e48382SNiek Linnenbank /* Check if DMA can be performed */ 367*82e48382SNiek Linnenbank if (s->byte_count == 0 || s->block_size == 0 || 368*82e48382SNiek Linnenbank !(s->global_ctl & SD_GCTL_DMA_ENB)) { 369*82e48382SNiek Linnenbank return; 370*82e48382SNiek Linnenbank } 371*82e48382SNiek Linnenbank 372*82e48382SNiek Linnenbank /* 373*82e48382SNiek Linnenbank * For read operations, data must be available on the SD bus 374*82e48382SNiek Linnenbank * If not, it is an error and we should not act at all 375*82e48382SNiek Linnenbank */ 376*82e48382SNiek Linnenbank if (!is_write && !sdbus_data_ready(&s->sdbus)) { 377*82e48382SNiek Linnenbank return; 378*82e48382SNiek Linnenbank } 379*82e48382SNiek Linnenbank 380*82e48382SNiek Linnenbank /* Process the DMA descriptors until all data is copied */ 381*82e48382SNiek Linnenbank while (s->byte_count > 0) { 382*82e48382SNiek Linnenbank bytes_done = allwinner_sdhost_process_desc(s, desc_addr, &desc, 383*82e48382SNiek Linnenbank is_write, s->byte_count); 384*82e48382SNiek Linnenbank allwinner_sdhost_update_transfer_cnt(s, bytes_done); 385*82e48382SNiek Linnenbank 386*82e48382SNiek Linnenbank if (bytes_done <= s->byte_count) { 387*82e48382SNiek Linnenbank s->byte_count -= bytes_done; 388*82e48382SNiek Linnenbank } else { 389*82e48382SNiek Linnenbank s->byte_count = 0; 390*82e48382SNiek Linnenbank } 391*82e48382SNiek Linnenbank 392*82e48382SNiek Linnenbank if (desc.status & DESC_STATUS_LAST) { 393*82e48382SNiek Linnenbank break; 394*82e48382SNiek Linnenbank } else { 395*82e48382SNiek Linnenbank desc_addr = desc.next; 396*82e48382SNiek Linnenbank } 397*82e48382SNiek Linnenbank } 398*82e48382SNiek Linnenbank 399*82e48382SNiek Linnenbank /* Raise IRQ to signal DMA is completed */ 400*82e48382SNiek Linnenbank s->irq_status |= SD_RISR_DATA_COMPLETE | SD_RISR_SDIO_INTR; 401*82e48382SNiek Linnenbank 402*82e48382SNiek Linnenbank /* Update DMAC bits */ 403*82e48382SNiek Linnenbank s->dmac_status |= SD_IDST_INT_SUMMARY; 404*82e48382SNiek Linnenbank 405*82e48382SNiek Linnenbank if (is_write) { 406*82e48382SNiek Linnenbank s->dmac_status |= SD_IDST_TRANSMIT_IRQ; 407*82e48382SNiek Linnenbank } else { 408*82e48382SNiek Linnenbank s->dmac_status |= SD_IDST_RECEIVE_IRQ; 409*82e48382SNiek Linnenbank } 410*82e48382SNiek Linnenbank } 411*82e48382SNiek Linnenbank 412*82e48382SNiek Linnenbank static uint64_t allwinner_sdhost_read(void *opaque, hwaddr offset, 413*82e48382SNiek Linnenbank unsigned size) 414*82e48382SNiek Linnenbank { 415*82e48382SNiek Linnenbank AwSdHostState *s = AW_SDHOST(opaque); 416*82e48382SNiek Linnenbank uint32_t res = 0; 417*82e48382SNiek Linnenbank 418*82e48382SNiek Linnenbank switch (offset) { 419*82e48382SNiek Linnenbank case REG_SD_GCTL: /* Global Control */ 420*82e48382SNiek Linnenbank res = s->global_ctl; 421*82e48382SNiek Linnenbank break; 422*82e48382SNiek Linnenbank case REG_SD_CKCR: /* Clock Control */ 423*82e48382SNiek Linnenbank res = s->clock_ctl; 424*82e48382SNiek Linnenbank break; 425*82e48382SNiek Linnenbank case REG_SD_TMOR: /* Timeout */ 426*82e48382SNiek Linnenbank res = s->timeout; 427*82e48382SNiek Linnenbank break; 428*82e48382SNiek Linnenbank case REG_SD_BWDR: /* Bus Width */ 429*82e48382SNiek Linnenbank res = s->bus_width; 430*82e48382SNiek Linnenbank break; 431*82e48382SNiek Linnenbank case REG_SD_BKSR: /* Block Size */ 432*82e48382SNiek Linnenbank res = s->block_size; 433*82e48382SNiek Linnenbank break; 434*82e48382SNiek Linnenbank case REG_SD_BYCR: /* Byte Count */ 435*82e48382SNiek Linnenbank res = s->byte_count; 436*82e48382SNiek Linnenbank break; 437*82e48382SNiek Linnenbank case REG_SD_CMDR: /* Command */ 438*82e48382SNiek Linnenbank res = s->command; 439*82e48382SNiek Linnenbank break; 440*82e48382SNiek Linnenbank case REG_SD_CAGR: /* Command Argument */ 441*82e48382SNiek Linnenbank res = s->command_arg; 442*82e48382SNiek Linnenbank break; 443*82e48382SNiek Linnenbank case REG_SD_RESP0: /* Response Zero */ 444*82e48382SNiek Linnenbank res = s->response[0]; 445*82e48382SNiek Linnenbank break; 446*82e48382SNiek Linnenbank case REG_SD_RESP1: /* Response One */ 447*82e48382SNiek Linnenbank res = s->response[1]; 448*82e48382SNiek Linnenbank break; 449*82e48382SNiek Linnenbank case REG_SD_RESP2: /* Response Two */ 450*82e48382SNiek Linnenbank res = s->response[2]; 451*82e48382SNiek Linnenbank break; 452*82e48382SNiek Linnenbank case REG_SD_RESP3: /* Response Three */ 453*82e48382SNiek Linnenbank res = s->response[3]; 454*82e48382SNiek Linnenbank break; 455*82e48382SNiek Linnenbank case REG_SD_IMKR: /* Interrupt Mask */ 456*82e48382SNiek Linnenbank res = s->irq_mask; 457*82e48382SNiek Linnenbank break; 458*82e48382SNiek Linnenbank case REG_SD_MISR: /* Masked Interrupt Status */ 459*82e48382SNiek Linnenbank res = s->irq_status & s->irq_mask; 460*82e48382SNiek Linnenbank break; 461*82e48382SNiek Linnenbank case REG_SD_RISR: /* Raw Interrupt Status */ 462*82e48382SNiek Linnenbank res = s->irq_status; 463*82e48382SNiek Linnenbank break; 464*82e48382SNiek Linnenbank case REG_SD_STAR: /* Status */ 465*82e48382SNiek Linnenbank res = s->status; 466*82e48382SNiek Linnenbank break; 467*82e48382SNiek Linnenbank case REG_SD_FWLR: /* FIFO Water Level */ 468*82e48382SNiek Linnenbank res = s->fifo_wlevel; 469*82e48382SNiek Linnenbank break; 470*82e48382SNiek Linnenbank case REG_SD_FUNS: /* FIFO Function Select */ 471*82e48382SNiek Linnenbank res = s->fifo_func_sel; 472*82e48382SNiek Linnenbank break; 473*82e48382SNiek Linnenbank case REG_SD_DBGC: /* Debug Enable */ 474*82e48382SNiek Linnenbank res = s->debug_enable; 475*82e48382SNiek Linnenbank break; 476*82e48382SNiek Linnenbank case REG_SD_A12A: /* Auto command 12 argument */ 477*82e48382SNiek Linnenbank res = s->auto12_arg; 478*82e48382SNiek Linnenbank break; 479*82e48382SNiek Linnenbank case REG_SD_NTSR: /* SD NewTiming Set */ 480*82e48382SNiek Linnenbank res = s->newtiming_set; 481*82e48382SNiek Linnenbank break; 482*82e48382SNiek Linnenbank case REG_SD_SDBG: /* SD newTiming Set Debug */ 483*82e48382SNiek Linnenbank res = s->newtiming_debug; 484*82e48382SNiek Linnenbank break; 485*82e48382SNiek Linnenbank case REG_SD_HWRST: /* Hardware Reset Register */ 486*82e48382SNiek Linnenbank res = s->hardware_rst; 487*82e48382SNiek Linnenbank break; 488*82e48382SNiek Linnenbank case REG_SD_DMAC: /* Internal DMA Controller Control */ 489*82e48382SNiek Linnenbank res = s->dmac; 490*82e48382SNiek Linnenbank break; 491*82e48382SNiek Linnenbank case REG_SD_DLBA: /* Descriptor List Base Address */ 492*82e48382SNiek Linnenbank res = s->desc_base; 493*82e48382SNiek Linnenbank break; 494*82e48382SNiek Linnenbank case REG_SD_IDST: /* Internal DMA Controller Status */ 495*82e48382SNiek Linnenbank res = s->dmac_status; 496*82e48382SNiek Linnenbank break; 497*82e48382SNiek Linnenbank case REG_SD_IDIE: /* Internal DMA Controller Interrupt Enable */ 498*82e48382SNiek Linnenbank res = s->dmac_irq; 499*82e48382SNiek Linnenbank break; 500*82e48382SNiek Linnenbank case REG_SD_THLDC: /* Card Threshold Control */ 501*82e48382SNiek Linnenbank res = s->card_threshold; 502*82e48382SNiek Linnenbank break; 503*82e48382SNiek Linnenbank case REG_SD_DSBD: /* eMMC DDR Start Bit Detection Control */ 504*82e48382SNiek Linnenbank res = s->startbit_detect; 505*82e48382SNiek Linnenbank break; 506*82e48382SNiek Linnenbank case REG_SD_RES_CRC: /* Response CRC from card/eMMC */ 507*82e48382SNiek Linnenbank res = s->response_crc; 508*82e48382SNiek Linnenbank break; 509*82e48382SNiek Linnenbank case REG_SD_DATA7_CRC: /* CRC Data 7 from card/eMMC */ 510*82e48382SNiek Linnenbank case REG_SD_DATA6_CRC: /* CRC Data 6 from card/eMMC */ 511*82e48382SNiek Linnenbank case REG_SD_DATA5_CRC: /* CRC Data 5 from card/eMMC */ 512*82e48382SNiek Linnenbank case REG_SD_DATA4_CRC: /* CRC Data 4 from card/eMMC */ 513*82e48382SNiek Linnenbank case REG_SD_DATA3_CRC: /* CRC Data 3 from card/eMMC */ 514*82e48382SNiek Linnenbank case REG_SD_DATA2_CRC: /* CRC Data 2 from card/eMMC */ 515*82e48382SNiek Linnenbank case REG_SD_DATA1_CRC: /* CRC Data 1 from card/eMMC */ 516*82e48382SNiek Linnenbank case REG_SD_DATA0_CRC: /* CRC Data 0 from card/eMMC */ 517*82e48382SNiek Linnenbank res = s->data_crc[((offset - REG_SD_DATA7_CRC) / sizeof(uint32_t))]; 518*82e48382SNiek Linnenbank break; 519*82e48382SNiek Linnenbank case REG_SD_CRC_STA: /* CRC status from card/eMMC in write operation */ 520*82e48382SNiek Linnenbank res = s->status_crc; 521*82e48382SNiek Linnenbank break; 522*82e48382SNiek Linnenbank case REG_SD_FIFO: /* Read/Write FIFO */ 523*82e48382SNiek Linnenbank if (sdbus_data_ready(&s->sdbus)) { 524*82e48382SNiek Linnenbank res = sdbus_read_data(&s->sdbus); 525*82e48382SNiek Linnenbank res |= sdbus_read_data(&s->sdbus) << 8; 526*82e48382SNiek Linnenbank res |= sdbus_read_data(&s->sdbus) << 16; 527*82e48382SNiek Linnenbank res |= sdbus_read_data(&s->sdbus) << 24; 528*82e48382SNiek Linnenbank allwinner_sdhost_update_transfer_cnt(s, sizeof(uint32_t)); 529*82e48382SNiek Linnenbank allwinner_sdhost_auto_stop(s); 530*82e48382SNiek Linnenbank allwinner_sdhost_update_irq(s); 531*82e48382SNiek Linnenbank } else { 532*82e48382SNiek Linnenbank qemu_log_mask(LOG_GUEST_ERROR, "%s: no data ready on SD bus\n", 533*82e48382SNiek Linnenbank __func__); 534*82e48382SNiek Linnenbank } 535*82e48382SNiek Linnenbank break; 536*82e48382SNiek Linnenbank default: 537*82e48382SNiek Linnenbank qemu_log_mask(LOG_GUEST_ERROR, "%s: out-of-bounds offset %" 538*82e48382SNiek Linnenbank HWADDR_PRIx"\n", __func__, offset); 539*82e48382SNiek Linnenbank res = 0; 540*82e48382SNiek Linnenbank break; 541*82e48382SNiek Linnenbank } 542*82e48382SNiek Linnenbank 543*82e48382SNiek Linnenbank trace_allwinner_sdhost_read(offset, res, size); 544*82e48382SNiek Linnenbank return res; 545*82e48382SNiek Linnenbank } 546*82e48382SNiek Linnenbank 547*82e48382SNiek Linnenbank static void allwinner_sdhost_write(void *opaque, hwaddr offset, 548*82e48382SNiek Linnenbank uint64_t value, unsigned size) 549*82e48382SNiek Linnenbank { 550*82e48382SNiek Linnenbank AwSdHostState *s = AW_SDHOST(opaque); 551*82e48382SNiek Linnenbank 552*82e48382SNiek Linnenbank trace_allwinner_sdhost_write(offset, value, size); 553*82e48382SNiek Linnenbank 554*82e48382SNiek Linnenbank switch (offset) { 555*82e48382SNiek Linnenbank case REG_SD_GCTL: /* Global Control */ 556*82e48382SNiek Linnenbank s->global_ctl = value; 557*82e48382SNiek Linnenbank s->global_ctl &= ~(SD_GCTL_DMA_RST | SD_GCTL_FIFO_RST | 558*82e48382SNiek Linnenbank SD_GCTL_SOFT_RST); 559*82e48382SNiek Linnenbank allwinner_sdhost_update_irq(s); 560*82e48382SNiek Linnenbank break; 561*82e48382SNiek Linnenbank case REG_SD_CKCR: /* Clock Control */ 562*82e48382SNiek Linnenbank s->clock_ctl = value; 563*82e48382SNiek Linnenbank break; 564*82e48382SNiek Linnenbank case REG_SD_TMOR: /* Timeout */ 565*82e48382SNiek Linnenbank s->timeout = value; 566*82e48382SNiek Linnenbank break; 567*82e48382SNiek Linnenbank case REG_SD_BWDR: /* Bus Width */ 568*82e48382SNiek Linnenbank s->bus_width = value; 569*82e48382SNiek Linnenbank break; 570*82e48382SNiek Linnenbank case REG_SD_BKSR: /* Block Size */ 571*82e48382SNiek Linnenbank s->block_size = value; 572*82e48382SNiek Linnenbank break; 573*82e48382SNiek Linnenbank case REG_SD_BYCR: /* Byte Count */ 574*82e48382SNiek Linnenbank s->byte_count = value; 575*82e48382SNiek Linnenbank s->transfer_cnt = value; 576*82e48382SNiek Linnenbank break; 577*82e48382SNiek Linnenbank case REG_SD_CMDR: /* Command */ 578*82e48382SNiek Linnenbank s->command = value; 579*82e48382SNiek Linnenbank if (value & SD_CMDR_LOAD) { 580*82e48382SNiek Linnenbank allwinner_sdhost_send_command(s); 581*82e48382SNiek Linnenbank allwinner_sdhost_dma(s); 582*82e48382SNiek Linnenbank allwinner_sdhost_auto_stop(s); 583*82e48382SNiek Linnenbank } 584*82e48382SNiek Linnenbank allwinner_sdhost_update_irq(s); 585*82e48382SNiek Linnenbank break; 586*82e48382SNiek Linnenbank case REG_SD_CAGR: /* Command Argument */ 587*82e48382SNiek Linnenbank s->command_arg = value; 588*82e48382SNiek Linnenbank break; 589*82e48382SNiek Linnenbank case REG_SD_RESP0: /* Response Zero */ 590*82e48382SNiek Linnenbank s->response[0] = value; 591*82e48382SNiek Linnenbank break; 592*82e48382SNiek Linnenbank case REG_SD_RESP1: /* Response One */ 593*82e48382SNiek Linnenbank s->response[1] = value; 594*82e48382SNiek Linnenbank break; 595*82e48382SNiek Linnenbank case REG_SD_RESP2: /* Response Two */ 596*82e48382SNiek Linnenbank s->response[2] = value; 597*82e48382SNiek Linnenbank break; 598*82e48382SNiek Linnenbank case REG_SD_RESP3: /* Response Three */ 599*82e48382SNiek Linnenbank s->response[3] = value; 600*82e48382SNiek Linnenbank break; 601*82e48382SNiek Linnenbank case REG_SD_IMKR: /* Interrupt Mask */ 602*82e48382SNiek Linnenbank s->irq_mask = value; 603*82e48382SNiek Linnenbank allwinner_sdhost_update_irq(s); 604*82e48382SNiek Linnenbank break; 605*82e48382SNiek Linnenbank case REG_SD_MISR: /* Masked Interrupt Status */ 606*82e48382SNiek Linnenbank case REG_SD_RISR: /* Raw Interrupt Status */ 607*82e48382SNiek Linnenbank s->irq_status &= ~value; 608*82e48382SNiek Linnenbank allwinner_sdhost_update_irq(s); 609*82e48382SNiek Linnenbank break; 610*82e48382SNiek Linnenbank case REG_SD_STAR: /* Status */ 611*82e48382SNiek Linnenbank s->status &= ~value; 612*82e48382SNiek Linnenbank allwinner_sdhost_update_irq(s); 613*82e48382SNiek Linnenbank break; 614*82e48382SNiek Linnenbank case REG_SD_FWLR: /* FIFO Water Level */ 615*82e48382SNiek Linnenbank s->fifo_wlevel = value; 616*82e48382SNiek Linnenbank break; 617*82e48382SNiek Linnenbank case REG_SD_FUNS: /* FIFO Function Select */ 618*82e48382SNiek Linnenbank s->fifo_func_sel = value; 619*82e48382SNiek Linnenbank break; 620*82e48382SNiek Linnenbank case REG_SD_DBGC: /* Debug Enable */ 621*82e48382SNiek Linnenbank s->debug_enable = value; 622*82e48382SNiek Linnenbank break; 623*82e48382SNiek Linnenbank case REG_SD_A12A: /* Auto command 12 argument */ 624*82e48382SNiek Linnenbank s->auto12_arg = value; 625*82e48382SNiek Linnenbank break; 626*82e48382SNiek Linnenbank case REG_SD_NTSR: /* SD NewTiming Set */ 627*82e48382SNiek Linnenbank s->newtiming_set = value; 628*82e48382SNiek Linnenbank break; 629*82e48382SNiek Linnenbank case REG_SD_SDBG: /* SD newTiming Set Debug */ 630*82e48382SNiek Linnenbank s->newtiming_debug = value; 631*82e48382SNiek Linnenbank break; 632*82e48382SNiek Linnenbank case REG_SD_HWRST: /* Hardware Reset Register */ 633*82e48382SNiek Linnenbank s->hardware_rst = value; 634*82e48382SNiek Linnenbank break; 635*82e48382SNiek Linnenbank case REG_SD_DMAC: /* Internal DMA Controller Control */ 636*82e48382SNiek Linnenbank s->dmac = value; 637*82e48382SNiek Linnenbank allwinner_sdhost_update_irq(s); 638*82e48382SNiek Linnenbank break; 639*82e48382SNiek Linnenbank case REG_SD_DLBA: /* Descriptor List Base Address */ 640*82e48382SNiek Linnenbank s->desc_base = value; 641*82e48382SNiek Linnenbank break; 642*82e48382SNiek Linnenbank case REG_SD_IDST: /* Internal DMA Controller Status */ 643*82e48382SNiek Linnenbank s->dmac_status &= (~SD_IDST_WR_MASK) | (~value & SD_IDST_WR_MASK); 644*82e48382SNiek Linnenbank allwinner_sdhost_update_irq(s); 645*82e48382SNiek Linnenbank break; 646*82e48382SNiek Linnenbank case REG_SD_IDIE: /* Internal DMA Controller Interrupt Enable */ 647*82e48382SNiek Linnenbank s->dmac_irq = value; 648*82e48382SNiek Linnenbank allwinner_sdhost_update_irq(s); 649*82e48382SNiek Linnenbank break; 650*82e48382SNiek Linnenbank case REG_SD_THLDC: /* Card Threshold Control */ 651*82e48382SNiek Linnenbank s->card_threshold = value; 652*82e48382SNiek Linnenbank break; 653*82e48382SNiek Linnenbank case REG_SD_DSBD: /* eMMC DDR Start Bit Detection Control */ 654*82e48382SNiek Linnenbank s->startbit_detect = value; 655*82e48382SNiek Linnenbank break; 656*82e48382SNiek Linnenbank case REG_SD_FIFO: /* Read/Write FIFO */ 657*82e48382SNiek Linnenbank sdbus_write_data(&s->sdbus, value & 0xff); 658*82e48382SNiek Linnenbank sdbus_write_data(&s->sdbus, (value >> 8) & 0xff); 659*82e48382SNiek Linnenbank sdbus_write_data(&s->sdbus, (value >> 16) & 0xff); 660*82e48382SNiek Linnenbank sdbus_write_data(&s->sdbus, (value >> 24) & 0xff); 661*82e48382SNiek Linnenbank allwinner_sdhost_update_transfer_cnt(s, sizeof(uint32_t)); 662*82e48382SNiek Linnenbank allwinner_sdhost_auto_stop(s); 663*82e48382SNiek Linnenbank allwinner_sdhost_update_irq(s); 664*82e48382SNiek Linnenbank break; 665*82e48382SNiek Linnenbank case REG_SD_RES_CRC: /* Response CRC from card/eMMC */ 666*82e48382SNiek Linnenbank case REG_SD_DATA7_CRC: /* CRC Data 7 from card/eMMC */ 667*82e48382SNiek Linnenbank case REG_SD_DATA6_CRC: /* CRC Data 6 from card/eMMC */ 668*82e48382SNiek Linnenbank case REG_SD_DATA5_CRC: /* CRC Data 5 from card/eMMC */ 669*82e48382SNiek Linnenbank case REG_SD_DATA4_CRC: /* CRC Data 4 from card/eMMC */ 670*82e48382SNiek Linnenbank case REG_SD_DATA3_CRC: /* CRC Data 3 from card/eMMC */ 671*82e48382SNiek Linnenbank case REG_SD_DATA2_CRC: /* CRC Data 2 from card/eMMC */ 672*82e48382SNiek Linnenbank case REG_SD_DATA1_CRC: /* CRC Data 1 from card/eMMC */ 673*82e48382SNiek Linnenbank case REG_SD_DATA0_CRC: /* CRC Data 0 from card/eMMC */ 674*82e48382SNiek Linnenbank case REG_SD_CRC_STA: /* CRC status from card/eMMC in write operation */ 675*82e48382SNiek Linnenbank break; 676*82e48382SNiek Linnenbank default: 677*82e48382SNiek Linnenbank qemu_log_mask(LOG_GUEST_ERROR, "%s: out-of-bounds offset %" 678*82e48382SNiek Linnenbank HWADDR_PRIx"\n", __func__, offset); 679*82e48382SNiek Linnenbank break; 680*82e48382SNiek Linnenbank } 681*82e48382SNiek Linnenbank } 682*82e48382SNiek Linnenbank 683*82e48382SNiek Linnenbank static const MemoryRegionOps allwinner_sdhost_ops = { 684*82e48382SNiek Linnenbank .read = allwinner_sdhost_read, 685*82e48382SNiek Linnenbank .write = allwinner_sdhost_write, 686*82e48382SNiek Linnenbank .endianness = DEVICE_NATIVE_ENDIAN, 687*82e48382SNiek Linnenbank .valid = { 688*82e48382SNiek Linnenbank .min_access_size = 4, 689*82e48382SNiek Linnenbank .max_access_size = 4, 690*82e48382SNiek Linnenbank }, 691*82e48382SNiek Linnenbank .impl.min_access_size = 4, 692*82e48382SNiek Linnenbank }; 693*82e48382SNiek Linnenbank 694*82e48382SNiek Linnenbank static const VMStateDescription vmstate_allwinner_sdhost = { 695*82e48382SNiek Linnenbank .name = "allwinner-sdhost", 696*82e48382SNiek Linnenbank .version_id = 1, 697*82e48382SNiek Linnenbank .minimum_version_id = 1, 698*82e48382SNiek Linnenbank .fields = (VMStateField[]) { 699*82e48382SNiek Linnenbank VMSTATE_UINT32(global_ctl, AwSdHostState), 700*82e48382SNiek Linnenbank VMSTATE_UINT32(clock_ctl, AwSdHostState), 701*82e48382SNiek Linnenbank VMSTATE_UINT32(timeout, AwSdHostState), 702*82e48382SNiek Linnenbank VMSTATE_UINT32(bus_width, AwSdHostState), 703*82e48382SNiek Linnenbank VMSTATE_UINT32(block_size, AwSdHostState), 704*82e48382SNiek Linnenbank VMSTATE_UINT32(byte_count, AwSdHostState), 705*82e48382SNiek Linnenbank VMSTATE_UINT32(transfer_cnt, AwSdHostState), 706*82e48382SNiek Linnenbank VMSTATE_UINT32(command, AwSdHostState), 707*82e48382SNiek Linnenbank VMSTATE_UINT32(command_arg, AwSdHostState), 708*82e48382SNiek Linnenbank VMSTATE_UINT32_ARRAY(response, AwSdHostState, 4), 709*82e48382SNiek Linnenbank VMSTATE_UINT32(irq_mask, AwSdHostState), 710*82e48382SNiek Linnenbank VMSTATE_UINT32(irq_status, AwSdHostState), 711*82e48382SNiek Linnenbank VMSTATE_UINT32(status, AwSdHostState), 712*82e48382SNiek Linnenbank VMSTATE_UINT32(fifo_wlevel, AwSdHostState), 713*82e48382SNiek Linnenbank VMSTATE_UINT32(fifo_func_sel, AwSdHostState), 714*82e48382SNiek Linnenbank VMSTATE_UINT32(debug_enable, AwSdHostState), 715*82e48382SNiek Linnenbank VMSTATE_UINT32(auto12_arg, AwSdHostState), 716*82e48382SNiek Linnenbank VMSTATE_UINT32(newtiming_set, AwSdHostState), 717*82e48382SNiek Linnenbank VMSTATE_UINT32(newtiming_debug, AwSdHostState), 718*82e48382SNiek Linnenbank VMSTATE_UINT32(hardware_rst, AwSdHostState), 719*82e48382SNiek Linnenbank VMSTATE_UINT32(dmac, AwSdHostState), 720*82e48382SNiek Linnenbank VMSTATE_UINT32(desc_base, AwSdHostState), 721*82e48382SNiek Linnenbank VMSTATE_UINT32(dmac_status, AwSdHostState), 722*82e48382SNiek Linnenbank VMSTATE_UINT32(dmac_irq, AwSdHostState), 723*82e48382SNiek Linnenbank VMSTATE_UINT32(card_threshold, AwSdHostState), 724*82e48382SNiek Linnenbank VMSTATE_UINT32(startbit_detect, AwSdHostState), 725*82e48382SNiek Linnenbank VMSTATE_UINT32(response_crc, AwSdHostState), 726*82e48382SNiek Linnenbank VMSTATE_UINT32_ARRAY(data_crc, AwSdHostState, 8), 727*82e48382SNiek Linnenbank VMSTATE_UINT32(status_crc, AwSdHostState), 728*82e48382SNiek Linnenbank VMSTATE_END_OF_LIST() 729*82e48382SNiek Linnenbank } 730*82e48382SNiek Linnenbank }; 731*82e48382SNiek Linnenbank 732*82e48382SNiek Linnenbank static void allwinner_sdhost_init(Object *obj) 733*82e48382SNiek Linnenbank { 734*82e48382SNiek Linnenbank AwSdHostState *s = AW_SDHOST(obj); 735*82e48382SNiek Linnenbank 736*82e48382SNiek Linnenbank qbus_create_inplace(&s->sdbus, sizeof(s->sdbus), 737*82e48382SNiek Linnenbank TYPE_AW_SDHOST_BUS, DEVICE(s), "sd-bus"); 738*82e48382SNiek Linnenbank 739*82e48382SNiek Linnenbank memory_region_init_io(&s->iomem, obj, &allwinner_sdhost_ops, s, 740*82e48382SNiek Linnenbank TYPE_AW_SDHOST, 4 * KiB); 741*82e48382SNiek Linnenbank sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->iomem); 742*82e48382SNiek Linnenbank sysbus_init_irq(SYS_BUS_DEVICE(s), &s->irq); 743*82e48382SNiek Linnenbank } 744*82e48382SNiek Linnenbank 745*82e48382SNiek Linnenbank static void allwinner_sdhost_reset(DeviceState *dev) 746*82e48382SNiek Linnenbank { 747*82e48382SNiek Linnenbank AwSdHostState *s = AW_SDHOST(dev); 748*82e48382SNiek Linnenbank 749*82e48382SNiek Linnenbank s->global_ctl = REG_SD_GCTL_RST; 750*82e48382SNiek Linnenbank s->clock_ctl = REG_SD_CKCR_RST; 751*82e48382SNiek Linnenbank s->timeout = REG_SD_TMOR_RST; 752*82e48382SNiek Linnenbank s->bus_width = REG_SD_BWDR_RST; 753*82e48382SNiek Linnenbank s->block_size = REG_SD_BKSR_RST; 754*82e48382SNiek Linnenbank s->byte_count = REG_SD_BYCR_RST; 755*82e48382SNiek Linnenbank s->transfer_cnt = 0; 756*82e48382SNiek Linnenbank 757*82e48382SNiek Linnenbank s->command = REG_SD_CMDR_RST; 758*82e48382SNiek Linnenbank s->command_arg = REG_SD_CAGR_RST; 759*82e48382SNiek Linnenbank 760*82e48382SNiek Linnenbank for (int i = 0; i < ARRAY_SIZE(s->response); i++) { 761*82e48382SNiek Linnenbank s->response[i] = REG_SD_RESP_RST; 762*82e48382SNiek Linnenbank } 763*82e48382SNiek Linnenbank 764*82e48382SNiek Linnenbank s->irq_mask = REG_SD_IMKR_RST; 765*82e48382SNiek Linnenbank s->irq_status = REG_SD_RISR_RST; 766*82e48382SNiek Linnenbank s->status = REG_SD_STAR_RST; 767*82e48382SNiek Linnenbank 768*82e48382SNiek Linnenbank s->fifo_wlevel = REG_SD_FWLR_RST; 769*82e48382SNiek Linnenbank s->fifo_func_sel = REG_SD_FUNS_RST; 770*82e48382SNiek Linnenbank s->debug_enable = REG_SD_DBGC_RST; 771*82e48382SNiek Linnenbank s->auto12_arg = REG_SD_A12A_RST; 772*82e48382SNiek Linnenbank s->newtiming_set = REG_SD_NTSR_RST; 773*82e48382SNiek Linnenbank s->newtiming_debug = REG_SD_SDBG_RST; 774*82e48382SNiek Linnenbank s->hardware_rst = REG_SD_HWRST_RST; 775*82e48382SNiek Linnenbank s->dmac = REG_SD_DMAC_RST; 776*82e48382SNiek Linnenbank s->desc_base = REG_SD_DLBA_RST; 777*82e48382SNiek Linnenbank s->dmac_status = REG_SD_IDST_RST; 778*82e48382SNiek Linnenbank s->dmac_irq = REG_SD_IDIE_RST; 779*82e48382SNiek Linnenbank s->card_threshold = REG_SD_THLDC_RST; 780*82e48382SNiek Linnenbank s->startbit_detect = REG_SD_DSBD_RST; 781*82e48382SNiek Linnenbank s->response_crc = REG_SD_RES_CRC_RST; 782*82e48382SNiek Linnenbank 783*82e48382SNiek Linnenbank for (int i = 0; i < ARRAY_SIZE(s->data_crc); i++) { 784*82e48382SNiek Linnenbank s->data_crc[i] = REG_SD_DATA_CRC_RST; 785*82e48382SNiek Linnenbank } 786*82e48382SNiek Linnenbank 787*82e48382SNiek Linnenbank s->status_crc = REG_SD_CRC_STA_RST; 788*82e48382SNiek Linnenbank } 789*82e48382SNiek Linnenbank 790*82e48382SNiek Linnenbank static void allwinner_sdhost_bus_class_init(ObjectClass *klass, void *data) 791*82e48382SNiek Linnenbank { 792*82e48382SNiek Linnenbank SDBusClass *sbc = SD_BUS_CLASS(klass); 793*82e48382SNiek Linnenbank 794*82e48382SNiek Linnenbank sbc->set_inserted = allwinner_sdhost_set_inserted; 795*82e48382SNiek Linnenbank } 796*82e48382SNiek Linnenbank 797*82e48382SNiek Linnenbank static void allwinner_sdhost_class_init(ObjectClass *klass, void *data) 798*82e48382SNiek Linnenbank { 799*82e48382SNiek Linnenbank DeviceClass *dc = DEVICE_CLASS(klass); 800*82e48382SNiek Linnenbank 801*82e48382SNiek Linnenbank dc->reset = allwinner_sdhost_reset; 802*82e48382SNiek Linnenbank dc->vmsd = &vmstate_allwinner_sdhost; 803*82e48382SNiek Linnenbank } 804*82e48382SNiek Linnenbank 805*82e48382SNiek Linnenbank static void allwinner_sdhost_sun4i_class_init(ObjectClass *klass, void *data) 806*82e48382SNiek Linnenbank { 807*82e48382SNiek Linnenbank AwSdHostClass *sc = AW_SDHOST_CLASS(klass); 808*82e48382SNiek Linnenbank sc->max_desc_size = 8 * KiB; 809*82e48382SNiek Linnenbank } 810*82e48382SNiek Linnenbank 811*82e48382SNiek Linnenbank static void allwinner_sdhost_sun5i_class_init(ObjectClass *klass, void *data) 812*82e48382SNiek Linnenbank { 813*82e48382SNiek Linnenbank AwSdHostClass *sc = AW_SDHOST_CLASS(klass); 814*82e48382SNiek Linnenbank sc->max_desc_size = 64 * KiB; 815*82e48382SNiek Linnenbank } 816*82e48382SNiek Linnenbank 817*82e48382SNiek Linnenbank static TypeInfo allwinner_sdhost_info = { 818*82e48382SNiek Linnenbank .name = TYPE_AW_SDHOST, 819*82e48382SNiek Linnenbank .parent = TYPE_SYS_BUS_DEVICE, 820*82e48382SNiek Linnenbank .instance_init = allwinner_sdhost_init, 821*82e48382SNiek Linnenbank .instance_size = sizeof(AwSdHostState), 822*82e48382SNiek Linnenbank .class_init = allwinner_sdhost_class_init, 823*82e48382SNiek Linnenbank .class_size = sizeof(AwSdHostClass), 824*82e48382SNiek Linnenbank .abstract = true, 825*82e48382SNiek Linnenbank }; 826*82e48382SNiek Linnenbank 827*82e48382SNiek Linnenbank static const TypeInfo allwinner_sdhost_sun4i_info = { 828*82e48382SNiek Linnenbank .name = TYPE_AW_SDHOST_SUN4I, 829*82e48382SNiek Linnenbank .parent = TYPE_AW_SDHOST, 830*82e48382SNiek Linnenbank .class_init = allwinner_sdhost_sun4i_class_init, 831*82e48382SNiek Linnenbank }; 832*82e48382SNiek Linnenbank 833*82e48382SNiek Linnenbank static const TypeInfo allwinner_sdhost_sun5i_info = { 834*82e48382SNiek Linnenbank .name = TYPE_AW_SDHOST_SUN5I, 835*82e48382SNiek Linnenbank .parent = TYPE_AW_SDHOST, 836*82e48382SNiek Linnenbank .class_init = allwinner_sdhost_sun5i_class_init, 837*82e48382SNiek Linnenbank }; 838*82e48382SNiek Linnenbank 839*82e48382SNiek Linnenbank static const TypeInfo allwinner_sdhost_bus_info = { 840*82e48382SNiek Linnenbank .name = TYPE_AW_SDHOST_BUS, 841*82e48382SNiek Linnenbank .parent = TYPE_SD_BUS, 842*82e48382SNiek Linnenbank .instance_size = sizeof(SDBus), 843*82e48382SNiek Linnenbank .class_init = allwinner_sdhost_bus_class_init, 844*82e48382SNiek Linnenbank }; 845*82e48382SNiek Linnenbank 846*82e48382SNiek Linnenbank static void allwinner_sdhost_register_types(void) 847*82e48382SNiek Linnenbank { 848*82e48382SNiek Linnenbank type_register_static(&allwinner_sdhost_info); 849*82e48382SNiek Linnenbank type_register_static(&allwinner_sdhost_sun4i_info); 850*82e48382SNiek Linnenbank type_register_static(&allwinner_sdhost_sun5i_info); 851*82e48382SNiek Linnenbank type_register_static(&allwinner_sdhost_bus_info); 852*82e48382SNiek Linnenbank } 853*82e48382SNiek Linnenbank 854*82e48382SNiek Linnenbank type_init(allwinner_sdhost_register_types) 855