Beispiel #1
0
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;
    }
}
Beispiel #2
0
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;
    }
}
Beispiel #3
0
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);
}
Beispiel #4
0
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) && !t->running) {
                trace_slavio_timer_mem_writel_status_start(timer_index);
                ptimer_run(t->timer, 0);
                t->running = 1;
            } else if (!(val & 1) && t->running) {
                trace_slavio_timer_mem_writel_status_stop(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;
                        trace_slavio_timer_mem_writel_mode_user(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;
                        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;
    }
Beispiel #5
0
static void slavio_timer_mem_writel(void *opaque, target_phys_addr_t addr,
                                    uint32_t val)
{
    SLAVIO_TIMERState *s = opaque;
    uint32_t saddr;

    DPRINTF("write " TARGET_FMT_plx " %08x\n", addr, val);
    saddr = addr >> 2;
    switch (saddr) {
    case TIMER_LIMIT:
        if (slavio_timer_is_user(s)) {
            uint64_t count;

            // set user counter MSW, reset counter
            s->limit = TIMER_MAX_COUNT64;
            s->counthigh = val & (TIMER_MAX_COUNT64 >> 32);
            s->reached = 0;
            count = ((uint64_t)s->counthigh << 32) | s->count;
            DPRINTF("processor %d user timer set to %016llx\n", s->slave_index,
                    count);
            if (s->timer)
                ptimer_set_count(s->timer, LIMIT_TO_PERIODS(s->limit - count));
        } else {
            // set limit, reset counter
            qemu_irq_lower(s->irq);
            s->limit = val & TIMER_MAX_COUNT32;
            if (s->timer) {
                if (s->limit == 0) /* free-run */
                    ptimer_set_limit(s->timer,
                                     LIMIT_TO_PERIODS(TIMER_MAX_COUNT32), 1);
                else
                    ptimer_set_limit(s->timer, LIMIT_TO_PERIODS(s->limit), 1);
            }
        }
        break;
    case TIMER_COUNTER:
        if (slavio_timer_is_user(s)) {
            uint64_t count;

            // set user counter LSW, reset counter
            s->limit = TIMER_MAX_COUNT64;
            s->count = val & TIMER_MAX_COUNT64;
            s->reached = 0;
            count = ((uint64_t)s->counthigh) << 32 | s->count;
            DPRINTF("processor %d user timer set to %016llx\n", s->slave_index,
                    count);
            if (s->timer)
                ptimer_set_count(s->timer, LIMIT_TO_PERIODS(s->limit - count));
        } else
            DPRINTF("not user timer\n");
        break;
    case TIMER_COUNTER_NORST:
        // set limit without resetting counter
        s->limit = val & TIMER_MAX_COUNT32;
        if (s->timer) {
            if (s->limit == 0)	/* free-run */
                ptimer_set_limit(s->timer,
                                 LIMIT_TO_PERIODS(TIMER_MAX_COUNT32), 0);
            else
                ptimer_set_limit(s->timer, LIMIT_TO_PERIODS(s->limit), 0);
        }
        break;
    case TIMER_STATUS:
        if (slavio_timer_is_user(s)) {
            // start/stop user counter
            if ((val & 1) && !s->running) {
                DPRINTF("processor %d user timer started\n", s->slave_index);
                if (s->timer)
                    ptimer_run(s->timer, 0);
                s->running = 1;
            } else if (!(val & 1) && s->running) {
                DPRINTF("processor %d user timer stopped\n", s->slave_index);
                if (s->timer)
                    ptimer_stop(s->timer);
                s->running = 0;
            }
        }
        break;
    case TIMER_MODE:
        if (s->master == NULL) {
            unsigned int i;

            for (i = 0; i < s->num_slaves; i++) {
                unsigned int processor = 1 << i;

                // check for a change in timer mode for this processor
                if ((val & processor) != (s->slave_mode & processor)) {
                    if (val & processor) { // counter -> user timer
                        qemu_irq_lower(s->slave[i]->irq);
                        // counters are always running
                        ptimer_stop(s->slave[i]->timer);
                        s->slave[i]->running = 0;
                        // user timer limit is always the same
                        s->slave[i]->limit = TIMER_MAX_COUNT64;
                        ptimer_set_limit(s->slave[i]->timer,
                                         LIMIT_TO_PERIODS(s->slave[i]->limit),
                                         1);
                        // set this processors user timer bit in config
                        // register
                        s->slave_mode |= processor;
                        DPRINTF("processor %d changed from counter to user "
                                "timer\n", s->slave[i]->slave_index);
                    } else { // user timer -> counter
                        // stop the user timer if it is running
                        if (s->slave[i]->running)
                            ptimer_stop(s->slave[i]->timer);
                        // start the counter
                        ptimer_run(s->slave[i]->timer, 0);
                        s->slave[i]->running = 1;
                        // clear this processors user timer bit in config
                        // register
                        s->slave_mode &= ~processor;
                        DPRINTF("processor %d changed from user timer to "
                                "counter\n", s->slave[i]->slave_index);
                    }
                }
            }
        } else
            DPRINTF("not system timer\n");
        break;
    default:
        DPRINTF("invalid write address " TARGET_FMT_plx "\n", addr);
        break;
    }
Beispiel #6
0
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;
    }
}
Beispiel #7
0
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;
    }
Beispiel #8
0
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;
    }
}