qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

mcf5206.c (16656B)


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