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

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

unix.superglobalmegacorp.com

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