1/* Copyright (C) 2007-2008 The Android Open Source Project
2**
3** This software is licensed under the terms of the GNU General Public
4** License version 2, as published by the Free Software Foundation, and
5** may be copied, distributed, and modified under those terms.
6**
7** This program is distributed in the hope that it will be useful,
8** but WITHOUT ANY WARRANTY; without even the implied warranty of
9** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10** GNU General Public License for more details.
11*/
12#include "qemu-common.h"
13#include "qemu-timer.h"
14#include "cpu.h"
15#include "arm_pic.h"
16#include "goldfish_device.h"
17#include "hw/hw.h"
18
19enum {
20    TIMER_TIME_LOW          = 0x00, // get low bits of current time and update TIMER_TIME_HIGH
21    TIMER_TIME_HIGH         = 0x04, // get high bits of time at last TIMER_TIME_LOW read
22    TIMER_ALARM_LOW         = 0x08, // set low bits of alarm and activate it
23    TIMER_ALARM_HIGH        = 0x0c, // set high bits of next alarm
24    TIMER_CLEAR_INTERRUPT   = 0x10,
25    TIMER_CLEAR_ALARM       = 0x14
26};
27
28struct timer_state {
29    struct goldfish_device dev;
30    uint32_t alarm_low_ns;
31    int32_t alarm_high_ns;
32    int64_t now_ns;
33    int     armed;
34    QEMUTimer *timer;
35};
36
37#define  GOLDFISH_TIMER_SAVE_VERSION  1
38
39static void  goldfish_timer_save(QEMUFile*  f, void*  opaque)
40{
41    struct timer_state*  s   = opaque;
42
43    qemu_put_be64(f, s->now_ns);  /* in case the kernel is in the middle of a timer read */
44    qemu_put_byte(f, s->armed);
45    if (s->armed) {
46        int64_t  now_ns   = qemu_get_clock_ns(vm_clock);
47        int64_t  alarm_ns = (s->alarm_low_ns | (int64_t)s->alarm_high_ns << 32);
48        qemu_put_be64(f, alarm_ns - now_ns);
49    }
50}
51
52static int  goldfish_timer_load(QEMUFile*  f, void*  opaque, int  version_id)
53{
54    struct timer_state*  s   = opaque;
55
56    if (version_id != GOLDFISH_TIMER_SAVE_VERSION)
57        return -1;
58
59    s->now_ns = qemu_get_be64(f);
60    s->armed  = qemu_get_byte(f);
61    if (s->armed) {
62        int64_t  now_tks   = qemu_get_clock(vm_clock);
63        int64_t  diff_tks  = qemu_get_be64(f);
64        int64_t  alarm_tks = now_tks + diff_tks;
65
66        if (alarm_tks <= now_tks) {
67            goldfish_device_set_irq(&s->dev, 0, 1);
68            s->armed = 0;
69        } else {
70            qemu_mod_timer(s->timer, alarm_tks);
71        }
72    }
73    return 0;
74}
75
76static uint32_t goldfish_timer_read(void *opaque, target_phys_addr_t offset)
77{
78    struct timer_state *s = (struct timer_state *)opaque;
79    switch(offset) {
80        case TIMER_TIME_LOW:
81            s->now_ns = qemu_get_clock_ns(vm_clock);
82            return s->now_ns;
83        case TIMER_TIME_HIGH:
84            return s->now_ns >> 32;
85        default:
86            cpu_abort (cpu_single_env, "goldfish_timer_read: Bad offset %x\n", offset);
87            return 0;
88    }
89}
90
91static void goldfish_timer_write(void *opaque, target_phys_addr_t offset, uint32_t value_ns)
92{
93    struct timer_state *s = (struct timer_state *)opaque;
94    int64_t alarm_ns, now_ns;
95    switch(offset) {
96        case TIMER_ALARM_LOW:
97            s->alarm_low_ns = value_ns;
98            alarm_ns = (s->alarm_low_ns | (int64_t)s->alarm_high_ns << 32);
99            now_ns   = qemu_get_clock_ns(vm_clock);
100            if (alarm_ns <= now_ns) {
101                goldfish_device_set_irq(&s->dev, 0, 1);
102            } else {
103                qemu_mod_timer(s->timer, alarm_ns);
104                s->armed = 1;
105            }
106            break;
107        case TIMER_ALARM_HIGH:
108            s->alarm_high_ns = value_ns;
109            break;
110        case TIMER_CLEAR_ALARM:
111            qemu_del_timer(s->timer);
112            s->armed = 0;
113            /* fall through */
114        case TIMER_CLEAR_INTERRUPT:
115            goldfish_device_set_irq(&s->dev, 0, 0);
116            break;
117        default:
118            cpu_abort (cpu_single_env, "goldfish_timer_write: Bad offset %x\n", offset);
119    }
120}
121
122static void goldfish_timer_tick(void *opaque)
123{
124    struct timer_state *s = (struct timer_state *)opaque;
125
126    s->armed = 0;
127    goldfish_device_set_irq(&s->dev, 0, 1);
128}
129
130struct rtc_state {
131    struct goldfish_device dev;
132    uint32_t alarm_low;
133    int32_t alarm_high;
134    int64_t now;
135};
136
137/* we save the RTC for the case where the kernel is in the middle of a rtc_read
138 * (i.e. it has read the low 32-bit of s->now, but not the high 32-bits yet */
139#define  GOLDFISH_RTC_SAVE_VERSION  1
140
141static void  goldfish_rtc_save(QEMUFile*  f, void*  opaque)
142{
143    struct rtc_state*  s = opaque;
144
145    qemu_put_be64(f, s->now);
146}
147
148static int  goldfish_rtc_load(QEMUFile*  f, void*  opaque, int  version_id)
149{
150    struct  rtc_state*  s = opaque;
151
152    if (version_id != GOLDFISH_RTC_SAVE_VERSION)
153        return -1;
154
155    /* this is an old value that is not correct. but that's ok anyway */
156    s->now = qemu_get_be64(f);
157    return 0;
158}
159
160static uint32_t goldfish_rtc_read(void *opaque, target_phys_addr_t offset)
161{
162    struct rtc_state *s = (struct rtc_state *)opaque;
163    switch(offset) {
164        case 0x0:
165            s->now = (int64_t)time(NULL) * 1000000000;
166            return s->now;
167        case 0x4:
168            return s->now >> 32;
169        default:
170            cpu_abort (cpu_single_env, "goldfish_rtc_read: Bad offset %x\n", offset);
171            return 0;
172    }
173}
174
175static void goldfish_rtc_write(void *opaque, target_phys_addr_t offset, uint32_t value)
176{
177    struct rtc_state *s = (struct rtc_state *)opaque;
178    int64_t alarm;
179    switch(offset) {
180        case 0x8:
181            s->alarm_low = value;
182            alarm = s->alarm_low | (int64_t)s->alarm_high << 32;
183            //printf("next alarm at %lld, tps %lld\n", alarm, ticks_per_sec);
184            //qemu_mod_timer(s->timer, alarm);
185            break;
186        case 0xc:
187            s->alarm_high = value;
188            //printf("alarm_high %d\n", s->alarm_high);
189            break;
190        case 0x10:
191            goldfish_device_set_irq(&s->dev, 0, 0);
192            break;
193        default:
194            cpu_abort (cpu_single_env, "goldfish_rtc_write: Bad offset %x\n", offset);
195    }
196}
197
198static struct timer_state timer_state = {
199    .dev = {
200        .name = "goldfish_timer",
201        .id = -1,
202        .size = 0x1000,
203        .irq_count = 1,
204    }
205};
206
207static struct timer_state rtc_state = {
208    .dev = {
209        .name = "goldfish_rtc",
210        .id = -1,
211        .size = 0x1000,
212        .irq_count = 1,
213    }
214};
215
216static CPUReadMemoryFunc *goldfish_timer_readfn[] = {
217    goldfish_timer_read,
218    goldfish_timer_read,
219    goldfish_timer_read
220};
221
222static CPUWriteMemoryFunc *goldfish_timer_writefn[] = {
223    goldfish_timer_write,
224    goldfish_timer_write,
225    goldfish_timer_write
226};
227
228static CPUReadMemoryFunc *goldfish_rtc_readfn[] = {
229    goldfish_rtc_read,
230    goldfish_rtc_read,
231    goldfish_rtc_read
232};
233
234static CPUWriteMemoryFunc *goldfish_rtc_writefn[] = {
235    goldfish_rtc_write,
236    goldfish_rtc_write,
237    goldfish_rtc_write
238};
239
240void goldfish_timer_and_rtc_init(uint32_t timerbase, int timerirq)
241{
242    timer_state.dev.base = timerbase;
243    timer_state.dev.irq = timerirq;
244    timer_state.timer = qemu_new_timer_ns(vm_clock, goldfish_timer_tick, &timer_state);
245    goldfish_device_add(&timer_state.dev, goldfish_timer_readfn, goldfish_timer_writefn, &timer_state);
246    register_savevm( "goldfish_timer", 0, GOLDFISH_TIMER_SAVE_VERSION,
247                     goldfish_timer_save, goldfish_timer_load, &timer_state);
248
249    goldfish_device_add(&rtc_state.dev, goldfish_rtc_readfn, goldfish_rtc_writefn, &rtc_state);
250    register_savevm( "goldfish_rtc", 0, GOLDFISH_RTC_SAVE_VERSION,
251                     goldfish_rtc_save, goldfish_rtc_load, &rtc_state);
252}
253
254