(linenum→info "unix/slp.c:2238")

qemu/0.9.1/hw/arm_timer.c

    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 "hw.h"
   11: #include "qemu-timer.h"
   12: #include "primecell.h"
   13: 
   14: /* Common timer implementation.  */
   15: 
   16: #define TIMER_CTRL_ONESHOT      (1 << 0)
   17: #define TIMER_CTRL_32BIT        (1 << 1)
   18: #define TIMER_CTRL_DIV1         (0 << 2)
   19: #define TIMER_CTRL_DIV16        (1 << 2)
   20: #define TIMER_CTRL_DIV256       (2 << 2)
   21: #define TIMER_CTRL_IE           (1 << 5)
   22: #define TIMER_CTRL_PERIODIC     (1 << 6)
   23: #define TIMER_CTRL_ENABLE       (1 << 7)
   24: 
   25: typedef struct {
   26:     ptimer_state *timer;
   27:     uint32_t control;
   28:     uint32_t limit;
   29:     int freq;
   30:     int int_level;
   31:     qemu_irq irq;
   32: } arm_timer_state;
   33: 
   34: /* Check all active timers, and schedule the next timer interrupt.  */
   35: 
   36: static void arm_timer_update(arm_timer_state *s)
   37: {
   38:     /* Update interrupts.  */
   39:     if (s->int_level && (s->control & TIMER_CTRL_IE)) {
   40:         qemu_irq_raise(s->irq);
   41:     } else {
   42:         qemu_irq_lower(s->irq);
   43:     }
   44: }
   45: 
   46: static uint32_t arm_timer_read(void *opaque, target_phys_addr_t offset)
   47: {
   48:     arm_timer_state *s = (arm_timer_state *)opaque;
   49: 
   50:     switch (offset >> 2) {
   51:     case 0: /* TimerLoad */
   52:     case 6: /* TimerBGLoad */
   53:         return s->limit;
   54:     case 1: /* TimerValue */
   55:         return ptimer_get_count(s->timer);
   56:     case 2: /* TimerControl */
   57:         return s->control;
   58:     case 4: /* TimerRIS */
   59:         return s->int_level;
   60:     case 5: /* TimerMIS */
   61:         if ((s->control & TIMER_CTRL_IE) == 0)
   62:             return 0;
   63:         return s->int_level;
   64:     default:
   65:         cpu_abort (cpu_single_env, "arm_timer_read: Bad offset %x\n",
   66:                    (int)offset);
   67:         return 0;
   68:     }
   69: }
   70: 
   71: /* Reset the timer limit after settings have changed.  */
   72: static void arm_timer_recalibrate(arm_timer_state *s, int reload)
   73: {
   74:     uint32_t limit;
   75: 
   76:     if ((s->control & TIMER_CTRL_PERIODIC) == 0) {
   77:         /* Free running.  */
   78:         if (s->control & TIMER_CTRL_32BIT)
   79:             limit = 0xffffffff;
   80:         else
   81:             limit = 0xffff;
   82:     } else {
   83:           /* Periodic.  */
   84:           limit = s->limit;
   85:     }
   86:     ptimer_set_limit(s->timer, limit, reload);
   87: }
   88: 
   89: static void arm_timer_write(void *opaque, target_phys_addr_t offset,
   90:                             uint32_t value)
   91: {
   92:     arm_timer_state *s = (arm_timer_state *)opaque;
   93:     int freq;
   94: 
   95:     switch (offset >> 2) {
   96:     case 0: /* TimerLoad */
   97:         s->limit = value;
   98:         arm_timer_recalibrate(s, 1);
   99:         break;
  100:     case 1: /* TimerValue */
  101:         /* ??? Linux seems to want to write to this readonly register.
  102:            Ignore it.  */
  103:         break;
  104:     case 2: /* TimerControl */
  105:         if (s->control & TIMER_CTRL_ENABLE) {
  106:             /* Pause the timer if it is running.  This may cause some
  107:                inaccuracy dure to rounding, but avoids a whole lot of other
  108:                messyness.  */
  109:             ptimer_stop(s->timer);
  110:         }
  111:         s->control = value;
  112:         freq = s->freq;
  113:         /* ??? Need to recalculate expiry time after changing divisor.  */
  114:         switch ((value >> 2) & 3) {
  115:         case 1: freq >>= 4; break;
  116:         case 2: freq >>= 8; break;
  117:         }
  118:         arm_timer_recalibrate(s, 0);
  119:         ptimer_set_freq(s->timer, freq);
  120:         if (s->control & TIMER_CTRL_ENABLE) {
  121:             /* Restart the timer if still enabled.  */
  122:             ptimer_run(s->timer, (s->control & TIMER_CTRL_ONESHOT) != 0);
  123:         }
  124:         break;
  125:     case 3: /* TimerIntClr */
  126:         s->int_level = 0;
  127:         break;
  128:     case 6: /* TimerBGLoad */
  129:         s->limit = value;
  130:         arm_timer_recalibrate(s, 0);
  131:         break;
  132:     default:
  133:         cpu_abort (cpu_single_env, "arm_timer_write: Bad offset %x\n",
  134:                    (int)offset);
  135:     }
  136:     arm_timer_update(s);
  137: }
  138: 
  139: static void arm_timer_tick(void *opaque)
  140: {
  141:     arm_timer_state *s = (arm_timer_state *)opaque;
  142:     s->int_level = 1;
  143:     arm_timer_update(s);
  144: }
  145: 
  146: static void *arm_timer_init(uint32_t freq, qemu_irq irq)
  147: {
  148:     arm_timer_state *s;
  149:     QEMUBH *bh;
  150: 
  151:     s = (arm_timer_state *)qemu_mallocz(sizeof(arm_timer_state));
  152:     s->irq = irq;
  153:     s->freq = freq;
  154:     s->control = TIMER_CTRL_IE;
  155: 
  156:     bh = qemu_bh_new(arm_timer_tick, s);
  157:     s->timer = ptimer_init(bh);
  158:     /* ??? Save/restore.  */
  159:     return s;
  160: }
  161: 
  162: /* ARM PrimeCell SP804 dual timer module.
  163:    Docs for this device don't seem to be publicly available.  This
  164:    implementation is based on guesswork, the linux kernel sources and the
  165:    Integrator/CP timer modules.  */
  166: 
  167: typedef struct {
  168:     void *timer[2];
  169:     int level[2];
  170:     uint32_t base;
  171:     qemu_irq irq;
  172: } sp804_state;
  173: 
  174: /* Merge the IRQs from the two component devices.  */
  175: static void sp804_set_irq(void *opaque, int irq, int level)
  176: {
  177:     sp804_state *s = (sp804_state *)opaque;
  178: 
  179:     s->level[irq] = level;
  180:     qemu_set_irq(s->irq, s->level[0] || s->level[1]);
  181: }
  182: 
  183: static uint32_t sp804_read(void *opaque, target_phys_addr_t offset)
  184: {
  185:     sp804_state *s = (sp804_state *)opaque;
  186: 
  187:     /* ??? Don't know the PrimeCell ID for this device.  */
  188:     offset -= s->base;
  189:     if (offset < 0x20) {
  190:         return arm_timer_read(s->timer[0], offset);
  191:     } else {
  192:         return arm_timer_read(s->timer[1], offset - 0x20);
  193:     }
  194: }
  195: 
  196: static void sp804_write(void *opaque, target_phys_addr_t offset,
  197:                         uint32_t value)
  198: {
  199:     sp804_state *s = (sp804_state *)opaque;
  200: 
  201:     offset -= s->base;
  202:     if (offset < 0x20) {
  203:         arm_timer_write(s->timer[0], offset, value);
  204:     } else {
  205:         arm_timer_write(s->timer[1], offset - 0x20, value);
  206:     }
  207: }
  208: 
  209: static CPUReadMemoryFunc *sp804_readfn[] = {
  210:    sp804_read,
  211:    sp804_read,
  212:    sp804_read
  213: };
  214: 
  215: static CPUWriteMemoryFunc *sp804_writefn[] = {
  216:    sp804_write,
  217:    sp804_write,
  218:    sp804_write
  219: };
  220: 
  221: void sp804_init(uint32_t base, qemu_irq irq)
  222: {
  223:     int iomemtype;
  224:     sp804_state *s;
  225:     qemu_irq *qi;
  226: 
  227:     s = (sp804_state *)qemu_mallocz(sizeof(sp804_state));
  228:     qi = qemu_allocate_irqs(sp804_set_irq, s, 2);
  229:     s->base = base;
  230:     s->irq = irq;
  231:     /* ??? The timers are actually configurable between 32kHz and 1MHz, but
  232:        we don't implement that.  */
  233:     s->timer[0] = arm_timer_init(1000000, qi[0]);
  234:     s->timer[1] = arm_timer_init(1000000, qi[1]);
  235:     iomemtype = cpu_register_io_memory(0, sp804_readfn,
  236:                                        sp804_writefn, s);
  237:     cpu_register_physical_memory(base, 0x00001000, iomemtype);
  238:     /* ??? Save/restore.  */
  239: }
  240: 
  241: 
  242: /* Integrator/CP timer module.  */
  243: 
  244: typedef struct {
  245:     void *timer[3];
  246:     uint32_t base;
  247: } icp_pit_state;
  248: 
  249: static uint32_t icp_pit_read(void *opaque, target_phys_addr_t offset)
  250: {
  251:     icp_pit_state *s = (icp_pit_state *)opaque;
  252:     int n;
  253: 
  254:     /* ??? Don't know the PrimeCell ID for this device.  */
  255:     offset -= s->base;
  256:     n = offset >> 8;
  257:     if (n > 3)
  258:         cpu_abort(cpu_single_env, "sp804_read: Bad timer %d\n", n);
  259: 
  260:     return arm_timer_read(s->timer[n], offset & 0xff);
  261: }
  262: 
  263: static void icp_pit_write(void *opaque, target_phys_addr_t offset,
  264:                           uint32_t value)
  265: {
  266:     icp_pit_state *s = (icp_pit_state *)opaque;
  267:     int n;
  268: 
  269:     offset -= s->base;
  270:     n = offset >> 8;
  271:     if (n > 3)
  272:         cpu_abort(cpu_single_env, "sp804_write: Bad timer %d\n", n);
  273: 
  274:     arm_timer_write(s->timer[n], offset & 0xff, value);
  275: }
  276: 
  277: 
  278: static CPUReadMemoryFunc *icp_pit_readfn[] = {
  279:    icp_pit_read,
  280:    icp_pit_read,
  281:    icp_pit_read
  282: };
  283: 
  284: static CPUWriteMemoryFunc *icp_pit_writefn[] = {
  285:    icp_pit_write,
  286:    icp_pit_write,
  287:    icp_pit_write
  288: };
  289: 
  290: void icp_pit_init(uint32_t base, qemu_irq *pic, int irq)
  291: {
  292:     int iomemtype;
  293:     icp_pit_state *s;
  294: 
  295:     s = (icp_pit_state *)qemu_mallocz(sizeof(icp_pit_state));
  296:     s->base = base;
  297:     /* Timer 0 runs at the system clock speed (40MHz).  */
  298:     s->timer[0] = arm_timer_init(40000000, pic[irq]);
  299:     /* The other two timers run at 1MHz.  */
  300:     s->timer[1] = arm_timer_init(1000000, pic[irq + 1]);
  301:     s->timer[2] = arm_timer_init(1000000, pic[irq + 2]);
  302: 
  303:     iomemtype = cpu_register_io_memory(0, icp_pit_readfn,
  304:                                        icp_pit_writefn, s);
  305:     cpu_register_physical_memory(base, 0x00001000, iomemtype);
  306:     /* ??? Save/restore.  */
  307: }
  308: 
Syntax (Markdown)