static void main_cpu_reset(void *opaque) { ResetData *s = (ResetData *)opaque; CPUState *env = s->env; static unsigned int nr_resets; cpu_reset(env); env->tick_cmpr = TICK_INT_DIS | 0; ptimer_set_limit(env->tick, TICK_MAX, 1); ptimer_run(env->tick, 1); env->stick_cmpr = TICK_INT_DIS | 0; ptimer_set_limit(env->stick, TICK_MAX, 1); ptimer_run(env->stick, 1); env->hstick_cmpr = TICK_INT_DIS | 0; ptimer_set_limit(env->hstick, TICK_MAX, 1); ptimer_run(env->hstick, 1); env->gregs[1] = 0; // Memory start env->gregs[2] = ram_size; // Memory size env->gregs[3] = 0; // Machine description XXX if (nr_resets++ == 0) { /* Power on reset */ env->pc = s->prom_addr + 0x20ULL; } else { env->pc = s->prom_addr + 0x40ULL; } env->npc = env->pc + 4; }
static void digic_timer_write(void *opaque, hwaddr offset, uint64_t value, unsigned size) { DigicTimerState *s = opaque; switch (offset) { case DIGIC_TIMER_CONTROL: if (value & DIGIC_TIMER_CONTROL_RST) { digic_timer_reset((DeviceState *)s); break; } if (value & DIGIC_TIMER_CONTROL_EN) { ptimer_run(s->ptimer, 0); } s->control = (uint32_t)value; break; case DIGIC_TIMER_RELVALUE: s->relvalue = extract32(value, 0, 16); ptimer_set_limit(s->ptimer, s->relvalue, 1); break; case DIGIC_TIMER_VALUE: break; default: qemu_log_mask(LOG_UNIMP, "digic-timer: read access to unknown register 0x" TARGET_FMT_plx, offset); } }
static void timer_write(void *opaque, target_phys_addr_t addr, uint32_t value) { LM32TimerState *s = opaque; trace_lm32_timer_memory_write(addr, value); addr >>= 2; switch (addr) { case R_SR: s->regs[R_SR] &= ~SR_TO; break; case R_CR: s->regs[R_CR] = value; if (s->regs[R_CR] & CR_START) { ptimer_run(s->ptimer, 1); } if (s->regs[R_CR] & CR_STOP) { ptimer_stop(s->ptimer); } break; case R_PERIOD: s->regs[R_PERIOD] = value; ptimer_set_count(s->ptimer, value); break; case R_SNAPSHOT: error_report("lm32_timer: write access to read only register 0x" TARGET_FMT_plx, addr << 2); break; default: error_report("lm32_timer: write access to unknown register 0x" TARGET_FMT_plx, addr << 2); break; } timer_update_irq(s); }
static void imx_epit_reset(DeviceState *dev) { IMXEPITState *s = IMX_EPIT(dev); /* * Soft reset doesn't touch some bits; hard reset clears them */ s->cr &= (CR_EN|CR_ENMOD|CR_STOPEN|CR_DOZEN|CR_WAITEN|CR_DBGEN); s->sr = 0; s->lr = EPIT_TIMER_MAX; s->cmp = 0; s->cnt = 0; /* stop both timers */ ptimer_stop(s->timer_cmp); ptimer_stop(s->timer_reload); /* compute new frequency */ imx_epit_set_freq(s); /* init both timers to EPIT_TIMER_MAX */ ptimer_set_limit(s->timer_cmp, EPIT_TIMER_MAX, 1); ptimer_set_limit(s->timer_reload, EPIT_TIMER_MAX, 1); if (s->freq && (s->cr & CR_EN)) { /* if the timer is still enabled, restart it */ ptimer_run(s->timer_reload, 0); } }
static inline void timer_watchdog_update(struct etrax_timer *t, uint32_t value) { unsigned int wd_en = t->rw_wd_ctrl & (1 << 8); unsigned int wd_key = t->rw_wd_ctrl >> 9; unsigned int wd_cnt = t->rw_wd_ctrl & 511; unsigned int new_key = value >> 9 & ((1 << 7) - 1); unsigned int new_cmd = (value >> 8) & 1; /* If the watchdog is enabled, they written key must match the complement of the previous. */ wd_key = ~wd_key & ((1 << 7) - 1); if (wd_en && wd_key != new_key) return; D(printf("en=%d new_key=%x oldkey=%x cmd=%d cnt=%d\n", wd_en, new_key, wd_key, new_cmd, wd_cnt)); if (t->wd_hits) qemu_irq_lower(t->nmi); t->wd_hits = 0; ptimer_set_freq(t->ptimer_wd, 760); if (wd_cnt == 0) wd_cnt = 256; ptimer_set_count(t->ptimer_wd, wd_cnt); if (new_cmd) ptimer_run(t->ptimer_wd, 1); else ptimer_stop(t->ptimer_wd); t->rw_wd_ctrl = value; }
static void puv3_ost_write(void *opaque, target_phys_addr_t offset, uint64_t value, unsigned size) { PUV3OSTState *s = opaque; DPRINTF("offset 0x%x, value 0x%x\n", offset, value); switch (offset) { case 0x00: /* Match Register 0 */ s->reg_OSMR0 = value; if (s->reg_OSMR0 > s->reg_OSCR) { ptimer_set_count(s->ptimer, s->reg_OSMR0 - s->reg_OSCR); } else { ptimer_set_count(s->ptimer, s->reg_OSMR0 + (0xffffffff - s->reg_OSCR)); } ptimer_run(s->ptimer, 2); break; case 0x14: /* Status Register */ assert(value == 0); if (s->reg_OSSR) { s->reg_OSSR = value; qemu_irq_lower(s->irq); } break; case 0x1c: /* Interrupt Enable Register */ s->reg_OIER = value; break; default: DPRINTF("Bad offset %x\n", (int)offset); } }
static void main_cpu_reset(void *opaque) { ResetData *s = (ResetData *)opaque; CPUState *env = s->env; cpu_reset(env); env->tick_cmpr = TICK_INT_DIS | 0; ptimer_set_limit(env->tick, TICK_MAX, 1); ptimer_run(env->tick, 1); env->stick_cmpr = TICK_INT_DIS | 0; ptimer_set_limit(env->stick, TICK_MAX, 1); ptimer_run(env->stick, 1); env->hstick_cmpr = TICK_INT_DIS | 0; ptimer_set_limit(env->hstick, TICK_MAX, 1); ptimer_run(env->hstick, 1); env->gregs[1] = 0; // Memory start env->gregs[2] = ram_size; // Memory size env->gregs[3] = 0; // Machine description XXX env->pc = s->reset_addr; env->npc = env->pc + 4; }
static void timer_update(struct Msf2Timer *st) { uint64_t count; if (!(st->regs[R_TIM_CTRL] & TIMER_CTRL_ENBL)) { ptimer_stop(st->ptimer); return; } count = st->regs[R_TIM_LOADVAL]; ptimer_set_limit(st->ptimer, count, 1); ptimer_run(st->ptimer, 1); }
static void timer_hit(void *opaque) { LM32TimerState *s = opaque; trace_lm32_timer_hit(); s->regs[R_SR] |= SR_TO; if (s->regs[R_CR] & CR_CONT) { ptimer_set_count(s->ptimer, s->regs[R_PERIOD]); ptimer_run(s->ptimer, 1); } timer_update_irq(s); }
static void arm_timer_write(void *opaque, hwaddr offset, uint32_t value) { arm_timer_state *s = (arm_timer_state *)opaque; int freq; switch (offset >> 2) { case 0: /* TimerLoad */ s->limit = value; arm_timer_recalibrate(s, 1); break; case 1: /* TimerValue */ /* ??? Linux seems to want to write to this readonly register. Ignore it. */ break; case 2: /* TimerControl */ if (s->control & TIMER_CTRL_ENABLE) { /* Pause the timer if it is running. This may cause some inaccuracy dure to rounding, but avoids a whole lot of other messyness. */ ptimer_stop(s->timer); } s->control = value; freq = s->freq; /* ??? Need to recalculate expiry time after changing divisor. */ switch ((value >> 2) & 3) { case 1: freq >>= 4; break; case 2: freq >>= 8; break; } arm_timer_recalibrate(s, s->control & TIMER_CTRL_ENABLE); ptimer_set_freq(s->timer, freq); if (s->control & TIMER_CTRL_ENABLE) { /* Restart the timer if still enabled. */ ptimer_run(s->timer, (s->control & TIMER_CTRL_ONESHOT) != 0); } break; case 3: /* TimerIntClr */ s->int_level = 0; break; case 6: /* TimerBGLoad */ s->limit = value; arm_timer_recalibrate(s, 0); break; default: qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset %x\n", __func__, (int)offset); } arm_timer_update(s); }
static void watchdog_hit(void *opaque) { struct etrax_timer *t = opaque; if (t->wd_hits == 0) { /* real hw gives a single tick before reseting but we are a bit friendlier to compensate for our slower execution. */ ptimer_set_count(t->ptimer_wd, 10); ptimer_run(t->ptimer_wd, 1); qemu_irq_raise(t->nmi); } else qemu_system_reset_request(); t->wd_hits++; }
static void etsec_timer_hit(void *opaque) { eTSEC *etsec = opaque; ptimer_stop(etsec->ptimer); if (!(etsec->regs[DMACTRL].value & DMACTRL_WOP)) { if (!(etsec->regs[DMACTRL].value & DMACTRL_GTS)) { etsec_walk_tx_ring(etsec, 0); } ptimer_set_count(etsec->ptimer, 1); ptimer_run(etsec->ptimer, 1); } }
static void timer_enable(struct xlx_timer *xt) { uint64_t count; D(fprintf(stderr, "%s timer=%d down=%d\n", __func__, xt->nr, xt->regs[R_TCSR] & TCSR_UDT)); ptimer_stop(xt->ptimer); if (xt->regs[R_TCSR] & TCSR_UDT) count = xt->regs[R_TLR]; else count = ~0 - xt->regs[R_TLR]; ptimer_set_limit(xt->ptimer, count, 1); ptimer_run(xt->ptimer, 1); }
static void imx_gpt_timeout(void *opaque) { IMXGPTState *s = IMX_GPT(opaque); DPRINTF("\n"); s->sr |= s->next_int; s->next_int = 0; imx_gpt_compute_next_timeout(s, true); imx_gpt_update_int(s); if (s->freq && (s->cr & GPT_CR_EN)) { ptimer_run(s->timer, 1); } }
static void sh_timer_start_stop(void *opaque, int enable) { sh_timer_state *s = (sh_timer_state *)opaque; #ifdef DEBUG_TIMER printf("sh_timer_start_stop %d (%d)\n", enable, s->enabled); #endif if (s->enabled && !enable) { ptimer_stop(s->timer); } if (!s->enabled && enable) { ptimer_run(s->timer, 0); } s->enabled = !!enable; #ifdef DEBUG_TIMER printf("sh_timer_start_stop done %d\n", s->enabled); #endif }
static int rtt_init(SysBusDevice *dev) { rtt_state *s = FROM_SYSBUS(rtt_state, dev); QEMUBH *bh; memory_region_init_io(&s->iomem, OBJECT(s), &rtt_ops, s, "rtt", 0x20); sysbus_init_mmio(dev, &s->iomem); sysbus_init_irq(dev, &s->irq); //s->ssi = ssi_create_bus(&dev->qdev, "ssi"); //rtt_reset(s); //vmstate_register(&dev->qdev, -1, &vmstate_rtt, s); bh = qemu_bh_new(rtt_tick, s); s->timer = ptimer_init(bh); ptimer_set_freq(s->timer, 10); ptimer_set_limit(s->timer, 1, 1); ptimer_run(s->timer, 0); return 0; }
static void grlib_gptimer_enable(GPTimer *timer) { assert(timer != NULL); ptimer_stop(timer->ptimer); if (!(timer->config & GPTIMER_ENABLE)) { /* Timer disabled */ trace_grlib_gptimer_disabled(timer->id, timer->config); return; } /* ptimer is triggered when the counter reach 0 but GPTimer is triggered at underflow. Set count + 1 to simulate the GPTimer behavior. */ trace_grlib_gptimer_enable(timer->id, timer->counter + 1); ptimer_set_count(timer->ptimer, timer->counter + 1); ptimer_run(timer->ptimer, 1); }
static void write_dmactrl(eTSEC *etsec, eTSEC_Register *reg, uint32_t reg_index, uint32_t value) { reg->value = value; if (value & DMACTRL_GRS) { if (etsec->rx_buffer_len != 0) { /* Graceful receive stop delayed until end of frame */ } else { /* Graceful receive stop now */ etsec->regs[IEVENT].value |= IEVENT_GRSC; if (etsec->regs[IMASK].value & IMASK_GRSCEN) { qemu_irq_raise(etsec->err_irq); } } } if (value & DMACTRL_GTS) { if (etsec->tx_buffer_len != 0) { /* Graceful transmit stop delayed until end of frame */ } else { /* Graceful transmit stop now */ etsec->regs[IEVENT].value |= IEVENT_GTSC; if (etsec->regs[IMASK].value & IMASK_GTSCEN) { qemu_irq_raise(etsec->err_irq); } } } if (!(value & DMACTRL_WOP)) { /* Start polling */ ptimer_stop(etsec->ptimer); ptimer_set_count(etsec->ptimer, 1); ptimer_run(etsec->ptimer, 1); } }
static void pit_control_pw(RegisterInfo *reg, uint64_t value) { XilinxPIT *s = XILINX_IO_MODULE_PIT(reg->opaque); uint32_t v32 = value; if (!s->cfg.use) { qemu_log_mask(LOG_GUEST_ERROR, "%s: Disabled\n", s->prefix); return; } ptimer_stop(s->ptimer); if (v32 & IOM_PIT_CONTROL_EN) { if (s->ps_enable) { /* pre-scalar mode Do-Nothing here. Wait for the friend to hit_in * and decrement the counter(s->ps_counter)*/ s->ps_counter = s->regs[R_IOM_PIT_PRELOAD]; } else { ptimer_set_limit(s->ptimer, s->regs[R_IOM_PIT_PRELOAD], 1); ptimer_run(s->ptimer, !(v32 & IOM_PIT_CONTROL_PRELOAD)); } } }
static void imx_gpt_reset(DeviceState *dev) { IMXGPTState *s = IMX_GPT(dev); /* stop timer */ ptimer_stop(s->timer); /* * Soft reset doesn't touch some bits; hard reset clears them */ s->cr &= ~(GPT_CR_EN|GPT_CR_ENMOD|GPT_CR_STOPEN|GPT_CR_DOZEN| GPT_CR_WAITEN|GPT_CR_DBGEN); s->sr = 0; s->pr = 0; s->ir = 0; s->cnt = 0; s->ocr1 = GPT_TIMER_MAX; s->ocr2 = GPT_TIMER_MAX; s->ocr3 = GPT_TIMER_MAX; s->icr1 = 0; s->icr2 = 0; s->next_timeout = GPT_TIMER_MAX; s->next_int = 0; /* compute new freq */ imx_gpt_set_freq(s); /* reset the limit to GPT_TIMER_MAX */ ptimer_set_limit(s->timer, GPT_TIMER_MAX, 1); /* if the timer is still enabled, restart it */ if (s->freq && (s->cr & GPT_CR_EN)) { ptimer_run(s->timer, 1); } }
static void sysctl_write(void *opaque, target_phys_addr_t addr, uint64_t value, unsigned size) { MilkymistSysctlState *s = opaque; trace_milkymist_sysctl_memory_write(addr, value); addr >>= 2; switch (addr) { case R_GPIO_OUT: case R_GPIO_INTEN: case R_TIMER0_COUNTER: case R_TIMER1_COUNTER: s->regs[addr] = value; break; case R_TIMER0_COMPARE: ptimer_set_limit(s->ptimer0, value, 0); s->regs[addr] = value; break; case R_TIMER1_COMPARE: ptimer_set_limit(s->ptimer1, value, 0); s->regs[addr] = value; break; case R_TIMER0_CONTROL: s->regs[addr] = value; if (s->regs[R_TIMER0_CONTROL] & CTRL_ENABLE) { trace_milkymist_sysctl_start_timer0(); ptimer_set_count(s->ptimer0, s->regs[R_TIMER0_COMPARE] - s->regs[R_TIMER0_COUNTER]); ptimer_run(s->ptimer0, 0); } else { trace_milkymist_sysctl_stop_timer0(); ptimer_stop(s->ptimer0); } break; case R_TIMER1_CONTROL: s->regs[addr] = value; if (s->regs[R_TIMER1_CONTROL] & CTRL_ENABLE) { trace_milkymist_sysctl_start_timer1(); ptimer_set_count(s->ptimer1, s->regs[R_TIMER1_COMPARE] - s->regs[R_TIMER1_COUNTER]); ptimer_run(s->ptimer1, 0); } else { trace_milkymist_sysctl_stop_timer1(); ptimer_stop(s->ptimer1); } break; case R_ICAP: sysctl_icap_write(s, value); break; case R_SYSTEM_ID: qemu_system_reset_request(); break; case R_GPIO_IN: case R_CAPABILITIES: error_report("milkymist_sysctl: write to read-only register 0x" TARGET_FMT_plx, addr << 2); break; default: error_report("milkymist_sysctl: write access to unknown register 0x" TARGET_FMT_plx, addr << 2); break; } }
static void slavio_timer_mem_writel(void *opaque, hwaddr addr, uint64_t val, unsigned size) { TimerContext *tc = opaque; SLAVIO_TIMERState *s = tc->s; uint32_t saddr; unsigned int timer_index = tc->timer_index; CPUTimerState *t = &s->cputimer[timer_index]; trace_slavio_timer_mem_writel(addr, val); saddr = addr >> 2; switch (saddr) { case TIMER_LIMIT: if (slavio_timer_is_user(tc)) { uint64_t count; // set user counter MSW, reset counter t->limit = TIMER_MAX_COUNT64; t->counthigh = val & (TIMER_MAX_COUNT64 >> 32); t->reached = 0; count = ((uint64_t)t->counthigh << 32) | t->count; trace_slavio_timer_mem_writel_limit(timer_index, count); ptimer_set_count(t->timer, LIMIT_TO_PERIODS(t->limit - count)); } else { // set limit, reset counter qemu_irq_lower(t->irq); t->limit = val & TIMER_MAX_COUNT32; if (t->timer) { if (t->limit == 0) { /* free-run */ ptimer_set_limit(t->timer, LIMIT_TO_PERIODS(TIMER_MAX_COUNT32), 1); } else { ptimer_set_limit(t->timer, LIMIT_TO_PERIODS(t->limit), 1); } } } break; case TIMER_COUNTER: if (slavio_timer_is_user(tc)) { uint64_t count; // set user counter LSW, reset counter t->limit = TIMER_MAX_COUNT64; t->count = val & TIMER_MAX_COUNT64; t->reached = 0; count = ((uint64_t)t->counthigh) << 32 | t->count; trace_slavio_timer_mem_writel_limit(timer_index, count); ptimer_set_count(t->timer, LIMIT_TO_PERIODS(t->limit - count)); } else { trace_slavio_timer_mem_writel_counter_invalid(); } break; case TIMER_COUNTER_NORST: // set limit without resetting counter t->limit = val & TIMER_MAX_COUNT32; if (t->limit == 0) { /* free-run */ ptimer_set_limit(t->timer, LIMIT_TO_PERIODS(TIMER_MAX_COUNT32), 0); } else { ptimer_set_limit(t->timer, LIMIT_TO_PERIODS(t->limit), 0); } break; case TIMER_STATUS: if (slavio_timer_is_user(tc)) { // start/stop user counter if (val & 1) { trace_slavio_timer_mem_writel_status_start(timer_index); ptimer_run(t->timer, 0); } else { trace_slavio_timer_mem_writel_status_stop(timer_index); ptimer_stop(t->timer); } } t->run = val & 1; break; case TIMER_MODE: if (timer_index == 0) { unsigned int i; for (i = 0; i < s->num_cpus; i++) { unsigned int processor = 1 << i; CPUTimerState *curr_timer = &s->cputimer[i + 1]; // check for a change in timer mode for this processor if ((val & processor) != (s->cputimer_mode & processor)) { if (val & processor) { // counter -> user timer qemu_irq_lower(curr_timer->irq); // counters are always running if (!curr_timer->run) { ptimer_stop(curr_timer->timer); } // user timer limit is always the same curr_timer->limit = TIMER_MAX_COUNT64; ptimer_set_limit(curr_timer->timer, LIMIT_TO_PERIODS(curr_timer->limit), 1); // set this processors user timer bit in config // register s->cputimer_mode |= processor; trace_slavio_timer_mem_writel_mode_user(timer_index); } else { // user timer -> counter // start the counter ptimer_run(curr_timer->timer, 0); // clear this processors user timer bit in config // register s->cputimer_mode &= ~processor; trace_slavio_timer_mem_writel_mode_counter(timer_index); } } } } else { trace_slavio_timer_mem_writel_mode_invalid(); } break; default: trace_slavio_timer_mem_writel_invalid(addr); break; }
static void imx_gpt_write(void *opaque, hwaddr offset, uint64_t value, unsigned size) { IMXGPTState *s = IMX_GPT(opaque); uint32_t oldreg; uint32_t reg = offset >> 2; DPRINTF("(%s, value = 0x%08x)\n", imx_gpt_reg_name(reg), (uint32_t)value); switch (reg) { case 0: oldreg = s->cr; s->cr = value & ~0x7c14; if (s->cr & GPT_CR_SWR) { /* force reset */ /* handle the reset */ imx_gpt_reset(DEVICE(s)); } else { /* set our freq, as the source might have changed */ imx_gpt_set_freq(s); if ((oldreg ^ s->cr) & GPT_CR_EN) { if (s->cr & GPT_CR_EN) { if (s->cr & GPT_CR_ENMOD) { s->next_timeout = GPT_TIMER_MAX; ptimer_set_count(s->timer, GPT_TIMER_MAX); imx_gpt_compute_next_timeout(s, false); } ptimer_run(s->timer, 1); } else { /* stop timer */ ptimer_stop(s->timer); } } } break; case 1: /* Prescaler */ s->pr = value & 0xfff; imx_gpt_set_freq(s); break; case 2: /* SR */ s->sr &= ~(value & 0x3f); imx_gpt_update_int(s); break; case 3: /* IR -- interrupt register */ s->ir = value & 0x3f; imx_gpt_update_int(s); imx_gpt_compute_next_timeout(s, false); break; case 4: /* OCR1 -- output compare register */ s->ocr1 = value; /* In non-freerun mode, reset count when this register is written */ if (!(s->cr & GPT_CR_FRR)) { s->next_timeout = GPT_TIMER_MAX; ptimer_set_limit(s->timer, GPT_TIMER_MAX, 1); } /* compute the new timeout */ imx_gpt_compute_next_timeout(s, false); break; case 5: /* OCR2 -- output compare register */ s->ocr2 = value; /* compute the new timeout */ imx_gpt_compute_next_timeout(s, false); break; case 6: /* OCR3 -- output compare register */ s->ocr3 = value; /* compute the new timeout */ imx_gpt_compute_next_timeout(s, false); break; default: IPRINTF("Bad offset %x\n", reg); break; } }
static void update_ctrl(struct etrax_timer *t, int tnum) { unsigned int op; unsigned int freq; unsigned int freq_hz; unsigned int div; uint32_t ctrl; ptimer_state *timer; if (tnum == 0) { ctrl = t->rw_tmr0_ctrl; div = t->rw_tmr0_div; timer = t->ptimer_t0; } else { ctrl = t->rw_tmr1_ctrl; div = t->rw_tmr1_div; timer = t->ptimer_t1; } op = ctrl & 3; freq = ctrl >> 2; freq_hz = 32000000; switch (freq) { case 0: case 1: D(printf ("extern or disabled timer clock?\n")); break; case 4: freq_hz = 29493000; break; case 5: freq_hz = 32000000; break; case 6: freq_hz = 32768000; break; case 7: freq_hz = 100000000; break; default: abort(); break; } D(printf ("freq_hz=%d div=%d\n", freq_hz, div)); ptimer_set_freq(timer, freq_hz); ptimer_set_limit(timer, div, 0); switch (op) { case 0: /* Load. */ ptimer_set_limit(timer, div, 1); break; case 1: /* Hold. */ ptimer_stop(timer); break; case 2: /* Run. */ ptimer_run(timer, 0); break; default: abort(); break; } }
static void a10_pit_write(void *opaque, hwaddr offset, uint64_t value, unsigned size) { AwA10PITState *s = AW_A10_PIT(opaque); uint8_t index; switch (offset) { case AW_A10_PIT_TIMER_IRQ_EN: s->irq_enable = value; a10_pit_update_irq(s); break; case AW_A10_PIT_TIMER_IRQ_ST: s->irq_status &= ~value; a10_pit_update_irq(s); break; case AW_A10_PIT_TIMER_BASE ... AW_A10_PIT_TIMER_BASE_END: index = offset & 0xf0; index >>= 4; index -= 1; switch (offset & 0x0f) { case AW_A10_PIT_TIMER_CONTROL: s->control[index] = value; a10_pit_set_freq(s, index); if (s->control[index] & AW_A10_PIT_TIMER_RELOAD) { ptimer_set_count(s->timer[index], s->interval[index]); } if (s->control[index] & AW_A10_PIT_TIMER_EN) { int oneshot = 0; if (s->control[index] & AW_A10_PIT_TIMER_MODE) { oneshot = 1; } ptimer_run(s->timer[index], oneshot); } else { ptimer_stop(s->timer[index]); } break; case AW_A10_PIT_TIMER_INTERVAL: s->interval[index] = value; ptimer_set_limit(s->timer[index], s->interval[index], 1); break; case AW_A10_PIT_TIMER_COUNT: s->count[index] = value; break; default: qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%x\n", __func__, (int)offset); } break; case AW_A10_PIT_WDOG_CONTROL: s->watch_dog_control = value; break; case AW_A10_PIT_WDOG_MODE: s->watch_dog_mode = value; break; case AW_A10_PIT_COUNT_LO: s->count_lo = value; break; case AW_A10_PIT_COUNT_HI: s->count_hi = value; break; case AW_A10_PIT_COUNT_CTL: s->count_ctl = value; if (s->count_ctl & AW_A10_PIT_COUNT_RL_EN) { uint64_t tmp_count = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); s->count_lo = tmp_count; s->count_hi = tmp_count >> 32; s->count_ctl &= ~AW_A10_PIT_COUNT_RL_EN; } if (s->count_ctl & AW_A10_PIT_COUNT_CLR_EN) { s->count_lo = 0; s->count_hi = 0; s->count_ctl &= ~AW_A10_PIT_COUNT_CLR_EN; } break; default: qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%x\n", __func__, (int)offset); break; }
static void slavio_timer_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) { TimerContext *tc = opaque; SLAVIO_TIMERState *s = tc->s; uint32_t saddr; unsigned int timer_index = tc->timer_index; CPUTimerState *t = &s->cputimer[timer_index]; DPRINTF("write " TARGET_FMT_plx " %08x\n", addr, val); saddr = addr >> 2; switch (saddr) { case TIMER_LIMIT: if (slavio_timer_is_user(tc)) { uint64_t count; // set user counter MSW, reset counter t->limit = TIMER_MAX_COUNT64; t->counthigh = val & (TIMER_MAX_COUNT64 >> 32); t->reached = 0; count = ((uint64_t)t->counthigh << 32) | t->count; DPRINTF("processor %d user timer set to %016" PRIx64 "\n", timer_index, count); ptimer_set_count(t->timer, LIMIT_TO_PERIODS(t->limit - count)); } else { // set limit, reset counter qemu_irq_lower(t->irq); t->limit = val & TIMER_MAX_COUNT32; if (t->timer) { if (t->limit == 0) { /* free-run */ ptimer_set_limit(t->timer, LIMIT_TO_PERIODS(TIMER_MAX_COUNT32), 1); } else { ptimer_set_limit(t->timer, LIMIT_TO_PERIODS(t->limit), 1); } } } break; case TIMER_COUNTER: if (slavio_timer_is_user(tc)) { uint64_t count; // set user counter LSW, reset counter t->limit = TIMER_MAX_COUNT64; t->count = val & TIMER_MAX_COUNT64; t->reached = 0; count = ((uint64_t)t->counthigh) << 32 | t->count; DPRINTF("processor %d user timer set to %016" PRIx64 "\n", timer_index, count); ptimer_set_count(t->timer, LIMIT_TO_PERIODS(t->limit - count)); } else DPRINTF("not user timer\n"); break; case TIMER_COUNTER_NORST: // set limit without resetting counter t->limit = val & TIMER_MAX_COUNT32; if (t->limit == 0) { /* free-run */ ptimer_set_limit(t->timer, LIMIT_TO_PERIODS(TIMER_MAX_COUNT32), 0); } else { ptimer_set_limit(t->timer, LIMIT_TO_PERIODS(t->limit), 0); } break; case TIMER_STATUS: if (slavio_timer_is_user(tc)) { // start/stop user counter if ((val & 1) && !t->running) { DPRINTF("processor %d user timer started\n", timer_index); ptimer_run(t->timer, 0); t->running = 1; } else if (!(val & 1) && t->running) { DPRINTF("processor %d user timer stopped\n", timer_index); ptimer_stop(t->timer); t->running = 0; } } break; case TIMER_MODE: if (timer_index == 0) { unsigned int i; for (i = 0; i < s->num_cpus; i++) { unsigned int processor = 1 << i; CPUTimerState *curr_timer = &s->cputimer[i + 1]; // check for a change in timer mode for this processor if ((val & processor) != (s->cputimer_mode & processor)) { if (val & processor) { // counter -> user timer qemu_irq_lower(curr_timer->irq); // counters are always running ptimer_stop(curr_timer->timer); curr_timer->running = 0; // user timer limit is always the same curr_timer->limit = TIMER_MAX_COUNT64; ptimer_set_limit(curr_timer->timer, LIMIT_TO_PERIODS(curr_timer->limit), 1); // set this processors user timer bit in config // register s->cputimer_mode |= processor; DPRINTF("processor %d changed from counter to user " "timer\n", timer_index); } else { // user timer -> counter // stop the user timer if it is running if (curr_timer->running) { ptimer_stop(curr_timer->timer); } // start the counter ptimer_run(curr_timer->timer, 0); curr_timer->running = 1; // clear this processors user timer bit in config // register s->cputimer_mode &= ~processor; DPRINTF("processor %d changed from user timer to " "counter\n", timer_index); } } } } else { DPRINTF("not system timer\n"); } break; default: DPRINTF("invalid write address " TARGET_FMT_plx "\n", addr); break; }
static void imx_epit_write(void *opaque, hwaddr offset, uint64_t value, unsigned size) { IMXEPITState *s = IMX_EPIT(opaque); uint32_t reg = offset >> 2; uint64_t oldcr; DPRINTF("(%s, value = 0x%08x)\n", imx_epit_reg_name(reg), (uint32_t)value); switch (reg) { case 0: /* CR */ oldcr = s->cr; s->cr = value & 0x03ffffff; if (s->cr & CR_SWR) { /* handle the reset */ imx_epit_reset(DEVICE(s)); } else { imx_epit_set_freq(s); } if (s->freq && (s->cr & CR_EN) && !(oldcr & CR_EN)) { if (s->cr & CR_ENMOD) { if (s->cr & CR_RLD) { ptimer_set_limit(s->timer_reload, s->lr, 1); ptimer_set_limit(s->timer_cmp, s->lr, 1); } else { ptimer_set_limit(s->timer_reload, EPIT_TIMER_MAX, 1); ptimer_set_limit(s->timer_cmp, EPIT_TIMER_MAX, 1); } } imx_epit_reload_compare_timer(s); ptimer_run(s->timer_reload, 0); if (s->cr & CR_OCIEN) { ptimer_run(s->timer_cmp, 0); } else { ptimer_stop(s->timer_cmp); } } else if (!(s->cr & CR_EN)) { /* stop both timers */ ptimer_stop(s->timer_reload); ptimer_stop(s->timer_cmp); } else if (s->cr & CR_OCIEN) { if (!(oldcr & CR_OCIEN)) { imx_epit_reload_compare_timer(s); ptimer_run(s->timer_cmp, 0); } } else { ptimer_stop(s->timer_cmp); } break; case 1: /* SR - ACK*/ /* writing 1 to OCIF clear the OCIF bit */ if (value & 0x01) { s->sr = 0; imx_epit_update_int(s); } break; case 2: /* LR - set ticks */ s->lr = value; if (s->cr & CR_RLD) { /* Also set the limit if the LRD bit is set */ /* If IOVW bit is set then set the timer value */ ptimer_set_limit(s->timer_reload, s->lr, s->cr & CR_IOVW); ptimer_set_limit(s->timer_cmp, s->lr, 0); } else if (s->cr & CR_IOVW) { /* If IOVW bit is set then set the timer value */ ptimer_set_count(s->timer_reload, s->lr); } imx_epit_reload_compare_timer(s); break; case 3: /* CMP */ s->cmp = value; imx_epit_reload_compare_timer(s); break; default: IPRINTF("Bad offset %x\n", reg); break; } }
static void sh_timer_write(void *opaque, target_phys_addr_t offset, uint32_t value) { sh_timer_state *s = (sh_timer_state *)opaque; int freq; switch (offset >> 2) { case OFFSET_TCOR: s->tcor = value; ptimer_set_limit(s->timer, s->tcor, 0); break; case OFFSET_TCNT: s->tcnt = value; ptimer_set_count(s->timer, s->tcnt); break; case OFFSET_TCR: if (s->enabled) { /* Pause the timer if it is running. This may cause some inaccuracy dure to rounding, but avoids a whole lot of other messyness. */ ptimer_stop(s->timer); } freq = s->freq; /* ??? Need to recalculate expiry time after changing divisor. */ switch (value & TIMER_TCR_TPSC) { case 0: freq >>= 2; break; case 1: freq >>= 4; break; case 2: freq >>= 6; break; case 3: freq >>= 8; break; case 4: freq >>= 10; break; case 6: case 7: if (s->feat & TIMER_FEAT_EXTCLK) break; default: hw_error("sh_timer_write: Reserved TPSC value\n"); break; } switch ((value & TIMER_TCR_CKEG) >> 3) { case 0: break; case 1: case 2: case 3: if (s->feat & TIMER_FEAT_EXTCLK) break; default: hw_error("sh_timer_write: Reserved CKEG value\n"); break; } switch ((value & TIMER_TCR_ICPE) >> 6) { case 0: break; case 2: case 3: if (s->feat & TIMER_FEAT_CAPT) break; default: hw_error("sh_timer_write: Reserved ICPE value\n"); break; } if ((value & TIMER_TCR_UNF) == 0) s->int_level = 0; value &= ~TIMER_TCR_UNF; if ((value & TIMER_TCR_ICPF) && (!(s->feat & TIMER_FEAT_CAPT))) hw_error("sh_timer_write: Reserved ICPF value\n"); value &= ~TIMER_TCR_ICPF; /* capture not supported */ if (value & TIMER_TCR_RESERVED) hw_error("sh_timer_write: Reserved TCR bits set\n"); s->tcr = value; ptimer_set_limit(s->timer, s->tcor, 0); ptimer_set_freq(s->timer, freq); if (s->enabled) { /* Restart the timer if still enabled. */ ptimer_run(s->timer, 0); } break; case OFFSET_TCPR: if (s->feat & TIMER_FEAT_CAPT) { s->tcpr = value; break; } default: hw_error("sh_timer_write: Bad offset %x\n", (int)offset); } sh_timer_update(s); }