From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1MR5qT-0006jv-GG for qemu-devel@nongnu.org; Wed, 15 Jul 2009 10:52:33 -0400 Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1MR5qN-0006Y6-MH for qemu-devel@nongnu.org; Wed, 15 Jul 2009 10:52:32 -0400 Received: from [199.232.76.173] (port=53477 helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1MR5qN-0006Xj-Ex for qemu-devel@nongnu.org; Wed, 15 Jul 2009 10:52:27 -0400 Received: from [82.113.48.144] (port=4818 helo=FilipNavara-PC) by monty-python.gnu.org with smtp (Exim 4.60) (envelope-from ) id 1MR5qM-0000bi-Qd for qemu-devel@nongnu.org; Wed, 15 Jul 2009 10:52:27 -0400 Date: Wed, 15 Jul 09 16:52:24 Central Europe Standard Time From: Filip Navara Sender: Filip Navara MIME-Version: 1.0 Content-Type: text/plain; Message-Id: Subject: [Qemu-devel] [PATCH 08/14] AT91 Real-Time Timer List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org This patch implements the RTT used on AT91 microcontrollers. All documented features are implemented. Signed-off-by: Filip Navara --- Makefile.target | 2 +- hw/at91_rtt.c | 181 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 182 insertions(+), 1 deletions(-) create mode 100644 hw/at91_rtt.c diff --git a/Makefile.target b/Makefile.target index b28edf9..8d7c7d1 100644 --- a/Makefile.target +++ b/Makefile.target @@ -666,7 +666,7 @@ obj-y += framebuffer.o obj-y += syborg.o syborg_fb.o syborg_interrupt.o syborg_keyboard.o obj-y += syborg_serial.o syborg_timer.o syborg_pointer.o syborg_rtc.o obj-y += syborg_virtio.o -obj-y += at91_aic.o at91_dbgu.o at91_pio.o at91_pit.o at91_pmc.o +obj-y += at91_aic.o at91_dbgu.o at91_pio.o at91_pit.o at91_pmc.o at91_rtt.o obj-y += gpio_rotary.o gpio_keypad.o CPPFLAGS += -DHAS_AUDIO endif diff --git a/hw/at91_rtt.c b/hw/at91_rtt.c new file mode 100644 index 0000000..5635933 --- /dev/null +++ b/hw/at91_rtt.c @@ -0,0 +1,181 @@ +/* + * AT91 Real-time Timer + * + * Copyright (c) 2009 Filip Navara + * + * 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 "sysbus.h" +#include "qemu-timer.h" + +#define RTT_SIZE 0x10 + +#define RTT_MR 0x00 /* Mode Register */ +#define RTT_AR 0x04 /* Alarm Register */ +#define RTT_VR 0x08 /* Value Register */ +#define RTT_SR 0x0c /* Status Register */ + +#define MR_ALMIEN 0x10000 +#define MR_RTTINCIEN 0x20000 +#define MR_RTTRST 0x40000 + +#define SR_ALMS 0x01 +#define SR_RTTINC 0x02 + +typedef struct RTTState { + SysBusDevice busdev; + qemu_irq irq; + ptimer_state *timer; + uint32_t mr; + uint32_t ar; + uint32_t vr; + uint32_t sr; +} RTTState; + +static void at91_rtt_tick(void *opaque) +{ + RTTState *s = opaque; + + s->vr++; + s->sr |= SR_RTTINC; + if (s->ar != ~0 && s->vr == s->ar + 1) { + s->sr |= SR_ALMS; + } + if (((s->sr & SR_RTTINC) && (s->mr & MR_RTTINCIEN)) || + ((s->sr & SR_ALMS) && (s->mr & MR_ALMIEN))) { + qemu_set_irq(s->irq, 1); + } +} + +static uint32_t at91_rtt_mem_read(void *opaque, target_phys_addr_t offset) +{ + RTTState *s = opaque; + uint32_t sr; + + offset &= RTT_SIZE - 1; + switch (offset) { + case RTT_MR: + return s->mr; + case RTT_AR: + return s->ar; + case RTT_VR: + return s->vr; + case RTT_SR: + sr = s->sr; + qemu_set_irq(s->irq, 0); + s->sr = 0; + return sr; + default: + return 0; + } +} + +static void at91_rtt_mem_write(void *opaque, target_phys_addr_t offset, + uint32_t value) +{ + RTTState *s = opaque; + + offset &= RTT_SIZE - 1; + switch (offset) { + case RTT_MR: + if (value & MR_RTTRST) { + s->vr = 0; + if ((value & 0xffff) == 0) { + ptimer_set_freq(s->timer, 1); + } else { + ptimer_set_freq(s->timer, 0x8000 / (value & 0xffff)); + } + } + s->mr = value; + break; + case RTT_AR: + s->ar = value; + break; + } +} + +static CPUReadMemoryFunc *at91_rtt_readfn[] = { + at91_rtt_mem_read, + at91_rtt_mem_read, + at91_rtt_mem_read, +}; + +static CPUWriteMemoryFunc *at91_rtt_writefn[] = { + at91_rtt_mem_write, + at91_rtt_mem_write, + at91_rtt_mem_write, +}; + +static void at91_rtt_save(QEMUFile *f, void *opaque) +{ + RTTState *s = opaque; + + qemu_put_be32(f, s->mr); + qemu_put_be32(f, s->ar); + qemu_put_be32(f, s->vr); + qemu_put_be32(f, s->sr); + qemu_put_ptimer(f, s->timer); +} + +static int at91_rtt_load(QEMUFile *f, void *opaque, int version_id) +{ + RTTState *s = opaque; + + if (version_id != 1) + return -EINVAL; + + s->mr = qemu_get_be32(f); + s->ar = qemu_get_be32(f); + s->vr = qemu_get_be32(f); + s->sr = qemu_get_be32(f); + qemu_get_ptimer(f, s->timer); + + return 0; +} + +static void at91_rtt_init(SysBusDevice *dev) +{ + RTTState *s = FROM_SYSBUS(typeof (*s), dev); + QEMUBH *bh; + int rtt_regs; + + s->mr = 0x8000; + s->ar = ~0; + + bh = qemu_bh_new(at91_rtt_tick, s); + s->timer = ptimer_init(bh); + ptimer_set_freq(s->timer, 1); + ptimer_set_limit(s->timer, 1, 1); + ptimer_run(s->timer, 0); + + sysbus_init_irq(dev, &s->irq); + + rtt_regs = cpu_register_io_memory(at91_rtt_readfn, at91_rtt_writefn, s); + sysbus_init_mmio(dev, RTT_SIZE, rtt_regs); + + register_savevm("at91_rtt", -1, 1, at91_rtt_save, at91_rtt_load, s); +} + +static void at91_rtt_register(void) +{ + sysbus_register_dev("at91,rtt", sizeof(RTTState), at91_rtt_init); +} + +device_init(at91_rtt_register) -- 1.6.3.msysgit.0