Annotation of qemu/hw/pxa2xx_timer.c, revision 1.1

1.1     ! root        1: /*
        !             2:  * Intel XScale PXA255/270 OS Timers.
        !             3:  *
        !             4:  * Copyright (c) 2006 Openedhand Ltd.
        !             5:  * Copyright (c) 2006 Thorsten Zitterell
        !             6:  *
        !             7:  * This code is licenced under the GPL.
        !             8:  */
        !             9: 
        !            10: #include "hw.h"
        !            11: #include "qemu-timer.h"
        !            12: #include "sysemu.h"
        !            13: #include "pxa.h"
        !            14: 
        !            15: #define OSMR0  0x00
        !            16: #define OSMR1  0x04
        !            17: #define OSMR2  0x08
        !            18: #define OSMR3  0x0c
        !            19: #define OSMR4  0x80
        !            20: #define OSMR5  0x84
        !            21: #define OSMR6  0x88
        !            22: #define OSMR7  0x8c
        !            23: #define OSMR8  0x90
        !            24: #define OSMR9  0x94
        !            25: #define OSMR10 0x98
        !            26: #define OSMR11 0x9c
        !            27: #define OSCR   0x10    /* OS Timer Count */
        !            28: #define OSCR4  0x40
        !            29: #define OSCR5  0x44
        !            30: #define OSCR6  0x48
        !            31: #define OSCR7  0x4c
        !            32: #define OSCR8  0x50
        !            33: #define OSCR9  0x54
        !            34: #define OSCR10 0x58
        !            35: #define OSCR11 0x5c
        !            36: #define OSSR   0x14    /* Timer status register */
        !            37: #define OWER   0x18
        !            38: #define OIER   0x1c    /* Interrupt enable register  3-0 to E3-E0 */
        !            39: #define OMCR4  0xc0    /* OS Match Control registers */
        !            40: #define OMCR5  0xc4
        !            41: #define OMCR6  0xc8
        !            42: #define OMCR7  0xcc
        !            43: #define OMCR8  0xd0
        !            44: #define OMCR9  0xd4
        !            45: #define OMCR10 0xd8
        !            46: #define OMCR11 0xdc
        !            47: #define OSNR   0x20
        !            48: 
        !            49: #define PXA25X_FREQ    3686400 /* 3.6864 MHz */
        !            50: #define PXA27X_FREQ    3250000 /* 3.25 MHz */
        !            51: 
        !            52: static int pxa2xx_timer4_freq[8] = {
        !            53:     [0] = 0,
        !            54:     [1] = 32768,
        !            55:     [2] = 1000,
        !            56:     [3] = 1,
        !            57:     [4] = 1000000,
        !            58:     /* [5] is the "Externally supplied clock".  Assign if necessary.  */
        !            59:     [5 ... 7] = 0,
        !            60: };
        !            61: 
        !            62: struct pxa2xx_timer0_s {
        !            63:     uint32_t value;
        !            64:     int level;
        !            65:     qemu_irq irq;
        !            66:     QEMUTimer *qtimer;
        !            67:     int num;
        !            68:     void *info;
        !            69: };
        !            70: 
        !            71: struct pxa2xx_timer4_s {
        !            72:     struct pxa2xx_timer0_s tm;
        !            73:     int32_t oldclock;
        !            74:     int32_t clock;
        !            75:     uint64_t lastload;
        !            76:     uint32_t freq;
        !            77:     uint32_t control;
        !            78: };
        !            79: 
        !            80: typedef struct {
        !            81:     target_phys_addr_t base;
        !            82:     int32_t clock;
        !            83:     int32_t oldclock;
        !            84:     uint64_t lastload;
        !            85:     uint32_t freq;
        !            86:     struct pxa2xx_timer0_s timer[4];
        !            87:     struct pxa2xx_timer4_s *tm4;
        !            88:     uint32_t events;
        !            89:     uint32_t irq_enabled;
        !            90:     uint32_t reset3;
        !            91:     uint32_t snapshot;
        !            92: } pxa2xx_timer_info;
        !            93: 
        !            94: static void pxa2xx_timer_update(void *opaque, uint64_t now_qemu)
        !            95: {
        !            96:     pxa2xx_timer_info *s = (pxa2xx_timer_info *) opaque;
        !            97:     int i;
        !            98:     uint32_t now_vm;
        !            99:     uint64_t new_qemu;
        !           100: 
        !           101:     now_vm = s->clock +
        !           102:             muldiv64(now_qemu - s->lastload, s->freq, ticks_per_sec);
        !           103: 
        !           104:     for (i = 0; i < 4; i ++) {
        !           105:         new_qemu = now_qemu + muldiv64((uint32_t) (s->timer[i].value - now_vm),
        !           106:                         ticks_per_sec, s->freq);
        !           107:         qemu_mod_timer(s->timer[i].qtimer, new_qemu);
        !           108:     }
        !           109: }
        !           110: 
        !           111: static void pxa2xx_timer_update4(void *opaque, uint64_t now_qemu, int n)
        !           112: {
        !           113:     pxa2xx_timer_info *s = (pxa2xx_timer_info *) opaque;
        !           114:     uint32_t now_vm;
        !           115:     uint64_t new_qemu;
        !           116:     static const int counters[8] = { 0, 0, 0, 0, 4, 4, 6, 6 };
        !           117:     int counter;
        !           118: 
        !           119:     if (s->tm4[n].control & (1 << 7))
        !           120:         counter = n;
        !           121:     else
        !           122:         counter = counters[n];
        !           123: 
        !           124:     if (!s->tm4[counter].freq) {
        !           125:         qemu_del_timer(s->tm4[n].tm.qtimer);
        !           126:         return;
        !           127:     }
        !           128: 
        !           129:     now_vm = s->tm4[counter].clock + muldiv64(now_qemu -
        !           130:                     s->tm4[counter].lastload,
        !           131:                     s->tm4[counter].freq, ticks_per_sec);
        !           132: 
        !           133:     new_qemu = now_qemu + muldiv64((uint32_t) (s->tm4[n].tm.value - now_vm),
        !           134:                     ticks_per_sec, s->tm4[counter].freq);
        !           135:     qemu_mod_timer(s->tm4[n].tm.qtimer, new_qemu);
        !           136: }
        !           137: 
        !           138: static uint32_t pxa2xx_timer_read(void *opaque, target_phys_addr_t offset)
        !           139: {
        !           140:     pxa2xx_timer_info *s = (pxa2xx_timer_info *) opaque;
        !           141:     int tm = 0;
        !           142: 
        !           143:     offset -= s->base;
        !           144: 
        !           145:     switch (offset) {
        !           146:     case OSMR3:  tm ++;
        !           147:     case OSMR2:  tm ++;
        !           148:     case OSMR1:  tm ++;
        !           149:     case OSMR0:
        !           150:         return s->timer[tm].value;
        !           151:     case OSMR11: tm ++;
        !           152:     case OSMR10: tm ++;
        !           153:     case OSMR9:  tm ++;
        !           154:     case OSMR8:  tm ++;
        !           155:     case OSMR7:  tm ++;
        !           156:     case OSMR6:  tm ++;
        !           157:     case OSMR5:  tm ++;
        !           158:     case OSMR4:
        !           159:         if (!s->tm4)
        !           160:             goto badreg;
        !           161:         return s->tm4[tm].tm.value;
        !           162:     case OSCR:
        !           163:         return s->clock + muldiv64(qemu_get_clock(vm_clock) -
        !           164:                         s->lastload, s->freq, ticks_per_sec);
        !           165:     case OSCR11: tm ++;
        !           166:     case OSCR10: tm ++;
        !           167:     case OSCR9:  tm ++;
        !           168:     case OSCR8:  tm ++;
        !           169:     case OSCR7:  tm ++;
        !           170:     case OSCR6:  tm ++;
        !           171:     case OSCR5:  tm ++;
        !           172:     case OSCR4:
        !           173:         if (!s->tm4)
        !           174:             goto badreg;
        !           175: 
        !           176:         if ((tm == 9 - 4 || tm == 11 - 4) && (s->tm4[tm].control & (1 << 9))) {
        !           177:             if (s->tm4[tm - 1].freq)
        !           178:                 s->snapshot = s->tm4[tm - 1].clock + muldiv64(
        !           179:                                 qemu_get_clock(vm_clock) -
        !           180:                                 s->tm4[tm - 1].lastload,
        !           181:                                 s->tm4[tm - 1].freq, ticks_per_sec);
        !           182:             else
        !           183:                 s->snapshot = s->tm4[tm - 1].clock;
        !           184:         }
        !           185: 
        !           186:         if (!s->tm4[tm].freq)
        !           187:             return s->tm4[tm].clock;
        !           188:         return s->tm4[tm].clock + muldiv64(qemu_get_clock(vm_clock) -
        !           189:                         s->tm4[tm].lastload, s->tm4[tm].freq, ticks_per_sec);
        !           190:     case OIER:
        !           191:         return s->irq_enabled;
        !           192:     case OSSR: /* Status register */
        !           193:         return s->events;
        !           194:     case OWER:
        !           195:         return s->reset3;
        !           196:     case OMCR11: tm ++;
        !           197:     case OMCR10: tm ++;
        !           198:     case OMCR9:  tm ++;
        !           199:     case OMCR8:  tm ++;
        !           200:     case OMCR7:  tm ++;
        !           201:     case OMCR6:  tm ++;
        !           202:     case OMCR5:  tm ++;
        !           203:     case OMCR4:
        !           204:         if (!s->tm4)
        !           205:             goto badreg;
        !           206:         return s->tm4[tm].control;
        !           207:     case OSNR:
        !           208:         return s->snapshot;
        !           209:     default:
        !           210:     badreg:
        !           211:         cpu_abort(cpu_single_env, "pxa2xx_timer_read: Bad offset "
        !           212:                         REG_FMT "\n", offset);
        !           213:     }
        !           214: 
        !           215:     return 0;
        !           216: }
        !           217: 
        !           218: static void pxa2xx_timer_write(void *opaque, target_phys_addr_t offset,
        !           219:                 uint32_t value)
        !           220: {
        !           221:     int i, tm = 0;
        !           222:     pxa2xx_timer_info *s = (pxa2xx_timer_info *) opaque;
        !           223: 
        !           224:     offset -= s->base;
        !           225: 
        !           226:     switch (offset) {
        !           227:     case OSMR3:  tm ++;
        !           228:     case OSMR2:  tm ++;
        !           229:     case OSMR1:  tm ++;
        !           230:     case OSMR0:
        !           231:         s->timer[tm].value = value;
        !           232:         pxa2xx_timer_update(s, qemu_get_clock(vm_clock));
        !           233:         break;
        !           234:     case OSMR11: tm ++;
        !           235:     case OSMR10: tm ++;
        !           236:     case OSMR9:  tm ++;
        !           237:     case OSMR8:  tm ++;
        !           238:     case OSMR7:  tm ++;
        !           239:     case OSMR6:  tm ++;
        !           240:     case OSMR5:  tm ++;
        !           241:     case OSMR4:
        !           242:         if (!s->tm4)
        !           243:             goto badreg;
        !           244:         s->tm4[tm].tm.value = value;
        !           245:         pxa2xx_timer_update4(s, qemu_get_clock(vm_clock), tm);
        !           246:         break;
        !           247:     case OSCR:
        !           248:         s->oldclock = s->clock;
        !           249:         s->lastload = qemu_get_clock(vm_clock);
        !           250:         s->clock = value;
        !           251:         pxa2xx_timer_update(s, s->lastload);
        !           252:         break;
        !           253:     case OSCR11: tm ++;
        !           254:     case OSCR10: tm ++;
        !           255:     case OSCR9:  tm ++;
        !           256:     case OSCR8:  tm ++;
        !           257:     case OSCR7:  tm ++;
        !           258:     case OSCR6:  tm ++;
        !           259:     case OSCR5:  tm ++;
        !           260:     case OSCR4:
        !           261:         if (!s->tm4)
        !           262:             goto badreg;
        !           263:         s->tm4[tm].oldclock = s->tm4[tm].clock;
        !           264:         s->tm4[tm].lastload = qemu_get_clock(vm_clock);
        !           265:         s->tm4[tm].clock = value;
        !           266:         pxa2xx_timer_update4(s, s->tm4[tm].lastload, tm);
        !           267:         break;
        !           268:     case OIER:
        !           269:         s->irq_enabled = value & 0xfff;
        !           270:         break;
        !           271:     case OSSR: /* Status register */
        !           272:         s->events &= ~value;
        !           273:         for (i = 0; i < 4; i ++, value >>= 1) {
        !           274:             if (s->timer[i].level && (value & 1)) {
        !           275:                 s->timer[i].level = 0;
        !           276:                 qemu_irq_lower(s->timer[i].irq);
        !           277:             }
        !           278:         }
        !           279:         if (s->tm4) {
        !           280:             for (i = 0; i < 8; i ++, value >>= 1)
        !           281:                 if (s->tm4[i].tm.level && (value & 1))
        !           282:                     s->tm4[i].tm.level = 0;
        !           283:             if (!(s->events & 0xff0))
        !           284:                 qemu_irq_lower(s->tm4->tm.irq);
        !           285:         }
        !           286:         break;
        !           287:     case OWER: /* XXX: Reset on OSMR3 match? */
        !           288:         s->reset3 = value;
        !           289:         break;
        !           290:     case OMCR7:  tm ++;
        !           291:     case OMCR6:  tm ++;
        !           292:     case OMCR5:  tm ++;
        !           293:     case OMCR4:
        !           294:         if (!s->tm4)
        !           295:             goto badreg;
        !           296:         s->tm4[tm].control = value & 0x0ff;
        !           297:         /* XXX Stop if running (shouldn't happen) */
        !           298:         if ((value & (1 << 7)) || tm == 0)
        !           299:             s->tm4[tm].freq = pxa2xx_timer4_freq[value & 7];
        !           300:         else {
        !           301:             s->tm4[tm].freq = 0;
        !           302:             pxa2xx_timer_update4(s, qemu_get_clock(vm_clock), tm);
        !           303:         }
        !           304:         break;
        !           305:     case OMCR11: tm ++;
        !           306:     case OMCR10: tm ++;
        !           307:     case OMCR9:  tm ++;
        !           308:     case OMCR8:  tm += 4;
        !           309:         if (!s->tm4)
        !           310:             goto badreg;
        !           311:         s->tm4[tm].control = value & 0x3ff;
        !           312:         /* XXX Stop if running (shouldn't happen) */
        !           313:         if ((value & (1 << 7)) || !(tm & 1))
        !           314:             s->tm4[tm].freq =
        !           315:                     pxa2xx_timer4_freq[(value & (1 << 8)) ?  0 : (value & 7)];
        !           316:         else {
        !           317:             s->tm4[tm].freq = 0;
        !           318:             pxa2xx_timer_update4(s, qemu_get_clock(vm_clock), tm);
        !           319:         }
        !           320:         break;
        !           321:     default:
        !           322:     badreg:
        !           323:         cpu_abort(cpu_single_env, "pxa2xx_timer_write: Bad offset "
        !           324:                         REG_FMT "\n", offset);
        !           325:     }
        !           326: }
        !           327: 
        !           328: static CPUReadMemoryFunc *pxa2xx_timer_readfn[] = {
        !           329:     pxa2xx_timer_read,
        !           330:     pxa2xx_timer_read,
        !           331:     pxa2xx_timer_read,
        !           332: };
        !           333: 
        !           334: static CPUWriteMemoryFunc *pxa2xx_timer_writefn[] = {
        !           335:     pxa2xx_timer_write,
        !           336:     pxa2xx_timer_write,
        !           337:     pxa2xx_timer_write,
        !           338: };
        !           339: 
        !           340: static void pxa2xx_timer_tick(void *opaque)
        !           341: {
        !           342:     struct pxa2xx_timer0_s *t = (struct pxa2xx_timer0_s *) opaque;
        !           343:     pxa2xx_timer_info *i = (pxa2xx_timer_info *) t->info;
        !           344: 
        !           345:     if (i->irq_enabled & (1 << t->num)) {
        !           346:         t->level = 1;
        !           347:         i->events |= 1 << t->num;
        !           348:         qemu_irq_raise(t->irq);
        !           349:     }
        !           350: 
        !           351:     if (t->num == 3)
        !           352:         if (i->reset3 & 1) {
        !           353:             i->reset3 = 0;
        !           354:             qemu_system_reset_request();
        !           355:         }
        !           356: }
        !           357: 
        !           358: static void pxa2xx_timer_tick4(void *opaque)
        !           359: {
        !           360:     struct pxa2xx_timer4_s *t = (struct pxa2xx_timer4_s *) opaque;
        !           361:     pxa2xx_timer_info *i = (pxa2xx_timer_info *) t->tm.info;
        !           362: 
        !           363:     pxa2xx_timer_tick(&t->tm);
        !           364:     if (t->control & (1 << 3))
        !           365:         t->clock = 0;
        !           366:     if (t->control & (1 << 6))
        !           367:         pxa2xx_timer_update4(i, qemu_get_clock(vm_clock), t->tm.num - 4);
        !           368: }
        !           369: 
        !           370: static void pxa2xx_timer_save(QEMUFile *f, void *opaque)
        !           371: {
        !           372:     pxa2xx_timer_info *s = (pxa2xx_timer_info *) opaque;
        !           373:     int i;
        !           374: 
        !           375:     qemu_put_be32s(f, &s->clock);
        !           376:     qemu_put_be32s(f, &s->oldclock);
        !           377:     qemu_put_be64s(f, &s->lastload);
        !           378: 
        !           379:     for (i = 0; i < 4; i ++) {
        !           380:         qemu_put_be32s(f, &s->timer[i].value);
        !           381:         qemu_put_be32(f, s->timer[i].level);
        !           382:     }
        !           383:     if (s->tm4)
        !           384:         for (i = 0; i < 8; i ++) {
        !           385:             qemu_put_be32s(f, &s->tm4[i].tm.value);
        !           386:             qemu_put_be32(f, s->tm4[i].tm.level);
        !           387:             qemu_put_be32s(f, &s->tm4[i].oldclock);
        !           388:             qemu_put_be32s(f, &s->tm4[i].clock);
        !           389:             qemu_put_be64s(f, &s->tm4[i].lastload);
        !           390:             qemu_put_be32s(f, &s->tm4[i].freq);
        !           391:             qemu_put_be32s(f, &s->tm4[i].control);
        !           392:         }
        !           393: 
        !           394:     qemu_put_be32s(f, &s->events);
        !           395:     qemu_put_be32s(f, &s->irq_enabled);
        !           396:     qemu_put_be32s(f, &s->reset3);
        !           397:     qemu_put_be32s(f, &s->snapshot);
        !           398: }
        !           399: 
        !           400: static int pxa2xx_timer_load(QEMUFile *f, void *opaque, int version_id)
        !           401: {
        !           402:     pxa2xx_timer_info *s = (pxa2xx_timer_info *) opaque;
        !           403:     int64_t now;
        !           404:     int i;
        !           405: 
        !           406:     qemu_get_be32s(f, &s->clock);
        !           407:     qemu_get_be32s(f, &s->oldclock);
        !           408:     qemu_get_be64s(f, &s->lastload);
        !           409: 
        !           410:     now = qemu_get_clock(vm_clock);
        !           411:     for (i = 0; i < 4; i ++) {
        !           412:         qemu_get_be32s(f, &s->timer[i].value);
        !           413:         s->timer[i].level = qemu_get_be32(f);
        !           414:     }
        !           415:     pxa2xx_timer_update(s, now);
        !           416: 
        !           417:     if (s->tm4)
        !           418:         for (i = 0; i < 8; i ++) {
        !           419:             qemu_get_be32s(f, &s->tm4[i].tm.value);
        !           420:             s->tm4[i].tm.level = qemu_get_be32(f);
        !           421:             qemu_get_be32s(f, &s->tm4[i].oldclock);
        !           422:             qemu_get_be32s(f, &s->tm4[i].clock);
        !           423:             qemu_get_be64s(f, &s->tm4[i].lastload);
        !           424:             qemu_get_be32s(f, &s->tm4[i].freq);
        !           425:             qemu_get_be32s(f, &s->tm4[i].control);
        !           426:             pxa2xx_timer_update4(s, now, i);
        !           427:         }
        !           428: 
        !           429:     qemu_get_be32s(f, &s->events);
        !           430:     qemu_get_be32s(f, &s->irq_enabled);
        !           431:     qemu_get_be32s(f, &s->reset3);
        !           432:     qemu_get_be32s(f, &s->snapshot);
        !           433: 
        !           434:     return 0;
        !           435: }
        !           436: 
        !           437: static pxa2xx_timer_info *pxa2xx_timer_init(target_phys_addr_t base,
        !           438:                 qemu_irq *irqs)
        !           439: {
        !           440:     int i;
        !           441:     int iomemtype;
        !           442:     pxa2xx_timer_info *s;
        !           443: 
        !           444:     s = (pxa2xx_timer_info *) qemu_mallocz(sizeof(pxa2xx_timer_info));
        !           445:     s->base = base;
        !           446:     s->irq_enabled = 0;
        !           447:     s->oldclock = 0;
        !           448:     s->clock = 0;
        !           449:     s->lastload = qemu_get_clock(vm_clock);
        !           450:     s->reset3 = 0;
        !           451: 
        !           452:     for (i = 0; i < 4; i ++) {
        !           453:         s->timer[i].value = 0;
        !           454:         s->timer[i].irq = irqs[i];
        !           455:         s->timer[i].info = s;
        !           456:         s->timer[i].num = i;
        !           457:         s->timer[i].level = 0;
        !           458:         s->timer[i].qtimer = qemu_new_timer(vm_clock,
        !           459:                         pxa2xx_timer_tick, &s->timer[i]);
        !           460:     }
        !           461: 
        !           462:     iomemtype = cpu_register_io_memory(0, pxa2xx_timer_readfn,
        !           463:                     pxa2xx_timer_writefn, s);
        !           464:     cpu_register_physical_memory(base, 0x00001000, iomemtype);
        !           465: 
        !           466:     register_savevm("pxa2xx_timer", 0, 0,
        !           467:                     pxa2xx_timer_save, pxa2xx_timer_load, s);
        !           468: 
        !           469:     return s;
        !           470: }
        !           471: 
        !           472: void pxa25x_timer_init(target_phys_addr_t base, qemu_irq *irqs)
        !           473: {
        !           474:     pxa2xx_timer_info *s = pxa2xx_timer_init(base, irqs);
        !           475:     s->freq = PXA25X_FREQ;
        !           476:     s->tm4 = 0;
        !           477: }
        !           478: 
        !           479: void pxa27x_timer_init(target_phys_addr_t base,
        !           480:                 qemu_irq *irqs, qemu_irq irq4)
        !           481: {
        !           482:     pxa2xx_timer_info *s = pxa2xx_timer_init(base, irqs);
        !           483:     int i;
        !           484:     s->freq = PXA27X_FREQ;
        !           485:     s->tm4 = (struct pxa2xx_timer4_s *) qemu_mallocz(8 *
        !           486:                     sizeof(struct pxa2xx_timer4_s));
        !           487:     for (i = 0; i < 8; i ++) {
        !           488:         s->tm4[i].tm.value = 0;
        !           489:         s->tm4[i].tm.irq = irq4;
        !           490:         s->tm4[i].tm.info = s;
        !           491:         s->tm4[i].tm.num = i + 4;
        !           492:         s->tm4[i].tm.level = 0;
        !           493:         s->tm4[i].freq = 0;
        !           494:         s->tm4[i].control = 0x0;
        !           495:         s->tm4[i].tm.qtimer = qemu_new_timer(vm_clock,
        !           496:                         pxa2xx_timer_tick4, &s->tm4[i]);
        !           497:     }
        !           498: }

unix.superglobalmegacorp.com

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