1*49ab747fSPaolo Bonzini /* 2*49ab747fSPaolo Bonzini * Arm PrimeCell PL181 MultiMedia Card Interface 3*49ab747fSPaolo Bonzini * 4*49ab747fSPaolo Bonzini * Copyright (c) 2007 CodeSourcery. 5*49ab747fSPaolo Bonzini * Written by Paul Brook 6*49ab747fSPaolo Bonzini * 7*49ab747fSPaolo Bonzini * This code is licensed under the GPL. 8*49ab747fSPaolo Bonzini */ 9*49ab747fSPaolo Bonzini 10*49ab747fSPaolo Bonzini #include "sysemu/blockdev.h" 11*49ab747fSPaolo Bonzini #include "hw/sysbus.h" 12*49ab747fSPaolo Bonzini #include "hw/sd.h" 13*49ab747fSPaolo Bonzini 14*49ab747fSPaolo Bonzini //#define DEBUG_PL181 1 15*49ab747fSPaolo Bonzini 16*49ab747fSPaolo Bonzini #ifdef DEBUG_PL181 17*49ab747fSPaolo Bonzini #define DPRINTF(fmt, ...) \ 18*49ab747fSPaolo Bonzini do { printf("pl181: " fmt , ## __VA_ARGS__); } while (0) 19*49ab747fSPaolo Bonzini #else 20*49ab747fSPaolo Bonzini #define DPRINTF(fmt, ...) do {} while(0) 21*49ab747fSPaolo Bonzini #endif 22*49ab747fSPaolo Bonzini 23*49ab747fSPaolo Bonzini #define PL181_FIFO_LEN 16 24*49ab747fSPaolo Bonzini 25*49ab747fSPaolo Bonzini typedef struct { 26*49ab747fSPaolo Bonzini SysBusDevice busdev; 27*49ab747fSPaolo Bonzini MemoryRegion iomem; 28*49ab747fSPaolo Bonzini SDState *card; 29*49ab747fSPaolo Bonzini uint32_t clock; 30*49ab747fSPaolo Bonzini uint32_t power; 31*49ab747fSPaolo Bonzini uint32_t cmdarg; 32*49ab747fSPaolo Bonzini uint32_t cmd; 33*49ab747fSPaolo Bonzini uint32_t datatimer; 34*49ab747fSPaolo Bonzini uint32_t datalength; 35*49ab747fSPaolo Bonzini uint32_t respcmd; 36*49ab747fSPaolo Bonzini uint32_t response[4]; 37*49ab747fSPaolo Bonzini uint32_t datactrl; 38*49ab747fSPaolo Bonzini uint32_t datacnt; 39*49ab747fSPaolo Bonzini uint32_t status; 40*49ab747fSPaolo Bonzini uint32_t mask[2]; 41*49ab747fSPaolo Bonzini int32_t fifo_pos; 42*49ab747fSPaolo Bonzini int32_t fifo_len; 43*49ab747fSPaolo Bonzini /* The linux 2.6.21 driver is buggy, and misbehaves if new data arrives 44*49ab747fSPaolo Bonzini while it is reading the FIFO. We hack around this be defering 45*49ab747fSPaolo Bonzini subsequent transfers until after the driver polls the status word. 46*49ab747fSPaolo Bonzini http://www.arm.linux.org.uk/developer/patches/viewpatch.php?id=4446/1 47*49ab747fSPaolo Bonzini */ 48*49ab747fSPaolo Bonzini int32_t linux_hack; 49*49ab747fSPaolo Bonzini uint32_t fifo[PL181_FIFO_LEN]; 50*49ab747fSPaolo Bonzini qemu_irq irq[2]; 51*49ab747fSPaolo Bonzini /* GPIO outputs for 'card is readonly' and 'card inserted' */ 52*49ab747fSPaolo Bonzini qemu_irq cardstatus[2]; 53*49ab747fSPaolo Bonzini } pl181_state; 54*49ab747fSPaolo Bonzini 55*49ab747fSPaolo Bonzini static const VMStateDescription vmstate_pl181 = { 56*49ab747fSPaolo Bonzini .name = "pl181", 57*49ab747fSPaolo Bonzini .version_id = 1, 58*49ab747fSPaolo Bonzini .minimum_version_id = 1, 59*49ab747fSPaolo Bonzini .fields = (VMStateField[]) { 60*49ab747fSPaolo Bonzini VMSTATE_UINT32(clock, pl181_state), 61*49ab747fSPaolo Bonzini VMSTATE_UINT32(power, pl181_state), 62*49ab747fSPaolo Bonzini VMSTATE_UINT32(cmdarg, pl181_state), 63*49ab747fSPaolo Bonzini VMSTATE_UINT32(cmd, pl181_state), 64*49ab747fSPaolo Bonzini VMSTATE_UINT32(datatimer, pl181_state), 65*49ab747fSPaolo Bonzini VMSTATE_UINT32(datalength, pl181_state), 66*49ab747fSPaolo Bonzini VMSTATE_UINT32(respcmd, pl181_state), 67*49ab747fSPaolo Bonzini VMSTATE_UINT32_ARRAY(response, pl181_state, 4), 68*49ab747fSPaolo Bonzini VMSTATE_UINT32(datactrl, pl181_state), 69*49ab747fSPaolo Bonzini VMSTATE_UINT32(datacnt, pl181_state), 70*49ab747fSPaolo Bonzini VMSTATE_UINT32(status, pl181_state), 71*49ab747fSPaolo Bonzini VMSTATE_UINT32_ARRAY(mask, pl181_state, 2), 72*49ab747fSPaolo Bonzini VMSTATE_INT32(fifo_pos, pl181_state), 73*49ab747fSPaolo Bonzini VMSTATE_INT32(fifo_len, pl181_state), 74*49ab747fSPaolo Bonzini VMSTATE_INT32(linux_hack, pl181_state), 75*49ab747fSPaolo Bonzini VMSTATE_UINT32_ARRAY(fifo, pl181_state, PL181_FIFO_LEN), 76*49ab747fSPaolo Bonzini VMSTATE_END_OF_LIST() 77*49ab747fSPaolo Bonzini } 78*49ab747fSPaolo Bonzini }; 79*49ab747fSPaolo Bonzini 80*49ab747fSPaolo Bonzini #define PL181_CMD_INDEX 0x3f 81*49ab747fSPaolo Bonzini #define PL181_CMD_RESPONSE (1 << 6) 82*49ab747fSPaolo Bonzini #define PL181_CMD_LONGRESP (1 << 7) 83*49ab747fSPaolo Bonzini #define PL181_CMD_INTERRUPT (1 << 8) 84*49ab747fSPaolo Bonzini #define PL181_CMD_PENDING (1 << 9) 85*49ab747fSPaolo Bonzini #define PL181_CMD_ENABLE (1 << 10) 86*49ab747fSPaolo Bonzini 87*49ab747fSPaolo Bonzini #define PL181_DATA_ENABLE (1 << 0) 88*49ab747fSPaolo Bonzini #define PL181_DATA_DIRECTION (1 << 1) 89*49ab747fSPaolo Bonzini #define PL181_DATA_MODE (1 << 2) 90*49ab747fSPaolo Bonzini #define PL181_DATA_DMAENABLE (1 << 3) 91*49ab747fSPaolo Bonzini 92*49ab747fSPaolo Bonzini #define PL181_STATUS_CMDCRCFAIL (1 << 0) 93*49ab747fSPaolo Bonzini #define PL181_STATUS_DATACRCFAIL (1 << 1) 94*49ab747fSPaolo Bonzini #define PL181_STATUS_CMDTIMEOUT (1 << 2) 95*49ab747fSPaolo Bonzini #define PL181_STATUS_DATATIMEOUT (1 << 3) 96*49ab747fSPaolo Bonzini #define PL181_STATUS_TXUNDERRUN (1 << 4) 97*49ab747fSPaolo Bonzini #define PL181_STATUS_RXOVERRUN (1 << 5) 98*49ab747fSPaolo Bonzini #define PL181_STATUS_CMDRESPEND (1 << 6) 99*49ab747fSPaolo Bonzini #define PL181_STATUS_CMDSENT (1 << 7) 100*49ab747fSPaolo Bonzini #define PL181_STATUS_DATAEND (1 << 8) 101*49ab747fSPaolo Bonzini #define PL181_STATUS_DATABLOCKEND (1 << 10) 102*49ab747fSPaolo Bonzini #define PL181_STATUS_CMDACTIVE (1 << 11) 103*49ab747fSPaolo Bonzini #define PL181_STATUS_TXACTIVE (1 << 12) 104*49ab747fSPaolo Bonzini #define PL181_STATUS_RXACTIVE (1 << 13) 105*49ab747fSPaolo Bonzini #define PL181_STATUS_TXFIFOHALFEMPTY (1 << 14) 106*49ab747fSPaolo Bonzini #define PL181_STATUS_RXFIFOHALFFULL (1 << 15) 107*49ab747fSPaolo Bonzini #define PL181_STATUS_TXFIFOFULL (1 << 16) 108*49ab747fSPaolo Bonzini #define PL181_STATUS_RXFIFOFULL (1 << 17) 109*49ab747fSPaolo Bonzini #define PL181_STATUS_TXFIFOEMPTY (1 << 18) 110*49ab747fSPaolo Bonzini #define PL181_STATUS_RXFIFOEMPTY (1 << 19) 111*49ab747fSPaolo Bonzini #define PL181_STATUS_TXDATAAVLBL (1 << 20) 112*49ab747fSPaolo Bonzini #define PL181_STATUS_RXDATAAVLBL (1 << 21) 113*49ab747fSPaolo Bonzini 114*49ab747fSPaolo Bonzini #define PL181_STATUS_TX_FIFO (PL181_STATUS_TXACTIVE \ 115*49ab747fSPaolo Bonzini |PL181_STATUS_TXFIFOHALFEMPTY \ 116*49ab747fSPaolo Bonzini |PL181_STATUS_TXFIFOFULL \ 117*49ab747fSPaolo Bonzini |PL181_STATUS_TXFIFOEMPTY \ 118*49ab747fSPaolo Bonzini |PL181_STATUS_TXDATAAVLBL) 119*49ab747fSPaolo Bonzini #define PL181_STATUS_RX_FIFO (PL181_STATUS_RXACTIVE \ 120*49ab747fSPaolo Bonzini |PL181_STATUS_RXFIFOHALFFULL \ 121*49ab747fSPaolo Bonzini |PL181_STATUS_RXFIFOFULL \ 122*49ab747fSPaolo Bonzini |PL181_STATUS_RXFIFOEMPTY \ 123*49ab747fSPaolo Bonzini |PL181_STATUS_RXDATAAVLBL) 124*49ab747fSPaolo Bonzini 125*49ab747fSPaolo Bonzini static const unsigned char pl181_id[] = 126*49ab747fSPaolo Bonzini { 0x81, 0x11, 0x04, 0x00, 0x0d, 0xf0, 0x05, 0xb1 }; 127*49ab747fSPaolo Bonzini 128*49ab747fSPaolo Bonzini static void pl181_update(pl181_state *s) 129*49ab747fSPaolo Bonzini { 130*49ab747fSPaolo Bonzini int i; 131*49ab747fSPaolo Bonzini for (i = 0; i < 2; i++) { 132*49ab747fSPaolo Bonzini qemu_set_irq(s->irq[i], (s->status & s->mask[i]) != 0); 133*49ab747fSPaolo Bonzini } 134*49ab747fSPaolo Bonzini } 135*49ab747fSPaolo Bonzini 136*49ab747fSPaolo Bonzini static void pl181_fifo_push(pl181_state *s, uint32_t value) 137*49ab747fSPaolo Bonzini { 138*49ab747fSPaolo Bonzini int n; 139*49ab747fSPaolo Bonzini 140*49ab747fSPaolo Bonzini if (s->fifo_len == PL181_FIFO_LEN) { 141*49ab747fSPaolo Bonzini fprintf(stderr, "pl181: FIFO overflow\n"); 142*49ab747fSPaolo Bonzini return; 143*49ab747fSPaolo Bonzini } 144*49ab747fSPaolo Bonzini n = (s->fifo_pos + s->fifo_len) & (PL181_FIFO_LEN - 1); 145*49ab747fSPaolo Bonzini s->fifo_len++; 146*49ab747fSPaolo Bonzini s->fifo[n] = value; 147*49ab747fSPaolo Bonzini DPRINTF("FIFO push %08x\n", (int)value); 148*49ab747fSPaolo Bonzini } 149*49ab747fSPaolo Bonzini 150*49ab747fSPaolo Bonzini static uint32_t pl181_fifo_pop(pl181_state *s) 151*49ab747fSPaolo Bonzini { 152*49ab747fSPaolo Bonzini uint32_t value; 153*49ab747fSPaolo Bonzini 154*49ab747fSPaolo Bonzini if (s->fifo_len == 0) { 155*49ab747fSPaolo Bonzini fprintf(stderr, "pl181: FIFO underflow\n"); 156*49ab747fSPaolo Bonzini return 0; 157*49ab747fSPaolo Bonzini } 158*49ab747fSPaolo Bonzini value = s->fifo[s->fifo_pos]; 159*49ab747fSPaolo Bonzini s->fifo_len--; 160*49ab747fSPaolo Bonzini s->fifo_pos = (s->fifo_pos + 1) & (PL181_FIFO_LEN - 1); 161*49ab747fSPaolo Bonzini DPRINTF("FIFO pop %08x\n", (int)value); 162*49ab747fSPaolo Bonzini return value; 163*49ab747fSPaolo Bonzini } 164*49ab747fSPaolo Bonzini 165*49ab747fSPaolo Bonzini static void pl181_send_command(pl181_state *s) 166*49ab747fSPaolo Bonzini { 167*49ab747fSPaolo Bonzini SDRequest request; 168*49ab747fSPaolo Bonzini uint8_t response[16]; 169*49ab747fSPaolo Bonzini int rlen; 170*49ab747fSPaolo Bonzini 171*49ab747fSPaolo Bonzini request.cmd = s->cmd & PL181_CMD_INDEX; 172*49ab747fSPaolo Bonzini request.arg = s->cmdarg; 173*49ab747fSPaolo Bonzini DPRINTF("Command %d %08x\n", request.cmd, request.arg); 174*49ab747fSPaolo Bonzini rlen = sd_do_command(s->card, &request, response); 175*49ab747fSPaolo Bonzini if (rlen < 0) 176*49ab747fSPaolo Bonzini goto error; 177*49ab747fSPaolo Bonzini if (s->cmd & PL181_CMD_RESPONSE) { 178*49ab747fSPaolo Bonzini #define RWORD(n) ((response[n] << 24) | (response[n + 1] << 16) \ 179*49ab747fSPaolo Bonzini | (response[n + 2] << 8) | response[n + 3]) 180*49ab747fSPaolo Bonzini if (rlen == 0 || (rlen == 4 && (s->cmd & PL181_CMD_LONGRESP))) 181*49ab747fSPaolo Bonzini goto error; 182*49ab747fSPaolo Bonzini if (rlen != 4 && rlen != 16) 183*49ab747fSPaolo Bonzini goto error; 184*49ab747fSPaolo Bonzini s->response[0] = RWORD(0); 185*49ab747fSPaolo Bonzini if (rlen == 4) { 186*49ab747fSPaolo Bonzini s->response[1] = s->response[2] = s->response[3] = 0; 187*49ab747fSPaolo Bonzini } else { 188*49ab747fSPaolo Bonzini s->response[1] = RWORD(4); 189*49ab747fSPaolo Bonzini s->response[2] = RWORD(8); 190*49ab747fSPaolo Bonzini s->response[3] = RWORD(12) & ~1; 191*49ab747fSPaolo Bonzini } 192*49ab747fSPaolo Bonzini DPRINTF("Response received\n"); 193*49ab747fSPaolo Bonzini s->status |= PL181_STATUS_CMDRESPEND; 194*49ab747fSPaolo Bonzini #undef RWORD 195*49ab747fSPaolo Bonzini } else { 196*49ab747fSPaolo Bonzini DPRINTF("Command sent\n"); 197*49ab747fSPaolo Bonzini s->status |= PL181_STATUS_CMDSENT; 198*49ab747fSPaolo Bonzini } 199*49ab747fSPaolo Bonzini return; 200*49ab747fSPaolo Bonzini 201*49ab747fSPaolo Bonzini error: 202*49ab747fSPaolo Bonzini DPRINTF("Timeout\n"); 203*49ab747fSPaolo Bonzini s->status |= PL181_STATUS_CMDTIMEOUT; 204*49ab747fSPaolo Bonzini } 205*49ab747fSPaolo Bonzini 206*49ab747fSPaolo Bonzini /* Transfer data between the card and the FIFO. This is complicated by 207*49ab747fSPaolo Bonzini the FIFO holding 32-bit words and the card taking data in single byte 208*49ab747fSPaolo Bonzini chunks. FIFO bytes are transferred in little-endian order. */ 209*49ab747fSPaolo Bonzini 210*49ab747fSPaolo Bonzini static void pl181_fifo_run(pl181_state *s) 211*49ab747fSPaolo Bonzini { 212*49ab747fSPaolo Bonzini uint32_t bits; 213*49ab747fSPaolo Bonzini uint32_t value = 0; 214*49ab747fSPaolo Bonzini int n; 215*49ab747fSPaolo Bonzini int is_read; 216*49ab747fSPaolo Bonzini 217*49ab747fSPaolo Bonzini is_read = (s->datactrl & PL181_DATA_DIRECTION) != 0; 218*49ab747fSPaolo Bonzini if (s->datacnt != 0 && (!is_read || sd_data_ready(s->card)) 219*49ab747fSPaolo Bonzini && !s->linux_hack) { 220*49ab747fSPaolo Bonzini if (is_read) { 221*49ab747fSPaolo Bonzini n = 0; 222*49ab747fSPaolo Bonzini while (s->datacnt && s->fifo_len < PL181_FIFO_LEN) { 223*49ab747fSPaolo Bonzini value |= (uint32_t)sd_read_data(s->card) << (n * 8); 224*49ab747fSPaolo Bonzini s->datacnt--; 225*49ab747fSPaolo Bonzini n++; 226*49ab747fSPaolo Bonzini if (n == 4) { 227*49ab747fSPaolo Bonzini pl181_fifo_push(s, value); 228*49ab747fSPaolo Bonzini n = 0; 229*49ab747fSPaolo Bonzini value = 0; 230*49ab747fSPaolo Bonzini } 231*49ab747fSPaolo Bonzini } 232*49ab747fSPaolo Bonzini if (n != 0) { 233*49ab747fSPaolo Bonzini pl181_fifo_push(s, value); 234*49ab747fSPaolo Bonzini } 235*49ab747fSPaolo Bonzini } else { /* write */ 236*49ab747fSPaolo Bonzini n = 0; 237*49ab747fSPaolo Bonzini while (s->datacnt > 0 && (s->fifo_len > 0 || n > 0)) { 238*49ab747fSPaolo Bonzini if (n == 0) { 239*49ab747fSPaolo Bonzini value = pl181_fifo_pop(s); 240*49ab747fSPaolo Bonzini n = 4; 241*49ab747fSPaolo Bonzini } 242*49ab747fSPaolo Bonzini n--; 243*49ab747fSPaolo Bonzini s->datacnt--; 244*49ab747fSPaolo Bonzini sd_write_data(s->card, value & 0xff); 245*49ab747fSPaolo Bonzini value >>= 8; 246*49ab747fSPaolo Bonzini } 247*49ab747fSPaolo Bonzini } 248*49ab747fSPaolo Bonzini } 249*49ab747fSPaolo Bonzini s->status &= ~(PL181_STATUS_RX_FIFO | PL181_STATUS_TX_FIFO); 250*49ab747fSPaolo Bonzini if (s->datacnt == 0) { 251*49ab747fSPaolo Bonzini s->status |= PL181_STATUS_DATAEND; 252*49ab747fSPaolo Bonzini /* HACK: */ 253*49ab747fSPaolo Bonzini s->status |= PL181_STATUS_DATABLOCKEND; 254*49ab747fSPaolo Bonzini DPRINTF("Transfer Complete\n"); 255*49ab747fSPaolo Bonzini } 256*49ab747fSPaolo Bonzini if (s->datacnt == 0 && s->fifo_len == 0) { 257*49ab747fSPaolo Bonzini s->datactrl &= ~PL181_DATA_ENABLE; 258*49ab747fSPaolo Bonzini DPRINTF("Data engine idle\n"); 259*49ab747fSPaolo Bonzini } else { 260*49ab747fSPaolo Bonzini /* Update FIFO bits. */ 261*49ab747fSPaolo Bonzini bits = PL181_STATUS_TXACTIVE | PL181_STATUS_RXACTIVE; 262*49ab747fSPaolo Bonzini if (s->fifo_len == 0) { 263*49ab747fSPaolo Bonzini bits |= PL181_STATUS_TXFIFOEMPTY; 264*49ab747fSPaolo Bonzini bits |= PL181_STATUS_RXFIFOEMPTY; 265*49ab747fSPaolo Bonzini } else { 266*49ab747fSPaolo Bonzini bits |= PL181_STATUS_TXDATAAVLBL; 267*49ab747fSPaolo Bonzini bits |= PL181_STATUS_RXDATAAVLBL; 268*49ab747fSPaolo Bonzini } 269*49ab747fSPaolo Bonzini if (s->fifo_len == 16) { 270*49ab747fSPaolo Bonzini bits |= PL181_STATUS_TXFIFOFULL; 271*49ab747fSPaolo Bonzini bits |= PL181_STATUS_RXFIFOFULL; 272*49ab747fSPaolo Bonzini } 273*49ab747fSPaolo Bonzini if (s->fifo_len <= 8) { 274*49ab747fSPaolo Bonzini bits |= PL181_STATUS_TXFIFOHALFEMPTY; 275*49ab747fSPaolo Bonzini } 276*49ab747fSPaolo Bonzini if (s->fifo_len >= 8) { 277*49ab747fSPaolo Bonzini bits |= PL181_STATUS_RXFIFOHALFFULL; 278*49ab747fSPaolo Bonzini } 279*49ab747fSPaolo Bonzini if (s->datactrl & PL181_DATA_DIRECTION) { 280*49ab747fSPaolo Bonzini bits &= PL181_STATUS_RX_FIFO; 281*49ab747fSPaolo Bonzini } else { 282*49ab747fSPaolo Bonzini bits &= PL181_STATUS_TX_FIFO; 283*49ab747fSPaolo Bonzini } 284*49ab747fSPaolo Bonzini s->status |= bits; 285*49ab747fSPaolo Bonzini } 286*49ab747fSPaolo Bonzini } 287*49ab747fSPaolo Bonzini 288*49ab747fSPaolo Bonzini static uint64_t pl181_read(void *opaque, hwaddr offset, 289*49ab747fSPaolo Bonzini unsigned size) 290*49ab747fSPaolo Bonzini { 291*49ab747fSPaolo Bonzini pl181_state *s = (pl181_state *)opaque; 292*49ab747fSPaolo Bonzini uint32_t tmp; 293*49ab747fSPaolo Bonzini 294*49ab747fSPaolo Bonzini if (offset >= 0xfe0 && offset < 0x1000) { 295*49ab747fSPaolo Bonzini return pl181_id[(offset - 0xfe0) >> 2]; 296*49ab747fSPaolo Bonzini } 297*49ab747fSPaolo Bonzini switch (offset) { 298*49ab747fSPaolo Bonzini case 0x00: /* Power */ 299*49ab747fSPaolo Bonzini return s->power; 300*49ab747fSPaolo Bonzini case 0x04: /* Clock */ 301*49ab747fSPaolo Bonzini return s->clock; 302*49ab747fSPaolo Bonzini case 0x08: /* Argument */ 303*49ab747fSPaolo Bonzini return s->cmdarg; 304*49ab747fSPaolo Bonzini case 0x0c: /* Command */ 305*49ab747fSPaolo Bonzini return s->cmd; 306*49ab747fSPaolo Bonzini case 0x10: /* RespCmd */ 307*49ab747fSPaolo Bonzini return s->respcmd; 308*49ab747fSPaolo Bonzini case 0x14: /* Response0 */ 309*49ab747fSPaolo Bonzini return s->response[0]; 310*49ab747fSPaolo Bonzini case 0x18: /* Response1 */ 311*49ab747fSPaolo Bonzini return s->response[1]; 312*49ab747fSPaolo Bonzini case 0x1c: /* Response2 */ 313*49ab747fSPaolo Bonzini return s->response[2]; 314*49ab747fSPaolo Bonzini case 0x20: /* Response3 */ 315*49ab747fSPaolo Bonzini return s->response[3]; 316*49ab747fSPaolo Bonzini case 0x24: /* DataTimer */ 317*49ab747fSPaolo Bonzini return s->datatimer; 318*49ab747fSPaolo Bonzini case 0x28: /* DataLength */ 319*49ab747fSPaolo Bonzini return s->datalength; 320*49ab747fSPaolo Bonzini case 0x2c: /* DataCtrl */ 321*49ab747fSPaolo Bonzini return s->datactrl; 322*49ab747fSPaolo Bonzini case 0x30: /* DataCnt */ 323*49ab747fSPaolo Bonzini return s->datacnt; 324*49ab747fSPaolo Bonzini case 0x34: /* Status */ 325*49ab747fSPaolo Bonzini tmp = s->status; 326*49ab747fSPaolo Bonzini if (s->linux_hack) { 327*49ab747fSPaolo Bonzini s->linux_hack = 0; 328*49ab747fSPaolo Bonzini pl181_fifo_run(s); 329*49ab747fSPaolo Bonzini pl181_update(s); 330*49ab747fSPaolo Bonzini } 331*49ab747fSPaolo Bonzini return tmp; 332*49ab747fSPaolo Bonzini case 0x3c: /* Mask0 */ 333*49ab747fSPaolo Bonzini return s->mask[0]; 334*49ab747fSPaolo Bonzini case 0x40: /* Mask1 */ 335*49ab747fSPaolo Bonzini return s->mask[1]; 336*49ab747fSPaolo Bonzini case 0x48: /* FifoCnt */ 337*49ab747fSPaolo Bonzini /* The documentation is somewhat vague about exactly what FifoCnt 338*49ab747fSPaolo Bonzini does. On real hardware it appears to be when decrememnted 339*49ab747fSPaolo Bonzini when a word is transferred between the FIFO and the serial 340*49ab747fSPaolo Bonzini data engine. DataCnt is decremented after each byte is 341*49ab747fSPaolo Bonzini transferred between the serial engine and the card. 342*49ab747fSPaolo Bonzini We don't emulate this level of detail, so both can be the same. */ 343*49ab747fSPaolo Bonzini tmp = (s->datacnt + 3) >> 2; 344*49ab747fSPaolo Bonzini if (s->linux_hack) { 345*49ab747fSPaolo Bonzini s->linux_hack = 0; 346*49ab747fSPaolo Bonzini pl181_fifo_run(s); 347*49ab747fSPaolo Bonzini pl181_update(s); 348*49ab747fSPaolo Bonzini } 349*49ab747fSPaolo Bonzini return tmp; 350*49ab747fSPaolo Bonzini case 0x80: case 0x84: case 0x88: case 0x8c: /* FifoData */ 351*49ab747fSPaolo Bonzini case 0x90: case 0x94: case 0x98: case 0x9c: 352*49ab747fSPaolo Bonzini case 0xa0: case 0xa4: case 0xa8: case 0xac: 353*49ab747fSPaolo Bonzini case 0xb0: case 0xb4: case 0xb8: case 0xbc: 354*49ab747fSPaolo Bonzini if (s->fifo_len == 0) { 355*49ab747fSPaolo Bonzini qemu_log_mask(LOG_GUEST_ERROR, "pl181: Unexpected FIFO read\n"); 356*49ab747fSPaolo Bonzini return 0; 357*49ab747fSPaolo Bonzini } else { 358*49ab747fSPaolo Bonzini uint32_t value; 359*49ab747fSPaolo Bonzini value = pl181_fifo_pop(s); 360*49ab747fSPaolo Bonzini s->linux_hack = 1; 361*49ab747fSPaolo Bonzini pl181_fifo_run(s); 362*49ab747fSPaolo Bonzini pl181_update(s); 363*49ab747fSPaolo Bonzini return value; 364*49ab747fSPaolo Bonzini } 365*49ab747fSPaolo Bonzini default: 366*49ab747fSPaolo Bonzini qemu_log_mask(LOG_GUEST_ERROR, 367*49ab747fSPaolo Bonzini "pl181_read: Bad offset %x\n", (int)offset); 368*49ab747fSPaolo Bonzini return 0; 369*49ab747fSPaolo Bonzini } 370*49ab747fSPaolo Bonzini } 371*49ab747fSPaolo Bonzini 372*49ab747fSPaolo Bonzini static void pl181_write(void *opaque, hwaddr offset, 373*49ab747fSPaolo Bonzini uint64_t value, unsigned size) 374*49ab747fSPaolo Bonzini { 375*49ab747fSPaolo Bonzini pl181_state *s = (pl181_state *)opaque; 376*49ab747fSPaolo Bonzini 377*49ab747fSPaolo Bonzini switch (offset) { 378*49ab747fSPaolo Bonzini case 0x00: /* Power */ 379*49ab747fSPaolo Bonzini s->power = value & 0xff; 380*49ab747fSPaolo Bonzini break; 381*49ab747fSPaolo Bonzini case 0x04: /* Clock */ 382*49ab747fSPaolo Bonzini s->clock = value & 0xff; 383*49ab747fSPaolo Bonzini break; 384*49ab747fSPaolo Bonzini case 0x08: /* Argument */ 385*49ab747fSPaolo Bonzini s->cmdarg = value; 386*49ab747fSPaolo Bonzini break; 387*49ab747fSPaolo Bonzini case 0x0c: /* Command */ 388*49ab747fSPaolo Bonzini s->cmd = value; 389*49ab747fSPaolo Bonzini if (s->cmd & PL181_CMD_ENABLE) { 390*49ab747fSPaolo Bonzini if (s->cmd & PL181_CMD_INTERRUPT) { 391*49ab747fSPaolo Bonzini qemu_log_mask(LOG_UNIMP, 392*49ab747fSPaolo Bonzini "pl181: Interrupt mode not implemented\n"); 393*49ab747fSPaolo Bonzini } if (s->cmd & PL181_CMD_PENDING) { 394*49ab747fSPaolo Bonzini qemu_log_mask(LOG_UNIMP, 395*49ab747fSPaolo Bonzini "pl181: Pending commands not implemented\n"); 396*49ab747fSPaolo Bonzini } else { 397*49ab747fSPaolo Bonzini pl181_send_command(s); 398*49ab747fSPaolo Bonzini pl181_fifo_run(s); 399*49ab747fSPaolo Bonzini } 400*49ab747fSPaolo Bonzini /* The command has completed one way or the other. */ 401*49ab747fSPaolo Bonzini s->cmd &= ~PL181_CMD_ENABLE; 402*49ab747fSPaolo Bonzini } 403*49ab747fSPaolo Bonzini break; 404*49ab747fSPaolo Bonzini case 0x24: /* DataTimer */ 405*49ab747fSPaolo Bonzini s->datatimer = value; 406*49ab747fSPaolo Bonzini break; 407*49ab747fSPaolo Bonzini case 0x28: /* DataLength */ 408*49ab747fSPaolo Bonzini s->datalength = value & 0xffff; 409*49ab747fSPaolo Bonzini break; 410*49ab747fSPaolo Bonzini case 0x2c: /* DataCtrl */ 411*49ab747fSPaolo Bonzini s->datactrl = value & 0xff; 412*49ab747fSPaolo Bonzini if (value & PL181_DATA_ENABLE) { 413*49ab747fSPaolo Bonzini s->datacnt = s->datalength; 414*49ab747fSPaolo Bonzini pl181_fifo_run(s); 415*49ab747fSPaolo Bonzini } 416*49ab747fSPaolo Bonzini break; 417*49ab747fSPaolo Bonzini case 0x38: /* Clear */ 418*49ab747fSPaolo Bonzini s->status &= ~(value & 0x7ff); 419*49ab747fSPaolo Bonzini break; 420*49ab747fSPaolo Bonzini case 0x3c: /* Mask0 */ 421*49ab747fSPaolo Bonzini s->mask[0] = value; 422*49ab747fSPaolo Bonzini break; 423*49ab747fSPaolo Bonzini case 0x40: /* Mask1 */ 424*49ab747fSPaolo Bonzini s->mask[1] = value; 425*49ab747fSPaolo Bonzini break; 426*49ab747fSPaolo Bonzini case 0x80: case 0x84: case 0x88: case 0x8c: /* FifoData */ 427*49ab747fSPaolo Bonzini case 0x90: case 0x94: case 0x98: case 0x9c: 428*49ab747fSPaolo Bonzini case 0xa0: case 0xa4: case 0xa8: case 0xac: 429*49ab747fSPaolo Bonzini case 0xb0: case 0xb4: case 0xb8: case 0xbc: 430*49ab747fSPaolo Bonzini if (s->datacnt == 0) { 431*49ab747fSPaolo Bonzini qemu_log_mask(LOG_GUEST_ERROR, "pl181: Unexpected FIFO write\n"); 432*49ab747fSPaolo Bonzini } else { 433*49ab747fSPaolo Bonzini pl181_fifo_push(s, value); 434*49ab747fSPaolo Bonzini pl181_fifo_run(s); 435*49ab747fSPaolo Bonzini } 436*49ab747fSPaolo Bonzini break; 437*49ab747fSPaolo Bonzini default: 438*49ab747fSPaolo Bonzini qemu_log_mask(LOG_GUEST_ERROR, 439*49ab747fSPaolo Bonzini "pl181_write: Bad offset %x\n", (int)offset); 440*49ab747fSPaolo Bonzini } 441*49ab747fSPaolo Bonzini pl181_update(s); 442*49ab747fSPaolo Bonzini } 443*49ab747fSPaolo Bonzini 444*49ab747fSPaolo Bonzini static const MemoryRegionOps pl181_ops = { 445*49ab747fSPaolo Bonzini .read = pl181_read, 446*49ab747fSPaolo Bonzini .write = pl181_write, 447*49ab747fSPaolo Bonzini .endianness = DEVICE_NATIVE_ENDIAN, 448*49ab747fSPaolo Bonzini }; 449*49ab747fSPaolo Bonzini 450*49ab747fSPaolo Bonzini static void pl181_reset(DeviceState *d) 451*49ab747fSPaolo Bonzini { 452*49ab747fSPaolo Bonzini pl181_state *s = DO_UPCAST(pl181_state, busdev.qdev, d); 453*49ab747fSPaolo Bonzini 454*49ab747fSPaolo Bonzini s->power = 0; 455*49ab747fSPaolo Bonzini s->cmdarg = 0; 456*49ab747fSPaolo Bonzini s->cmd = 0; 457*49ab747fSPaolo Bonzini s->datatimer = 0; 458*49ab747fSPaolo Bonzini s->datalength = 0; 459*49ab747fSPaolo Bonzini s->respcmd = 0; 460*49ab747fSPaolo Bonzini s->response[0] = 0; 461*49ab747fSPaolo Bonzini s->response[1] = 0; 462*49ab747fSPaolo Bonzini s->response[2] = 0; 463*49ab747fSPaolo Bonzini s->response[3] = 0; 464*49ab747fSPaolo Bonzini s->datatimer = 0; 465*49ab747fSPaolo Bonzini s->datalength = 0; 466*49ab747fSPaolo Bonzini s->datactrl = 0; 467*49ab747fSPaolo Bonzini s->datacnt = 0; 468*49ab747fSPaolo Bonzini s->status = 0; 469*49ab747fSPaolo Bonzini s->linux_hack = 0; 470*49ab747fSPaolo Bonzini s->mask[0] = 0; 471*49ab747fSPaolo Bonzini s->mask[1] = 0; 472*49ab747fSPaolo Bonzini 473*49ab747fSPaolo Bonzini /* We can assume our GPIO outputs have been wired up now */ 474*49ab747fSPaolo Bonzini sd_set_cb(s->card, s->cardstatus[0], s->cardstatus[1]); 475*49ab747fSPaolo Bonzini } 476*49ab747fSPaolo Bonzini 477*49ab747fSPaolo Bonzini static int pl181_init(SysBusDevice *dev) 478*49ab747fSPaolo Bonzini { 479*49ab747fSPaolo Bonzini pl181_state *s = FROM_SYSBUS(pl181_state, dev); 480*49ab747fSPaolo Bonzini DriveInfo *dinfo; 481*49ab747fSPaolo Bonzini 482*49ab747fSPaolo Bonzini memory_region_init_io(&s->iomem, &pl181_ops, s, "pl181", 0x1000); 483*49ab747fSPaolo Bonzini sysbus_init_mmio(dev, &s->iomem); 484*49ab747fSPaolo Bonzini sysbus_init_irq(dev, &s->irq[0]); 485*49ab747fSPaolo Bonzini sysbus_init_irq(dev, &s->irq[1]); 486*49ab747fSPaolo Bonzini qdev_init_gpio_out(&s->busdev.qdev, s->cardstatus, 2); 487*49ab747fSPaolo Bonzini dinfo = drive_get_next(IF_SD); 488*49ab747fSPaolo Bonzini s->card = sd_init(dinfo ? dinfo->bdrv : NULL, 0); 489*49ab747fSPaolo Bonzini return 0; 490*49ab747fSPaolo Bonzini } 491*49ab747fSPaolo Bonzini 492*49ab747fSPaolo Bonzini static void pl181_class_init(ObjectClass *klass, void *data) 493*49ab747fSPaolo Bonzini { 494*49ab747fSPaolo Bonzini SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass); 495*49ab747fSPaolo Bonzini DeviceClass *k = DEVICE_CLASS(klass); 496*49ab747fSPaolo Bonzini 497*49ab747fSPaolo Bonzini sdc->init = pl181_init; 498*49ab747fSPaolo Bonzini k->vmsd = &vmstate_pl181; 499*49ab747fSPaolo Bonzini k->reset = pl181_reset; 500*49ab747fSPaolo Bonzini k->no_user = 1; 501*49ab747fSPaolo Bonzini } 502*49ab747fSPaolo Bonzini 503*49ab747fSPaolo Bonzini static const TypeInfo pl181_info = { 504*49ab747fSPaolo Bonzini .name = "pl181", 505*49ab747fSPaolo Bonzini .parent = TYPE_SYS_BUS_DEVICE, 506*49ab747fSPaolo Bonzini .instance_size = sizeof(pl181_state), 507*49ab747fSPaolo Bonzini .class_init = pl181_class_init, 508*49ab747fSPaolo Bonzini }; 509*49ab747fSPaolo Bonzini 510*49ab747fSPaolo Bonzini static void pl181_register_types(void) 511*49ab747fSPaolo Bonzini { 512*49ab747fSPaolo Bonzini type_register_static(&pl181_info); 513*49ab747fSPaolo Bonzini } 514*49ab747fSPaolo Bonzini 515*49ab747fSPaolo Bonzini type_init(pl181_register_types) 516