]> Git Repo - qemu.git/blob - hw/pl031.c
qom: Unify type registration
[qemu.git] / hw / pl031.c
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  *
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.
12  */
13
14 #include "sysbus.h"
15 #include "qemu-timer.h"
16
17 //#define DEBUG_PL031
18
19 #ifdef DEBUG_PL031
20 #define DPRINTF(fmt, ...) \
21 do { printf("pl031: " fmt , ## __VA_ARGS__); } while (0)
22 #else
23 #define DPRINTF(fmt, ...) do {} while(0)
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
35 typedef struct {
36     SysBusDevice busdev;
37     MemoryRegion iomem;
38     QEMUTimer *timer;
39     qemu_irq irq;
40
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
50 static const VMStateDescription vmstate_pl031 = {
51     .name = "pl031",
52     .version_id = 1,
53     .minimum_version_id = 1,
54     .fields = (VMStateField[]) {
55         VMSTATE_UINT32(tick_offset, pl031_state),
56         VMSTATE_UINT32(mr, pl031_state),
57         VMSTATE_UINT32(lr, pl031_state),
58         VMSTATE_UINT32(cr, pl031_state),
59         VMSTATE_UINT32(im, pl031_state),
60         VMSTATE_UINT32(is, pl031_state),
61         VMSTATE_END_OF_LIST()
62     }
63 };
64
65 static const unsigned char pl031_id[] = {
66     0x31, 0x10, 0x14, 0x00,         /* Device ID        */
67     0x0d, 0xf0, 0x05, 0xb1          /* Cell ID      */
68 };
69
70 static void pl031_update(pl031_state *s)
71 {
72     qemu_set_irq(s->irq, s->is & s->im);
73 }
74
75 static void pl031_interrupt(void * opaque)
76 {
77     pl031_state *s = (pl031_state *)opaque;
78
79     s->im = 1;
80     DPRINTF("Alarm raised\n");
81     pl031_update(s);
82 }
83
84 static uint32_t pl031_get_count(pl031_state *s)
85 {
86     /* This assumes qemu_get_clock_ns returns the time since the machine was
87        created.  */
88     return s->tick_offset + qemu_get_clock_ns(vm_clock) / get_ticks_per_sec();
89 }
90
91 static void pl031_set_alarm(pl031_state *s)
92 {
93     int64_t now;
94     uint32_t ticks;
95
96     now = qemu_get_clock_ns(vm_clock);
97     ticks = s->tick_offset + now / get_ticks_per_sec();
98
99     /* The timer wraps around.  This subtraction also wraps in the same way,
100        and gives correct results when alarm < now_ticks.  */
101     ticks = s->mr - ticks;
102     DPRINTF("Alarm set in %ud ticks\n", ticks);
103     if (ticks == 0) {
104         qemu_del_timer(s->timer);
105         pl031_interrupt(s);
106     } else {
107         qemu_mod_timer(s->timer, now + (int64_t)ticks * get_ticks_per_sec());
108     }
109 }
110
111 static uint64_t pl031_read(void *opaque, target_phys_addr_t offset,
112                            unsigned size)
113 {
114     pl031_state *s = (pl031_state *)opaque;
115
116     if (offset >= 0xfe0  &&  offset < 0x1000)
117         return pl031_id[(offset - 0xfe0) >> 2];
118
119     switch (offset) {
120     case RTC_DR:
121         return pl031_get_count(s);
122     case RTC_MR:
123         return s->mr;
124     case RTC_IMSC:
125         return s->im;
126     case RTC_RIS:
127         return s->is;
128     case RTC_LR:
129         return s->lr;
130     case RTC_CR:
131         /* RTC is permanently enabled.  */
132         return 1;
133     case RTC_MIS:
134         return s->is & s->im;
135     case RTC_ICR:
136         fprintf(stderr, "qemu: pl031_read: Unexpected offset 0x%x\n",
137                 (int)offset);
138         break;
139     default:
140         hw_error("pl031_read: Bad offset 0x%x\n", (int)offset);
141         break;
142     }
143
144     return 0;
145 }
146
147 static void pl031_write(void * opaque, target_phys_addr_t offset,
148                         uint64_t value, unsigned size)
149 {
150     pl031_state *s = (pl031_state *)opaque;
151
152
153     switch (offset) {
154     case RTC_LR:
155         s->tick_offset += value - pl031_get_count(s);
156         pl031_set_alarm(s);
157         break;
158     case RTC_MR:
159         s->mr = value;
160         pl031_set_alarm(s);
161         break;
162     case RTC_IMSC:
163         s->im = value & 1;
164         DPRINTF("Interrupt mask %d\n", s->im);
165         pl031_update(s);
166         break;
167     case RTC_ICR:
168         /* The PL031 documentation (DDI0224B) states that the interrupt is
169            cleared when bit 0 of the written value is set.  However the
170            arm926e documentation (DDI0287B) states that the interrupt is
171            cleared when any value is written.  */
172         DPRINTF("Interrupt cleared");
173         s->is = 0;
174         pl031_update(s);
175         break;
176     case RTC_CR:
177         /* Written value is ignored.  */
178         break;
179
180     case RTC_DR:
181     case RTC_MIS:
182     case RTC_RIS:
183         fprintf(stderr, "qemu: pl031_write: Unexpected offset 0x%x\n",
184                 (int)offset);
185         break;
186
187     default:
188         hw_error("pl031_write: Bad offset 0x%x\n", (int)offset);
189         break;
190     }
191 }
192
193 static const MemoryRegionOps pl031_ops = {
194     .read = pl031_read,
195     .write = pl031_write,
196     .endianness = DEVICE_NATIVE_ENDIAN,
197 };
198
199 static int pl031_init(SysBusDevice *dev)
200 {
201     pl031_state *s = FROM_SYSBUS(pl031_state, dev);
202     struct tm tm;
203
204     memory_region_init_io(&s->iomem, &pl031_ops, s, "pl031", 0x1000);
205     sysbus_init_mmio(dev, &s->iomem);
206
207     sysbus_init_irq(dev, &s->irq);
208     /* ??? We assume vm_clock is zero at this point.  */
209     qemu_get_timedate(&tm, 0);
210     s->tick_offset = mktimegm(&tm);
211
212     s->timer = qemu_new_timer_ns(vm_clock, pl031_interrupt, s);
213     return 0;
214 }
215
216 static void pl031_class_init(ObjectClass *klass, void *data)
217 {
218     DeviceClass *dc = DEVICE_CLASS(klass);
219     SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
220
221     k->init = pl031_init;
222     dc->no_user = 1;
223     dc->vmsd = &vmstate_pl031;
224 }
225
226 static TypeInfo pl031_info = {
227     .name          = "pl031",
228     .parent        = TYPE_SYS_BUS_DEVICE,
229     .instance_size = sizeof(pl031_state),
230     .class_init    = pl031_class_init,
231 };
232
233 static void pl031_register_types(void)
234 {
235     type_register_static(&pl031_info);
236 }
237
238 type_init(pl031_register_types)
This page took 0.036251 seconds and 4 git commands to generate.