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