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

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

unix.superglobalmegacorp.com

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