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

1.1       root        1: /* 
                      2:  * ARM PrimeCell Timer modules.
                      3:  *
                      4:  * Copyright (c) 2005-2006 CodeSourcery.
                      5:  * Written by Paul Brook
                      6:  *
                      7:  * This code is licenced under the GPL.
                      8:  */
                      9: 
                     10: #include "vl.h"
                     11: #include "arm_pic.h"
                     12: 
                     13: /* Common timer implementation.  */
                     14: 
                     15: #define TIMER_CTRL_ONESHOT      (1 << 0)
                     16: #define TIMER_CTRL_32BIT        (1 << 1)
                     17: #define TIMER_CTRL_DIV1         (0 << 2)
                     18: #define TIMER_CTRL_DIV16        (1 << 2)
                     19: #define TIMER_CTRL_DIV256       (2 << 2)
                     20: #define TIMER_CTRL_IE           (1 << 5)
                     21: #define TIMER_CTRL_PERIODIC     (1 << 6)
                     22: #define TIMER_CTRL_ENABLE       (1 << 7)
                     23: 
                     24: typedef struct {
                     25:     int64_t next_time;
                     26:     int64_t expires;
                     27:     int64_t loaded;
                     28:     QEMUTimer *timer;
                     29:     uint32_t control;
                     30:     uint32_t count;
                     31:     uint32_t limit;
                     32:     int raw_freq;
                     33:     int freq;
                     34:     int int_level;
                     35:     void *pic;
                     36:     int irq;
                     37: } arm_timer_state;
                     38: 
                     39: /* Calculate the new expiry time of the given timer.  */
                     40: 
                     41: static void arm_timer_reload(arm_timer_state *s)
                     42: {
                     43:     int64_t delay;
                     44: 
                     45:     s->loaded = s->expires;
                     46:     delay = muldiv64(s->count, ticks_per_sec, s->freq);
                     47:     if (delay == 0)
                     48:         delay = 1;
                     49:     s->expires += delay;
                     50: }
                     51: 
                     52: /* Check all active timers, and schedule the next timer interrupt.  */
                     53: 
                     54: static void arm_timer_update(arm_timer_state *s, int64_t now)
                     55: {
                     56:     int64_t next;
                     57: 
                     58:     /* Ignore disabled timers.  */
                     59:     if ((s->control & TIMER_CTRL_ENABLE) == 0)
                     60:         return;
                     61:     /* Ignore expired one-shot timers.  */
                     62:     if (s->count == 0 && (s->control & TIMER_CTRL_ONESHOT))
                     63:         return;
                     64:     if (s->expires - now <= 0) {
                     65:         /* Timer has expired.  */
                     66:         s->int_level = 1;
                     67:         if (s->control & TIMER_CTRL_ONESHOT) {
                     68:             /* One-shot.  */
                     69:             s->count = 0;
                     70:         } else {
                     71:             if ((s->control & TIMER_CTRL_PERIODIC) == 0) {
                     72:                 /* Free running.  */
                     73:                 if (s->control & TIMER_CTRL_32BIT)
                     74:                     s->count = 0xffffffff;
                     75:                 else
                     76:                     s->count = 0xffff;
                     77:             } else {
                     78:                   /* Periodic.  */
                     79:                   s->count = s->limit;
                     80:             }
                     81:         }
                     82:     }
                     83:     while (s->expires - now <= 0) {
                     84:         arm_timer_reload(s);
                     85:     }
                     86:     /* Update interrupts.  */
                     87:     if (s->int_level && (s->control & TIMER_CTRL_IE)) {
                     88:         pic_set_irq_new(s->pic, s->irq, 1);
                     89:     } else {
                     90:         pic_set_irq_new(s->pic, s->irq, 0);
                     91:     }
                     92: 
                     93:     next = now;
                     94:     if (next - s->expires < 0)
                     95:         next = s->expires;
                     96: 
                     97:     /* Schedule the next timer interrupt.  */
                     98:     if (next == now) {
                     99:         qemu_del_timer(s->timer);
                    100:         s->next_time = 0;
                    101:     } else if (next != s->next_time) {
                    102:         qemu_mod_timer(s->timer, next);
                    103:         s->next_time = next;
                    104:     }
                    105: }
                    106: 
                    107: /* Return the current value of the timer.  */
                    108: static uint32_t arm_timer_getcount(arm_timer_state *s, int64_t now)
                    109: {
1.1.1.2 ! root      110:     int64_t left;
1.1       root      111:     int64_t period;
                    112: 
                    113:     if (s->count == 0)
                    114:         return 0;
                    115:     if ((s->control & TIMER_CTRL_ENABLE) == 0)
                    116:         return s->count;
1.1.1.2 ! root      117:     left = s->expires - now;
1.1       root      118:     period = s->expires - s->loaded;
                    119:     /* If the timer should have expired then return 0.  This can happen
                    120:        when the host timer signal doesnt occur immediately.  It's better to
                    121:        have a timer appear to sit at zero for a while than have it wrap
                    122:        around before the guest interrupt is raised.  */
                    123:     /* ??? Could we trigger the interrupt here?  */
1.1.1.2 ! root      124:     if (left < 0)
1.1       root      125:         return 0;
                    126:     /* We need to calculate count * elapsed / period without overfowing.
                    127:        Scale both elapsed and period so they fit in a 32-bit int.  */
                    128:     while (period != (int32_t)period) {
                    129:         period >>= 1;
1.1.1.2 ! root      130:         left >>= 1;
1.1       root      131:     }
1.1.1.2 ! root      132:     return ((uint64_t)s->count * (uint64_t)(int32_t)left)
1.1       root      133:             / (int32_t)period;
                    134: }
                    135: 
                    136: uint32_t arm_timer_read(void *opaque, target_phys_addr_t offset)
                    137: {
                    138:     arm_timer_state *s = (arm_timer_state *)opaque;
                    139: 
                    140:     switch (offset >> 2) {
                    141:     case 0: /* TimerLoad */
                    142:     case 6: /* TimerBGLoad */
                    143:         return s->limit;
                    144:     case 1: /* TimerValue */
                    145:         return arm_timer_getcount(s, qemu_get_clock(vm_clock));
                    146:     case 2: /* TimerControl */
                    147:         return s->control;
                    148:     case 4: /* TimerRIS */
                    149:         return s->int_level;
                    150:     case 5: /* TimerMIS */
                    151:         if ((s->control & TIMER_CTRL_IE) == 0)
                    152:             return 0;
                    153:         return s->int_level;
                    154:     default:
                    155:         cpu_abort (cpu_single_env, "arm_timer_read: Bad offset %x\n", offset);
                    156:         return 0;
                    157:     }
                    158: }
                    159: 
                    160: static void arm_timer_write(void *opaque, target_phys_addr_t offset,
                    161:                             uint32_t value)
                    162: {
                    163:     arm_timer_state *s = (arm_timer_state *)opaque;
                    164:     int64_t now;
                    165: 
                    166:     now = qemu_get_clock(vm_clock);
                    167:     switch (offset >> 2) {
                    168:     case 0: /* TimerLoad */
                    169:         s->limit = value;
                    170:         s->count = value;
                    171:         s->expires = now;
                    172:         arm_timer_reload(s);
                    173:         break;
                    174:     case 1: /* TimerValue */
                    175:         /* ??? Linux seems to want to write to this readonly register.
                    176:            Ignore it.  */
                    177:         break;
                    178:     case 2: /* TimerControl */
                    179:         if (s->control & TIMER_CTRL_ENABLE) {
                    180:             /* Pause the timer if it is running.  This may cause some
                    181:                inaccuracy dure to rounding, but avoids a whole lot of other
                    182:                messyness.  */
                    183:             s->count = arm_timer_getcount(s, now);
                    184:         }
                    185:         s->control = value;
                    186:         s->freq = s->raw_freq;
                    187:         /* ??? Need to recalculate expiry time after changing divisor.  */
                    188:         switch ((value >> 2) & 3) {
                    189:         case 1: s->freq >>= 4; break;
                    190:         case 2: s->freq >>= 8; break;
                    191:         }
                    192:         if (s->control & TIMER_CTRL_ENABLE) {
                    193:             /* Restart the timer if still enabled.  */
                    194:             s->expires = now;
                    195:             arm_timer_reload(s);
                    196:         }
                    197:         break;
                    198:     case 3: /* TimerIntClr */
                    199:         s->int_level = 0;
                    200:         break;
                    201:     case 6: /* TimerBGLoad */
                    202:         s->limit = value;
                    203:         break;
                    204:     default:
                    205:         cpu_abort (cpu_single_env, "arm_timer_write: Bad offset %x\n", offset);
                    206:     }
                    207:     arm_timer_update(s, now);
                    208: }
                    209: 
                    210: static void arm_timer_tick(void *opaque)
                    211: {
                    212:     int64_t now;
                    213: 
                    214:     now = qemu_get_clock(vm_clock);
                    215:     arm_timer_update((arm_timer_state *)opaque, now);
                    216: }
                    217: 
                    218: static void *arm_timer_init(uint32_t freq, void *pic, int irq)
                    219: {
                    220:     arm_timer_state *s;
                    221: 
                    222:     s = (arm_timer_state *)qemu_mallocz(sizeof(arm_timer_state));
                    223:     s->pic = pic;
                    224:     s->irq = irq;
                    225:     s->raw_freq = s->freq = 1000000;
                    226:     s->control = TIMER_CTRL_IE;
                    227:     s->count = 0xffffffff;
                    228: 
                    229:     s->timer = qemu_new_timer(vm_clock, arm_timer_tick, s);
                    230:     /* ??? Save/restore.  */
                    231:     return s;
                    232: }
                    233: 
                    234: /* ARM PrimeCell SP804 dual timer module.
                    235:    Docs for this device don't seem to be publicly available.  This
                    236:    implementation is based on gueswork, the linux kernel sources and the
                    237:    Integrator/CP timer modules.  */
                    238: 
                    239: typedef struct {
                    240:     /* Include a pseudo-PIC device to merge the two interrupt sources.  */
                    241:     arm_pic_handler handler;
                    242:     void *timer[2];
                    243:     int level[2];
                    244:     uint32_t base;
                    245:     /* The output PIC device.  */
                    246:     void *pic;
                    247:     int irq;
                    248: } sp804_state;
                    249: 
                    250: static void sp804_set_irq(void *opaque, int irq, int level)
                    251: {
                    252:     sp804_state *s = (sp804_state *)opaque;
                    253: 
                    254:     s->level[irq] = level;
                    255:     pic_set_irq_new(s->pic, s->irq, s->level[0] || s->level[1]);
                    256: }
                    257: 
                    258: static uint32_t sp804_read(void *opaque, target_phys_addr_t offset)
                    259: {
                    260:     sp804_state *s = (sp804_state *)opaque;
                    261: 
                    262:     /* ??? Don't know the PrimeCell ID for this device.  */
                    263:     offset -= s->base;
                    264:     if (offset < 0x20) {
                    265:         return arm_timer_read(s->timer[0], offset);
                    266:     } else {
                    267:         return arm_timer_read(s->timer[1], offset - 0x20);
                    268:     }
                    269: }
                    270: 
                    271: static void sp804_write(void *opaque, target_phys_addr_t offset,
                    272:                         uint32_t value)
                    273: {
                    274:     sp804_state *s = (sp804_state *)opaque;
                    275: 
                    276:     offset -= s->base;
                    277:     if (offset < 0x20) {
                    278:         arm_timer_write(s->timer[0], offset, value);
                    279:     } else {
                    280:         arm_timer_write(s->timer[1], offset - 0x20, value);
                    281:     }
                    282: }
                    283: 
                    284: static CPUReadMemoryFunc *sp804_readfn[] = {
                    285:    sp804_read,
                    286:    sp804_read,
                    287:    sp804_read
                    288: };
                    289: 
                    290: static CPUWriteMemoryFunc *sp804_writefn[] = {
                    291:    sp804_write,
                    292:    sp804_write,
                    293:    sp804_write
                    294: };
                    295: 
                    296: void sp804_init(uint32_t base, void *pic, int irq)
                    297: {
                    298:     int iomemtype;
                    299:     sp804_state *s;
                    300: 
                    301:     s = (sp804_state *)qemu_mallocz(sizeof(sp804_state));
                    302:     s->handler = sp804_set_irq;
                    303:     s->base = base;
                    304:     s->pic = pic;
                    305:     s->irq = irq;
                    306:     /* ??? The timers are actually configurable between 32kHz and 1MHz, but
                    307:        we don't implement that.  */
                    308:     s->timer[0] = arm_timer_init(1000000, s, 0);
                    309:     s->timer[1] = arm_timer_init(1000000, s, 1);
                    310:     iomemtype = cpu_register_io_memory(0, sp804_readfn,
                    311:                                        sp804_writefn, s);
                    312:     cpu_register_physical_memory(base, 0x00000fff, iomemtype);
                    313:     /* ??? Save/restore.  */
                    314: }
                    315: 
                    316: 
                    317: /* Integrator/CP timer module.  */
                    318: 
                    319: typedef struct {
                    320:     void *timer[3];
                    321:     uint32_t base;
                    322: } icp_pit_state;
                    323: 
                    324: static uint32_t icp_pit_read(void *opaque, target_phys_addr_t offset)
                    325: {
                    326:     icp_pit_state *s = (icp_pit_state *)opaque;
                    327:     int n;
                    328: 
                    329:     /* ??? Don't know the PrimeCell ID for this device.  */
                    330:     offset -= s->base;
                    331:     n = offset >> 8;
                    332:     if (n > 3)
                    333:         cpu_abort(cpu_single_env, "sp804_read: Bad timer %d\n", n);
                    334: 
                    335:     return arm_timer_read(s->timer[n], offset & 0xff);
                    336: }
                    337: 
                    338: static void icp_pit_write(void *opaque, target_phys_addr_t offset,
                    339:                           uint32_t value)
                    340: {
                    341:     icp_pit_state *s = (icp_pit_state *)opaque;
                    342:     int n;
                    343: 
                    344:     offset -= s->base;
                    345:     n = offset >> 8;
                    346:     if (n > 3)
                    347:         cpu_abort(cpu_single_env, "sp804_write: Bad timer %d\n", n);
                    348: 
                    349:     arm_timer_write(s->timer[n], offset & 0xff, value);
                    350: }
                    351: 
                    352: 
                    353: static CPUReadMemoryFunc *icp_pit_readfn[] = {
                    354:    icp_pit_read,
                    355:    icp_pit_read,
                    356:    icp_pit_read
                    357: };
                    358: 
                    359: static CPUWriteMemoryFunc *icp_pit_writefn[] = {
                    360:    icp_pit_write,
                    361:    icp_pit_write,
                    362:    icp_pit_write
                    363: };
                    364: 
                    365: void icp_pit_init(uint32_t base, void *pic, int irq)
                    366: {
                    367:     int iomemtype;
                    368:     icp_pit_state *s;
                    369: 
                    370:     s = (icp_pit_state *)qemu_mallocz(sizeof(icp_pit_state));
                    371:     s->base = base;
                    372:     /* Timer 0 runs at the system clock speed (40MHz).  */
                    373:     s->timer[0] = arm_timer_init(40000000, pic, irq);
                    374:     /* The other two timers run at 1MHz.  */
                    375:     s->timer[1] = arm_timer_init(1000000, pic, irq + 1);
                    376:     s->timer[2] = arm_timer_init(1000000, pic, irq + 2);
                    377: 
                    378:     iomemtype = cpu_register_io_memory(0, icp_pit_readfn,
                    379:                                        icp_pit_writefn, s);
                    380:     cpu_register_physical_memory(base, 0x00000fff, iomemtype);
                    381:     /* ??? Save/restore.  */
                    382: }
                    383: 

unix.superglobalmegacorp.com