Annotation of qemu/hw/pl181.c, revision 1.1.1.7

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

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.