Statistics
| Branch: | Revision:

root / hw / pl031.c @ 37f32f0f

History | View | Annotate | Download (6.1 kB)

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_devices(void)
234
{
235
    type_register_static(&pl031_info);
236
}
237

    
238
device_init(pl031_register_devices)