1a1bb27b1Spbrook /* 2a1bb27b1Spbrook * Arm PrimeCell PL181 MultiMedia Card Interface 3a1bb27b1Spbrook * 4a1bb27b1Spbrook * Copyright (c) 2007 CodeSourcery. 5a1bb27b1Spbrook * Written by Paul Brook 6a1bb27b1Spbrook * 78e31bf38SMatthew Fernandez * This code is licensed under the GPL. 8a1bb27b1Spbrook */ 9a1bb27b1Spbrook 109c17d615SPaolo Bonzini #include "sysemu/blockdev.h" 1183c9f4caSPaolo Bonzini #include "hw/sysbus.h" 1283c9f4caSPaolo Bonzini #include "hw/sd.h" 13a1bb27b1Spbrook 14a1bb27b1Spbrook //#define DEBUG_PL181 1 15a1bb27b1Spbrook 16a1bb27b1Spbrook #ifdef DEBUG_PL181 17001faf32SBlue Swirl #define DPRINTF(fmt, ...) \ 18001faf32SBlue Swirl do { printf("pl181: " fmt , ## __VA_ARGS__); } while (0) 19a1bb27b1Spbrook #else 20001faf32SBlue Swirl #define DPRINTF(fmt, ...) do {} while(0) 21a1bb27b1Spbrook #endif 22a1bb27b1Spbrook 23a1bb27b1Spbrook #define PL181_FIFO_LEN 16 24a1bb27b1Spbrook 25a1bb27b1Spbrook typedef struct { 26aa9311d8SPaul Brook SysBusDevice busdev; 27ca45842aSAvi Kivity MemoryRegion iomem; 2842a10898Spbrook SDState *card; 29a1bb27b1Spbrook uint32_t clock; 30a1bb27b1Spbrook uint32_t power; 31a1bb27b1Spbrook uint32_t cmdarg; 32a1bb27b1Spbrook uint32_t cmd; 33a1bb27b1Spbrook uint32_t datatimer; 34a1bb27b1Spbrook uint32_t datalength; 35a1bb27b1Spbrook uint32_t respcmd; 36a1bb27b1Spbrook uint32_t response[4]; 37a1bb27b1Spbrook uint32_t datactrl; 38a1bb27b1Spbrook uint32_t datacnt; 39a1bb27b1Spbrook uint32_t status; 40a1bb27b1Spbrook uint32_t mask[2]; 41624923beSPeter Maydell int32_t fifo_pos; 42624923beSPeter Maydell int32_t fifo_len; 436361cdb6Spbrook /* The linux 2.6.21 driver is buggy, and misbehaves if new data arrives 446361cdb6Spbrook while it is reading the FIFO. We hack around this be defering 456361cdb6Spbrook subsequent transfers until after the driver polls the status word. 466361cdb6Spbrook http://www.arm.linux.org.uk/developer/patches/viewpatch.php?id=4446/1 476361cdb6Spbrook */ 48624923beSPeter Maydell int32_t linux_hack; 49a1bb27b1Spbrook uint32_t fifo[PL181_FIFO_LEN]; 50d537cf6cSpbrook qemu_irq irq[2]; 51c31a4724SPeter Maydell /* GPIO outputs for 'card is readonly' and 'card inserted' */ 52c31a4724SPeter Maydell qemu_irq cardstatus[2]; 53a1bb27b1Spbrook } pl181_state; 54a1bb27b1Spbrook 55624923beSPeter Maydell static const VMStateDescription vmstate_pl181 = { 56624923beSPeter Maydell .name = "pl181", 57624923beSPeter Maydell .version_id = 1, 58624923beSPeter Maydell .minimum_version_id = 1, 59624923beSPeter Maydell .fields = (VMStateField[]) { 60624923beSPeter Maydell VMSTATE_UINT32(clock, pl181_state), 61624923beSPeter Maydell VMSTATE_UINT32(power, pl181_state), 62624923beSPeter Maydell VMSTATE_UINT32(cmdarg, pl181_state), 63624923beSPeter Maydell VMSTATE_UINT32(cmd, pl181_state), 64624923beSPeter Maydell VMSTATE_UINT32(datatimer, pl181_state), 65624923beSPeter Maydell VMSTATE_UINT32(datalength, pl181_state), 66624923beSPeter Maydell VMSTATE_UINT32(respcmd, pl181_state), 67624923beSPeter Maydell VMSTATE_UINT32_ARRAY(response, pl181_state, 4), 68624923beSPeter Maydell VMSTATE_UINT32(datactrl, pl181_state), 69624923beSPeter Maydell VMSTATE_UINT32(datacnt, pl181_state), 70624923beSPeter Maydell VMSTATE_UINT32(status, pl181_state), 71624923beSPeter Maydell VMSTATE_UINT32_ARRAY(mask, pl181_state, 2), 72624923beSPeter Maydell VMSTATE_INT32(fifo_pos, pl181_state), 73624923beSPeter Maydell VMSTATE_INT32(fifo_len, pl181_state), 74624923beSPeter Maydell VMSTATE_INT32(linux_hack, pl181_state), 75624923beSPeter Maydell VMSTATE_UINT32_ARRAY(fifo, pl181_state, PL181_FIFO_LEN), 76624923beSPeter Maydell VMSTATE_END_OF_LIST() 77624923beSPeter Maydell } 78624923beSPeter Maydell }; 79624923beSPeter Maydell 80a1bb27b1Spbrook #define PL181_CMD_INDEX 0x3f 81a1bb27b1Spbrook #define PL181_CMD_RESPONSE (1 << 6) 82a1bb27b1Spbrook #define PL181_CMD_LONGRESP (1 << 7) 83a1bb27b1Spbrook #define PL181_CMD_INTERRUPT (1 << 8) 84a1bb27b1Spbrook #define PL181_CMD_PENDING (1 << 9) 85a1bb27b1Spbrook #define PL181_CMD_ENABLE (1 << 10) 86a1bb27b1Spbrook 87a1bb27b1Spbrook #define PL181_DATA_ENABLE (1 << 0) 88a1bb27b1Spbrook #define PL181_DATA_DIRECTION (1 << 1) 89a1bb27b1Spbrook #define PL181_DATA_MODE (1 << 2) 90a1bb27b1Spbrook #define PL181_DATA_DMAENABLE (1 << 3) 91a1bb27b1Spbrook 92a1bb27b1Spbrook #define PL181_STATUS_CMDCRCFAIL (1 << 0) 93a1bb27b1Spbrook #define PL181_STATUS_DATACRCFAIL (1 << 1) 94a1bb27b1Spbrook #define PL181_STATUS_CMDTIMEOUT (1 << 2) 95a1bb27b1Spbrook #define PL181_STATUS_DATATIMEOUT (1 << 3) 96a1bb27b1Spbrook #define PL181_STATUS_TXUNDERRUN (1 << 4) 97a1bb27b1Spbrook #define PL181_STATUS_RXOVERRUN (1 << 5) 98a1bb27b1Spbrook #define PL181_STATUS_CMDRESPEND (1 << 6) 99a1bb27b1Spbrook #define PL181_STATUS_CMDSENT (1 << 7) 100a1bb27b1Spbrook #define PL181_STATUS_DATAEND (1 << 8) 101a1bb27b1Spbrook #define PL181_STATUS_DATABLOCKEND (1 << 10) 102a1bb27b1Spbrook #define PL181_STATUS_CMDACTIVE (1 << 11) 103a1bb27b1Spbrook #define PL181_STATUS_TXACTIVE (1 << 12) 104a1bb27b1Spbrook #define PL181_STATUS_RXACTIVE (1 << 13) 105a1bb27b1Spbrook #define PL181_STATUS_TXFIFOHALFEMPTY (1 << 14) 106a1bb27b1Spbrook #define PL181_STATUS_RXFIFOHALFFULL (1 << 15) 107a1bb27b1Spbrook #define PL181_STATUS_TXFIFOFULL (1 << 16) 108a1bb27b1Spbrook #define PL181_STATUS_RXFIFOFULL (1 << 17) 109a1bb27b1Spbrook #define PL181_STATUS_TXFIFOEMPTY (1 << 18) 110a1bb27b1Spbrook #define PL181_STATUS_RXFIFOEMPTY (1 << 19) 111a1bb27b1Spbrook #define PL181_STATUS_TXDATAAVLBL (1 << 20) 112a1bb27b1Spbrook #define PL181_STATUS_RXDATAAVLBL (1 << 21) 113a1bb27b1Spbrook 114a1bb27b1Spbrook #define PL181_STATUS_TX_FIFO (PL181_STATUS_TXACTIVE \ 115a1bb27b1Spbrook |PL181_STATUS_TXFIFOHALFEMPTY \ 116a1bb27b1Spbrook |PL181_STATUS_TXFIFOFULL \ 117a1bb27b1Spbrook |PL181_STATUS_TXFIFOEMPTY \ 118a1bb27b1Spbrook |PL181_STATUS_TXDATAAVLBL) 119a1bb27b1Spbrook #define PL181_STATUS_RX_FIFO (PL181_STATUS_RXACTIVE \ 120a1bb27b1Spbrook |PL181_STATUS_RXFIFOHALFFULL \ 121a1bb27b1Spbrook |PL181_STATUS_RXFIFOFULL \ 122a1bb27b1Spbrook |PL181_STATUS_RXFIFOEMPTY \ 123a1bb27b1Spbrook |PL181_STATUS_RXDATAAVLBL) 124a1bb27b1Spbrook 125a1bb27b1Spbrook static const unsigned char pl181_id[] = 126a1bb27b1Spbrook { 0x81, 0x11, 0x04, 0x00, 0x0d, 0xf0, 0x05, 0xb1 }; 127a1bb27b1Spbrook 128a1bb27b1Spbrook static void pl181_update(pl181_state *s) 129a1bb27b1Spbrook { 130a1bb27b1Spbrook int i; 131a1bb27b1Spbrook for (i = 0; i < 2; i++) { 132d537cf6cSpbrook qemu_set_irq(s->irq[i], (s->status & s->mask[i]) != 0); 133a1bb27b1Spbrook } 134a1bb27b1Spbrook } 135a1bb27b1Spbrook 136a1bb27b1Spbrook static void pl181_fifo_push(pl181_state *s, uint32_t value) 137a1bb27b1Spbrook { 138a1bb27b1Spbrook int n; 139a1bb27b1Spbrook 140a1bb27b1Spbrook if (s->fifo_len == PL181_FIFO_LEN) { 141a1bb27b1Spbrook fprintf(stderr, "pl181: FIFO overflow\n"); 142a1bb27b1Spbrook return; 143a1bb27b1Spbrook } 144a1bb27b1Spbrook n = (s->fifo_pos + s->fifo_len) & (PL181_FIFO_LEN - 1); 145a1bb27b1Spbrook s->fifo_len++; 146a1bb27b1Spbrook s->fifo[n] = value; 147a1bb27b1Spbrook DPRINTF("FIFO push %08x\n", (int)value); 148a1bb27b1Spbrook } 149a1bb27b1Spbrook 150a1bb27b1Spbrook static uint32_t pl181_fifo_pop(pl181_state *s) 151a1bb27b1Spbrook { 152a1bb27b1Spbrook uint32_t value; 153a1bb27b1Spbrook 154a1bb27b1Spbrook if (s->fifo_len == 0) { 155a1bb27b1Spbrook fprintf(stderr, "pl181: FIFO underflow\n"); 156a1bb27b1Spbrook return 0; 157a1bb27b1Spbrook } 158a1bb27b1Spbrook value = s->fifo[s->fifo_pos]; 159a1bb27b1Spbrook s->fifo_len--; 160a1bb27b1Spbrook s->fifo_pos = (s->fifo_pos + 1) & (PL181_FIFO_LEN - 1); 161a1bb27b1Spbrook DPRINTF("FIFO pop %08x\n", (int)value); 162a1bb27b1Spbrook return value; 163a1bb27b1Spbrook } 164a1bb27b1Spbrook 165a1bb27b1Spbrook static void pl181_send_command(pl181_state *s) 166a1bb27b1Spbrook { 167bc24a225SPaul Brook SDRequest request; 168a1bb27b1Spbrook uint8_t response[16]; 169a1bb27b1Spbrook int rlen; 170a1bb27b1Spbrook 171a1bb27b1Spbrook request.cmd = s->cmd & PL181_CMD_INDEX; 172a1bb27b1Spbrook request.arg = s->cmdarg; 173a1bb27b1Spbrook DPRINTF("Command %d %08x\n", request.cmd, request.arg); 174a1bb27b1Spbrook rlen = sd_do_command(s->card, &request, response); 175a1bb27b1Spbrook if (rlen < 0) 176a1bb27b1Spbrook goto error; 177a1bb27b1Spbrook if (s->cmd & PL181_CMD_RESPONSE) { 178a1bb27b1Spbrook #define RWORD(n) ((response[n] << 24) | (response[n + 1] << 16) \ 179a1bb27b1Spbrook | (response[n + 2] << 8) | response[n + 3]) 180a1bb27b1Spbrook if (rlen == 0 || (rlen == 4 && (s->cmd & PL181_CMD_LONGRESP))) 181a1bb27b1Spbrook goto error; 182a1bb27b1Spbrook if (rlen != 4 && rlen != 16) 183a1bb27b1Spbrook goto error; 184a1bb27b1Spbrook s->response[0] = RWORD(0); 185a1bb27b1Spbrook if (rlen == 4) { 186a1bb27b1Spbrook s->response[1] = s->response[2] = s->response[3] = 0; 187a1bb27b1Spbrook } else { 188a1bb27b1Spbrook s->response[1] = RWORD(4); 189a1bb27b1Spbrook s->response[2] = RWORD(8); 190a1bb27b1Spbrook s->response[3] = RWORD(12) & ~1; 191a1bb27b1Spbrook } 192aa1f17c1Sths DPRINTF("Response received\n"); 193a1bb27b1Spbrook s->status |= PL181_STATUS_CMDRESPEND; 194a1bb27b1Spbrook #undef RWORD 195a1bb27b1Spbrook } else { 196a1bb27b1Spbrook DPRINTF("Command sent\n"); 197a1bb27b1Spbrook s->status |= PL181_STATUS_CMDSENT; 198a1bb27b1Spbrook } 199a1bb27b1Spbrook return; 200a1bb27b1Spbrook 201a1bb27b1Spbrook error: 202a1bb27b1Spbrook DPRINTF("Timeout\n"); 203a1bb27b1Spbrook s->status |= PL181_STATUS_CMDTIMEOUT; 204a1bb27b1Spbrook } 205a1bb27b1Spbrook 206aa1f17c1Sths /* Transfer data between the card and the FIFO. This is complicated by 207a1bb27b1Spbrook the FIFO holding 32-bit words and the card taking data in single byte 208a1bb27b1Spbrook chunks. FIFO bytes are transferred in little-endian order. */ 209a1bb27b1Spbrook 210a1bb27b1Spbrook static void pl181_fifo_run(pl181_state *s) 211a1bb27b1Spbrook { 212a1bb27b1Spbrook uint32_t bits; 213f21126dfSBlue Swirl uint32_t value = 0; 214a1bb27b1Spbrook int n; 215a1bb27b1Spbrook int is_read; 216a1bb27b1Spbrook 217a1bb27b1Spbrook is_read = (s->datactrl & PL181_DATA_DIRECTION) != 0; 2186361cdb6Spbrook if (s->datacnt != 0 && (!is_read || sd_data_ready(s->card)) 2196361cdb6Spbrook && !s->linux_hack) { 220bc3b26f5SPaul Brook if (is_read) { 221a1bb27b1Spbrook n = 0; 222bc3b26f5SPaul Brook while (s->datacnt && s->fifo_len < PL181_FIFO_LEN) { 223a1bb27b1Spbrook value |= (uint32_t)sd_read_data(s->card) << (n * 8); 224bc3b26f5SPaul Brook s->datacnt--; 225a1bb27b1Spbrook n++; 226a1bb27b1Spbrook if (n == 4) { 227a1bb27b1Spbrook pl181_fifo_push(s, value); 228a1bb27b1Spbrook n = 0; 229bc3b26f5SPaul Brook value = 0; 230a1bb27b1Spbrook } 231bc3b26f5SPaul Brook } 232bc3b26f5SPaul Brook if (n != 0) { 233bc3b26f5SPaul Brook pl181_fifo_push(s, value); 234bc3b26f5SPaul Brook } 235bc3b26f5SPaul Brook } else { /* write */ 236bc3b26f5SPaul Brook n = 0; 237bc3b26f5SPaul Brook while (s->datacnt > 0 && (s->fifo_len > 0 || n > 0)) { 238a1bb27b1Spbrook if (n == 0) { 239a1bb27b1Spbrook value = pl181_fifo_pop(s); 240a1bb27b1Spbrook n = 4; 241a1bb27b1Spbrook } 242bc3b26f5SPaul Brook n--; 243bc3b26f5SPaul Brook s->datacnt--; 244a1bb27b1Spbrook sd_write_data(s->card, value & 0xff); 245a1bb27b1Spbrook value >>= 8; 246a1bb27b1Spbrook } 247a1bb27b1Spbrook } 248a1bb27b1Spbrook } 249a1bb27b1Spbrook s->status &= ~(PL181_STATUS_RX_FIFO | PL181_STATUS_TX_FIFO); 250a1bb27b1Spbrook if (s->datacnt == 0) { 251a1bb27b1Spbrook s->status |= PL181_STATUS_DATAEND; 252a1bb27b1Spbrook /* HACK: */ 253a1bb27b1Spbrook s->status |= PL181_STATUS_DATABLOCKEND; 254a1bb27b1Spbrook DPRINTF("Transfer Complete\n"); 255a1bb27b1Spbrook } 2566361cdb6Spbrook if (s->datacnt == 0 && s->fifo_len == 0) { 257a1bb27b1Spbrook s->datactrl &= ~PL181_DATA_ENABLE; 258a1bb27b1Spbrook DPRINTF("Data engine idle\n"); 259a1bb27b1Spbrook } else { 260a1bb27b1Spbrook /* Update FIFO bits. */ 261a1bb27b1Spbrook bits = PL181_STATUS_TXACTIVE | PL181_STATUS_RXACTIVE; 262a1bb27b1Spbrook if (s->fifo_len == 0) { 263a1bb27b1Spbrook bits |= PL181_STATUS_TXFIFOEMPTY; 264a1bb27b1Spbrook bits |= PL181_STATUS_RXFIFOEMPTY; 265a1bb27b1Spbrook } else { 266a1bb27b1Spbrook bits |= PL181_STATUS_TXDATAAVLBL; 267a1bb27b1Spbrook bits |= PL181_STATUS_RXDATAAVLBL; 268a1bb27b1Spbrook } 269a1bb27b1Spbrook if (s->fifo_len == 16) { 270a1bb27b1Spbrook bits |= PL181_STATUS_TXFIFOFULL; 271a1bb27b1Spbrook bits |= PL181_STATUS_RXFIFOFULL; 272a1bb27b1Spbrook } 273a1bb27b1Spbrook if (s->fifo_len <= 8) { 274a1bb27b1Spbrook bits |= PL181_STATUS_TXFIFOHALFEMPTY; 275a1bb27b1Spbrook } 276a1bb27b1Spbrook if (s->fifo_len >= 8) { 277a1bb27b1Spbrook bits |= PL181_STATUS_RXFIFOHALFFULL; 278a1bb27b1Spbrook } 279a1bb27b1Spbrook if (s->datactrl & PL181_DATA_DIRECTION) { 280a1bb27b1Spbrook bits &= PL181_STATUS_RX_FIFO; 281a1bb27b1Spbrook } else { 282a1bb27b1Spbrook bits &= PL181_STATUS_TX_FIFO; 283a1bb27b1Spbrook } 284a1bb27b1Spbrook s->status |= bits; 285a1bb27b1Spbrook } 286a1bb27b1Spbrook } 287a1bb27b1Spbrook 288a8170e5eSAvi Kivity static uint64_t pl181_read(void *opaque, hwaddr offset, 289ca45842aSAvi Kivity unsigned size) 290a1bb27b1Spbrook { 291a1bb27b1Spbrook pl181_state *s = (pl181_state *)opaque; 2926361cdb6Spbrook uint32_t tmp; 293a1bb27b1Spbrook 294a1bb27b1Spbrook if (offset >= 0xfe0 && offset < 0x1000) { 295a1bb27b1Spbrook return pl181_id[(offset - 0xfe0) >> 2]; 296a1bb27b1Spbrook } 297a1bb27b1Spbrook switch (offset) { 298a1bb27b1Spbrook case 0x00: /* Power */ 299a1bb27b1Spbrook return s->power; 300a1bb27b1Spbrook case 0x04: /* Clock */ 301a1bb27b1Spbrook return s->clock; 302a1bb27b1Spbrook case 0x08: /* Argument */ 303a1bb27b1Spbrook return s->cmdarg; 304a1bb27b1Spbrook case 0x0c: /* Command */ 305a1bb27b1Spbrook return s->cmd; 306a1bb27b1Spbrook case 0x10: /* RespCmd */ 307a1bb27b1Spbrook return s->respcmd; 308a1bb27b1Spbrook case 0x14: /* Response0 */ 309a1bb27b1Spbrook return s->response[0]; 310a1bb27b1Spbrook case 0x18: /* Response1 */ 311a1bb27b1Spbrook return s->response[1]; 312a1bb27b1Spbrook case 0x1c: /* Response2 */ 313a1bb27b1Spbrook return s->response[2]; 314a1bb27b1Spbrook case 0x20: /* Response3 */ 315a1bb27b1Spbrook return s->response[3]; 316a1bb27b1Spbrook case 0x24: /* DataTimer */ 317a1bb27b1Spbrook return s->datatimer; 318a1bb27b1Spbrook case 0x28: /* DataLength */ 319a1bb27b1Spbrook return s->datalength; 320a1bb27b1Spbrook case 0x2c: /* DataCtrl */ 321a1bb27b1Spbrook return s->datactrl; 322a1bb27b1Spbrook case 0x30: /* DataCnt */ 323a1bb27b1Spbrook return s->datacnt; 324a1bb27b1Spbrook case 0x34: /* Status */ 3256361cdb6Spbrook tmp = s->status; 3266361cdb6Spbrook if (s->linux_hack) { 3276361cdb6Spbrook s->linux_hack = 0; 3286361cdb6Spbrook pl181_fifo_run(s); 3296361cdb6Spbrook pl181_update(s); 3306361cdb6Spbrook } 3316361cdb6Spbrook return tmp; 332a1bb27b1Spbrook case 0x3c: /* Mask0 */ 333a1bb27b1Spbrook return s->mask[0]; 334a1bb27b1Spbrook case 0x40: /* Mask1 */ 335a1bb27b1Spbrook return s->mask[1]; 336a1bb27b1Spbrook case 0x48: /* FifoCnt */ 3376361cdb6Spbrook /* The documentation is somewhat vague about exactly what FifoCnt 3386361cdb6Spbrook does. On real hardware it appears to be when decrememnted 33966a0a2cbSDong Xu Wang when a word is transferred between the FIFO and the serial 3406361cdb6Spbrook data engine. DataCnt is decremented after each byte is 34166a0a2cbSDong Xu Wang transferred between the serial engine and the card. 3426361cdb6Spbrook We don't emulate this level of detail, so both can be the same. */ 3436361cdb6Spbrook tmp = (s->datacnt + 3) >> 2; 3446361cdb6Spbrook if (s->linux_hack) { 3456361cdb6Spbrook s->linux_hack = 0; 3466361cdb6Spbrook pl181_fifo_run(s); 3476361cdb6Spbrook pl181_update(s); 3486361cdb6Spbrook } 3496361cdb6Spbrook return tmp; 350a1bb27b1Spbrook case 0x80: case 0x84: case 0x88: case 0x8c: /* FifoData */ 351a1bb27b1Spbrook case 0x90: case 0x94: case 0x98: case 0x9c: 352a1bb27b1Spbrook case 0xa0: case 0xa4: case 0xa8: case 0xac: 353a1bb27b1Spbrook case 0xb0: case 0xb4: case 0xb8: case 0xbc: 3546361cdb6Spbrook if (s->fifo_len == 0) { 3559351d708SPeter Maydell qemu_log_mask(LOG_GUEST_ERROR, "pl181: Unexpected FIFO read\n"); 356a1bb27b1Spbrook return 0; 357a1bb27b1Spbrook } else { 358a1bb27b1Spbrook uint32_t value; 359a1bb27b1Spbrook value = pl181_fifo_pop(s); 3606361cdb6Spbrook s->linux_hack = 1; 361a1bb27b1Spbrook pl181_fifo_run(s); 362a1bb27b1Spbrook pl181_update(s); 363a1bb27b1Spbrook return value; 364a1bb27b1Spbrook } 365a1bb27b1Spbrook default: 3669351d708SPeter Maydell qemu_log_mask(LOG_GUEST_ERROR, 3679351d708SPeter Maydell "pl181_read: Bad offset %x\n", (int)offset); 368a1bb27b1Spbrook return 0; 369a1bb27b1Spbrook } 370a1bb27b1Spbrook } 371a1bb27b1Spbrook 372a8170e5eSAvi Kivity static void pl181_write(void *opaque, hwaddr offset, 373ca45842aSAvi Kivity uint64_t value, unsigned size) 374a1bb27b1Spbrook { 375a1bb27b1Spbrook pl181_state *s = (pl181_state *)opaque; 376a1bb27b1Spbrook 377a1bb27b1Spbrook switch (offset) { 378a1bb27b1Spbrook case 0x00: /* Power */ 379a1bb27b1Spbrook s->power = value & 0xff; 380a1bb27b1Spbrook break; 381a1bb27b1Spbrook case 0x04: /* Clock */ 382a1bb27b1Spbrook s->clock = value & 0xff; 383a1bb27b1Spbrook break; 384a1bb27b1Spbrook case 0x08: /* Argument */ 385a1bb27b1Spbrook s->cmdarg = value; 386a1bb27b1Spbrook break; 387a1bb27b1Spbrook case 0x0c: /* Command */ 388a1bb27b1Spbrook s->cmd = value; 389a1bb27b1Spbrook if (s->cmd & PL181_CMD_ENABLE) { 390a1bb27b1Spbrook if (s->cmd & PL181_CMD_INTERRUPT) { 3919351d708SPeter Maydell qemu_log_mask(LOG_UNIMP, 3929351d708SPeter Maydell "pl181: Interrupt mode not implemented\n"); 393a1bb27b1Spbrook } if (s->cmd & PL181_CMD_PENDING) { 3949351d708SPeter Maydell qemu_log_mask(LOG_UNIMP, 3959351d708SPeter Maydell "pl181: Pending commands not implemented\n"); 396a1bb27b1Spbrook } else { 397a1bb27b1Spbrook pl181_send_command(s); 398a1bb27b1Spbrook pl181_fifo_run(s); 399a1bb27b1Spbrook } 400a1bb27b1Spbrook /* The command has completed one way or the other. */ 401a1bb27b1Spbrook s->cmd &= ~PL181_CMD_ENABLE; 402a1bb27b1Spbrook } 403a1bb27b1Spbrook break; 404a1bb27b1Spbrook case 0x24: /* DataTimer */ 405a1bb27b1Spbrook s->datatimer = value; 406a1bb27b1Spbrook break; 407a1bb27b1Spbrook case 0x28: /* DataLength */ 408a1bb27b1Spbrook s->datalength = value & 0xffff; 409a1bb27b1Spbrook break; 410a1bb27b1Spbrook case 0x2c: /* DataCtrl */ 411a1bb27b1Spbrook s->datactrl = value & 0xff; 412a1bb27b1Spbrook if (value & PL181_DATA_ENABLE) { 413a1bb27b1Spbrook s->datacnt = s->datalength; 414a1bb27b1Spbrook pl181_fifo_run(s); 415a1bb27b1Spbrook } 416a1bb27b1Spbrook break; 417a1bb27b1Spbrook case 0x38: /* Clear */ 418a1bb27b1Spbrook s->status &= ~(value & 0x7ff); 419a1bb27b1Spbrook break; 420a1bb27b1Spbrook case 0x3c: /* Mask0 */ 421a1bb27b1Spbrook s->mask[0] = value; 422a1bb27b1Spbrook break; 423a1bb27b1Spbrook case 0x40: /* Mask1 */ 424a1bb27b1Spbrook s->mask[1] = value; 425a1bb27b1Spbrook break; 426a1bb27b1Spbrook case 0x80: case 0x84: case 0x88: case 0x8c: /* FifoData */ 427a1bb27b1Spbrook case 0x90: case 0x94: case 0x98: case 0x9c: 428a1bb27b1Spbrook case 0xa0: case 0xa4: case 0xa8: case 0xac: 429a1bb27b1Spbrook case 0xb0: case 0xb4: case 0xb8: case 0xbc: 4306361cdb6Spbrook if (s->datacnt == 0) { 4319351d708SPeter Maydell qemu_log_mask(LOG_GUEST_ERROR, "pl181: Unexpected FIFO write\n"); 432a1bb27b1Spbrook } else { 433a1bb27b1Spbrook pl181_fifo_push(s, value); 434a1bb27b1Spbrook pl181_fifo_run(s); 435a1bb27b1Spbrook } 436a1bb27b1Spbrook break; 437a1bb27b1Spbrook default: 4389351d708SPeter Maydell qemu_log_mask(LOG_GUEST_ERROR, 4399351d708SPeter Maydell "pl181_write: Bad offset %x\n", (int)offset); 440a1bb27b1Spbrook } 441a1bb27b1Spbrook pl181_update(s); 442a1bb27b1Spbrook } 443a1bb27b1Spbrook 444ca45842aSAvi Kivity static const MemoryRegionOps pl181_ops = { 445ca45842aSAvi Kivity .read = pl181_read, 446ca45842aSAvi Kivity .write = pl181_write, 447ca45842aSAvi Kivity .endianness = DEVICE_NATIVE_ENDIAN, 448a1bb27b1Spbrook }; 449a1bb27b1Spbrook 450624923beSPeter Maydell static void pl181_reset(DeviceState *d) 451a1bb27b1Spbrook { 452624923beSPeter Maydell pl181_state *s = DO_UPCAST(pl181_state, busdev.qdev, d); 453a1bb27b1Spbrook 454a1bb27b1Spbrook s->power = 0; 455a1bb27b1Spbrook s->cmdarg = 0; 456a1bb27b1Spbrook s->cmd = 0; 457a1bb27b1Spbrook s->datatimer = 0; 458a1bb27b1Spbrook s->datalength = 0; 459a1bb27b1Spbrook s->respcmd = 0; 460a1bb27b1Spbrook s->response[0] = 0; 461a1bb27b1Spbrook s->response[1] = 0; 462a1bb27b1Spbrook s->response[2] = 0; 463a1bb27b1Spbrook s->response[3] = 0; 464a1bb27b1Spbrook s->datatimer = 0; 465a1bb27b1Spbrook s->datalength = 0; 466a1bb27b1Spbrook s->datactrl = 0; 467a1bb27b1Spbrook s->datacnt = 0; 468a1bb27b1Spbrook s->status = 0; 4696361cdb6Spbrook s->linux_hack = 0; 470a1bb27b1Spbrook s->mask[0] = 0; 471a1bb27b1Spbrook s->mask[1] = 0; 472c31a4724SPeter Maydell 473c31a4724SPeter Maydell /* We can assume our GPIO outputs have been wired up now */ 474c31a4724SPeter Maydell sd_set_cb(s->card, s->cardstatus[0], s->cardstatus[1]); 475a1bb27b1Spbrook } 476a1bb27b1Spbrook 47781a322d4SGerd Hoffmann static int pl181_init(SysBusDevice *dev) 478a1bb27b1Spbrook { 479aa9311d8SPaul Brook pl181_state *s = FROM_SYSBUS(pl181_state, dev); 48013839974SMarkus Armbruster DriveInfo *dinfo; 481a1bb27b1Spbrook 482*29776739SPaolo Bonzini memory_region_init_io(&s->iomem, OBJECT(s), &pl181_ops, s, "pl181", 0x1000); 483750ecd44SAvi Kivity sysbus_init_mmio(dev, &s->iomem); 484aa9311d8SPaul Brook sysbus_init_irq(dev, &s->irq[0]); 485aa9311d8SPaul Brook sysbus_init_irq(dev, &s->irq[1]); 486c31a4724SPeter Maydell qdev_init_gpio_out(&s->busdev.qdev, s->cardstatus, 2); 48713839974SMarkus Armbruster dinfo = drive_get_next(IF_SD); 4886790f59dSliguang s->card = sd_init(dinfo ? dinfo->bdrv : NULL, false); 48981a322d4SGerd Hoffmann return 0; 490a1bb27b1Spbrook } 491aa9311d8SPaul Brook 492999e12bbSAnthony Liguori static void pl181_class_init(ObjectClass *klass, void *data) 493999e12bbSAnthony Liguori { 494999e12bbSAnthony Liguori SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass); 49539bffca2SAnthony Liguori DeviceClass *k = DEVICE_CLASS(klass); 496999e12bbSAnthony Liguori 497999e12bbSAnthony Liguori sdc->init = pl181_init; 49839bffca2SAnthony Liguori k->vmsd = &vmstate_pl181; 49939bffca2SAnthony Liguori k->reset = pl181_reset; 50039bffca2SAnthony Liguori k->no_user = 1; 501999e12bbSAnthony Liguori } 502999e12bbSAnthony Liguori 5038c43a6f0SAndreas Färber static const TypeInfo pl181_info = { 504999e12bbSAnthony Liguori .name = "pl181", 50539bffca2SAnthony Liguori .parent = TYPE_SYS_BUS_DEVICE, 50639bffca2SAnthony Liguori .instance_size = sizeof(pl181_state), 507999e12bbSAnthony Liguori .class_init = pl181_class_init, 508624923beSPeter Maydell }; 509624923beSPeter Maydell 51083f7d43aSAndreas Färber static void pl181_register_types(void) 511aa9311d8SPaul Brook { 51239bffca2SAnthony Liguori type_register_static(&pl181_info); 513aa9311d8SPaul Brook } 514aa9311d8SPaul Brook 51583f7d43aSAndreas Färber type_init(pl181_register_types) 516