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

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: 
                     10: #include "hw.h"
                     11: #include "primecell.h"
                     12: #include "sd.h"
                     13: 
                     14: //#define DEBUG_PL181 1
                     15: 
                     16: #ifdef DEBUG_PL181
                     17: #define DPRINTF(fmt, args...) \
                     18: do { printf("pl181: " fmt , ##args); } while (0)
                     19: #else
                     20: #define DPRINTF(fmt, args...) do {} while(0)
                     21: #endif
                     22: 
                     23: #define PL181_FIFO_LEN 16
                     24: 
                     25: typedef struct {
                     26:     SDState *card;
                     27:     uint32_t base;
                     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: {
                    139:     struct sd_request_s request;
                    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;
                    185:     uint32_t value;
                    186:     int n;
                    187:     int limit;
                    188:     int is_read;
                    189: 
                    190:     is_read = (s->datactrl & PL181_DATA_DIRECTION) != 0;
                    191:     if (s->datacnt != 0 && (!is_read || sd_data_ready(s->card))
                    192:             && !s->linux_hack) {
                    193:         limit = is_read ? PL181_FIFO_LEN : 0;
                    194:         n = 0;
                    195:         value = 0;
                    196:         while (s->datacnt && s->fifo_len != limit) {
                    197:             if (is_read) {
                    198:                 value |= (uint32_t)sd_read_data(s->card) << (n * 8);
                    199:                 n++;
                    200:                 if (n == 4) {
                    201:                     pl181_fifo_push(s, value);
                    202:                     value = 0;
                    203:                     n = 0;
                    204:                 }
                    205:             } else {
                    206:                 if (n == 0) {
                    207:                     value = pl181_fifo_pop(s);
                    208:                     n = 4;
                    209:                 }
                    210:                 sd_write_data(s->card, value & 0xff);
                    211:                 value >>= 8;
                    212:                 n--;
                    213:             }
                    214:             s->datacnt--;
                    215:         }
                    216:         if (n && is_read) {
                    217:             pl181_fifo_push(s, value);
                    218:         }
                    219:     }
                    220:     s->status &= ~(PL181_STATUS_RX_FIFO | PL181_STATUS_TX_FIFO);
                    221:     if (s->datacnt == 0) {
                    222:         s->status |= PL181_STATUS_DATAEND;
                    223:         /* HACK: */
                    224:         s->status |= PL181_STATUS_DATABLOCKEND;
                    225:         DPRINTF("Transfer Complete\n");
                    226:     }
                    227:     if (s->datacnt == 0 && s->fifo_len == 0) {
                    228:         s->datactrl &= ~PL181_DATA_ENABLE;
                    229:         DPRINTF("Data engine idle\n");
                    230:     } else {
                    231:         /* Update FIFO bits.  */
                    232:         bits = PL181_STATUS_TXACTIVE | PL181_STATUS_RXACTIVE;
                    233:         if (s->fifo_len == 0) {
                    234:             bits |= PL181_STATUS_TXFIFOEMPTY;
                    235:             bits |= PL181_STATUS_RXFIFOEMPTY;
                    236:         } else {
                    237:             bits |= PL181_STATUS_TXDATAAVLBL;
                    238:             bits |= PL181_STATUS_RXDATAAVLBL;
                    239:         }
                    240:         if (s->fifo_len == 16) {
                    241:             bits |= PL181_STATUS_TXFIFOFULL;
                    242:             bits |= PL181_STATUS_RXFIFOFULL;
                    243:         }
                    244:         if (s->fifo_len <= 8) {
                    245:             bits |= PL181_STATUS_TXFIFOHALFEMPTY;
                    246:         }
                    247:         if (s->fifo_len >= 8) {
                    248:             bits |= PL181_STATUS_RXFIFOHALFFULL;
                    249:         }
                    250:         if (s->datactrl & PL181_DATA_DIRECTION) {
                    251:             bits &= PL181_STATUS_RX_FIFO;
                    252:         } else {
                    253:             bits &= PL181_STATUS_TX_FIFO;
                    254:         }
                    255:         s->status |= bits;
                    256:     }
                    257: }
                    258: 
                    259: static uint32_t pl181_read(void *opaque, target_phys_addr_t offset)
                    260: {
                    261:     pl181_state *s = (pl181_state *)opaque;
                    262:     uint32_t tmp;
                    263: 
                    264:     offset -= s->base;
                    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:
                    337:         cpu_abort (cpu_single_env, "pl181_read: Bad offset %x\n", (int)offset);
                    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:     offset -= s->base;
                    348:     switch (offset) {
                    349:     case 0x00: /* Power */
                    350:         s->power = value & 0xff;
                    351:         break;
                    352:     case 0x04: /* Clock */
                    353:         s->clock = value & 0xff;
                    354:         break;
                    355:     case 0x08: /* Argument */
                    356:         s->cmdarg = value;
                    357:         break;
                    358:     case 0x0c: /* Command */
                    359:         s->cmd = value;
                    360:         if (s->cmd & PL181_CMD_ENABLE) {
                    361:             if (s->cmd & PL181_CMD_INTERRUPT) {
                    362:                 fprintf(stderr, "pl181: Interrupt mode not implemented\n");
                    363:                 abort();
                    364:             } if (s->cmd & PL181_CMD_PENDING) {
                    365:                 fprintf(stderr, "pl181: Pending commands not implemented\n");
                    366:                 abort();
                    367:             } else {
                    368:                 pl181_send_command(s);
                    369:                 pl181_fifo_run(s);
                    370:             }
                    371:             /* The command has completed one way or the other.  */
                    372:             s->cmd &= ~PL181_CMD_ENABLE;
                    373:         }
                    374:         break;
                    375:     case 0x24: /* DataTimer */
                    376:         s->datatimer = value;
                    377:         break;
                    378:     case 0x28: /* DataLength */
                    379:         s->datalength = value & 0xffff;
                    380:         break;
                    381:     case 0x2c: /* DataCtrl */
                    382:         s->datactrl = value & 0xff;
                    383:         if (value & PL181_DATA_ENABLE) {
                    384:             s->datacnt = s->datalength;
                    385:             pl181_fifo_run(s);
                    386:         }
                    387:         break;
                    388:     case 0x38: /* Clear */
                    389:         s->status &= ~(value & 0x7ff);
                    390:         break;
                    391:     case 0x3c: /* Mask0 */
                    392:         s->mask[0] = value;
                    393:         break;
                    394:     case 0x40: /* Mask1 */
                    395:         s->mask[1] = value;
                    396:         break;
                    397:     case 0x80: case 0x84: case 0x88: case 0x8c: /* FifoData */
                    398:     case 0x90: case 0x94: case 0x98: case 0x9c:
                    399:     case 0xa0: case 0xa4: case 0xa8: case 0xac:
                    400:     case 0xb0: case 0xb4: case 0xb8: case 0xbc:
                    401:         if (s->datacnt == 0) {
                    402:             fprintf(stderr, "pl181: Unexpected FIFO write\n");
                    403:         } else {
                    404:             pl181_fifo_push(s, value);
                    405:             pl181_fifo_run(s);
                    406:         }
                    407:         break;
                    408:     default:
                    409:         cpu_abort (cpu_single_env, "pl181_write: Bad offset %x\n", (int)offset);
                    410:     }
                    411:     pl181_update(s);
                    412: }
                    413: 
                    414: static CPUReadMemoryFunc *pl181_readfn[] = {
                    415:    pl181_read,
                    416:    pl181_read,
                    417:    pl181_read
                    418: };
                    419: 
                    420: static CPUWriteMemoryFunc *pl181_writefn[] = {
                    421:    pl181_write,
                    422:    pl181_write,
                    423:    pl181_write
                    424: };
                    425: 
                    426: static void pl181_reset(void *opaque)
                    427: {
                    428:     pl181_state *s = (pl181_state *)opaque;
                    429: 
                    430:     s->power = 0;
                    431:     s->cmdarg = 0;
                    432:     s->cmd = 0;
                    433:     s->datatimer = 0;
                    434:     s->datalength = 0;
                    435:     s->respcmd = 0;
                    436:     s->response[0] = 0;
                    437:     s->response[1] = 0;
                    438:     s->response[2] = 0;
                    439:     s->response[3] = 0;
                    440:     s->datatimer = 0;
                    441:     s->datalength = 0;
                    442:     s->datactrl = 0;
                    443:     s->datacnt = 0;
                    444:     s->status = 0;
                    445:     s->linux_hack = 0;
                    446:     s->mask[0] = 0;
                    447:     s->mask[1] = 0;
                    448: }
                    449: 
                    450: void pl181_init(uint32_t base, BlockDriverState *bd,
                    451:                 qemu_irq irq0, qemu_irq irq1)
                    452: {
                    453:     int iomemtype;
                    454:     pl181_state *s;
                    455: 
                    456:     s = (pl181_state *)qemu_mallocz(sizeof(pl181_state));
                    457:     iomemtype = cpu_register_io_memory(0, pl181_readfn,
                    458:                                        pl181_writefn, s);
                    459:     cpu_register_physical_memory(base, 0x00001000, iomemtype);
                    460:     s->base = base;
                    461:     s->card = sd_init(bd, 0);
                    462:     s->irq[0] = irq0;
                    463:     s->irq[1] = irq1;
                    464:     qemu_register_reset(pl181_reset, s);
                    465:     pl181_reset(s);
                    466:     /* ??? Save/restore.  */
                    467: }

unix.superglobalmegacorp.com

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