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

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