diff options
author | 2017-04-25 03:31:15 -0700 | |
---|---|---|
committer | 2017-05-22 06:48:08 +0000 | |
commit | bb756eebdac6fd24e8919e2c43f7d2c8c4091f59 (patch) | |
tree | ca11e03542edf2d8f631efeca5e1626d211107e3 /qemu/hw/timer | |
parent | a14b48d18a9ed03ec191cf16b162206998a895ce (diff) |
Adding qemu as a submodule of KVMFORNFV
This Patch includes the changes to add qemu as a submodule to
kvmfornfv repo and make use of the updated latest qemu for the
execution of all testcase
Change-Id: I1280af507a857675c7f81d30c95255635667bdd7
Signed-off-by:RajithaY<rajithax.yerrumsetty@intel.com>
Diffstat (limited to 'qemu/hw/timer')
33 files changed, 0 insertions, 14696 deletions
diff --git a/qemu/hw/timer/Makefile.objs b/qemu/hw/timer/Makefile.objs deleted file mode 100644 index 003c14fa2..000000000 --- a/qemu/hw/timer/Makefile.objs +++ /dev/null @@ -1,35 +0,0 @@ -common-obj-$(CONFIG_ARM_TIMER) += arm_timer.o -common-obj-$(CONFIG_ARM_MPTIMER) += arm_mptimer.o -common-obj-$(CONFIG_A9_GTIMER) += a9gtimer.o -common-obj-$(CONFIG_CADENCE) += cadence_ttc.o -common-obj-$(CONFIG_DS1338) += ds1338.o -common-obj-$(CONFIG_HPET) += hpet.o -common-obj-$(CONFIG_I8254) += i8254_common.o i8254.o -common-obj-$(CONFIG_M48T59) += m48t59.o -common-obj-$(CONFIG_PL031) += pl031.o -common-obj-$(CONFIG_PUV3) += puv3_ost.o -common-obj-$(CONFIG_TWL92230) += twl92230.o -common-obj-$(CONFIG_XILINX) += xilinx_timer.o -common-obj-$(CONFIG_SLAVIO) += slavio_timer.o -common-obj-$(CONFIG_ETRAXFS) += etraxfs_timer.o -common-obj-$(CONFIG_GRLIB) += grlib_gptimer.o -common-obj-$(CONFIG_IMX) += imx_epit.o -common-obj-$(CONFIG_IMX) += imx_gpt.o -common-obj-$(CONFIG_LM32) += lm32_timer.o -common-obj-$(CONFIG_MILKYMIST) += milkymist-sysctl.o - -obj-$(CONFIG_EXYNOS4) += exynos4210_mct.o -obj-$(CONFIG_EXYNOS4) += exynos4210_pwm.o -obj-$(CONFIG_EXYNOS4) += exynos4210_rtc.o -obj-$(CONFIG_OMAP) += omap_gptimer.o -obj-$(CONFIG_OMAP) += omap_synctimer.o -obj-$(CONFIG_PXA2XX) += pxa2xx_timer.o -obj-$(CONFIG_SH4) += sh_timer.o -obj-$(CONFIG_DIGIC) += digic-timer.o - -obj-$(CONFIG_MC146818RTC) += mc146818rtc.o - -obj-$(CONFIG_ALLWINNER_A10_PIT) += allwinner-a10-pit.o - -common-obj-$(CONFIG_STM32F2XX_TIMER) += stm32f2xx_timer.o -common-obj-$(CONFIG_ASPEED_SOC) += aspeed_timer.o diff --git a/qemu/hw/timer/a9gtimer.c b/qemu/hw/timer/a9gtimer.c deleted file mode 100644 index afe577c76..000000000 --- a/qemu/hw/timer/a9gtimer.c +++ /dev/null @@ -1,372 +0,0 @@ -/* - * Global peripheral timer block for ARM A9MP - * - * (C) 2013 Xilinx Inc. - * - * Written by François LEGAL - * Written by Peter Crosthwaite <peter.crosthwaite@xilinx.com> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, see <http://www.gnu.org/licenses/>. - */ - -#include "qemu/osdep.h" -#include "hw/timer/a9gtimer.h" -#include "qapi/error.h" -#include "qemu/timer.h" -#include "qemu/bitops.h" -#include "qemu/log.h" -#include "qom/cpu.h" - -#ifndef A9_GTIMER_ERR_DEBUG -#define A9_GTIMER_ERR_DEBUG 0 -#endif - -#define DB_PRINT_L(level, ...) do { \ - if (A9_GTIMER_ERR_DEBUG > (level)) { \ - fprintf(stderr, ": %s: ", __func__); \ - fprintf(stderr, ## __VA_ARGS__); \ - } \ -} while (0); - -#define DB_PRINT(...) DB_PRINT_L(0, ## __VA_ARGS__) - -static inline int a9_gtimer_get_current_cpu(A9GTimerState *s) -{ - if (current_cpu->cpu_index >= s->num_cpu) { - hw_error("a9gtimer: num-cpu %d but this cpu is %d!\n", - s->num_cpu, current_cpu->cpu_index); - } - return current_cpu->cpu_index; -} - -static inline uint64_t a9_gtimer_get_conv(A9GTimerState *s) -{ - uint64_t prescale = extract32(s->control, R_CONTROL_PRESCALER_SHIFT, - R_CONTROL_PRESCALER_LEN); - - return (prescale + 1) * 10; -} - -static A9GTimerUpdate a9_gtimer_get_update(A9GTimerState *s) -{ - A9GTimerUpdate ret; - - ret.now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); - ret.new = s->ref_counter + - (ret.now - s->cpu_ref_time) / a9_gtimer_get_conv(s); - return ret; -} - -static void a9_gtimer_update(A9GTimerState *s, bool sync) -{ - - A9GTimerUpdate update = a9_gtimer_get_update(s); - int i; - int64_t next_cdiff = 0; - - for (i = 0; i < s->num_cpu; ++i) { - A9GTimerPerCPU *gtb = &s->per_cpu[i]; - int64_t cdiff = 0; - - if ((s->control & R_CONTROL_TIMER_ENABLE) && - (gtb->control & R_CONTROL_COMP_ENABLE)) { - /* R2p0+, where the compare function is >= */ - while (gtb->compare < update.new) { - DB_PRINT("Compare event happened for CPU %d\n", i); - gtb->status = 1; - if (gtb->control & R_CONTROL_AUTO_INCREMENT) { - DB_PRINT("Auto incrementing timer compare by %" PRId32 "\n", - gtb->inc); - gtb->compare += gtb->inc; - } else { - break; - } - } - cdiff = (int64_t)gtb->compare - (int64_t)update.new + 1; - if (cdiff > 0 && (cdiff < next_cdiff || !next_cdiff)) { - next_cdiff = cdiff; - } - } - - qemu_set_irq(gtb->irq, - gtb->status && (gtb->control & R_CONTROL_IRQ_ENABLE)); - } - - timer_del(s->timer); - if (next_cdiff) { - DB_PRINT("scheduling qemu_timer to fire again in %" - PRIx64 " cycles\n", next_cdiff); - timer_mod(s->timer, update.now + next_cdiff * a9_gtimer_get_conv(s)); - } - - if (s->control & R_CONTROL_TIMER_ENABLE) { - s->counter = update.new; - } - - if (sync) { - s->cpu_ref_time = update.now; - s->ref_counter = s->counter; - } -} - -static void a9_gtimer_update_no_sync(void *opaque) -{ - A9GTimerState *s = A9_GTIMER(opaque); - - a9_gtimer_update(s, false); -} - -static uint64_t a9_gtimer_read(void *opaque, hwaddr addr, unsigned size) -{ - A9GTimerPerCPU *gtb = (A9GTimerPerCPU *)opaque; - A9GTimerState *s = gtb->parent; - A9GTimerUpdate update; - uint64_t ret = 0; - int shift = 0; - - switch (addr) { - case R_COUNTER_HI: - shift = 32; - /* fallthrough */ - case R_COUNTER_LO: - update = a9_gtimer_get_update(s); - ret = extract64(update.new, shift, 32); - break; - case R_CONTROL: - ret = s->control | gtb->control; - break; - case R_INTERRUPT_STATUS: - ret = gtb->status; - break; - case R_COMPARATOR_HI: - shift = 32; - /* fallthrough */ - case R_COMPARATOR_LO: - ret = extract64(gtb->compare, shift, 32); - break; - case R_AUTO_INCREMENT: - ret = gtb->inc; - break; - default: - qemu_log_mask(LOG_GUEST_ERROR, "bad a9gtimer register: %x\n", - (unsigned)addr); - return 0; - } - - DB_PRINT("addr:%#x data:%#08" PRIx64 "\n", (unsigned)addr, ret); - return ret; -} - -static void a9_gtimer_write(void *opaque, hwaddr addr, uint64_t value, - unsigned size) -{ - A9GTimerPerCPU *gtb = (A9GTimerPerCPU *)opaque; - A9GTimerState *s = gtb->parent; - int shift = 0; - - DB_PRINT("addr:%#x data:%#08" PRIx64 "\n", (unsigned)addr, value); - - switch (addr) { - case R_COUNTER_HI: - shift = 32; - /* fallthrough */ - case R_COUNTER_LO: - /* - * Keep it simple - ARM docco explicitly says to disable timer before - * modding it, so dont bother trying to do all the difficult on the fly - * timer modifications - (if they even work in real hardware??). - */ - if (s->control & R_CONTROL_TIMER_ENABLE) { - qemu_log_mask(LOG_GUEST_ERROR, "Cannot mod running ARM gtimer\n"); - return; - } - s->counter = deposit64(s->counter, shift, 32, value); - return; - case R_CONTROL: - a9_gtimer_update(s, (value ^ s->control) & R_CONTROL_NEEDS_SYNC); - gtb->control = value & R_CONTROL_BANKED; - s->control = value & ~R_CONTROL_BANKED; - break; - case R_INTERRUPT_STATUS: - a9_gtimer_update(s, false); - gtb->status &= ~value; - break; - case R_COMPARATOR_HI: - shift = 32; - /* fallthrough */ - case R_COMPARATOR_LO: - a9_gtimer_update(s, false); - gtb->compare = deposit64(gtb->compare, shift, 32, value); - break; - case R_AUTO_INCREMENT: - gtb->inc = value; - return; - default: - return; - } - - a9_gtimer_update(s, false); -} - -/* Wrapper functions to implement the "read global timer for - * the current CPU" memory regions. - */ -static uint64_t a9_gtimer_this_read(void *opaque, hwaddr addr, - unsigned size) -{ - A9GTimerState *s = A9_GTIMER(opaque); - int id = a9_gtimer_get_current_cpu(s); - - /* no \n so concatenates with message from read fn */ - DB_PRINT("CPU:%d:", id); - - return a9_gtimer_read(&s->per_cpu[id], addr, size); -} - -static void a9_gtimer_this_write(void *opaque, hwaddr addr, - uint64_t value, unsigned size) -{ - A9GTimerState *s = A9_GTIMER(opaque); - int id = a9_gtimer_get_current_cpu(s); - - /* no \n so concatenates with message from write fn */ - DB_PRINT("CPU:%d:", id); - - a9_gtimer_write(&s->per_cpu[id], addr, value, size); -} - -static const MemoryRegionOps a9_gtimer_this_ops = { - .read = a9_gtimer_this_read, - .write = a9_gtimer_this_write, - .valid = { - .min_access_size = 4, - .max_access_size = 4, - }, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static const MemoryRegionOps a9_gtimer_ops = { - .read = a9_gtimer_read, - .write = a9_gtimer_write, - .valid = { - .min_access_size = 4, - .max_access_size = 4, - }, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static void a9_gtimer_reset(DeviceState *dev) -{ - A9GTimerState *s = A9_GTIMER(dev); - int i; - - s->counter = 0; - s->control = 0; - - for (i = 0; i < s->num_cpu; i++) { - A9GTimerPerCPU *gtb = &s->per_cpu[i]; - - gtb->control = 0; - gtb->status = 0; - gtb->compare = 0; - gtb->inc = 0; - } - a9_gtimer_update(s, false); -} - -static void a9_gtimer_realize(DeviceState *dev, Error **errp) -{ - A9GTimerState *s = A9_GTIMER(dev); - SysBusDevice *sbd = SYS_BUS_DEVICE(dev); - int i; - - if (s->num_cpu < 1 || s->num_cpu > A9_GTIMER_MAX_CPUS) { - error_setg(errp, "%s: num-cpu must be between 1 and %d", - __func__, A9_GTIMER_MAX_CPUS); - return; - } - - memory_region_init_io(&s->iomem, OBJECT(dev), &a9_gtimer_this_ops, s, - "a9gtimer shared", 0x20); - sysbus_init_mmio(sbd, &s->iomem); - s->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, a9_gtimer_update_no_sync, s); - - for (i = 0; i < s->num_cpu; i++) { - A9GTimerPerCPU *gtb = &s->per_cpu[i]; - - gtb->parent = s; - sysbus_init_irq(sbd, >b->irq); - memory_region_init_io(>b->iomem, OBJECT(dev), &a9_gtimer_ops, gtb, - "a9gtimer per cpu", 0x20); - sysbus_init_mmio(sbd, >b->iomem); - } -} - -static const VMStateDescription vmstate_a9_gtimer_per_cpu = { - .name = "arm.cortex-a9-global-timer.percpu", - .version_id = 1, - .minimum_version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_UINT32(control, A9GTimerPerCPU), - VMSTATE_UINT64(compare, A9GTimerPerCPU), - VMSTATE_UINT32(status, A9GTimerPerCPU), - VMSTATE_UINT32(inc, A9GTimerPerCPU), - VMSTATE_END_OF_LIST() - } -}; - -static const VMStateDescription vmstate_a9_gtimer = { - .name = "arm.cortex-a9-global-timer", - .version_id = 1, - .minimum_version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_TIMER_PTR(timer, A9GTimerState), - VMSTATE_UINT64(counter, A9GTimerState), - VMSTATE_UINT64(ref_counter, A9GTimerState), - VMSTATE_UINT64(cpu_ref_time, A9GTimerState), - VMSTATE_STRUCT_VARRAY_UINT32(per_cpu, A9GTimerState, num_cpu, - 1, vmstate_a9_gtimer_per_cpu, - A9GTimerPerCPU), - VMSTATE_END_OF_LIST() - } -}; - -static Property a9_gtimer_properties[] = { - DEFINE_PROP_UINT32("num-cpu", A9GTimerState, num_cpu, 0), - DEFINE_PROP_END_OF_LIST() -}; - -static void a9_gtimer_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - - dc->realize = a9_gtimer_realize; - dc->vmsd = &vmstate_a9_gtimer; - dc->reset = a9_gtimer_reset; - dc->props = a9_gtimer_properties; -} - -static const TypeInfo a9_gtimer_info = { - .name = TYPE_A9_GTIMER, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(A9GTimerState), - .class_init = a9_gtimer_class_init, -}; - -static void a9_gtimer_register_types(void) -{ - type_register_static(&a9_gtimer_info); -} - -type_init(a9_gtimer_register_types) diff --git a/qemu/hw/timer/allwinner-a10-pit.c b/qemu/hw/timer/allwinner-a10-pit.c deleted file mode 100644 index 51cdc98f3..000000000 --- a/qemu/hw/timer/allwinner-a10-pit.c +++ /dev/null @@ -1,296 +0,0 @@ -/* - * Allwinner A10 timer device emulation - * - * Copyright (C) 2013 Li Guang - * Written by Li Guang <lig.fnst@cn.fujitsu.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include "qemu/osdep.h" -#include "hw/sysbus.h" -#include "sysemu/sysemu.h" -#include "hw/timer/allwinner-a10-pit.h" - -static void a10_pit_update_irq(AwA10PITState *s) -{ - int i; - - for (i = 0; i < AW_A10_PIT_TIMER_NR; i++) { - qemu_set_irq(s->irq[i], !!(s->irq_status & s->irq_enable & (1 << i))); - } -} - -static uint64_t a10_pit_read(void *opaque, hwaddr offset, unsigned size) -{ - AwA10PITState *s = AW_A10_PIT(opaque); - uint8_t index; - - switch (offset) { - case AW_A10_PIT_TIMER_IRQ_EN: - return s->irq_enable; - case AW_A10_PIT_TIMER_IRQ_ST: - return s->irq_status; - 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: - return s->control[index]; - case AW_A10_PIT_TIMER_INTERVAL: - return s->interval[index]; - case AW_A10_PIT_TIMER_COUNT: - s->count[index] = ptimer_get_count(s->timer[index]); - return s->count[index]; - default: - qemu_log_mask(LOG_GUEST_ERROR, - "%s: Bad offset 0x%x\n", __func__, (int)offset); - break; - } - case AW_A10_PIT_WDOG_CONTROL: - break; - case AW_A10_PIT_WDOG_MODE: - break; - case AW_A10_PIT_COUNT_LO: - return s->count_lo; - case AW_A10_PIT_COUNT_HI: - return s->count_hi; - case AW_A10_PIT_COUNT_CTL: - return s->count_ctl; - default: - qemu_log_mask(LOG_GUEST_ERROR, - "%s: Bad offset 0x%x\n", __func__, (int)offset); - break; - } - - return 0; -} - -static void a10_pit_set_freq(AwA10PITState *s, int index) -{ - uint32_t prescaler, source, source_freq; - - prescaler = 1 << extract32(s->control[index], 4, 3); - source = extract32(s->control[index], 2, 2); - source_freq = s->clk_freq[source]; - - if (source_freq) { - ptimer_set_freq(s->timer[index], source_freq / prescaler); - } else { - qemu_log_mask(LOG_GUEST_ERROR, "%s: Invalid clock source %u\n", - __func__, source); - } -} - -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 const MemoryRegionOps a10_pit_ops = { - .read = a10_pit_read, - .write = a10_pit_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static Property a10_pit_properties[] = { - DEFINE_PROP_UINT32("clk0-freq", AwA10PITState, clk_freq[0], 0), - DEFINE_PROP_UINT32("clk1-freq", AwA10PITState, clk_freq[1], 0), - DEFINE_PROP_UINT32("clk2-freq", AwA10PITState, clk_freq[2], 0), - DEFINE_PROP_UINT32("clk3-freq", AwA10PITState, clk_freq[3], 0), - DEFINE_PROP_END_OF_LIST(), -}; - -static const VMStateDescription vmstate_a10_pit = { - .name = "a10.pit", - .version_id = 1, - .minimum_version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_UINT32(irq_enable, AwA10PITState), - VMSTATE_UINT32(irq_status, AwA10PITState), - VMSTATE_UINT32_ARRAY(control, AwA10PITState, AW_A10_PIT_TIMER_NR), - VMSTATE_UINT32_ARRAY(interval, AwA10PITState, AW_A10_PIT_TIMER_NR), - VMSTATE_UINT32_ARRAY(count, AwA10PITState, AW_A10_PIT_TIMER_NR), - VMSTATE_UINT32(watch_dog_mode, AwA10PITState), - VMSTATE_UINT32(watch_dog_control, AwA10PITState), - VMSTATE_UINT32(count_lo, AwA10PITState), - VMSTATE_UINT32(count_hi, AwA10PITState), - VMSTATE_UINT32(count_ctl, AwA10PITState), - VMSTATE_PTIMER_ARRAY(timer, AwA10PITState, AW_A10_PIT_TIMER_NR), - VMSTATE_END_OF_LIST() - } -}; - -static void a10_pit_reset(DeviceState *dev) -{ - AwA10PITState *s = AW_A10_PIT(dev); - uint8_t i; - - s->irq_enable = 0; - s->irq_status = 0; - a10_pit_update_irq(s); - - for (i = 0; i < 6; i++) { - s->control[i] = AW_A10_PIT_DEFAULT_CLOCK; - s->interval[i] = 0; - s->count[i] = 0; - ptimer_stop(s->timer[i]); - a10_pit_set_freq(s, i); - } - s->watch_dog_mode = 0; - s->watch_dog_control = 0; - s->count_lo = 0; - s->count_hi = 0; - s->count_ctl = 0; -} - -static void a10_pit_timer_cb(void *opaque) -{ - AwA10TimerContext *tc = opaque; - AwA10PITState *s = tc->container; - uint8_t i = tc->index; - - if (s->control[i] & AW_A10_PIT_TIMER_EN) { - s->irq_status |= 1 << i; - if (s->control[i] & AW_A10_PIT_TIMER_MODE) { - ptimer_stop(s->timer[i]); - s->control[i] &= ~AW_A10_PIT_TIMER_EN; - } - a10_pit_update_irq(s); - } -} - -static void a10_pit_init(Object *obj) -{ - AwA10PITState *s = AW_A10_PIT(obj); - SysBusDevice *sbd = SYS_BUS_DEVICE(obj); - QEMUBH * bh[AW_A10_PIT_TIMER_NR]; - uint8_t i; - - for (i = 0; i < AW_A10_PIT_TIMER_NR; i++) { - sysbus_init_irq(sbd, &s->irq[i]); - } - memory_region_init_io(&s->iomem, OBJECT(s), &a10_pit_ops, s, - TYPE_AW_A10_PIT, 0x400); - sysbus_init_mmio(sbd, &s->iomem); - - for (i = 0; i < AW_A10_PIT_TIMER_NR; i++) { - AwA10TimerContext *tc = &s->timer_context[i]; - - tc->container = s; - tc->index = i; - bh[i] = qemu_bh_new(a10_pit_timer_cb, tc); - s->timer[i] = ptimer_init(bh[i]); - } -} - -static void a10_pit_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - - dc->reset = a10_pit_reset; - dc->props = a10_pit_properties; - dc->desc = "allwinner a10 timer"; - dc->vmsd = &vmstate_a10_pit; -} - -static const TypeInfo a10_pit_info = { - .name = TYPE_AW_A10_PIT, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(AwA10PITState), - .instance_init = a10_pit_init, - .class_init = a10_pit_class_init, -}; - -static void a10_register_types(void) -{ - type_register_static(&a10_pit_info); -} - -type_init(a10_register_types); diff --git a/qemu/hw/timer/arm_mptimer.c b/qemu/hw/timer/arm_mptimer.c deleted file mode 100644 index d66bbf01b..000000000 --- a/qemu/hw/timer/arm_mptimer.c +++ /dev/null @@ -1,303 +0,0 @@ -/* - * Private peripheral timer/watchdog blocks for ARM 11MPCore and A9MP - * - * Copyright (c) 2006-2007 CodeSourcery. - * Copyright (c) 2011 Linaro Limited - * Written by Paul Brook, Peter Maydell - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, see <http://www.gnu.org/licenses/>. - */ - -#include "qemu/osdep.h" -#include "hw/timer/arm_mptimer.h" -#include "qapi/error.h" -#include "qemu/timer.h" -#include "qom/cpu.h" - -/* This device implements the per-cpu private timer and watchdog block - * which is used in both the ARM11MPCore and Cortex-A9MP. - */ - -static inline int get_current_cpu(ARMMPTimerState *s) -{ - if (current_cpu->cpu_index >= s->num_cpu) { - hw_error("arm_mptimer: num-cpu %d but this cpu is %d!\n", - s->num_cpu, current_cpu->cpu_index); - } - return current_cpu->cpu_index; -} - -static inline void timerblock_update_irq(TimerBlock *tb) -{ - qemu_set_irq(tb->irq, tb->status && (tb->control & 4)); -} - -/* Return conversion factor from mpcore timer ticks to qemu timer ticks. */ -static inline uint32_t timerblock_scale(TimerBlock *tb) -{ - return (((tb->control >> 8) & 0xff) + 1) * 10; -} - -static void timerblock_reload(TimerBlock *tb, int restart) -{ - if (tb->count == 0) { - return; - } - if (restart) { - tb->tick = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); - } - tb->tick += (int64_t)tb->count * timerblock_scale(tb); - timer_mod(tb->timer, tb->tick); -} - -static void timerblock_tick(void *opaque) -{ - TimerBlock *tb = (TimerBlock *)opaque; - tb->status = 1; - if (tb->control & 2) { - tb->count = tb->load; - timerblock_reload(tb, 0); - } else { - tb->count = 0; - } - timerblock_update_irq(tb); -} - -static uint64_t timerblock_read(void *opaque, hwaddr addr, - unsigned size) -{ - TimerBlock *tb = (TimerBlock *)opaque; - int64_t val; - switch (addr) { - case 0: /* Load */ - return tb->load; - case 4: /* Counter. */ - if (((tb->control & 1) == 0) || (tb->count == 0)) { - return 0; - } - /* Slow and ugly, but hopefully won't happen too often. */ - val = tb->tick - qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); - val /= timerblock_scale(tb); - if (val < 0) { - val = 0; - } - return val; - case 8: /* Control. */ - return tb->control; - case 12: /* Interrupt status. */ - return tb->status; - default: - return 0; - } -} - -static void timerblock_write(void *opaque, hwaddr addr, - uint64_t value, unsigned size) -{ - TimerBlock *tb = (TimerBlock *)opaque; - int64_t old; - switch (addr) { - case 0: /* Load */ - tb->load = value; - /* Fall through. */ - case 4: /* Counter. */ - if ((tb->control & 1) && tb->count) { - /* Cancel the previous timer. */ - timer_del(tb->timer); - } - tb->count = value; - if (tb->control & 1) { - timerblock_reload(tb, 1); - } - break; - case 8: /* Control. */ - old = tb->control; - tb->control = value; - if (value & 1) { - if ((old & 1) && (tb->count != 0)) { - /* Do nothing if timer is ticking right now. */ - break; - } - if (tb->control & 2) { - tb->count = tb->load; - } - timerblock_reload(tb, 1); - } else if (old & 1) { - /* Shutdown the timer. */ - timer_del(tb->timer); - } - break; - case 12: /* Interrupt status. */ - tb->status &= ~value; - timerblock_update_irq(tb); - break; - } -} - -/* Wrapper functions to implement the "read timer/watchdog for - * the current CPU" memory regions. - */ -static uint64_t arm_thistimer_read(void *opaque, hwaddr addr, - unsigned size) -{ - ARMMPTimerState *s = (ARMMPTimerState *)opaque; - int id = get_current_cpu(s); - return timerblock_read(&s->timerblock[id], addr, size); -} - -static void arm_thistimer_write(void *opaque, hwaddr addr, - uint64_t value, unsigned size) -{ - ARMMPTimerState *s = (ARMMPTimerState *)opaque; - int id = get_current_cpu(s); - timerblock_write(&s->timerblock[id], addr, value, size); -} - -static const MemoryRegionOps arm_thistimer_ops = { - .read = arm_thistimer_read, - .write = arm_thistimer_write, - .valid = { - .min_access_size = 4, - .max_access_size = 4, - }, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static const MemoryRegionOps timerblock_ops = { - .read = timerblock_read, - .write = timerblock_write, - .valid = { - .min_access_size = 4, - .max_access_size = 4, - }, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static void timerblock_reset(TimerBlock *tb) -{ - tb->count = 0; - tb->load = 0; - tb->control = 0; - tb->status = 0; - tb->tick = 0; - if (tb->timer) { - timer_del(tb->timer); - } -} - -static void arm_mptimer_reset(DeviceState *dev) -{ - ARMMPTimerState *s = ARM_MPTIMER(dev); - int i; - - for (i = 0; i < ARRAY_SIZE(s->timerblock); i++) { - timerblock_reset(&s->timerblock[i]); - } -} - -static void arm_mptimer_init(Object *obj) -{ - ARMMPTimerState *s = ARM_MPTIMER(obj); - - memory_region_init_io(&s->iomem, obj, &arm_thistimer_ops, s, - "arm_mptimer_timer", 0x20); - sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->iomem); -} - -static void arm_mptimer_realize(DeviceState *dev, Error **errp) -{ - SysBusDevice *sbd = SYS_BUS_DEVICE(dev); - ARMMPTimerState *s = ARM_MPTIMER(dev); - int i; - - if (s->num_cpu < 1 || s->num_cpu > ARM_MPTIMER_MAX_CPUS) { - error_setg(errp, "num-cpu must be between 1 and %d", - ARM_MPTIMER_MAX_CPUS); - return; - } - /* We implement one timer block per CPU, and expose multiple MMIO regions: - * * region 0 is "timer for this core" - * * region 1 is "timer for core 0" - * * region 2 is "timer for core 1" - * and so on. - * The outgoing interrupt lines are - * * timer for core 0 - * * timer for core 1 - * and so on. - */ - for (i = 0; i < s->num_cpu; i++) { - TimerBlock *tb = &s->timerblock[i]; - tb->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, timerblock_tick, tb); - sysbus_init_irq(sbd, &tb->irq); - memory_region_init_io(&tb->iomem, OBJECT(s), &timerblock_ops, tb, - "arm_mptimer_timerblock", 0x20); - sysbus_init_mmio(sbd, &tb->iomem); - } -} - -static const VMStateDescription vmstate_timerblock = { - .name = "arm_mptimer_timerblock", - .version_id = 2, - .minimum_version_id = 2, - .fields = (VMStateField[]) { - VMSTATE_UINT32(count, TimerBlock), - VMSTATE_UINT32(load, TimerBlock), - VMSTATE_UINT32(control, TimerBlock), - VMSTATE_UINT32(status, TimerBlock), - VMSTATE_INT64(tick, TimerBlock), - VMSTATE_TIMER_PTR(timer, TimerBlock), - VMSTATE_END_OF_LIST() - } -}; - -static const VMStateDescription vmstate_arm_mptimer = { - .name = "arm_mptimer", - .version_id = 2, - .minimum_version_id = 2, - .fields = (VMStateField[]) { - VMSTATE_STRUCT_VARRAY_UINT32(timerblock, ARMMPTimerState, num_cpu, - 2, vmstate_timerblock, TimerBlock), - VMSTATE_END_OF_LIST() - } -}; - -static Property arm_mptimer_properties[] = { - DEFINE_PROP_UINT32("num-cpu", ARMMPTimerState, num_cpu, 0), - DEFINE_PROP_END_OF_LIST() -}; - -static void arm_mptimer_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - - dc->realize = arm_mptimer_realize; - dc->vmsd = &vmstate_arm_mptimer; - dc->reset = arm_mptimer_reset; - dc->props = arm_mptimer_properties; -} - -static const TypeInfo arm_mptimer_info = { - .name = TYPE_ARM_MPTIMER, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(ARMMPTimerState), - .instance_init = arm_mptimer_init, - .class_init = arm_mptimer_class_init, -}; - -static void arm_mptimer_register_types(void) -{ - type_register_static(&arm_mptimer_info); -} - -type_init(arm_mptimer_register_types) diff --git a/qemu/hw/timer/arm_timer.c b/qemu/hw/timer/arm_timer.c deleted file mode 100644 index f1ede5f53..000000000 --- a/qemu/hw/timer/arm_timer.c +++ /dev/null @@ -1,409 +0,0 @@ -/* - * ARM PrimeCell Timer modules. - * - * Copyright (c) 2005-2006 CodeSourcery. - * Written by Paul Brook - * - * This code is licensed under the GPL. - */ - -#include "qemu/osdep.h" -#include "hw/sysbus.h" -#include "qemu/timer.h" -#include "qemu-common.h" -#include "hw/qdev.h" -#include "hw/ptimer.h" -#include "qemu/main-loop.h" - -/* Common timer implementation. */ - -#define TIMER_CTRL_ONESHOT (1 << 0) -#define TIMER_CTRL_32BIT (1 << 1) -#define TIMER_CTRL_DIV1 (0 << 2) -#define TIMER_CTRL_DIV16 (1 << 2) -#define TIMER_CTRL_DIV256 (2 << 2) -#define TIMER_CTRL_IE (1 << 5) -#define TIMER_CTRL_PERIODIC (1 << 6) -#define TIMER_CTRL_ENABLE (1 << 7) - -typedef struct { - ptimer_state *timer; - uint32_t control; - uint32_t limit; - int freq; - int int_level; - qemu_irq irq; -} arm_timer_state; - -/* Check all active timers, and schedule the next timer interrupt. */ - -static void arm_timer_update(arm_timer_state *s) -{ - /* Update interrupts. */ - if (s->int_level && (s->control & TIMER_CTRL_IE)) { - qemu_irq_raise(s->irq); - } else { - qemu_irq_lower(s->irq); - } -} - -static uint32_t arm_timer_read(void *opaque, hwaddr offset) -{ - arm_timer_state *s = (arm_timer_state *)opaque; - - switch (offset >> 2) { - case 0: /* TimerLoad */ - case 6: /* TimerBGLoad */ - return s->limit; - case 1: /* TimerValue */ - return ptimer_get_count(s->timer); - case 2: /* TimerControl */ - return s->control; - case 4: /* TimerRIS */ - return s->int_level; - case 5: /* TimerMIS */ - if ((s->control & TIMER_CTRL_IE) == 0) - return 0; - return s->int_level; - default: - qemu_log_mask(LOG_GUEST_ERROR, - "%s: Bad offset %x\n", __func__, (int)offset); - return 0; - } -} - -/* Reset the timer limit after settings have changed. */ -static void arm_timer_recalibrate(arm_timer_state *s, int reload) -{ - uint32_t limit; - - if ((s->control & (TIMER_CTRL_PERIODIC | TIMER_CTRL_ONESHOT)) == 0) { - /* Free running. */ - if (s->control & TIMER_CTRL_32BIT) - limit = 0xffffffff; - else - limit = 0xffff; - } else { - /* Periodic. */ - limit = s->limit; - } - ptimer_set_limit(s->timer, limit, reload); -} - -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 arm_timer_tick(void *opaque) -{ - arm_timer_state *s = (arm_timer_state *)opaque; - s->int_level = 1; - arm_timer_update(s); -} - -static const VMStateDescription vmstate_arm_timer = { - .name = "arm_timer", - .version_id = 1, - .minimum_version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_UINT32(control, arm_timer_state), - VMSTATE_UINT32(limit, arm_timer_state), - VMSTATE_INT32(int_level, arm_timer_state), - VMSTATE_PTIMER(timer, arm_timer_state), - VMSTATE_END_OF_LIST() - } -}; - -static arm_timer_state *arm_timer_init(uint32_t freq) -{ - arm_timer_state *s; - QEMUBH *bh; - - s = (arm_timer_state *)g_malloc0(sizeof(arm_timer_state)); - s->freq = freq; - s->control = TIMER_CTRL_IE; - - bh = qemu_bh_new(arm_timer_tick, s); - s->timer = ptimer_init(bh); - vmstate_register(NULL, -1, &vmstate_arm_timer, s); - return s; -} - -/* ARM PrimeCell SP804 dual timer module. - * Docs at - * http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0271d/index.html -*/ - -#define TYPE_SP804 "sp804" -#define SP804(obj) OBJECT_CHECK(SP804State, (obj), TYPE_SP804) - -typedef struct SP804State { - SysBusDevice parent_obj; - - MemoryRegion iomem; - arm_timer_state *timer[2]; - uint32_t freq0, freq1; - int level[2]; - qemu_irq irq; -} SP804State; - -static const uint8_t sp804_ids[] = { - /* Timer ID */ - 0x04, 0x18, 0x14, 0, - /* PrimeCell ID */ - 0xd, 0xf0, 0x05, 0xb1 -}; - -/* Merge the IRQs from the two component devices. */ -static void sp804_set_irq(void *opaque, int irq, int level) -{ - SP804State *s = (SP804State *)opaque; - - s->level[irq] = level; - qemu_set_irq(s->irq, s->level[0] || s->level[1]); -} - -static uint64_t sp804_read(void *opaque, hwaddr offset, - unsigned size) -{ - SP804State *s = (SP804State *)opaque; - - if (offset < 0x20) { - return arm_timer_read(s->timer[0], offset); - } - if (offset < 0x40) { - return arm_timer_read(s->timer[1], offset - 0x20); - } - - /* TimerPeriphID */ - if (offset >= 0xfe0 && offset <= 0xffc) { - return sp804_ids[(offset - 0xfe0) >> 2]; - } - - switch (offset) { - /* Integration Test control registers, which we won't support */ - case 0xf00: /* TimerITCR */ - case 0xf04: /* TimerITOP (strictly write only but..) */ - qemu_log_mask(LOG_UNIMP, - "%s: integration test registers unimplemented\n", - __func__); - return 0; - } - - qemu_log_mask(LOG_GUEST_ERROR, - "%s: Bad offset %x\n", __func__, (int)offset); - return 0; -} - -static void sp804_write(void *opaque, hwaddr offset, - uint64_t value, unsigned size) -{ - SP804State *s = (SP804State *)opaque; - - if (offset < 0x20) { - arm_timer_write(s->timer[0], offset, value); - return; - } - - if (offset < 0x40) { - arm_timer_write(s->timer[1], offset - 0x20, value); - return; - } - - /* Technically we could be writing to the Test Registers, but not likely */ - qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset %x\n", - __func__, (int)offset); -} - -static const MemoryRegionOps sp804_ops = { - .read = sp804_read, - .write = sp804_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static const VMStateDescription vmstate_sp804 = { - .name = "sp804", - .version_id = 1, - .minimum_version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_INT32_ARRAY(level, SP804State, 2), - VMSTATE_END_OF_LIST() - } -}; - -static void sp804_init(Object *obj) -{ - SP804State *s = SP804(obj); - SysBusDevice *sbd = SYS_BUS_DEVICE(obj); - - sysbus_init_irq(sbd, &s->irq); - memory_region_init_io(&s->iomem, obj, &sp804_ops, s, - "sp804", 0x1000); - sysbus_init_mmio(sbd, &s->iomem); -} - -static void sp804_realize(DeviceState *dev, Error **errp) -{ - SP804State *s = SP804(dev); - - s->timer[0] = arm_timer_init(s->freq0); - s->timer[1] = arm_timer_init(s->freq1); - s->timer[0]->irq = qemu_allocate_irq(sp804_set_irq, s, 0); - s->timer[1]->irq = qemu_allocate_irq(sp804_set_irq, s, 1); -} - -/* Integrator/CP timer module. */ - -#define TYPE_INTEGRATOR_PIT "integrator_pit" -#define INTEGRATOR_PIT(obj) \ - OBJECT_CHECK(icp_pit_state, (obj), TYPE_INTEGRATOR_PIT) - -typedef struct { - SysBusDevice parent_obj; - - MemoryRegion iomem; - arm_timer_state *timer[3]; -} icp_pit_state; - -static uint64_t icp_pit_read(void *opaque, hwaddr offset, - unsigned size) -{ - icp_pit_state *s = (icp_pit_state *)opaque; - int n; - - /* ??? Don't know the PrimeCell ID for this device. */ - n = offset >> 8; - if (n > 2) { - qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad timer %d\n", __func__, n); - return 0; - } - - return arm_timer_read(s->timer[n], offset & 0xff); -} - -static void icp_pit_write(void *opaque, hwaddr offset, - uint64_t value, unsigned size) -{ - icp_pit_state *s = (icp_pit_state *)opaque; - int n; - - n = offset >> 8; - if (n > 2) { - qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad timer %d\n", __func__, n); - return; - } - - arm_timer_write(s->timer[n], offset & 0xff, value); -} - -static const MemoryRegionOps icp_pit_ops = { - .read = icp_pit_read, - .write = icp_pit_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static void icp_pit_init(Object *obj) -{ - icp_pit_state *s = INTEGRATOR_PIT(obj); - SysBusDevice *dev = SYS_BUS_DEVICE(obj); - - /* Timer 0 runs at the system clock speed (40MHz). */ - s->timer[0] = arm_timer_init(40000000); - /* The other two timers run at 1MHz. */ - s->timer[1] = arm_timer_init(1000000); - s->timer[2] = arm_timer_init(1000000); - - sysbus_init_irq(dev, &s->timer[0]->irq); - sysbus_init_irq(dev, &s->timer[1]->irq); - sysbus_init_irq(dev, &s->timer[2]->irq); - - memory_region_init_io(&s->iomem, obj, &icp_pit_ops, s, - "icp_pit", 0x1000); - sysbus_init_mmio(dev, &s->iomem); - /* This device has no state to save/restore. The component timers will - save themselves. */ -} - -static const TypeInfo icp_pit_info = { - .name = TYPE_INTEGRATOR_PIT, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(icp_pit_state), - .instance_init = icp_pit_init, -}; - -static Property sp804_properties[] = { - DEFINE_PROP_UINT32("freq0", SP804State, freq0, 1000000), - DEFINE_PROP_UINT32("freq1", SP804State, freq1, 1000000), - DEFINE_PROP_END_OF_LIST(), -}; - -static void sp804_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *k = DEVICE_CLASS(klass); - - k->realize = sp804_realize; - k->props = sp804_properties; - k->vmsd = &vmstate_sp804; -} - -static const TypeInfo sp804_info = { - .name = TYPE_SP804, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(SP804State), - .instance_init = sp804_init, - .class_init = sp804_class_init, -}; - -static void arm_timer_register_types(void) -{ - type_register_static(&icp_pit_info); - type_register_static(&sp804_info); -} - -type_init(arm_timer_register_types) diff --git a/qemu/hw/timer/aspeed_timer.c b/qemu/hw/timer/aspeed_timer.c deleted file mode 100644 index 51e8303cd..000000000 --- a/qemu/hw/timer/aspeed_timer.c +++ /dev/null @@ -1,449 +0,0 @@ -/* - * ASPEED AST2400 Timer - * - * Andrew Jeffery <andrew@aj.id.au> - * - * Copyright (C) 2016 IBM Corp. - * - * This code is licensed under the GPL version 2 or later. See - * the COPYING file in the top-level directory. - */ - -#include "qemu/osdep.h" -#include "hw/ptimer.h" -#include "hw/sysbus.h" -#include "hw/timer/aspeed_timer.h" -#include "qemu-common.h" -#include "qemu/bitops.h" -#include "qemu/main-loop.h" -#include "qemu/timer.h" -#include "trace.h" - -#define TIMER_NR_REGS 4 - -#define TIMER_CTRL_BITS 4 -#define TIMER_CTRL_MASK ((1 << TIMER_CTRL_BITS) - 1) - -#define TIMER_CLOCK_USE_EXT true -#define TIMER_CLOCK_EXT_HZ 1000000 -#define TIMER_CLOCK_USE_APB false -#define TIMER_CLOCK_APB_HZ 24000000 - -#define TIMER_REG_STATUS 0 -#define TIMER_REG_RELOAD 1 -#define TIMER_REG_MATCH_FIRST 2 -#define TIMER_REG_MATCH_SECOND 3 - -#define TIMER_FIRST_CAP_PULSE 4 - -enum timer_ctrl_op { - op_enable = 0, - op_external_clock, - op_overflow_interrupt, - op_pulse_enable -}; - -/** - * Avoid mutual references between AspeedTimerCtrlState and AspeedTimer - * structs, as it's a waste of memory. The ptimer BH callback needs to know - * whether a specific AspeedTimer is enabled, but this information is held in - * AspeedTimerCtrlState. So, provide a helper to hoist ourselves from an - * arbitrary AspeedTimer to AspeedTimerCtrlState. - */ -static inline AspeedTimerCtrlState *timer_to_ctrl(AspeedTimer *t) -{ - const AspeedTimer (*timers)[] = (void *)t - (t->id * sizeof(*t)); - return container_of(timers, AspeedTimerCtrlState, timers); -} - -static inline bool timer_ctrl_status(AspeedTimer *t, enum timer_ctrl_op op) -{ - return !!(timer_to_ctrl(t)->ctrl & BIT(t->id * TIMER_CTRL_BITS + op)); -} - -static inline bool timer_enabled(AspeedTimer *t) -{ - return timer_ctrl_status(t, op_enable); -} - -static inline bool timer_overflow_interrupt(AspeedTimer *t) -{ - return timer_ctrl_status(t, op_overflow_interrupt); -} - -static inline bool timer_can_pulse(AspeedTimer *t) -{ - return t->id >= TIMER_FIRST_CAP_PULSE; -} - -static void aspeed_timer_expire(void *opaque) -{ - AspeedTimer *t = opaque; - - /* Only support interrupts on match values of zero for the moment - this is - * sufficient to boot an aspeed_defconfig Linux kernel. - * - * TODO: matching on arbitrary values (see e.g. hw/timer/a9gtimer.c) - */ - bool match = !(t->match[0] && t->match[1]); - bool interrupt = timer_overflow_interrupt(t) || match; - if (timer_enabled(t) && interrupt) { - t->level = !t->level; - qemu_set_irq(t->irq, t->level); - } -} - -static uint64_t aspeed_timer_get_value(AspeedTimer *t, int reg) -{ - uint64_t value; - - switch (reg) { - case TIMER_REG_STATUS: - value = ptimer_get_count(t->timer); - break; - case TIMER_REG_RELOAD: - value = t->reload; - break; - case TIMER_REG_MATCH_FIRST: - case TIMER_REG_MATCH_SECOND: - value = t->match[reg - 2]; - break; - default: - qemu_log_mask(LOG_UNIMP, "%s: Programming error: unexpected reg: %d\n", - __func__, reg); - value = 0; - break; - } - return value; -} - -static uint64_t aspeed_timer_read(void *opaque, hwaddr offset, unsigned size) -{ - AspeedTimerCtrlState *s = opaque; - const int reg = (offset & 0xf) / 4; - uint64_t value; - - switch (offset) { - case 0x30: /* Control Register */ - value = s->ctrl; - break; - case 0x34: /* Control Register 2 */ - value = s->ctrl2; - break; - case 0x00 ... 0x2c: /* Timers 1 - 4 */ - value = aspeed_timer_get_value(&s->timers[(offset >> 4)], reg); - break; - case 0x40 ... 0x8c: /* Timers 5 - 8 */ - value = aspeed_timer_get_value(&s->timers[(offset >> 4) - 1], reg); - break; - /* Illegal */ - case 0x38: - case 0x3C: - default: - qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIx "\n", - __func__, offset); - value = 0; - break; - } - trace_aspeed_timer_read(offset, size, value); - return value; -} - -static void aspeed_timer_set_value(AspeedTimerCtrlState *s, int timer, int reg, - uint32_t value) -{ - AspeedTimer *t; - - trace_aspeed_timer_set_value(timer, reg, value); - t = &s->timers[timer]; - switch (reg) { - case TIMER_REG_STATUS: - if (timer_enabled(t)) { - ptimer_set_count(t->timer, value); - } - break; - case TIMER_REG_RELOAD: - t->reload = value; - ptimer_set_limit(t->timer, value, 1); - break; - case TIMER_REG_MATCH_FIRST: - case TIMER_REG_MATCH_SECOND: - if (value) { - /* Non-zero match values are unsupported. As such an interrupt will - * always be triggered when the timer reaches zero even if the - * overflow interrupt control bit is clear. - */ - qemu_log_mask(LOG_UNIMP, "%s: Match value unsupported by device: " - "0x%" PRIx32 "\n", __func__, value); - } else { - t->match[reg - 2] = value; - } - break; - default: - qemu_log_mask(LOG_UNIMP, "%s: Programming error: unexpected reg: %d\n", - __func__, reg); - break; - } -} - -/* Control register operations are broken out into helpers that can be - * explictly called on aspeed_timer_reset(), but also from - * aspeed_timer_ctrl_op(). - */ - -static void aspeed_timer_ctrl_enable(AspeedTimer *t, bool enable) -{ - trace_aspeed_timer_ctrl_enable(t->id, enable); - if (enable) { - ptimer_run(t->timer, 0); - } else { - ptimer_stop(t->timer); - ptimer_set_limit(t->timer, t->reload, 1); - } -} - -static void aspeed_timer_ctrl_external_clock(AspeedTimer *t, bool enable) -{ - trace_aspeed_timer_ctrl_external_clock(t->id, enable); - if (enable) { - ptimer_set_freq(t->timer, TIMER_CLOCK_EXT_HZ); - } else { - ptimer_set_freq(t->timer, TIMER_CLOCK_APB_HZ); - } -} - -static void aspeed_timer_ctrl_overflow_interrupt(AspeedTimer *t, bool enable) -{ - trace_aspeed_timer_ctrl_overflow_interrupt(t->id, enable); -} - -static void aspeed_timer_ctrl_pulse_enable(AspeedTimer *t, bool enable) -{ - if (timer_can_pulse(t)) { - trace_aspeed_timer_ctrl_pulse_enable(t->id, enable); - } else { - qemu_log_mask(LOG_GUEST_ERROR, - "%s: Timer does not support pulse mode\n", __func__); - } -} - -/** - * Given the actions are fixed in number and completely described in helper - * functions, dispatch with a lookup table rather than manage control flow with - * a switch statement. - */ -static void (*const ctrl_ops[])(AspeedTimer *, bool) = { - [op_enable] = aspeed_timer_ctrl_enable, - [op_external_clock] = aspeed_timer_ctrl_external_clock, - [op_overflow_interrupt] = aspeed_timer_ctrl_overflow_interrupt, - [op_pulse_enable] = aspeed_timer_ctrl_pulse_enable, -}; - -/** - * Conditionally affect changes chosen by a timer's control bit. - * - * The aspeed_timer_ctrl_op() interface is convenient for the - * aspeed_timer_set_ctrl() function as the "no change" early exit can be - * calculated for all operations, which cleans up the caller code. However the - * interface isn't convenient for the reset function where we want to enter a - * specific state without artificially constructing old and new values that - * will fall through the change guard (and motivates extracting the actions - * out to helper functions). - * - * @t: The timer to manipulate - * @op: The type of operation to be performed - * @old: The old state of the timer's control bits - * @new: The incoming state for the timer's control bits - */ -static void aspeed_timer_ctrl_op(AspeedTimer *t, enum timer_ctrl_op op, - uint8_t old, uint8_t new) -{ - const uint8_t mask = BIT(op); - const bool enable = !!(new & mask); - const bool changed = ((old ^ new) & mask); - if (!changed) { - return; - } - ctrl_ops[op](t, enable); -} - -static void aspeed_timer_set_ctrl(AspeedTimerCtrlState *s, uint32_t reg) -{ - int i; - int shift; - uint8_t t_old, t_new; - AspeedTimer *t; - const uint8_t enable_mask = BIT(op_enable); - - /* Handle a dependency between the 'enable' and remaining three - * configuration bits - i.e. if more than one bit in the control set has - * changed, including the 'enable' bit, then we want either disable the - * timer and perform configuration, or perform configuration and then - * enable the timer - */ - for (i = 0; i < ASPEED_TIMER_NR_TIMERS; i++) { - t = &s->timers[i]; - shift = (i * TIMER_CTRL_BITS); - t_old = (s->ctrl >> shift) & TIMER_CTRL_MASK; - t_new = (reg >> shift) & TIMER_CTRL_MASK; - - /* If we are disabling, do so first */ - if ((t_old & enable_mask) && !(t_new & enable_mask)) { - aspeed_timer_ctrl_enable(t, false); - } - aspeed_timer_ctrl_op(t, op_external_clock, t_old, t_new); - aspeed_timer_ctrl_op(t, op_overflow_interrupt, t_old, t_new); - aspeed_timer_ctrl_op(t, op_pulse_enable, t_old, t_new); - /* If we are enabling, do so last */ - if (!(t_old & enable_mask) && (t_new & enable_mask)) { - aspeed_timer_ctrl_enable(t, true); - } - } - s->ctrl = reg; -} - -static void aspeed_timer_set_ctrl2(AspeedTimerCtrlState *s, uint32_t value) -{ - trace_aspeed_timer_set_ctrl2(value); -} - -static void aspeed_timer_write(void *opaque, hwaddr offset, uint64_t value, - unsigned size) -{ - const uint32_t tv = (uint32_t)(value & 0xFFFFFFFF); - const int reg = (offset & 0xf) / 4; - AspeedTimerCtrlState *s = opaque; - - switch (offset) { - /* Control Registers */ - case 0x30: - aspeed_timer_set_ctrl(s, tv); - break; - case 0x34: - aspeed_timer_set_ctrl2(s, tv); - break; - /* Timer Registers */ - case 0x00 ... 0x2c: - aspeed_timer_set_value(s, (offset >> TIMER_NR_REGS), reg, tv); - break; - case 0x40 ... 0x8c: - aspeed_timer_set_value(s, (offset >> TIMER_NR_REGS) - 1, reg, tv); - break; - /* Illegal */ - case 0x38: - case 0x3C: - default: - qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIx "\n", - __func__, offset); - break; - } -} - -static const MemoryRegionOps aspeed_timer_ops = { - .read = aspeed_timer_read, - .write = aspeed_timer_write, - .endianness = DEVICE_LITTLE_ENDIAN, - .valid.min_access_size = 4, - .valid.max_access_size = 4, - .valid.unaligned = false, -}; - -static void aspeed_init_one_timer(AspeedTimerCtrlState *s, uint8_t id) -{ - QEMUBH *bh; - AspeedTimer *t = &s->timers[id]; - - t->id = id; - bh = qemu_bh_new(aspeed_timer_expire, t); - t->timer = ptimer_init(bh); -} - -static void aspeed_timer_realize(DeviceState *dev, Error **errp) -{ - int i; - SysBusDevice *sbd = SYS_BUS_DEVICE(dev); - AspeedTimerCtrlState *s = ASPEED_TIMER(dev); - - for (i = 0; i < ASPEED_TIMER_NR_TIMERS; i++) { - aspeed_init_one_timer(s, i); - sysbus_init_irq(sbd, &s->timers[i].irq); - } - memory_region_init_io(&s->iomem, OBJECT(s), &aspeed_timer_ops, s, - TYPE_ASPEED_TIMER, 0x1000); - sysbus_init_mmio(sbd, &s->iomem); -} - -static void aspeed_timer_reset(DeviceState *dev) -{ - int i; - AspeedTimerCtrlState *s = ASPEED_TIMER(dev); - - for (i = 0; i < ASPEED_TIMER_NR_TIMERS; i++) { - AspeedTimer *t = &s->timers[i]; - /* Explictly call helpers to avoid any conditional behaviour through - * aspeed_timer_set_ctrl(). - */ - aspeed_timer_ctrl_enable(t, false); - aspeed_timer_ctrl_external_clock(t, TIMER_CLOCK_USE_APB); - aspeed_timer_ctrl_overflow_interrupt(t, false); - aspeed_timer_ctrl_pulse_enable(t, false); - t->level = 0; - t->reload = 0; - t->match[0] = 0; - t->match[1] = 0; - } - s->ctrl = 0; - s->ctrl2 = 0; -} - -static const VMStateDescription vmstate_aspeed_timer = { - .name = "aspeed.timer", - .version_id = 1, - .minimum_version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_UINT8(id, AspeedTimer), - VMSTATE_INT32(level, AspeedTimer), - VMSTATE_PTIMER(timer, AspeedTimer), - VMSTATE_UINT32(reload, AspeedTimer), - VMSTATE_UINT32_ARRAY(match, AspeedTimer, 2), - VMSTATE_END_OF_LIST() - } -}; - -static const VMStateDescription vmstate_aspeed_timer_state = { - .name = "aspeed.timerctrl", - .version_id = 1, - .minimum_version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_UINT32(ctrl, AspeedTimerCtrlState), - VMSTATE_UINT32(ctrl2, AspeedTimerCtrlState), - VMSTATE_STRUCT_ARRAY(timers, AspeedTimerCtrlState, - ASPEED_TIMER_NR_TIMERS, 1, vmstate_aspeed_timer, - AspeedTimer), - VMSTATE_END_OF_LIST() - } -}; - -static void timer_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - - dc->realize = aspeed_timer_realize; - dc->reset = aspeed_timer_reset; - dc->desc = "ASPEED Timer"; - dc->vmsd = &vmstate_aspeed_timer_state; -} - -static const TypeInfo aspeed_timer_info = { - .name = TYPE_ASPEED_TIMER, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(AspeedTimerCtrlState), - .class_init = timer_class_init, -}; - -static void aspeed_timer_register_types(void) -{ - type_register_static(&aspeed_timer_info); -} - -type_init(aspeed_timer_register_types) diff --git a/qemu/hw/timer/cadence_ttc.c b/qemu/hw/timer/cadence_ttc.c deleted file mode 100644 index 03f5b9c20..000000000 --- a/qemu/hw/timer/cadence_ttc.c +++ /dev/null @@ -1,492 +0,0 @@ -/* - * Xilinx Zynq cadence TTC model - * - * Copyright (c) 2011 Xilinx Inc. - * Copyright (c) 2012 Peter A.G. Crosthwaite (peter.crosthwaite@petalogix.com) - * Copyright (c) 2012 PetaLogix Pty Ltd. - * Written By Haibing Ma - * M. Habib - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, see <http://www.gnu.org/licenses/>. - */ - -#include "qemu/osdep.h" -#include "hw/sysbus.h" -#include "qemu/timer.h" - -#ifdef CADENCE_TTC_ERR_DEBUG -#define DB_PRINT(...) do { \ - fprintf(stderr, ": %s: ", __func__); \ - fprintf(stderr, ## __VA_ARGS__); \ - } while (0); -#else - #define DB_PRINT(...) -#endif - -#define COUNTER_INTR_IV 0x00000001 -#define COUNTER_INTR_M1 0x00000002 -#define COUNTER_INTR_M2 0x00000004 -#define COUNTER_INTR_M3 0x00000008 -#define COUNTER_INTR_OV 0x00000010 -#define COUNTER_INTR_EV 0x00000020 - -#define COUNTER_CTRL_DIS 0x00000001 -#define COUNTER_CTRL_INT 0x00000002 -#define COUNTER_CTRL_DEC 0x00000004 -#define COUNTER_CTRL_MATCH 0x00000008 -#define COUNTER_CTRL_RST 0x00000010 - -#define CLOCK_CTRL_PS_EN 0x00000001 -#define CLOCK_CTRL_PS_V 0x0000001e - -typedef struct { - QEMUTimer *timer; - int freq; - - uint32_t reg_clock; - uint32_t reg_count; - uint32_t reg_value; - uint16_t reg_interval; - uint16_t reg_match[3]; - uint32_t reg_intr; - uint32_t reg_intr_en; - uint32_t reg_event_ctrl; - uint32_t reg_event; - - uint64_t cpu_time; - unsigned int cpu_time_valid; - - qemu_irq irq; -} CadenceTimerState; - -#define TYPE_CADENCE_TTC "cadence_ttc" -#define CADENCE_TTC(obj) \ - OBJECT_CHECK(CadenceTTCState, (obj), TYPE_CADENCE_TTC) - -typedef struct CadenceTTCState { - SysBusDevice parent_obj; - - MemoryRegion iomem; - CadenceTimerState timer[3]; -} CadenceTTCState; - -static void cadence_timer_update(CadenceTimerState *s) -{ - qemu_set_irq(s->irq, !!(s->reg_intr & s->reg_intr_en)); -} - -static CadenceTimerState *cadence_timer_from_addr(void *opaque, - hwaddr offset) -{ - unsigned int index; - CadenceTTCState *s = (CadenceTTCState *)opaque; - - index = (offset >> 2) % 3; - - return &s->timer[index]; -} - -static uint64_t cadence_timer_get_ns(CadenceTimerState *s, uint64_t timer_steps) -{ - /* timer_steps has max value of 0x100000000. double check it - * (or overflow can happen below) */ - assert(timer_steps <= 1ULL << 32); - - uint64_t r = timer_steps * 1000000000ULL; - if (s->reg_clock & CLOCK_CTRL_PS_EN) { - r >>= 16 - (((s->reg_clock & CLOCK_CTRL_PS_V) >> 1) + 1); - } else { - r >>= 16; - } - r /= (uint64_t)s->freq; - return r; -} - -static uint64_t cadence_timer_get_steps(CadenceTimerState *s, uint64_t ns) -{ - uint64_t to_divide = 1000000000ULL; - - uint64_t r = ns; - /* for very large intervals (> 8s) do some division first to stop - * overflow (costs some prescision) */ - while (r >= 8ULL << 30 && to_divide > 1) { - r /= 1000; - to_divide /= 1000; - } - r <<= 16; - /* keep early-dividing as needed */ - while (r >= 8ULL << 30 && to_divide > 1) { - r /= 1000; - to_divide /= 1000; - } - r *= (uint64_t)s->freq; - if (s->reg_clock & CLOCK_CTRL_PS_EN) { - r /= 1 << (((s->reg_clock & CLOCK_CTRL_PS_V) >> 1) + 1); - } - - r /= to_divide; - return r; -} - -/* determine if x is in between a and b, exclusive of a, inclusive of b */ - -static inline int64_t is_between(int64_t x, int64_t a, int64_t b) -{ - if (a < b) { - return x > a && x <= b; - } - return x < a && x >= b; -} - -static void cadence_timer_run(CadenceTimerState *s) -{ - int i; - int64_t event_interval, next_value; - - assert(s->cpu_time_valid); /* cadence_timer_sync must be called first */ - - if (s->reg_count & COUNTER_CTRL_DIS) { - s->cpu_time_valid = 0; - return; - } - - { /* figure out what's going to happen next (rollover or match) */ - int64_t interval = (uint64_t)((s->reg_count & COUNTER_CTRL_INT) ? - (int64_t)s->reg_interval + 1 : 0x10000ULL) << 16; - next_value = (s->reg_count & COUNTER_CTRL_DEC) ? -1ULL : interval; - for (i = 0; i < 3; ++i) { - int64_t cand = (uint64_t)s->reg_match[i] << 16; - if (is_between(cand, (uint64_t)s->reg_value, next_value)) { - next_value = cand; - } - } - } - DB_PRINT("next timer event value: %09llx\n", - (unsigned long long)next_value); - - event_interval = next_value - (int64_t)s->reg_value; - event_interval = (event_interval < 0) ? -event_interval : event_interval; - - timer_mod(s->timer, s->cpu_time + - cadence_timer_get_ns(s, event_interval)); -} - -static void cadence_timer_sync(CadenceTimerState *s) -{ - int i; - int64_t r, x; - int64_t interval = ((s->reg_count & COUNTER_CTRL_INT) ? - (int64_t)s->reg_interval + 1 : 0x10000ULL) << 16; - uint64_t old_time = s->cpu_time; - - s->cpu_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); - DB_PRINT("cpu time: %lld ns\n", (long long)old_time); - - if (!s->cpu_time_valid || old_time == s->cpu_time) { - s->cpu_time_valid = 1; - return; - } - - r = (int64_t)cadence_timer_get_steps(s, s->cpu_time - old_time); - x = (int64_t)s->reg_value + ((s->reg_count & COUNTER_CTRL_DEC) ? -r : r); - - for (i = 0; i < 3; ++i) { - int64_t m = (int64_t)s->reg_match[i] << 16; - if (m > interval) { - continue; - } - /* check to see if match event has occurred. check m +/- interval - * to account for match events in wrap around cases */ - if (is_between(m, s->reg_value, x) || - is_between(m + interval, s->reg_value, x) || - is_between(m - interval, s->reg_value, x)) { - s->reg_intr |= (2 << i); - } - } - if ((x < 0) || (x >= interval)) { - s->reg_intr |= (s->reg_count & COUNTER_CTRL_INT) ? - COUNTER_INTR_IV : COUNTER_INTR_OV; - } - while (x < 0) { - x += interval; - } - s->reg_value = (uint32_t)(x % interval); - cadence_timer_update(s); -} - -static void cadence_timer_tick(void *opaque) -{ - CadenceTimerState *s = opaque; - - DB_PRINT("\n"); - cadence_timer_sync(s); - cadence_timer_run(s); -} - -static uint32_t cadence_ttc_read_imp(void *opaque, hwaddr offset) -{ - CadenceTimerState *s = cadence_timer_from_addr(opaque, offset); - uint32_t value; - - cadence_timer_sync(s); - cadence_timer_run(s); - - switch (offset) { - case 0x00: /* clock control */ - case 0x04: - case 0x08: - return s->reg_clock; - - case 0x0c: /* counter control */ - case 0x10: - case 0x14: - return s->reg_count; - - case 0x18: /* counter value */ - case 0x1c: - case 0x20: - return (uint16_t)(s->reg_value >> 16); - - case 0x24: /* reg_interval counter */ - case 0x28: - case 0x2c: - return s->reg_interval; - - case 0x30: /* match 1 counter */ - case 0x34: - case 0x38: - return s->reg_match[0]; - - case 0x3c: /* match 2 counter */ - case 0x40: - case 0x44: - return s->reg_match[1]; - - case 0x48: /* match 3 counter */ - case 0x4c: - case 0x50: - return s->reg_match[2]; - - case 0x54: /* interrupt register */ - case 0x58: - case 0x5c: - /* cleared after read */ - value = s->reg_intr; - s->reg_intr = 0; - cadence_timer_update(s); - return value; - - case 0x60: /* interrupt enable */ - case 0x64: - case 0x68: - return s->reg_intr_en; - - case 0x6c: - case 0x70: - case 0x74: - return s->reg_event_ctrl; - - case 0x78: - case 0x7c: - case 0x80: - return s->reg_event; - - default: - return 0; - } -} - -static uint64_t cadence_ttc_read(void *opaque, hwaddr offset, - unsigned size) -{ - uint32_t ret = cadence_ttc_read_imp(opaque, offset); - - DB_PRINT("addr: %08x data: %08x\n", (unsigned)offset, (unsigned)ret); - return ret; -} - -static void cadence_ttc_write(void *opaque, hwaddr offset, - uint64_t value, unsigned size) -{ - CadenceTimerState *s = cadence_timer_from_addr(opaque, offset); - - DB_PRINT("addr: %08x data %08x\n", (unsigned)offset, (unsigned)value); - - cadence_timer_sync(s); - - switch (offset) { - case 0x00: /* clock control */ - case 0x04: - case 0x08: - s->reg_clock = value & 0x3F; - break; - - case 0x0c: /* counter control */ - case 0x10: - case 0x14: - if (value & COUNTER_CTRL_RST) { - s->reg_value = 0; - } - s->reg_count = value & 0x3f & ~COUNTER_CTRL_RST; - break; - - case 0x24: /* interval register */ - case 0x28: - case 0x2c: - s->reg_interval = value & 0xffff; - break; - - case 0x30: /* match register */ - case 0x34: - case 0x38: - s->reg_match[0] = value & 0xffff; - break; - - case 0x3c: /* match register */ - case 0x40: - case 0x44: - s->reg_match[1] = value & 0xffff; - break; - - case 0x48: /* match register */ - case 0x4c: - case 0x50: - s->reg_match[2] = value & 0xffff; - break; - - case 0x54: /* interrupt register */ - case 0x58: - case 0x5c: - break; - - case 0x60: /* interrupt enable */ - case 0x64: - case 0x68: - s->reg_intr_en = value & 0x3f; - break; - - case 0x6c: /* event control */ - case 0x70: - case 0x74: - s->reg_event_ctrl = value & 0x07; - break; - - default: - return; - } - - cadence_timer_run(s); - cadence_timer_update(s); -} - -static const MemoryRegionOps cadence_ttc_ops = { - .read = cadence_ttc_read, - .write = cadence_ttc_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static void cadence_timer_reset(CadenceTimerState *s) -{ - s->reg_count = 0x21; -} - -static void cadence_timer_init(uint32_t freq, CadenceTimerState *s) -{ - memset(s, 0, sizeof(CadenceTimerState)); - s->freq = freq; - - cadence_timer_reset(s); - - s->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, cadence_timer_tick, s); -} - -static void cadence_ttc_init(Object *obj) -{ - CadenceTTCState *s = CADENCE_TTC(obj); - int i; - - for (i = 0; i < 3; ++i) { - cadence_timer_init(133000000, &s->timer[i]); - sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->timer[i].irq); - } - - memory_region_init_io(&s->iomem, obj, &cadence_ttc_ops, s, - "timer", 0x1000); - sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->iomem); -} - -static void cadence_timer_pre_save(void *opaque) -{ - cadence_timer_sync((CadenceTimerState *)opaque); -} - -static int cadence_timer_post_load(void *opaque, int version_id) -{ - CadenceTimerState *s = opaque; - - s->cpu_time_valid = 0; - cadence_timer_sync(s); - cadence_timer_run(s); - cadence_timer_update(s); - return 0; -} - -static const VMStateDescription vmstate_cadence_timer = { - .name = "cadence_timer", - .version_id = 1, - .minimum_version_id = 1, - .pre_save = cadence_timer_pre_save, - .post_load = cadence_timer_post_load, - .fields = (VMStateField[]) { - VMSTATE_UINT32(reg_clock, CadenceTimerState), - VMSTATE_UINT32(reg_count, CadenceTimerState), - VMSTATE_UINT32(reg_value, CadenceTimerState), - VMSTATE_UINT16(reg_interval, CadenceTimerState), - VMSTATE_UINT16_ARRAY(reg_match, CadenceTimerState, 3), - VMSTATE_UINT32(reg_intr, CadenceTimerState), - VMSTATE_UINT32(reg_intr_en, CadenceTimerState), - VMSTATE_UINT32(reg_event_ctrl, CadenceTimerState), - VMSTATE_UINT32(reg_event, CadenceTimerState), - VMSTATE_END_OF_LIST() - } -}; - -static const VMStateDescription vmstate_cadence_ttc = { - .name = "cadence_TTC", - .version_id = 1, - .minimum_version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_STRUCT_ARRAY(timer, CadenceTTCState, 3, 0, - vmstate_cadence_timer, - CadenceTimerState), - VMSTATE_END_OF_LIST() - } -}; - -static void cadence_ttc_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - - dc->vmsd = &vmstate_cadence_ttc; -} - -static const TypeInfo cadence_ttc_info = { - .name = TYPE_CADENCE_TTC, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(CadenceTTCState), - .instance_init = cadence_ttc_init, - .class_init = cadence_ttc_class_init, -}; - -static void cadence_ttc_register_types(void) -{ - type_register_static(&cadence_ttc_info); -} - -type_init(cadence_ttc_register_types) diff --git a/qemu/hw/timer/digic-timer.c b/qemu/hw/timer/digic-timer.c deleted file mode 100644 index 5b97e1e1a..000000000 --- a/qemu/hw/timer/digic-timer.c +++ /dev/null @@ -1,163 +0,0 @@ -/* - * QEMU model of the Canon DIGIC timer block. - * - * Copyright (C) 2013 Antony Pavlov <antonynpavlov@gmail.com> - * - * This model is based on reverse engineering efforts - * made by CHDK (http://chdk.wikia.com) and - * Magic Lantern (http://www.magiclantern.fm) projects - * contributors. - * - * See "Timer/Clock Module" docs here: - * http://magiclantern.wikia.com/wiki/Register_Map - * - * The QEMU model of the OSTimer in PKUnity SoC by Guan Xuetao - * is used as a template. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#include "qemu/osdep.h" -#include "hw/sysbus.h" -#include "hw/ptimer.h" -#include "qemu/main-loop.h" - -#include "hw/timer/digic-timer.h" - -static const VMStateDescription vmstate_digic_timer = { - .name = "digic.timer", - .version_id = 1, - .minimum_version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_PTIMER(ptimer, DigicTimerState), - VMSTATE_UINT32(control, DigicTimerState), - VMSTATE_UINT32(relvalue, DigicTimerState), - VMSTATE_END_OF_LIST() - } -}; - -static void digic_timer_reset(DeviceState *dev) -{ - DigicTimerState *s = DIGIC_TIMER(dev); - - ptimer_stop(s->ptimer); - s->control = 0; - s->relvalue = 0; -} - -static uint64_t digic_timer_read(void *opaque, hwaddr offset, unsigned size) -{ - DigicTimerState *s = opaque; - uint64_t ret = 0; - - switch (offset) { - case DIGIC_TIMER_CONTROL: - ret = s->control; - break; - case DIGIC_TIMER_RELVALUE: - ret = s->relvalue; - break; - case DIGIC_TIMER_VALUE: - ret = ptimer_get_count(s->ptimer) & 0xffff; - break; - default: - qemu_log_mask(LOG_UNIMP, - "digic-timer: read access to unknown register 0x" - TARGET_FMT_plx, offset); - } - - return ret; -} - -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 const MemoryRegionOps digic_timer_ops = { - .read = digic_timer_read, - .write = digic_timer_write, - .impl = { - .min_access_size = 4, - .max_access_size = 4, - }, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static void digic_timer_init(Object *obj) -{ - DigicTimerState *s = DIGIC_TIMER(obj); - - s->ptimer = ptimer_init(NULL); - - /* - * FIXME: there is no documentation on Digic timer - * frequency setup so let it always run at 1 MHz - */ - ptimer_set_freq(s->ptimer, 1 * 1000 * 1000); - - memory_region_init_io(&s->iomem, OBJECT(s), &digic_timer_ops, s, - TYPE_DIGIC_TIMER, 0x100); - sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->iomem); -} - -static void digic_timer_class_init(ObjectClass *klass, void *class_data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - - dc->reset = digic_timer_reset; - dc->vmsd = &vmstate_digic_timer; -} - -static const TypeInfo digic_timer_info = { - .name = TYPE_DIGIC_TIMER, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(DigicTimerState), - .instance_init = digic_timer_init, - .class_init = digic_timer_class_init, -}; - -static void digic_timer_register_type(void) -{ - type_register_static(&digic_timer_info); -} - -type_init(digic_timer_register_type) diff --git a/qemu/hw/timer/ds1338.c b/qemu/hw/timer/ds1338.c deleted file mode 100644 index 0112949e2..000000000 --- a/qemu/hw/timer/ds1338.c +++ /dev/null @@ -1,243 +0,0 @@ -/* - * MAXIM DS1338 I2C RTC+NVRAM - * - * Copyright (c) 2009 CodeSourcery. - * Written by Paul Brook - * - * This code is licensed under the GNU GPL v2. - * - * Contributions after 2012-01-13 are licensed under the terms of the - * GNU GPL, version 2 or (at your option) any later version. - */ - -#include "qemu/osdep.h" -#include "qemu-common.h" -#include "hw/i2c/i2c.h" -#include "qemu/bcd.h" - -/* Size of NVRAM including both the user-accessible area and the - * secondary register area. - */ -#define NVRAM_SIZE 64 - -/* Flags definitions */ -#define SECONDS_CH 0x80 -#define HOURS_12 0x40 -#define HOURS_PM 0x20 -#define CTRL_OSF 0x20 - -#define TYPE_DS1338 "ds1338" -#define DS1338(obj) OBJECT_CHECK(DS1338State, (obj), TYPE_DS1338) - -typedef struct DS1338State { - I2CSlave parent_obj; - - int64_t offset; - uint8_t wday_offset; - uint8_t nvram[NVRAM_SIZE]; - int32_t ptr; - bool addr_byte; -} DS1338State; - -static const VMStateDescription vmstate_ds1338 = { - .name = "ds1338", - .version_id = 2, - .minimum_version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_I2C_SLAVE(parent_obj, DS1338State), - VMSTATE_INT64(offset, DS1338State), - VMSTATE_UINT8_V(wday_offset, DS1338State, 2), - VMSTATE_UINT8_ARRAY(nvram, DS1338State, NVRAM_SIZE), - VMSTATE_INT32(ptr, DS1338State), - VMSTATE_BOOL(addr_byte, DS1338State), - VMSTATE_END_OF_LIST() - } -}; - -static void capture_current_time(DS1338State *s) -{ - /* Capture the current time into the secondary registers - * which will be actually read by the data transfer operation. - */ - struct tm now; - qemu_get_timedate(&now, s->offset); - s->nvram[0] = to_bcd(now.tm_sec); - s->nvram[1] = to_bcd(now.tm_min); - if (s->nvram[2] & HOURS_12) { - int tmp = now.tm_hour; - if (tmp % 12 == 0) { - tmp += 12; - } - if (tmp <= 12) { - s->nvram[2] = HOURS_12 | to_bcd(tmp); - } else { - s->nvram[2] = HOURS_12 | HOURS_PM | to_bcd(tmp - 12); - } - } else { - s->nvram[2] = to_bcd(now.tm_hour); - } - s->nvram[3] = (now.tm_wday + s->wday_offset) % 7 + 1; - s->nvram[4] = to_bcd(now.tm_mday); - s->nvram[5] = to_bcd(now.tm_mon + 1); - s->nvram[6] = to_bcd(now.tm_year - 100); -} - -static void inc_regptr(DS1338State *s) -{ - /* The register pointer wraps around after 0x3F; wraparound - * causes the current time/date to be retransferred into - * the secondary registers. - */ - s->ptr = (s->ptr + 1) & (NVRAM_SIZE - 1); - if (!s->ptr) { - capture_current_time(s); - } -} - -static void ds1338_event(I2CSlave *i2c, enum i2c_event event) -{ - DS1338State *s = DS1338(i2c); - - switch (event) { - case I2C_START_RECV: - /* In h/w, capture happens on any START condition, not just a - * START_RECV, but there is no need to actually capture on - * START_SEND, because the guest can't get at that data - * without going through a START_RECV which would overwrite it. - */ - capture_current_time(s); - break; - case I2C_START_SEND: - s->addr_byte = true; - break; - default: - break; - } -} - -static int ds1338_recv(I2CSlave *i2c) -{ - DS1338State *s = DS1338(i2c); - uint8_t res; - - res = s->nvram[s->ptr]; - inc_regptr(s); - return res; -} - -static int ds1338_send(I2CSlave *i2c, uint8_t data) -{ - DS1338State *s = DS1338(i2c); - - if (s->addr_byte) { - s->ptr = data & (NVRAM_SIZE - 1); - s->addr_byte = false; - return 0; - } - if (s->ptr < 7) { - /* Time register. */ - struct tm now; - qemu_get_timedate(&now, s->offset); - switch(s->ptr) { - case 0: - /* TODO: Implement CH (stop) bit. */ - now.tm_sec = from_bcd(data & 0x7f); - break; - case 1: - now.tm_min = from_bcd(data & 0x7f); - break; - case 2: - if (data & HOURS_12) { - int tmp = from_bcd(data & (HOURS_PM - 1)); - if (data & HOURS_PM) { - tmp += 12; - } - if (tmp % 12 == 0) { - tmp -= 12; - } - now.tm_hour = tmp; - } else { - now.tm_hour = from_bcd(data & (HOURS_12 - 1)); - } - break; - case 3: - { - /* The day field is supposed to contain a value in - the range 1-7. Otherwise behavior is undefined. - */ - int user_wday = (data & 7) - 1; - s->wday_offset = (user_wday - now.tm_wday + 7) % 7; - } - break; - case 4: - now.tm_mday = from_bcd(data & 0x3f); - break; - case 5: - now.tm_mon = from_bcd(data & 0x1f) - 1; - break; - case 6: - now.tm_year = from_bcd(data) + 100; - break; - } - s->offset = qemu_timedate_diff(&now); - } else if (s->ptr == 7) { - /* Control register. */ - - /* Ensure bits 2, 3 and 6 will read back as zero. */ - data &= 0xB3; - - /* Attempting to write the OSF flag to logic 1 leaves the - value unchanged. */ - data = (data & ~CTRL_OSF) | (data & s->nvram[s->ptr] & CTRL_OSF); - - s->nvram[s->ptr] = data; - } else { - s->nvram[s->ptr] = data; - } - inc_regptr(s); - return 0; -} - -static int ds1338_init(I2CSlave *i2c) -{ - return 0; -} - -static void ds1338_reset(DeviceState *dev) -{ - DS1338State *s = DS1338(dev); - - /* The clock is running and synchronized with the host */ - s->offset = 0; - s->wday_offset = 0; - memset(s->nvram, 0, NVRAM_SIZE); - s->ptr = 0; - s->addr_byte = false; -} - -static void ds1338_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - I2CSlaveClass *k = I2C_SLAVE_CLASS(klass); - - k->init = ds1338_init; - k->event = ds1338_event; - k->recv = ds1338_recv; - k->send = ds1338_send; - dc->reset = ds1338_reset; - dc->vmsd = &vmstate_ds1338; -} - -static const TypeInfo ds1338_info = { - .name = TYPE_DS1338, - .parent = TYPE_I2C_SLAVE, - .instance_size = sizeof(DS1338State), - .class_init = ds1338_class_init, -}; - -static void ds1338_register_types(void) -{ - type_register_static(&ds1338_info); -} - -type_init(ds1338_register_types) diff --git a/qemu/hw/timer/etraxfs_timer.c b/qemu/hw/timer/etraxfs_timer.c deleted file mode 100644 index 36d8f462c..000000000 --- a/qemu/hw/timer/etraxfs_timer.c +++ /dev/null @@ -1,358 +0,0 @@ -/* - * QEMU ETRAX Timers - * - * Copyright (c) 2007 Edgar E. Iglesias, Axis Communications AB. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include "qemu/osdep.h" -#include "hw/sysbus.h" -#include "sysemu/sysemu.h" -#include "qemu/timer.h" -#include "hw/ptimer.h" - -#define D(x) - -#define RW_TMR0_DIV 0x00 -#define R_TMR0_DATA 0x04 -#define RW_TMR0_CTRL 0x08 -#define RW_TMR1_DIV 0x10 -#define R_TMR1_DATA 0x14 -#define RW_TMR1_CTRL 0x18 -#define R_TIME 0x38 -#define RW_WD_CTRL 0x40 -#define R_WD_STAT 0x44 -#define RW_INTR_MASK 0x48 -#define RW_ACK_INTR 0x4c -#define R_INTR 0x50 -#define R_MASKED_INTR 0x54 - -#define TYPE_ETRAX_FS_TIMER "etraxfs,timer" -#define ETRAX_TIMER(obj) \ - OBJECT_CHECK(ETRAXTimerState, (obj), TYPE_ETRAX_FS_TIMER) - -typedef struct ETRAXTimerState { - SysBusDevice parent_obj; - - MemoryRegion mmio; - qemu_irq irq; - qemu_irq nmi; - - QEMUBH *bh_t0; - QEMUBH *bh_t1; - QEMUBH *bh_wd; - ptimer_state *ptimer_t0; - ptimer_state *ptimer_t1; - ptimer_state *ptimer_wd; - - int wd_hits; - - /* Control registers. */ - uint32_t rw_tmr0_div; - uint32_t r_tmr0_data; - uint32_t rw_tmr0_ctrl; - - uint32_t rw_tmr1_div; - uint32_t r_tmr1_data; - uint32_t rw_tmr1_ctrl; - - uint32_t rw_wd_ctrl; - - uint32_t rw_intr_mask; - uint32_t rw_ack_intr; - uint32_t r_intr; - uint32_t r_masked_intr; -} ETRAXTimerState; - -static uint64_t -timer_read(void *opaque, hwaddr addr, unsigned int size) -{ - ETRAXTimerState *t = opaque; - uint32_t r = 0; - - switch (addr) { - case R_TMR0_DATA: - r = ptimer_get_count(t->ptimer_t0); - break; - case R_TMR1_DATA: - r = ptimer_get_count(t->ptimer_t1); - break; - case R_TIME: - r = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) / 10; - break; - case RW_INTR_MASK: - r = t->rw_intr_mask; - break; - case R_MASKED_INTR: - r = t->r_intr & t->rw_intr_mask; - break; - default: - D(printf ("%s %x\n", __func__, addr)); - break; - } - return r; -} - -static void update_ctrl(ETRAXTimerState *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 timer_update_irq(ETRAXTimerState *t) -{ - t->r_intr &= ~(t->rw_ack_intr); - t->r_masked_intr = t->r_intr & t->rw_intr_mask; - - D(printf("%s: masked_intr=%x\n", __func__, t->r_masked_intr)); - qemu_set_irq(t->irq, !!t->r_masked_intr); -} - -static void timer0_hit(void *opaque) -{ - ETRAXTimerState *t = opaque; - t->r_intr |= 1; - timer_update_irq(t); -} - -static void timer1_hit(void *opaque) -{ - ETRAXTimerState *t = opaque; - t->r_intr |= 2; - timer_update_irq(t); -} - -static void watchdog_hit(void *opaque) -{ - ETRAXTimerState *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 inline void timer_watchdog_update(ETRAXTimerState *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 -timer_write(void *opaque, hwaddr addr, - uint64_t val64, unsigned int size) -{ - ETRAXTimerState *t = opaque; - uint32_t value = val64; - - switch (addr) - { - case RW_TMR0_DIV: - t->rw_tmr0_div = value; - break; - case RW_TMR0_CTRL: - D(printf ("RW_TMR0_CTRL=%x\n", value)); - t->rw_tmr0_ctrl = value; - update_ctrl(t, 0); - break; - case RW_TMR1_DIV: - t->rw_tmr1_div = value; - break; - case RW_TMR1_CTRL: - D(printf ("RW_TMR1_CTRL=%x\n", value)); - t->rw_tmr1_ctrl = value; - update_ctrl(t, 1); - break; - case RW_INTR_MASK: - D(printf ("RW_INTR_MASK=%x\n", value)); - t->rw_intr_mask = value; - timer_update_irq(t); - break; - case RW_WD_CTRL: - timer_watchdog_update(t, value); - break; - case RW_ACK_INTR: - t->rw_ack_intr = value; - timer_update_irq(t); - t->rw_ack_intr = 0; - break; - default: - printf ("%s " TARGET_FMT_plx " %x\n", - __func__, addr, value); - break; - } -} - -static const MemoryRegionOps timer_ops = { - .read = timer_read, - .write = timer_write, - .endianness = DEVICE_LITTLE_ENDIAN, - .valid = { - .min_access_size = 4, - .max_access_size = 4 - } -}; - -static void etraxfs_timer_reset(void *opaque) -{ - ETRAXTimerState *t = opaque; - - ptimer_stop(t->ptimer_t0); - ptimer_stop(t->ptimer_t1); - ptimer_stop(t->ptimer_wd); - t->rw_wd_ctrl = 0; - t->r_intr = 0; - t->rw_intr_mask = 0; - qemu_irq_lower(t->irq); -} - -static int etraxfs_timer_init(SysBusDevice *dev) -{ - ETRAXTimerState *t = ETRAX_TIMER(dev); - - t->bh_t0 = qemu_bh_new(timer0_hit, t); - t->bh_t1 = qemu_bh_new(timer1_hit, t); - t->bh_wd = qemu_bh_new(watchdog_hit, t); - t->ptimer_t0 = ptimer_init(t->bh_t0); - t->ptimer_t1 = ptimer_init(t->bh_t1); - t->ptimer_wd = ptimer_init(t->bh_wd); - - sysbus_init_irq(dev, &t->irq); - sysbus_init_irq(dev, &t->nmi); - - memory_region_init_io(&t->mmio, OBJECT(t), &timer_ops, t, - "etraxfs-timer", 0x5c); - sysbus_init_mmio(dev, &t->mmio); - qemu_register_reset(etraxfs_timer_reset, t); - return 0; -} - -static void etraxfs_timer_class_init(ObjectClass *klass, void *data) -{ - SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass); - - sdc->init = etraxfs_timer_init; -} - -static const TypeInfo etraxfs_timer_info = { - .name = TYPE_ETRAX_FS_TIMER, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(ETRAXTimerState), - .class_init = etraxfs_timer_class_init, -}; - -static void etraxfs_timer_register_types(void) -{ - type_register_static(&etraxfs_timer_info); -} - -type_init(etraxfs_timer_register_types) diff --git a/qemu/hw/timer/exynos4210_mct.c b/qemu/hw/timer/exynos4210_mct.c deleted file mode 100644 index ae69345f0..000000000 --- a/qemu/hw/timer/exynos4210_mct.c +++ /dev/null @@ -1,1480 +0,0 @@ -/* - * Samsung exynos4210 Multi Core timer - * - * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. - * All rights reserved. - * - * Evgeny Voevodin <e.voevodin@samsung.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, see <http://www.gnu.org/licenses/>. - */ - -/* - * Global Timer: - * - * Consists of two timers. First represents Free Running Counter and second - * is used to measure interval from FRC to nearest comparator. - * - * 0 UINT64_MAX - * | timer0 | - * | <-------------------------------------------------------------- | - * | --------------------------------------------frc---------------> | - * |______________________________________________|__________________| - * CMP0 CMP1 CMP2 | CMP3 - * __| |_ - * | timer1 | - * | -------------> | - * frc CMPx - * - * Problem: when implementing global timer as is, overflow arises. - * next_time = cur_time + period * count; - * period and count are 64 bits width. - * Lets arm timer for MCT_GT_COUNTER_STEP count and update internal G_CNT - * register during each event. - * - * Problem: both timers need to be implemented using MCT_XT_COUNTER_STEP because - * local timer contains two counters: TCNT and ICNT. TCNT == 0 -> ICNT--. - * IRQ is generated when ICNT riches zero. Implementation where TCNT == 0 - * generates IRQs suffers from too frequently events. Better to have one - * uint64_t counter equal to TCNT*ICNT and arm ptimer.c for a minimum(TCNT*ICNT, - * MCT_GT_COUNTER_STEP); (yes, if target tunes ICNT * TCNT to be too low values, - * there is no way to avoid frequently events). - */ - -#include "qemu/osdep.h" -#include "hw/sysbus.h" -#include "qemu/timer.h" -#include "qemu/main-loop.h" -#include "qemu-common.h" -#include "hw/ptimer.h" - -#include "hw/arm/exynos4210.h" - -//#define DEBUG_MCT - -#ifdef DEBUG_MCT -#define DPRINTF(fmt, ...) \ - do { fprintf(stdout, "MCT: [%24s:%5d] " fmt, __func__, __LINE__, \ - ## __VA_ARGS__); } while (0) -#else -#define DPRINTF(fmt, ...) do {} while (0) -#endif - -#define MCT_CFG 0x000 -#define G_CNT_L 0x100 -#define G_CNT_U 0x104 -#define G_CNT_WSTAT 0x110 -#define G_COMP0_L 0x200 -#define G_COMP0_U 0x204 -#define G_COMP0_ADD_INCR 0x208 -#define G_COMP1_L 0x210 -#define G_COMP1_U 0x214 -#define G_COMP1_ADD_INCR 0x218 -#define G_COMP2_L 0x220 -#define G_COMP2_U 0x224 -#define G_COMP2_ADD_INCR 0x228 -#define G_COMP3_L 0x230 -#define G_COMP3_U 0x234 -#define G_COMP3_ADD_INCR 0x238 -#define G_TCON 0x240 -#define G_INT_CSTAT 0x244 -#define G_INT_ENB 0x248 -#define G_WSTAT 0x24C -#define L0_TCNTB 0x300 -#define L0_TCNTO 0x304 -#define L0_ICNTB 0x308 -#define L0_ICNTO 0x30C -#define L0_FRCNTB 0x310 -#define L0_FRCNTO 0x314 -#define L0_TCON 0x320 -#define L0_INT_CSTAT 0x330 -#define L0_INT_ENB 0x334 -#define L0_WSTAT 0x340 -#define L1_TCNTB 0x400 -#define L1_TCNTO 0x404 -#define L1_ICNTB 0x408 -#define L1_ICNTO 0x40C -#define L1_FRCNTB 0x410 -#define L1_FRCNTO 0x414 -#define L1_TCON 0x420 -#define L1_INT_CSTAT 0x430 -#define L1_INT_ENB 0x434 -#define L1_WSTAT 0x440 - -#define MCT_CFG_GET_PRESCALER(x) ((x) & 0xFF) -#define MCT_CFG_GET_DIVIDER(x) (1 << ((x) >> 8 & 7)) - -#define GET_G_COMP_IDX(offset) (((offset) - G_COMP0_L) / 0x10) -#define GET_G_COMP_ADD_INCR_IDX(offset) (((offset) - G_COMP0_ADD_INCR) / 0x10) - -#define G_COMP_L(x) (G_COMP0_L + (x) * 0x10) -#define G_COMP_U(x) (G_COMP0_U + (x) * 0x10) - -#define G_COMP_ADD_INCR(x) (G_COMP0_ADD_INCR + (x) * 0x10) - -/* MCT bits */ -#define G_TCON_COMP_ENABLE(x) (1 << 2 * (x)) -#define G_TCON_AUTO_ICREMENT(x) (1 << (2 * (x) + 1)) -#define G_TCON_TIMER_ENABLE (1 << 8) - -#define G_INT_ENABLE(x) (1 << (x)) -#define G_INT_CSTAT_COMP(x) (1 << (x)) - -#define G_CNT_WSTAT_L 1 -#define G_CNT_WSTAT_U 2 - -#define G_WSTAT_COMP_L(x) (1 << 4 * (x)) -#define G_WSTAT_COMP_U(x) (1 << ((4 * (x)) + 1)) -#define G_WSTAT_COMP_ADDINCR(x) (1 << ((4 * (x)) + 2)) -#define G_WSTAT_TCON_WRITE (1 << 16) - -#define GET_L_TIMER_IDX(offset) ((((offset) & 0xF00) - L0_TCNTB) / 0x100) -#define GET_L_TIMER_CNT_REG_IDX(offset, lt_i) \ - (((offset) - (L0_TCNTB + 0x100 * (lt_i))) >> 2) - -#define L_ICNTB_MANUAL_UPDATE (1 << 31) - -#define L_TCON_TICK_START (1) -#define L_TCON_INT_START (1 << 1) -#define L_TCON_INTERVAL_MODE (1 << 2) -#define L_TCON_FRC_START (1 << 3) - -#define L_INT_CSTAT_INTCNT (1 << 0) -#define L_INT_CSTAT_FRCCNT (1 << 1) - -#define L_INT_INTENB_ICNTEIE (1 << 0) -#define L_INT_INTENB_FRCEIE (1 << 1) - -#define L_WSTAT_TCNTB_WRITE (1 << 0) -#define L_WSTAT_ICNTB_WRITE (1 << 1) -#define L_WSTAT_FRCCNTB_WRITE (1 << 2) -#define L_WSTAT_TCON_WRITE (1 << 3) - -enum LocalTimerRegCntIndexes { - L_REG_CNT_TCNTB, - L_REG_CNT_TCNTO, - L_REG_CNT_ICNTB, - L_REG_CNT_ICNTO, - L_REG_CNT_FRCCNTB, - L_REG_CNT_FRCCNTO, - - L_REG_CNT_AMOUNT -}; - -#define MCT_NIRQ 6 -#define MCT_SFR_SIZE 0x444 - -#define MCT_GT_CMP_NUM 4 - -#define MCT_GT_MAX_VAL UINT64_MAX - -#define MCT_GT_COUNTER_STEP 0x100000000ULL -#define MCT_LT_COUNTER_STEP 0x100000000ULL -#define MCT_LT_CNT_LOW_LIMIT 0x100 - -/* global timer */ -typedef struct { - qemu_irq irq[MCT_GT_CMP_NUM]; - - struct gregs { - uint64_t cnt; - uint32_t cnt_wstat; - uint32_t tcon; - uint32_t int_cstat; - uint32_t int_enb; - uint32_t wstat; - uint64_t comp[MCT_GT_CMP_NUM]; - uint32_t comp_add_incr[MCT_GT_CMP_NUM]; - } reg; - - uint64_t count; /* Value FRC was armed with */ - int32_t curr_comp; /* Current comparator FRC is running to */ - - ptimer_state *ptimer_frc; /* FRC timer */ - -} Exynos4210MCTGT; - -/* local timer */ -typedef struct { - int id; /* timer id */ - qemu_irq irq; /* local timer irq */ - - struct tick_timer { - uint32_t cnt_run; /* cnt timer is running */ - uint32_t int_run; /* int timer is running */ - - uint32_t last_icnto; - uint32_t last_tcnto; - uint32_t tcntb; /* initial value for TCNTB */ - uint32_t icntb; /* initial value for ICNTB */ - - /* for step mode */ - uint64_t distance; /* distance to count to the next event */ - uint64_t progress; /* progress when counting by steps */ - uint64_t count; /* count to arm timer with */ - - ptimer_state *ptimer_tick; /* timer for tick counter */ - } tick_timer; - - /* use ptimer.c to represent count down timer */ - - ptimer_state *ptimer_frc; /* timer for free running counter */ - - /* registers */ - struct lregs { - uint32_t cnt[L_REG_CNT_AMOUNT]; - uint32_t tcon; - uint32_t int_cstat; - uint32_t int_enb; - uint32_t wstat; - } reg; - -} Exynos4210MCTLT; - -#define TYPE_EXYNOS4210_MCT "exynos4210.mct" -#define EXYNOS4210_MCT(obj) \ - OBJECT_CHECK(Exynos4210MCTState, (obj), TYPE_EXYNOS4210_MCT) - -typedef struct Exynos4210MCTState { - SysBusDevice parent_obj; - - MemoryRegion iomem; - - /* Registers */ - uint32_t reg_mct_cfg; - - Exynos4210MCTLT l_timer[2]; - Exynos4210MCTGT g_timer; - - uint32_t freq; /* all timers tick frequency, TCLK */ -} Exynos4210MCTState; - -/*** VMState ***/ -static const VMStateDescription vmstate_tick_timer = { - .name = "exynos4210.mct.tick_timer", - .version_id = 1, - .minimum_version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_UINT32(cnt_run, struct tick_timer), - VMSTATE_UINT32(int_run, struct tick_timer), - VMSTATE_UINT32(last_icnto, struct tick_timer), - VMSTATE_UINT32(last_tcnto, struct tick_timer), - VMSTATE_UINT32(tcntb, struct tick_timer), - VMSTATE_UINT32(icntb, struct tick_timer), - VMSTATE_UINT64(distance, struct tick_timer), - VMSTATE_UINT64(progress, struct tick_timer), - VMSTATE_UINT64(count, struct tick_timer), - VMSTATE_PTIMER(ptimer_tick, struct tick_timer), - VMSTATE_END_OF_LIST() - } -}; - -static const VMStateDescription vmstate_lregs = { - .name = "exynos4210.mct.lregs", - .version_id = 1, - .minimum_version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_UINT32_ARRAY(cnt, struct lregs, L_REG_CNT_AMOUNT), - VMSTATE_UINT32(tcon, struct lregs), - VMSTATE_UINT32(int_cstat, struct lregs), - VMSTATE_UINT32(int_enb, struct lregs), - VMSTATE_UINT32(wstat, struct lregs), - VMSTATE_END_OF_LIST() - } -}; - -static const VMStateDescription vmstate_exynos4210_mct_lt = { - .name = "exynos4210.mct.lt", - .version_id = 1, - .minimum_version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_INT32(id, Exynos4210MCTLT), - VMSTATE_STRUCT(tick_timer, Exynos4210MCTLT, 0, - vmstate_tick_timer, - struct tick_timer), - VMSTATE_PTIMER(ptimer_frc, Exynos4210MCTLT), - VMSTATE_STRUCT(reg, Exynos4210MCTLT, 0, - vmstate_lregs, - struct lregs), - VMSTATE_END_OF_LIST() - } -}; - -static const VMStateDescription vmstate_gregs = { - .name = "exynos4210.mct.lregs", - .version_id = 1, - .minimum_version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_UINT64(cnt, struct gregs), - VMSTATE_UINT32(cnt_wstat, struct gregs), - VMSTATE_UINT32(tcon, struct gregs), - VMSTATE_UINT32(int_cstat, struct gregs), - VMSTATE_UINT32(int_enb, struct gregs), - VMSTATE_UINT32(wstat, struct gregs), - VMSTATE_UINT64_ARRAY(comp, struct gregs, MCT_GT_CMP_NUM), - VMSTATE_UINT32_ARRAY(comp_add_incr, struct gregs, - MCT_GT_CMP_NUM), - VMSTATE_END_OF_LIST() - } -}; - -static const VMStateDescription vmstate_exynos4210_mct_gt = { - .name = "exynos4210.mct.lt", - .version_id = 1, - .minimum_version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_STRUCT(reg, Exynos4210MCTGT, 0, vmstate_gregs, - struct gregs), - VMSTATE_UINT64(count, Exynos4210MCTGT), - VMSTATE_INT32(curr_comp, Exynos4210MCTGT), - VMSTATE_PTIMER(ptimer_frc, Exynos4210MCTGT), - VMSTATE_END_OF_LIST() - } -}; - -static const VMStateDescription vmstate_exynos4210_mct_state = { - .name = "exynos4210.mct", - .version_id = 1, - .minimum_version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_UINT32(reg_mct_cfg, Exynos4210MCTState), - VMSTATE_STRUCT_ARRAY(l_timer, Exynos4210MCTState, 2, 0, - vmstate_exynos4210_mct_lt, Exynos4210MCTLT), - VMSTATE_STRUCT(g_timer, Exynos4210MCTState, 0, - vmstate_exynos4210_mct_gt, Exynos4210MCTGT), - VMSTATE_UINT32(freq, Exynos4210MCTState), - VMSTATE_END_OF_LIST() - } -}; - -static void exynos4210_mct_update_freq(Exynos4210MCTState *s); - -/* - * Set counter of FRC global timer. - */ -static void exynos4210_gfrc_set_count(Exynos4210MCTGT *s, uint64_t count) -{ - s->count = count; - DPRINTF("global timer frc set count 0x%llx\n", count); - ptimer_set_count(s->ptimer_frc, count); -} - -/* - * Get counter of FRC global timer. - */ -static uint64_t exynos4210_gfrc_get_count(Exynos4210MCTGT *s) -{ - uint64_t count = 0; - count = ptimer_get_count(s->ptimer_frc); - count = s->count - count; - return s->reg.cnt + count; -} - -/* - * Stop global FRC timer - */ -static void exynos4210_gfrc_stop(Exynos4210MCTGT *s) -{ - DPRINTF("global timer frc stop\n"); - - ptimer_stop(s->ptimer_frc); -} - -/* - * Start global FRC timer - */ -static void exynos4210_gfrc_start(Exynos4210MCTGT *s) -{ - DPRINTF("global timer frc start\n"); - - ptimer_run(s->ptimer_frc, 1); -} - -/* - * Find next nearest Comparator. If current Comparator value equals to other - * Comparator value, skip them both - */ -static int32_t exynos4210_gcomp_find(Exynos4210MCTState *s) -{ - int res; - int i; - int enabled; - uint64_t min; - int min_comp_i; - uint64_t gfrc; - uint64_t distance; - uint64_t distance_min; - int comp_i; - - /* get gfrc count */ - gfrc = exynos4210_gfrc_get_count(&s->g_timer); - - min = UINT64_MAX; - distance_min = UINT64_MAX; - comp_i = MCT_GT_CMP_NUM; - min_comp_i = MCT_GT_CMP_NUM; - enabled = 0; - - /* lookup for nearest comparator */ - for (i = 0; i < MCT_GT_CMP_NUM; i++) { - - if (s->g_timer.reg.tcon & G_TCON_COMP_ENABLE(i)) { - - enabled = 1; - - if (s->g_timer.reg.comp[i] > gfrc) { - /* Comparator is upper then FRC */ - distance = s->g_timer.reg.comp[i] - gfrc; - - if (distance <= distance_min) { - distance_min = distance; - comp_i = i; - } - } else { - /* Comparator is below FRC, find the smallest */ - - if (s->g_timer.reg.comp[i] <= min) { - min = s->g_timer.reg.comp[i]; - min_comp_i = i; - } - } - } - } - - if (!enabled) { - /* All Comparators disabled */ - res = -1; - } else if (comp_i < MCT_GT_CMP_NUM) { - /* Found upper Comparator */ - res = comp_i; - } else { - /* All Comparators are below or equal to FRC */ - res = min_comp_i; - } - - DPRINTF("found comparator %d: comp 0x%llx distance 0x%llx, gfrc 0x%llx\n", - res, - s->g_timer.reg.comp[res], - distance_min, - gfrc); - - return res; -} - -/* - * Get distance to nearest Comparator - */ -static uint64_t exynos4210_gcomp_get_distance(Exynos4210MCTState *s, int32_t id) -{ - if (id == -1) { - /* no enabled Comparators, choose max distance */ - return MCT_GT_COUNTER_STEP; - } - if (s->g_timer.reg.comp[id] - s->g_timer.reg.cnt < MCT_GT_COUNTER_STEP) { - return s->g_timer.reg.comp[id] - s->g_timer.reg.cnt; - } else { - return MCT_GT_COUNTER_STEP; - } -} - -/* - * Restart global FRC timer - */ -static void exynos4210_gfrc_restart(Exynos4210MCTState *s) -{ - uint64_t distance; - - exynos4210_gfrc_stop(&s->g_timer); - - s->g_timer.curr_comp = exynos4210_gcomp_find(s); - - distance = exynos4210_gcomp_get_distance(s, s->g_timer.curr_comp); - - if (distance > MCT_GT_COUNTER_STEP || !distance) { - distance = MCT_GT_COUNTER_STEP; - } - - exynos4210_gfrc_set_count(&s->g_timer, distance); - exynos4210_gfrc_start(&s->g_timer); -} - -/* - * Raise global timer CMP IRQ - */ -static void exynos4210_gcomp_raise_irq(void *opaque, uint32_t id) -{ - Exynos4210MCTGT *s = opaque; - - /* If CSTAT is pending and IRQ is enabled */ - if ((s->reg.int_cstat & G_INT_CSTAT_COMP(id)) && - (s->reg.int_enb & G_INT_ENABLE(id))) { - DPRINTF("gcmp timer[%d] IRQ\n", id); - qemu_irq_raise(s->irq[id]); - } -} - -/* - * Lower global timer CMP IRQ - */ -static void exynos4210_gcomp_lower_irq(void *opaque, uint32_t id) -{ - Exynos4210MCTGT *s = opaque; - qemu_irq_lower(s->irq[id]); -} - -/* - * Global timer FRC event handler. - * Each event occurs when internal counter reaches counter + MCT_GT_COUNTER_STEP - * Every time we arm global FRC timer to count for MCT_GT_COUNTER_STEP value - */ -static void exynos4210_gfrc_event(void *opaque) -{ - Exynos4210MCTState *s = (Exynos4210MCTState *)opaque; - int i; - uint64_t distance; - - DPRINTF("\n"); - - s->g_timer.reg.cnt += s->g_timer.count; - - /* Process all comparators */ - for (i = 0; i < MCT_GT_CMP_NUM; i++) { - - if (s->g_timer.reg.cnt == s->g_timer.reg.comp[i]) { - /* reached nearest comparator */ - - s->g_timer.reg.int_cstat |= G_INT_CSTAT_COMP(i); - - /* Auto increment */ - if (s->g_timer.reg.tcon & G_TCON_AUTO_ICREMENT(i)) { - s->g_timer.reg.comp[i] += s->g_timer.reg.comp_add_incr[i]; - } - - /* IRQ */ - exynos4210_gcomp_raise_irq(&s->g_timer, i); - } - } - - /* Reload FRC to reach nearest comparator */ - s->g_timer.curr_comp = exynos4210_gcomp_find(s); - distance = exynos4210_gcomp_get_distance(s, s->g_timer.curr_comp); - if (distance > MCT_GT_COUNTER_STEP || !distance) { - distance = MCT_GT_COUNTER_STEP; - } - exynos4210_gfrc_set_count(&s->g_timer, distance); - - exynos4210_gfrc_start(&s->g_timer); -} - -/* - * Get counter of FRC local timer. - */ -static uint64_t exynos4210_lfrc_get_count(Exynos4210MCTLT *s) -{ - return ptimer_get_count(s->ptimer_frc); -} - -/* - * Set counter of FRC local timer. - */ -static void exynos4210_lfrc_update_count(Exynos4210MCTLT *s) -{ - if (!s->reg.cnt[L_REG_CNT_FRCCNTB]) { - ptimer_set_count(s->ptimer_frc, MCT_LT_COUNTER_STEP); - } else { - ptimer_set_count(s->ptimer_frc, s->reg.cnt[L_REG_CNT_FRCCNTB]); - } -} - -/* - * Start local FRC timer - */ -static void exynos4210_lfrc_start(Exynos4210MCTLT *s) -{ - ptimer_run(s->ptimer_frc, 1); -} - -/* - * Stop local FRC timer - */ -static void exynos4210_lfrc_stop(Exynos4210MCTLT *s) -{ - ptimer_stop(s->ptimer_frc); -} - -/* - * Local timer free running counter tick handler - */ -static void exynos4210_lfrc_event(void *opaque) -{ - Exynos4210MCTLT * s = (Exynos4210MCTLT *)opaque; - - /* local frc expired */ - - DPRINTF("\n"); - - s->reg.int_cstat |= L_INT_CSTAT_FRCCNT; - - /* update frc counter */ - exynos4210_lfrc_update_count(s); - - /* raise irq */ - if (s->reg.int_enb & L_INT_INTENB_FRCEIE) { - qemu_irq_raise(s->irq); - } - - /* we reached here, this means that timer is enabled */ - exynos4210_lfrc_start(s); -} - -static uint32_t exynos4210_ltick_int_get_cnto(struct tick_timer *s); -static uint32_t exynos4210_ltick_cnt_get_cnto(struct tick_timer *s); -static void exynos4210_ltick_recalc_count(struct tick_timer *s); - -/* - * Action on enabling local tick int timer - */ -static void exynos4210_ltick_int_start(struct tick_timer *s) -{ - if (!s->int_run) { - s->int_run = 1; - } -} - -/* - * Action on disabling local tick int timer - */ -static void exynos4210_ltick_int_stop(struct tick_timer *s) -{ - if (s->int_run) { - s->last_icnto = exynos4210_ltick_int_get_cnto(s); - s->int_run = 0; - } -} - -/* - * Get count for INT timer - */ -static uint32_t exynos4210_ltick_int_get_cnto(struct tick_timer *s) -{ - uint32_t icnto; - uint64_t remain; - uint64_t count; - uint64_t counted; - uint64_t cur_progress; - - count = ptimer_get_count(s->ptimer_tick); - if (count) { - /* timer is still counting, called not from event */ - counted = s->count - ptimer_get_count(s->ptimer_tick); - cur_progress = s->progress + counted; - } else { - /* timer expired earlier */ - cur_progress = s->progress; - } - - remain = s->distance - cur_progress; - - if (!s->int_run) { - /* INT is stopped. */ - icnto = s->last_icnto; - } else { - /* Both are counting */ - icnto = remain / s->tcntb; - } - - return icnto; -} - -/* - * Start local tick cnt timer. - */ -static void exynos4210_ltick_cnt_start(struct tick_timer *s) -{ - if (!s->cnt_run) { - - exynos4210_ltick_recalc_count(s); - ptimer_set_count(s->ptimer_tick, s->count); - ptimer_run(s->ptimer_tick, 1); - - s->cnt_run = 1; - } -} - -/* - * Stop local tick cnt timer. - */ -static void exynos4210_ltick_cnt_stop(struct tick_timer *s) -{ - if (s->cnt_run) { - - s->last_tcnto = exynos4210_ltick_cnt_get_cnto(s); - - if (s->int_run) { - exynos4210_ltick_int_stop(s); - } - - ptimer_stop(s->ptimer_tick); - - s->cnt_run = 0; - } -} - -/* - * Get counter for CNT timer - */ -static uint32_t exynos4210_ltick_cnt_get_cnto(struct tick_timer *s) -{ - uint32_t tcnto; - uint32_t icnto; - uint64_t remain; - uint64_t counted; - uint64_t count; - uint64_t cur_progress; - - count = ptimer_get_count(s->ptimer_tick); - if (count) { - /* timer is still counting, called not from event */ - counted = s->count - ptimer_get_count(s->ptimer_tick); - cur_progress = s->progress + counted; - } else { - /* timer expired earlier */ - cur_progress = s->progress; - } - - remain = s->distance - cur_progress; - - if (!s->cnt_run) { - /* Both are stopped. */ - tcnto = s->last_tcnto; - } else if (!s->int_run) { - /* INT counter is stopped, progress is by CNT timer */ - tcnto = remain % s->tcntb; - } else { - /* Both are counting */ - icnto = remain / s->tcntb; - if (icnto) { - tcnto = remain % (icnto * s->tcntb); - } else { - tcnto = remain % s->tcntb; - } - } - - return tcnto; -} - -/* - * Set new values of counters for CNT and INT timers - */ -static void exynos4210_ltick_set_cntb(struct tick_timer *s, uint32_t new_cnt, - uint32_t new_int) -{ - uint32_t cnt_stopped = 0; - uint32_t int_stopped = 0; - - if (s->cnt_run) { - exynos4210_ltick_cnt_stop(s); - cnt_stopped = 1; - } - - if (s->int_run) { - exynos4210_ltick_int_stop(s); - int_stopped = 1; - } - - s->tcntb = new_cnt + 1; - s->icntb = new_int + 1; - - if (cnt_stopped) { - exynos4210_ltick_cnt_start(s); - } - if (int_stopped) { - exynos4210_ltick_int_start(s); - } - -} - -/* - * Calculate new counter value for tick timer - */ -static void exynos4210_ltick_recalc_count(struct tick_timer *s) -{ - uint64_t to_count; - - if ((s->cnt_run && s->last_tcnto) || (s->int_run && s->last_icnto)) { - /* - * one or both timers run and not counted to the end; - * distance is not passed, recalculate with last_tcnto * last_icnto - */ - - if (s->last_tcnto) { - to_count = (uint64_t)s->last_tcnto * s->last_icnto; - } else { - to_count = s->last_icnto; - } - } else { - /* distance is passed, recalculate with tcnto * icnto */ - if (s->icntb) { - s->distance = (uint64_t)s->tcntb * s->icntb; - } else { - s->distance = s->tcntb; - } - - to_count = s->distance; - s->progress = 0; - } - - if (to_count > MCT_LT_COUNTER_STEP) { - /* count by step */ - s->count = MCT_LT_COUNTER_STEP; - } else { - s->count = to_count; - } -} - -/* - * Initialize tick_timer - */ -static void exynos4210_ltick_timer_init(struct tick_timer *s) -{ - exynos4210_ltick_int_stop(s); - exynos4210_ltick_cnt_stop(s); - - s->count = 0; - s->distance = 0; - s->progress = 0; - s->icntb = 0; - s->tcntb = 0; -} - -/* - * tick_timer event. - * Raises when abstract tick_timer expires. - */ -static void exynos4210_ltick_timer_event(struct tick_timer *s) -{ - s->progress += s->count; -} - -/* - * Local timer tick counter handler. - * Don't use reloaded timers. If timer counter = zero - * then handler called but after handler finished no - * timer reload occurs. - */ -static void exynos4210_ltick_event(void *opaque) -{ - Exynos4210MCTLT * s = (Exynos4210MCTLT *)opaque; - uint32_t tcnto; - uint32_t icnto; -#ifdef DEBUG_MCT - static uint64_t time1[2] = {0}; - static uint64_t time2[2] = {0}; -#endif - - /* Call tick_timer event handler, it will update its tcntb and icntb. */ - exynos4210_ltick_timer_event(&s->tick_timer); - - /* get tick_timer cnt */ - tcnto = exynos4210_ltick_cnt_get_cnto(&s->tick_timer); - - /* get tick_timer int */ - icnto = exynos4210_ltick_int_get_cnto(&s->tick_timer); - - /* raise IRQ if needed */ - if (!icnto && s->reg.tcon & L_TCON_INT_START) { - /* INT counter enabled and expired */ - - s->reg.int_cstat |= L_INT_CSTAT_INTCNT; - - /* raise interrupt if enabled */ - if (s->reg.int_enb & L_INT_INTENB_ICNTEIE) { -#ifdef DEBUG_MCT - time2[s->id] = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); - DPRINTF("local timer[%d] IRQ: %llx\n", s->id, - time2[s->id] - time1[s->id]); - time1[s->id] = time2[s->id]; -#endif - qemu_irq_raise(s->irq); - } - - /* reload ICNTB */ - if (s->reg.tcon & L_TCON_INTERVAL_MODE) { - exynos4210_ltick_set_cntb(&s->tick_timer, - s->reg.cnt[L_REG_CNT_TCNTB], - s->reg.cnt[L_REG_CNT_ICNTB]); - } - } else { - /* reload TCNTB */ - if (!tcnto) { - exynos4210_ltick_set_cntb(&s->tick_timer, - s->reg.cnt[L_REG_CNT_TCNTB], - icnto); - } - } - - /* start tick_timer cnt */ - exynos4210_ltick_cnt_start(&s->tick_timer); - - /* start tick_timer int */ - exynos4210_ltick_int_start(&s->tick_timer); -} - -/* update timer frequency */ -static void exynos4210_mct_update_freq(Exynos4210MCTState *s) -{ - uint32_t freq = s->freq; - s->freq = 24000000 / - ((MCT_CFG_GET_PRESCALER(s->reg_mct_cfg)+1) * - MCT_CFG_GET_DIVIDER(s->reg_mct_cfg)); - - if (freq != s->freq) { - DPRINTF("freq=%dHz\n", s->freq); - - /* global timer */ - ptimer_set_freq(s->g_timer.ptimer_frc, s->freq); - - /* local timer */ - ptimer_set_freq(s->l_timer[0].tick_timer.ptimer_tick, s->freq); - ptimer_set_freq(s->l_timer[0].ptimer_frc, s->freq); - ptimer_set_freq(s->l_timer[1].tick_timer.ptimer_tick, s->freq); - ptimer_set_freq(s->l_timer[1].ptimer_frc, s->freq); - } -} - -/* set defaul_timer values for all fields */ -static void exynos4210_mct_reset(DeviceState *d) -{ - Exynos4210MCTState *s = EXYNOS4210_MCT(d); - uint32_t i; - - s->reg_mct_cfg = 0; - - /* global timer */ - memset(&s->g_timer.reg, 0, sizeof(s->g_timer.reg)); - exynos4210_gfrc_stop(&s->g_timer); - - /* local timer */ - memset(s->l_timer[0].reg.cnt, 0, sizeof(s->l_timer[0].reg.cnt)); - memset(s->l_timer[1].reg.cnt, 0, sizeof(s->l_timer[1].reg.cnt)); - for (i = 0; i < 2; i++) { - s->l_timer[i].reg.int_cstat = 0; - s->l_timer[i].reg.int_enb = 0; - s->l_timer[i].reg.tcon = 0; - s->l_timer[i].reg.wstat = 0; - s->l_timer[i].tick_timer.count = 0; - s->l_timer[i].tick_timer.distance = 0; - s->l_timer[i].tick_timer.progress = 0; - ptimer_stop(s->l_timer[i].ptimer_frc); - - exynos4210_ltick_timer_init(&s->l_timer[i].tick_timer); - } - - exynos4210_mct_update_freq(s); - -} - -/* Multi Core Timer read */ -static uint64_t exynos4210_mct_read(void *opaque, hwaddr offset, - unsigned size) -{ - Exynos4210MCTState *s = (Exynos4210MCTState *)opaque; - int index; - int shift; - uint64_t count; - uint32_t value; - int lt_i; - - switch (offset) { - - case MCT_CFG: - value = s->reg_mct_cfg; - break; - - case G_CNT_L: case G_CNT_U: - shift = 8 * (offset & 0x4); - count = exynos4210_gfrc_get_count(&s->g_timer); - value = UINT32_MAX & (count >> shift); - DPRINTF("read FRC=0x%llx\n", count); - break; - - case G_CNT_WSTAT: - value = s->g_timer.reg.cnt_wstat; - break; - - case G_COMP_L(0): case G_COMP_L(1): case G_COMP_L(2): case G_COMP_L(3): - case G_COMP_U(0): case G_COMP_U(1): case G_COMP_U(2): case G_COMP_U(3): - index = GET_G_COMP_IDX(offset); - shift = 8 * (offset & 0x4); - value = UINT32_MAX & (s->g_timer.reg.comp[index] >> shift); - break; - - case G_TCON: - value = s->g_timer.reg.tcon; - break; - - case G_INT_CSTAT: - value = s->g_timer.reg.int_cstat; - break; - - case G_INT_ENB: - value = s->g_timer.reg.int_enb; - break; - case G_WSTAT: - value = s->g_timer.reg.wstat; - break; - - case G_COMP0_ADD_INCR: case G_COMP1_ADD_INCR: - case G_COMP2_ADD_INCR: case G_COMP3_ADD_INCR: - value = s->g_timer.reg.comp_add_incr[GET_G_COMP_ADD_INCR_IDX(offset)]; - break; - - /* Local timers */ - case L0_TCNTB: case L0_ICNTB: case L0_FRCNTB: - case L1_TCNTB: case L1_ICNTB: case L1_FRCNTB: - lt_i = GET_L_TIMER_IDX(offset); - index = GET_L_TIMER_CNT_REG_IDX(offset, lt_i); - value = s->l_timer[lt_i].reg.cnt[index]; - break; - - case L0_TCNTO: case L1_TCNTO: - lt_i = GET_L_TIMER_IDX(offset); - - value = exynos4210_ltick_cnt_get_cnto(&s->l_timer[lt_i].tick_timer); - DPRINTF("local timer[%d] read TCNTO %x\n", lt_i, value); - break; - - case L0_ICNTO: case L1_ICNTO: - lt_i = GET_L_TIMER_IDX(offset); - - value = exynos4210_ltick_int_get_cnto(&s->l_timer[lt_i].tick_timer); - DPRINTF("local timer[%d] read ICNTO %x\n", lt_i, value); - break; - - case L0_FRCNTO: case L1_FRCNTO: - lt_i = GET_L_TIMER_IDX(offset); - - value = exynos4210_lfrc_get_count(&s->l_timer[lt_i]); - - break; - - case L0_TCON: case L1_TCON: - lt_i = ((offset & 0xF00) - L0_TCNTB) / 0x100; - value = s->l_timer[lt_i].reg.tcon; - break; - - case L0_INT_CSTAT: case L1_INT_CSTAT: - lt_i = ((offset & 0xF00) - L0_TCNTB) / 0x100; - value = s->l_timer[lt_i].reg.int_cstat; - break; - - case L0_INT_ENB: case L1_INT_ENB: - lt_i = ((offset & 0xF00) - L0_TCNTB) / 0x100; - value = s->l_timer[lt_i].reg.int_enb; - break; - - case L0_WSTAT: case L1_WSTAT: - lt_i = ((offset & 0xF00) - L0_TCNTB) / 0x100; - value = s->l_timer[lt_i].reg.wstat; - break; - - default: - hw_error("exynos4210.mct: bad read offset " - TARGET_FMT_plx "\n", offset); - break; - } - return value; -} - -/* MCT write */ -static void exynos4210_mct_write(void *opaque, hwaddr offset, - uint64_t value, unsigned size) -{ - Exynos4210MCTState *s = (Exynos4210MCTState *)opaque; - int index; /* index in buffer which represents register set */ - int shift; - int lt_i; - uint64_t new_frc; - uint32_t i; - uint32_t old_val; -#ifdef DEBUG_MCT - static uint32_t icntb_max[2] = {0}; - static uint32_t icntb_min[2] = {UINT32_MAX, UINT32_MAX}; - static uint32_t tcntb_max[2] = {0}; - static uint32_t tcntb_min[2] = {UINT32_MAX, UINT32_MAX}; -#endif - - new_frc = s->g_timer.reg.cnt; - - switch (offset) { - - case MCT_CFG: - s->reg_mct_cfg = value; - exynos4210_mct_update_freq(s); - break; - - case G_CNT_L: - case G_CNT_U: - if (offset == G_CNT_L) { - - DPRINTF("global timer write to reg.cntl %llx\n", value); - - new_frc = (s->g_timer.reg.cnt & (uint64_t)UINT32_MAX << 32) + value; - s->g_timer.reg.cnt_wstat |= G_CNT_WSTAT_L; - } - if (offset == G_CNT_U) { - - DPRINTF("global timer write to reg.cntu %llx\n", value); - - new_frc = (s->g_timer.reg.cnt & UINT32_MAX) + - ((uint64_t)value << 32); - s->g_timer.reg.cnt_wstat |= G_CNT_WSTAT_U; - } - - s->g_timer.reg.cnt = new_frc; - exynos4210_gfrc_restart(s); - break; - - case G_CNT_WSTAT: - s->g_timer.reg.cnt_wstat &= ~(value); - break; - - case G_COMP_L(0): case G_COMP_L(1): case G_COMP_L(2): case G_COMP_L(3): - case G_COMP_U(0): case G_COMP_U(1): case G_COMP_U(2): case G_COMP_U(3): - index = GET_G_COMP_IDX(offset); - shift = 8 * (offset & 0x4); - s->g_timer.reg.comp[index] = - (s->g_timer.reg.comp[index] & - (((uint64_t)UINT32_MAX << 32) >> shift)) + - (value << shift); - - DPRINTF("comparator %d write 0x%llx val << %d\n", index, value, shift); - - if (offset&0x4) { - s->g_timer.reg.wstat |= G_WSTAT_COMP_U(index); - } else { - s->g_timer.reg.wstat |= G_WSTAT_COMP_L(index); - } - - exynos4210_gfrc_restart(s); - break; - - case G_TCON: - old_val = s->g_timer.reg.tcon; - s->g_timer.reg.tcon = value; - s->g_timer.reg.wstat |= G_WSTAT_TCON_WRITE; - - DPRINTF("global timer write to reg.g_tcon %llx\n", value); - - /* Start FRC if transition from disabled to enabled */ - if ((value & G_TCON_TIMER_ENABLE) > (old_val & - G_TCON_TIMER_ENABLE)) { - exynos4210_gfrc_start(&s->g_timer); - } - if ((value & G_TCON_TIMER_ENABLE) < (old_val & - G_TCON_TIMER_ENABLE)) { - exynos4210_gfrc_stop(&s->g_timer); - } - - /* Start CMP if transition from disabled to enabled */ - for (i = 0; i < MCT_GT_CMP_NUM; i++) { - if ((value & G_TCON_COMP_ENABLE(i)) != (old_val & - G_TCON_COMP_ENABLE(i))) { - exynos4210_gfrc_restart(s); - } - } - break; - - case G_INT_CSTAT: - s->g_timer.reg.int_cstat &= ~(value); - for (i = 0; i < MCT_GT_CMP_NUM; i++) { - if (value & G_INT_CSTAT_COMP(i)) { - exynos4210_gcomp_lower_irq(&s->g_timer, i); - } - } - break; - - case G_INT_ENB: - - /* Raise IRQ if transition from disabled to enabled and CSTAT pending */ - for (i = 0; i < MCT_GT_CMP_NUM; i++) { - if ((value & G_INT_ENABLE(i)) > (s->g_timer.reg.tcon & - G_INT_ENABLE(i))) { - if (s->g_timer.reg.int_cstat & G_INT_CSTAT_COMP(i)) { - exynos4210_gcomp_raise_irq(&s->g_timer, i); - } - } - - if ((value & G_INT_ENABLE(i)) < (s->g_timer.reg.tcon & - G_INT_ENABLE(i))) { - exynos4210_gcomp_lower_irq(&s->g_timer, i); - } - } - - DPRINTF("global timer INT enable %llx\n", value); - s->g_timer.reg.int_enb = value; - break; - - case G_WSTAT: - s->g_timer.reg.wstat &= ~(value); - break; - - case G_COMP0_ADD_INCR: case G_COMP1_ADD_INCR: - case G_COMP2_ADD_INCR: case G_COMP3_ADD_INCR: - index = GET_G_COMP_ADD_INCR_IDX(offset); - s->g_timer.reg.comp_add_incr[index] = value; - s->g_timer.reg.wstat |= G_WSTAT_COMP_ADDINCR(index); - break; - - /* Local timers */ - case L0_TCON: case L1_TCON: - lt_i = GET_L_TIMER_IDX(offset); - old_val = s->l_timer[lt_i].reg.tcon; - - s->l_timer[lt_i].reg.wstat |= L_WSTAT_TCON_WRITE; - s->l_timer[lt_i].reg.tcon = value; - - /* Stop local CNT */ - if ((value & L_TCON_TICK_START) < - (old_val & L_TCON_TICK_START)) { - DPRINTF("local timer[%d] stop cnt\n", lt_i); - exynos4210_ltick_cnt_stop(&s->l_timer[lt_i].tick_timer); - } - - /* Stop local INT */ - if ((value & L_TCON_INT_START) < - (old_val & L_TCON_INT_START)) { - DPRINTF("local timer[%d] stop int\n", lt_i); - exynos4210_ltick_int_stop(&s->l_timer[lt_i].tick_timer); - } - - /* Start local CNT */ - if ((value & L_TCON_TICK_START) > - (old_val & L_TCON_TICK_START)) { - DPRINTF("local timer[%d] start cnt\n", lt_i); - exynos4210_ltick_cnt_start(&s->l_timer[lt_i].tick_timer); - } - - /* Start local INT */ - if ((value & L_TCON_INT_START) > - (old_val & L_TCON_INT_START)) { - DPRINTF("local timer[%d] start int\n", lt_i); - exynos4210_ltick_int_start(&s->l_timer[lt_i].tick_timer); - } - - /* Start or Stop local FRC if TCON changed */ - if ((value & L_TCON_FRC_START) > - (s->l_timer[lt_i].reg.tcon & L_TCON_FRC_START)) { - DPRINTF("local timer[%d] start frc\n", lt_i); - exynos4210_lfrc_start(&s->l_timer[lt_i]); - } - if ((value & L_TCON_FRC_START) < - (s->l_timer[lt_i].reg.tcon & L_TCON_FRC_START)) { - DPRINTF("local timer[%d] stop frc\n", lt_i); - exynos4210_lfrc_stop(&s->l_timer[lt_i]); - } - break; - - case L0_TCNTB: case L1_TCNTB: - - lt_i = GET_L_TIMER_IDX(offset); - index = GET_L_TIMER_CNT_REG_IDX(offset, lt_i); - - /* - * TCNTB is updated to internal register only after CNT expired. - * Due to this we should reload timer to nearest moment when CNT is - * expired and then in event handler update tcntb to new TCNTB value. - */ - exynos4210_ltick_set_cntb(&s->l_timer[lt_i].tick_timer, value, - s->l_timer[lt_i].tick_timer.icntb); - - s->l_timer[lt_i].reg.wstat |= L_WSTAT_TCNTB_WRITE; - s->l_timer[lt_i].reg.cnt[L_REG_CNT_TCNTB] = value; - -#ifdef DEBUG_MCT - if (tcntb_min[lt_i] > value) { - tcntb_min[lt_i] = value; - } - if (tcntb_max[lt_i] < value) { - tcntb_max[lt_i] = value; - } - DPRINTF("local timer[%d] TCNTB write %llx; max=%x, min=%x\n", - lt_i, value, tcntb_max[lt_i], tcntb_min[lt_i]); -#endif - break; - - case L0_ICNTB: case L1_ICNTB: - - lt_i = GET_L_TIMER_IDX(offset); - index = GET_L_TIMER_CNT_REG_IDX(offset, lt_i); - - s->l_timer[lt_i].reg.wstat |= L_WSTAT_ICNTB_WRITE; - s->l_timer[lt_i].reg.cnt[L_REG_CNT_ICNTB] = value & - ~L_ICNTB_MANUAL_UPDATE; - - /* - * We need to avoid too small values for TCNTB*ICNTB. If not, IRQ event - * could raise too fast disallowing QEMU to execute target code. - */ - if (s->l_timer[lt_i].reg.cnt[L_REG_CNT_ICNTB] * - s->l_timer[lt_i].reg.cnt[L_REG_CNT_TCNTB] < MCT_LT_CNT_LOW_LIMIT) { - if (!s->l_timer[lt_i].reg.cnt[L_REG_CNT_TCNTB]) { - s->l_timer[lt_i].reg.cnt[L_REG_CNT_ICNTB] = - MCT_LT_CNT_LOW_LIMIT; - } else { - s->l_timer[lt_i].reg.cnt[L_REG_CNT_ICNTB] = - MCT_LT_CNT_LOW_LIMIT / - s->l_timer[lt_i].reg.cnt[L_REG_CNT_TCNTB]; - } - } - - if (value & L_ICNTB_MANUAL_UPDATE) { - exynos4210_ltick_set_cntb(&s->l_timer[lt_i].tick_timer, - s->l_timer[lt_i].tick_timer.tcntb, - s->l_timer[lt_i].reg.cnt[L_REG_CNT_ICNTB]); - } - -#ifdef DEBUG_MCT - if (icntb_min[lt_i] > value) { - icntb_min[lt_i] = value; - } - if (icntb_max[lt_i] < value) { - icntb_max[lt_i] = value; - } -DPRINTF("local timer[%d] ICNTB write %llx; max=%x, min=%x\n\n", - lt_i, value, icntb_max[lt_i], icntb_min[lt_i]); -#endif -break; - - case L0_FRCNTB: case L1_FRCNTB: - - lt_i = GET_L_TIMER_IDX(offset); - index = GET_L_TIMER_CNT_REG_IDX(offset, lt_i); - - DPRINTF("local timer[%d] FRCNTB write %llx\n", lt_i, value); - - s->l_timer[lt_i].reg.wstat |= L_WSTAT_FRCCNTB_WRITE; - s->l_timer[lt_i].reg.cnt[L_REG_CNT_FRCCNTB] = value; - - break; - - case L0_TCNTO: case L1_TCNTO: - case L0_ICNTO: case L1_ICNTO: - case L0_FRCNTO: case L1_FRCNTO: - fprintf(stderr, "\n[exynos4210.mct: write to RO register " - TARGET_FMT_plx "]\n\n", offset); - break; - - case L0_INT_CSTAT: case L1_INT_CSTAT: - lt_i = GET_L_TIMER_IDX(offset); - - DPRINTF("local timer[%d] CSTAT write %llx\n", lt_i, value); - - s->l_timer[lt_i].reg.int_cstat &= ~value; - if (!s->l_timer[lt_i].reg.int_cstat) { - qemu_irq_lower(s->l_timer[lt_i].irq); - } - break; - - case L0_INT_ENB: case L1_INT_ENB: - lt_i = GET_L_TIMER_IDX(offset); - old_val = s->l_timer[lt_i].reg.int_enb; - - /* Raise Local timer IRQ if cstat is pending */ - if ((value & L_INT_INTENB_ICNTEIE) > (old_val & L_INT_INTENB_ICNTEIE)) { - if (s->l_timer[lt_i].reg.int_cstat & L_INT_CSTAT_INTCNT) { - qemu_irq_raise(s->l_timer[lt_i].irq); - } - } - - s->l_timer[lt_i].reg.int_enb = value; - - break; - - case L0_WSTAT: case L1_WSTAT: - lt_i = GET_L_TIMER_IDX(offset); - - s->l_timer[lt_i].reg.wstat &= ~value; - break; - - default: - hw_error("exynos4210.mct: bad write offset " - TARGET_FMT_plx "\n", offset); - break; - } -} - -static const MemoryRegionOps exynos4210_mct_ops = { - .read = exynos4210_mct_read, - .write = exynos4210_mct_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -/* MCT init */ -static void exynos4210_mct_init(Object *obj) -{ - int i; - Exynos4210MCTState *s = EXYNOS4210_MCT(obj); - SysBusDevice *dev = SYS_BUS_DEVICE(obj); - QEMUBH *bh[2]; - - /* Global timer */ - bh[0] = qemu_bh_new(exynos4210_gfrc_event, s); - s->g_timer.ptimer_frc = ptimer_init(bh[0]); - memset(&s->g_timer.reg, 0, sizeof(struct gregs)); - - /* Local timers */ - for (i = 0; i < 2; i++) { - bh[0] = qemu_bh_new(exynos4210_ltick_event, &s->l_timer[i]); - bh[1] = qemu_bh_new(exynos4210_lfrc_event, &s->l_timer[i]); - s->l_timer[i].tick_timer.ptimer_tick = ptimer_init(bh[0]); - s->l_timer[i].ptimer_frc = ptimer_init(bh[1]); - s->l_timer[i].id = i; - } - - /* IRQs */ - for (i = 0; i < MCT_GT_CMP_NUM; i++) { - sysbus_init_irq(dev, &s->g_timer.irq[i]); - } - for (i = 0; i < 2; i++) { - sysbus_init_irq(dev, &s->l_timer[i].irq); - } - - memory_region_init_io(&s->iomem, obj, &exynos4210_mct_ops, s, - "exynos4210-mct", MCT_SFR_SIZE); - sysbus_init_mmio(dev, &s->iomem); -} - -static void exynos4210_mct_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - - dc->reset = exynos4210_mct_reset; - dc->vmsd = &vmstate_exynos4210_mct_state; -} - -static const TypeInfo exynos4210_mct_info = { - .name = TYPE_EXYNOS4210_MCT, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(Exynos4210MCTState), - .instance_init = exynos4210_mct_init, - .class_init = exynos4210_mct_class_init, -}; - -static void exynos4210_mct_register_types(void) -{ - type_register_static(&exynos4210_mct_info); -} - -type_init(exynos4210_mct_register_types) diff --git a/qemu/hw/timer/exynos4210_pwm.c b/qemu/hw/timer/exynos4210_pwm.c deleted file mode 100644 index 0e9e2e9bf..000000000 --- a/qemu/hw/timer/exynos4210_pwm.c +++ /dev/null @@ -1,424 +0,0 @@ -/* - * Samsung exynos4210 Pulse Width Modulation Timer - * - * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. - * All rights reserved. - * - * Evgeny Voevodin <e.voevodin@samsung.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, see <http://www.gnu.org/licenses/>. - */ - -#include "qemu/osdep.h" -#include "hw/sysbus.h" -#include "qemu/timer.h" -#include "qemu-common.h" -#include "qemu/main-loop.h" -#include "hw/ptimer.h" - -#include "hw/arm/exynos4210.h" - -//#define DEBUG_PWM - -#ifdef DEBUG_PWM -#define DPRINTF(fmt, ...) \ - do { fprintf(stdout, "PWM: [%24s:%5d] " fmt, __func__, __LINE__, \ - ## __VA_ARGS__); } while (0) -#else -#define DPRINTF(fmt, ...) do {} while (0) -#endif - -#define EXYNOS4210_PWM_TIMERS_NUM 5 -#define EXYNOS4210_PWM_REG_MEM_SIZE 0x50 - -#define TCFG0 0x0000 -#define TCFG1 0x0004 -#define TCON 0x0008 -#define TCNTB0 0x000C -#define TCMPB0 0x0010 -#define TCNTO0 0x0014 -#define TCNTB1 0x0018 -#define TCMPB1 0x001C -#define TCNTO1 0x0020 -#define TCNTB2 0x0024 -#define TCMPB2 0x0028 -#define TCNTO2 0x002C -#define TCNTB3 0x0030 -#define TCMPB3 0x0034 -#define TCNTO3 0x0038 -#define TCNTB4 0x003C -#define TCNTO4 0x0040 -#define TINT_CSTAT 0x0044 - -#define TCNTB(x) (0xC * (x)) -#define TCMPB(x) (0xC * (x) + 1) -#define TCNTO(x) (0xC * (x) + 2) - -#define GET_PRESCALER(reg, x) (((reg) & (0xFF << (8 * (x)))) >> 8 * (x)) -#define GET_DIVIDER(reg, x) (1 << (((reg) & (0xF << (4 * (x)))) >> (4 * (x)))) - -/* - * Attention! Timer4 doesn't have OUTPUT_INVERTER, - * so Auto Reload bit is not accessible by macros! - */ -#define TCON_TIMER_BASE(x) (((x) ? 1 : 0) * 4 + 4 * (x)) -#define TCON_TIMER_START(x) (1 << (TCON_TIMER_BASE(x) + 0)) -#define TCON_TIMER_MANUAL_UPD(x) (1 << (TCON_TIMER_BASE(x) + 1)) -#define TCON_TIMER_OUTPUT_INV(x) (1 << (TCON_TIMER_BASE(x) + 2)) -#define TCON_TIMER_AUTO_RELOAD(x) (1 << (TCON_TIMER_BASE(x) + 3)) -#define TCON_TIMER4_AUTO_RELOAD (1 << 22) - -#define TINT_CSTAT_STATUS(x) (1 << (5 + (x))) -#define TINT_CSTAT_ENABLE(x) (1 << (x)) - -/* timer struct */ -typedef struct { - uint32_t id; /* timer id */ - qemu_irq irq; /* local timer irq */ - uint32_t freq; /* timer frequency */ - - /* use ptimer.c to represent count down timer */ - ptimer_state *ptimer; /* timer */ - - /* registers */ - uint32_t reg_tcntb; /* counter register buffer */ - uint32_t reg_tcmpb; /* compare register buffer */ - - struct Exynos4210PWMState *parent; - -} Exynos4210PWM; - -#define TYPE_EXYNOS4210_PWM "exynos4210.pwm" -#define EXYNOS4210_PWM(obj) \ - OBJECT_CHECK(Exynos4210PWMState, (obj), TYPE_EXYNOS4210_PWM) - -typedef struct Exynos4210PWMState { - SysBusDevice parent_obj; - - MemoryRegion iomem; - - uint32_t reg_tcfg[2]; - uint32_t reg_tcon; - uint32_t reg_tint_cstat; - - Exynos4210PWM timer[EXYNOS4210_PWM_TIMERS_NUM]; - -} Exynos4210PWMState; - -/*** VMState ***/ -static const VMStateDescription vmstate_exynos4210_pwm = { - .name = "exynos4210.pwm.pwm", - .version_id = 1, - .minimum_version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_UINT32(id, Exynos4210PWM), - VMSTATE_UINT32(freq, Exynos4210PWM), - VMSTATE_PTIMER(ptimer, Exynos4210PWM), - VMSTATE_UINT32(reg_tcntb, Exynos4210PWM), - VMSTATE_UINT32(reg_tcmpb, Exynos4210PWM), - VMSTATE_END_OF_LIST() - } -}; - -static const VMStateDescription vmstate_exynos4210_pwm_state = { - .name = "exynos4210.pwm", - .version_id = 1, - .minimum_version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_UINT32_ARRAY(reg_tcfg, Exynos4210PWMState, 2), - VMSTATE_UINT32(reg_tcon, Exynos4210PWMState), - VMSTATE_UINT32(reg_tint_cstat, Exynos4210PWMState), - VMSTATE_STRUCT_ARRAY(timer, Exynos4210PWMState, - EXYNOS4210_PWM_TIMERS_NUM, 0, - vmstate_exynos4210_pwm, Exynos4210PWM), - VMSTATE_END_OF_LIST() - } -}; - -/* - * PWM update frequency - */ -static void exynos4210_pwm_update_freq(Exynos4210PWMState *s, uint32_t id) -{ - uint32_t freq; - freq = s->timer[id].freq; - if (id > 1) { - s->timer[id].freq = 24000000 / - ((GET_PRESCALER(s->reg_tcfg[0], 1) + 1) * - (GET_DIVIDER(s->reg_tcfg[1], id))); - } else { - s->timer[id].freq = 24000000 / - ((GET_PRESCALER(s->reg_tcfg[0], 0) + 1) * - (GET_DIVIDER(s->reg_tcfg[1], id))); - } - - if (freq != s->timer[id].freq) { - ptimer_set_freq(s->timer[id].ptimer, s->timer[id].freq); - DPRINTF("freq=%dHz\n", s->timer[id].freq); - } -} - -/* - * Counter tick handler - */ -static void exynos4210_pwm_tick(void *opaque) -{ - Exynos4210PWM *s = (Exynos4210PWM *)opaque; - Exynos4210PWMState *p = (Exynos4210PWMState *)s->parent; - uint32_t id = s->id; - bool cmp; - - DPRINTF("timer %d tick\n", id); - - /* set irq status */ - p->reg_tint_cstat |= TINT_CSTAT_STATUS(id); - - /* raise IRQ */ - if (p->reg_tint_cstat & TINT_CSTAT_ENABLE(id)) { - DPRINTF("timer %d IRQ\n", id); - qemu_irq_raise(p->timer[id].irq); - } - - /* reload timer */ - if (id != 4) { - cmp = p->reg_tcon & TCON_TIMER_AUTO_RELOAD(id); - } else { - cmp = p->reg_tcon & TCON_TIMER4_AUTO_RELOAD; - } - - if (cmp) { - DPRINTF("auto reload timer %d count to %x\n", id, - p->timer[id].reg_tcntb); - ptimer_set_count(p->timer[id].ptimer, p->timer[id].reg_tcntb); - ptimer_run(p->timer[id].ptimer, 1); - } else { - /* stop timer, set status to STOP, see Basic Timer Operation */ - p->reg_tcon &= ~TCON_TIMER_START(id); - ptimer_stop(p->timer[id].ptimer); - } -} - -/* - * PWM Read - */ -static uint64_t exynos4210_pwm_read(void *opaque, hwaddr offset, - unsigned size) -{ - Exynos4210PWMState *s = (Exynos4210PWMState *)opaque; - uint32_t value = 0; - int index; - - switch (offset) { - case TCFG0: case TCFG1: - index = (offset - TCFG0) >> 2; - value = s->reg_tcfg[index]; - break; - - case TCON: - value = s->reg_tcon; - break; - - case TCNTB0: case TCNTB1: - case TCNTB2: case TCNTB3: case TCNTB4: - index = (offset - TCNTB0) / 0xC; - value = s->timer[index].reg_tcntb; - break; - - case TCMPB0: case TCMPB1: - case TCMPB2: case TCMPB3: - index = (offset - TCMPB0) / 0xC; - value = s->timer[index].reg_tcmpb; - break; - - case TCNTO0: case TCNTO1: - case TCNTO2: case TCNTO3: case TCNTO4: - index = (offset == TCNTO4) ? 4 : (offset - TCNTO0) / 0xC; - value = ptimer_get_count(s->timer[index].ptimer); - break; - - case TINT_CSTAT: - value = s->reg_tint_cstat; - break; - - default: - fprintf(stderr, - "[exynos4210.pwm: bad read offset " TARGET_FMT_plx "]\n", - offset); - break; - } - return value; -} - -/* - * PWM Write - */ -static void exynos4210_pwm_write(void *opaque, hwaddr offset, - uint64_t value, unsigned size) -{ - Exynos4210PWMState *s = (Exynos4210PWMState *)opaque; - int index; - uint32_t new_val; - int i; - - switch (offset) { - case TCFG0: case TCFG1: - index = (offset - TCFG0) >> 2; - s->reg_tcfg[index] = value; - - /* update timers frequencies */ - for (i = 0; i < EXYNOS4210_PWM_TIMERS_NUM; i++) { - exynos4210_pwm_update_freq(s, s->timer[i].id); - } - break; - - case TCON: - for (i = 0; i < EXYNOS4210_PWM_TIMERS_NUM; i++) { - if ((value & TCON_TIMER_MANUAL_UPD(i)) > - (s->reg_tcon & TCON_TIMER_MANUAL_UPD(i))) { - /* - * TCNTB and TCMPB are loaded into TCNT and TCMP. - * Update timers. - */ - - /* this will start timer to run, this ok, because - * during processing start bit timer will be stopped - * if needed */ - ptimer_set_count(s->timer[i].ptimer, s->timer[i].reg_tcntb); - DPRINTF("set timer %d count to %x\n", i, - s->timer[i].reg_tcntb); - } - - if ((value & TCON_TIMER_START(i)) > - (s->reg_tcon & TCON_TIMER_START(i))) { - /* changed to start */ - ptimer_run(s->timer[i].ptimer, 1); - DPRINTF("run timer %d\n", i); - } - - if ((value & TCON_TIMER_START(i)) < - (s->reg_tcon & TCON_TIMER_START(i))) { - /* changed to stop */ - ptimer_stop(s->timer[i].ptimer); - DPRINTF("stop timer %d\n", i); - } - } - s->reg_tcon = value; - break; - - case TCNTB0: case TCNTB1: - case TCNTB2: case TCNTB3: case TCNTB4: - index = (offset - TCNTB0) / 0xC; - s->timer[index].reg_tcntb = value; - break; - - case TCMPB0: case TCMPB1: - case TCMPB2: case TCMPB3: - index = (offset - TCMPB0) / 0xC; - s->timer[index].reg_tcmpb = value; - break; - - case TINT_CSTAT: - new_val = (s->reg_tint_cstat & 0x3E0) + (0x1F & value); - new_val &= ~(0x3E0 & value); - - for (i = 0; i < EXYNOS4210_PWM_TIMERS_NUM; i++) { - if ((new_val & TINT_CSTAT_STATUS(i)) < - (s->reg_tint_cstat & TINT_CSTAT_STATUS(i))) { - qemu_irq_lower(s->timer[i].irq); - } - } - - s->reg_tint_cstat = new_val; - break; - - default: - fprintf(stderr, - "[exynos4210.pwm: bad write offset " TARGET_FMT_plx "]\n", - offset); - break; - - } -} - -/* - * Set default values to timer fields and registers - */ -static void exynos4210_pwm_reset(DeviceState *d) -{ - Exynos4210PWMState *s = EXYNOS4210_PWM(d); - int i; - s->reg_tcfg[0] = 0x0101; - s->reg_tcfg[1] = 0x0; - s->reg_tcon = 0; - s->reg_tint_cstat = 0; - for (i = 0; i < EXYNOS4210_PWM_TIMERS_NUM; i++) { - s->timer[i].reg_tcmpb = 0; - s->timer[i].reg_tcntb = 0; - - exynos4210_pwm_update_freq(s, s->timer[i].id); - ptimer_stop(s->timer[i].ptimer); - } -} - -static const MemoryRegionOps exynos4210_pwm_ops = { - .read = exynos4210_pwm_read, - .write = exynos4210_pwm_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -/* - * PWM timer initialization - */ -static void exynos4210_pwm_init(Object *obj) -{ - Exynos4210PWMState *s = EXYNOS4210_PWM(obj); - SysBusDevice *dev = SYS_BUS_DEVICE(obj); - int i; - QEMUBH *bh; - - for (i = 0; i < EXYNOS4210_PWM_TIMERS_NUM; i++) { - bh = qemu_bh_new(exynos4210_pwm_tick, &s->timer[i]); - sysbus_init_irq(dev, &s->timer[i].irq); - s->timer[i].ptimer = ptimer_init(bh); - s->timer[i].id = i; - s->timer[i].parent = s; - } - - memory_region_init_io(&s->iomem, obj, &exynos4210_pwm_ops, s, - "exynos4210-pwm", EXYNOS4210_PWM_REG_MEM_SIZE); - sysbus_init_mmio(dev, &s->iomem); -} - -static void exynos4210_pwm_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - - dc->reset = exynos4210_pwm_reset; - dc->vmsd = &vmstate_exynos4210_pwm_state; -} - -static const TypeInfo exynos4210_pwm_info = { - .name = TYPE_EXYNOS4210_PWM, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(Exynos4210PWMState), - .instance_init = exynos4210_pwm_init, - .class_init = exynos4210_pwm_class_init, -}; - -static void exynos4210_pwm_register_types(void) -{ - type_register_static(&exynos4210_pwm_info); -} - -type_init(exynos4210_pwm_register_types) diff --git a/qemu/hw/timer/exynos4210_rtc.c b/qemu/hw/timer/exynos4210_rtc.c deleted file mode 100644 index da4dd451b..000000000 --- a/qemu/hw/timer/exynos4210_rtc.c +++ /dev/null @@ -1,595 +0,0 @@ -/* - * Samsung exynos4210 Real Time Clock - * - * Copyright (c) 2012 Samsung Electronics Co., Ltd. - * Ogurtsov Oleg <o.ogurtsov@samsung.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, see <http://www.gnu.org/licenses/>. - * - */ - -/* Description: - * Register RTCCON: - * CLKSEL Bit[1] not used - * CLKOUTEN Bit[9] not used - */ - -#include "qemu/osdep.h" -#include "hw/sysbus.h" -#include "qemu/timer.h" -#include "qemu-common.h" -#include "qemu/bcd.h" -#include "hw/ptimer.h" - -#include "hw/hw.h" -#include "sysemu/sysemu.h" - -#include "hw/arm/exynos4210.h" - -#define DEBUG_RTC 0 - -#if DEBUG_RTC -#define DPRINTF(fmt, ...) \ - do { fprintf(stdout, "RTC: [%24s:%5d] " fmt, __func__, __LINE__, \ - ## __VA_ARGS__); } while (0) -#else -#define DPRINTF(fmt, ...) do {} while (0) -#endif - -#define EXYNOS4210_RTC_REG_MEM_SIZE 0x0100 - -#define INTP 0x0030 -#define RTCCON 0x0040 -#define TICCNT 0x0044 -#define RTCALM 0x0050 -#define ALMSEC 0x0054 -#define ALMMIN 0x0058 -#define ALMHOUR 0x005C -#define ALMDAY 0x0060 -#define ALMMON 0x0064 -#define ALMYEAR 0x0068 -#define BCDSEC 0x0070 -#define BCDMIN 0x0074 -#define BCDHOUR 0x0078 -#define BCDDAY 0x007C -#define BCDDAYWEEK 0x0080 -#define BCDMON 0x0084 -#define BCDYEAR 0x0088 -#define CURTICNT 0x0090 - -#define TICK_TIMER_ENABLE 0x0100 -#define TICNT_THRESHOLD 2 - - -#define RTC_ENABLE 0x0001 - -#define INTP_TICK_ENABLE 0x0001 -#define INTP_ALM_ENABLE 0x0002 - -#define ALARM_INT_ENABLE 0x0040 - -#define RTC_BASE_FREQ 32768 - -#define TYPE_EXYNOS4210_RTC "exynos4210.rtc" -#define EXYNOS4210_RTC(obj) \ - OBJECT_CHECK(Exynos4210RTCState, (obj), TYPE_EXYNOS4210_RTC) - -typedef struct Exynos4210RTCState { - SysBusDevice parent_obj; - - MemoryRegion iomem; - - /* registers */ - uint32_t reg_intp; - uint32_t reg_rtccon; - uint32_t reg_ticcnt; - uint32_t reg_rtcalm; - uint32_t reg_almsec; - uint32_t reg_almmin; - uint32_t reg_almhour; - uint32_t reg_almday; - uint32_t reg_almmon; - uint32_t reg_almyear; - uint32_t reg_curticcnt; - - ptimer_state *ptimer; /* tick timer */ - ptimer_state *ptimer_1Hz; /* clock timer */ - uint32_t freq; - - qemu_irq tick_irq; /* Time Tick Generator irq */ - qemu_irq alm_irq; /* alarm irq */ - - struct tm current_tm; /* current time */ -} Exynos4210RTCState; - -#define TICCKSEL(value) ((value & (0x0F << 4)) >> 4) - -/*** VMState ***/ -static const VMStateDescription vmstate_exynos4210_rtc_state = { - .name = "exynos4210.rtc", - .version_id = 1, - .minimum_version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_UINT32(reg_intp, Exynos4210RTCState), - VMSTATE_UINT32(reg_rtccon, Exynos4210RTCState), - VMSTATE_UINT32(reg_ticcnt, Exynos4210RTCState), - VMSTATE_UINT32(reg_rtcalm, Exynos4210RTCState), - VMSTATE_UINT32(reg_almsec, Exynos4210RTCState), - VMSTATE_UINT32(reg_almmin, Exynos4210RTCState), - VMSTATE_UINT32(reg_almhour, Exynos4210RTCState), - VMSTATE_UINT32(reg_almday, Exynos4210RTCState), - VMSTATE_UINT32(reg_almmon, Exynos4210RTCState), - VMSTATE_UINT32(reg_almyear, Exynos4210RTCState), - VMSTATE_UINT32(reg_curticcnt, Exynos4210RTCState), - VMSTATE_PTIMER(ptimer, Exynos4210RTCState), - VMSTATE_PTIMER(ptimer_1Hz, Exynos4210RTCState), - VMSTATE_UINT32(freq, Exynos4210RTCState), - VMSTATE_INT32(current_tm.tm_sec, Exynos4210RTCState), - VMSTATE_INT32(current_tm.tm_min, Exynos4210RTCState), - VMSTATE_INT32(current_tm.tm_hour, Exynos4210RTCState), - VMSTATE_INT32(current_tm.tm_wday, Exynos4210RTCState), - VMSTATE_INT32(current_tm.tm_mday, Exynos4210RTCState), - VMSTATE_INT32(current_tm.tm_mon, Exynos4210RTCState), - VMSTATE_INT32(current_tm.tm_year, Exynos4210RTCState), - VMSTATE_END_OF_LIST() - } -}; - -#define BCD3DIGITS(x) \ - ((uint32_t)to_bcd((uint8_t)(x % 100)) + \ - ((uint32_t)to_bcd((uint8_t)((x % 1000) / 100)) << 8)) - -static void check_alarm_raise(Exynos4210RTCState *s) -{ - unsigned int alarm_raise = 0; - struct tm stm = s->current_tm; - - if ((s->reg_rtcalm & 0x01) && - (to_bcd((uint8_t)stm.tm_sec) == (uint8_t)s->reg_almsec)) { - alarm_raise = 1; - } - if ((s->reg_rtcalm & 0x02) && - (to_bcd((uint8_t)stm.tm_min) == (uint8_t)s->reg_almmin)) { - alarm_raise = 1; - } - if ((s->reg_rtcalm & 0x04) && - (to_bcd((uint8_t)stm.tm_hour) == (uint8_t)s->reg_almhour)) { - alarm_raise = 1; - } - if ((s->reg_rtcalm & 0x08) && - (to_bcd((uint8_t)stm.tm_mday) == (uint8_t)s->reg_almday)) { - alarm_raise = 1; - } - if ((s->reg_rtcalm & 0x10) && - (to_bcd((uint8_t)stm.tm_mon) == (uint8_t)s->reg_almmon)) { - alarm_raise = 1; - } - if ((s->reg_rtcalm & 0x20) && - (BCD3DIGITS(stm.tm_year) == s->reg_almyear)) { - alarm_raise = 1; - } - - if (alarm_raise) { - DPRINTF("ALARM IRQ\n"); - /* set irq status */ - s->reg_intp |= INTP_ALM_ENABLE; - qemu_irq_raise(s->alm_irq); - } -} - -/* - * RTC update frequency - * Parameters: - * reg_value - current RTCCON register or his new value - */ -static void exynos4210_rtc_update_freq(Exynos4210RTCState *s, - uint32_t reg_value) -{ - uint32_t freq; - - freq = s->freq; - /* set frequncy for time generator */ - s->freq = RTC_BASE_FREQ / (1 << TICCKSEL(reg_value)); - - if (freq != s->freq) { - ptimer_set_freq(s->ptimer, s->freq); - DPRINTF("freq=%dHz\n", s->freq); - } -} - -/* month is between 0 and 11. */ -static int get_days_in_month(int month, int year) -{ - static const int days_tab[12] = { - 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 - }; - int d; - if ((unsigned)month >= 12) { - return 31; - } - d = days_tab[month]; - if (month == 1) { - if ((year % 4) == 0 && ((year % 100) != 0 || (year % 400) == 0)) { - d++; - } - } - return d; -} - -/* update 'tm' to the next second */ -static void rtc_next_second(struct tm *tm) -{ - int days_in_month; - - tm->tm_sec++; - if ((unsigned)tm->tm_sec >= 60) { - tm->tm_sec = 0; - tm->tm_min++; - if ((unsigned)tm->tm_min >= 60) { - tm->tm_min = 0; - tm->tm_hour++; - if ((unsigned)tm->tm_hour >= 24) { - tm->tm_hour = 0; - /* next day */ - tm->tm_wday++; - if ((unsigned)tm->tm_wday >= 7) { - tm->tm_wday = 0; - } - days_in_month = get_days_in_month(tm->tm_mon, - tm->tm_year + 1900); - tm->tm_mday++; - if (tm->tm_mday < 1) { - tm->tm_mday = 1; - } else if (tm->tm_mday > days_in_month) { - tm->tm_mday = 1; - tm->tm_mon++; - if (tm->tm_mon >= 12) { - tm->tm_mon = 0; - tm->tm_year++; - } - } - } - } - } -} - -/* - * tick handler - */ -static void exynos4210_rtc_tick(void *opaque) -{ - Exynos4210RTCState *s = (Exynos4210RTCState *)opaque; - - DPRINTF("TICK IRQ\n"); - /* set irq status */ - s->reg_intp |= INTP_TICK_ENABLE; - /* raise IRQ */ - qemu_irq_raise(s->tick_irq); - - /* restart timer */ - ptimer_set_count(s->ptimer, s->reg_ticcnt); - ptimer_run(s->ptimer, 1); -} - -/* - * 1Hz clock handler - */ -static void exynos4210_rtc_1Hz_tick(void *opaque) -{ - Exynos4210RTCState *s = (Exynos4210RTCState *)opaque; - - rtc_next_second(&s->current_tm); - /* DPRINTF("1Hz tick\n"); */ - - /* raise IRQ */ - if (s->reg_rtcalm & ALARM_INT_ENABLE) { - check_alarm_raise(s); - } - - ptimer_set_count(s->ptimer_1Hz, RTC_BASE_FREQ); - ptimer_run(s->ptimer_1Hz, 1); -} - -/* - * RTC Read - */ -static uint64_t exynos4210_rtc_read(void *opaque, hwaddr offset, - unsigned size) -{ - uint32_t value = 0; - Exynos4210RTCState *s = (Exynos4210RTCState *)opaque; - - switch (offset) { - case INTP: - value = s->reg_intp; - break; - case RTCCON: - value = s->reg_rtccon; - break; - case TICCNT: - value = s->reg_ticcnt; - break; - case RTCALM: - value = s->reg_rtcalm; - break; - case ALMSEC: - value = s->reg_almsec; - break; - case ALMMIN: - value = s->reg_almmin; - break; - case ALMHOUR: - value = s->reg_almhour; - break; - case ALMDAY: - value = s->reg_almday; - break; - case ALMMON: - value = s->reg_almmon; - break; - case ALMYEAR: - value = s->reg_almyear; - break; - - case BCDSEC: - value = (uint32_t)to_bcd((uint8_t)s->current_tm.tm_sec); - break; - case BCDMIN: - value = (uint32_t)to_bcd((uint8_t)s->current_tm.tm_min); - break; - case BCDHOUR: - value = (uint32_t)to_bcd((uint8_t)s->current_tm.tm_hour); - break; - case BCDDAYWEEK: - value = (uint32_t)to_bcd((uint8_t)s->current_tm.tm_wday); - break; - case BCDDAY: - value = (uint32_t)to_bcd((uint8_t)s->current_tm.tm_mday); - break; - case BCDMON: - value = (uint32_t)to_bcd((uint8_t)s->current_tm.tm_mon + 1); - break; - case BCDYEAR: - value = BCD3DIGITS(s->current_tm.tm_year); - break; - - case CURTICNT: - s->reg_curticcnt = ptimer_get_count(s->ptimer); - value = s->reg_curticcnt; - break; - - default: - fprintf(stderr, - "[exynos4210.rtc: bad read offset " TARGET_FMT_plx "]\n", - offset); - break; - } - return value; -} - -/* - * RTC Write - */ -static void exynos4210_rtc_write(void *opaque, hwaddr offset, - uint64_t value, unsigned size) -{ - Exynos4210RTCState *s = (Exynos4210RTCState *)opaque; - - switch (offset) { - case INTP: - if (value & INTP_ALM_ENABLE) { - qemu_irq_lower(s->alm_irq); - s->reg_intp &= (~INTP_ALM_ENABLE); - } - if (value & INTP_TICK_ENABLE) { - qemu_irq_lower(s->tick_irq); - s->reg_intp &= (~INTP_TICK_ENABLE); - } - break; - case RTCCON: - if (value & RTC_ENABLE) { - exynos4210_rtc_update_freq(s, value); - } - if ((value & RTC_ENABLE) > (s->reg_rtccon & RTC_ENABLE)) { - /* clock timer */ - ptimer_set_count(s->ptimer_1Hz, RTC_BASE_FREQ); - ptimer_run(s->ptimer_1Hz, 1); - DPRINTF("run clock timer\n"); - } - if ((value & RTC_ENABLE) < (s->reg_rtccon & RTC_ENABLE)) { - /* tick timer */ - ptimer_stop(s->ptimer); - /* clock timer */ - ptimer_stop(s->ptimer_1Hz); - DPRINTF("stop all timers\n"); - } - if (value & RTC_ENABLE) { - if ((value & TICK_TIMER_ENABLE) > - (s->reg_rtccon & TICK_TIMER_ENABLE) && - (s->reg_ticcnt)) { - ptimer_set_count(s->ptimer, s->reg_ticcnt); - ptimer_run(s->ptimer, 1); - DPRINTF("run tick timer\n"); - } - if ((value & TICK_TIMER_ENABLE) < - (s->reg_rtccon & TICK_TIMER_ENABLE)) { - ptimer_stop(s->ptimer); - } - } - s->reg_rtccon = value; - break; - case TICCNT: - if (value > TICNT_THRESHOLD) { - s->reg_ticcnt = value; - } else { - fprintf(stderr, - "[exynos4210.rtc: bad TICNT value %u ]\n", - (uint32_t)value); - } - break; - - case RTCALM: - s->reg_rtcalm = value; - break; - case ALMSEC: - s->reg_almsec = (value & 0x7f); - break; - case ALMMIN: - s->reg_almmin = (value & 0x7f); - break; - case ALMHOUR: - s->reg_almhour = (value & 0x3f); - break; - case ALMDAY: - s->reg_almday = (value & 0x3f); - break; - case ALMMON: - s->reg_almmon = (value & 0x1f); - break; - case ALMYEAR: - s->reg_almyear = (value & 0x0fff); - break; - - case BCDSEC: - if (s->reg_rtccon & RTC_ENABLE) { - s->current_tm.tm_sec = (int)from_bcd((uint8_t)value); - } - break; - case BCDMIN: - if (s->reg_rtccon & RTC_ENABLE) { - s->current_tm.tm_min = (int)from_bcd((uint8_t)value); - } - break; - case BCDHOUR: - if (s->reg_rtccon & RTC_ENABLE) { - s->current_tm.tm_hour = (int)from_bcd((uint8_t)value); - } - break; - case BCDDAYWEEK: - if (s->reg_rtccon & RTC_ENABLE) { - s->current_tm.tm_wday = (int)from_bcd((uint8_t)value); - } - break; - case BCDDAY: - if (s->reg_rtccon & RTC_ENABLE) { - s->current_tm.tm_mday = (int)from_bcd((uint8_t)value); - } - break; - case BCDMON: - if (s->reg_rtccon & RTC_ENABLE) { - s->current_tm.tm_mon = (int)from_bcd((uint8_t)value) - 1; - } - break; - case BCDYEAR: - if (s->reg_rtccon & RTC_ENABLE) { - /* 3 digits */ - s->current_tm.tm_year = (int)from_bcd((uint8_t)value) + - (int)from_bcd((uint8_t)((value >> 8) & 0x0f)) * 100; - } - break; - - default: - fprintf(stderr, - "[exynos4210.rtc: bad write offset " TARGET_FMT_plx "]\n", - offset); - break; - - } -} - -/* - * Set default values to timer fields and registers - */ -static void exynos4210_rtc_reset(DeviceState *d) -{ - Exynos4210RTCState *s = EXYNOS4210_RTC(d); - - qemu_get_timedate(&s->current_tm, 0); - - DPRINTF("Get time from host: %d-%d-%d %2d:%02d:%02d\n", - s->current_tm.tm_year, s->current_tm.tm_mon, s->current_tm.tm_mday, - s->current_tm.tm_hour, s->current_tm.tm_min, s->current_tm.tm_sec); - - s->reg_intp = 0; - s->reg_rtccon = 0; - s->reg_ticcnt = 0; - s->reg_rtcalm = 0; - s->reg_almsec = 0; - s->reg_almmin = 0; - s->reg_almhour = 0; - s->reg_almday = 0; - s->reg_almmon = 0; - s->reg_almyear = 0; - - s->reg_curticcnt = 0; - - exynos4210_rtc_update_freq(s, s->reg_rtccon); - ptimer_stop(s->ptimer); - ptimer_stop(s->ptimer_1Hz); -} - -static const MemoryRegionOps exynos4210_rtc_ops = { - .read = exynos4210_rtc_read, - .write = exynos4210_rtc_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -/* - * RTC timer initialization - */ -static void exynos4210_rtc_init(Object *obj) -{ - Exynos4210RTCState *s = EXYNOS4210_RTC(obj); - SysBusDevice *dev = SYS_BUS_DEVICE(obj); - QEMUBH *bh; - - bh = qemu_bh_new(exynos4210_rtc_tick, s); - s->ptimer = ptimer_init(bh); - ptimer_set_freq(s->ptimer, RTC_BASE_FREQ); - exynos4210_rtc_update_freq(s, 0); - - bh = qemu_bh_new(exynos4210_rtc_1Hz_tick, s); - s->ptimer_1Hz = ptimer_init(bh); - ptimer_set_freq(s->ptimer_1Hz, RTC_BASE_FREQ); - - sysbus_init_irq(dev, &s->alm_irq); - sysbus_init_irq(dev, &s->tick_irq); - - memory_region_init_io(&s->iomem, obj, &exynos4210_rtc_ops, s, - "exynos4210-rtc", EXYNOS4210_RTC_REG_MEM_SIZE); - sysbus_init_mmio(dev, &s->iomem); -} - -static void exynos4210_rtc_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - - dc->reset = exynos4210_rtc_reset; - dc->vmsd = &vmstate_exynos4210_rtc_state; -} - -static const TypeInfo exynos4210_rtc_info = { - .name = TYPE_EXYNOS4210_RTC, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(Exynos4210RTCState), - .instance_init = exynos4210_rtc_init, - .class_init = exynos4210_rtc_class_init, -}; - -static void exynos4210_rtc_register_types(void) -{ - type_register_static(&exynos4210_rtc_info); -} - -type_init(exynos4210_rtc_register_types) diff --git a/qemu/hw/timer/grlib_gptimer.c b/qemu/hw/timer/grlib_gptimer.c deleted file mode 100644 index dd000f5af..000000000 --- a/qemu/hw/timer/grlib_gptimer.c +++ /dev/null @@ -1,412 +0,0 @@ -/* - * QEMU GRLIB GPTimer Emulator - * - * Copyright (c) 2010-2011 AdaCore - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#include "qemu/osdep.h" -#include "hw/sysbus.h" -#include "qemu/timer.h" -#include "hw/ptimer.h" -#include "qemu/timer.h" -#include "qemu/main-loop.h" - -#include "trace.h" - -#define UNIT_REG_SIZE 16 /* Size of memory mapped regs for the unit */ -#define GPTIMER_REG_SIZE 16 /* Size of memory mapped regs for a GPTimer */ - -#define GPTIMER_MAX_TIMERS 8 - -/* GPTimer Config register fields */ -#define GPTIMER_ENABLE (1 << 0) -#define GPTIMER_RESTART (1 << 1) -#define GPTIMER_LOAD (1 << 2) -#define GPTIMER_INT_ENABLE (1 << 3) -#define GPTIMER_INT_PENDING (1 << 4) -#define GPTIMER_CHAIN (1 << 5) /* Not supported */ -#define GPTIMER_DEBUG_HALT (1 << 6) /* Not supported */ - -/* Memory mapped register offsets */ -#define SCALER_OFFSET 0x00 -#define SCALER_RELOAD_OFFSET 0x04 -#define CONFIG_OFFSET 0x08 -#define COUNTER_OFFSET 0x00 -#define COUNTER_RELOAD_OFFSET 0x04 -#define TIMER_BASE 0x10 - -#define TYPE_GRLIB_GPTIMER "grlib,gptimer" -#define GRLIB_GPTIMER(obj) \ - OBJECT_CHECK(GPTimerUnit, (obj), TYPE_GRLIB_GPTIMER) - -typedef struct GPTimer GPTimer; -typedef struct GPTimerUnit GPTimerUnit; - -struct GPTimer { - QEMUBH *bh; - struct ptimer_state *ptimer; - - qemu_irq irq; - int id; - GPTimerUnit *unit; - - /* registers */ - uint32_t counter; - uint32_t reload; - uint32_t config; -}; - -struct GPTimerUnit { - SysBusDevice parent_obj; - - MemoryRegion iomem; - - uint32_t nr_timers; /* Number of timers available */ - uint32_t freq_hz; /* System frequency */ - uint32_t irq_line; /* Base irq line */ - - GPTimer *timers; - - /* registers */ - uint32_t scaler; - uint32_t reload; - uint32_t config; -}; - -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); - - ptimer_set_count(timer->ptimer, (uint64_t)timer->counter + 1); - ptimer_run(timer->ptimer, 1); -} - -static void grlib_gptimer_restart(GPTimer *timer) -{ - assert(timer != NULL); - - trace_grlib_gptimer_restart(timer->id, timer->reload); - - timer->counter = timer->reload; - grlib_gptimer_enable(timer); -} - -static void grlib_gptimer_set_scaler(GPTimerUnit *unit, uint32_t scaler) -{ - int i = 0; - uint32_t value = 0; - - assert(unit != NULL); - - if (scaler > 0) { - value = unit->freq_hz / (scaler + 1); - } else { - value = unit->freq_hz; - } - - trace_grlib_gptimer_set_scaler(scaler, value); - - for (i = 0; i < unit->nr_timers; i++) { - ptimer_set_freq(unit->timers[i].ptimer, value); - } -} - -static void grlib_gptimer_hit(void *opaque) -{ - GPTimer *timer = opaque; - assert(timer != NULL); - - trace_grlib_gptimer_hit(timer->id); - - /* Timer expired */ - - if (timer->config & GPTIMER_INT_ENABLE) { - /* Set the pending bit (only unset by write in the config register) */ - timer->config |= GPTIMER_INT_PENDING; - qemu_irq_pulse(timer->irq); - } - - if (timer->config & GPTIMER_RESTART) { - grlib_gptimer_restart(timer); - } -} - -static uint64_t grlib_gptimer_read(void *opaque, hwaddr addr, - unsigned size) -{ - GPTimerUnit *unit = opaque; - hwaddr timer_addr; - int id; - uint32_t value = 0; - - addr &= 0xff; - - /* Unit registers */ - switch (addr) { - case SCALER_OFFSET: - trace_grlib_gptimer_readl(-1, addr, unit->scaler); - return unit->scaler; - - case SCALER_RELOAD_OFFSET: - trace_grlib_gptimer_readl(-1, addr, unit->reload); - return unit->reload; - - case CONFIG_OFFSET: - trace_grlib_gptimer_readl(-1, addr, unit->config); - return unit->config; - - default: - break; - } - - timer_addr = (addr % TIMER_BASE); - id = (addr - TIMER_BASE) / TIMER_BASE; - - if (id >= 0 && id < unit->nr_timers) { - - /* GPTimer registers */ - switch (timer_addr) { - case COUNTER_OFFSET: - value = ptimer_get_count(unit->timers[id].ptimer); - trace_grlib_gptimer_readl(id, addr, value); - return value; - - case COUNTER_RELOAD_OFFSET: - value = unit->timers[id].reload; - trace_grlib_gptimer_readl(id, addr, value); - return value; - - case CONFIG_OFFSET: - trace_grlib_gptimer_readl(id, addr, unit->timers[id].config); - return unit->timers[id].config; - - default: - break; - } - - } - - trace_grlib_gptimer_readl(-1, addr, 0); - return 0; -} - -static void grlib_gptimer_write(void *opaque, hwaddr addr, - uint64_t value, unsigned size) -{ - GPTimerUnit *unit = opaque; - hwaddr timer_addr; - int id; - - addr &= 0xff; - - /* Unit registers */ - switch (addr) { - case SCALER_OFFSET: - value &= 0xFFFF; /* clean up the value */ - unit->scaler = value; - trace_grlib_gptimer_writel(-1, addr, unit->scaler); - return; - - case SCALER_RELOAD_OFFSET: - value &= 0xFFFF; /* clean up the value */ - unit->reload = value; - trace_grlib_gptimer_writel(-1, addr, unit->reload); - grlib_gptimer_set_scaler(unit, value); - return; - - case CONFIG_OFFSET: - /* Read Only (disable timer freeze not supported) */ - trace_grlib_gptimer_writel(-1, addr, 0); - return; - - default: - break; - } - - timer_addr = (addr % TIMER_BASE); - id = (addr - TIMER_BASE) / TIMER_BASE; - - if (id >= 0 && id < unit->nr_timers) { - - /* GPTimer registers */ - switch (timer_addr) { - case COUNTER_OFFSET: - trace_grlib_gptimer_writel(id, addr, value); - unit->timers[id].counter = value; - grlib_gptimer_enable(&unit->timers[id]); - return; - - case COUNTER_RELOAD_OFFSET: - trace_grlib_gptimer_writel(id, addr, value); - unit->timers[id].reload = value; - return; - - case CONFIG_OFFSET: - trace_grlib_gptimer_writel(id, addr, value); - - if (value & GPTIMER_INT_PENDING) { - /* clear pending bit */ - value &= ~GPTIMER_INT_PENDING; - } else { - /* keep pending bit */ - value |= unit->timers[id].config & GPTIMER_INT_PENDING; - } - - unit->timers[id].config = value; - - /* gptimer_restart calls gptimer_enable, so if "enable" and "load" - bits are present, we just have to call restart. */ - - if (value & GPTIMER_LOAD) { - grlib_gptimer_restart(&unit->timers[id]); - } else if (value & GPTIMER_ENABLE) { - grlib_gptimer_enable(&unit->timers[id]); - } - - /* These fields must always be read as 0 */ - value &= ~(GPTIMER_LOAD & GPTIMER_DEBUG_HALT); - - unit->timers[id].config = value; - return; - - default: - break; - } - - } - - trace_grlib_gptimer_writel(-1, addr, value); -} - -static const MemoryRegionOps grlib_gptimer_ops = { - .read = grlib_gptimer_read, - .write = grlib_gptimer_write, - .endianness = DEVICE_NATIVE_ENDIAN, - .valid = { - .min_access_size = 4, - .max_access_size = 4, - }, -}; - -static void grlib_gptimer_reset(DeviceState *d) -{ - GPTimerUnit *unit = GRLIB_GPTIMER(d); - int i = 0; - - assert(unit != NULL); - - unit->scaler = 0; - unit->reload = 0; - - unit->config = unit->nr_timers; - unit->config |= unit->irq_line << 3; - unit->config |= 1 << 8; /* separate interrupt */ - unit->config |= 1 << 9; /* Disable timer freeze */ - - - for (i = 0; i < unit->nr_timers; i++) { - GPTimer *timer = &unit->timers[i]; - - timer->counter = 0; - timer->reload = 0; - timer->config = 0; - ptimer_stop(timer->ptimer); - ptimer_set_count(timer->ptimer, 0); - ptimer_set_freq(timer->ptimer, unit->freq_hz); - } -} - -static int grlib_gptimer_init(SysBusDevice *dev) -{ - GPTimerUnit *unit = GRLIB_GPTIMER(dev); - unsigned int i; - - assert(unit->nr_timers > 0); - assert(unit->nr_timers <= GPTIMER_MAX_TIMERS); - - unit->timers = g_malloc0(sizeof unit->timers[0] * unit->nr_timers); - - for (i = 0; i < unit->nr_timers; i++) { - GPTimer *timer = &unit->timers[i]; - - timer->unit = unit; - timer->bh = qemu_bh_new(grlib_gptimer_hit, timer); - timer->ptimer = ptimer_init(timer->bh); - timer->id = i; - - /* One IRQ line for each timer */ - sysbus_init_irq(dev, &timer->irq); - - ptimer_set_freq(timer->ptimer, unit->freq_hz); - } - - memory_region_init_io(&unit->iomem, OBJECT(unit), &grlib_gptimer_ops, - unit, "gptimer", - UNIT_REG_SIZE + GPTIMER_REG_SIZE * unit->nr_timers); - - sysbus_init_mmio(dev, &unit->iomem); - return 0; -} - -static Property grlib_gptimer_properties[] = { - DEFINE_PROP_UINT32("frequency", GPTimerUnit, freq_hz, 40000000), - DEFINE_PROP_UINT32("irq-line", GPTimerUnit, irq_line, 8), - DEFINE_PROP_UINT32("nr-timers", GPTimerUnit, nr_timers, 2), - DEFINE_PROP_END_OF_LIST(), -}; - -static void grlib_gptimer_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); - - k->init = grlib_gptimer_init; - dc->reset = grlib_gptimer_reset; - dc->props = grlib_gptimer_properties; -} - -static const TypeInfo grlib_gptimer_info = { - .name = TYPE_GRLIB_GPTIMER, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(GPTimerUnit), - .class_init = grlib_gptimer_class_init, -}; - -static void grlib_gptimer_register_types(void) -{ - type_register_static(&grlib_gptimer_info); -} - -type_init(grlib_gptimer_register_types) diff --git a/qemu/hw/timer/hpet.c b/qemu/hw/timer/hpet.c deleted file mode 100644 index a2c18b30c..000000000 --- a/qemu/hw/timer/hpet.c +++ /dev/null @@ -1,789 +0,0 @@ -/* - * High Precision Event Timer emulation - * - * Copyright (c) 2007 Alexander Graf - * Copyright (c) 2008 IBM Corporation - * - * Authors: Beth Kon <bkon@us.ibm.com> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see <http://www.gnu.org/licenses/>. - * - * ***************************************************************** - * - * This driver attempts to emulate an HPET device in software. - */ - -#include "qemu/osdep.h" -#include "hw/hw.h" -#include "hw/i386/pc.h" -#include "ui/console.h" -#include "qapi/error.h" -#include "qemu/error-report.h" -#include "qemu/timer.h" -#include "hw/timer/hpet.h" -#include "hw/sysbus.h" -#include "hw/timer/mc146818rtc.h" -#include "hw/timer/i8254.h" - -//#define HPET_DEBUG -#ifdef HPET_DEBUG -#define DPRINTF printf -#else -#define DPRINTF(...) -#endif - -#define HPET_MSI_SUPPORT 0 - -#define HPET(obj) OBJECT_CHECK(HPETState, (obj), TYPE_HPET) - -struct HPETState; -typedef struct HPETTimer { /* timers */ - uint8_t tn; /*timer number*/ - QEMUTimer *qemu_timer; - struct HPETState *state; - /* Memory-mapped, software visible timer registers */ - uint64_t config; /* configuration/cap */ - uint64_t cmp; /* comparator */ - uint64_t fsb; /* FSB route */ - /* Hidden register state */ - uint64_t period; /* Last value written to comparator */ - uint8_t wrap_flag; /* timer pop will indicate wrap for one-shot 32-bit - * mode. Next pop will be actual timer expiration. - */ -} HPETTimer; - -typedef struct HPETState { - /*< private >*/ - SysBusDevice parent_obj; - /*< public >*/ - - MemoryRegion iomem; - uint64_t hpet_offset; - qemu_irq irqs[HPET_NUM_IRQ_ROUTES]; - uint32_t flags; - uint8_t rtc_irq_level; - qemu_irq pit_enabled; - uint8_t num_timers; - uint32_t intcap; - HPETTimer timer[HPET_MAX_TIMERS]; - - /* Memory-mapped, software visible registers */ - uint64_t capability; /* capabilities */ - uint64_t config; /* configuration */ - uint64_t isr; /* interrupt status reg */ - uint64_t hpet_counter; /* main counter */ - uint8_t hpet_id; /* instance id */ -} HPETState; - -static uint32_t hpet_in_legacy_mode(HPETState *s) -{ - return s->config & HPET_CFG_LEGACY; -} - -static uint32_t timer_int_route(struct HPETTimer *timer) -{ - return (timer->config & HPET_TN_INT_ROUTE_MASK) >> HPET_TN_INT_ROUTE_SHIFT; -} - -static uint32_t timer_fsb_route(HPETTimer *t) -{ - return t->config & HPET_TN_FSB_ENABLE; -} - -static uint32_t hpet_enabled(HPETState *s) -{ - return s->config & HPET_CFG_ENABLE; -} - -static uint32_t timer_is_periodic(HPETTimer *t) -{ - return t->config & HPET_TN_PERIODIC; -} - -static uint32_t timer_enabled(HPETTimer *t) -{ - return t->config & HPET_TN_ENABLE; -} - -static uint32_t hpet_time_after(uint64_t a, uint64_t b) -{ - return ((int32_t)(b - a) < 0); -} - -static uint32_t hpet_time_after64(uint64_t a, uint64_t b) -{ - return ((int64_t)(b - a) < 0); -} - -static uint64_t ticks_to_ns(uint64_t value) -{ - return value * HPET_CLK_PERIOD; -} - -static uint64_t ns_to_ticks(uint64_t value) -{ - return value / HPET_CLK_PERIOD; -} - -static uint64_t hpet_fixup_reg(uint64_t new, uint64_t old, uint64_t mask) -{ - new &= mask; - new |= old & ~mask; - return new; -} - -static int activating_bit(uint64_t old, uint64_t new, uint64_t mask) -{ - return (!(old & mask) && (new & mask)); -} - -static int deactivating_bit(uint64_t old, uint64_t new, uint64_t mask) -{ - return ((old & mask) && !(new & mask)); -} - -static uint64_t hpet_get_ticks(HPETState *s) -{ - return ns_to_ticks(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + s->hpet_offset); -} - -/* - * calculate diff between comparator value and current ticks - */ -static inline uint64_t hpet_calculate_diff(HPETTimer *t, uint64_t current) -{ - - if (t->config & HPET_TN_32BIT) { - uint32_t diff, cmp; - - cmp = (uint32_t)t->cmp; - diff = cmp - (uint32_t)current; - diff = (int32_t)diff > 0 ? diff : (uint32_t)1; - return (uint64_t)diff; - } else { - uint64_t diff, cmp; - - cmp = t->cmp; - diff = cmp - current; - diff = (int64_t)diff > 0 ? diff : (uint64_t)1; - return diff; - } -} - -static void update_irq(struct HPETTimer *timer, int set) -{ - uint64_t mask; - HPETState *s; - int route; - - if (timer->tn <= 1 && hpet_in_legacy_mode(timer->state)) { - /* if LegacyReplacementRoute bit is set, HPET specification requires - * timer0 be routed to IRQ0 in NON-APIC or IRQ2 in the I/O APIC, - * timer1 be routed to IRQ8 in NON-APIC or IRQ8 in the I/O APIC. - */ - route = (timer->tn == 0) ? 0 : RTC_ISA_IRQ; - } else { - route = timer_int_route(timer); - } - s = timer->state; - mask = 1 << timer->tn; - if (!set || !timer_enabled(timer) || !hpet_enabled(timer->state)) { - s->isr &= ~mask; - if (!timer_fsb_route(timer)) { - qemu_irq_lower(s->irqs[route]); - } - } else if (timer_fsb_route(timer)) { - address_space_stl_le(&address_space_memory, timer->fsb >> 32, - timer->fsb & 0xffffffff, MEMTXATTRS_UNSPECIFIED, - NULL); - } else if (timer->config & HPET_TN_TYPE_LEVEL) { - s->isr |= mask; - qemu_irq_raise(s->irqs[route]); - } else { - s->isr &= ~mask; - qemu_irq_pulse(s->irqs[route]); - } -} - -static void hpet_pre_save(void *opaque) -{ - HPETState *s = opaque; - - /* save current counter value */ - s->hpet_counter = hpet_get_ticks(s); -} - -static int hpet_pre_load(void *opaque) -{ - HPETState *s = opaque; - - /* version 1 only supports 3, later versions will load the actual value */ - s->num_timers = HPET_MIN_TIMERS; - return 0; -} - -static bool hpet_validate_num_timers(void *opaque, int version_id) -{ - HPETState *s = opaque; - - if (s->num_timers < HPET_MIN_TIMERS) { - return false; - } else if (s->num_timers > HPET_MAX_TIMERS) { - return false; - } - return true; -} - -static int hpet_post_load(void *opaque, int version_id) -{ - HPETState *s = opaque; - - /* Recalculate the offset between the main counter and guest time */ - s->hpet_offset = ticks_to_ns(s->hpet_counter) - qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); - - /* Push number of timers into capability returned via HPET_ID */ - s->capability &= ~HPET_ID_NUM_TIM_MASK; - s->capability |= (s->num_timers - 1) << HPET_ID_NUM_TIM_SHIFT; - hpet_cfg.hpet[s->hpet_id].event_timer_block_id = (uint32_t)s->capability; - - /* Derive HPET_MSI_SUPPORT from the capability of the first timer. */ - s->flags &= ~(1 << HPET_MSI_SUPPORT); - if (s->timer[0].config & HPET_TN_FSB_CAP) { - s->flags |= 1 << HPET_MSI_SUPPORT; - } - return 0; -} - -static bool hpet_rtc_irq_level_needed(void *opaque) -{ - HPETState *s = opaque; - - return s->rtc_irq_level != 0; -} - -static const VMStateDescription vmstate_hpet_rtc_irq_level = { - .name = "hpet/rtc_irq_level", - .version_id = 1, - .minimum_version_id = 1, - .needed = hpet_rtc_irq_level_needed, - .fields = (VMStateField[]) { - VMSTATE_UINT8(rtc_irq_level, HPETState), - VMSTATE_END_OF_LIST() - } -}; - -static const VMStateDescription vmstate_hpet_timer = { - .name = "hpet_timer", - .version_id = 1, - .minimum_version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_UINT8(tn, HPETTimer), - VMSTATE_UINT64(config, HPETTimer), - VMSTATE_UINT64(cmp, HPETTimer), - VMSTATE_UINT64(fsb, HPETTimer), - VMSTATE_UINT64(period, HPETTimer), - VMSTATE_UINT8(wrap_flag, HPETTimer), - VMSTATE_TIMER_PTR(qemu_timer, HPETTimer), - VMSTATE_END_OF_LIST() - } -}; - -static const VMStateDescription vmstate_hpet = { - .name = "hpet", - .version_id = 2, - .minimum_version_id = 1, - .pre_save = hpet_pre_save, - .pre_load = hpet_pre_load, - .post_load = hpet_post_load, - .fields = (VMStateField[]) { - VMSTATE_UINT64(config, HPETState), - VMSTATE_UINT64(isr, HPETState), - VMSTATE_UINT64(hpet_counter, HPETState), - VMSTATE_UINT8_V(num_timers, HPETState, 2), - VMSTATE_VALIDATE("num_timers in range", hpet_validate_num_timers), - VMSTATE_STRUCT_VARRAY_UINT8(timer, HPETState, num_timers, 0, - vmstate_hpet_timer, HPETTimer), - VMSTATE_END_OF_LIST() - }, - .subsections = (const VMStateDescription*[]) { - &vmstate_hpet_rtc_irq_level, - NULL - } -}; - -/* - * timer expiration callback - */ -static void hpet_timer(void *opaque) -{ - HPETTimer *t = opaque; - uint64_t diff; - - uint64_t period = t->period; - uint64_t cur_tick = hpet_get_ticks(t->state); - - if (timer_is_periodic(t) && period != 0) { - if (t->config & HPET_TN_32BIT) { - while (hpet_time_after(cur_tick, t->cmp)) { - t->cmp = (uint32_t)(t->cmp + t->period); - } - } else { - while (hpet_time_after64(cur_tick, t->cmp)) { - t->cmp += period; - } - } - diff = hpet_calculate_diff(t, cur_tick); - timer_mod(t->qemu_timer, - qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + (int64_t)ticks_to_ns(diff)); - } else if (t->config & HPET_TN_32BIT && !timer_is_periodic(t)) { - if (t->wrap_flag) { - diff = hpet_calculate_diff(t, cur_tick); - timer_mod(t->qemu_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + - (int64_t)ticks_to_ns(diff)); - t->wrap_flag = 0; - } - } - update_irq(t, 1); -} - -static void hpet_set_timer(HPETTimer *t) -{ - uint64_t diff; - uint32_t wrap_diff; /* how many ticks until we wrap? */ - uint64_t cur_tick = hpet_get_ticks(t->state); - - /* whenever new timer is being set up, make sure wrap_flag is 0 */ - t->wrap_flag = 0; - diff = hpet_calculate_diff(t, cur_tick); - - /* hpet spec says in one-shot 32-bit mode, generate an interrupt when - * counter wraps in addition to an interrupt with comparator match. - */ - if (t->config & HPET_TN_32BIT && !timer_is_periodic(t)) { - wrap_diff = 0xffffffff - (uint32_t)cur_tick; - if (wrap_diff < (uint32_t)diff) { - diff = wrap_diff; - t->wrap_flag = 1; - } - } - timer_mod(t->qemu_timer, - qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + (int64_t)ticks_to_ns(diff)); -} - -static void hpet_del_timer(HPETTimer *t) -{ - timer_del(t->qemu_timer); - update_irq(t, 0); -} - -#ifdef HPET_DEBUG -static uint32_t hpet_ram_readb(void *opaque, hwaddr addr) -{ - printf("qemu: hpet_read b at %" PRIx64 "\n", addr); - return 0; -} - -static uint32_t hpet_ram_readw(void *opaque, hwaddr addr) -{ - printf("qemu: hpet_read w at %" PRIx64 "\n", addr); - return 0; -} -#endif - -static uint64_t hpet_ram_read(void *opaque, hwaddr addr, - unsigned size) -{ - HPETState *s = opaque; - uint64_t cur_tick, index; - - DPRINTF("qemu: Enter hpet_ram_readl at %" PRIx64 "\n", addr); - index = addr; - /*address range of all TN regs*/ - if (index >= 0x100 && index <= 0x3ff) { - uint8_t timer_id = (addr - 0x100) / 0x20; - HPETTimer *timer = &s->timer[timer_id]; - - if (timer_id > s->num_timers) { - DPRINTF("qemu: timer id out of range\n"); - return 0; - } - - switch ((addr - 0x100) % 0x20) { - case HPET_TN_CFG: - return timer->config; - case HPET_TN_CFG + 4: // Interrupt capabilities - return timer->config >> 32; - case HPET_TN_CMP: // comparator register - return timer->cmp; - case HPET_TN_CMP + 4: - return timer->cmp >> 32; - case HPET_TN_ROUTE: - return timer->fsb; - case HPET_TN_ROUTE + 4: - return timer->fsb >> 32; - default: - DPRINTF("qemu: invalid hpet_ram_readl\n"); - break; - } - } else { - switch (index) { - case HPET_ID: - return s->capability; - case HPET_PERIOD: - return s->capability >> 32; - case HPET_CFG: - return s->config; - case HPET_CFG + 4: - DPRINTF("qemu: invalid HPET_CFG + 4 hpet_ram_readl\n"); - return 0; - case HPET_COUNTER: - if (hpet_enabled(s)) { - cur_tick = hpet_get_ticks(s); - } else { - cur_tick = s->hpet_counter; - } - DPRINTF("qemu: reading counter = %" PRIx64 "\n", cur_tick); - return cur_tick; - case HPET_COUNTER + 4: - if (hpet_enabled(s)) { - cur_tick = hpet_get_ticks(s); - } else { - cur_tick = s->hpet_counter; - } - DPRINTF("qemu: reading counter + 4 = %" PRIx64 "\n", cur_tick); - return cur_tick >> 32; - case HPET_STATUS: - return s->isr; - default: - DPRINTF("qemu: invalid hpet_ram_readl\n"); - break; - } - } - return 0; -} - -static void hpet_ram_write(void *opaque, hwaddr addr, - uint64_t value, unsigned size) -{ - int i; - HPETState *s = opaque; - uint64_t old_val, new_val, val, index; - - DPRINTF("qemu: Enter hpet_ram_writel at %" PRIx64 " = %#x\n", addr, value); - index = addr; - old_val = hpet_ram_read(opaque, addr, 4); - new_val = value; - - /*address range of all TN regs*/ - if (index >= 0x100 && index <= 0x3ff) { - uint8_t timer_id = (addr - 0x100) / 0x20; - HPETTimer *timer = &s->timer[timer_id]; - - DPRINTF("qemu: hpet_ram_writel timer_id = %#x\n", timer_id); - if (timer_id > s->num_timers) { - DPRINTF("qemu: timer id out of range\n"); - return; - } - switch ((addr - 0x100) % 0x20) { - case HPET_TN_CFG: - DPRINTF("qemu: hpet_ram_writel HPET_TN_CFG\n"); - if (activating_bit(old_val, new_val, HPET_TN_FSB_ENABLE)) { - update_irq(timer, 0); - } - val = hpet_fixup_reg(new_val, old_val, HPET_TN_CFG_WRITE_MASK); - timer->config = (timer->config & 0xffffffff00000000ULL) | val; - if (new_val & HPET_TN_32BIT) { - timer->cmp = (uint32_t)timer->cmp; - timer->period = (uint32_t)timer->period; - } - if (activating_bit(old_val, new_val, HPET_TN_ENABLE) && - hpet_enabled(s)) { - hpet_set_timer(timer); - } else if (deactivating_bit(old_val, new_val, HPET_TN_ENABLE)) { - hpet_del_timer(timer); - } - break; - case HPET_TN_CFG + 4: // Interrupt capabilities - DPRINTF("qemu: invalid HPET_TN_CFG+4 write\n"); - break; - case HPET_TN_CMP: // comparator register - DPRINTF("qemu: hpet_ram_writel HPET_TN_CMP\n"); - if (timer->config & HPET_TN_32BIT) { - new_val = (uint32_t)new_val; - } - if (!timer_is_periodic(timer) - || (timer->config & HPET_TN_SETVAL)) { - timer->cmp = (timer->cmp & 0xffffffff00000000ULL) | new_val; - } - if (timer_is_periodic(timer)) { - /* - * FIXME: Clamp period to reasonable min value? - * Clamp period to reasonable max value - */ - new_val &= (timer->config & HPET_TN_32BIT ? ~0u : ~0ull) >> 1; - timer->period = - (timer->period & 0xffffffff00000000ULL) | new_val; - } - timer->config &= ~HPET_TN_SETVAL; - if (hpet_enabled(s)) { - hpet_set_timer(timer); - } - break; - case HPET_TN_CMP + 4: // comparator register high order - DPRINTF("qemu: hpet_ram_writel HPET_TN_CMP + 4\n"); - if (!timer_is_periodic(timer) - || (timer->config & HPET_TN_SETVAL)) { - timer->cmp = (timer->cmp & 0xffffffffULL) | new_val << 32; - } else { - /* - * FIXME: Clamp period to reasonable min value? - * Clamp period to reasonable max value - */ - new_val &= (timer->config & HPET_TN_32BIT ? ~0u : ~0ull) >> 1; - timer->period = - (timer->period & 0xffffffffULL) | new_val << 32; - } - timer->config &= ~HPET_TN_SETVAL; - if (hpet_enabled(s)) { - hpet_set_timer(timer); - } - break; - case HPET_TN_ROUTE: - timer->fsb = (timer->fsb & 0xffffffff00000000ULL) | new_val; - break; - case HPET_TN_ROUTE + 4: - timer->fsb = (new_val << 32) | (timer->fsb & 0xffffffff); - break; - default: - DPRINTF("qemu: invalid hpet_ram_writel\n"); - break; - } - return; - } else { - switch (index) { - case HPET_ID: - return; - case HPET_CFG: - val = hpet_fixup_reg(new_val, old_val, HPET_CFG_WRITE_MASK); - s->config = (s->config & 0xffffffff00000000ULL) | val; - if (activating_bit(old_val, new_val, HPET_CFG_ENABLE)) { - /* Enable main counter and interrupt generation. */ - s->hpet_offset = - ticks_to_ns(s->hpet_counter) - qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); - for (i = 0; i < s->num_timers; i++) { - if ((&s->timer[i])->cmp != ~0ULL) { - hpet_set_timer(&s->timer[i]); - } - } - } else if (deactivating_bit(old_val, new_val, HPET_CFG_ENABLE)) { - /* Halt main counter and disable interrupt generation. */ - s->hpet_counter = hpet_get_ticks(s); - for (i = 0; i < s->num_timers; i++) { - hpet_del_timer(&s->timer[i]); - } - } - /* i8254 and RTC output pins are disabled - * when HPET is in legacy mode */ - if (activating_bit(old_val, new_val, HPET_CFG_LEGACY)) { - qemu_set_irq(s->pit_enabled, 0); - qemu_irq_lower(s->irqs[0]); - qemu_irq_lower(s->irqs[RTC_ISA_IRQ]); - } else if (deactivating_bit(old_val, new_val, HPET_CFG_LEGACY)) { - qemu_irq_lower(s->irqs[0]); - qemu_set_irq(s->pit_enabled, 1); - qemu_set_irq(s->irqs[RTC_ISA_IRQ], s->rtc_irq_level); - } - break; - case HPET_CFG + 4: - DPRINTF("qemu: invalid HPET_CFG+4 write\n"); - break; - case HPET_STATUS: - val = new_val & s->isr; - for (i = 0; i < s->num_timers; i++) { - if (val & (1 << i)) { - update_irq(&s->timer[i], 0); - } - } - break; - case HPET_COUNTER: - if (hpet_enabled(s)) { - DPRINTF("qemu: Writing counter while HPET enabled!\n"); - } - s->hpet_counter = - (s->hpet_counter & 0xffffffff00000000ULL) | value; - DPRINTF("qemu: HPET counter written. ctr = %#x -> %" PRIx64 "\n", - value, s->hpet_counter); - break; - case HPET_COUNTER + 4: - if (hpet_enabled(s)) { - DPRINTF("qemu: Writing counter while HPET enabled!\n"); - } - s->hpet_counter = - (s->hpet_counter & 0xffffffffULL) | (((uint64_t)value) << 32); - DPRINTF("qemu: HPET counter + 4 written. ctr = %#x -> %" PRIx64 "\n", - value, s->hpet_counter); - break; - default: - DPRINTF("qemu: invalid hpet_ram_writel\n"); - break; - } - } -} - -static const MemoryRegionOps hpet_ram_ops = { - .read = hpet_ram_read, - .write = hpet_ram_write, - .valid = { - .min_access_size = 4, - .max_access_size = 4, - }, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static void hpet_reset(DeviceState *d) -{ - HPETState *s = HPET(d); - SysBusDevice *sbd = SYS_BUS_DEVICE(d); - int i; - - for (i = 0; i < s->num_timers; i++) { - HPETTimer *timer = &s->timer[i]; - - hpet_del_timer(timer); - timer->cmp = ~0ULL; - timer->config = HPET_TN_PERIODIC_CAP | HPET_TN_SIZE_CAP; - if (s->flags & (1 << HPET_MSI_SUPPORT)) { - timer->config |= HPET_TN_FSB_CAP; - } - /* advertise availability of ioapic int */ - timer->config |= (uint64_t)s->intcap << 32; - timer->period = 0ULL; - timer->wrap_flag = 0; - } - - qemu_set_irq(s->pit_enabled, 1); - s->hpet_counter = 0ULL; - s->hpet_offset = 0ULL; - s->config = 0ULL; - hpet_cfg.hpet[s->hpet_id].event_timer_block_id = (uint32_t)s->capability; - hpet_cfg.hpet[s->hpet_id].address = sbd->mmio[0].addr; - - /* to document that the RTC lowers its output on reset as well */ - s->rtc_irq_level = 0; -} - -static void hpet_handle_legacy_irq(void *opaque, int n, int level) -{ - HPETState *s = HPET(opaque); - - if (n == HPET_LEGACY_PIT_INT) { - if (!hpet_in_legacy_mode(s)) { - qemu_set_irq(s->irqs[0], level); - } - } else { - s->rtc_irq_level = level; - if (!hpet_in_legacy_mode(s)) { - qemu_set_irq(s->irqs[RTC_ISA_IRQ], level); - } - } -} - -static void hpet_init(Object *obj) -{ - SysBusDevice *sbd = SYS_BUS_DEVICE(obj); - HPETState *s = HPET(obj); - - /* HPET Area */ - memory_region_init_io(&s->iomem, obj, &hpet_ram_ops, s, "hpet", HPET_LEN); - sysbus_init_mmio(sbd, &s->iomem); -} - -static void hpet_realize(DeviceState *dev, Error **errp) -{ - SysBusDevice *sbd = SYS_BUS_DEVICE(dev); - HPETState *s = HPET(dev); - int i; - HPETTimer *timer; - - if (!s->intcap) { - error_printf("Hpet's intcap not initialized.\n"); - } - if (hpet_cfg.count == UINT8_MAX) { - /* first instance */ - hpet_cfg.count = 0; - } - - if (hpet_cfg.count == 8) { - error_setg(errp, "Only 8 instances of HPET is allowed"); - return; - } - - s->hpet_id = hpet_cfg.count++; - - for (i = 0; i < HPET_NUM_IRQ_ROUTES; i++) { - sysbus_init_irq(sbd, &s->irqs[i]); - } - - if (s->num_timers < HPET_MIN_TIMERS) { - s->num_timers = HPET_MIN_TIMERS; - } else if (s->num_timers > HPET_MAX_TIMERS) { - s->num_timers = HPET_MAX_TIMERS; - } - for (i = 0; i < HPET_MAX_TIMERS; i++) { - timer = &s->timer[i]; - timer->qemu_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, hpet_timer, timer); - timer->tn = i; - timer->state = s; - } - - /* 64-bit main counter; LegacyReplacementRoute. */ - s->capability = 0x8086a001ULL; - s->capability |= (s->num_timers - 1) << HPET_ID_NUM_TIM_SHIFT; - s->capability |= ((uint64_t)(HPET_CLK_PERIOD * FS_PER_NS) << 32); - - qdev_init_gpio_in(dev, hpet_handle_legacy_irq, 2); - qdev_init_gpio_out(dev, &s->pit_enabled, 1); -} - -static Property hpet_device_properties[] = { - DEFINE_PROP_UINT8("timers", HPETState, num_timers, HPET_MIN_TIMERS), - DEFINE_PROP_BIT("msi", HPETState, flags, HPET_MSI_SUPPORT, false), - DEFINE_PROP_UINT32(HPET_INTCAP, HPETState, intcap, 0), - DEFINE_PROP_END_OF_LIST(), -}; - -static void hpet_device_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - - dc->realize = hpet_realize; - dc->reset = hpet_reset; - dc->vmsd = &vmstate_hpet; - dc->props = hpet_device_properties; -} - -static const TypeInfo hpet_device_info = { - .name = TYPE_HPET, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(HPETState), - .instance_init = hpet_init, - .class_init = hpet_device_class_init, -}; - -static void hpet_register_types(void) -{ - type_register_static(&hpet_device_info); -} - -type_init(hpet_register_types) diff --git a/qemu/hw/timer/i8254.c b/qemu/hw/timer/i8254.c deleted file mode 100644 index 5e61ad50a..000000000 --- a/qemu/hw/timer/i8254.c +++ /dev/null @@ -1,384 +0,0 @@ -/* - * QEMU 8253/8254 interval timer emulation - * - * Copyright (c) 2003-2004 Fabrice Bellard - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include "qemu/osdep.h" -#include "hw/hw.h" -#include "hw/i386/pc.h" -#include "hw/isa/isa.h" -#include "qemu/timer.h" -#include "hw/timer/i8254.h" -#include "hw/timer/i8254_internal.h" - -//#define DEBUG_PIT - -#define RW_STATE_LSB 1 -#define RW_STATE_MSB 2 -#define RW_STATE_WORD0 3 -#define RW_STATE_WORD1 4 - -#define PIT_CLASS(class) OBJECT_CLASS_CHECK(PITClass, (class), TYPE_I8254) -#define PIT_GET_CLASS(obj) OBJECT_GET_CLASS(PITClass, (obj), TYPE_I8254) - -typedef struct PITClass { - PITCommonClass parent_class; - - DeviceRealize parent_realize; -} PITClass; - -static void pit_irq_timer_update(PITChannelState *s, int64_t current_time); - -static int pit_get_count(PITChannelState *s) -{ - uint64_t d; - int counter; - - d = muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - s->count_load_time, PIT_FREQ, - NANOSECONDS_PER_SECOND); - switch(s->mode) { - case 0: - case 1: - case 4: - case 5: - counter = (s->count - d) & 0xffff; - break; - case 3: - /* XXX: may be incorrect for odd counts */ - counter = s->count - ((2 * d) % s->count); - break; - default: - counter = s->count - (d % s->count); - break; - } - return counter; -} - -/* val must be 0 or 1 */ -static void pit_set_channel_gate(PITCommonState *s, PITChannelState *sc, - int val) -{ - switch (sc->mode) { - default: - case 0: - case 4: - /* XXX: just disable/enable counting */ - break; - case 1: - case 5: - if (sc->gate < val) { - /* restart counting on rising edge */ - sc->count_load_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); - pit_irq_timer_update(sc, sc->count_load_time); - } - break; - case 2: - case 3: - if (sc->gate < val) { - /* restart counting on rising edge */ - sc->count_load_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); - pit_irq_timer_update(sc, sc->count_load_time); - } - /* XXX: disable/enable counting */ - break; - } - sc->gate = val; -} - -static inline void pit_load_count(PITChannelState *s, int val) -{ - if (val == 0) - val = 0x10000; - s->count_load_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); - s->count = val; - pit_irq_timer_update(s, s->count_load_time); -} - -/* if already latched, do not latch again */ -static void pit_latch_count(PITChannelState *s) -{ - if (!s->count_latched) { - s->latched_count = pit_get_count(s); - s->count_latched = s->rw_mode; - } -} - -static void pit_ioport_write(void *opaque, hwaddr addr, - uint64_t val, unsigned size) -{ - PITCommonState *pit = opaque; - int channel, access; - PITChannelState *s; - - addr &= 3; - if (addr == 3) { - channel = val >> 6; - if (channel == 3) { - /* read back command */ - for(channel = 0; channel < 3; channel++) { - s = &pit->channels[channel]; - if (val & (2 << channel)) { - if (!(val & 0x20)) { - pit_latch_count(s); - } - if (!(val & 0x10) && !s->status_latched) { - /* status latch */ - /* XXX: add BCD and null count */ - s->status = - (pit_get_out(s, - qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL)) << 7) | - (s->rw_mode << 4) | - (s->mode << 1) | - s->bcd; - s->status_latched = 1; - } - } - } - } else { - s = &pit->channels[channel]; - access = (val >> 4) & 3; - if (access == 0) { - pit_latch_count(s); - } else { - s->rw_mode = access; - s->read_state = access; - s->write_state = access; - - s->mode = (val >> 1) & 7; - s->bcd = val & 1; - /* XXX: update irq timer ? */ - } - } - } else { - s = &pit->channels[addr]; - switch(s->write_state) { - default: - case RW_STATE_LSB: - pit_load_count(s, val); - break; - case RW_STATE_MSB: - pit_load_count(s, val << 8); - break; - case RW_STATE_WORD0: - s->write_latch = val; - s->write_state = RW_STATE_WORD1; - break; - case RW_STATE_WORD1: - pit_load_count(s, s->write_latch | (val << 8)); - s->write_state = RW_STATE_WORD0; - break; - } - } -} - -static uint64_t pit_ioport_read(void *opaque, hwaddr addr, - unsigned size) -{ - PITCommonState *pit = opaque; - int ret, count; - PITChannelState *s; - - addr &= 3; - - if (addr == 3) { - /* Mode/Command register is write only, read is ignored */ - return 0; - } - - s = &pit->channels[addr]; - if (s->status_latched) { - s->status_latched = 0; - ret = s->status; - } else if (s->count_latched) { - switch(s->count_latched) { - default: - case RW_STATE_LSB: - ret = s->latched_count & 0xff; - s->count_latched = 0; - break; - case RW_STATE_MSB: - ret = s->latched_count >> 8; - s->count_latched = 0; - break; - case RW_STATE_WORD0: - ret = s->latched_count & 0xff; - s->count_latched = RW_STATE_MSB; - break; - } - } else { - switch(s->read_state) { - default: - case RW_STATE_LSB: - count = pit_get_count(s); - ret = count & 0xff; - break; - case RW_STATE_MSB: - count = pit_get_count(s); - ret = (count >> 8) & 0xff; - break; - case RW_STATE_WORD0: - count = pit_get_count(s); - ret = count & 0xff; - s->read_state = RW_STATE_WORD1; - break; - case RW_STATE_WORD1: - count = pit_get_count(s); - ret = (count >> 8) & 0xff; - s->read_state = RW_STATE_WORD0; - break; - } - } - return ret; -} - -static void pit_irq_timer_update(PITChannelState *s, int64_t current_time) -{ - int64_t expire_time; - int irq_level; - - if (!s->irq_timer || s->irq_disabled) { - return; - } - expire_time = pit_get_next_transition_time(s, current_time); - irq_level = pit_get_out(s, current_time); - qemu_set_irq(s->irq, irq_level); -#ifdef DEBUG_PIT - printf("irq_level=%d next_delay=%f\n", - irq_level, - (double)(expire_time - current_time) / NANOSECONDS_PER_SECOND); -#endif - s->next_transition_time = expire_time; - if (expire_time != -1) - timer_mod(s->irq_timer, expire_time); - else - timer_del(s->irq_timer); -} - -static void pit_irq_timer(void *opaque) -{ - PITChannelState *s = opaque; - - pit_irq_timer_update(s, s->next_transition_time); -} - -static void pit_reset(DeviceState *dev) -{ - PITCommonState *pit = PIT_COMMON(dev); - PITChannelState *s; - - pit_reset_common(pit); - - s = &pit->channels[0]; - if (!s->irq_disabled) { - timer_mod(s->irq_timer, s->next_transition_time); - } -} - -/* When HPET is operating in legacy mode, suppress the ignored timer IRQ, - * reenable it when legacy mode is left again. */ -static void pit_irq_control(void *opaque, int n, int enable) -{ - PITCommonState *pit = opaque; - PITChannelState *s = &pit->channels[0]; - - if (enable) { - s->irq_disabled = 0; - pit_irq_timer_update(s, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL)); - } else { - s->irq_disabled = 1; - timer_del(s->irq_timer); - } -} - -static const MemoryRegionOps pit_ioport_ops = { - .read = pit_ioport_read, - .write = pit_ioport_write, - .impl = { - .min_access_size = 1, - .max_access_size = 1, - }, - .endianness = DEVICE_LITTLE_ENDIAN, -}; - -static void pit_post_load(PITCommonState *s) -{ - PITChannelState *sc = &s->channels[0]; - - if (sc->next_transition_time != -1) { - timer_mod(sc->irq_timer, sc->next_transition_time); - } else { - timer_del(sc->irq_timer); - } -} - -static void pit_realizefn(DeviceState *dev, Error **errp) -{ - PITCommonState *pit = PIT_COMMON(dev); - PITClass *pc = PIT_GET_CLASS(dev); - PITChannelState *s; - - s = &pit->channels[0]; - /* the timer 0 is connected to an IRQ */ - s->irq_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, pit_irq_timer, s); - qdev_init_gpio_out(dev, &s->irq, 1); - - memory_region_init_io(&pit->ioports, OBJECT(pit), &pit_ioport_ops, - pit, "pit", 4); - - qdev_init_gpio_in(dev, pit_irq_control, 1); - - pc->parent_realize(dev, errp); -} - -static Property pit_properties[] = { - DEFINE_PROP_UINT32("iobase", PITCommonState, iobase, -1), - DEFINE_PROP_END_OF_LIST(), -}; - -static void pit_class_initfn(ObjectClass *klass, void *data) -{ - PITClass *pc = PIT_CLASS(klass); - PITCommonClass *k = PIT_COMMON_CLASS(klass); - DeviceClass *dc = DEVICE_CLASS(klass); - - pc->parent_realize = dc->realize; - dc->realize = pit_realizefn; - k->set_channel_gate = pit_set_channel_gate; - k->get_channel_info = pit_get_channel_info_common; - k->post_load = pit_post_load; - dc->reset = pit_reset; - dc->props = pit_properties; -} - -static const TypeInfo pit_info = { - .name = TYPE_I8254, - .parent = TYPE_PIT_COMMON, - .instance_size = sizeof(PITCommonState), - .class_init = pit_class_initfn, - .class_size = sizeof(PITClass), -}; - -static void pit_register_types(void) -{ - type_register_static(&pit_info); -} - -type_init(pit_register_types) diff --git a/qemu/hw/timer/i8254_common.c b/qemu/hw/timer/i8254_common.c deleted file mode 100644 index e18299a48..000000000 --- a/qemu/hw/timer/i8254_common.c +++ /dev/null @@ -1,307 +0,0 @@ -/* - * QEMU 8253/8254 - common bits of emulated and KVM kernel model - * - * Copyright (c) 2003-2004 Fabrice Bellard - * Copyright (c) 2012 Jan Kiszka, Siemens AG - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include "qemu/osdep.h" -#include "hw/hw.h" -#include "hw/i386/pc.h" -#include "hw/isa/isa.h" -#include "qemu/timer.h" -#include "hw/timer/i8254.h" -#include "hw/timer/i8254_internal.h" - -/* val must be 0 or 1 */ -void pit_set_gate(ISADevice *dev, int channel, int val) -{ - PITCommonState *pit = PIT_COMMON(dev); - PITChannelState *s = &pit->channels[channel]; - PITCommonClass *c = PIT_COMMON_GET_CLASS(pit); - - c->set_channel_gate(pit, s, val); -} - -/* get pit output bit */ -int pit_get_out(PITChannelState *s, int64_t current_time) -{ - uint64_t d; - int out; - - d = muldiv64(current_time - s->count_load_time, PIT_FREQ, - NANOSECONDS_PER_SECOND); - switch (s->mode) { - default: - case 0: - out = (d >= s->count); - break; - case 1: - out = (d < s->count); - break; - case 2: - if ((d % s->count) == 0 && d != 0) { - out = 1; - } else { - out = 0; - } - break; - case 3: - out = (d % s->count) < ((s->count + 1) >> 1); - break; - case 4: - case 5: - out = (d == s->count); - break; - } - return out; -} - -/* return -1 if no transition will occur. */ -int64_t pit_get_next_transition_time(PITChannelState *s, int64_t current_time) -{ - uint64_t d, next_time, base; - int period2; - - d = muldiv64(current_time - s->count_load_time, PIT_FREQ, - NANOSECONDS_PER_SECOND); - switch (s->mode) { - default: - case 0: - case 1: - if (d < s->count) { - next_time = s->count; - } else { - return -1; - } - break; - case 2: - base = (d / s->count) * s->count; - if ((d - base) == 0 && d != 0) { - next_time = base + s->count; - } else { - next_time = base + s->count + 1; - } - break; - case 3: - base = (d / s->count) * s->count; - period2 = ((s->count + 1) >> 1); - if ((d - base) < period2) { - next_time = base + period2; - } else { - next_time = base + s->count; - } - break; - case 4: - case 5: - if (d < s->count) { - next_time = s->count; - } else if (d == s->count) { - next_time = s->count + 1; - } else { - return -1; - } - break; - } - /* convert to timer units */ - next_time = s->count_load_time + muldiv64(next_time, NANOSECONDS_PER_SECOND, - PIT_FREQ); - /* fix potential rounding problems */ - /* XXX: better solution: use a clock at PIT_FREQ Hz */ - if (next_time <= current_time) { - next_time = current_time + 1; - } - return next_time; -} - -void pit_get_channel_info_common(PITCommonState *s, PITChannelState *sc, - PITChannelInfo *info) -{ - info->gate = sc->gate; - info->mode = sc->mode; - info->initial_count = sc->count; - info->out = pit_get_out(sc, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL)); -} - -void pit_get_channel_info(ISADevice *dev, int channel, PITChannelInfo *info) -{ - PITCommonState *pit = PIT_COMMON(dev); - PITChannelState *s = &pit->channels[channel]; - PITCommonClass *c = PIT_COMMON_GET_CLASS(pit); - - c->get_channel_info(pit, s, info); -} - -void pit_reset_common(PITCommonState *pit) -{ - PITChannelState *s; - int i; - - for (i = 0; i < 3; i++) { - s = &pit->channels[i]; - s->mode = 3; - s->gate = (i != 2); - s->count_load_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); - s->count = 0x10000; - if (i == 0 && !s->irq_disabled) { - s->next_transition_time = - pit_get_next_transition_time(s, s->count_load_time); - } - } -} - -static void pit_common_realize(DeviceState *dev, Error **errp) -{ - ISADevice *isadev = ISA_DEVICE(dev); - PITCommonState *pit = PIT_COMMON(dev); - - isa_register_ioport(isadev, &pit->ioports, pit->iobase); - - qdev_set_legacy_instance_id(dev, pit->iobase, 2); -} - -static const VMStateDescription vmstate_pit_channel = { - .name = "pit channel", - .version_id = 2, - .minimum_version_id = 2, - .fields = (VMStateField[]) { - VMSTATE_INT32(count, PITChannelState), - VMSTATE_UINT16(latched_count, PITChannelState), - VMSTATE_UINT8(count_latched, PITChannelState), - VMSTATE_UINT8(status_latched, PITChannelState), - VMSTATE_UINT8(status, PITChannelState), - VMSTATE_UINT8(read_state, PITChannelState), - VMSTATE_UINT8(write_state, PITChannelState), - VMSTATE_UINT8(write_latch, PITChannelState), - VMSTATE_UINT8(rw_mode, PITChannelState), - VMSTATE_UINT8(mode, PITChannelState), - VMSTATE_UINT8(bcd, PITChannelState), - VMSTATE_UINT8(gate, PITChannelState), - VMSTATE_INT64(count_load_time, PITChannelState), - VMSTATE_INT64(next_transition_time, PITChannelState), - VMSTATE_END_OF_LIST() - } -}; - -static int pit_load_old(QEMUFile *f, void *opaque, int version_id) -{ - PITCommonState *pit = opaque; - PITCommonClass *c = PIT_COMMON_GET_CLASS(pit); - PITChannelState *s; - int i; - - if (version_id != 1) { - return -EINVAL; - } - - for (i = 0; i < 3; i++) { - s = &pit->channels[i]; - s->count = qemu_get_be32(f); - qemu_get_be16s(f, &s->latched_count); - qemu_get_8s(f, &s->count_latched); - qemu_get_8s(f, &s->status_latched); - qemu_get_8s(f, &s->status); - qemu_get_8s(f, &s->read_state); - qemu_get_8s(f, &s->write_state); - qemu_get_8s(f, &s->write_latch); - qemu_get_8s(f, &s->rw_mode); - qemu_get_8s(f, &s->mode); - qemu_get_8s(f, &s->bcd); - qemu_get_8s(f, &s->gate); - s->count_load_time = qemu_get_be64(f); - s->irq_disabled = 0; - if (i == 0) { - s->next_transition_time = qemu_get_be64(f); - } - } - if (c->post_load) { - c->post_load(pit); - } - return 0; -} - -static void pit_dispatch_pre_save(void *opaque) -{ - PITCommonState *s = opaque; - PITCommonClass *c = PIT_COMMON_GET_CLASS(s); - - if (c->pre_save) { - c->pre_save(s); - } -} - -static int pit_dispatch_post_load(void *opaque, int version_id) -{ - PITCommonState *s = opaque; - PITCommonClass *c = PIT_COMMON_GET_CLASS(s); - - if (c->post_load) { - c->post_load(s); - } - return 0; -} - -static const VMStateDescription vmstate_pit_common = { - .name = "i8254", - .version_id = 3, - .minimum_version_id = 2, - .minimum_version_id_old = 1, - .load_state_old = pit_load_old, - .pre_save = pit_dispatch_pre_save, - .post_load = pit_dispatch_post_load, - .fields = (VMStateField[]) { - VMSTATE_UINT32_V(channels[0].irq_disabled, PITCommonState, 3), - VMSTATE_STRUCT_ARRAY(channels, PITCommonState, 3, 2, - vmstate_pit_channel, PITChannelState), - VMSTATE_INT64(channels[0].next_transition_time, - PITCommonState), /* formerly irq_timer */ - VMSTATE_END_OF_LIST() - } -}; - -static void pit_common_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - - dc->realize = pit_common_realize; - dc->vmsd = &vmstate_pit_common; - /* - * Reason: unlike ordinary ISA devices, the PIT may need to be - * wired to the HPET, and because of that, some wiring is always - * done by board code. - */ - dc->cannot_instantiate_with_device_add_yet = true; -} - -static const TypeInfo pit_common_type = { - .name = TYPE_PIT_COMMON, - .parent = TYPE_ISA_DEVICE, - .instance_size = sizeof(PITCommonState), - .class_size = sizeof(PITCommonClass), - .class_init = pit_common_class_init, - .abstract = true, -}; - -static void register_devices(void) -{ - type_register_static(&pit_common_type); -} - -type_init(register_devices); diff --git a/qemu/hw/timer/imx_epit.c b/qemu/hw/timer/imx_epit.c deleted file mode 100644 index f5836e21f..000000000 --- a/qemu/hw/timer/imx_epit.c +++ /dev/null @@ -1,344 +0,0 @@ -/* - * IMX EPIT Timer - * - * Copyright (c) 2008 OK Labs - * Copyright (c) 2011 NICTA Pty Ltd - * Originally written by Hans Jiang - * Updated by Peter Chubb - * Updated by Jean-Christophe Dubois <jcd@tribudubois.net> - * - * This code is licensed under GPL version 2 or later. See - * the COPYING file in the top-level directory. - * - */ - -#include "qemu/osdep.h" -#include "hw/timer/imx_epit.h" -#include "hw/misc/imx_ccm.h" -#include "qemu/main-loop.h" - -#ifndef DEBUG_IMX_EPIT -#define DEBUG_IMX_EPIT 0 -#endif - -#define DPRINTF(fmt, args...) \ - do { \ - if (DEBUG_IMX_EPIT) { \ - fprintf(stderr, "[%s]%s: " fmt , TYPE_IMX_EPIT, \ - __func__, ##args); \ - } \ - } while (0) - -static char const *imx_epit_reg_name(uint32_t reg) -{ - switch (reg) { - case 0: - return "CR"; - case 1: - return "SR"; - case 2: - return "LR"; - case 3: - return "CMP"; - case 4: - return "CNT"; - default: - return "[?]"; - } -} - -/* - * Exact clock frequencies vary from board to board. - * These are typical. - */ -static const IMXClk imx_epit_clocks[] = { - CLK_NONE, /* 00 disabled */ - CLK_IPG, /* 01 ipg_clk, ~532MHz */ - CLK_IPG_HIGH, /* 10 ipg_clk_highfreq */ - CLK_32k, /* 11 ipg_clk_32k -- ~32kHz */ -}; - -/* - * Update interrupt status - */ -static void imx_epit_update_int(IMXEPITState *s) -{ - if (s->sr && (s->cr & CR_OCIEN) && (s->cr & CR_EN)) { - qemu_irq_raise(s->irq); - } else { - qemu_irq_lower(s->irq); - } -} - -static void imx_epit_set_freq(IMXEPITState *s) -{ - uint32_t clksrc; - uint32_t prescaler; - - clksrc = extract32(s->cr, CR_CLKSRC_SHIFT, 2); - prescaler = 1 + extract32(s->cr, CR_PRESCALE_SHIFT, 12); - - s->freq = imx_ccm_get_clock_frequency(s->ccm, - imx_epit_clocks[clksrc]) / prescaler; - - DPRINTF("Setting ptimer frequency to %u\n", s->freq); - - if (s->freq) { - ptimer_set_freq(s->timer_reload, s->freq); - ptimer_set_freq(s->timer_cmp, s->freq); - } -} - -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 uint32_t imx_epit_update_count(IMXEPITState *s) -{ - s->cnt = ptimer_get_count(s->timer_reload); - - return s->cnt; -} - -static uint64_t imx_epit_read(void *opaque, hwaddr offset, unsigned size) -{ - IMXEPITState *s = IMX_EPIT(opaque); - uint32_t reg_value = 0; - - switch (offset >> 2) { - case 0: /* Control Register */ - reg_value = s->cr; - break; - - case 1: /* Status Register */ - reg_value = s->sr; - break; - - case 2: /* LR - ticks*/ - reg_value = s->lr; - break; - - case 3: /* CMP */ - reg_value = s->cmp; - break; - - case 4: /* CNT */ - imx_epit_update_count(s); - reg_value = s->cnt; - break; - - default: - qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad register at offset 0x%" - HWADDR_PRIx "\n", TYPE_IMX_EPIT, __func__, offset); - break; - } - - DPRINTF("(%s) = 0x%08x\n", imx_epit_reg_name(offset >> 2), reg_value); - - return reg_value; -} - -static void imx_epit_reload_compare_timer(IMXEPITState *s) -{ - if ((s->cr & (CR_EN | CR_OCIEN)) == (CR_EN | CR_OCIEN)) { - /* if the compare feature is on and timers are running */ - uint32_t tmp = imx_epit_update_count(s); - uint64_t next; - if (tmp > s->cmp) { - /* It'll fire in this round of the timer */ - next = tmp - s->cmp; - } else { /* catch it next time around */ - next = tmp - s->cmp + ((s->cr & CR_RLD) ? EPIT_TIMER_MAX : s->lr); - } - ptimer_set_count(s->timer_cmp, next); - } -} - -static void imx_epit_write(void *opaque, hwaddr offset, uint64_t value, - unsigned size) -{ - IMXEPITState *s = IMX_EPIT(opaque); - uint64_t oldcr; - - DPRINTF("(%s, value = 0x%08x)\n", imx_epit_reg_name(offset >> 2), - (uint32_t)value); - - switch (offset >> 2) { - 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: - qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad register at offset 0x%" - HWADDR_PRIx "\n", TYPE_IMX_EPIT, __func__, offset); - - break; - } -} -static void imx_epit_cmp(void *opaque) -{ - IMXEPITState *s = IMX_EPIT(opaque); - - DPRINTF("sr was %d\n", s->sr); - - s->sr = 1; - imx_epit_update_int(s); -} - -static const MemoryRegionOps imx_epit_ops = { - .read = imx_epit_read, - .write = imx_epit_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static const VMStateDescription vmstate_imx_timer_epit = { - .name = TYPE_IMX_EPIT, - .version_id = 2, - .minimum_version_id = 2, - .fields = (VMStateField[]) { - VMSTATE_UINT32(cr, IMXEPITState), - VMSTATE_UINT32(sr, IMXEPITState), - VMSTATE_UINT32(lr, IMXEPITState), - VMSTATE_UINT32(cmp, IMXEPITState), - VMSTATE_UINT32(cnt, IMXEPITState), - VMSTATE_UINT32(freq, IMXEPITState), - VMSTATE_PTIMER(timer_reload, IMXEPITState), - VMSTATE_PTIMER(timer_cmp, IMXEPITState), - VMSTATE_END_OF_LIST() - } -}; - -static void imx_epit_realize(DeviceState *dev, Error **errp) -{ - IMXEPITState *s = IMX_EPIT(dev); - SysBusDevice *sbd = SYS_BUS_DEVICE(dev); - QEMUBH *bh; - - DPRINTF("\n"); - - sysbus_init_irq(sbd, &s->irq); - memory_region_init_io(&s->iomem, OBJECT(s), &imx_epit_ops, s, TYPE_IMX_EPIT, - 0x00001000); - sysbus_init_mmio(sbd, &s->iomem); - - s->timer_reload = ptimer_init(NULL); - - bh = qemu_bh_new(imx_epit_cmp, s); - s->timer_cmp = ptimer_init(bh); -} - -static void imx_epit_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - - dc->realize = imx_epit_realize; - dc->reset = imx_epit_reset; - dc->vmsd = &vmstate_imx_timer_epit; - dc->desc = "i.MX periodic timer"; -} - -static const TypeInfo imx_epit_info = { - .name = TYPE_IMX_EPIT, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(IMXEPITState), - .class_init = imx_epit_class_init, -}; - -static void imx_epit_register_types(void) -{ - type_register_static(&imx_epit_info); -} - -type_init(imx_epit_register_types) diff --git a/qemu/hw/timer/imx_gpt.c b/qemu/hw/timer/imx_gpt.c deleted file mode 100644 index ab2e213a1..000000000 --- a/qemu/hw/timer/imx_gpt.c +++ /dev/null @@ -1,467 +0,0 @@ -/* - * IMX GPT Timer - * - * Copyright (c) 2008 OK Labs - * Copyright (c) 2011 NICTA Pty Ltd - * Originally written by Hans Jiang - * Updated by Peter Chubb - * Updated by Jean-Christophe Dubois <jcd@tribudubois.net> - * - * This code is licensed under GPL version 2 or later. See - * the COPYING file in the top-level directory. - * - */ - -#include "qemu/osdep.h" -#include "hw/timer/imx_gpt.h" -#include "hw/misc/imx_ccm.h" -#include "qemu/main-loop.h" - -#ifndef DEBUG_IMX_GPT -#define DEBUG_IMX_GPT 0 -#endif - -#define DPRINTF(fmt, args...) \ - do { \ - if (DEBUG_IMX_GPT) { \ - fprintf(stderr, "[%s]%s: " fmt , TYPE_IMX_GPT, \ - __func__, ##args); \ - } \ - } while (0) - -static char const *imx_gpt_reg_name(uint32_t reg) -{ - switch (reg) { - case 0: - return "CR"; - case 1: - return "PR"; - case 2: - return "SR"; - case 3: - return "IR"; - case 4: - return "OCR1"; - case 5: - return "OCR2"; - case 6: - return "OCR3"; - case 7: - return "ICR1"; - case 8: - return "ICR2"; - case 9: - return "CNT"; - default: - return "[?]"; - } -} - -static const VMStateDescription vmstate_imx_timer_gpt = { - .name = TYPE_IMX_GPT, - .version_id = 3, - .minimum_version_id = 3, - .fields = (VMStateField[]) { - VMSTATE_UINT32(cr, IMXGPTState), - VMSTATE_UINT32(pr, IMXGPTState), - VMSTATE_UINT32(sr, IMXGPTState), - VMSTATE_UINT32(ir, IMXGPTState), - VMSTATE_UINT32(ocr1, IMXGPTState), - VMSTATE_UINT32(ocr2, IMXGPTState), - VMSTATE_UINT32(ocr3, IMXGPTState), - VMSTATE_UINT32(icr1, IMXGPTState), - VMSTATE_UINT32(icr2, IMXGPTState), - VMSTATE_UINT32(cnt, IMXGPTState), - VMSTATE_UINT32(next_timeout, IMXGPTState), - VMSTATE_UINT32(next_int, IMXGPTState), - VMSTATE_UINT32(freq, IMXGPTState), - VMSTATE_PTIMER(timer, IMXGPTState), - VMSTATE_END_OF_LIST() - } -}; - -static const IMXClk imx_gpt_clocks[] = { - CLK_NONE, /* 000 No clock source */ - CLK_IPG, /* 001 ipg_clk, 532MHz*/ - CLK_IPG_HIGH, /* 010 ipg_clk_highfreq */ - CLK_NONE, /* 011 not defined */ - CLK_32k, /* 100 ipg_clk_32k */ - CLK_NONE, /* 101 not defined */ - CLK_NONE, /* 110 not defined */ - CLK_NONE, /* 111 not defined */ -}; - -static void imx_gpt_set_freq(IMXGPTState *s) -{ - uint32_t clksrc = extract32(s->cr, GPT_CR_CLKSRC_SHIFT, 3); - - s->freq = imx_ccm_get_clock_frequency(s->ccm, - imx_gpt_clocks[clksrc]) / (1 + s->pr); - - DPRINTF("Setting clksrc %d to frequency %d\n", clksrc, s->freq); - - if (s->freq) { - ptimer_set_freq(s->timer, s->freq); - } -} - -static void imx_gpt_update_int(IMXGPTState *s) -{ - if ((s->sr & s->ir) && (s->cr & GPT_CR_EN)) { - qemu_irq_raise(s->irq); - } else { - qemu_irq_lower(s->irq); - } -} - -static uint32_t imx_gpt_update_count(IMXGPTState *s) -{ - s->cnt = s->next_timeout - (uint32_t)ptimer_get_count(s->timer); - - return s->cnt; -} - -static inline uint32_t imx_gpt_find_limit(uint32_t count, uint32_t reg, - uint32_t timeout) -{ - if ((count < reg) && (timeout > reg)) { - timeout = reg; - } - - return timeout; -} - -static void imx_gpt_compute_next_timeout(IMXGPTState *s, bool event) -{ - uint32_t timeout = GPT_TIMER_MAX; - uint32_t count; - long long limit; - - if (!(s->cr & GPT_CR_EN)) { - /* if not enabled just return */ - return; - } - - /* update the count */ - count = imx_gpt_update_count(s); - - if (event) { - /* - * This is an event (the ptimer reached 0 and stopped), and the - * timer counter is now equal to s->next_timeout. - */ - if (!(s->cr & GPT_CR_FRR) && (count == s->ocr1)) { - /* We are in restart mode and we crossed the compare channel 1 - * value. We need to reset the counter to 0. - */ - count = s->cnt = s->next_timeout = 0; - } else if (count == GPT_TIMER_MAX) { - /* We reached GPT_TIMER_MAX so we need to rollover */ - count = s->cnt = s->next_timeout = 0; - } - } - - /* now, find the next timeout related to count */ - - if (s->ir & GPT_IR_OF1IE) { - timeout = imx_gpt_find_limit(count, s->ocr1, timeout); - } - if (s->ir & GPT_IR_OF2IE) { - timeout = imx_gpt_find_limit(count, s->ocr2, timeout); - } - if (s->ir & GPT_IR_OF3IE) { - timeout = imx_gpt_find_limit(count, s->ocr3, timeout); - } - - /* find the next set of interrupts to raise for next timer event */ - - s->next_int = 0; - if ((s->ir & GPT_IR_OF1IE) && (timeout == s->ocr1)) { - s->next_int |= GPT_SR_OF1; - } - if ((s->ir & GPT_IR_OF2IE) && (timeout == s->ocr2)) { - s->next_int |= GPT_SR_OF2; - } - if ((s->ir & GPT_IR_OF3IE) && (timeout == s->ocr3)) { - s->next_int |= GPT_SR_OF3; - } - if ((s->ir & GPT_IR_ROVIE) && (timeout == GPT_TIMER_MAX)) { - s->next_int |= GPT_SR_ROV; - } - - /* the new range to count down from */ - limit = timeout - imx_gpt_update_count(s); - - if (limit < 0) { - /* - * if we reach here, then QEMU is running too slow and we pass the - * timeout limit while computing it. Let's deliver the interrupt - * and compute a new limit. - */ - s->sr |= s->next_int; - - imx_gpt_compute_next_timeout(s, event); - - imx_gpt_update_int(s); - } else { - /* New timeout value */ - s->next_timeout = timeout; - - /* reset the limit to the computed range */ - ptimer_set_limit(s->timer, limit, 1); - } -} - -static uint64_t imx_gpt_read(void *opaque, hwaddr offset, unsigned size) -{ - IMXGPTState *s = IMX_GPT(opaque); - uint32_t reg_value = 0; - - switch (offset >> 2) { - case 0: /* Control Register */ - reg_value = s->cr; - break; - - case 1: /* prescaler */ - reg_value = s->pr; - break; - - case 2: /* Status Register */ - reg_value = s->sr; - break; - - case 3: /* Interrupt Register */ - reg_value = s->ir; - break; - - case 4: /* Output Compare Register 1 */ - reg_value = s->ocr1; - break; - - case 5: /* Output Compare Register 2 */ - reg_value = s->ocr2; - break; - - case 6: /* Output Compare Register 3 */ - reg_value = s->ocr3; - break; - - case 7: /* input Capture Register 1 */ - qemu_log_mask(LOG_UNIMP, "[%s]%s: icr1 feature is not implemented\n", - TYPE_IMX_GPT, __func__); - reg_value = s->icr1; - break; - - case 8: /* input Capture Register 2 */ - qemu_log_mask(LOG_UNIMP, "[%s]%s: icr2 feature is not implemented\n", - TYPE_IMX_GPT, __func__); - reg_value = s->icr2; - break; - - case 9: /* cnt */ - imx_gpt_update_count(s); - reg_value = s->cnt; - break; - - default: - qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad register at offset 0x%" - HWADDR_PRIx "\n", TYPE_IMX_GPT, __func__, offset); - break; - } - - DPRINTF("(%s) = 0x%08x\n", imx_gpt_reg_name(offset >> 2), reg_value); - - return reg_value; -} - -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 imx_gpt_write(void *opaque, hwaddr offset, uint64_t value, - unsigned size) -{ - IMXGPTState *s = IMX_GPT(opaque); - uint32_t oldreg; - - DPRINTF("(%s, value = 0x%08x)\n", imx_gpt_reg_name(offset >> 2), - (uint32_t)value); - - switch (offset >> 2) { - 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: - qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad register at offset 0x%" - HWADDR_PRIx "\n", TYPE_IMX_GPT, __func__, offset); - break; - } -} - -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 const MemoryRegionOps imx_gpt_ops = { - .read = imx_gpt_read, - .write = imx_gpt_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - - -static void imx_gpt_realize(DeviceState *dev, Error **errp) -{ - IMXGPTState *s = IMX_GPT(dev); - SysBusDevice *sbd = SYS_BUS_DEVICE(dev); - QEMUBH *bh; - - sysbus_init_irq(sbd, &s->irq); - memory_region_init_io(&s->iomem, OBJECT(s), &imx_gpt_ops, s, TYPE_IMX_GPT, - 0x00001000); - sysbus_init_mmio(sbd, &s->iomem); - - bh = qemu_bh_new(imx_gpt_timeout, s); - s->timer = ptimer_init(bh); -} - -static void imx_gpt_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - - dc->realize = imx_gpt_realize; - dc->reset = imx_gpt_reset; - dc->vmsd = &vmstate_imx_timer_gpt; - dc->desc = "i.MX general timer"; -} - -static const TypeInfo imx_gpt_info = { - .name = TYPE_IMX_GPT, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(IMXGPTState), - .class_init = imx_gpt_class_init, -}; - -static void imx_gpt_register_types(void) -{ - type_register_static(&imx_gpt_info); -} - -type_init(imx_gpt_register_types) diff --git a/qemu/hw/timer/lm32_timer.c b/qemu/hw/timer/lm32_timer.c deleted file mode 100644 index 3198355aa..000000000 --- a/qemu/hw/timer/lm32_timer.c +++ /dev/null @@ -1,236 +0,0 @@ -/* - * QEMU model of the LatticeMico32 timer block. - * - * Copyright (c) 2010 Michael Walle <michael@walle.cc> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see <http://www.gnu.org/licenses/>. - * - * - * Specification available at: - * http://www.latticesemi.com/documents/mico32timer.pdf - */ - -#include "qemu/osdep.h" -#include "hw/hw.h" -#include "hw/sysbus.h" -#include "trace.h" -#include "qemu/timer.h" -#include "hw/ptimer.h" -#include "qemu/error-report.h" -#include "qemu/main-loop.h" - -#define DEFAULT_FREQUENCY (50*1000000) - -enum { - R_SR = 0, - R_CR, - R_PERIOD, - R_SNAPSHOT, - R_MAX -}; - -enum { - SR_TO = (1 << 0), - SR_RUN = (1 << 1), -}; - -enum { - CR_ITO = (1 << 0), - CR_CONT = (1 << 1), - CR_START = (1 << 2), - CR_STOP = (1 << 3), -}; - -#define TYPE_LM32_TIMER "lm32-timer" -#define LM32_TIMER(obj) OBJECT_CHECK(LM32TimerState, (obj), TYPE_LM32_TIMER) - -struct LM32TimerState { - SysBusDevice parent_obj; - - MemoryRegion iomem; - - QEMUBH *bh; - ptimer_state *ptimer; - - qemu_irq irq; - uint32_t freq_hz; - - uint32_t regs[R_MAX]; -}; -typedef struct LM32TimerState LM32TimerState; - -static void timer_update_irq(LM32TimerState *s) -{ - int state = (s->regs[R_SR] & SR_TO) && (s->regs[R_CR] & CR_ITO); - - trace_lm32_timer_irq_state(state); - qemu_set_irq(s->irq, state); -} - -static uint64_t timer_read(void *opaque, hwaddr addr, unsigned size) -{ - LM32TimerState *s = opaque; - uint32_t r = 0; - - addr >>= 2; - switch (addr) { - case R_SR: - case R_CR: - case R_PERIOD: - r = s->regs[addr]; - break; - case R_SNAPSHOT: - r = (uint32_t)ptimer_get_count(s->ptimer); - break; - default: - error_report("lm32_timer: read access to unknown register 0x" - TARGET_FMT_plx, addr << 2); - break; - } - - trace_lm32_timer_memory_read(addr << 2, r); - return r; -} - -static void timer_write(void *opaque, hwaddr addr, - uint64_t value, unsigned size) -{ - 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 const MemoryRegionOps timer_ops = { - .read = timer_read, - .write = timer_write, - .endianness = DEVICE_NATIVE_ENDIAN, - .valid = { - .min_access_size = 4, - .max_access_size = 4, - }, -}; - -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 timer_reset(DeviceState *d) -{ - LM32TimerState *s = LM32_TIMER(d); - int i; - - for (i = 0; i < R_MAX; i++) { - s->regs[i] = 0; - } - ptimer_stop(s->ptimer); -} - -static int lm32_timer_init(SysBusDevice *dev) -{ - LM32TimerState *s = LM32_TIMER(dev); - - sysbus_init_irq(dev, &s->irq); - - s->bh = qemu_bh_new(timer_hit, s); - s->ptimer = ptimer_init(s->bh); - ptimer_set_freq(s->ptimer, s->freq_hz); - - memory_region_init_io(&s->iomem, OBJECT(s), &timer_ops, s, - "timer", R_MAX * 4); - sysbus_init_mmio(dev, &s->iomem); - - return 0; -} - -static const VMStateDescription vmstate_lm32_timer = { - .name = "lm32-timer", - .version_id = 1, - .minimum_version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_PTIMER(ptimer, LM32TimerState), - VMSTATE_UINT32(freq_hz, LM32TimerState), - VMSTATE_UINT32_ARRAY(regs, LM32TimerState, R_MAX), - VMSTATE_END_OF_LIST() - } -}; - -static Property lm32_timer_properties[] = { - DEFINE_PROP_UINT32("frequency", LM32TimerState, freq_hz, DEFAULT_FREQUENCY), - DEFINE_PROP_END_OF_LIST(), -}; - -static void lm32_timer_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); - - k->init = lm32_timer_init; - dc->reset = timer_reset; - dc->vmsd = &vmstate_lm32_timer; - dc->props = lm32_timer_properties; -} - -static const TypeInfo lm32_timer_info = { - .name = TYPE_LM32_TIMER, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(LM32TimerState), - .class_init = lm32_timer_class_init, -}; - -static void lm32_timer_register_types(void) -{ - type_register_static(&lm32_timer_info); -} - -type_init(lm32_timer_register_types) diff --git a/qemu/hw/timer/m48t59.c b/qemu/hw/timer/m48t59.c deleted file mode 100644 index e46ca8839..000000000 --- a/qemu/hw/timer/m48t59.c +++ /dev/null @@ -1,947 +0,0 @@ -/* - * QEMU M48T59 and M48T08 NVRAM emulation for PPC PREP and Sparc platforms - * - * Copyright (c) 2003-2005, 2007 Jocelyn Mayer - * Copyright (c) 2013 Hervé Poussineau - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include "qemu/osdep.h" -#include "hw/hw.h" -#include "hw/timer/m48t59.h" -#include "qapi/error.h" -#include "qemu/timer.h" -#include "sysemu/sysemu.h" -#include "hw/sysbus.h" -#include "hw/isa/isa.h" -#include "exec/address-spaces.h" -#include "qemu/bcd.h" - -//#define DEBUG_NVRAM - -#if defined(DEBUG_NVRAM) -#define NVRAM_PRINTF(fmt, ...) do { printf(fmt , ## __VA_ARGS__); } while (0) -#else -#define NVRAM_PRINTF(fmt, ...) do { } while (0) -#endif - -#define TYPE_M48TXX_SYS_BUS "sysbus-m48txx" -#define M48TXX_SYS_BUS_GET_CLASS(obj) \ - OBJECT_GET_CLASS(M48txxSysBusDeviceClass, (obj), TYPE_M48TXX_SYS_BUS) -#define M48TXX_SYS_BUS_CLASS(klass) \ - OBJECT_CLASS_CHECK(M48txxSysBusDeviceClass, (klass), TYPE_M48TXX_SYS_BUS) -#define M48TXX_SYS_BUS(obj) \ - OBJECT_CHECK(M48txxSysBusState, (obj), TYPE_M48TXX_SYS_BUS) - -#define TYPE_M48TXX_ISA "isa-m48txx" -#define M48TXX_ISA_GET_CLASS(obj) \ - OBJECT_GET_CLASS(M48txxISADeviceClass, (obj), TYPE_M48TXX_ISA) -#define M48TXX_ISA_CLASS(klass) \ - OBJECT_CLASS_CHECK(M48txxISADeviceClass, (klass), TYPE_M48TXX_ISA) -#define M48TXX_ISA(obj) \ - OBJECT_CHECK(M48txxISAState, (obj), TYPE_M48TXX_ISA) - -/* - * The M48T02, M48T08 and M48T59 chips are very similar. The newer '59 has - * alarm and a watchdog timer and related control registers. In the - * PPC platform there is also a nvram lock function. - */ - -typedef struct M48txxInfo { - const char *isa_name; - const char *sysbus_name; - uint32_t model; /* 2 = m48t02, 8 = m48t08, 59 = m48t59 */ - uint32_t size; -} M48txxInfo; - -/* - * Chipset docs: - * http://www.st.com/stonline/products/literature/ds/2410/m48t02.pdf - * http://www.st.com/stonline/products/literature/ds/2411/m48t08.pdf - * http://www.st.com/stonline/products/literature/od/7001/m48t59y.pdf - */ - -typedef struct M48t59State { - /* Hardware parameters */ - qemu_irq IRQ; - MemoryRegion iomem; - uint32_t size; - int32_t base_year; - /* RTC management */ - time_t time_offset; - time_t stop_time; - /* Alarm & watchdog */ - struct tm alarm; - QEMUTimer *alrm_timer; - QEMUTimer *wd_timer; - /* NVRAM storage */ - uint8_t *buffer; - /* Model parameters */ - uint32_t model; /* 2 = m48t02, 8 = m48t08, 59 = m48t59 */ - /* NVRAM storage */ - uint16_t addr; - uint8_t lock; -} M48t59State; - -typedef struct M48txxISAState { - ISADevice parent_obj; - M48t59State state; - uint32_t io_base; - MemoryRegion io; -} M48txxISAState; - -typedef struct M48txxISADeviceClass { - ISADeviceClass parent_class; - M48txxInfo info; -} M48txxISADeviceClass; - -typedef struct M48txxSysBusState { - SysBusDevice parent_obj; - M48t59State state; - MemoryRegion io; -} M48txxSysBusState; - -typedef struct M48txxSysBusDeviceClass { - SysBusDeviceClass parent_class; - M48txxInfo info; -} M48txxSysBusDeviceClass; - -static M48txxInfo m48txx_info[] = { - { - .sysbus_name = "sysbus-m48t02", - .model = 2, - .size = 0x800, - },{ - .sysbus_name = "sysbus-m48t08", - .model = 8, - .size = 0x2000, - },{ - .sysbus_name = "sysbus-m48t59", - .model = 59, - .size = 0x2000, - },{ - .isa_name = "isa-m48t59", - .model = 59, - .size = 0x2000, - } -}; - - -/* Fake timer functions */ - -/* Alarm management */ -static void alarm_cb (void *opaque) -{ - struct tm tm; - uint64_t next_time; - M48t59State *NVRAM = opaque; - - qemu_set_irq(NVRAM->IRQ, 1); - if ((NVRAM->buffer[0x1FF5] & 0x80) == 0 && - (NVRAM->buffer[0x1FF4] & 0x80) == 0 && - (NVRAM->buffer[0x1FF3] & 0x80) == 0 && - (NVRAM->buffer[0x1FF2] & 0x80) == 0) { - /* Repeat once a month */ - qemu_get_timedate(&tm, NVRAM->time_offset); - tm.tm_mon++; - if (tm.tm_mon == 13) { - tm.tm_mon = 1; - tm.tm_year++; - } - next_time = qemu_timedate_diff(&tm) - NVRAM->time_offset; - } else if ((NVRAM->buffer[0x1FF5] & 0x80) != 0 && - (NVRAM->buffer[0x1FF4] & 0x80) == 0 && - (NVRAM->buffer[0x1FF3] & 0x80) == 0 && - (NVRAM->buffer[0x1FF2] & 0x80) == 0) { - /* Repeat once a day */ - next_time = 24 * 60 * 60; - } else if ((NVRAM->buffer[0x1FF5] & 0x80) != 0 && - (NVRAM->buffer[0x1FF4] & 0x80) != 0 && - (NVRAM->buffer[0x1FF3] & 0x80) == 0 && - (NVRAM->buffer[0x1FF2] & 0x80) == 0) { - /* Repeat once an hour */ - next_time = 60 * 60; - } else if ((NVRAM->buffer[0x1FF5] & 0x80) != 0 && - (NVRAM->buffer[0x1FF4] & 0x80) != 0 && - (NVRAM->buffer[0x1FF3] & 0x80) != 0 && - (NVRAM->buffer[0x1FF2] & 0x80) == 0) { - /* Repeat once a minute */ - next_time = 60; - } else { - /* Repeat once a second */ - next_time = 1; - } - timer_mod(NVRAM->alrm_timer, qemu_clock_get_ns(rtc_clock) + - next_time * 1000); - qemu_set_irq(NVRAM->IRQ, 0); -} - -static void set_alarm(M48t59State *NVRAM) -{ - int diff; - if (NVRAM->alrm_timer != NULL) { - timer_del(NVRAM->alrm_timer); - diff = qemu_timedate_diff(&NVRAM->alarm) - NVRAM->time_offset; - if (diff > 0) - timer_mod(NVRAM->alrm_timer, diff * 1000); - } -} - -/* RTC management helpers */ -static inline void get_time(M48t59State *NVRAM, struct tm *tm) -{ - qemu_get_timedate(tm, NVRAM->time_offset); -} - -static void set_time(M48t59State *NVRAM, struct tm *tm) -{ - NVRAM->time_offset = qemu_timedate_diff(tm); - set_alarm(NVRAM); -} - -/* Watchdog management */ -static void watchdog_cb (void *opaque) -{ - M48t59State *NVRAM = opaque; - - NVRAM->buffer[0x1FF0] |= 0x80; - if (NVRAM->buffer[0x1FF7] & 0x80) { - NVRAM->buffer[0x1FF7] = 0x00; - NVRAM->buffer[0x1FFC] &= ~0x40; - /* May it be a hw CPU Reset instead ? */ - qemu_system_reset_request(); - } else { - qemu_set_irq(NVRAM->IRQ, 1); - qemu_set_irq(NVRAM->IRQ, 0); - } -} - -static void set_up_watchdog(M48t59State *NVRAM, uint8_t value) -{ - uint64_t interval; /* in 1/16 seconds */ - - NVRAM->buffer[0x1FF0] &= ~0x80; - if (NVRAM->wd_timer != NULL) { - timer_del(NVRAM->wd_timer); - if (value != 0) { - interval = (1 << (2 * (value & 0x03))) * ((value >> 2) & 0x1F); - timer_mod(NVRAM->wd_timer, ((uint64_t)time(NULL) * 1000) + - ((interval * 1000) >> 4)); - } - } -} - -/* Direct access to NVRAM */ -static void m48t59_write(M48t59State *NVRAM, uint32_t addr, uint32_t val) -{ - struct tm tm; - int tmp; - - if (addr > 0x1FF8 && addr < 0x2000) - NVRAM_PRINTF("%s: 0x%08x => 0x%08x\n", __func__, addr, val); - - /* check for NVRAM access */ - if ((NVRAM->model == 2 && addr < 0x7f8) || - (NVRAM->model == 8 && addr < 0x1ff8) || - (NVRAM->model == 59 && addr < 0x1ff0)) { - goto do_write; - } - - /* TOD access */ - switch (addr) { - case 0x1FF0: - /* flags register : read-only */ - break; - case 0x1FF1: - /* unused */ - break; - case 0x1FF2: - /* alarm seconds */ - tmp = from_bcd(val & 0x7F); - if (tmp >= 0 && tmp <= 59) { - NVRAM->alarm.tm_sec = tmp; - NVRAM->buffer[0x1FF2] = val; - set_alarm(NVRAM); - } - break; - case 0x1FF3: - /* alarm minutes */ - tmp = from_bcd(val & 0x7F); - if (tmp >= 0 && tmp <= 59) { - NVRAM->alarm.tm_min = tmp; - NVRAM->buffer[0x1FF3] = val; - set_alarm(NVRAM); - } - break; - case 0x1FF4: - /* alarm hours */ - tmp = from_bcd(val & 0x3F); - if (tmp >= 0 && tmp <= 23) { - NVRAM->alarm.tm_hour = tmp; - NVRAM->buffer[0x1FF4] = val; - set_alarm(NVRAM); - } - break; - case 0x1FF5: - /* alarm date */ - tmp = from_bcd(val & 0x3F); - if (tmp != 0) { - NVRAM->alarm.tm_mday = tmp; - NVRAM->buffer[0x1FF5] = val; - set_alarm(NVRAM); - } - break; - case 0x1FF6: - /* interrupts */ - NVRAM->buffer[0x1FF6] = val; - break; - case 0x1FF7: - /* watchdog */ - NVRAM->buffer[0x1FF7] = val; - set_up_watchdog(NVRAM, val); - break; - case 0x1FF8: - case 0x07F8: - /* control */ - NVRAM->buffer[addr] = (val & ~0xA0) | 0x90; - break; - case 0x1FF9: - case 0x07F9: - /* seconds (BCD) */ - tmp = from_bcd(val & 0x7F); - if (tmp >= 0 && tmp <= 59) { - get_time(NVRAM, &tm); - tm.tm_sec = tmp; - set_time(NVRAM, &tm); - } - if ((val & 0x80) ^ (NVRAM->buffer[addr] & 0x80)) { - if (val & 0x80) { - NVRAM->stop_time = time(NULL); - } else { - NVRAM->time_offset += NVRAM->stop_time - time(NULL); - NVRAM->stop_time = 0; - } - } - NVRAM->buffer[addr] = val & 0x80; - break; - case 0x1FFA: - case 0x07FA: - /* minutes (BCD) */ - tmp = from_bcd(val & 0x7F); - if (tmp >= 0 && tmp <= 59) { - get_time(NVRAM, &tm); - tm.tm_min = tmp; - set_time(NVRAM, &tm); - } - break; - case 0x1FFB: - case 0x07FB: - /* hours (BCD) */ - tmp = from_bcd(val & 0x3F); - if (tmp >= 0 && tmp <= 23) { - get_time(NVRAM, &tm); - tm.tm_hour = tmp; - set_time(NVRAM, &tm); - } - break; - case 0x1FFC: - case 0x07FC: - /* day of the week / century */ - tmp = from_bcd(val & 0x07); - get_time(NVRAM, &tm); - tm.tm_wday = tmp; - set_time(NVRAM, &tm); - NVRAM->buffer[addr] = val & 0x40; - break; - case 0x1FFD: - case 0x07FD: - /* date (BCD) */ - tmp = from_bcd(val & 0x3F); - if (tmp != 0) { - get_time(NVRAM, &tm); - tm.tm_mday = tmp; - set_time(NVRAM, &tm); - } - break; - case 0x1FFE: - case 0x07FE: - /* month */ - tmp = from_bcd(val & 0x1F); - if (tmp >= 1 && tmp <= 12) { - get_time(NVRAM, &tm); - tm.tm_mon = tmp - 1; - set_time(NVRAM, &tm); - } - break; - case 0x1FFF: - case 0x07FF: - /* year */ - tmp = from_bcd(val); - if (tmp >= 0 && tmp <= 99) { - get_time(NVRAM, &tm); - tm.tm_year = from_bcd(val) + NVRAM->base_year - 1900; - set_time(NVRAM, &tm); - } - break; - default: - /* Check lock registers state */ - if (addr >= 0x20 && addr <= 0x2F && (NVRAM->lock & 1)) - break; - if (addr >= 0x30 && addr <= 0x3F && (NVRAM->lock & 2)) - break; - do_write: - if (addr < NVRAM->size) { - NVRAM->buffer[addr] = val & 0xFF; - } - break; - } -} - -static uint32_t m48t59_read(M48t59State *NVRAM, uint32_t addr) -{ - struct tm tm; - uint32_t retval = 0xFF; - - /* check for NVRAM access */ - if ((NVRAM->model == 2 && addr < 0x078f) || - (NVRAM->model == 8 && addr < 0x1ff8) || - (NVRAM->model == 59 && addr < 0x1ff0)) { - goto do_read; - } - - /* TOD access */ - switch (addr) { - case 0x1FF0: - /* flags register */ - goto do_read; - case 0x1FF1: - /* unused */ - retval = 0; - break; - case 0x1FF2: - /* alarm seconds */ - goto do_read; - case 0x1FF3: - /* alarm minutes */ - goto do_read; - case 0x1FF4: - /* alarm hours */ - goto do_read; - case 0x1FF5: - /* alarm date */ - goto do_read; - case 0x1FF6: - /* interrupts */ - goto do_read; - case 0x1FF7: - /* A read resets the watchdog */ - set_up_watchdog(NVRAM, NVRAM->buffer[0x1FF7]); - goto do_read; - case 0x1FF8: - case 0x07F8: - /* control */ - goto do_read; - case 0x1FF9: - case 0x07F9: - /* seconds (BCD) */ - get_time(NVRAM, &tm); - retval = (NVRAM->buffer[addr] & 0x80) | to_bcd(tm.tm_sec); - break; - case 0x1FFA: - case 0x07FA: - /* minutes (BCD) */ - get_time(NVRAM, &tm); - retval = to_bcd(tm.tm_min); - break; - case 0x1FFB: - case 0x07FB: - /* hours (BCD) */ - get_time(NVRAM, &tm); - retval = to_bcd(tm.tm_hour); - break; - case 0x1FFC: - case 0x07FC: - /* day of the week / century */ - get_time(NVRAM, &tm); - retval = NVRAM->buffer[addr] | tm.tm_wday; - break; - case 0x1FFD: - case 0x07FD: - /* date */ - get_time(NVRAM, &tm); - retval = to_bcd(tm.tm_mday); - break; - case 0x1FFE: - case 0x07FE: - /* month */ - get_time(NVRAM, &tm); - retval = to_bcd(tm.tm_mon + 1); - break; - case 0x1FFF: - case 0x07FF: - /* year */ - get_time(NVRAM, &tm); - retval = to_bcd((tm.tm_year + 1900 - NVRAM->base_year) % 100); - break; - default: - /* Check lock registers state */ - if (addr >= 0x20 && addr <= 0x2F && (NVRAM->lock & 1)) - break; - if (addr >= 0x30 && addr <= 0x3F && (NVRAM->lock & 2)) - break; - do_read: - if (addr < NVRAM->size) { - retval = NVRAM->buffer[addr]; - } - break; - } - if (addr > 0x1FF9 && addr < 0x2000) - NVRAM_PRINTF("%s: 0x%08x <= 0x%08x\n", __func__, addr, retval); - - return retval; -} - -static void m48t59_toggle_lock(M48t59State *NVRAM, int lock) -{ - NVRAM->lock ^= 1 << lock; -} - -/* IO access to NVRAM */ -static void NVRAM_writeb(void *opaque, hwaddr addr, uint64_t val, - unsigned size) -{ - M48t59State *NVRAM = opaque; - - NVRAM_PRINTF("%s: 0x%08x => 0x%08x\n", __func__, addr, val); - switch (addr) { - case 0: - NVRAM->addr &= ~0x00FF; - NVRAM->addr |= val; - break; - case 1: - NVRAM->addr &= ~0xFF00; - NVRAM->addr |= val << 8; - break; - case 3: - m48t59_write(NVRAM, NVRAM->addr, val); - NVRAM->addr = 0x0000; - break; - default: - break; - } -} - -static uint64_t NVRAM_readb(void *opaque, hwaddr addr, unsigned size) -{ - M48t59State *NVRAM = opaque; - uint32_t retval; - - switch (addr) { - case 3: - retval = m48t59_read(NVRAM, NVRAM->addr); - break; - default: - retval = -1; - break; - } - NVRAM_PRINTF("%s: 0x%08x <= 0x%08x\n", __func__, addr, retval); - - return retval; -} - -static void nvram_writeb (void *opaque, hwaddr addr, uint32_t value) -{ - M48t59State *NVRAM = opaque; - - m48t59_write(NVRAM, addr, value & 0xff); -} - -static void nvram_writew (void *opaque, hwaddr addr, uint32_t value) -{ - M48t59State *NVRAM = opaque; - - m48t59_write(NVRAM, addr, (value >> 8) & 0xff); - m48t59_write(NVRAM, addr + 1, value & 0xff); -} - -static void nvram_writel (void *opaque, hwaddr addr, uint32_t value) -{ - M48t59State *NVRAM = opaque; - - m48t59_write(NVRAM, addr, (value >> 24) & 0xff); - m48t59_write(NVRAM, addr + 1, (value >> 16) & 0xff); - m48t59_write(NVRAM, addr + 2, (value >> 8) & 0xff); - m48t59_write(NVRAM, addr + 3, value & 0xff); -} - -static uint32_t nvram_readb (void *opaque, hwaddr addr) -{ - M48t59State *NVRAM = opaque; - - return m48t59_read(NVRAM, addr); -} - -static uint32_t nvram_readw (void *opaque, hwaddr addr) -{ - M48t59State *NVRAM = opaque; - uint32_t retval; - - retval = m48t59_read(NVRAM, addr) << 8; - retval |= m48t59_read(NVRAM, addr + 1); - return retval; -} - -static uint32_t nvram_readl (void *opaque, hwaddr addr) -{ - M48t59State *NVRAM = opaque; - uint32_t retval; - - retval = m48t59_read(NVRAM, addr) << 24; - retval |= m48t59_read(NVRAM, addr + 1) << 16; - retval |= m48t59_read(NVRAM, addr + 2) << 8; - retval |= m48t59_read(NVRAM, addr + 3); - return retval; -} - -static const MemoryRegionOps nvram_ops = { - .old_mmio = { - .read = { nvram_readb, nvram_readw, nvram_readl, }, - .write = { nvram_writeb, nvram_writew, nvram_writel, }, - }, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static const VMStateDescription vmstate_m48t59 = { - .name = "m48t59", - .version_id = 1, - .minimum_version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_UINT8(lock, M48t59State), - VMSTATE_UINT16(addr, M48t59State), - VMSTATE_VBUFFER_UINT32(buffer, M48t59State, 0, NULL, 0, size), - VMSTATE_END_OF_LIST() - } -}; - -static void m48t59_reset_common(M48t59State *NVRAM) -{ - NVRAM->addr = 0; - NVRAM->lock = 0; - if (NVRAM->alrm_timer != NULL) - timer_del(NVRAM->alrm_timer); - - if (NVRAM->wd_timer != NULL) - timer_del(NVRAM->wd_timer); -} - -static void m48t59_reset_isa(DeviceState *d) -{ - M48txxISAState *isa = M48TXX_ISA(d); - M48t59State *NVRAM = &isa->state; - - m48t59_reset_common(NVRAM); -} - -static void m48t59_reset_sysbus(DeviceState *d) -{ - M48txxSysBusState *sys = M48TXX_SYS_BUS(d); - M48t59State *NVRAM = &sys->state; - - m48t59_reset_common(NVRAM); -} - -static const MemoryRegionOps m48t59_io_ops = { - .read = NVRAM_readb, - .write = NVRAM_writeb, - .impl = { - .min_access_size = 1, - .max_access_size = 1, - }, - .endianness = DEVICE_LITTLE_ENDIAN, -}; - -/* Initialisation routine */ -Nvram *m48t59_init(qemu_irq IRQ, hwaddr mem_base, - uint32_t io_base, uint16_t size, int base_year, - int model) -{ - DeviceState *dev; - SysBusDevice *s; - int i; - - for (i = 0; i < ARRAY_SIZE(m48txx_info); i++) { - if (!m48txx_info[i].sysbus_name || - m48txx_info[i].size != size || - m48txx_info[i].model != model) { - continue; - } - - dev = qdev_create(NULL, m48txx_info[i].sysbus_name); - qdev_prop_set_int32(dev, "base-year", base_year); - qdev_init_nofail(dev); - s = SYS_BUS_DEVICE(dev); - sysbus_connect_irq(s, 0, IRQ); - if (io_base != 0) { - memory_region_add_subregion(get_system_io(), io_base, - sysbus_mmio_get_region(s, 1)); - } - if (mem_base != 0) { - sysbus_mmio_map(s, 0, mem_base); - } - - return NVRAM(s); - } - - assert(false); - return NULL; -} - -Nvram *m48t59_init_isa(ISABus *bus, uint32_t io_base, uint16_t size, - int base_year, int model) -{ - DeviceState *dev; - int i; - - for (i = 0; i < ARRAY_SIZE(m48txx_info); i++) { - if (!m48txx_info[i].isa_name || - m48txx_info[i].size != size || - m48txx_info[i].model != model) { - continue; - } - - dev = DEVICE(isa_create(bus, m48txx_info[i].isa_name)); - qdev_prop_set_uint32(dev, "iobase", io_base); - qdev_prop_set_int32(dev, "base-year", base_year); - qdev_init_nofail(dev); - return NVRAM(dev); - } - - assert(false); - return NULL; -} - -static void m48t59_realize_common(M48t59State *s, Error **errp) -{ - s->buffer = g_malloc0(s->size); - if (s->model == 59) { - s->alrm_timer = timer_new_ns(rtc_clock, &alarm_cb, s); - s->wd_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, &watchdog_cb, s); - } - qemu_get_timedate(&s->alarm, 0); - - vmstate_register(NULL, -1, &vmstate_m48t59, s); -} - -static void m48t59_isa_realize(DeviceState *dev, Error **errp) -{ - M48txxISADeviceClass *u = M48TXX_ISA_GET_CLASS(dev); - ISADevice *isadev = ISA_DEVICE(dev); - M48txxISAState *d = M48TXX_ISA(dev); - M48t59State *s = &d->state; - - s->model = u->info.model; - s->size = u->info.size; - isa_init_irq(isadev, &s->IRQ, 8); - m48t59_realize_common(s, errp); - memory_region_init_io(&d->io, OBJECT(dev), &m48t59_io_ops, s, "m48t59", 4); - if (d->io_base != 0) { - isa_register_ioport(isadev, &d->io, d->io_base); - } -} - -static int m48t59_init1(SysBusDevice *dev) -{ - M48txxSysBusDeviceClass *u = M48TXX_SYS_BUS_GET_CLASS(dev); - M48txxSysBusState *d = M48TXX_SYS_BUS(dev); - Object *o = OBJECT(dev); - M48t59State *s = &d->state; - Error *err = NULL; - - s->model = u->info.model; - s->size = u->info.size; - sysbus_init_irq(dev, &s->IRQ); - - memory_region_init_io(&s->iomem, o, &nvram_ops, s, "m48t59.nvram", - s->size); - memory_region_init_io(&d->io, o, &m48t59_io_ops, s, "m48t59", 4); - sysbus_init_mmio(dev, &s->iomem); - sysbus_init_mmio(dev, &d->io); - m48t59_realize_common(s, &err); - if (err != NULL) { - error_free(err); - return -1; - } - - return 0; -} - -static uint32_t m48txx_isa_read(Nvram *obj, uint32_t addr) -{ - M48txxISAState *d = M48TXX_ISA(obj); - return m48t59_read(&d->state, addr); -} - -static void m48txx_isa_write(Nvram *obj, uint32_t addr, uint32_t val) -{ - M48txxISAState *d = M48TXX_ISA(obj); - m48t59_write(&d->state, addr, val); -} - -static void m48txx_isa_toggle_lock(Nvram *obj, int lock) -{ - M48txxISAState *d = M48TXX_ISA(obj); - m48t59_toggle_lock(&d->state, lock); -} - -static Property m48t59_isa_properties[] = { - DEFINE_PROP_INT32("base-year", M48txxISAState, state.base_year, 0), - DEFINE_PROP_UINT32("iobase", M48txxISAState, io_base, 0x74), - DEFINE_PROP_END_OF_LIST(), -}; - -static void m48txx_isa_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - NvramClass *nc = NVRAM_CLASS(klass); - - dc->realize = m48t59_isa_realize; - dc->reset = m48t59_reset_isa; - dc->props = m48t59_isa_properties; - nc->read = m48txx_isa_read; - nc->write = m48txx_isa_write; - nc->toggle_lock = m48txx_isa_toggle_lock; -} - -static void m48txx_isa_concrete_class_init(ObjectClass *klass, void *data) -{ - M48txxISADeviceClass *u = M48TXX_ISA_CLASS(klass); - M48txxInfo *info = data; - - u->info = *info; -} - -static uint32_t m48txx_sysbus_read(Nvram *obj, uint32_t addr) -{ - M48txxSysBusState *d = M48TXX_SYS_BUS(obj); - return m48t59_read(&d->state, addr); -} - -static void m48txx_sysbus_write(Nvram *obj, uint32_t addr, uint32_t val) -{ - M48txxSysBusState *d = M48TXX_SYS_BUS(obj); - m48t59_write(&d->state, addr, val); -} - -static void m48txx_sysbus_toggle_lock(Nvram *obj, int lock) -{ - M48txxSysBusState *d = M48TXX_SYS_BUS(obj); - m48t59_toggle_lock(&d->state, lock); -} - -static Property m48t59_sysbus_properties[] = { - DEFINE_PROP_INT32("base-year", M48txxSysBusState, state.base_year, 0), - DEFINE_PROP_END_OF_LIST(), -}; - -static void m48txx_sysbus_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); - NvramClass *nc = NVRAM_CLASS(klass); - - k->init = m48t59_init1; - dc->reset = m48t59_reset_sysbus; - dc->props = m48t59_sysbus_properties; - nc->read = m48txx_sysbus_read; - nc->write = m48txx_sysbus_write; - nc->toggle_lock = m48txx_sysbus_toggle_lock; -} - -static void m48txx_sysbus_concrete_class_init(ObjectClass *klass, void *data) -{ - M48txxSysBusDeviceClass *u = M48TXX_SYS_BUS_CLASS(klass); - M48txxInfo *info = data; - - u->info = *info; -} - -static const TypeInfo nvram_info = { - .name = TYPE_NVRAM, - .parent = TYPE_INTERFACE, - .class_size = sizeof(NvramClass), -}; - -static const TypeInfo m48txx_sysbus_type_info = { - .name = TYPE_M48TXX_SYS_BUS, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(M48txxSysBusState), - .abstract = true, - .class_init = m48txx_sysbus_class_init, - .interfaces = (InterfaceInfo[]) { - { TYPE_NVRAM }, - { } - } -}; - -static const TypeInfo m48txx_isa_type_info = { - .name = TYPE_M48TXX_ISA, - .parent = TYPE_ISA_DEVICE, - .instance_size = sizeof(M48txxISAState), - .abstract = true, - .class_init = m48txx_isa_class_init, - .interfaces = (InterfaceInfo[]) { - { TYPE_NVRAM }, - { } - } -}; - -static void m48t59_register_types(void) -{ - TypeInfo sysbus_type_info = { - .parent = TYPE_M48TXX_SYS_BUS, - .class_size = sizeof(M48txxSysBusDeviceClass), - .class_init = m48txx_sysbus_concrete_class_init, - }; - TypeInfo isa_type_info = { - .parent = TYPE_M48TXX_ISA, - .class_size = sizeof(M48txxISADeviceClass), - .class_init = m48txx_isa_concrete_class_init, - }; - int i; - - type_register_static(&nvram_info); - type_register_static(&m48txx_sysbus_type_info); - type_register_static(&m48txx_isa_type_info); - - for (i = 0; i < ARRAY_SIZE(m48txx_info); i++) { - if (m48txx_info[i].sysbus_name) { - sysbus_type_info.name = m48txx_info[i].sysbus_name; - sysbus_type_info.class_data = &m48txx_info[i]; - type_register(&sysbus_type_info); - } - - if (m48txx_info[i].isa_name) { - isa_type_info.name = m48txx_info[i].isa_name; - isa_type_info.class_data = &m48txx_info[i]; - type_register(&isa_type_info); - } - } -} - -type_init(m48t59_register_types) diff --git a/qemu/hw/timer/mc146818rtc.c b/qemu/hw/timer/mc146818rtc.c deleted file mode 100644 index 2ac0fd3e4..000000000 --- a/qemu/hw/timer/mc146818rtc.c +++ /dev/null @@ -1,971 +0,0 @@ -/* - * QEMU MC146818 RTC emulation - * - * Copyright (c) 2003-2004 Fabrice Bellard - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include "qemu/osdep.h" -#include "config-target.h" -#include "qemu/cutils.h" -#include "qemu/bcd.h" -#include "hw/hw.h" -#include "qemu/timer.h" -#include "sysemu/sysemu.h" -#include "hw/timer/mc146818rtc.h" -#include "qapi/visitor.h" -#include "qapi-event.h" -#include "qmp-commands.h" - -#ifdef TARGET_I386 -#include "hw/i386/apic.h" -#endif - -//#define DEBUG_CMOS -//#define DEBUG_COALESCED - -#ifdef DEBUG_CMOS -# define CMOS_DPRINTF(format, ...) printf(format, ## __VA_ARGS__) -#else -# define CMOS_DPRINTF(format, ...) do { } while (0) -#endif - -#ifdef DEBUG_COALESCED -# define DPRINTF_C(format, ...) printf(format, ## __VA_ARGS__) -#else -# define DPRINTF_C(format, ...) do { } while (0) -#endif - -#define SEC_PER_MIN 60 -#define MIN_PER_HOUR 60 -#define SEC_PER_HOUR 3600 -#define HOUR_PER_DAY 24 -#define SEC_PER_DAY 86400 - -#define RTC_REINJECT_ON_ACK_COUNT 20 -#define RTC_CLOCK_RATE 32768 -#define UIP_HOLD_LENGTH (8 * NANOSECONDS_PER_SECOND / 32768) - -#define MC146818_RTC(obj) OBJECT_CHECK(RTCState, (obj), TYPE_MC146818_RTC) - -typedef struct RTCState { - ISADevice parent_obj; - - MemoryRegion io; - uint8_t cmos_data[128]; - uint8_t cmos_index; - int32_t base_year; - uint64_t base_rtc; - uint64_t last_update; - int64_t offset; - qemu_irq irq; - int it_shift; - /* periodic timer */ - QEMUTimer *periodic_timer; - int64_t next_periodic_time; - /* update-ended timer */ - QEMUTimer *update_timer; - uint64_t next_alarm_time; - uint16_t irq_reinject_on_ack_count; - uint32_t irq_coalesced; - uint32_t period; - QEMUTimer *coalesced_timer; - Notifier clock_reset_notifier; - LostTickPolicy lost_tick_policy; - Notifier suspend_notifier; - QLIST_ENTRY(RTCState) link; -} RTCState; - -static void rtc_set_time(RTCState *s); -static void rtc_update_time(RTCState *s); -static void rtc_set_cmos(RTCState *s, const struct tm *tm); -static inline int rtc_from_bcd(RTCState *s, int a); -static uint64_t get_next_alarm(RTCState *s); - -static inline bool rtc_running(RTCState *s) -{ - return (!(s->cmos_data[RTC_REG_B] & REG_B_SET) && - (s->cmos_data[RTC_REG_A] & 0x70) <= 0x20); -} - -static uint64_t get_guest_rtc_ns(RTCState *s) -{ - uint64_t guest_rtc; - uint64_t guest_clock = qemu_clock_get_ns(rtc_clock); - - guest_rtc = s->base_rtc * NANOSECONDS_PER_SECOND + - guest_clock - s->last_update + s->offset; - return guest_rtc; -} - -#ifdef TARGET_I386 -static void rtc_coalesced_timer_update(RTCState *s) -{ - if (s->irq_coalesced == 0) { - timer_del(s->coalesced_timer); - } else { - /* divide each RTC interval to 2 - 8 smaller intervals */ - int c = MIN(s->irq_coalesced, 7) + 1; - int64_t next_clock = qemu_clock_get_ns(rtc_clock) + - muldiv64(s->period / c, NANOSECONDS_PER_SECOND, RTC_CLOCK_RATE); - timer_mod(s->coalesced_timer, next_clock); - } -} - -static void rtc_coalesced_timer(void *opaque) -{ - RTCState *s = opaque; - - if (s->irq_coalesced != 0) { - apic_reset_irq_delivered(); - s->cmos_data[RTC_REG_C] |= 0xc0; - DPRINTF_C("cmos: injecting from timer\n"); - qemu_irq_raise(s->irq); - if (apic_get_irq_delivered()) { - s->irq_coalesced--; - DPRINTF_C("cmos: coalesced irqs decreased to %d\n", - s->irq_coalesced); - } - } - - rtc_coalesced_timer_update(s); -} -#endif - -/* handle periodic timer */ -static void periodic_timer_update(RTCState *s, int64_t current_time) -{ - int period_code, period; - int64_t cur_clock, next_irq_clock; - - period_code = s->cmos_data[RTC_REG_A] & 0x0f; - if (period_code != 0 - && (s->cmos_data[RTC_REG_B] & REG_B_PIE)) { - if (period_code <= 2) - period_code += 7; - /* period in 32 Khz cycles */ - period = 1 << (period_code - 1); -#ifdef TARGET_I386 - if (period != s->period) { - s->irq_coalesced = (s->irq_coalesced * s->period) / period; - DPRINTF_C("cmos: coalesced irqs scaled to %d\n", s->irq_coalesced); - } - s->period = period; -#endif - /* compute 32 khz clock */ - cur_clock = - muldiv64(current_time, RTC_CLOCK_RATE, NANOSECONDS_PER_SECOND); - - next_irq_clock = (cur_clock & ~(period - 1)) + period; - s->next_periodic_time = muldiv64(next_irq_clock, NANOSECONDS_PER_SECOND, - RTC_CLOCK_RATE) + 1; - timer_mod(s->periodic_timer, s->next_periodic_time); - } else { -#ifdef TARGET_I386 - s->irq_coalesced = 0; -#endif - timer_del(s->periodic_timer); - } -} - -static void rtc_periodic_timer(void *opaque) -{ - RTCState *s = opaque; - - periodic_timer_update(s, s->next_periodic_time); - s->cmos_data[RTC_REG_C] |= REG_C_PF; - if (s->cmos_data[RTC_REG_B] & REG_B_PIE) { - s->cmos_data[RTC_REG_C] |= REG_C_IRQF; -#ifdef TARGET_I386 - if (s->lost_tick_policy == LOST_TICK_POLICY_SLEW) { - if (s->irq_reinject_on_ack_count >= RTC_REINJECT_ON_ACK_COUNT) - s->irq_reinject_on_ack_count = 0; - apic_reset_irq_delivered(); - qemu_irq_raise(s->irq); - if (!apic_get_irq_delivered()) { - s->irq_coalesced++; - rtc_coalesced_timer_update(s); - DPRINTF_C("cmos: coalesced irqs increased to %d\n", - s->irq_coalesced); - } - } else -#endif - qemu_irq_raise(s->irq); - } -} - -/* handle update-ended timer */ -static void check_update_timer(RTCState *s) -{ - uint64_t next_update_time; - uint64_t guest_nsec; - int next_alarm_sec; - - /* From the data sheet: "Holding the dividers in reset prevents - * interrupts from operating, while setting the SET bit allows" - * them to occur. However, it will prevent an alarm interrupt - * from occurring, because the time of day is not updated. - */ - if ((s->cmos_data[RTC_REG_A] & 0x60) == 0x60) { - timer_del(s->update_timer); - return; - } - if ((s->cmos_data[RTC_REG_C] & REG_C_UF) && - (s->cmos_data[RTC_REG_B] & REG_B_SET)) { - timer_del(s->update_timer); - return; - } - if ((s->cmos_data[RTC_REG_C] & REG_C_UF) && - (s->cmos_data[RTC_REG_C] & REG_C_AF)) { - timer_del(s->update_timer); - return; - } - - guest_nsec = get_guest_rtc_ns(s) % NANOSECONDS_PER_SECOND; - /* if UF is clear, reprogram to next second */ - next_update_time = qemu_clock_get_ns(rtc_clock) - + NANOSECONDS_PER_SECOND - guest_nsec; - - /* Compute time of next alarm. One second is already accounted - * for in next_update_time. - */ - next_alarm_sec = get_next_alarm(s); - s->next_alarm_time = next_update_time + - (next_alarm_sec - 1) * NANOSECONDS_PER_SECOND; - - if (s->cmos_data[RTC_REG_C] & REG_C_UF) { - /* UF is set, but AF is clear. Program the timer to target - * the alarm time. */ - next_update_time = s->next_alarm_time; - } - if (next_update_time != timer_expire_time_ns(s->update_timer)) { - timer_mod(s->update_timer, next_update_time); - } -} - -static inline uint8_t convert_hour(RTCState *s, uint8_t hour) -{ - if (!(s->cmos_data[RTC_REG_B] & REG_B_24H)) { - hour %= 12; - if (s->cmos_data[RTC_HOURS] & 0x80) { - hour += 12; - } - } - return hour; -} - -static uint64_t get_next_alarm(RTCState *s) -{ - int32_t alarm_sec, alarm_min, alarm_hour, cur_hour, cur_min, cur_sec; - int32_t hour, min, sec; - - rtc_update_time(s); - - alarm_sec = rtc_from_bcd(s, s->cmos_data[RTC_SECONDS_ALARM]); - alarm_min = rtc_from_bcd(s, s->cmos_data[RTC_MINUTES_ALARM]); - alarm_hour = rtc_from_bcd(s, s->cmos_data[RTC_HOURS_ALARM]); - alarm_hour = alarm_hour == -1 ? -1 : convert_hour(s, alarm_hour); - - cur_sec = rtc_from_bcd(s, s->cmos_data[RTC_SECONDS]); - cur_min = rtc_from_bcd(s, s->cmos_data[RTC_MINUTES]); - cur_hour = rtc_from_bcd(s, s->cmos_data[RTC_HOURS]); - cur_hour = convert_hour(s, cur_hour); - - if (alarm_hour == -1) { - alarm_hour = cur_hour; - if (alarm_min == -1) { - alarm_min = cur_min; - if (alarm_sec == -1) { - alarm_sec = cur_sec + 1; - } else if (cur_sec > alarm_sec) { - alarm_min++; - } - } else if (cur_min == alarm_min) { - if (alarm_sec == -1) { - alarm_sec = cur_sec + 1; - } else { - if (cur_sec > alarm_sec) { - alarm_hour++; - } - } - if (alarm_sec == SEC_PER_MIN) { - /* wrap to next hour, minutes is not in don't care mode */ - alarm_sec = 0; - alarm_hour++; - } - } else if (cur_min > alarm_min) { - alarm_hour++; - } - } else if (cur_hour == alarm_hour) { - if (alarm_min == -1) { - alarm_min = cur_min; - if (alarm_sec == -1) { - alarm_sec = cur_sec + 1; - } else if (cur_sec > alarm_sec) { - alarm_min++; - } - - if (alarm_sec == SEC_PER_MIN) { - alarm_sec = 0; - alarm_min++; - } - /* wrap to next day, hour is not in don't care mode */ - alarm_min %= MIN_PER_HOUR; - } else if (cur_min == alarm_min) { - if (alarm_sec == -1) { - alarm_sec = cur_sec + 1; - } - /* wrap to next day, hours+minutes not in don't care mode */ - alarm_sec %= SEC_PER_MIN; - } - } - - /* values that are still don't care fire at the next min/sec */ - if (alarm_min == -1) { - alarm_min = 0; - } - if (alarm_sec == -1) { - alarm_sec = 0; - } - - /* keep values in range */ - if (alarm_sec == SEC_PER_MIN) { - alarm_sec = 0; - alarm_min++; - } - if (alarm_min == MIN_PER_HOUR) { - alarm_min = 0; - alarm_hour++; - } - alarm_hour %= HOUR_PER_DAY; - - hour = alarm_hour - cur_hour; - min = hour * MIN_PER_HOUR + alarm_min - cur_min; - sec = min * SEC_PER_MIN + alarm_sec - cur_sec; - return sec <= 0 ? sec + SEC_PER_DAY : sec; -} - -static void rtc_update_timer(void *opaque) -{ - RTCState *s = opaque; - int32_t irqs = REG_C_UF; - int32_t new_irqs; - - assert((s->cmos_data[RTC_REG_A] & 0x60) != 0x60); - - /* UIP might have been latched, update time and clear it. */ - rtc_update_time(s); - s->cmos_data[RTC_REG_A] &= ~REG_A_UIP; - - if (qemu_clock_get_ns(rtc_clock) >= s->next_alarm_time) { - irqs |= REG_C_AF; - if (s->cmos_data[RTC_REG_B] & REG_B_AIE) { - qemu_system_wakeup_request(QEMU_WAKEUP_REASON_RTC); - } - } - - new_irqs = irqs & ~s->cmos_data[RTC_REG_C]; - s->cmos_data[RTC_REG_C] |= irqs; - if ((new_irqs & s->cmos_data[RTC_REG_B]) != 0) { - s->cmos_data[RTC_REG_C] |= REG_C_IRQF; - qemu_irq_raise(s->irq); - } - check_update_timer(s); -} - -static void cmos_ioport_write(void *opaque, hwaddr addr, - uint64_t data, unsigned size) -{ - RTCState *s = opaque; - - if ((addr & 1) == 0) { - s->cmos_index = data & 0x7f; - } else { - CMOS_DPRINTF("cmos: write index=0x%02x val=0x%02" PRIx64 "\n", - s->cmos_index, data); - switch(s->cmos_index) { - case RTC_SECONDS_ALARM: - case RTC_MINUTES_ALARM: - case RTC_HOURS_ALARM: - s->cmos_data[s->cmos_index] = data; - check_update_timer(s); - break; - case RTC_IBM_PS2_CENTURY_BYTE: - s->cmos_index = RTC_CENTURY; - /* fall through */ - case RTC_CENTURY: - case RTC_SECONDS: - case RTC_MINUTES: - case RTC_HOURS: - case RTC_DAY_OF_WEEK: - case RTC_DAY_OF_MONTH: - case RTC_MONTH: - case RTC_YEAR: - s->cmos_data[s->cmos_index] = data; - /* if in set mode, do not update the time */ - if (rtc_running(s)) { - rtc_set_time(s); - check_update_timer(s); - } - break; - case RTC_REG_A: - if ((data & 0x60) == 0x60) { - if (rtc_running(s)) { - rtc_update_time(s); - } - /* What happens to UIP when divider reset is enabled is - * unclear from the datasheet. Shouldn't matter much - * though. - */ - s->cmos_data[RTC_REG_A] &= ~REG_A_UIP; - } else if (((s->cmos_data[RTC_REG_A] & 0x60) == 0x60) && - (data & 0x70) <= 0x20) { - /* when the divider reset is removed, the first update cycle - * begins one-half second later*/ - if (!(s->cmos_data[RTC_REG_B] & REG_B_SET)) { - s->offset = 500000000; - rtc_set_time(s); - } - s->cmos_data[RTC_REG_A] &= ~REG_A_UIP; - } - /* UIP bit is read only */ - s->cmos_data[RTC_REG_A] = (data & ~REG_A_UIP) | - (s->cmos_data[RTC_REG_A] & REG_A_UIP); - periodic_timer_update(s, qemu_clock_get_ns(rtc_clock)); - check_update_timer(s); - break; - case RTC_REG_B: - if (data & REG_B_SET) { - /* update cmos to when the rtc was stopping */ - if (rtc_running(s)) { - rtc_update_time(s); - } - /* set mode: reset UIP mode */ - s->cmos_data[RTC_REG_A] &= ~REG_A_UIP; - data &= ~REG_B_UIE; - } else { - /* if disabling set mode, update the time */ - if ((s->cmos_data[RTC_REG_B] & REG_B_SET) && - (s->cmos_data[RTC_REG_A] & 0x70) <= 0x20) { - s->offset = get_guest_rtc_ns(s) % NANOSECONDS_PER_SECOND; - rtc_set_time(s); - } - } - /* if an interrupt flag is already set when the interrupt - * becomes enabled, raise an interrupt immediately. */ - if (data & s->cmos_data[RTC_REG_C] & REG_C_MASK) { - s->cmos_data[RTC_REG_C] |= REG_C_IRQF; - qemu_irq_raise(s->irq); - } else { - s->cmos_data[RTC_REG_C] &= ~REG_C_IRQF; - qemu_irq_lower(s->irq); - } - s->cmos_data[RTC_REG_B] = data; - periodic_timer_update(s, qemu_clock_get_ns(rtc_clock)); - check_update_timer(s); - break; - case RTC_REG_C: - case RTC_REG_D: - /* cannot write to them */ - break; - default: - s->cmos_data[s->cmos_index] = data; - break; - } - } -} - -static inline int rtc_to_bcd(RTCState *s, int a) -{ - if (s->cmos_data[RTC_REG_B] & REG_B_DM) { - return a; - } else { - return ((a / 10) << 4) | (a % 10); - } -} - -static inline int rtc_from_bcd(RTCState *s, int a) -{ - if ((a & 0xc0) == 0xc0) { - return -1; - } - if (s->cmos_data[RTC_REG_B] & REG_B_DM) { - return a; - } else { - return ((a >> 4) * 10) + (a & 0x0f); - } -} - -static void rtc_get_time(RTCState *s, struct tm *tm) -{ - tm->tm_sec = rtc_from_bcd(s, s->cmos_data[RTC_SECONDS]); - tm->tm_min = rtc_from_bcd(s, s->cmos_data[RTC_MINUTES]); - tm->tm_hour = rtc_from_bcd(s, s->cmos_data[RTC_HOURS] & 0x7f); - if (!(s->cmos_data[RTC_REG_B] & REG_B_24H)) { - tm->tm_hour %= 12; - if (s->cmos_data[RTC_HOURS] & 0x80) { - tm->tm_hour += 12; - } - } - tm->tm_wday = rtc_from_bcd(s, s->cmos_data[RTC_DAY_OF_WEEK]) - 1; - tm->tm_mday = rtc_from_bcd(s, s->cmos_data[RTC_DAY_OF_MONTH]); - tm->tm_mon = rtc_from_bcd(s, s->cmos_data[RTC_MONTH]) - 1; - tm->tm_year = - rtc_from_bcd(s, s->cmos_data[RTC_YEAR]) + s->base_year + - rtc_from_bcd(s, s->cmos_data[RTC_CENTURY]) * 100 - 1900; -} - -static QLIST_HEAD(, RTCState) rtc_devices = - QLIST_HEAD_INITIALIZER(rtc_devices); - -#ifdef TARGET_I386 -void qmp_rtc_reset_reinjection(Error **errp) -{ - RTCState *s; - - QLIST_FOREACH(s, &rtc_devices, link) { - s->irq_coalesced = 0; - } -} -#endif - -static void rtc_set_time(RTCState *s) -{ - struct tm tm; - - rtc_get_time(s, &tm); - s->base_rtc = mktimegm(&tm); - s->last_update = qemu_clock_get_ns(rtc_clock); - - qapi_event_send_rtc_change(qemu_timedate_diff(&tm), &error_abort); -} - -static void rtc_set_cmos(RTCState *s, const struct tm *tm) -{ - int year; - - s->cmos_data[RTC_SECONDS] = rtc_to_bcd(s, tm->tm_sec); - s->cmos_data[RTC_MINUTES] = rtc_to_bcd(s, tm->tm_min); - if (s->cmos_data[RTC_REG_B] & REG_B_24H) { - /* 24 hour format */ - s->cmos_data[RTC_HOURS] = rtc_to_bcd(s, tm->tm_hour); - } else { - /* 12 hour format */ - int h = (tm->tm_hour % 12) ? tm->tm_hour % 12 : 12; - s->cmos_data[RTC_HOURS] = rtc_to_bcd(s, h); - if (tm->tm_hour >= 12) - s->cmos_data[RTC_HOURS] |= 0x80; - } - s->cmos_data[RTC_DAY_OF_WEEK] = rtc_to_bcd(s, tm->tm_wday + 1); - s->cmos_data[RTC_DAY_OF_MONTH] = rtc_to_bcd(s, tm->tm_mday); - s->cmos_data[RTC_MONTH] = rtc_to_bcd(s, tm->tm_mon + 1); - year = tm->tm_year + 1900 - s->base_year; - s->cmos_data[RTC_YEAR] = rtc_to_bcd(s, year % 100); - s->cmos_data[RTC_CENTURY] = rtc_to_bcd(s, year / 100); -} - -static void rtc_update_time(RTCState *s) -{ - struct tm ret; - time_t guest_sec; - int64_t guest_nsec; - - guest_nsec = get_guest_rtc_ns(s); - guest_sec = guest_nsec / NANOSECONDS_PER_SECOND; - gmtime_r(&guest_sec, &ret); - - /* Is SET flag of Register B disabled? */ - if ((s->cmos_data[RTC_REG_B] & REG_B_SET) == 0) { - rtc_set_cmos(s, &ret); - } -} - -static int update_in_progress(RTCState *s) -{ - int64_t guest_nsec; - - if (!rtc_running(s)) { - return 0; - } - if (timer_pending(s->update_timer)) { - int64_t next_update_time = timer_expire_time_ns(s->update_timer); - /* Latch UIP until the timer expires. */ - if (qemu_clock_get_ns(rtc_clock) >= - (next_update_time - UIP_HOLD_LENGTH)) { - s->cmos_data[RTC_REG_A] |= REG_A_UIP; - return 1; - } - } - - guest_nsec = get_guest_rtc_ns(s); - /* UIP bit will be set at last 244us of every second. */ - if ((guest_nsec % NANOSECONDS_PER_SECOND) >= - (NANOSECONDS_PER_SECOND - UIP_HOLD_LENGTH)) { - return 1; - } - return 0; -} - -static uint64_t cmos_ioport_read(void *opaque, hwaddr addr, - unsigned size) -{ - RTCState *s = opaque; - int ret; - if ((addr & 1) == 0) { - return 0xff; - } else { - switch(s->cmos_index) { - case RTC_IBM_PS2_CENTURY_BYTE: - s->cmos_index = RTC_CENTURY; - /* fall through */ - case RTC_CENTURY: - case RTC_SECONDS: - case RTC_MINUTES: - case RTC_HOURS: - case RTC_DAY_OF_WEEK: - case RTC_DAY_OF_MONTH: - case RTC_MONTH: - case RTC_YEAR: - /* if not in set mode, calibrate cmos before - * reading*/ - if (rtc_running(s)) { - rtc_update_time(s); - } - ret = s->cmos_data[s->cmos_index]; - break; - case RTC_REG_A: - if (update_in_progress(s)) { - s->cmos_data[s->cmos_index] |= REG_A_UIP; - } else { - s->cmos_data[s->cmos_index] &= ~REG_A_UIP; - } - ret = s->cmos_data[s->cmos_index]; - break; - case RTC_REG_C: - ret = s->cmos_data[s->cmos_index]; - qemu_irq_lower(s->irq); - s->cmos_data[RTC_REG_C] = 0x00; - if (ret & (REG_C_UF | REG_C_AF)) { - check_update_timer(s); - } -#ifdef TARGET_I386 - if(s->irq_coalesced && - (s->cmos_data[RTC_REG_B] & REG_B_PIE) && - s->irq_reinject_on_ack_count < RTC_REINJECT_ON_ACK_COUNT) { - s->irq_reinject_on_ack_count++; - s->cmos_data[RTC_REG_C] |= REG_C_IRQF | REG_C_PF; - apic_reset_irq_delivered(); - DPRINTF_C("cmos: injecting on ack\n"); - qemu_irq_raise(s->irq); - if (apic_get_irq_delivered()) { - s->irq_coalesced--; - DPRINTF_C("cmos: coalesced irqs decreased to %d\n", - s->irq_coalesced); - } - } -#endif - break; - default: - ret = s->cmos_data[s->cmos_index]; - break; - } - CMOS_DPRINTF("cmos: read index=0x%02x val=0x%02x\n", - s->cmos_index, ret); - return ret; - } -} - -void rtc_set_memory(ISADevice *dev, int addr, int val) -{ - RTCState *s = MC146818_RTC(dev); - if (addr >= 0 && addr <= 127) - s->cmos_data[addr] = val; -} - -int rtc_get_memory(ISADevice *dev, int addr) -{ - RTCState *s = MC146818_RTC(dev); - assert(addr >= 0 && addr <= 127); - return s->cmos_data[addr]; -} - -static void rtc_set_date_from_host(ISADevice *dev) -{ - RTCState *s = MC146818_RTC(dev); - struct tm tm; - - qemu_get_timedate(&tm, 0); - - s->base_rtc = mktimegm(&tm); - s->last_update = qemu_clock_get_ns(rtc_clock); - s->offset = 0; - - /* set the CMOS date */ - rtc_set_cmos(s, &tm); -} - -static int rtc_post_load(void *opaque, int version_id) -{ - RTCState *s = opaque; - - if (version_id <= 2) { - rtc_set_time(s); - s->offset = 0; - check_update_timer(s); - } - - uint64_t now = qemu_clock_get_ns(rtc_clock); - if (now < s->next_periodic_time || - now > (s->next_periodic_time + get_max_clock_jump())) { - periodic_timer_update(s, qemu_clock_get_ns(rtc_clock)); - } - -#ifdef TARGET_I386 - if (version_id >= 2) { - if (s->lost_tick_policy == LOST_TICK_POLICY_SLEW) { - rtc_coalesced_timer_update(s); - } - } -#endif - return 0; -} - -static bool rtc_irq_reinject_on_ack_count_needed(void *opaque) -{ - RTCState *s = (RTCState *)opaque; - return s->irq_reinject_on_ack_count != 0; -} - -static const VMStateDescription vmstate_rtc_irq_reinject_on_ack_count = { - .name = "mc146818rtc/irq_reinject_on_ack_count", - .version_id = 1, - .minimum_version_id = 1, - .needed = rtc_irq_reinject_on_ack_count_needed, - .fields = (VMStateField[]) { - VMSTATE_UINT16(irq_reinject_on_ack_count, RTCState), - VMSTATE_END_OF_LIST() - } -}; - -static const VMStateDescription vmstate_rtc = { - .name = "mc146818rtc", - .version_id = 3, - .minimum_version_id = 1, - .post_load = rtc_post_load, - .fields = (VMStateField[]) { - VMSTATE_BUFFER(cmos_data, RTCState), - VMSTATE_UINT8(cmos_index, RTCState), - VMSTATE_UNUSED(7*4), - VMSTATE_TIMER_PTR(periodic_timer, RTCState), - VMSTATE_INT64(next_periodic_time, RTCState), - VMSTATE_UNUSED(3*8), - VMSTATE_UINT32_V(irq_coalesced, RTCState, 2), - VMSTATE_UINT32_V(period, RTCState, 2), - VMSTATE_UINT64_V(base_rtc, RTCState, 3), - VMSTATE_UINT64_V(last_update, RTCState, 3), - VMSTATE_INT64_V(offset, RTCState, 3), - VMSTATE_TIMER_PTR_V(update_timer, RTCState, 3), - VMSTATE_UINT64_V(next_alarm_time, RTCState, 3), - VMSTATE_END_OF_LIST() - }, - .subsections = (const VMStateDescription*[]) { - &vmstate_rtc_irq_reinject_on_ack_count, - NULL - } -}; - -static void rtc_notify_clock_reset(Notifier *notifier, void *data) -{ - RTCState *s = container_of(notifier, RTCState, clock_reset_notifier); - int64_t now = *(int64_t *)data; - - rtc_set_date_from_host(ISA_DEVICE(s)); - periodic_timer_update(s, now); - check_update_timer(s); -#ifdef TARGET_I386 - if (s->lost_tick_policy == LOST_TICK_POLICY_SLEW) { - rtc_coalesced_timer_update(s); - } -#endif -} - -/* set CMOS shutdown status register (index 0xF) as S3_resume(0xFE) - BIOS will read it and start S3 resume at POST Entry */ -static void rtc_notify_suspend(Notifier *notifier, void *data) -{ - RTCState *s = container_of(notifier, RTCState, suspend_notifier); - rtc_set_memory(ISA_DEVICE(s), 0xF, 0xFE); -} - -static void rtc_reset(void *opaque) -{ - RTCState *s = opaque; - - s->cmos_data[RTC_REG_B] &= ~(REG_B_PIE | REG_B_AIE | REG_B_SQWE); - s->cmos_data[RTC_REG_C] &= ~(REG_C_UF | REG_C_IRQF | REG_C_PF | REG_C_AF); - check_update_timer(s); - - qemu_irq_lower(s->irq); - -#ifdef TARGET_I386 - if (s->lost_tick_policy == LOST_TICK_POLICY_SLEW) { - s->irq_coalesced = 0; - s->irq_reinject_on_ack_count = 0; - } -#endif -} - -static const MemoryRegionOps cmos_ops = { - .read = cmos_ioport_read, - .write = cmos_ioport_write, - .impl = { - .min_access_size = 1, - .max_access_size = 1, - }, - .endianness = DEVICE_LITTLE_ENDIAN, -}; - -static void rtc_get_date(Object *obj, struct tm *current_tm, Error **errp) -{ - RTCState *s = MC146818_RTC(obj); - - rtc_update_time(s); - rtc_get_time(s, current_tm); -} - -static void rtc_realizefn(DeviceState *dev, Error **errp) -{ - ISADevice *isadev = ISA_DEVICE(dev); - RTCState *s = MC146818_RTC(dev); - int base = 0x70; - - s->cmos_data[RTC_REG_A] = 0x26; - s->cmos_data[RTC_REG_B] = 0x02; - s->cmos_data[RTC_REG_C] = 0x00; - s->cmos_data[RTC_REG_D] = 0x80; - - /* This is for historical reasons. The default base year qdev property - * was set to 2000 for most machine types before the century byte was - * implemented. - * - * This if statement means that the century byte will be always 0 - * (at least until 2079...) for base_year = 1980, but will be set - * correctly for base_year = 2000. - */ - if (s->base_year == 2000) { - s->base_year = 0; - } - - rtc_set_date_from_host(isadev); - -#ifdef TARGET_I386 - switch (s->lost_tick_policy) { - case LOST_TICK_POLICY_SLEW: - s->coalesced_timer = - timer_new_ns(rtc_clock, rtc_coalesced_timer, s); - break; - case LOST_TICK_POLICY_DISCARD: - break; - default: - error_setg(errp, "Invalid lost tick policy."); - return; - } -#endif - - s->periodic_timer = timer_new_ns(rtc_clock, rtc_periodic_timer, s); - s->update_timer = timer_new_ns(rtc_clock, rtc_update_timer, s); - check_update_timer(s); - - s->clock_reset_notifier.notify = rtc_notify_clock_reset; - qemu_clock_register_reset_notifier(rtc_clock, - &s->clock_reset_notifier); - - s->suspend_notifier.notify = rtc_notify_suspend; - qemu_register_suspend_notifier(&s->suspend_notifier); - - memory_region_init_io(&s->io, OBJECT(s), &cmos_ops, s, "rtc", 2); - isa_register_ioport(isadev, &s->io, base); - - qdev_set_legacy_instance_id(dev, base, 3); - qemu_register_reset(rtc_reset, s); - - object_property_add_tm(OBJECT(s), "date", rtc_get_date, NULL); - - object_property_add_alias(qdev_get_machine(), "rtc-time", - OBJECT(s), "date", NULL); -} - -ISADevice *rtc_init(ISABus *bus, int base_year, qemu_irq intercept_irq) -{ - DeviceState *dev; - ISADevice *isadev; - RTCState *s; - - isadev = isa_create(bus, TYPE_MC146818_RTC); - dev = DEVICE(isadev); - s = MC146818_RTC(isadev); - qdev_prop_set_int32(dev, "base_year", base_year); - qdev_init_nofail(dev); - if (intercept_irq) { - s->irq = intercept_irq; - } else { - isa_init_irq(isadev, &s->irq, RTC_ISA_IRQ); - } - QLIST_INSERT_HEAD(&rtc_devices, s, link); - - return isadev; -} - -static Property mc146818rtc_properties[] = { - DEFINE_PROP_INT32("base_year", RTCState, base_year, 1980), - DEFINE_PROP_LOSTTICKPOLICY("lost_tick_policy", RTCState, - lost_tick_policy, LOST_TICK_POLICY_DISCARD), - DEFINE_PROP_END_OF_LIST(), -}; - -static void rtc_class_initfn(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - - dc->realize = rtc_realizefn; - dc->vmsd = &vmstate_rtc; - dc->props = mc146818rtc_properties; - /* Reason: needs to be wired up by rtc_init() */ - dc->cannot_instantiate_with_device_add_yet = true; -} - -static void rtc_finalize(Object *obj) -{ - object_property_del(qdev_get_machine(), "rtc", NULL); -} - -static const TypeInfo mc146818rtc_info = { - .name = TYPE_MC146818_RTC, - .parent = TYPE_ISA_DEVICE, - .instance_size = sizeof(RTCState), - .class_init = rtc_class_initfn, - .instance_finalize = rtc_finalize, -}; - -static void mc146818rtc_register_types(void) -{ - type_register_static(&mc146818rtc_info); -} - -type_init(mc146818rtc_register_types) diff --git a/qemu/hw/timer/milkymist-sysctl.c b/qemu/hw/timer/milkymist-sysctl.c deleted file mode 100644 index 5f2948037..000000000 --- a/qemu/hw/timer/milkymist-sysctl.c +++ /dev/null @@ -1,342 +0,0 @@ -/* - * QEMU model of the Milkymist System Controller. - * - * Copyright (c) 2010-2012 Michael Walle <michael@walle.cc> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see <http://www.gnu.org/licenses/>. - * - * - * Specification available at: - * http://www.milkymist.org/socdoc/sysctl.pdf - */ - -#include "qemu/osdep.h" -#include "hw/hw.h" -#include "hw/sysbus.h" -#include "sysemu/sysemu.h" -#include "trace.h" -#include "qemu/timer.h" -#include "hw/ptimer.h" -#include "qemu/error-report.h" - -enum { - CTRL_ENABLE = (1<<0), - CTRL_AUTORESTART = (1<<1), -}; - -enum { - ICAP_READY = (1<<0), -}; - -enum { - R_GPIO_IN = 0, - R_GPIO_OUT, - R_GPIO_INTEN, - R_TIMER0_CONTROL = 4, - R_TIMER0_COMPARE, - R_TIMER0_COUNTER, - R_TIMER1_CONTROL = 8, - R_TIMER1_COMPARE, - R_TIMER1_COUNTER, - R_ICAP = 16, - R_DBG_SCRATCHPAD = 20, - R_DBG_WRITE_LOCK, - R_CLK_FREQUENCY = 29, - R_CAPABILITIES, - R_SYSTEM_ID, - R_MAX -}; - -#define TYPE_MILKYMIST_SYSCTL "milkymist-sysctl" -#define MILKYMIST_SYSCTL(obj) \ - OBJECT_CHECK(MilkymistSysctlState, (obj), TYPE_MILKYMIST_SYSCTL) - -struct MilkymistSysctlState { - SysBusDevice parent_obj; - - MemoryRegion regs_region; - - QEMUBH *bh0; - QEMUBH *bh1; - ptimer_state *ptimer0; - ptimer_state *ptimer1; - - uint32_t freq_hz; - uint32_t capabilities; - uint32_t systemid; - uint32_t strappings; - - uint32_t regs[R_MAX]; - - qemu_irq gpio_irq; - qemu_irq timer0_irq; - qemu_irq timer1_irq; -}; -typedef struct MilkymistSysctlState MilkymistSysctlState; - -static void sysctl_icap_write(MilkymistSysctlState *s, uint32_t value) -{ - trace_milkymist_sysctl_icap_write(value); - switch (value & 0xffff) { - case 0x000e: - qemu_system_shutdown_request(); - break; - } -} - -static uint64_t sysctl_read(void *opaque, hwaddr addr, - unsigned size) -{ - MilkymistSysctlState *s = opaque; - uint32_t r = 0; - - addr >>= 2; - switch (addr) { - case R_TIMER0_COUNTER: - r = (uint32_t)ptimer_get_count(s->ptimer0); - /* milkymist timer counts up */ - r = s->regs[R_TIMER0_COMPARE] - r; - break; - case R_TIMER1_COUNTER: - r = (uint32_t)ptimer_get_count(s->ptimer1); - /* milkymist timer counts up */ - r = s->regs[R_TIMER1_COMPARE] - r; - break; - case R_GPIO_IN: - case R_GPIO_OUT: - case R_GPIO_INTEN: - case R_TIMER0_CONTROL: - case R_TIMER0_COMPARE: - case R_TIMER1_CONTROL: - case R_TIMER1_COMPARE: - case R_ICAP: - case R_DBG_SCRATCHPAD: - case R_DBG_WRITE_LOCK: - case R_CLK_FREQUENCY: - case R_CAPABILITIES: - case R_SYSTEM_ID: - r = s->regs[addr]; - break; - - default: - error_report("milkymist_sysctl: read access to unknown register 0x" - TARGET_FMT_plx, addr << 2); - break; - } - - trace_milkymist_sysctl_memory_read(addr << 2, r); - - return r; -} - -static void sysctl_write(void *opaque, hwaddr 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: - case R_DBG_SCRATCHPAD: - 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_DBG_WRITE_LOCK: - s->regs[addr] = 1; - break; - case R_SYSTEM_ID: - qemu_system_reset_request(); - break; - - case R_GPIO_IN: - case R_CLK_FREQUENCY: - 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 const MemoryRegionOps sysctl_mmio_ops = { - .read = sysctl_read, - .write = sysctl_write, - .valid = { - .min_access_size = 4, - .max_access_size = 4, - }, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static void timer0_hit(void *opaque) -{ - MilkymistSysctlState *s = opaque; - - if (!(s->regs[R_TIMER0_CONTROL] & CTRL_AUTORESTART)) { - s->regs[R_TIMER0_CONTROL] &= ~CTRL_ENABLE; - trace_milkymist_sysctl_stop_timer0(); - ptimer_stop(s->ptimer0); - } - - trace_milkymist_sysctl_pulse_irq_timer0(); - qemu_irq_pulse(s->timer0_irq); -} - -static void timer1_hit(void *opaque) -{ - MilkymistSysctlState *s = opaque; - - if (!(s->regs[R_TIMER1_CONTROL] & CTRL_AUTORESTART)) { - s->regs[R_TIMER1_CONTROL] &= ~CTRL_ENABLE; - trace_milkymist_sysctl_stop_timer1(); - ptimer_stop(s->ptimer1); - } - - trace_milkymist_sysctl_pulse_irq_timer1(); - qemu_irq_pulse(s->timer1_irq); -} - -static void milkymist_sysctl_reset(DeviceState *d) -{ - MilkymistSysctlState *s = MILKYMIST_SYSCTL(d); - int i; - - for (i = 0; i < R_MAX; i++) { - s->regs[i] = 0; - } - - ptimer_stop(s->ptimer0); - ptimer_stop(s->ptimer1); - - /* defaults */ - s->regs[R_ICAP] = ICAP_READY; - s->regs[R_SYSTEM_ID] = s->systemid; - s->regs[R_CLK_FREQUENCY] = s->freq_hz; - s->regs[R_CAPABILITIES] = s->capabilities; - s->regs[R_GPIO_IN] = s->strappings; -} - -static int milkymist_sysctl_init(SysBusDevice *dev) -{ - MilkymistSysctlState *s = MILKYMIST_SYSCTL(dev); - - sysbus_init_irq(dev, &s->gpio_irq); - sysbus_init_irq(dev, &s->timer0_irq); - sysbus_init_irq(dev, &s->timer1_irq); - - s->bh0 = qemu_bh_new(timer0_hit, s); - s->bh1 = qemu_bh_new(timer1_hit, s); - s->ptimer0 = ptimer_init(s->bh0); - s->ptimer1 = ptimer_init(s->bh1); - ptimer_set_freq(s->ptimer0, s->freq_hz); - ptimer_set_freq(s->ptimer1, s->freq_hz); - - memory_region_init_io(&s->regs_region, OBJECT(s), &sysctl_mmio_ops, s, - "milkymist-sysctl", R_MAX * 4); - sysbus_init_mmio(dev, &s->regs_region); - - return 0; -} - -static const VMStateDescription vmstate_milkymist_sysctl = { - .name = "milkymist-sysctl", - .version_id = 1, - .minimum_version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_UINT32_ARRAY(regs, MilkymistSysctlState, R_MAX), - VMSTATE_PTIMER(ptimer0, MilkymistSysctlState), - VMSTATE_PTIMER(ptimer1, MilkymistSysctlState), - VMSTATE_END_OF_LIST() - } -}; - -static Property milkymist_sysctl_properties[] = { - DEFINE_PROP_UINT32("frequency", MilkymistSysctlState, - freq_hz, 80000000), - DEFINE_PROP_UINT32("capabilities", MilkymistSysctlState, - capabilities, 0x00000000), - DEFINE_PROP_UINT32("systemid", MilkymistSysctlState, - systemid, 0x10014d31), - DEFINE_PROP_UINT32("gpio_strappings", MilkymistSysctlState, - strappings, 0x00000001), - DEFINE_PROP_END_OF_LIST(), -}; - -static void milkymist_sysctl_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); - - k->init = milkymist_sysctl_init; - dc->reset = milkymist_sysctl_reset; - dc->vmsd = &vmstate_milkymist_sysctl; - dc->props = milkymist_sysctl_properties; -} - -static const TypeInfo milkymist_sysctl_info = { - .name = TYPE_MILKYMIST_SYSCTL, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(MilkymistSysctlState), - .class_init = milkymist_sysctl_class_init, -}; - -static void milkymist_sysctl_register_types(void) -{ - type_register_static(&milkymist_sysctl_info); -} - -type_init(milkymist_sysctl_register_types) diff --git a/qemu/hw/timer/omap_gptimer.c b/qemu/hw/timer/omap_gptimer.c deleted file mode 100644 index 3a4386304..000000000 --- a/qemu/hw/timer/omap_gptimer.c +++ /dev/null @@ -1,488 +0,0 @@ -/* - * TI OMAP2 general purpose timers emulation. - * - * Copyright (C) 2007-2008 Nokia Corporation - * Written by Andrzej Zaborowski <andrew@openedhand.com> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 or - * (at your option) any later version of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, see <http://www.gnu.org/licenses/>. - */ -#include "qemu/osdep.h" -#include "hw/hw.h" -#include "qemu/timer.h" -#include "hw/arm/omap.h" - -/* GP timers */ -struct omap_gp_timer_s { - MemoryRegion iomem; - qemu_irq irq; - qemu_irq wkup; - qemu_irq in; - qemu_irq out; - omap_clk clk; - QEMUTimer *timer; - QEMUTimer *match; - struct omap_target_agent_s *ta; - - int in_val; - int out_val; - int64_t time; - int64_t rate; - int64_t ticks_per_sec; - - int16_t config; - int status; - int it_ena; - int wu_ena; - int enable; - int inout; - int capt2; - int pt; - enum { - gpt_trigger_none, gpt_trigger_overflow, gpt_trigger_both - } trigger; - enum { - gpt_capture_none, gpt_capture_rising, - gpt_capture_falling, gpt_capture_both - } capture; - int scpwm; - int ce; - int pre; - int ptv; - int ar; - int st; - int posted; - uint32_t val; - uint32_t load_val; - uint32_t capture_val[2]; - uint32_t match_val; - int capt_num; - - uint16_t writeh; /* LSB */ - uint16_t readh; /* MSB */ -}; - -#define GPT_TCAR_IT (1 << 2) -#define GPT_OVF_IT (1 << 1) -#define GPT_MAT_IT (1 << 0) - -static inline void omap_gp_timer_intr(struct omap_gp_timer_s *timer, int it) -{ - if (timer->it_ena & it) { - if (!timer->status) - qemu_irq_raise(timer->irq); - - timer->status |= it; - /* Or are the status bits set even when masked? - * i.e. is masking applied before or after the status register? */ - } - - if (timer->wu_ena & it) - qemu_irq_pulse(timer->wkup); -} - -static inline void omap_gp_timer_out(struct omap_gp_timer_s *timer, int level) -{ - if (!timer->inout && timer->out_val != level) { - timer->out_val = level; - qemu_set_irq(timer->out, level); - } -} - -static inline uint32_t omap_gp_timer_read(struct omap_gp_timer_s *timer) -{ - uint64_t distance; - - if (timer->st && timer->rate) { - distance = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - timer->time; - distance = muldiv64(distance, timer->rate, timer->ticks_per_sec); - - if (distance >= 0xffffffff - timer->val) - return 0xffffffff; - else - return timer->val + distance; - } else - return timer->val; -} - -static inline void omap_gp_timer_sync(struct omap_gp_timer_s *timer) -{ - if (timer->st) { - timer->val = omap_gp_timer_read(timer); - timer->time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); - } -} - -static inline void omap_gp_timer_update(struct omap_gp_timer_s *timer) -{ - int64_t expires, matches; - - if (timer->st && timer->rate) { - expires = muldiv64(0x100000000ll - timer->val, - timer->ticks_per_sec, timer->rate); - timer_mod(timer->timer, timer->time + expires); - - if (timer->ce && timer->match_val >= timer->val) { - matches = muldiv64(timer->match_val - timer->val, - timer->ticks_per_sec, timer->rate); - timer_mod(timer->match, timer->time + matches); - } else - timer_del(timer->match); - } else { - timer_del(timer->timer); - timer_del(timer->match); - omap_gp_timer_out(timer, timer->scpwm); - } -} - -static inline void omap_gp_timer_trigger(struct omap_gp_timer_s *timer) -{ - if (timer->pt) - /* TODO in overflow-and-match mode if the first event to - * occur is the match, don't toggle. */ - omap_gp_timer_out(timer, !timer->out_val); - else - /* TODO inverted pulse on timer->out_val == 1? */ - qemu_irq_pulse(timer->out); -} - -static void omap_gp_timer_tick(void *opaque) -{ - struct omap_gp_timer_s *timer = (struct omap_gp_timer_s *) opaque; - - if (!timer->ar) { - timer->st = 0; - timer->val = 0; - } else { - timer->val = timer->load_val; - timer->time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); - } - - if (timer->trigger == gpt_trigger_overflow || - timer->trigger == gpt_trigger_both) - omap_gp_timer_trigger(timer); - - omap_gp_timer_intr(timer, GPT_OVF_IT); - omap_gp_timer_update(timer); -} - -static void omap_gp_timer_match(void *opaque) -{ - struct omap_gp_timer_s *timer = (struct omap_gp_timer_s *) opaque; - - if (timer->trigger == gpt_trigger_both) - omap_gp_timer_trigger(timer); - - omap_gp_timer_intr(timer, GPT_MAT_IT); -} - -static void omap_gp_timer_input(void *opaque, int line, int on) -{ - struct omap_gp_timer_s *s = (struct omap_gp_timer_s *) opaque; - int trigger; - - switch (s->capture) { - default: - case gpt_capture_none: - trigger = 0; - break; - case gpt_capture_rising: - trigger = !s->in_val && on; - break; - case gpt_capture_falling: - trigger = s->in_val && !on; - break; - case gpt_capture_both: - trigger = (s->in_val == !on); - break; - } - s->in_val = on; - - if (s->inout && trigger && s->capt_num < 2) { - s->capture_val[s->capt_num] = omap_gp_timer_read(s); - - if (s->capt2 == s->capt_num ++) - omap_gp_timer_intr(s, GPT_TCAR_IT); - } -} - -static void omap_gp_timer_clk_update(void *opaque, int line, int on) -{ - struct omap_gp_timer_s *timer = (struct omap_gp_timer_s *) opaque; - - omap_gp_timer_sync(timer); - timer->rate = on ? omap_clk_getrate(timer->clk) : 0; - omap_gp_timer_update(timer); -} - -static void omap_gp_timer_clk_setup(struct omap_gp_timer_s *timer) -{ - omap_clk_adduser(timer->clk, - qemu_allocate_irq(omap_gp_timer_clk_update, timer, 0)); - timer->rate = omap_clk_getrate(timer->clk); -} - -void omap_gp_timer_reset(struct omap_gp_timer_s *s) -{ - s->config = 0x000; - s->status = 0; - s->it_ena = 0; - s->wu_ena = 0; - s->inout = 0; - s->capt2 = 0; - s->capt_num = 0; - s->pt = 0; - s->trigger = gpt_trigger_none; - s->capture = gpt_capture_none; - s->scpwm = 0; - s->ce = 0; - s->pre = 0; - s->ptv = 0; - s->ar = 0; - s->st = 0; - s->posted = 1; - s->val = 0x00000000; - s->load_val = 0x00000000; - s->capture_val[0] = 0x00000000; - s->capture_val[1] = 0x00000000; - s->match_val = 0x00000000; - omap_gp_timer_update(s); -} - -static uint32_t omap_gp_timer_readw(void *opaque, hwaddr addr) -{ - struct omap_gp_timer_s *s = (struct omap_gp_timer_s *) opaque; - - switch (addr) { - case 0x00: /* TIDR */ - return 0x21; - - case 0x10: /* TIOCP_CFG */ - return s->config; - - case 0x14: /* TISTAT */ - /* ??? When's this bit reset? */ - return 1; /* RESETDONE */ - - case 0x18: /* TISR */ - return s->status; - - case 0x1c: /* TIER */ - return s->it_ena; - - case 0x20: /* TWER */ - return s->wu_ena; - - case 0x24: /* TCLR */ - return (s->inout << 14) | - (s->capt2 << 13) | - (s->pt << 12) | - (s->trigger << 10) | - (s->capture << 8) | - (s->scpwm << 7) | - (s->ce << 6) | - (s->pre << 5) | - (s->ptv << 2) | - (s->ar << 1) | - (s->st << 0); - - case 0x28: /* TCRR */ - return omap_gp_timer_read(s); - - case 0x2c: /* TLDR */ - return s->load_val; - - case 0x30: /* TTGR */ - return 0xffffffff; - - case 0x34: /* TWPS */ - return 0x00000000; /* No posted writes pending. */ - - case 0x38: /* TMAR */ - return s->match_val; - - case 0x3c: /* TCAR1 */ - return s->capture_val[0]; - - case 0x40: /* TSICR */ - return s->posted << 2; - - case 0x44: /* TCAR2 */ - return s->capture_val[1]; - } - - OMAP_BAD_REG(addr); - return 0; -} - -static uint32_t omap_gp_timer_readh(void *opaque, hwaddr addr) -{ - struct omap_gp_timer_s *s = (struct omap_gp_timer_s *) opaque; - uint32_t ret; - - if (addr & 2) - return s->readh; - else { - ret = omap_gp_timer_readw(opaque, addr); - s->readh = ret >> 16; - return ret & 0xffff; - } -} - -static void omap_gp_timer_write(void *opaque, hwaddr addr, - uint32_t value) -{ - struct omap_gp_timer_s *s = (struct omap_gp_timer_s *) opaque; - - switch (addr) { - case 0x00: /* TIDR */ - case 0x14: /* TISTAT */ - case 0x34: /* TWPS */ - case 0x3c: /* TCAR1 */ - case 0x44: /* TCAR2 */ - OMAP_RO_REG(addr); - break; - - case 0x10: /* TIOCP_CFG */ - s->config = value & 0x33d; - if (((value >> 3) & 3) == 3) /* IDLEMODE */ - fprintf(stderr, "%s: illegal IDLEMODE value in TIOCP_CFG\n", - __FUNCTION__); - if (value & 2) /* SOFTRESET */ - omap_gp_timer_reset(s); - break; - - case 0x18: /* TISR */ - if (value & GPT_TCAR_IT) - s->capt_num = 0; - if (s->status && !(s->status &= ~value)) - qemu_irq_lower(s->irq); - break; - - case 0x1c: /* TIER */ - s->it_ena = value & 7; - break; - - case 0x20: /* TWER */ - s->wu_ena = value & 7; - break; - - case 0x24: /* TCLR */ - omap_gp_timer_sync(s); - s->inout = (value >> 14) & 1; - s->capt2 = (value >> 13) & 1; - s->pt = (value >> 12) & 1; - s->trigger = (value >> 10) & 3; - if (s->capture == gpt_capture_none && - ((value >> 8) & 3) != gpt_capture_none) - s->capt_num = 0; - s->capture = (value >> 8) & 3; - s->scpwm = (value >> 7) & 1; - s->ce = (value >> 6) & 1; - s->pre = (value >> 5) & 1; - s->ptv = (value >> 2) & 7; - s->ar = (value >> 1) & 1; - s->st = (value >> 0) & 1; - if (s->inout && s->trigger != gpt_trigger_none) - fprintf(stderr, "%s: GP timer pin must be an output " - "for this trigger mode\n", __FUNCTION__); - if (!s->inout && s->capture != gpt_capture_none) - fprintf(stderr, "%s: GP timer pin must be an input " - "for this capture mode\n", __FUNCTION__); - if (s->trigger == gpt_trigger_none) - omap_gp_timer_out(s, s->scpwm); - /* TODO: make sure this doesn't overflow 32-bits */ - s->ticks_per_sec = NANOSECONDS_PER_SECOND << (s->pre ? s->ptv + 1 : 0); - omap_gp_timer_update(s); - break; - - case 0x28: /* TCRR */ - s->time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); - s->val = value; - omap_gp_timer_update(s); - break; - - case 0x2c: /* TLDR */ - s->load_val = value; - break; - - case 0x30: /* TTGR */ - s->time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); - s->val = s->load_val; - omap_gp_timer_update(s); - break; - - case 0x38: /* TMAR */ - omap_gp_timer_sync(s); - s->match_val = value; - omap_gp_timer_update(s); - break; - - case 0x40: /* TSICR */ - s->posted = (value >> 2) & 1; - if (value & 2) /* How much exactly are we supposed to reset? */ - omap_gp_timer_reset(s); - break; - - default: - OMAP_BAD_REG(addr); - } -} - -static void omap_gp_timer_writeh(void *opaque, hwaddr addr, - uint32_t value) -{ - struct omap_gp_timer_s *s = (struct omap_gp_timer_s *) opaque; - - if (addr & 2) - omap_gp_timer_write(opaque, addr, (value << 16) | s->writeh); - else - s->writeh = (uint16_t) value; -} - -static const MemoryRegionOps omap_gp_timer_ops = { - .old_mmio = { - .read = { - omap_badwidth_read32, - omap_gp_timer_readh, - omap_gp_timer_readw, - }, - .write = { - omap_badwidth_write32, - omap_gp_timer_writeh, - omap_gp_timer_write, - }, - }, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -struct omap_gp_timer_s *omap_gp_timer_init(struct omap_target_agent_s *ta, - qemu_irq irq, omap_clk fclk, omap_clk iclk) -{ - struct omap_gp_timer_s *s = g_new0(struct omap_gp_timer_s, 1); - - s->ta = ta; - s->irq = irq; - s->clk = fclk; - s->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, omap_gp_timer_tick, s); - s->match = timer_new_ns(QEMU_CLOCK_VIRTUAL, omap_gp_timer_match, s); - s->in = qemu_allocate_irq(omap_gp_timer_input, s, 0); - omap_gp_timer_reset(s); - omap_gp_timer_clk_setup(s); - - memory_region_init_io(&s->iomem, NULL, &omap_gp_timer_ops, s, "omap.gptimer", - omap_l4_region_size(ta, 0)); - omap_l4_attach(ta, 0, &s->iomem); - - return s; -} diff --git a/qemu/hw/timer/omap_synctimer.c b/qemu/hw/timer/omap_synctimer.c deleted file mode 100644 index 9ee651979..000000000 --- a/qemu/hw/timer/omap_synctimer.c +++ /dev/null @@ -1,104 +0,0 @@ -/* - * TI OMAP2 32kHz sync timer emulation. - * - * Copyright (C) 2007-2008 Nokia Corporation - * Written by Andrzej Zaborowski <andrew@openedhand.com> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 or - * (at your option) any later version of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, see <http://www.gnu.org/licenses/>. - */ -#include "qemu/osdep.h" -#include "hw/hw.h" -#include "qemu/timer.h" -#include "hw/arm/omap.h" -struct omap_synctimer_s { - MemoryRegion iomem; - uint32_t val; - uint16_t readh; -}; - -/* 32-kHz Sync Timer of the OMAP2 */ -static uint32_t omap_synctimer_read(struct omap_synctimer_s *s) { - return muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), 0x8000, - NANOSECONDS_PER_SECOND); -} - -void omap_synctimer_reset(struct omap_synctimer_s *s) -{ - s->val = omap_synctimer_read(s); -} - -static uint32_t omap_synctimer_readw(void *opaque, hwaddr addr) -{ - struct omap_synctimer_s *s = (struct omap_synctimer_s *) opaque; - - switch (addr) { - case 0x00: /* 32KSYNCNT_REV */ - return 0x21; - - case 0x10: /* CR */ - return omap_synctimer_read(s) - s->val; - } - - OMAP_BAD_REG(addr); - return 0; -} - -static uint32_t omap_synctimer_readh(void *opaque, hwaddr addr) -{ - struct omap_synctimer_s *s = (struct omap_synctimer_s *) opaque; - uint32_t ret; - - if (addr & 2) - return s->readh; - else { - ret = omap_synctimer_readw(opaque, addr); - s->readh = ret >> 16; - return ret & 0xffff; - } -} - -static void omap_synctimer_write(void *opaque, hwaddr addr, - uint32_t value) -{ - OMAP_BAD_REG(addr); -} - -static const MemoryRegionOps omap_synctimer_ops = { - .old_mmio = { - .read = { - omap_badwidth_read32, - omap_synctimer_readh, - omap_synctimer_readw, - }, - .write = { - omap_badwidth_write32, - omap_synctimer_write, - omap_synctimer_write, - }, - }, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -struct omap_synctimer_s *omap_synctimer_init(struct omap_target_agent_s *ta, - struct omap_mpu_state_s *mpu, omap_clk fclk, omap_clk iclk) -{ - struct omap_synctimer_s *s = g_malloc0(sizeof(*s)); - - omap_synctimer_reset(s); - memory_region_init_io(&s->iomem, NULL, &omap_synctimer_ops, s, "omap.synctimer", - omap_l4_region_size(ta, 0)); - omap_l4_attach(ta, 0, &s->iomem); - - return s; -} diff --git a/qemu/hw/timer/pl031.c b/qemu/hw/timer/pl031.c deleted file mode 100644 index 38e0cb5ad..000000000 --- a/qemu/hw/timer/pl031.c +++ /dev/null @@ -1,270 +0,0 @@ -/* - * ARM AMBA PrimeCell PL031 RTC - * - * Copyright (c) 2007 CodeSourcery - * - * This file is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Contributions after 2012-01-13 are licensed under the terms of the - * GNU GPL, version 2 or (at your option) any later version. - */ - -#include "qemu/osdep.h" -#include "hw/sysbus.h" -#include "qemu/timer.h" -#include "sysemu/sysemu.h" -#include "qemu/cutils.h" - -//#define DEBUG_PL031 - -#ifdef DEBUG_PL031 -#define DPRINTF(fmt, ...) \ -do { printf("pl031: " fmt , ## __VA_ARGS__); } while (0) -#else -#define DPRINTF(fmt, ...) do {} while(0) -#endif - -#define RTC_DR 0x00 /* Data read register */ -#define RTC_MR 0x04 /* Match register */ -#define RTC_LR 0x08 /* Data load register */ -#define RTC_CR 0x0c /* Control register */ -#define RTC_IMSC 0x10 /* Interrupt mask and set register */ -#define RTC_RIS 0x14 /* Raw interrupt status register */ -#define RTC_MIS 0x18 /* Masked interrupt status register */ -#define RTC_ICR 0x1c /* Interrupt clear register */ - -#define TYPE_PL031 "pl031" -#define PL031(obj) OBJECT_CHECK(PL031State, (obj), TYPE_PL031) - -typedef struct PL031State { - SysBusDevice parent_obj; - - MemoryRegion iomem; - QEMUTimer *timer; - qemu_irq irq; - - /* Needed to preserve the tick_count across migration, even if the - * absolute value of the rtc_clock is different on the source and - * destination. - */ - uint32_t tick_offset_vmstate; - uint32_t tick_offset; - - uint32_t mr; - uint32_t lr; - uint32_t cr; - uint32_t im; - uint32_t is; -} PL031State; - -static const unsigned char pl031_id[] = { - 0x31, 0x10, 0x14, 0x00, /* Device ID */ - 0x0d, 0xf0, 0x05, 0xb1 /* Cell ID */ -}; - -static void pl031_update(PL031State *s) -{ - qemu_set_irq(s->irq, s->is & s->im); -} - -static void pl031_interrupt(void * opaque) -{ - PL031State *s = (PL031State *)opaque; - - s->is = 1; - DPRINTF("Alarm raised\n"); - pl031_update(s); -} - -static uint32_t pl031_get_count(PL031State *s) -{ - int64_t now = qemu_clock_get_ns(rtc_clock); - return s->tick_offset + now / NANOSECONDS_PER_SECOND; -} - -static void pl031_set_alarm(PL031State *s) -{ - uint32_t ticks; - - /* The timer wraps around. This subtraction also wraps in the same way, - and gives correct results when alarm < now_ticks. */ - ticks = s->mr - pl031_get_count(s); - DPRINTF("Alarm set in %ud ticks\n", ticks); - if (ticks == 0) { - timer_del(s->timer); - pl031_interrupt(s); - } else { - int64_t now = qemu_clock_get_ns(rtc_clock); - timer_mod(s->timer, now + (int64_t)ticks * NANOSECONDS_PER_SECOND); - } -} - -static uint64_t pl031_read(void *opaque, hwaddr offset, - unsigned size) -{ - PL031State *s = (PL031State *)opaque; - - if (offset >= 0xfe0 && offset < 0x1000) - return pl031_id[(offset - 0xfe0) >> 2]; - - switch (offset) { - case RTC_DR: - return pl031_get_count(s); - case RTC_MR: - return s->mr; - case RTC_IMSC: - return s->im; - case RTC_RIS: - return s->is; - case RTC_LR: - return s->lr; - case RTC_CR: - /* RTC is permanently enabled. */ - return 1; - case RTC_MIS: - return s->is & s->im; - case RTC_ICR: - qemu_log_mask(LOG_GUEST_ERROR, - "pl031: read of write-only register at offset 0x%x\n", - (int)offset); - break; - default: - qemu_log_mask(LOG_GUEST_ERROR, - "pl031_read: Bad offset 0x%x\n", (int)offset); - break; - } - - return 0; -} - -static void pl031_write(void * opaque, hwaddr offset, - uint64_t value, unsigned size) -{ - PL031State *s = (PL031State *)opaque; - - - switch (offset) { - case RTC_LR: - s->tick_offset += value - pl031_get_count(s); - pl031_set_alarm(s); - break; - case RTC_MR: - s->mr = value; - pl031_set_alarm(s); - break; - case RTC_IMSC: - s->im = value & 1; - DPRINTF("Interrupt mask %d\n", s->im); - pl031_update(s); - break; - case RTC_ICR: - /* The PL031 documentation (DDI0224B) states that the interrupt is - cleared when bit 0 of the written value is set. However the - arm926e documentation (DDI0287B) states that the interrupt is - cleared when any value is written. */ - DPRINTF("Interrupt cleared"); - s->is = 0; - pl031_update(s); - break; - case RTC_CR: - /* Written value is ignored. */ - break; - - case RTC_DR: - case RTC_MIS: - case RTC_RIS: - qemu_log_mask(LOG_GUEST_ERROR, - "pl031: write to read-only register at offset 0x%x\n", - (int)offset); - break; - - default: - qemu_log_mask(LOG_GUEST_ERROR, - "pl031_write: Bad offset 0x%x\n", (int)offset); - break; - } -} - -static const MemoryRegionOps pl031_ops = { - .read = pl031_read, - .write = pl031_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static void pl031_init(Object *obj) -{ - PL031State *s = PL031(obj); - SysBusDevice *dev = SYS_BUS_DEVICE(obj); - struct tm tm; - - memory_region_init_io(&s->iomem, obj, &pl031_ops, s, "pl031", 0x1000); - sysbus_init_mmio(dev, &s->iomem); - - sysbus_init_irq(dev, &s->irq); - qemu_get_timedate(&tm, 0); - s->tick_offset = mktimegm(&tm) - - qemu_clock_get_ns(rtc_clock) / NANOSECONDS_PER_SECOND; - - s->timer = timer_new_ns(rtc_clock, pl031_interrupt, s); -} - -static void pl031_pre_save(void *opaque) -{ - PL031State *s = opaque; - - /* tick_offset is base_time - rtc_clock base time. Instead, we want to - * store the base time relative to the QEMU_CLOCK_VIRTUAL for backwards-compatibility. */ - int64_t delta = qemu_clock_get_ns(rtc_clock) - qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); - s->tick_offset_vmstate = s->tick_offset + delta / NANOSECONDS_PER_SECOND; -} - -static int pl031_post_load(void *opaque, int version_id) -{ - PL031State *s = opaque; - - int64_t delta = qemu_clock_get_ns(rtc_clock) - qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); - s->tick_offset = s->tick_offset_vmstate - delta / NANOSECONDS_PER_SECOND; - pl031_set_alarm(s); - return 0; -} - -static const VMStateDescription vmstate_pl031 = { - .name = "pl031", - .version_id = 1, - .minimum_version_id = 1, - .pre_save = pl031_pre_save, - .post_load = pl031_post_load, - .fields = (VMStateField[]) { - VMSTATE_UINT32(tick_offset_vmstate, PL031State), - VMSTATE_UINT32(mr, PL031State), - VMSTATE_UINT32(lr, PL031State), - VMSTATE_UINT32(cr, PL031State), - VMSTATE_UINT32(im, PL031State), - VMSTATE_UINT32(is, PL031State), - VMSTATE_END_OF_LIST() - } -}; - -static void pl031_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - - dc->vmsd = &vmstate_pl031; -} - -static const TypeInfo pl031_info = { - .name = TYPE_PL031, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(PL031State), - .instance_init = pl031_init, - .class_init = pl031_class_init, -}; - -static void pl031_register_types(void) -{ - type_register_static(&pl031_info); -} - -type_init(pl031_register_types) diff --git a/qemu/hw/timer/puv3_ost.c b/qemu/hw/timer/puv3_ost.c deleted file mode 100644 index 93650b799..000000000 --- a/qemu/hw/timer/puv3_ost.c +++ /dev/null @@ -1,157 +0,0 @@ -/* - * OSTimer device simulation in PKUnity SoC - * - * Copyright (C) 2010-2012 Guan Xuetao - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation, or any later version. - * See the COPYING file in the top-level directory. - */ -#include "qemu/osdep.h" -#include "hw/sysbus.h" -#include "hw/ptimer.h" -#include "qemu/main-loop.h" - -#undef DEBUG_PUV3 -#include "hw/unicore32/puv3.h" - -#define TYPE_PUV3_OST "puv3_ost" -#define PUV3_OST(obj) OBJECT_CHECK(PUV3OSTState, (obj), TYPE_PUV3_OST) - -/* puv3 ostimer implementation. */ -typedef struct PUV3OSTState { - SysBusDevice parent_obj; - - MemoryRegion iomem; - QEMUBH *bh; - qemu_irq irq; - ptimer_state *ptimer; - - uint32_t reg_OSMR0; - uint32_t reg_OSCR; - uint32_t reg_OSSR; - uint32_t reg_OIER; -} PUV3OSTState; - -static uint64_t puv3_ost_read(void *opaque, hwaddr offset, - unsigned size) -{ - PUV3OSTState *s = opaque; - uint32_t ret = 0; - - switch (offset) { - case 0x10: /* Counter Register */ - ret = s->reg_OSMR0 - (uint32_t)ptimer_get_count(s->ptimer); - break; - case 0x14: /* Status Register */ - ret = s->reg_OSSR; - break; - case 0x1c: /* Interrupt Enable Register */ - ret = s->reg_OIER; - break; - default: - DPRINTF("Bad offset %x\n", (int)offset); - } - DPRINTF("offset 0x%x, value 0x%x\n", offset, ret); - return ret; -} - -static void puv3_ost_write(void *opaque, hwaddr 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 const MemoryRegionOps puv3_ost_ops = { - .read = puv3_ost_read, - .write = puv3_ost_write, - .impl = { - .min_access_size = 4, - .max_access_size = 4, - }, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static void puv3_ost_tick(void *opaque) -{ - PUV3OSTState *s = opaque; - - DPRINTF("ost hit when ptimer counter from 0x%x to 0x%x!\n", - s->reg_OSCR, s->reg_OSMR0); - - s->reg_OSCR = s->reg_OSMR0; - if (s->reg_OIER) { - s->reg_OSSR = 1; - qemu_irq_raise(s->irq); - } -} - -static int puv3_ost_init(SysBusDevice *dev) -{ - PUV3OSTState *s = PUV3_OST(dev); - - s->reg_OIER = 0; - s->reg_OSSR = 0; - s->reg_OSMR0 = 0; - s->reg_OSCR = 0; - - sysbus_init_irq(dev, &s->irq); - - s->bh = qemu_bh_new(puv3_ost_tick, s); - s->ptimer = ptimer_init(s->bh); - ptimer_set_freq(s->ptimer, 50 * 1000 * 1000); - - memory_region_init_io(&s->iomem, OBJECT(s), &puv3_ost_ops, s, "puv3_ost", - PUV3_REGS_OFFSET); - sysbus_init_mmio(dev, &s->iomem); - - return 0; -} - -static void puv3_ost_class_init(ObjectClass *klass, void *data) -{ - SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass); - - sdc->init = puv3_ost_init; -} - -static const TypeInfo puv3_ost_info = { - .name = TYPE_PUV3_OST, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(PUV3OSTState), - .class_init = puv3_ost_class_init, -}; - -static void puv3_ost_register_type(void) -{ - type_register_static(&puv3_ost_info); -} - -type_init(puv3_ost_register_type) diff --git a/qemu/hw/timer/pxa2xx_timer.c b/qemu/hw/timer/pxa2xx_timer.c deleted file mode 100644 index 59002b407..000000000 --- a/qemu/hw/timer/pxa2xx_timer.c +++ /dev/null @@ -1,605 +0,0 @@ -/* - * Intel XScale PXA255/270 OS Timers. - * - * Copyright (c) 2006 Openedhand Ltd. - * Copyright (c) 2006 Thorsten Zitterell - * - * This code is licensed under the GPL. - */ - -#include "qemu/osdep.h" -#include "hw/hw.h" -#include "qemu/timer.h" -#include "sysemu/sysemu.h" -#include "hw/arm/pxa.h" -#include "hw/sysbus.h" - -#define OSMR0 0x00 -#define OSMR1 0x04 -#define OSMR2 0x08 -#define OSMR3 0x0c -#define OSMR4 0x80 -#define OSMR5 0x84 -#define OSMR6 0x88 -#define OSMR7 0x8c -#define OSMR8 0x90 -#define OSMR9 0x94 -#define OSMR10 0x98 -#define OSMR11 0x9c -#define OSCR 0x10 /* OS Timer Count */ -#define OSCR4 0x40 -#define OSCR5 0x44 -#define OSCR6 0x48 -#define OSCR7 0x4c -#define OSCR8 0x50 -#define OSCR9 0x54 -#define OSCR10 0x58 -#define OSCR11 0x5c -#define OSSR 0x14 /* Timer status register */ -#define OWER 0x18 -#define OIER 0x1c /* Interrupt enable register 3-0 to E3-E0 */ -#define OMCR4 0xc0 /* OS Match Control registers */ -#define OMCR5 0xc4 -#define OMCR6 0xc8 -#define OMCR7 0xcc -#define OMCR8 0xd0 -#define OMCR9 0xd4 -#define OMCR10 0xd8 -#define OMCR11 0xdc -#define OSNR 0x20 - -#define PXA25X_FREQ 3686400 /* 3.6864 MHz */ -#define PXA27X_FREQ 3250000 /* 3.25 MHz */ - -static int pxa2xx_timer4_freq[8] = { - [0] = 0, - [1] = 32768, - [2] = 1000, - [3] = 1, - [4] = 1000000, - /* [5] is the "Externally supplied clock". Assign if necessary. */ - [5 ... 7] = 0, -}; - -#define TYPE_PXA2XX_TIMER "pxa2xx-timer" -#define PXA2XX_TIMER(obj) \ - OBJECT_CHECK(PXA2xxTimerInfo, (obj), TYPE_PXA2XX_TIMER) - -typedef struct PXA2xxTimerInfo PXA2xxTimerInfo; - -typedef struct { - uint32_t value; - qemu_irq irq; - QEMUTimer *qtimer; - int num; - PXA2xxTimerInfo *info; -} PXA2xxTimer0; - -typedef struct { - PXA2xxTimer0 tm; - int32_t oldclock; - int32_t clock; - uint64_t lastload; - uint32_t freq; - uint32_t control; -} PXA2xxTimer4; - -struct PXA2xxTimerInfo { - SysBusDevice parent_obj; - - MemoryRegion iomem; - uint32_t flags; - - int32_t clock; - int32_t oldclock; - uint64_t lastload; - uint32_t freq; - PXA2xxTimer0 timer[4]; - uint32_t events; - uint32_t irq_enabled; - uint32_t reset3; - uint32_t snapshot; - - qemu_irq irq4; - PXA2xxTimer4 tm4[8]; -}; - -#define PXA2XX_TIMER_HAVE_TM4 0 - -static inline int pxa2xx_timer_has_tm4(PXA2xxTimerInfo *s) -{ - return s->flags & (1 << PXA2XX_TIMER_HAVE_TM4); -} - -static void pxa2xx_timer_update(void *opaque, uint64_t now_qemu) -{ - PXA2xxTimerInfo *s = (PXA2xxTimerInfo *) opaque; - int i; - uint32_t now_vm; - uint64_t new_qemu; - - now_vm = s->clock + - muldiv64(now_qemu - s->lastload, s->freq, NANOSECONDS_PER_SECOND); - - for (i = 0; i < 4; i ++) { - new_qemu = now_qemu + muldiv64((uint32_t) (s->timer[i].value - now_vm), - NANOSECONDS_PER_SECOND, s->freq); - timer_mod(s->timer[i].qtimer, new_qemu); - } -} - -static void pxa2xx_timer_update4(void *opaque, uint64_t now_qemu, int n) -{ - PXA2xxTimerInfo *s = (PXA2xxTimerInfo *) opaque; - uint32_t now_vm; - uint64_t new_qemu; - static const int counters[8] = { 0, 0, 0, 0, 4, 4, 6, 6 }; - int counter; - - if (s->tm4[n].control & (1 << 7)) - counter = n; - else - counter = counters[n]; - - if (!s->tm4[counter].freq) { - timer_del(s->tm4[n].tm.qtimer); - return; - } - - now_vm = s->tm4[counter].clock + muldiv64(now_qemu - - s->tm4[counter].lastload, - s->tm4[counter].freq, NANOSECONDS_PER_SECOND); - - new_qemu = now_qemu + muldiv64((uint32_t) (s->tm4[n].tm.value - now_vm), - NANOSECONDS_PER_SECOND, s->tm4[counter].freq); - timer_mod(s->tm4[n].tm.qtimer, new_qemu); -} - -static uint64_t pxa2xx_timer_read(void *opaque, hwaddr offset, - unsigned size) -{ - PXA2xxTimerInfo *s = (PXA2xxTimerInfo *) opaque; - int tm = 0; - - switch (offset) { - case OSMR3: tm ++; - /* fall through */ - case OSMR2: tm ++; - /* fall through */ - case OSMR1: tm ++; - /* fall through */ - case OSMR0: - return s->timer[tm].value; - case OSMR11: tm ++; - /* fall through */ - case OSMR10: tm ++; - /* fall through */ - case OSMR9: tm ++; - /* fall through */ - case OSMR8: tm ++; - /* fall through */ - case OSMR7: tm ++; - /* fall through */ - case OSMR6: tm ++; - /* fall through */ - case OSMR5: tm ++; - /* fall through */ - case OSMR4: - if (!pxa2xx_timer_has_tm4(s)) - goto badreg; - return s->tm4[tm].tm.value; - case OSCR: - return s->clock + muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - - s->lastload, s->freq, NANOSECONDS_PER_SECOND); - case OSCR11: tm ++; - /* fall through */ - case OSCR10: tm ++; - /* fall through */ - case OSCR9: tm ++; - /* fall through */ - case OSCR8: tm ++; - /* fall through */ - case OSCR7: tm ++; - /* fall through */ - case OSCR6: tm ++; - /* fall through */ - case OSCR5: tm ++; - /* fall through */ - case OSCR4: - if (!pxa2xx_timer_has_tm4(s)) - goto badreg; - - if ((tm == 9 - 4 || tm == 11 - 4) && (s->tm4[tm].control & (1 << 9))) { - if (s->tm4[tm - 1].freq) - s->snapshot = s->tm4[tm - 1].clock + muldiv64( - qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - - s->tm4[tm - 1].lastload, - s->tm4[tm - 1].freq, NANOSECONDS_PER_SECOND); - else - s->snapshot = s->tm4[tm - 1].clock; - } - - if (!s->tm4[tm].freq) - return s->tm4[tm].clock; - return s->tm4[tm].clock + - muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - - s->tm4[tm].lastload, s->tm4[tm].freq, - NANOSECONDS_PER_SECOND); - case OIER: - return s->irq_enabled; - case OSSR: /* Status register */ - return s->events; - case OWER: - return s->reset3; - case OMCR11: tm ++; - /* fall through */ - case OMCR10: tm ++; - /* fall through */ - case OMCR9: tm ++; - /* fall through */ - case OMCR8: tm ++; - /* fall through */ - case OMCR7: tm ++; - /* fall through */ - case OMCR6: tm ++; - /* fall through */ - case OMCR5: tm ++; - /* fall through */ - case OMCR4: - if (!pxa2xx_timer_has_tm4(s)) - goto badreg; - return s->tm4[tm].control; - case OSNR: - return s->snapshot; - default: - badreg: - hw_error("pxa2xx_timer_read: Bad offset " REG_FMT "\n", offset); - } - - return 0; -} - -static void pxa2xx_timer_write(void *opaque, hwaddr offset, - uint64_t value, unsigned size) -{ - int i, tm = 0; - PXA2xxTimerInfo *s = (PXA2xxTimerInfo *) opaque; - - switch (offset) { - case OSMR3: tm ++; - /* fall through */ - case OSMR2: tm ++; - /* fall through */ - case OSMR1: tm ++; - /* fall through */ - case OSMR0: - s->timer[tm].value = value; - pxa2xx_timer_update(s, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL)); - break; - case OSMR11: tm ++; - /* fall through */ - case OSMR10: tm ++; - /* fall through */ - case OSMR9: tm ++; - /* fall through */ - case OSMR8: tm ++; - /* fall through */ - case OSMR7: tm ++; - /* fall through */ - case OSMR6: tm ++; - /* fall through */ - case OSMR5: tm ++; - /* fall through */ - case OSMR4: - if (!pxa2xx_timer_has_tm4(s)) - goto badreg; - s->tm4[tm].tm.value = value; - pxa2xx_timer_update4(s, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), tm); - break; - case OSCR: - s->oldclock = s->clock; - s->lastload = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); - s->clock = value; - pxa2xx_timer_update(s, s->lastload); - break; - case OSCR11: tm ++; - /* fall through */ - case OSCR10: tm ++; - /* fall through */ - case OSCR9: tm ++; - /* fall through */ - case OSCR8: tm ++; - /* fall through */ - case OSCR7: tm ++; - /* fall through */ - case OSCR6: tm ++; - /* fall through */ - case OSCR5: tm ++; - /* fall through */ - case OSCR4: - if (!pxa2xx_timer_has_tm4(s)) - goto badreg; - s->tm4[tm].oldclock = s->tm4[tm].clock; - s->tm4[tm].lastload = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); - s->tm4[tm].clock = value; - pxa2xx_timer_update4(s, s->tm4[tm].lastload, tm); - break; - case OIER: - s->irq_enabled = value & 0xfff; - break; - case OSSR: /* Status register */ - value &= s->events; - s->events &= ~value; - for (i = 0; i < 4; i ++, value >>= 1) - if (value & 1) - qemu_irq_lower(s->timer[i].irq); - if (pxa2xx_timer_has_tm4(s) && !(s->events & 0xff0) && value) - qemu_irq_lower(s->irq4); - break; - case OWER: /* XXX: Reset on OSMR3 match? */ - s->reset3 = value; - break; - case OMCR7: tm ++; - /* fall through */ - case OMCR6: tm ++; - /* fall through */ - case OMCR5: tm ++; - /* fall through */ - case OMCR4: - if (!pxa2xx_timer_has_tm4(s)) - goto badreg; - s->tm4[tm].control = value & 0x0ff; - /* XXX Stop if running (shouldn't happen) */ - if ((value & (1 << 7)) || tm == 0) - s->tm4[tm].freq = pxa2xx_timer4_freq[value & 7]; - else { - s->tm4[tm].freq = 0; - pxa2xx_timer_update4(s, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), tm); - } - break; - case OMCR11: tm ++; - /* fall through */ - case OMCR10: tm ++; - /* fall through */ - case OMCR9: tm ++; - /* fall through */ - case OMCR8: tm += 4; - if (!pxa2xx_timer_has_tm4(s)) - goto badreg; - s->tm4[tm].control = value & 0x3ff; - /* XXX Stop if running (shouldn't happen) */ - if ((value & (1 << 7)) || !(tm & 1)) - s->tm4[tm].freq = - pxa2xx_timer4_freq[(value & (1 << 8)) ? 0 : (value & 7)]; - else { - s->tm4[tm].freq = 0; - pxa2xx_timer_update4(s, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), tm); - } - break; - default: - badreg: - hw_error("pxa2xx_timer_write: Bad offset " REG_FMT "\n", offset); - } -} - -static const MemoryRegionOps pxa2xx_timer_ops = { - .read = pxa2xx_timer_read, - .write = pxa2xx_timer_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static void pxa2xx_timer_tick(void *opaque) -{ - PXA2xxTimer0 *t = (PXA2xxTimer0 *) opaque; - PXA2xxTimerInfo *i = t->info; - - if (i->irq_enabled & (1 << t->num)) { - i->events |= 1 << t->num; - qemu_irq_raise(t->irq); - } - - if (t->num == 3) - if (i->reset3 & 1) { - i->reset3 = 0; - qemu_system_reset_request(); - } -} - -static void pxa2xx_timer_tick4(void *opaque) -{ - PXA2xxTimer4 *t = (PXA2xxTimer4 *) opaque; - PXA2xxTimerInfo *i = (PXA2xxTimerInfo *) t->tm.info; - - pxa2xx_timer_tick(&t->tm); - if (t->control & (1 << 3)) - t->clock = 0; - if (t->control & (1 << 6)) - pxa2xx_timer_update4(i, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), t->tm.num - 4); - if (i->events & 0xff0) - qemu_irq_raise(i->irq4); -} - -static int pxa25x_timer_post_load(void *opaque, int version_id) -{ - PXA2xxTimerInfo *s = (PXA2xxTimerInfo *) opaque; - int64_t now; - int i; - - now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); - pxa2xx_timer_update(s, now); - - if (pxa2xx_timer_has_tm4(s)) - for (i = 0; i < 8; i ++) - pxa2xx_timer_update4(s, now, i); - - return 0; -} - -static void pxa2xx_timer_init(Object *obj) -{ - PXA2xxTimerInfo *s = PXA2XX_TIMER(obj); - SysBusDevice *dev = SYS_BUS_DEVICE(obj); - - s->irq_enabled = 0; - s->oldclock = 0; - s->clock = 0; - s->lastload = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); - s->reset3 = 0; - - memory_region_init_io(&s->iomem, obj, &pxa2xx_timer_ops, s, - "pxa2xx-timer", 0x00001000); - sysbus_init_mmio(dev, &s->iomem); -} - -static void pxa2xx_timer_realize(DeviceState *dev, Error **errp) -{ - PXA2xxTimerInfo *s = PXA2XX_TIMER(dev); - SysBusDevice *sbd = SYS_BUS_DEVICE(dev); - int i; - - for (i = 0; i < 4; i ++) { - s->timer[i].value = 0; - sysbus_init_irq(sbd, &s->timer[i].irq); - s->timer[i].info = s; - s->timer[i].num = i; - s->timer[i].qtimer = timer_new_ns(QEMU_CLOCK_VIRTUAL, - pxa2xx_timer_tick, &s->timer[i]); - } - - if (s->flags & (1 << PXA2XX_TIMER_HAVE_TM4)) { - sysbus_init_irq(sbd, &s->irq4); - - for (i = 0; i < 8; i ++) { - s->tm4[i].tm.value = 0; - s->tm4[i].tm.info = s; - s->tm4[i].tm.num = i + 4; - s->tm4[i].freq = 0; - s->tm4[i].control = 0x0; - s->tm4[i].tm.qtimer = timer_new_ns(QEMU_CLOCK_VIRTUAL, - pxa2xx_timer_tick4, &s->tm4[i]); - } - } -} - -static const VMStateDescription vmstate_pxa2xx_timer0_regs = { - .name = "pxa2xx_timer0", - .version_id = 2, - .minimum_version_id = 2, - .fields = (VMStateField[]) { - VMSTATE_UINT32(value, PXA2xxTimer0), - VMSTATE_END_OF_LIST(), - }, -}; - -static const VMStateDescription vmstate_pxa2xx_timer4_regs = { - .name = "pxa2xx_timer4", - .version_id = 1, - .minimum_version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_STRUCT(tm, PXA2xxTimer4, 1, - vmstate_pxa2xx_timer0_regs, PXA2xxTimer0), - VMSTATE_INT32(oldclock, PXA2xxTimer4), - VMSTATE_INT32(clock, PXA2xxTimer4), - VMSTATE_UINT64(lastload, PXA2xxTimer4), - VMSTATE_UINT32(freq, PXA2xxTimer4), - VMSTATE_UINT32(control, PXA2xxTimer4), - VMSTATE_END_OF_LIST(), - }, -}; - -static bool pxa2xx_timer_has_tm4_test(void *opaque, int version_id) -{ - return pxa2xx_timer_has_tm4(opaque); -} - -static const VMStateDescription vmstate_pxa2xx_timer_regs = { - .name = "pxa2xx_timer", - .version_id = 1, - .minimum_version_id = 1, - .post_load = pxa25x_timer_post_load, - .fields = (VMStateField[]) { - VMSTATE_INT32(clock, PXA2xxTimerInfo), - VMSTATE_INT32(oldclock, PXA2xxTimerInfo), - VMSTATE_UINT64(lastload, PXA2xxTimerInfo), - VMSTATE_STRUCT_ARRAY(timer, PXA2xxTimerInfo, 4, 1, - vmstate_pxa2xx_timer0_regs, PXA2xxTimer0), - VMSTATE_UINT32(events, PXA2xxTimerInfo), - VMSTATE_UINT32(irq_enabled, PXA2xxTimerInfo), - VMSTATE_UINT32(reset3, PXA2xxTimerInfo), - VMSTATE_UINT32(snapshot, PXA2xxTimerInfo), - VMSTATE_STRUCT_ARRAY_TEST(tm4, PXA2xxTimerInfo, 8, - pxa2xx_timer_has_tm4_test, 0, - vmstate_pxa2xx_timer4_regs, PXA2xxTimer4), - VMSTATE_END_OF_LIST(), - } -}; - -static Property pxa25x_timer_dev_properties[] = { - DEFINE_PROP_UINT32("freq", PXA2xxTimerInfo, freq, PXA25X_FREQ), - DEFINE_PROP_BIT("tm4", PXA2xxTimerInfo, flags, - PXA2XX_TIMER_HAVE_TM4, false), - DEFINE_PROP_END_OF_LIST(), -}; - -static void pxa25x_timer_dev_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - - dc->desc = "PXA25x timer"; - dc->props = pxa25x_timer_dev_properties; -} - -static const TypeInfo pxa25x_timer_dev_info = { - .name = "pxa25x-timer", - .parent = TYPE_PXA2XX_TIMER, - .instance_size = sizeof(PXA2xxTimerInfo), - .class_init = pxa25x_timer_dev_class_init, -}; - -static Property pxa27x_timer_dev_properties[] = { - DEFINE_PROP_UINT32("freq", PXA2xxTimerInfo, freq, PXA27X_FREQ), - DEFINE_PROP_BIT("tm4", PXA2xxTimerInfo, flags, - PXA2XX_TIMER_HAVE_TM4, true), - DEFINE_PROP_END_OF_LIST(), -}; - -static void pxa27x_timer_dev_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - - dc->desc = "PXA27x timer"; - dc->props = pxa27x_timer_dev_properties; -} - -static const TypeInfo pxa27x_timer_dev_info = { - .name = "pxa27x-timer", - .parent = TYPE_PXA2XX_TIMER, - .instance_size = sizeof(PXA2xxTimerInfo), - .class_init = pxa27x_timer_dev_class_init, -}; - -static void pxa2xx_timer_class_init(ObjectClass *oc, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(oc); - - dc->realize = pxa2xx_timer_realize; - dc->vmsd = &vmstate_pxa2xx_timer_regs; -} - -static const TypeInfo pxa2xx_timer_type_info = { - .name = TYPE_PXA2XX_TIMER, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(PXA2xxTimerInfo), - .instance_init = pxa2xx_timer_init, - .abstract = true, - .class_init = pxa2xx_timer_class_init, -}; - -static void pxa2xx_timer_register_types(void) -{ - type_register_static(&pxa2xx_timer_type_info); - type_register_static(&pxa25x_timer_dev_info); - type_register_static(&pxa27x_timer_dev_info); -} - -type_init(pxa2xx_timer_register_types) diff --git a/qemu/hw/timer/sh_timer.c b/qemu/hw/timer/sh_timer.c deleted file mode 100644 index 255b2fc91..000000000 --- a/qemu/hw/timer/sh_timer.c +++ /dev/null @@ -1,335 +0,0 @@ -/* - * SuperH Timer modules. - * - * Copyright (c) 2007 Magnus Damm - * Based on arm_timer.c by Paul Brook - * Copyright (c) 2005-2006 CodeSourcery. - * - * This code is licensed under the GPL. - */ - -#include "qemu/osdep.h" -#include "hw/hw.h" -#include "hw/sh4/sh.h" -#include "qemu/timer.h" -#include "qemu/main-loop.h" -#include "exec/address-spaces.h" -#include "hw/ptimer.h" - -//#define DEBUG_TIMER - -#define TIMER_TCR_TPSC (7 << 0) -#define TIMER_TCR_CKEG (3 << 3) -#define TIMER_TCR_UNIE (1 << 5) -#define TIMER_TCR_ICPE (3 << 6) -#define TIMER_TCR_UNF (1 << 8) -#define TIMER_TCR_ICPF (1 << 9) -#define TIMER_TCR_RESERVED (0x3f << 10) - -#define TIMER_FEAT_CAPT (1 << 0) -#define TIMER_FEAT_EXTCLK (1 << 1) - -#define OFFSET_TCOR 0 -#define OFFSET_TCNT 1 -#define OFFSET_TCR 2 -#define OFFSET_TCPR 3 - -typedef struct { - ptimer_state *timer; - uint32_t tcnt; - uint32_t tcor; - uint32_t tcr; - uint32_t tcpr; - int freq; - int int_level; - int old_level; - int feat; - int enabled; - qemu_irq irq; -} sh_timer_state; - -/* Check all active timers, and schedule the next timer interrupt. */ - -static void sh_timer_update(sh_timer_state *s) -{ - int new_level = s->int_level && (s->tcr & TIMER_TCR_UNIE); - - if (new_level != s->old_level) - qemu_set_irq (s->irq, new_level); - - s->old_level = s->int_level; - s->int_level = new_level; -} - -static uint32_t sh_timer_read(void *opaque, hwaddr offset) -{ - sh_timer_state *s = (sh_timer_state *)opaque; - - switch (offset >> 2) { - case OFFSET_TCOR: - return s->tcor; - case OFFSET_TCNT: - return ptimer_get_count(s->timer); - case OFFSET_TCR: - return s->tcr | (s->int_level ? TIMER_TCR_UNF : 0); - case OFFSET_TCPR: - if (s->feat & TIMER_FEAT_CAPT) - return s->tcpr; - default: - hw_error("sh_timer_read: Bad offset %x\n", (int)offset); - return 0; - } -} - -static void sh_timer_write(void *opaque, hwaddr 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); -} - -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 void sh_timer_tick(void *opaque) -{ - sh_timer_state *s = (sh_timer_state *)opaque; - s->int_level = s->enabled; - sh_timer_update(s); -} - -static void *sh_timer_init(uint32_t freq, int feat, qemu_irq irq) -{ - sh_timer_state *s; - QEMUBH *bh; - - s = (sh_timer_state *)g_malloc0(sizeof(sh_timer_state)); - s->freq = freq; - s->feat = feat; - s->tcor = 0xffffffff; - s->tcnt = 0xffffffff; - s->tcpr = 0xdeadbeef; - s->tcr = 0; - s->enabled = 0; - s->irq = irq; - - bh = qemu_bh_new(sh_timer_tick, s); - s->timer = ptimer_init(bh); - - sh_timer_write(s, OFFSET_TCOR >> 2, s->tcor); - sh_timer_write(s, OFFSET_TCNT >> 2, s->tcnt); - sh_timer_write(s, OFFSET_TCPR >> 2, s->tcpr); - sh_timer_write(s, OFFSET_TCR >> 2, s->tcpr); - /* ??? Save/restore. */ - return s; -} - -typedef struct { - MemoryRegion iomem; - MemoryRegion iomem_p4; - MemoryRegion iomem_a7; - void *timer[3]; - int level[3]; - uint32_t tocr; - uint32_t tstr; - int feat; -} tmu012_state; - -static uint64_t tmu012_read(void *opaque, hwaddr offset, - unsigned size) -{ - tmu012_state *s = (tmu012_state *)opaque; - -#ifdef DEBUG_TIMER - printf("tmu012_read 0x%lx\n", (unsigned long) offset); -#endif - - if (offset >= 0x20) { - if (!(s->feat & TMU012_FEAT_3CHAN)) - hw_error("tmu012_write: Bad channel offset %x\n", (int)offset); - return sh_timer_read(s->timer[2], offset - 0x20); - } - - if (offset >= 0x14) - return sh_timer_read(s->timer[1], offset - 0x14); - - if (offset >= 0x08) - return sh_timer_read(s->timer[0], offset - 0x08); - - if (offset == 4) - return s->tstr; - - if ((s->feat & TMU012_FEAT_TOCR) && offset == 0) - return s->tocr; - - hw_error("tmu012_write: Bad offset %x\n", (int)offset); - return 0; -} - -static void tmu012_write(void *opaque, hwaddr offset, - uint64_t value, unsigned size) -{ - tmu012_state *s = (tmu012_state *)opaque; - -#ifdef DEBUG_TIMER - printf("tmu012_write 0x%lx 0x%08x\n", (unsigned long) offset, value); -#endif - - if (offset >= 0x20) { - if (!(s->feat & TMU012_FEAT_3CHAN)) - hw_error("tmu012_write: Bad channel offset %x\n", (int)offset); - sh_timer_write(s->timer[2], offset - 0x20, value); - return; - } - - if (offset >= 0x14) { - sh_timer_write(s->timer[1], offset - 0x14, value); - return; - } - - if (offset >= 0x08) { - sh_timer_write(s->timer[0], offset - 0x08, value); - return; - } - - if (offset == 4) { - sh_timer_start_stop(s->timer[0], value & (1 << 0)); - sh_timer_start_stop(s->timer[1], value & (1 << 1)); - if (s->feat & TMU012_FEAT_3CHAN) - sh_timer_start_stop(s->timer[2], value & (1 << 2)); - else - if (value & (1 << 2)) - hw_error("tmu012_write: Bad channel\n"); - - s->tstr = value; - return; - } - - if ((s->feat & TMU012_FEAT_TOCR) && offset == 0) { - s->tocr = value & (1 << 0); - } -} - -static const MemoryRegionOps tmu012_ops = { - .read = tmu012_read, - .write = tmu012_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -void tmu012_init(MemoryRegion *sysmem, hwaddr base, - int feat, uint32_t freq, - qemu_irq ch0_irq, qemu_irq ch1_irq, - qemu_irq ch2_irq0, qemu_irq ch2_irq1) -{ - tmu012_state *s; - int timer_feat = (feat & TMU012_FEAT_EXTCLK) ? TIMER_FEAT_EXTCLK : 0; - - s = (tmu012_state *)g_malloc0(sizeof(tmu012_state)); - s->feat = feat; - s->timer[0] = sh_timer_init(freq, timer_feat, ch0_irq); - s->timer[1] = sh_timer_init(freq, timer_feat, ch1_irq); - if (feat & TMU012_FEAT_3CHAN) - s->timer[2] = sh_timer_init(freq, timer_feat | TIMER_FEAT_CAPT, - ch2_irq0); /* ch2_irq1 not supported */ - - memory_region_init_io(&s->iomem, NULL, &tmu012_ops, s, - "timer", 0x100000000ULL); - - memory_region_init_alias(&s->iomem_p4, NULL, "timer-p4", - &s->iomem, 0, 0x1000); - memory_region_add_subregion(sysmem, P4ADDR(base), &s->iomem_p4); - - memory_region_init_alias(&s->iomem_a7, NULL, "timer-a7", - &s->iomem, 0, 0x1000); - memory_region_add_subregion(sysmem, A7ADDR(base), &s->iomem_a7); - /* ??? Save/restore. */ -} diff --git a/qemu/hw/timer/slavio_timer.c b/qemu/hw/timer/slavio_timer.c deleted file mode 100644 index fb3e08bed..000000000 --- a/qemu/hw/timer/slavio_timer.c +++ /dev/null @@ -1,435 +0,0 @@ -/* - * QEMU Sparc SLAVIO timer controller emulation - * - * Copyright (c) 2003-2005 Fabrice Bellard - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#include "qemu/osdep.h" -#include "hw/sparc/sun4m.h" -#include "qemu/timer.h" -#include "hw/ptimer.h" -#include "hw/sysbus.h" -#include "trace.h" -#include "qemu/main-loop.h" - -/* - * Registers of hardware timer in sun4m. - * - * This is the timer/counter part of chip STP2001 (Slave I/O), also - * produced as NCR89C105. See - * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C105.txt - * - * The 31-bit counter is incremented every 500ns by bit 9. Bits 8..0 - * are zero. Bit 31 is 1 when count has been reached. - * - * Per-CPU timers interrupt local CPU, system timer uses normal - * interrupt routing. - * - */ - -#define MAX_CPUS 16 - -typedef struct CPUTimerState { - qemu_irq irq; - ptimer_state *timer; - uint32_t count, counthigh, reached; - /* processor only */ - uint32_t run; - uint64_t limit; -} CPUTimerState; - -#define TYPE_SLAVIO_TIMER "slavio_timer" -#define SLAVIO_TIMER(obj) \ - OBJECT_CHECK(SLAVIO_TIMERState, (obj), TYPE_SLAVIO_TIMER) - -typedef struct SLAVIO_TIMERState { - SysBusDevice parent_obj; - - uint32_t num_cpus; - uint32_t cputimer_mode; - CPUTimerState cputimer[MAX_CPUS + 1]; -} SLAVIO_TIMERState; - -typedef struct TimerContext { - MemoryRegion iomem; - SLAVIO_TIMERState *s; - unsigned int timer_index; /* 0 for system, 1 ... MAX_CPUS for CPU timers */ -} TimerContext; - -#define SYS_TIMER_SIZE 0x14 -#define CPU_TIMER_SIZE 0x10 - -#define TIMER_LIMIT 0 -#define TIMER_COUNTER 1 -#define TIMER_COUNTER_NORST 2 -#define TIMER_STATUS 3 -#define TIMER_MODE 4 - -#define TIMER_COUNT_MASK32 0xfffffe00 -#define TIMER_LIMIT_MASK32 0x7fffffff -#define TIMER_MAX_COUNT64 0x7ffffffffffffe00ULL -#define TIMER_MAX_COUNT32 0x7ffffe00ULL -#define TIMER_REACHED 0x80000000 -#define TIMER_PERIOD 500ULL // 500ns -#define LIMIT_TO_PERIODS(l) (((l) >> 9) - 1) -#define PERIODS_TO_LIMIT(l) (((l) + 1) << 9) - -static int slavio_timer_is_user(TimerContext *tc) -{ - SLAVIO_TIMERState *s = tc->s; - unsigned int timer_index = tc->timer_index; - - return timer_index != 0 && (s->cputimer_mode & (1 << (timer_index - 1))); -} - -// Update count, set irq, update expire_time -// Convert from ptimer countdown units -static void slavio_timer_get_out(CPUTimerState *t) -{ - uint64_t count, limit; - - if (t->limit == 0) { /* free-run system or processor counter */ - limit = TIMER_MAX_COUNT32; - } else { - limit = t->limit; - } - count = limit - PERIODS_TO_LIMIT(ptimer_get_count(t->timer)); - - trace_slavio_timer_get_out(t->limit, t->counthigh, t->count); - t->count = count & TIMER_COUNT_MASK32; - t->counthigh = count >> 32; -} - -// timer callback -static void slavio_timer_irq(void *opaque) -{ - TimerContext *tc = opaque; - SLAVIO_TIMERState *s = tc->s; - CPUTimerState *t = &s->cputimer[tc->timer_index]; - - slavio_timer_get_out(t); - trace_slavio_timer_irq(t->counthigh, t->count); - /* if limit is 0 (free-run), there will be no match */ - if (t->limit != 0) { - t->reached = TIMER_REACHED; - } - /* there is no interrupt if user timer or free-run */ - if (!slavio_timer_is_user(tc) && t->limit != 0) { - qemu_irq_raise(t->irq); - } -} - -static uint64_t slavio_timer_mem_readl(void *opaque, hwaddr addr, - unsigned size) -{ - TimerContext *tc = opaque; - SLAVIO_TIMERState *s = tc->s; - uint32_t saddr, ret; - unsigned int timer_index = tc->timer_index; - CPUTimerState *t = &s->cputimer[timer_index]; - - saddr = addr >> 2; - switch (saddr) { - case TIMER_LIMIT: - // read limit (system counter mode) or read most signifying - // part of counter (user mode) - if (slavio_timer_is_user(tc)) { - // read user timer MSW - slavio_timer_get_out(t); - ret = t->counthigh | t->reached; - } else { - // read limit - // clear irq - qemu_irq_lower(t->irq); - t->reached = 0; - ret = t->limit & TIMER_LIMIT_MASK32; - } - break; - case TIMER_COUNTER: - // read counter and reached bit (system mode) or read lsbits - // of counter (user mode) - slavio_timer_get_out(t); - if (slavio_timer_is_user(tc)) { // read user timer LSW - ret = t->count & TIMER_MAX_COUNT64; - } else { // read limit - ret = (t->count & TIMER_MAX_COUNT32) | - t->reached; - } - break; - case TIMER_STATUS: - // only available in processor counter/timer - // read start/stop status - if (timer_index > 0) { - ret = t->run; - } else { - ret = 0; - } - break; - case TIMER_MODE: - // only available in system counter - // read user/system mode - ret = s->cputimer_mode; - break; - default: - trace_slavio_timer_mem_readl_invalid(addr); - ret = 0; - break; - } - trace_slavio_timer_mem_readl(addr, ret); - return ret; -} - -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 const MemoryRegionOps slavio_timer_mem_ops = { - .read = slavio_timer_mem_readl, - .write = slavio_timer_mem_writel, - .endianness = DEVICE_NATIVE_ENDIAN, - .valid = { - .min_access_size = 4, - .max_access_size = 4, - }, -}; - -static const VMStateDescription vmstate_timer = { - .name ="timer", - .version_id = 3, - .minimum_version_id = 3, - .fields = (VMStateField[]) { - VMSTATE_UINT64(limit, CPUTimerState), - VMSTATE_UINT32(count, CPUTimerState), - VMSTATE_UINT32(counthigh, CPUTimerState), - VMSTATE_UINT32(reached, CPUTimerState), - VMSTATE_UINT32(run , CPUTimerState), - VMSTATE_PTIMER(timer, CPUTimerState), - VMSTATE_END_OF_LIST() - } -}; - -static const VMStateDescription vmstate_slavio_timer = { - .name ="slavio_timer", - .version_id = 3, - .minimum_version_id = 3, - .fields = (VMStateField[]) { - VMSTATE_STRUCT_ARRAY(cputimer, SLAVIO_TIMERState, MAX_CPUS + 1, 3, - vmstate_timer, CPUTimerState), - VMSTATE_END_OF_LIST() - } -}; - -static void slavio_timer_reset(DeviceState *d) -{ - SLAVIO_TIMERState *s = SLAVIO_TIMER(d); - unsigned int i; - CPUTimerState *curr_timer; - - for (i = 0; i <= MAX_CPUS; i++) { - curr_timer = &s->cputimer[i]; - curr_timer->limit = 0; - curr_timer->count = 0; - curr_timer->reached = 0; - if (i <= s->num_cpus) { - ptimer_set_limit(curr_timer->timer, - LIMIT_TO_PERIODS(TIMER_MAX_COUNT32), 1); - ptimer_run(curr_timer->timer, 0); - curr_timer->run = 1; - } - } - s->cputimer_mode = 0; -} - -static int slavio_timer_init1(SysBusDevice *dev) -{ - SLAVIO_TIMERState *s = SLAVIO_TIMER(dev); - QEMUBH *bh; - unsigned int i; - TimerContext *tc; - - for (i = 0; i <= MAX_CPUS; i++) { - uint64_t size; - char timer_name[20]; - - tc = g_malloc0(sizeof(TimerContext)); - tc->s = s; - tc->timer_index = i; - - bh = qemu_bh_new(slavio_timer_irq, tc); - s->cputimer[i].timer = ptimer_init(bh); - ptimer_set_period(s->cputimer[i].timer, TIMER_PERIOD); - - size = i == 0 ? SYS_TIMER_SIZE : CPU_TIMER_SIZE; - snprintf(timer_name, sizeof(timer_name), "timer-%i", i); - memory_region_init_io(&tc->iomem, OBJECT(s), &slavio_timer_mem_ops, tc, - timer_name, size); - sysbus_init_mmio(dev, &tc->iomem); - - sysbus_init_irq(dev, &s->cputimer[i].irq); - } - - return 0; -} - -static Property slavio_timer_properties[] = { - DEFINE_PROP_UINT32("num_cpus", SLAVIO_TIMERState, num_cpus, 0), - DEFINE_PROP_END_OF_LIST(), -}; - -static void slavio_timer_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); - - k->init = slavio_timer_init1; - dc->reset = slavio_timer_reset; - dc->vmsd = &vmstate_slavio_timer; - dc->props = slavio_timer_properties; -} - -static const TypeInfo slavio_timer_info = { - .name = TYPE_SLAVIO_TIMER, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(SLAVIO_TIMERState), - .class_init = slavio_timer_class_init, -}; - -static void slavio_timer_register_types(void) -{ - type_register_static(&slavio_timer_info); -} - -type_init(slavio_timer_register_types) diff --git a/qemu/hw/timer/stm32f2xx_timer.c b/qemu/hw/timer/stm32f2xx_timer.c deleted file mode 100644 index 55dacbbe3..000000000 --- a/qemu/hw/timer/stm32f2xx_timer.c +++ /dev/null @@ -1,329 +0,0 @@ -/* - * STM32F2XX Timer - * - * Copyright (c) 2014 Alistair Francis <alistair@alistair23.me> - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#include "qemu/osdep.h" -#include "hw/timer/stm32f2xx_timer.h" - -#ifndef STM_TIMER_ERR_DEBUG -#define STM_TIMER_ERR_DEBUG 0 -#endif - -#define DB_PRINT_L(lvl, fmt, args...) do { \ - if (STM_TIMER_ERR_DEBUG >= lvl) { \ - qemu_log("%s: " fmt, __func__, ## args); \ - } \ -} while (0); - -#define DB_PRINT(fmt, args...) DB_PRINT_L(1, fmt, ## args) - -static void stm32f2xx_timer_set_alarm(STM32F2XXTimerState *s, int64_t now); - -static void stm32f2xx_timer_interrupt(void *opaque) -{ - STM32F2XXTimerState *s = opaque; - - DB_PRINT("Interrupt\n"); - - if (s->tim_dier & TIM_DIER_UIE && s->tim_cr1 & TIM_CR1_CEN) { - s->tim_sr |= 1; - qemu_irq_pulse(s->irq); - stm32f2xx_timer_set_alarm(s, s->hit_time); - } -} - -static inline int64_t stm32f2xx_ns_to_ticks(STM32F2XXTimerState *s, int64_t t) -{ - return muldiv64(t, s->freq_hz, 1000000000ULL) / (s->tim_psc + 1); -} - -static void stm32f2xx_timer_set_alarm(STM32F2XXTimerState *s, int64_t now) -{ - uint64_t ticks; - int64_t now_ticks; - - if (s->tim_arr == 0) { - return; - } - - DB_PRINT("Alarm set at: 0x%x\n", s->tim_cr1); - - now_ticks = stm32f2xx_ns_to_ticks(s, now); - ticks = s->tim_arr - (now_ticks - s->tick_offset); - - DB_PRINT("Alarm set in %d ticks\n", (int) ticks); - - s->hit_time = muldiv64((ticks + (uint64_t) now_ticks) * (s->tim_psc + 1), - 1000000000ULL, s->freq_hz); - - timer_mod(s->timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + s->hit_time); - DB_PRINT("Wait Time: %" PRId64 " ticks\n", s->hit_time); -} - -static void stm32f2xx_timer_reset(DeviceState *dev) -{ - STM32F2XXTimerState *s = STM32F2XXTIMER(dev); - int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); - - s->tim_cr1 = 0; - s->tim_cr2 = 0; - s->tim_smcr = 0; - s->tim_dier = 0; - s->tim_sr = 0; - s->tim_egr = 0; - s->tim_ccmr1 = 0; - s->tim_ccmr2 = 0; - s->tim_ccer = 0; - s->tim_psc = 0; - s->tim_arr = 0; - s->tim_ccr1 = 0; - s->tim_ccr2 = 0; - s->tim_ccr3 = 0; - s->tim_ccr4 = 0; - s->tim_dcr = 0; - s->tim_dmar = 0; - s->tim_or = 0; - - s->tick_offset = stm32f2xx_ns_to_ticks(s, now); -} - -static uint64_t stm32f2xx_timer_read(void *opaque, hwaddr offset, - unsigned size) -{ - STM32F2XXTimerState *s = opaque; - - DB_PRINT("Read 0x%"HWADDR_PRIx"\n", offset); - - switch (offset) { - case TIM_CR1: - return s->tim_cr1; - case TIM_CR2: - return s->tim_cr2; - case TIM_SMCR: - return s->tim_smcr; - case TIM_DIER: - return s->tim_dier; - case TIM_SR: - return s->tim_sr; - case TIM_EGR: - return s->tim_egr; - case TIM_CCMR1: - return s->tim_ccmr1; - case TIM_CCMR2: - return s->tim_ccmr2; - case TIM_CCER: - return s->tim_ccer; - case TIM_CNT: - return stm32f2xx_ns_to_ticks(s, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL)) - - s->tick_offset; - case TIM_PSC: - return s->tim_psc; - case TIM_ARR: - return s->tim_arr; - case TIM_CCR1: - return s->tim_ccr1; - case TIM_CCR2: - return s->tim_ccr2; - case TIM_CCR3: - return s->tim_ccr3; - case TIM_CCR4: - return s->tim_ccr4; - case TIM_DCR: - return s->tim_dcr; - case TIM_DMAR: - return s->tim_dmar; - case TIM_OR: - return s->tim_or; - default: - qemu_log_mask(LOG_GUEST_ERROR, - "%s: Bad offset 0x%"HWADDR_PRIx"\n", __func__, offset); - } - - return 0; -} - -static void stm32f2xx_timer_write(void *opaque, hwaddr offset, - uint64_t val64, unsigned size) -{ - STM32F2XXTimerState *s = opaque; - uint32_t value = val64; - int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); - uint32_t timer_val = 0; - - DB_PRINT("Write 0x%x, 0x%"HWADDR_PRIx"\n", value, offset); - - switch (offset) { - case TIM_CR1: - s->tim_cr1 = value; - return; - case TIM_CR2: - s->tim_cr2 = value; - return; - case TIM_SMCR: - s->tim_smcr = value; - return; - case TIM_DIER: - s->tim_dier = value; - return; - case TIM_SR: - /* This is set by hardware and cleared by software */ - s->tim_sr &= value; - return; - case TIM_EGR: - s->tim_egr = value; - if (s->tim_egr & TIM_EGR_UG) { - timer_val = 0; - break; - } - return; - case TIM_CCMR1: - s->tim_ccmr1 = value; - return; - case TIM_CCMR2: - s->tim_ccmr2 = value; - return; - case TIM_CCER: - s->tim_ccer = value; - return; - case TIM_PSC: - timer_val = stm32f2xx_ns_to_ticks(s, now) - s->tick_offset; - s->tim_psc = value; - value = timer_val; - break; - case TIM_CNT: - timer_val = value; - break; - case TIM_ARR: - s->tim_arr = value; - stm32f2xx_timer_set_alarm(s, now); - return; - case TIM_CCR1: - s->tim_ccr1 = value; - return; - case TIM_CCR2: - s->tim_ccr2 = value; - return; - case TIM_CCR3: - s->tim_ccr3 = value; - return; - case TIM_CCR4: - s->tim_ccr4 = value; - return; - case TIM_DCR: - s->tim_dcr = value; - return; - case TIM_DMAR: - s->tim_dmar = value; - return; - case TIM_OR: - s->tim_or = value; - return; - default: - qemu_log_mask(LOG_GUEST_ERROR, - "%s: Bad offset 0x%"HWADDR_PRIx"\n", __func__, offset); - return; - } - - /* This means that a register write has affected the timer in a way that - * requires a refresh of both tick_offset and the alarm. - */ - s->tick_offset = stm32f2xx_ns_to_ticks(s, now) - timer_val; - stm32f2xx_timer_set_alarm(s, now); -} - -static const MemoryRegionOps stm32f2xx_timer_ops = { - .read = stm32f2xx_timer_read, - .write = stm32f2xx_timer_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static const VMStateDescription vmstate_stm32f2xx_timer = { - .name = TYPE_STM32F2XX_TIMER, - .version_id = 1, - .minimum_version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_INT64(tick_offset, STM32F2XXTimerState), - VMSTATE_UINT32(tim_cr1, STM32F2XXTimerState), - VMSTATE_UINT32(tim_cr2, STM32F2XXTimerState), - VMSTATE_UINT32(tim_smcr, STM32F2XXTimerState), - VMSTATE_UINT32(tim_dier, STM32F2XXTimerState), - VMSTATE_UINT32(tim_sr, STM32F2XXTimerState), - VMSTATE_UINT32(tim_egr, STM32F2XXTimerState), - VMSTATE_UINT32(tim_ccmr1, STM32F2XXTimerState), - VMSTATE_UINT32(tim_ccmr2, STM32F2XXTimerState), - VMSTATE_UINT32(tim_ccer, STM32F2XXTimerState), - VMSTATE_UINT32(tim_psc, STM32F2XXTimerState), - VMSTATE_UINT32(tim_arr, STM32F2XXTimerState), - VMSTATE_UINT32(tim_ccr1, STM32F2XXTimerState), - VMSTATE_UINT32(tim_ccr2, STM32F2XXTimerState), - VMSTATE_UINT32(tim_ccr3, STM32F2XXTimerState), - VMSTATE_UINT32(tim_ccr4, STM32F2XXTimerState), - VMSTATE_UINT32(tim_dcr, STM32F2XXTimerState), - VMSTATE_UINT32(tim_dmar, STM32F2XXTimerState), - VMSTATE_UINT32(tim_or, STM32F2XXTimerState), - VMSTATE_END_OF_LIST() - } -}; - -static Property stm32f2xx_timer_properties[] = { - DEFINE_PROP_UINT64("clock-frequency", struct STM32F2XXTimerState, - freq_hz, 1000000000), - DEFINE_PROP_END_OF_LIST(), -}; - -static void stm32f2xx_timer_init(Object *obj) -{ - STM32F2XXTimerState *s = STM32F2XXTIMER(obj); - - sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->irq); - - memory_region_init_io(&s->iomem, obj, &stm32f2xx_timer_ops, s, - "stm32f2xx_timer", 0x4000); - sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->iomem); - - s->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, stm32f2xx_timer_interrupt, s); -} - -static void stm32f2xx_timer_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - - dc->reset = stm32f2xx_timer_reset; - dc->props = stm32f2xx_timer_properties; - dc->vmsd = &vmstate_stm32f2xx_timer; -} - -static const TypeInfo stm32f2xx_timer_info = { - .name = TYPE_STM32F2XX_TIMER, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(STM32F2XXTimerState), - .instance_init = stm32f2xx_timer_init, - .class_init = stm32f2xx_timer_class_init, -}; - -static void stm32f2xx_timer_register_types(void) -{ - type_register_static(&stm32f2xx_timer_info); -} - -type_init(stm32f2xx_timer_register_types) diff --git a/qemu/hw/timer/twl92230.c b/qemu/hw/timer/twl92230.c deleted file mode 100644 index 7ba4e9a7c..000000000 --- a/qemu/hw/timer/twl92230.c +++ /dev/null @@ -1,889 +0,0 @@ -/* - * TI TWL92230C energy-management companion device for the OMAP24xx. - * Aka. Menelaus (N4200 MENELAUS1_V2.2) - * - * Copyright (C) 2008 Nokia Corporation - * Written by Andrzej Zaborowski <andrew@openedhand.com> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 or - * (at your option) version 3 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, see <http://www.gnu.org/licenses/>. - */ - -#include "qemu/osdep.h" -#include "hw/hw.h" -#include "qemu/timer.h" -#include "hw/i2c/i2c.h" -#include "sysemu/sysemu.h" -#include "ui/console.h" -#include "qemu/bcd.h" - -#define VERBOSE 1 - -#define TYPE_TWL92230 "twl92230" -#define TWL92230(obj) OBJECT_CHECK(MenelausState, (obj), TYPE_TWL92230) - -typedef struct MenelausState { - I2CSlave parent_obj; - - int firstbyte; - uint8_t reg; - - uint8_t vcore[5]; - uint8_t dcdc[3]; - uint8_t ldo[8]; - uint8_t sleep[2]; - uint8_t osc; - uint8_t detect; - uint16_t mask; - uint16_t status; - uint8_t dir; - uint8_t inputs; - uint8_t outputs; - uint8_t bbsms; - uint8_t pull[4]; - uint8_t mmc_ctrl[3]; - uint8_t mmc_debounce; - struct { - uint8_t ctrl; - uint16_t comp; - QEMUTimer *hz_tm; - int64_t next; - struct tm tm; - struct tm new; - struct tm alm; - int sec_offset; - int alm_sec; - int next_comp; - } rtc; - uint16_t rtc_next_vmstate; - qemu_irq out[4]; - uint8_t pwrbtn_state; -} MenelausState; - -static inline void menelaus_update(MenelausState *s) -{ - qemu_set_irq(s->out[3], s->status & ~s->mask); -} - -static inline void menelaus_rtc_start(MenelausState *s) -{ - s->rtc.next += qemu_clock_get_ms(rtc_clock); - timer_mod(s->rtc.hz_tm, s->rtc.next); -} - -static inline void menelaus_rtc_stop(MenelausState *s) -{ - timer_del(s->rtc.hz_tm); - s->rtc.next -= qemu_clock_get_ms(rtc_clock); - if (s->rtc.next < 1) - s->rtc.next = 1; -} - -static void menelaus_rtc_update(MenelausState *s) -{ - qemu_get_timedate(&s->rtc.tm, s->rtc.sec_offset); -} - -static void menelaus_alm_update(MenelausState *s) -{ - if ((s->rtc.ctrl & 3) == 3) - s->rtc.alm_sec = qemu_timedate_diff(&s->rtc.alm) - s->rtc.sec_offset; -} - -static void menelaus_rtc_hz(void *opaque) -{ - MenelausState *s = (MenelausState *) opaque; - - s->rtc.next_comp --; - s->rtc.alm_sec --; - s->rtc.next += 1000; - timer_mod(s->rtc.hz_tm, s->rtc.next); - if ((s->rtc.ctrl >> 3) & 3) { /* EVERY */ - menelaus_rtc_update(s); - if (((s->rtc.ctrl >> 3) & 3) == 1 && !s->rtc.tm.tm_sec) - s->status |= 1 << 8; /* RTCTMR */ - else if (((s->rtc.ctrl >> 3) & 3) == 2 && !s->rtc.tm.tm_min) - s->status |= 1 << 8; /* RTCTMR */ - else if (!s->rtc.tm.tm_hour) - s->status |= 1 << 8; /* RTCTMR */ - } else - s->status |= 1 << 8; /* RTCTMR */ - if ((s->rtc.ctrl >> 1) & 1) { /* RTC_AL_EN */ - if (s->rtc.alm_sec == 0) - s->status |= 1 << 9; /* RTCALM */ - /* TODO: wake-up */ - } - if (s->rtc.next_comp <= 0) { - s->rtc.next -= muldiv64((int16_t) s->rtc.comp, 1000, 0x8000); - s->rtc.next_comp = 3600; - } - menelaus_update(s); -} - -static void menelaus_reset(I2CSlave *i2c) -{ - MenelausState *s = TWL92230(i2c); - - s->reg = 0x00; - - s->vcore[0] = 0x0c; /* XXX: X-loader needs 0x8c? check! */ - s->vcore[1] = 0x05; - s->vcore[2] = 0x02; - s->vcore[3] = 0x0c; - s->vcore[4] = 0x03; - s->dcdc[0] = 0x33; /* Depends on wiring */ - s->dcdc[1] = 0x03; - s->dcdc[2] = 0x00; - s->ldo[0] = 0x95; - s->ldo[1] = 0x7e; - s->ldo[2] = 0x00; - s->ldo[3] = 0x00; /* Depends on wiring */ - s->ldo[4] = 0x03; /* Depends on wiring */ - s->ldo[5] = 0x00; - s->ldo[6] = 0x00; - s->ldo[7] = 0x00; - s->sleep[0] = 0x00; - s->sleep[1] = 0x00; - s->osc = 0x01; - s->detect = 0x09; - s->mask = 0x0fff; - s->status = 0; - s->dir = 0x07; - s->outputs = 0x00; - s->bbsms = 0x00; - s->pull[0] = 0x00; - s->pull[1] = 0x00; - s->pull[2] = 0x00; - s->pull[3] = 0x00; - s->mmc_ctrl[0] = 0x03; - s->mmc_ctrl[1] = 0xc0; - s->mmc_ctrl[2] = 0x00; - s->mmc_debounce = 0x05; - - if (s->rtc.ctrl & 1) - menelaus_rtc_stop(s); - s->rtc.ctrl = 0x00; - s->rtc.comp = 0x0000; - s->rtc.next = 1000; - s->rtc.sec_offset = 0; - s->rtc.next_comp = 1800; - s->rtc.alm_sec = 1800; - s->rtc.alm.tm_sec = 0x00; - s->rtc.alm.tm_min = 0x00; - s->rtc.alm.tm_hour = 0x00; - s->rtc.alm.tm_mday = 0x01; - s->rtc.alm.tm_mon = 0x00; - s->rtc.alm.tm_year = 2004; - menelaus_update(s); -} - -static void menelaus_gpio_set(void *opaque, int line, int level) -{ - MenelausState *s = (MenelausState *) opaque; - - if (line < 3) { - /* No interrupt generated */ - s->inputs &= ~(1 << line); - s->inputs |= level << line; - return; - } - - if (!s->pwrbtn_state && level) { - s->status |= 1 << 11; /* PSHBTN */ - menelaus_update(s); - } - s->pwrbtn_state = level; -} - -#define MENELAUS_REV 0x01 -#define MENELAUS_VCORE_CTRL1 0x02 -#define MENELAUS_VCORE_CTRL2 0x03 -#define MENELAUS_VCORE_CTRL3 0x04 -#define MENELAUS_VCORE_CTRL4 0x05 -#define MENELAUS_VCORE_CTRL5 0x06 -#define MENELAUS_DCDC_CTRL1 0x07 -#define MENELAUS_DCDC_CTRL2 0x08 -#define MENELAUS_DCDC_CTRL3 0x09 -#define MENELAUS_LDO_CTRL1 0x0a -#define MENELAUS_LDO_CTRL2 0x0b -#define MENELAUS_LDO_CTRL3 0x0c -#define MENELAUS_LDO_CTRL4 0x0d -#define MENELAUS_LDO_CTRL5 0x0e -#define MENELAUS_LDO_CTRL6 0x0f -#define MENELAUS_LDO_CTRL7 0x10 -#define MENELAUS_LDO_CTRL8 0x11 -#define MENELAUS_SLEEP_CTRL1 0x12 -#define MENELAUS_SLEEP_CTRL2 0x13 -#define MENELAUS_DEVICE_OFF 0x14 -#define MENELAUS_OSC_CTRL 0x15 -#define MENELAUS_DETECT_CTRL 0x16 -#define MENELAUS_INT_MASK1 0x17 -#define MENELAUS_INT_MASK2 0x18 -#define MENELAUS_INT_STATUS1 0x19 -#define MENELAUS_INT_STATUS2 0x1a -#define MENELAUS_INT_ACK1 0x1b -#define MENELAUS_INT_ACK2 0x1c -#define MENELAUS_GPIO_CTRL 0x1d -#define MENELAUS_GPIO_IN 0x1e -#define MENELAUS_GPIO_OUT 0x1f -#define MENELAUS_BBSMS 0x20 -#define MENELAUS_RTC_CTRL 0x21 -#define MENELAUS_RTC_UPDATE 0x22 -#define MENELAUS_RTC_SEC 0x23 -#define MENELAUS_RTC_MIN 0x24 -#define MENELAUS_RTC_HR 0x25 -#define MENELAUS_RTC_DAY 0x26 -#define MENELAUS_RTC_MON 0x27 -#define MENELAUS_RTC_YR 0x28 -#define MENELAUS_RTC_WKDAY 0x29 -#define MENELAUS_RTC_AL_SEC 0x2a -#define MENELAUS_RTC_AL_MIN 0x2b -#define MENELAUS_RTC_AL_HR 0x2c -#define MENELAUS_RTC_AL_DAY 0x2d -#define MENELAUS_RTC_AL_MON 0x2e -#define MENELAUS_RTC_AL_YR 0x2f -#define MENELAUS_RTC_COMP_MSB 0x30 -#define MENELAUS_RTC_COMP_LSB 0x31 -#define MENELAUS_S1_PULL_EN 0x32 -#define MENELAUS_S1_PULL_DIR 0x33 -#define MENELAUS_S2_PULL_EN 0x34 -#define MENELAUS_S2_PULL_DIR 0x35 -#define MENELAUS_MCT_CTRL1 0x36 -#define MENELAUS_MCT_CTRL2 0x37 -#define MENELAUS_MCT_CTRL3 0x38 -#define MENELAUS_MCT_PIN_ST 0x39 -#define MENELAUS_DEBOUNCE1 0x3a - -static uint8_t menelaus_read(void *opaque, uint8_t addr) -{ - MenelausState *s = (MenelausState *) opaque; - int reg = 0; - - switch (addr) { - case MENELAUS_REV: - return 0x22; - - case MENELAUS_VCORE_CTRL5: reg ++; - case MENELAUS_VCORE_CTRL4: reg ++; - case MENELAUS_VCORE_CTRL3: reg ++; - case MENELAUS_VCORE_CTRL2: reg ++; - case MENELAUS_VCORE_CTRL1: - return s->vcore[reg]; - - case MENELAUS_DCDC_CTRL3: reg ++; - case MENELAUS_DCDC_CTRL2: reg ++; - case MENELAUS_DCDC_CTRL1: - return s->dcdc[reg]; - - case MENELAUS_LDO_CTRL8: reg ++; - case MENELAUS_LDO_CTRL7: reg ++; - case MENELAUS_LDO_CTRL6: reg ++; - case MENELAUS_LDO_CTRL5: reg ++; - case MENELAUS_LDO_CTRL4: reg ++; - case MENELAUS_LDO_CTRL3: reg ++; - case MENELAUS_LDO_CTRL2: reg ++; - case MENELAUS_LDO_CTRL1: - return s->ldo[reg]; - - case MENELAUS_SLEEP_CTRL2: reg ++; - case MENELAUS_SLEEP_CTRL1: - return s->sleep[reg]; - - case MENELAUS_DEVICE_OFF: - return 0; - - case MENELAUS_OSC_CTRL: - return s->osc | (1 << 7); /* CLK32K_GOOD */ - - case MENELAUS_DETECT_CTRL: - return s->detect; - - case MENELAUS_INT_MASK1: - return (s->mask >> 0) & 0xff; - case MENELAUS_INT_MASK2: - return (s->mask >> 8) & 0xff; - - case MENELAUS_INT_STATUS1: - return (s->status >> 0) & 0xff; - case MENELAUS_INT_STATUS2: - return (s->status >> 8) & 0xff; - - case MENELAUS_INT_ACK1: - case MENELAUS_INT_ACK2: - return 0; - - case MENELAUS_GPIO_CTRL: - return s->dir; - case MENELAUS_GPIO_IN: - return s->inputs | (~s->dir & s->outputs); - case MENELAUS_GPIO_OUT: - return s->outputs; - - case MENELAUS_BBSMS: - return s->bbsms; - - case MENELAUS_RTC_CTRL: - return s->rtc.ctrl; - case MENELAUS_RTC_UPDATE: - return 0x00; - case MENELAUS_RTC_SEC: - menelaus_rtc_update(s); - return to_bcd(s->rtc.tm.tm_sec); - case MENELAUS_RTC_MIN: - menelaus_rtc_update(s); - return to_bcd(s->rtc.tm.tm_min); - case MENELAUS_RTC_HR: - menelaus_rtc_update(s); - if ((s->rtc.ctrl >> 2) & 1) /* MODE12_n24 */ - return to_bcd((s->rtc.tm.tm_hour % 12) + 1) | - (!!(s->rtc.tm.tm_hour >= 12) << 7); /* PM_nAM */ - else - return to_bcd(s->rtc.tm.tm_hour); - case MENELAUS_RTC_DAY: - menelaus_rtc_update(s); - return to_bcd(s->rtc.tm.tm_mday); - case MENELAUS_RTC_MON: - menelaus_rtc_update(s); - return to_bcd(s->rtc.tm.tm_mon + 1); - case MENELAUS_RTC_YR: - menelaus_rtc_update(s); - return to_bcd(s->rtc.tm.tm_year - 2000); - case MENELAUS_RTC_WKDAY: - menelaus_rtc_update(s); - return to_bcd(s->rtc.tm.tm_wday); - case MENELAUS_RTC_AL_SEC: - return to_bcd(s->rtc.alm.tm_sec); - case MENELAUS_RTC_AL_MIN: - return to_bcd(s->rtc.alm.tm_min); - case MENELAUS_RTC_AL_HR: - if ((s->rtc.ctrl >> 2) & 1) /* MODE12_n24 */ - return to_bcd((s->rtc.alm.tm_hour % 12) + 1) | - (!!(s->rtc.alm.tm_hour >= 12) << 7);/* AL_PM_nAM */ - else - return to_bcd(s->rtc.alm.tm_hour); - case MENELAUS_RTC_AL_DAY: - return to_bcd(s->rtc.alm.tm_mday); - case MENELAUS_RTC_AL_MON: - return to_bcd(s->rtc.alm.tm_mon + 1); - case MENELAUS_RTC_AL_YR: - return to_bcd(s->rtc.alm.tm_year - 2000); - case MENELAUS_RTC_COMP_MSB: - return (s->rtc.comp >> 8) & 0xff; - case MENELAUS_RTC_COMP_LSB: - return (s->rtc.comp >> 0) & 0xff; - - case MENELAUS_S1_PULL_EN: - return s->pull[0]; - case MENELAUS_S1_PULL_DIR: - return s->pull[1]; - case MENELAUS_S2_PULL_EN: - return s->pull[2]; - case MENELAUS_S2_PULL_DIR: - return s->pull[3]; - - case MENELAUS_MCT_CTRL3: reg ++; - case MENELAUS_MCT_CTRL2: reg ++; - case MENELAUS_MCT_CTRL1: - return s->mmc_ctrl[reg]; - case MENELAUS_MCT_PIN_ST: - /* TODO: return the real Card Detect */ - return 0; - case MENELAUS_DEBOUNCE1: - return s->mmc_debounce; - - default: -#ifdef VERBOSE - printf("%s: unknown register %02x\n", __FUNCTION__, addr); -#endif - break; - } - return 0; -} - -static void menelaus_write(void *opaque, uint8_t addr, uint8_t value) -{ - MenelausState *s = (MenelausState *) opaque; - int line; - int reg = 0; - struct tm tm; - - switch (addr) { - case MENELAUS_VCORE_CTRL1: - s->vcore[0] = (value & 0xe) | MIN(value & 0x1f, 0x12); - break; - case MENELAUS_VCORE_CTRL2: - s->vcore[1] = value; - break; - case MENELAUS_VCORE_CTRL3: - s->vcore[2] = MIN(value & 0x1f, 0x12); - break; - case MENELAUS_VCORE_CTRL4: - s->vcore[3] = MIN(value & 0x1f, 0x12); - break; - case MENELAUS_VCORE_CTRL5: - s->vcore[4] = value & 3; - /* XXX - * auto set to 3 on M_Active, nRESWARM - * auto set to 0 on M_WaitOn, M_Backup - */ - break; - - case MENELAUS_DCDC_CTRL1: - s->dcdc[0] = value & 0x3f; - break; - case MENELAUS_DCDC_CTRL2: - s->dcdc[1] = value & 0x07; - /* XXX - * auto set to 3 on M_Active, nRESWARM - * auto set to 0 on M_WaitOn, M_Backup - */ - break; - case MENELAUS_DCDC_CTRL3: - s->dcdc[2] = value & 0x07; - break; - - case MENELAUS_LDO_CTRL1: - s->ldo[0] = value; - break; - case MENELAUS_LDO_CTRL2: - s->ldo[1] = value & 0x7f; - /* XXX - * auto set to 0x7e on M_WaitOn, M_Backup - */ - break; - case MENELAUS_LDO_CTRL3: - s->ldo[2] = value & 3; - /* XXX - * auto set to 3 on M_Active, nRESWARM - * auto set to 0 on M_WaitOn, M_Backup - */ - break; - case MENELAUS_LDO_CTRL4: - s->ldo[3] = value & 3; - /* XXX - * auto set to 3 on M_Active, nRESWARM - * auto set to 0 on M_WaitOn, M_Backup - */ - break; - case MENELAUS_LDO_CTRL5: - s->ldo[4] = value & 3; - /* XXX - * auto set to 3 on M_Active, nRESWARM - * auto set to 0 on M_WaitOn, M_Backup - */ - break; - case MENELAUS_LDO_CTRL6: - s->ldo[5] = value & 3; - break; - case MENELAUS_LDO_CTRL7: - s->ldo[6] = value & 3; - break; - case MENELAUS_LDO_CTRL8: - s->ldo[7] = value & 3; - break; - - case MENELAUS_SLEEP_CTRL2: reg ++; - case MENELAUS_SLEEP_CTRL1: - s->sleep[reg] = value; - break; - - case MENELAUS_DEVICE_OFF: - if (value & 1) { - menelaus_reset(I2C_SLAVE(s)); - } - break; - - case MENELAUS_OSC_CTRL: - s->osc = value & 7; - break; - - case MENELAUS_DETECT_CTRL: - s->detect = value & 0x7f; - break; - - case MENELAUS_INT_MASK1: - s->mask &= 0xf00; - s->mask |= value << 0; - menelaus_update(s); - break; - case MENELAUS_INT_MASK2: - s->mask &= 0x0ff; - s->mask |= value << 8; - menelaus_update(s); - break; - - case MENELAUS_INT_ACK1: - s->status &= ~(((uint16_t) value) << 0); - menelaus_update(s); - break; - case MENELAUS_INT_ACK2: - s->status &= ~(((uint16_t) value) << 8); - menelaus_update(s); - break; - - case MENELAUS_GPIO_CTRL: - for (line = 0; line < 3; line ++) { - if (((s->dir ^ value) >> line) & 1) { - qemu_set_irq(s->out[line], - ((s->outputs & ~s->dir) >> line) & 1); - } - } - s->dir = value & 0x67; - break; - case MENELAUS_GPIO_OUT: - for (line = 0; line < 3; line ++) { - if ((((s->outputs ^ value) & ~s->dir) >> line) & 1) { - qemu_set_irq(s->out[line], (s->outputs >> line) & 1); - } - } - s->outputs = value & 0x07; - break; - - case MENELAUS_BBSMS: - s->bbsms = 0x0d; - break; - - case MENELAUS_RTC_CTRL: - if ((s->rtc.ctrl ^ value) & 1) { /* RTC_EN */ - if (value & 1) - menelaus_rtc_start(s); - else - menelaus_rtc_stop(s); - } - s->rtc.ctrl = value & 0x1f; - menelaus_alm_update(s); - break; - case MENELAUS_RTC_UPDATE: - menelaus_rtc_update(s); - memcpy(&tm, &s->rtc.tm, sizeof(tm)); - switch (value & 0xf) { - case 0: - break; - case 1: - tm.tm_sec = s->rtc.new.tm_sec; - break; - case 2: - tm.tm_min = s->rtc.new.tm_min; - break; - case 3: - if (s->rtc.new.tm_hour > 23) - goto rtc_badness; - tm.tm_hour = s->rtc.new.tm_hour; - break; - case 4: - if (s->rtc.new.tm_mday < 1) - goto rtc_badness; - /* TODO check range */ - tm.tm_mday = s->rtc.new.tm_mday; - break; - case 5: - if (s->rtc.new.tm_mon < 0 || s->rtc.new.tm_mon > 11) - goto rtc_badness; - tm.tm_mon = s->rtc.new.tm_mon; - break; - case 6: - tm.tm_year = s->rtc.new.tm_year; - break; - case 7: - /* TODO set .tm_mday instead */ - tm.tm_wday = s->rtc.new.tm_wday; - break; - case 8: - if (s->rtc.new.tm_hour > 23) - goto rtc_badness; - if (s->rtc.new.tm_mday < 1) - goto rtc_badness; - if (s->rtc.new.tm_mon < 0 || s->rtc.new.tm_mon > 11) - goto rtc_badness; - tm.tm_sec = s->rtc.new.tm_sec; - tm.tm_min = s->rtc.new.tm_min; - tm.tm_hour = s->rtc.new.tm_hour; - tm.tm_mday = s->rtc.new.tm_mday; - tm.tm_mon = s->rtc.new.tm_mon; - tm.tm_year = s->rtc.new.tm_year; - break; - rtc_badness: - default: - fprintf(stderr, "%s: bad RTC_UPDATE value %02x\n", - __FUNCTION__, value); - s->status |= 1 << 10; /* RTCERR */ - menelaus_update(s); - } - s->rtc.sec_offset = qemu_timedate_diff(&tm); - break; - case MENELAUS_RTC_SEC: - s->rtc.tm.tm_sec = from_bcd(value & 0x7f); - break; - case MENELAUS_RTC_MIN: - s->rtc.tm.tm_min = from_bcd(value & 0x7f); - break; - case MENELAUS_RTC_HR: - s->rtc.tm.tm_hour = (s->rtc.ctrl & (1 << 2)) ? /* MODE12_n24 */ - MIN(from_bcd(value & 0x3f), 12) + ((value >> 7) ? 11 : -1) : - from_bcd(value & 0x3f); - break; - case MENELAUS_RTC_DAY: - s->rtc.tm.tm_mday = from_bcd(value); - break; - case MENELAUS_RTC_MON: - s->rtc.tm.tm_mon = MAX(1, from_bcd(value)) - 1; - break; - case MENELAUS_RTC_YR: - s->rtc.tm.tm_year = 2000 + from_bcd(value); - break; - case MENELAUS_RTC_WKDAY: - s->rtc.tm.tm_mday = from_bcd(value); - break; - case MENELAUS_RTC_AL_SEC: - s->rtc.alm.tm_sec = from_bcd(value & 0x7f); - menelaus_alm_update(s); - break; - case MENELAUS_RTC_AL_MIN: - s->rtc.alm.tm_min = from_bcd(value & 0x7f); - menelaus_alm_update(s); - break; - case MENELAUS_RTC_AL_HR: - s->rtc.alm.tm_hour = (s->rtc.ctrl & (1 << 2)) ? /* MODE12_n24 */ - MIN(from_bcd(value & 0x3f), 12) + ((value >> 7) ? 11 : -1) : - from_bcd(value & 0x3f); - menelaus_alm_update(s); - break; - case MENELAUS_RTC_AL_DAY: - s->rtc.alm.tm_mday = from_bcd(value); - menelaus_alm_update(s); - break; - case MENELAUS_RTC_AL_MON: - s->rtc.alm.tm_mon = MAX(1, from_bcd(value)) - 1; - menelaus_alm_update(s); - break; - case MENELAUS_RTC_AL_YR: - s->rtc.alm.tm_year = 2000 + from_bcd(value); - menelaus_alm_update(s); - break; - case MENELAUS_RTC_COMP_MSB: - s->rtc.comp &= 0xff; - s->rtc.comp |= value << 8; - break; - case MENELAUS_RTC_COMP_LSB: - s->rtc.comp &= 0xff << 8; - s->rtc.comp |= value; - break; - - case MENELAUS_S1_PULL_EN: - s->pull[0] = value; - break; - case MENELAUS_S1_PULL_DIR: - s->pull[1] = value & 0x1f; - break; - case MENELAUS_S2_PULL_EN: - s->pull[2] = value; - break; - case MENELAUS_S2_PULL_DIR: - s->pull[3] = value & 0x1f; - break; - - case MENELAUS_MCT_CTRL1: - s->mmc_ctrl[0] = value & 0x7f; - break; - case MENELAUS_MCT_CTRL2: - s->mmc_ctrl[1] = value; - /* TODO update Card Detect interrupts */ - break; - case MENELAUS_MCT_CTRL3: - s->mmc_ctrl[2] = value & 0xf; - break; - case MENELAUS_DEBOUNCE1: - s->mmc_debounce = value & 0x3f; - break; - - default: -#ifdef VERBOSE - printf("%s: unknown register %02x\n", __FUNCTION__, addr); -#endif - } -} - -static void menelaus_event(I2CSlave *i2c, enum i2c_event event) -{ - MenelausState *s = TWL92230(i2c); - - if (event == I2C_START_SEND) - s->firstbyte = 1; -} - -static int menelaus_tx(I2CSlave *i2c, uint8_t data) -{ - MenelausState *s = TWL92230(i2c); - - /* Interpret register address byte */ - if (s->firstbyte) { - s->reg = data; - s->firstbyte = 0; - } else - menelaus_write(s, s->reg ++, data); - - return 0; -} - -static int menelaus_rx(I2CSlave *i2c) -{ - MenelausState *s = TWL92230(i2c); - - return menelaus_read(s, s->reg ++); -} - -/* Save restore 32 bit int as uint16_t - This is a Big hack, but it is how the old state did it. - Or we broke compatibility in the state, or we can't use struct tm - */ - -static int get_int32_as_uint16(QEMUFile *f, void *pv, size_t size) -{ - int *v = pv; - *v = qemu_get_be16(f); - return 0; -} - -static void put_int32_as_uint16(QEMUFile *f, void *pv, size_t size) -{ - int *v = pv; - qemu_put_be16(f, *v); -} - -static const VMStateInfo vmstate_hack_int32_as_uint16 = { - .name = "int32_as_uint16", - .get = get_int32_as_uint16, - .put = put_int32_as_uint16, -}; - -#define VMSTATE_UINT16_HACK(_f, _s) \ - VMSTATE_SINGLE(_f, _s, 0, vmstate_hack_int32_as_uint16, int32_t) - - -static const VMStateDescription vmstate_menelaus_tm = { - .name = "menelaus_tm", - .version_id = 0, - .minimum_version_id = 0, - .fields = (VMStateField[]) { - VMSTATE_UINT16_HACK(tm_sec, struct tm), - VMSTATE_UINT16_HACK(tm_min, struct tm), - VMSTATE_UINT16_HACK(tm_hour, struct tm), - VMSTATE_UINT16_HACK(tm_mday, struct tm), - VMSTATE_UINT16_HACK(tm_min, struct tm), - VMSTATE_UINT16_HACK(tm_year, struct tm), - VMSTATE_END_OF_LIST() - } -}; - -static void menelaus_pre_save(void *opaque) -{ - MenelausState *s = opaque; - /* Should be <= 1000 */ - s->rtc_next_vmstate = s->rtc.next - qemu_clock_get_ms(rtc_clock); -} - -static int menelaus_post_load(void *opaque, int version_id) -{ - MenelausState *s = opaque; - - if (s->rtc.ctrl & 1) /* RTC_EN */ - menelaus_rtc_stop(s); - - s->rtc.next = s->rtc_next_vmstate; - - menelaus_alm_update(s); - menelaus_update(s); - if (s->rtc.ctrl & 1) /* RTC_EN */ - menelaus_rtc_start(s); - return 0; -} - -static const VMStateDescription vmstate_menelaus = { - .name = "menelaus", - .version_id = 0, - .minimum_version_id = 0, - .pre_save = menelaus_pre_save, - .post_load = menelaus_post_load, - .fields = (VMStateField[]) { - VMSTATE_INT32(firstbyte, MenelausState), - VMSTATE_UINT8(reg, MenelausState), - VMSTATE_UINT8_ARRAY(vcore, MenelausState, 5), - VMSTATE_UINT8_ARRAY(dcdc, MenelausState, 3), - VMSTATE_UINT8_ARRAY(ldo, MenelausState, 8), - VMSTATE_UINT8_ARRAY(sleep, MenelausState, 2), - VMSTATE_UINT8(osc, MenelausState), - VMSTATE_UINT8(detect, MenelausState), - VMSTATE_UINT16(mask, MenelausState), - VMSTATE_UINT16(status, MenelausState), - VMSTATE_UINT8(dir, MenelausState), - VMSTATE_UINT8(inputs, MenelausState), - VMSTATE_UINT8(outputs, MenelausState), - VMSTATE_UINT8(bbsms, MenelausState), - VMSTATE_UINT8_ARRAY(pull, MenelausState, 4), - VMSTATE_UINT8_ARRAY(mmc_ctrl, MenelausState, 3), - VMSTATE_UINT8(mmc_debounce, MenelausState), - VMSTATE_UINT8(rtc.ctrl, MenelausState), - VMSTATE_UINT16(rtc.comp, MenelausState), - VMSTATE_UINT16(rtc_next_vmstate, MenelausState), - VMSTATE_STRUCT(rtc.new, MenelausState, 0, vmstate_menelaus_tm, - struct tm), - VMSTATE_STRUCT(rtc.alm, MenelausState, 0, vmstate_menelaus_tm, - struct tm), - VMSTATE_UINT8(pwrbtn_state, MenelausState), - VMSTATE_I2C_SLAVE(parent_obj, MenelausState), - VMSTATE_END_OF_LIST() - } -}; - -static int twl92230_init(I2CSlave *i2c) -{ - DeviceState *dev = DEVICE(i2c); - MenelausState *s = TWL92230(i2c); - - s->rtc.hz_tm = timer_new_ms(rtc_clock, menelaus_rtc_hz, s); - /* Three output pins plus one interrupt pin. */ - qdev_init_gpio_out(dev, s->out, 4); - - /* Three input pins plus one power-button pin. */ - qdev_init_gpio_in(dev, menelaus_gpio_set, 4); - - menelaus_reset(i2c); - - return 0; -} - -static void twl92230_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - I2CSlaveClass *sc = I2C_SLAVE_CLASS(klass); - - sc->init = twl92230_init; - sc->event = menelaus_event; - sc->recv = menelaus_rx; - sc->send = menelaus_tx; - dc->vmsd = &vmstate_menelaus; -} - -static const TypeInfo twl92230_info = { - .name = TYPE_TWL92230, - .parent = TYPE_I2C_SLAVE, - .instance_size = sizeof(MenelausState), - .class_init = twl92230_class_init, -}; - -static void twl92230_register_types(void) -{ - type_register_static(&twl92230_info); -} - -type_init(twl92230_register_types) diff --git a/qemu/hw/timer/xilinx_timer.c b/qemu/hw/timer/xilinx_timer.c deleted file mode 100644 index 2ea970dc9..000000000 --- a/qemu/hw/timer/xilinx_timer.c +++ /dev/null @@ -1,266 +0,0 @@ -/* - * QEMU model of the Xilinx timer block. - * - * Copyright (c) 2009 Edgar E. Iglesias. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#include "qemu/osdep.h" -#include "hw/sysbus.h" -#include "hw/ptimer.h" -#include "qemu/log.h" -#include "qemu/main-loop.h" - -#define D(x) - -#define R_TCSR 0 -#define R_TLR 1 -#define R_TCR 2 -#define R_MAX 4 - -#define TCSR_MDT (1<<0) -#define TCSR_UDT (1<<1) -#define TCSR_GENT (1<<2) -#define TCSR_CAPT (1<<3) -#define TCSR_ARHT (1<<4) -#define TCSR_LOAD (1<<5) -#define TCSR_ENIT (1<<6) -#define TCSR_ENT (1<<7) -#define TCSR_TINT (1<<8) -#define TCSR_PWMA (1<<9) -#define TCSR_ENALL (1<<10) - -struct xlx_timer -{ - QEMUBH *bh; - ptimer_state *ptimer; - void *parent; - int nr; /* for debug. */ - - unsigned long timer_div; - - uint32_t regs[R_MAX]; -}; - -#define TYPE_XILINX_TIMER "xlnx.xps-timer" -#define XILINX_TIMER(obj) \ - OBJECT_CHECK(struct timerblock, (obj), TYPE_XILINX_TIMER) - -struct timerblock -{ - SysBusDevice parent_obj; - - MemoryRegion mmio; - qemu_irq irq; - uint8_t one_timer_only; - uint32_t freq_hz; - struct xlx_timer *timers; -}; - -static inline unsigned int num_timers(struct timerblock *t) -{ - return 2 - t->one_timer_only; -} - -static inline unsigned int timer_from_addr(hwaddr addr) -{ - /* Timers get a 4x32bit control reg area each. */ - return addr >> 2; -} - -static void timer_update_irq(struct timerblock *t) -{ - unsigned int i, irq = 0; - uint32_t csr; - - for (i = 0; i < num_timers(t); i++) { - csr = t->timers[i].regs[R_TCSR]; - irq |= (csr & TCSR_TINT) && (csr & TCSR_ENIT); - } - - /* All timers within the same slave share a single IRQ line. */ - qemu_set_irq(t->irq, !!irq); -} - -static uint64_t -timer_read(void *opaque, hwaddr addr, unsigned int size) -{ - struct timerblock *t = opaque; - struct xlx_timer *xt; - uint32_t r = 0; - unsigned int timer; - - addr >>= 2; - timer = timer_from_addr(addr); - xt = &t->timers[timer]; - /* Further decoding to address a specific timers reg. */ - addr &= 0x3; - switch (addr) - { - case R_TCR: - r = ptimer_get_count(xt->ptimer); - if (!(xt->regs[R_TCSR] & TCSR_UDT)) - r = ~r; - D(qemu_log("xlx_timer t=%d read counter=%x udt=%d\n", - timer, r, xt->regs[R_TCSR] & TCSR_UDT)); - break; - default: - if (addr < ARRAY_SIZE(xt->regs)) - r = xt->regs[addr]; - break; - - } - D(fprintf(stderr, "%s timer=%d %x=%x\n", __func__, timer, addr * 4, r)); - return r; -} - -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 -timer_write(void *opaque, hwaddr addr, - uint64_t val64, unsigned int size) -{ - struct timerblock *t = opaque; - struct xlx_timer *xt; - unsigned int timer; - uint32_t value = val64; - - addr >>= 2; - timer = timer_from_addr(addr); - xt = &t->timers[timer]; - D(fprintf(stderr, "%s addr=%x val=%x (timer=%d off=%d)\n", - __func__, addr * 4, value, timer, addr & 3)); - /* Further decoding to address a specific timers reg. */ - addr &= 3; - switch (addr) - { - case R_TCSR: - if (value & TCSR_TINT) - value &= ~TCSR_TINT; - - xt->regs[addr] = value & 0x7ff; - if (value & TCSR_ENT) - timer_enable(xt); - break; - - default: - if (addr < ARRAY_SIZE(xt->regs)) - xt->regs[addr] = value; - break; - } - timer_update_irq(t); -} - -static const MemoryRegionOps timer_ops = { - .read = timer_read, - .write = timer_write, - .endianness = DEVICE_NATIVE_ENDIAN, - .valid = { - .min_access_size = 4, - .max_access_size = 4 - } -}; - -static void timer_hit(void *opaque) -{ - struct xlx_timer *xt = opaque; - struct timerblock *t = xt->parent; - D(fprintf(stderr, "%s %d\n", __func__, xt->nr)); - xt->regs[R_TCSR] |= TCSR_TINT; - - if (xt->regs[R_TCSR] & TCSR_ARHT) - timer_enable(xt); - timer_update_irq(t); -} - -static void xilinx_timer_realize(DeviceState *dev, Error **errp) -{ - struct timerblock *t = XILINX_TIMER(dev); - unsigned int i; - - /* Init all the ptimers. */ - t->timers = g_malloc0(sizeof t->timers[0] * num_timers(t)); - for (i = 0; i < num_timers(t); i++) { - struct xlx_timer *xt = &t->timers[i]; - - xt->parent = t; - xt->nr = i; - xt->bh = qemu_bh_new(timer_hit, xt); - xt->ptimer = ptimer_init(xt->bh); - ptimer_set_freq(xt->ptimer, t->freq_hz); - } - - memory_region_init_io(&t->mmio, OBJECT(t), &timer_ops, t, "xlnx.xps-timer", - R_MAX * 4 * num_timers(t)); - sysbus_init_mmio(SYS_BUS_DEVICE(dev), &t->mmio); -} - -static void xilinx_timer_init(Object *obj) -{ - struct timerblock *t = XILINX_TIMER(obj); - - /* All timers share a single irq line. */ - sysbus_init_irq(SYS_BUS_DEVICE(obj), &t->irq); -} - -static Property xilinx_timer_properties[] = { - DEFINE_PROP_UINT32("clock-frequency", struct timerblock, freq_hz, - 62 * 1000000), - DEFINE_PROP_UINT8("one-timer-only", struct timerblock, one_timer_only, 0), - DEFINE_PROP_END_OF_LIST(), -}; - -static void xilinx_timer_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - - dc->realize = xilinx_timer_realize; - dc->props = xilinx_timer_properties; -} - -static const TypeInfo xilinx_timer_info = { - .name = TYPE_XILINX_TIMER, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(struct timerblock), - .instance_init = xilinx_timer_init, - .class_init = xilinx_timer_class_init, -}; - -static void xilinx_timer_register_types(void) -{ - type_register_static(&xilinx_timer_info); -} - -type_init(xilinx_timer_register_types) |