Commit 399858185de1e8e35c237639fe2977eebe97469e

Authored by Filip Navara
1 parent f79f00fe

AT91 Real-Time Timer

This patch implements the RTT used on AT91 microcontrollers. All documented features are implemented.

Signed-off-by: Filip Navara <filip.navara@gmail.com>
Showing 2 changed files with 193 additions and 1 deletions
Makefile.target
... ... @@ -431,7 +431,7 @@ obj-arm-y += framebuffer.o
431 431 obj-arm-y += syborg.o syborg_fb.o syborg_interrupt.o syborg_keyboard.o
432 432 obj-arm-y += syborg_serial.o syborg_timer.o syborg_pointer.o syborg_rtc.o
433 433 obj-arm-y += syborg_virtio.o
434   -obj-arm-y += at91_aic.o at91_dbgu.o at91_pio.o at91_pit.o at91_pmc.o
  434 +obj-arm-y += at91_aic.o at91_dbgu.o at91_pio.o at91_pit.o at91_pmc.o at91_rtt.o
435 435 obj-arm-y += gpio_rotary.o gpio_keypad.o
436 436  
437 437 ifeq ($(TARGET_BASE_ARCH), arm)
... ...
hw/at91_rtt.c 0 → 100644
  1 +/*
  2 + * AT91 Real-time Timer
  3 + *
  4 + * Copyright (c) 2009 Filip Navara
  5 + *
  6 + * Permission is hereby granted, free of charge, to any person obtaining a copy
  7 + * of this software and associated documentation files (the "Software"), to deal
  8 + * in the Software without restriction, including without limitation the rights
  9 + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10 + * copies of the Software, and to permit persons to whom the Software is
  11 + * furnished to do so, subject to the following conditions:
  12 + *
  13 + * The above copyright notice and this permission notice shall be included in
  14 + * all copies or substantial portions of the Software.
  15 + *
  16 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  19 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21 + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  22 + * THE SOFTWARE.
  23 + */
  24 +
  25 +#include "sysbus.h"
  26 +#include "qemu-timer.h"
  27 +
  28 +#define RTT_SIZE 0x10
  29 +
  30 +#define RTT_MR 0x00 /* Mode Register */
  31 +#define RTT_AR 0x04 /* Alarm Register */
  32 +#define RTT_VR 0x08 /* Value Register */
  33 +#define RTT_SR 0x0c /* Status Register */
  34 +
  35 +#define MR_ALMIEN 0x10000
  36 +#define MR_RTTINCIEN 0x20000
  37 +#define MR_RTTRST 0x40000
  38 +
  39 +#define SR_ALMS 0x01
  40 +#define SR_RTTINC 0x02
  41 +
  42 +typedef struct RTTState {
  43 + SysBusDevice busdev;
  44 + qemu_irq irq;
  45 + ptimer_state *timer;
  46 + uint32_t mr;
  47 + uint32_t ar;
  48 + uint32_t vr;
  49 + uint32_t sr;
  50 +} RTTState;
  51 +
  52 +static void at91_rtt_tick(void *opaque)
  53 +{
  54 + RTTState *s = opaque;
  55 +
  56 + s->vr++;
  57 + s->sr |= SR_RTTINC;
  58 + if (s->ar != ~0 && s->vr == s->ar + 1) {
  59 + s->sr |= SR_ALMS;
  60 + }
  61 + if (((s->sr & SR_RTTINC) && (s->mr & MR_RTTINCIEN)) ||
  62 + ((s->sr & SR_ALMS) && (s->mr & MR_ALMIEN))) {
  63 + qemu_set_irq(s->irq, 1);
  64 + }
  65 +}
  66 +
  67 +static uint32_t at91_rtt_mem_read(void *opaque, target_phys_addr_t offset)
  68 +{
  69 + RTTState *s = opaque;
  70 + uint32_t sr;
  71 +
  72 + offset &= RTT_SIZE - 1;
  73 + switch (offset) {
  74 + case RTT_MR:
  75 + return s->mr;
  76 + case RTT_AR:
  77 + return s->ar;
  78 + case RTT_VR:
  79 + return s->vr;
  80 + case RTT_SR:
  81 + sr = s->sr;
  82 + qemu_set_irq(s->irq, 0);
  83 + s->sr = 0;
  84 + return sr;
  85 + default:
  86 + return 0;
  87 + }
  88 +}
  89 +
  90 +static void at91_rtt_mem_write(void *opaque, target_phys_addr_t offset,
  91 + uint32_t value)
  92 +{
  93 + RTTState *s = opaque;
  94 +
  95 + offset &= RTT_SIZE - 1;
  96 + switch (offset) {
  97 + case RTT_MR:
  98 + if (value & MR_RTTRST) {
  99 + s->vr = 0;
  100 + if ((value & 0xffff) == 0) {
  101 + ptimer_set_freq(s->timer, 1);
  102 + } else {
  103 + ptimer_set_freq(s->timer, 0x8000 / (value & 0xffff));
  104 + }
  105 + }
  106 + s->mr = value;
  107 + break;
  108 + case RTT_AR:
  109 + s->ar = value;
  110 + break;
  111 + }
  112 +}
  113 +
  114 +static CPUReadMemoryFunc *at91_rtt_readfn[] = {
  115 + at91_rtt_mem_read,
  116 + at91_rtt_mem_read,
  117 + at91_rtt_mem_read,
  118 +};
  119 +
  120 +static CPUWriteMemoryFunc *at91_rtt_writefn[] = {
  121 + at91_rtt_mem_write,
  122 + at91_rtt_mem_write,
  123 + at91_rtt_mem_write,
  124 +};
  125 +
  126 +static void at91_rtt_save(QEMUFile *f, void *opaque)
  127 +{
  128 + RTTState *s = opaque;
  129 +
  130 + qemu_put_be32(f, s->mr);
  131 + qemu_put_be32(f, s->ar);
  132 + qemu_put_be32(f, s->vr);
  133 + qemu_put_be32(f, s->sr);
  134 + qemu_put_ptimer(f, s->timer);
  135 +}
  136 +
  137 +static int at91_rtt_load(QEMUFile *f, void *opaque, int version_id)
  138 +{
  139 + RTTState *s = opaque;
  140 +
  141 + if (version_id != 1)
  142 + return -EINVAL;
  143 +
  144 + s->mr = qemu_get_be32(f);
  145 + s->ar = qemu_get_be32(f);
  146 + s->vr = qemu_get_be32(f);
  147 + s->sr = qemu_get_be32(f);
  148 + qemu_get_ptimer(f, s->timer);
  149 +
  150 + return 0;
  151 +}
  152 +
  153 +static void at91_rtt_reset(void *opaque)
  154 +{
  155 + RTTState *s = opaque;
  156 +
  157 + s->mr = 0x8000;
  158 + s->ar = ~0;
  159 + s->vr = 0;
  160 + s->sr = 0;
  161 +}
  162 +
  163 +static void at91_rtt_init(SysBusDevice *dev)
  164 +{
  165 + RTTState *s = FROM_SYSBUS(typeof (*s), dev);
  166 + QEMUBH *bh;
  167 + int rtt_regs;
  168 +
  169 + at91_rtt_reset(s);
  170 +
  171 + bh = qemu_bh_new(at91_rtt_tick, s);
  172 + s->timer = ptimer_init(bh);
  173 + ptimer_set_freq(s->timer, 1);
  174 + ptimer_set_limit(s->timer, 1, 1);
  175 + ptimer_run(s->timer, 0);
  176 +
  177 + sysbus_init_irq(dev, &s->irq);
  178 +
  179 + rtt_regs = cpu_register_io_memory(at91_rtt_readfn, at91_rtt_writefn, s);
  180 + sysbus_init_mmio(dev, RTT_SIZE, rtt_regs);
  181 +
  182 + qemu_register_reset(at91_rtt_reset, s);
  183 +
  184 + register_savevm("at91_rtt", -1, 1, at91_rtt_save, at91_rtt_load, s);
  185 +}
  186 +
  187 +static void at91_rtt_register(void)
  188 +{
  189 + sysbus_register_dev("at91,rtt", sizeof(RTTState), at91_rtt_init);
  190 +}
  191 +
  192 +device_init(at91_rtt_register)
... ...