]> Git Repo - qemu.git/blame - hw/pl031.c
pl031: rearm alarm timer upon load
[qemu.git] / hw / pl031.c
CommitLineData
7e1543c2
PB
1/*
2 * ARM AMBA PrimeCell PL031 RTC
3 *
4 * Copyright (c) 2007 CodeSourcery
5 *
6 * This file is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 *
6b620ca3
PB
10 * Contributions after 2012-01-13 are licensed under the terms of the
11 * GNU GPL, version 2 or (at your option) any later version.
7e1543c2
PB
12 */
13
a63bdb31 14#include "sysbus.h"
87ecb68b 15#include "qemu-timer.h"
7e1543c2
PB
16
17//#define DEBUG_PL031
18
19#ifdef DEBUG_PL031
001faf32
BS
20#define DPRINTF(fmt, ...) \
21do { printf("pl031: " fmt , ## __VA_ARGS__); } while (0)
7e1543c2 22#else
001faf32 23#define DPRINTF(fmt, ...) do {} while(0)
7e1543c2
PB
24#endif
25
26#define RTC_DR 0x00 /* Data read register */
27#define RTC_MR 0x04 /* Match register */
28#define RTC_LR 0x08 /* Data load register */
29#define RTC_CR 0x0c /* Control register */
30#define RTC_IMSC 0x10 /* Interrupt mask and set register */
31#define RTC_RIS 0x14 /* Raw interrupt status register */
32#define RTC_MIS 0x18 /* Masked interrupt status register */
33#define RTC_ICR 0x1c /* Interrupt clear register */
34
35typedef struct {
a63bdb31 36 SysBusDevice busdev;
9edbe481 37 MemoryRegion iomem;
7e1543c2
PB
38 QEMUTimer *timer;
39 qemu_irq irq;
7e1543c2 40
7e1543c2
PB
41 uint32_t tick_offset;
42
43 uint32_t mr;
44 uint32_t lr;
45 uint32_t cr;
46 uint32_t im;
47 uint32_t is;
48} pl031_state;
49
50static const unsigned char pl031_id[] = {
51 0x31, 0x10, 0x14, 0x00, /* Device ID */
52 0x0d, 0xf0, 0x05, 0xb1 /* Cell ID */
53};
54
55static void pl031_update(pl031_state *s)
56{
57 qemu_set_irq(s->irq, s->is & s->im);
58}
59
60static void pl031_interrupt(void * opaque)
61{
62 pl031_state *s = (pl031_state *)opaque;
63
13a16f1d 64 s->is = 1;
7e1543c2
PB
65 DPRINTF("Alarm raised\n");
66 pl031_update(s);
67}
68
69static uint32_t pl031_get_count(pl031_state *s)
70{
74475455 71 /* This assumes qemu_get_clock_ns returns the time since the machine was
7e1543c2 72 created. */
74475455 73 return s->tick_offset + qemu_get_clock_ns(vm_clock) / get_ticks_per_sec();
7e1543c2
PB
74}
75
76static void pl031_set_alarm(pl031_state *s)
77{
78 int64_t now;
79 uint32_t ticks;
80
74475455 81 now = qemu_get_clock_ns(vm_clock);
6ee093c9 82 ticks = s->tick_offset + now / get_ticks_per_sec();
7e1543c2
PB
83
84 /* The timer wraps around. This subtraction also wraps in the same way,
85 and gives correct results when alarm < now_ticks. */
86 ticks = s->mr - ticks;
87 DPRINTF("Alarm set in %ud ticks\n", ticks);
88 if (ticks == 0) {
89 qemu_del_timer(s->timer);
90 pl031_interrupt(s);
91 } else {
6ee093c9 92 qemu_mod_timer(s->timer, now + (int64_t)ticks * get_ticks_per_sec());
7e1543c2
PB
93 }
94}
95
9edbe481
AK
96static uint64_t pl031_read(void *opaque, target_phys_addr_t offset,
97 unsigned size)
7e1543c2
PB
98{
99 pl031_state *s = (pl031_state *)opaque;
100
7e1543c2
PB
101 if (offset >= 0xfe0 && offset < 0x1000)
102 return pl031_id[(offset - 0xfe0) >> 2];
103
104 switch (offset) {
105 case RTC_DR:
106 return pl031_get_count(s);
107 case RTC_MR:
108 return s->mr;
109 case RTC_IMSC:
110 return s->im;
111 case RTC_RIS:
112 return s->is;
113 case RTC_LR:
114 return s->lr;
115 case RTC_CR:
116 /* RTC is permanently enabled. */
117 return 1;
118 case RTC_MIS:
119 return s->is & s->im;
120 case RTC_ICR:
121 fprintf(stderr, "qemu: pl031_read: Unexpected offset 0x%x\n",
122 (int)offset);
123 break;
124 default:
2ac71179 125 hw_error("pl031_read: Bad offset 0x%x\n", (int)offset);
7e1543c2
PB
126 break;
127 }
128
129 return 0;
130}
131
c227f099 132static void pl031_write(void * opaque, target_phys_addr_t offset,
9edbe481 133 uint64_t value, unsigned size)
7e1543c2
PB
134{
135 pl031_state *s = (pl031_state *)opaque;
136
7e1543c2
PB
137
138 switch (offset) {
139 case RTC_LR:
140 s->tick_offset += value - pl031_get_count(s);
141 pl031_set_alarm(s);
142 break;
143 case RTC_MR:
144 s->mr = value;
145 pl031_set_alarm(s);
146 break;
147 case RTC_IMSC:
148 s->im = value & 1;
149 DPRINTF("Interrupt mask %d\n", s->im);
150 pl031_update(s);
151 break;
152 case RTC_ICR:
ff2712ba 153 /* The PL031 documentation (DDI0224B) states that the interrupt is
7e1543c2
PB
154 cleared when bit 0 of the written value is set. However the
155 arm926e documentation (DDI0287B) states that the interrupt is
156 cleared when any value is written. */
157 DPRINTF("Interrupt cleared");
158 s->is = 0;
159 pl031_update(s);
160 break;
161 case RTC_CR:
162 /* Written value is ignored. */
163 break;
164
165 case RTC_DR:
166 case RTC_MIS:
167 case RTC_RIS:
168 fprintf(stderr, "qemu: pl031_write: Unexpected offset 0x%x\n",
169 (int)offset);
170 break;
171
172 default:
2ac71179 173 hw_error("pl031_write: Bad offset 0x%x\n", (int)offset);
7e1543c2
PB
174 break;
175 }
176}
177
9edbe481
AK
178static const MemoryRegionOps pl031_ops = {
179 .read = pl031_read,
180 .write = pl031_write,
181 .endianness = DEVICE_NATIVE_ENDIAN,
7e1543c2
PB
182};
183
81a322d4 184static int pl031_init(SysBusDevice *dev)
7e1543c2 185{
a63bdb31 186 pl031_state *s = FROM_SYSBUS(pl031_state, dev);
f6503059 187 struct tm tm;
7e1543c2 188
9edbe481 189 memory_region_init_io(&s->iomem, &pl031_ops, s, "pl031", 0x1000);
750ecd44 190 sysbus_init_mmio(dev, &s->iomem);
7e1543c2 191
a63bdb31 192 sysbus_init_irq(dev, &s->irq);
7e1543c2 193 /* ??? We assume vm_clock is zero at this point. */
f6503059 194 qemu_get_timedate(&tm, 0);
0cd2df75 195 s->tick_offset = mktimegm(&tm);
7e1543c2 196
74475455 197 s->timer = qemu_new_timer_ns(vm_clock, pl031_interrupt, s);
81a322d4 198 return 0;
7e1543c2 199}
a63bdb31 200
ac204b8f
PB
201static int pl031_post_load(void *opaque, int version_id)
202{
203 pl031_state *s = opaque;
204
205 pl031_set_alarm(s);
206 return 0;
207}
208
209static const VMStateDescription vmstate_pl031 = {
210 .name = "pl031",
211 .version_id = 1,
212 .minimum_version_id = 1,
213 .post_load = pl031_post_load,
214 .fields = (VMStateField[]) {
215 VMSTATE_UINT32(tick_offset, pl031_state),
216 VMSTATE_UINT32(mr, pl031_state),
217 VMSTATE_UINT32(lr, pl031_state),
218 VMSTATE_UINT32(cr, pl031_state),
219 VMSTATE_UINT32(im, pl031_state),
220 VMSTATE_UINT32(is, pl031_state),
221 VMSTATE_END_OF_LIST()
222 }
223};
224
999e12bb
AL
225static void pl031_class_init(ObjectClass *klass, void *data)
226{
39bffca2 227 DeviceClass *dc = DEVICE_CLASS(klass);
999e12bb
AL
228 SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
229
230 k->init = pl031_init;
39bffca2
AL
231 dc->no_user = 1;
232 dc->vmsd = &vmstate_pl031;
999e12bb
AL
233}
234
39bffca2
AL
235static TypeInfo pl031_info = {
236 .name = "pl031",
237 .parent = TYPE_SYS_BUS_DEVICE,
238 .instance_size = sizeof(pl031_state),
239 .class_init = pl031_class_init,
0dc5595c
PM
240};
241
83f7d43a 242static void pl031_register_types(void)
a63bdb31 243{
39bffca2 244 type_register_static(&pl031_info);
a63bdb31
PB
245}
246
83f7d43a 247type_init(pl031_register_types)
This page took 0.628223 seconds and 4 git commands to generate.