symbian-qemu-0.9.1-12/qemu-symbian-svp/hw/mcf5206.c
changeset 1 2fb8b9db1c86
equal deleted inserted replaced
0:ffa851df0825 1:2fb8b9db1c86
       
     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 }