Annotation of qemu/hw/mcf5206.c, revision 1.1.1.2

1.1       root        1: /*
                      2:  * Motorola ColdFire MCF5206 SoC embedded peripheral emulation.
                      3:  *
                      4:  * Copyright (c) 2007 CodeSourcery.
                      5:  *
                      6:  * This code is licenced under the GPL
                      7:  */
                      8: #include "hw.h"
                      9: #include "mcf.h"
                     10: #include "qemu-timer.h"
                     11: #include "sysemu.h"
                     12: 
                     13: /* General purpose timer module.  */
                     14: typedef struct {
                     15:     uint16_t tmr;
                     16:     uint16_t trr;
                     17:     uint16_t tcr;
                     18:     uint16_t ter;
                     19:     ptimer_state *timer;
                     20:     qemu_irq irq;
                     21:     int irq_state;
                     22: } m5206_timer_state;
                     23: 
                     24: #define TMR_RST 0x01
                     25: #define TMR_CLK 0x06
                     26: #define TMR_FRR 0x08
                     27: #define TMR_ORI 0x10
                     28: #define TMR_OM  0x20
                     29: #define TMR_CE  0xc0
                     30: 
                     31: #define TER_CAP 0x01
                     32: #define TER_REF 0x02
                     33: 
                     34: static void m5206_timer_update(m5206_timer_state *s)
                     35: {
                     36:     if ((s->tmr & TMR_ORI) != 0 && (s->ter & TER_REF))
                     37:         qemu_irq_raise(s->irq);
                     38:     else
                     39:         qemu_irq_lower(s->irq);
                     40: }
                     41: 
                     42: static void m5206_timer_reset(m5206_timer_state *s)
                     43: {
                     44:     s->tmr = 0;
                     45:     s->trr = 0;
                     46: }
                     47: 
                     48: static void m5206_timer_recalibrate(m5206_timer_state *s)
                     49: {
                     50:     int prescale;
                     51:     int mode;
                     52: 
                     53:     ptimer_stop(s->timer);
                     54: 
                     55:     if ((s->tmr & TMR_RST) == 0)
                     56:         return;
                     57: 
                     58:     prescale = (s->tmr >> 8) + 1;
                     59:     mode = (s->tmr >> 1) & 3;
                     60:     if (mode == 2)
                     61:         prescale *= 16;
                     62: 
                     63:     if (mode == 3 || mode == 0)
                     64:         cpu_abort(cpu_single_env,
                     65:                   "m5206_timer: mode %d not implemented\n", mode);
                     66:     if ((s->tmr & TMR_FRR) == 0)
                     67:         cpu_abort(cpu_single_env,
                     68:                   "m5206_timer: free running mode not implemented\n");
                     69: 
                     70:     /* Assume 66MHz system clock.  */
                     71:     ptimer_set_freq(s->timer, 66000000 / prescale);
                     72: 
                     73:     ptimer_set_limit(s->timer, s->trr, 0);
                     74: 
                     75:     ptimer_run(s->timer, 0);
                     76: }
                     77: 
                     78: static void m5206_timer_trigger(void *opaque)
                     79: {
                     80:     m5206_timer_state *s = (m5206_timer_state *)opaque;
                     81:     s->ter |= TER_REF;
                     82:     m5206_timer_update(s);
                     83: }
                     84: 
                     85: static uint32_t m5206_timer_read(m5206_timer_state *s, uint32_t addr)
                     86: {
                     87:     switch (addr) {
                     88:     case 0:
                     89:         return s->tmr;
                     90:     case 4:
                     91:         return s->trr;
                     92:     case 8:
                     93:         return s->tcr;
                     94:     case 0xc:
                     95:         return s->trr - ptimer_get_count(s->timer);
                     96:     case 0x11:
                     97:         return s->ter;
                     98:     default:
                     99:         return 0;
                    100:     }
                    101: }
                    102: 
                    103: static void m5206_timer_write(m5206_timer_state *s, uint32_t addr, uint32_t val)
                    104: {
                    105:     switch (addr) {
                    106:     case 0:
                    107:         if ((s->tmr & TMR_RST) != 0 && (val & TMR_RST) == 0) {
                    108:             m5206_timer_reset(s);
                    109:         }
                    110:         s->tmr = val;
                    111:         m5206_timer_recalibrate(s);
                    112:         break;
                    113:     case 4:
                    114:         s->trr = val;
                    115:         m5206_timer_recalibrate(s);
                    116:         break;
                    117:     case 8:
                    118:         s->tcr = val;
                    119:         break;
                    120:     case 0xc:
                    121:         ptimer_set_count(s->timer, val);
                    122:         break;
                    123:     case 0x11:
                    124:         s->ter &= ~val;
                    125:         break;
                    126:     default:
                    127:         break;
                    128:     }
                    129:     m5206_timer_update(s);
                    130: }
                    131: 
                    132: static m5206_timer_state *m5206_timer_init(qemu_irq irq)
                    133: {
                    134:     m5206_timer_state *s;
                    135:     QEMUBH *bh;
                    136: 
                    137:     s = (m5206_timer_state *)qemu_mallocz(sizeof(m5206_timer_state));
                    138:     bh = qemu_bh_new(m5206_timer_trigger, s);
                    139:     s->timer = ptimer_init(bh);
                    140:     s->irq = irq;
                    141:     m5206_timer_reset(s);
                    142:     return s;
                    143: }
                    144: 
                    145: /* System Integration Module.  */
                    146: 
                    147: typedef struct {
                    148:     CPUState *env;
                    149:     m5206_timer_state *timer[2];
                    150:     void *uart[2];
                    151:     uint8_t scr;
                    152:     uint8_t icr[14];
                    153:     uint16_t imr; /* 1 == interrupt is masked.  */
                    154:     uint16_t ipr;
                    155:     uint8_t rsr;
                    156:     uint8_t swivr;
                    157:     uint8_t par;
                    158:     /* Include the UART vector registers here.  */
                    159:     uint8_t uivr[2];
                    160: } m5206_mbar_state;
                    161: 
                    162: /* Interrupt controller.  */
                    163: 
                    164: static int m5206_find_pending_irq(m5206_mbar_state *s)
                    165: {
                    166:     int level;
                    167:     int vector;
                    168:     uint16_t active;
                    169:     int i;
                    170: 
                    171:     level = 0;
                    172:     vector = 0;
                    173:     active = s->ipr & ~s->imr;
                    174:     if (!active)
                    175:         return 0;
                    176: 
                    177:     for (i = 1; i < 14; i++) {
                    178:         if (active & (1 << i)) {
                    179:             if ((s->icr[i] & 0x1f) > level) {
                    180:                 level = s->icr[i] & 0x1f;
                    181:                 vector = i;
                    182:             }
                    183:         }
                    184:     }
                    185: 
                    186:     if (level < 4)
                    187:         vector = 0;
                    188: 
                    189:     return vector;
                    190: }
                    191: 
                    192: static void m5206_mbar_update(m5206_mbar_state *s)
                    193: {
                    194:     int irq;
                    195:     int vector;
                    196:     int level;
                    197: 
                    198:     irq = m5206_find_pending_irq(s);
                    199:     if (irq) {
                    200:         int tmp;
                    201:         tmp = s->icr[irq];
                    202:         level = (tmp >> 2) & 7;
                    203:         if (tmp & 0x80) {
                    204:             /* Autovector.  */
                    205:             vector = 24 + level;
                    206:         } else {
                    207:             switch (irq) {
                    208:             case 8: /* SWT */
                    209:                 vector = s->swivr;
                    210:                 break;
                    211:             case 12: /* UART1 */
                    212:                 vector = s->uivr[0];
                    213:                 break;
                    214:             case 13: /* UART2 */
                    215:                 vector = s->uivr[1];
                    216:                 break;
                    217:             default:
                    218:                 /* Unknown vector.  */
                    219:                 fprintf(stderr, "Unhandled vector for IRQ %d\n", irq);
                    220:                 vector = 0xf;
                    221:                 break;
                    222:             }
                    223:         }
                    224:     } else {
                    225:         level = 0;
                    226:         vector = 0;
                    227:     }
                    228:     m68k_set_irq_level(s->env, level, vector);
                    229: }
                    230: 
                    231: static void m5206_mbar_set_irq(void *opaque, int irq, int level)
                    232: {
                    233:     m5206_mbar_state *s = (m5206_mbar_state *)opaque;
                    234:     if (level) {
                    235:         s->ipr |= 1 << irq;
                    236:     } else {
                    237:         s->ipr &= ~(1 << irq);
                    238:     }
                    239:     m5206_mbar_update(s);
                    240: }
                    241: 
                    242: /* System Integration Module.  */
                    243: 
                    244: static void m5206_mbar_reset(m5206_mbar_state *s)
                    245: {
                    246:     s->scr = 0xc0;
                    247:     s->icr[1] = 0x04;
                    248:     s->icr[2] = 0x08;
                    249:     s->icr[3] = 0x0c;
                    250:     s->icr[4] = 0x10;
                    251:     s->icr[5] = 0x14;
                    252:     s->icr[6] = 0x18;
                    253:     s->icr[7] = 0x1c;
                    254:     s->icr[8] = 0x1c;
                    255:     s->icr[9] = 0x80;
                    256:     s->icr[10] = 0x80;
                    257:     s->icr[11] = 0x80;
                    258:     s->icr[12] = 0x00;
                    259:     s->icr[13] = 0x00;
                    260:     s->imr = 0x3ffe;
                    261:     s->rsr = 0x80;
                    262:     s->swivr = 0x0f;
                    263:     s->par = 0;
                    264: }
                    265: 
                    266: static uint32_t m5206_mbar_read(m5206_mbar_state *s, uint32_t offset)
                    267: {
                    268:     if (offset >= 0x100 && offset < 0x120) {
                    269:         return m5206_timer_read(s->timer[0], offset - 0x100);
                    270:     } else if (offset >= 0x120 && offset < 0x140) {
                    271:         return m5206_timer_read(s->timer[1], offset - 0x120);
                    272:     } else if (offset >= 0x140 && offset < 0x160) {
                    273:         return mcf_uart_read(s->uart[0], offset - 0x140);
                    274:     } else if (offset >= 0x180 && offset < 0x1a0) {
                    275:         return mcf_uart_read(s->uart[1], offset - 0x180);
                    276:     }
                    277:     switch (offset) {
                    278:     case 0x03: return s->scr;
                    279:     case 0x14 ... 0x20: return s->icr[offset - 0x13];
                    280:     case 0x36: return s->imr;
                    281:     case 0x3a: return s->ipr;
                    282:     case 0x40: return s->rsr;
                    283:     case 0x41: return 0;
                    284:     case 0x42: return s->swivr;
                    285:     case 0x50:
                    286:         /* DRAM mask register.  */
                    287:         /* FIXME: currently hardcoded to 128Mb.  */
                    288:         {
                    289:             uint32_t mask = ~0;
                    290:             while (mask > ram_size)
                    291:                 mask >>= 1;
                    292:             return mask & 0x0ffe0000;
                    293:         }
                    294:     case 0x5c: return 1; /* DRAM bank 1 empty.  */
                    295:     case 0xcb: return s->par;
                    296:     case 0x170: return s->uivr[0];
                    297:     case 0x1b0: return s->uivr[1];
                    298:     }
                    299:     cpu_abort(cpu_single_env, "Bad MBAR read offset 0x%x", (int)offset);
                    300:     return 0;
                    301: }
                    302: 
                    303: static void m5206_mbar_write(m5206_mbar_state *s, uint32_t offset,
                    304:                              uint32_t value)
                    305: {
                    306:     if (offset >= 0x100 && offset < 0x120) {
                    307:         m5206_timer_write(s->timer[0], offset - 0x100, value);
                    308:         return;
                    309:     } else if (offset >= 0x120 && offset < 0x140) {
                    310:         m5206_timer_write(s->timer[1], offset - 0x120, value);
                    311:         return;
                    312:     } else if (offset >= 0x140 && offset < 0x160) {
                    313:         mcf_uart_write(s->uart[0], offset - 0x140, value);
                    314:         return;
                    315:     } else if (offset >= 0x180 && offset < 0x1a0) {
                    316:         mcf_uart_write(s->uart[1], offset - 0x180, value);
                    317:         return;
                    318:     }
                    319:     switch (offset) {
                    320:     case 0x03:
                    321:         s->scr = value;
                    322:         break;
                    323:     case 0x14 ... 0x20:
                    324:         s->icr[offset - 0x13] = value;
                    325:         m5206_mbar_update(s);
                    326:         break;
                    327:     case 0x36:
                    328:         s->imr = value;
                    329:         m5206_mbar_update(s);
                    330:         break;
                    331:     case 0x40:
                    332:         s->rsr &= ~value;
                    333:         break;
                    334:     case 0x41:
                    335:         /* TODO: implement watchdog.  */
                    336:         break;
                    337:     case 0x42:
                    338:         s->swivr = value;
                    339:         break;
                    340:     case 0xcb:
                    341:         s->par = value;
                    342:         break;
                    343:     case 0x170:
                    344:         s->uivr[0] = value;
                    345:         break;
                    346:     case 0x178: case 0x17c: case 0x1c8: case 0x1bc:
                    347:         /* Not implemented: UART Output port bits.  */
                    348:         break;
                    349:     case 0x1b0:
                    350:         s->uivr[1] = value;
                    351:         break;
                    352:     default:
                    353:         cpu_abort(cpu_single_env, "Bad MBAR write offset 0x%x", (int)offset);
                    354:         break;
                    355:     }
                    356: }
                    357: 
                    358: /* Internal peripherals use a variety of register widths.
                    359:    This lookup table allows a single routine to handle all of them.  */
                    360: static const int m5206_mbar_width[] =
                    361: {
                    362:   /* 000-040 */ 1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,  2, 2, 2, 2,
                    363:   /* 040-080 */ 1, 2, 2, 2,  4, 1, 2, 4,  1, 2, 4, 2,  2, 4, 2, 2,
                    364:   /* 080-0c0 */ 4, 2, 2, 4,  2, 2, 4, 2,  2, 4, 2, 2,  4, 2, 2, 4,
                    365:   /* 0c0-100 */ 2, 2, 1, 0,  0, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0,
                    366:   /* 100-140 */ 2, 2, 2, 2,  1, 0, 0, 0,  2, 2, 2, 2,  1, 0, 0, 0,
                    367:   /* 140-180 */ 1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,
                    368:   /* 180-1c0 */ 1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,
                    369:   /* 1c0-200 */ 1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,
                    370: };
                    371: 
                    372: static uint32_t m5206_mbar_readw(void *opaque, target_phys_addr_t offset);
                    373: static uint32_t m5206_mbar_readl(void *opaque, target_phys_addr_t offset);
                    374: 
                    375: static uint32_t m5206_mbar_readb(void *opaque, target_phys_addr_t offset)
                    376: {
                    377:     m5206_mbar_state *s = (m5206_mbar_state *)opaque;
                    378:     offset &= 0x3ff;
                    379:     if (offset > 0x200) {
                    380:         cpu_abort(cpu_single_env, "Bad MBAR read offset 0x%x", (int)offset);
                    381:     }
                    382:     if (m5206_mbar_width[offset >> 2] > 1) {
                    383:         uint16_t val;
                    384:         val = m5206_mbar_readw(opaque, offset & ~1);
                    385:         if ((offset & 1) == 0) {
                    386:             val >>= 8;
                    387:         }
                    388:         return val & 0xff;
                    389:     }
                    390:     return m5206_mbar_read(s, offset);
                    391: }
                    392: 
                    393: static uint32_t m5206_mbar_readw(void *opaque, target_phys_addr_t offset)
                    394: {
                    395:     m5206_mbar_state *s = (m5206_mbar_state *)opaque;
                    396:     int width;
                    397:     offset &= 0x3ff;
                    398:     if (offset > 0x200) {
                    399:         cpu_abort(cpu_single_env, "Bad MBAR read offset 0x%x", (int)offset);
                    400:     }
                    401:     width = m5206_mbar_width[offset >> 2];
                    402:     if (width > 2) {
                    403:         uint32_t val;
                    404:         val = m5206_mbar_readl(opaque, offset & ~3);
                    405:         if ((offset & 3) == 0)
                    406:             val >>= 16;
                    407:         return val & 0xffff;
                    408:     } else if (width < 2) {
                    409:         uint16_t val;
                    410:         val = m5206_mbar_readb(opaque, offset) << 8;
                    411:         val |= m5206_mbar_readb(opaque, offset + 1);
                    412:         return val;
                    413:     }
                    414:     return m5206_mbar_read(s, offset);
                    415: }
                    416: 
                    417: static uint32_t m5206_mbar_readl(void *opaque, target_phys_addr_t offset)
                    418: {
                    419:     m5206_mbar_state *s = (m5206_mbar_state *)opaque;
                    420:     int width;
                    421:     offset &= 0x3ff;
                    422:     if (offset > 0x200) {
                    423:         cpu_abort(cpu_single_env, "Bad MBAR read offset 0x%x", (int)offset);
                    424:     }
                    425:     width = m5206_mbar_width[offset >> 2];
                    426:     if (width < 4) {
                    427:         uint32_t val;
                    428:         val = m5206_mbar_readw(opaque, offset) << 16;
                    429:         val |= m5206_mbar_readw(opaque, offset + 2);
                    430:         return val;
                    431:     }
                    432:     return m5206_mbar_read(s, offset);
                    433: }
                    434: 
                    435: static void m5206_mbar_writew(void *opaque, target_phys_addr_t offset,
                    436:                               uint32_t value);
                    437: static void m5206_mbar_writel(void *opaque, target_phys_addr_t offset,
                    438:                               uint32_t value);
                    439: 
                    440: static void m5206_mbar_writeb(void *opaque, target_phys_addr_t offset,
                    441:                               uint32_t value)
                    442: {
                    443:     m5206_mbar_state *s = (m5206_mbar_state *)opaque;
                    444:     int width;
                    445:     offset &= 0x3ff;
                    446:     if (offset > 0x200) {
                    447:         cpu_abort(cpu_single_env, "Bad MBAR write offset 0x%x", (int)offset);
                    448:     }
                    449:     width = m5206_mbar_width[offset >> 2];
                    450:     if (width > 1) {
                    451:         uint32_t tmp;
                    452:         tmp = m5206_mbar_readw(opaque, offset & ~1);
                    453:         if (offset & 1) {
                    454:             tmp = (tmp & 0xff00) | value;
                    455:         } else {
                    456:             tmp = (tmp & 0x00ff) | (value << 8);
                    457:         }
                    458:         m5206_mbar_writew(opaque, offset & ~1, tmp);
                    459:         return;
                    460:     }
                    461:     m5206_mbar_write(s, offset, value);
                    462: }
                    463: 
                    464: static void m5206_mbar_writew(void *opaque, target_phys_addr_t offset,
                    465:                               uint32_t value)
                    466: {
                    467:     m5206_mbar_state *s = (m5206_mbar_state *)opaque;
                    468:     int width;
                    469:     offset &= 0x3ff;
                    470:     if (offset > 0x200) {
                    471:         cpu_abort(cpu_single_env, "Bad MBAR write offset 0x%x", (int)offset);
                    472:     }
                    473:     width = m5206_mbar_width[offset >> 2];
                    474:     if (width > 2) {
                    475:         uint32_t tmp;
                    476:         tmp = m5206_mbar_readl(opaque, offset & ~3);
                    477:         if (offset & 3) {
                    478:             tmp = (tmp & 0xffff0000) | value;
                    479:         } else {
                    480:             tmp = (tmp & 0x0000ffff) | (value << 16);
                    481:         }
                    482:         m5206_mbar_writel(opaque, offset & ~3, tmp);
                    483:         return;
                    484:     } else if (width < 2) {
                    485:         m5206_mbar_writeb(opaque, offset, value >> 8);
                    486:         m5206_mbar_writeb(opaque, offset + 1, value & 0xff);
                    487:         return;
                    488:     }
                    489:     m5206_mbar_write(s, offset, value);
                    490: }
                    491: 
                    492: static void m5206_mbar_writel(void *opaque, target_phys_addr_t offset,
                    493:                               uint32_t value)
                    494: {
                    495:     m5206_mbar_state *s = (m5206_mbar_state *)opaque;
                    496:     int width;
                    497:     offset &= 0x3ff;
                    498:     if (offset > 0x200) {
                    499:         cpu_abort(cpu_single_env, "Bad MBAR write offset 0x%x", (int)offset);
                    500:     }
                    501:     width = m5206_mbar_width[offset >> 2];
                    502:     if (width < 4) {
                    503:         m5206_mbar_writew(opaque, offset, value >> 16);
                    504:         m5206_mbar_writew(opaque, offset + 2, value & 0xffff);
                    505:         return;
                    506:     }
                    507:     m5206_mbar_write(s, offset, value);
                    508: }
                    509: 
                    510: static CPUReadMemoryFunc *m5206_mbar_readfn[] = {
                    511:    m5206_mbar_readb,
                    512:    m5206_mbar_readw,
                    513:    m5206_mbar_readl
                    514: };
                    515: 
                    516: static CPUWriteMemoryFunc *m5206_mbar_writefn[] = {
                    517:    m5206_mbar_writeb,
                    518:    m5206_mbar_writew,
                    519:    m5206_mbar_writel
                    520: };
                    521: 
                    522: qemu_irq *mcf5206_init(uint32_t base, CPUState *env)
                    523: {
                    524:     m5206_mbar_state *s;
                    525:     qemu_irq *pic;
                    526:     int iomemtype;
                    527: 
                    528:     s = (m5206_mbar_state *)qemu_mallocz(sizeof(m5206_mbar_state));
                    529:     iomemtype = cpu_register_io_memory(0, m5206_mbar_readfn,
                    530:                                        m5206_mbar_writefn, s);
                    531:     cpu_register_physical_memory(base, 0x00001000, iomemtype);
                    532: 
                    533:     pic = qemu_allocate_irqs(m5206_mbar_set_irq, s, 14);
                    534:     s->timer[0] = m5206_timer_init(pic[9]);
                    535:     s->timer[1] = m5206_timer_init(pic[10]);
                    536:     s->uart[0] = mcf_uart_init(pic[12], serial_hds[0]);
                    537:     s->uart[1] = mcf_uart_init(pic[13], serial_hds[1]);
                    538:     s->env = env;
                    539: 
                    540:     m5206_mbar_reset(s);
                    541:     return pic;
                    542: }

unix.superglobalmegacorp.com

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