Add qemu 2.4.0
[kvmfornfv.git] / qemu / hw / timer / lm32_timer.c
1 /*
2  *  QEMU model of the LatticeMico32 timer block.
3  *
4  *  Copyright (c) 2010 Michael Walle <michael@walle.cc>
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18  *
19  *
20  * Specification available at:
21  *   http://www.latticesemi.com/documents/mico32timer.pdf
22  */
23
24 #include "hw/hw.h"
25 #include "hw/sysbus.h"
26 #include "trace.h"
27 #include "qemu/timer.h"
28 #include "hw/ptimer.h"
29 #include "qemu/error-report.h"
30 #include "qemu/main-loop.h"
31
32 #define DEFAULT_FREQUENCY (50*1000000)
33
34 enum {
35     R_SR = 0,
36     R_CR,
37     R_PERIOD,
38     R_SNAPSHOT,
39     R_MAX
40 };
41
42 enum {
43     SR_TO    = (1 << 0),
44     SR_RUN   = (1 << 1),
45 };
46
47 enum {
48     CR_ITO   = (1 << 0),
49     CR_CONT  = (1 << 1),
50     CR_START = (1 << 2),
51     CR_STOP  = (1 << 3),
52 };
53
54 #define TYPE_LM32_TIMER "lm32-timer"
55 #define LM32_TIMER(obj) OBJECT_CHECK(LM32TimerState, (obj), TYPE_LM32_TIMER)
56
57 struct LM32TimerState {
58     SysBusDevice parent_obj;
59
60     MemoryRegion iomem;
61
62     QEMUBH *bh;
63     ptimer_state *ptimer;
64
65     qemu_irq irq;
66     uint32_t freq_hz;
67
68     uint32_t regs[R_MAX];
69 };
70 typedef struct LM32TimerState LM32TimerState;
71
72 static void timer_update_irq(LM32TimerState *s)
73 {
74     int state = (s->regs[R_SR] & SR_TO) && (s->regs[R_CR] & CR_ITO);
75
76     trace_lm32_timer_irq_state(state);
77     qemu_set_irq(s->irq, state);
78 }
79
80 static uint64_t timer_read(void *opaque, hwaddr addr, unsigned size)
81 {
82     LM32TimerState *s = opaque;
83     uint32_t r = 0;
84
85     addr >>= 2;
86     switch (addr) {
87     case R_SR:
88     case R_CR:
89     case R_PERIOD:
90         r = s->regs[addr];
91         break;
92     case R_SNAPSHOT:
93         r = (uint32_t)ptimer_get_count(s->ptimer);
94         break;
95     default:
96         error_report("lm32_timer: read access to unknown register 0x"
97                 TARGET_FMT_plx, addr << 2);
98         break;
99     }
100
101     trace_lm32_timer_memory_read(addr << 2, r);
102     return r;
103 }
104
105 static void timer_write(void *opaque, hwaddr addr,
106                         uint64_t value, unsigned size)
107 {
108     LM32TimerState *s = opaque;
109
110     trace_lm32_timer_memory_write(addr, value);
111
112     addr >>= 2;
113     switch (addr) {
114     case R_SR:
115         s->regs[R_SR] &= ~SR_TO;
116         break;
117     case R_CR:
118         s->regs[R_CR] = value;
119         if (s->regs[R_CR] & CR_START) {
120             ptimer_run(s->ptimer, 1);
121         }
122         if (s->regs[R_CR] & CR_STOP) {
123             ptimer_stop(s->ptimer);
124         }
125         break;
126     case R_PERIOD:
127         s->regs[R_PERIOD] = value;
128         ptimer_set_count(s->ptimer, value);
129         break;
130     case R_SNAPSHOT:
131         error_report("lm32_timer: write access to read only register 0x"
132                 TARGET_FMT_plx, addr << 2);
133         break;
134     default:
135         error_report("lm32_timer: write access to unknown register 0x"
136                 TARGET_FMT_plx, addr << 2);
137         break;
138     }
139     timer_update_irq(s);
140 }
141
142 static const MemoryRegionOps timer_ops = {
143     .read = timer_read,
144     .write = timer_write,
145     .endianness = DEVICE_NATIVE_ENDIAN,
146     .valid = {
147         .min_access_size = 4,
148         .max_access_size = 4,
149     },
150 };
151
152 static void timer_hit(void *opaque)
153 {
154     LM32TimerState *s = opaque;
155
156     trace_lm32_timer_hit();
157
158     s->regs[R_SR] |= SR_TO;
159
160     if (s->regs[R_CR] & CR_CONT) {
161         ptimer_set_count(s->ptimer, s->regs[R_PERIOD]);
162         ptimer_run(s->ptimer, 1);
163     }
164     timer_update_irq(s);
165 }
166
167 static void timer_reset(DeviceState *d)
168 {
169     LM32TimerState *s = LM32_TIMER(d);
170     int i;
171
172     for (i = 0; i < R_MAX; i++) {
173         s->regs[i] = 0;
174     }
175     ptimer_stop(s->ptimer);
176 }
177
178 static int lm32_timer_init(SysBusDevice *dev)
179 {
180     LM32TimerState *s = LM32_TIMER(dev);
181
182     sysbus_init_irq(dev, &s->irq);
183
184     s->bh = qemu_bh_new(timer_hit, s);
185     s->ptimer = ptimer_init(s->bh);
186     ptimer_set_freq(s->ptimer, s->freq_hz);
187
188     memory_region_init_io(&s->iomem, OBJECT(s), &timer_ops, s,
189                           "timer", R_MAX * 4);
190     sysbus_init_mmio(dev, &s->iomem);
191
192     return 0;
193 }
194
195 static const VMStateDescription vmstate_lm32_timer = {
196     .name = "lm32-timer",
197     .version_id = 1,
198     .minimum_version_id = 1,
199     .fields = (VMStateField[]) {
200         VMSTATE_PTIMER(ptimer, LM32TimerState),
201         VMSTATE_UINT32(freq_hz, LM32TimerState),
202         VMSTATE_UINT32_ARRAY(regs, LM32TimerState, R_MAX),
203         VMSTATE_END_OF_LIST()
204     }
205 };
206
207 static Property lm32_timer_properties[] = {
208     DEFINE_PROP_UINT32("frequency", LM32TimerState, freq_hz, DEFAULT_FREQUENCY),
209     DEFINE_PROP_END_OF_LIST(),
210 };
211
212 static void lm32_timer_class_init(ObjectClass *klass, void *data)
213 {
214     DeviceClass *dc = DEVICE_CLASS(klass);
215     SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
216
217     k->init = lm32_timer_init;
218     dc->reset = timer_reset;
219     dc->vmsd = &vmstate_lm32_timer;
220     dc->props = lm32_timer_properties;
221 }
222
223 static const TypeInfo lm32_timer_info = {
224     .name          = TYPE_LM32_TIMER,
225     .parent        = TYPE_SYS_BUS_DEVICE,
226     .instance_size = sizeof(LM32TimerState),
227     .class_init    = lm32_timer_class_init,
228 };
229
230 static void lm32_timer_register_types(void)
231 {
232     type_register_static(&lm32_timer_info);
233 }
234
235 type_init(lm32_timer_register_types)