|
|
1.1 root 1: /*
2: * QEMU GRLIB GPTimer Emulator
3: *
4: * Copyright (c) 2010-2011 AdaCore
5: *
6: * Permission is hereby granted, free of charge, to any person obtaining a copy
7: * of this software and associated documentation files (the "Software"), to deal
8: * in the Software without restriction, including without limitation the rights
9: * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10: * copies of the Software, and to permit persons to whom the Software is
11: * furnished to do so, subject to the following conditions:
12: *
13: * The above copyright notice and this permission notice shall be included in
14: * all copies or substantial portions of the Software.
15: *
16: * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17: * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18: * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19: * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20: * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21: * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22: * THE SOFTWARE.
23: */
24:
25: #include "sysbus.h"
26: #include "qemu-timer.h"
1.1.1.4 ! root 27: #include "ptimer.h"
1.1 root 28:
29: #include "trace.h"
30:
31: #define UNIT_REG_SIZE 16 /* Size of memory mapped regs for the unit */
32: #define GPTIMER_REG_SIZE 16 /* Size of memory mapped regs for a GPTimer */
33:
34: #define GPTIMER_MAX_TIMERS 8
35:
36: /* GPTimer Config register fields */
37: #define GPTIMER_ENABLE (1 << 0)
38: #define GPTIMER_RESTART (1 << 1)
39: #define GPTIMER_LOAD (1 << 2)
40: #define GPTIMER_INT_ENABLE (1 << 3)
41: #define GPTIMER_INT_PENDING (1 << 4)
42: #define GPTIMER_CHAIN (1 << 5) /* Not supported */
43: #define GPTIMER_DEBUG_HALT (1 << 6) /* Not supported */
44:
45: /* Memory mapped register offsets */
46: #define SCALER_OFFSET 0x00
47: #define SCALER_RELOAD_OFFSET 0x04
48: #define CONFIG_OFFSET 0x08
49: #define COUNTER_OFFSET 0x00
50: #define COUNTER_RELOAD_OFFSET 0x04
51: #define TIMER_BASE 0x10
52:
53: typedef struct GPTimer GPTimer;
54: typedef struct GPTimerUnit GPTimerUnit;
55:
56: struct GPTimer {
57: QEMUBH *bh;
58: struct ptimer_state *ptimer;
59:
60: qemu_irq irq;
61: int id;
62: GPTimerUnit *unit;
63:
64: /* registers */
65: uint32_t counter;
66: uint32_t reload;
67: uint32_t config;
68: };
69:
70: struct GPTimerUnit {
71: SysBusDevice busdev;
1.1.1.4 ! root 72: MemoryRegion iomem;
1.1 root 73:
74: uint32_t nr_timers; /* Number of timers available */
75: uint32_t freq_hz; /* System frequency */
76: uint32_t irq_line; /* Base irq line */
77:
78: GPTimer *timers;
79:
80: /* registers */
81: uint32_t scaler;
82: uint32_t reload;
83: uint32_t config;
84: };
85:
86: static void grlib_gptimer_enable(GPTimer *timer)
87: {
88: assert(timer != NULL);
89:
90:
91: ptimer_stop(timer->ptimer);
92:
93: if (!(timer->config & GPTIMER_ENABLE)) {
94: /* Timer disabled */
95: trace_grlib_gptimer_disabled(timer->id, timer->config);
96: return;
97: }
98:
99: /* ptimer is triggered when the counter reach 0 but GPTimer is triggered at
100: underflow. Set count + 1 to simulate the GPTimer behavior. */
101:
102: trace_grlib_gptimer_enable(timer->id, timer->counter + 1);
103:
104: ptimer_set_count(timer->ptimer, timer->counter + 1);
105: ptimer_run(timer->ptimer, 1);
106: }
107:
108: static void grlib_gptimer_restart(GPTimer *timer)
109: {
110: assert(timer != NULL);
111:
112: trace_grlib_gptimer_restart(timer->id, timer->reload);
113:
114: timer->counter = timer->reload;
115: grlib_gptimer_enable(timer);
116: }
117:
118: static void grlib_gptimer_set_scaler(GPTimerUnit *unit, uint32_t scaler)
119: {
120: int i = 0;
121: uint32_t value = 0;
122:
123: assert(unit != NULL);
124:
125: if (scaler > 0) {
126: value = unit->freq_hz / (scaler + 1);
127: } else {
128: value = unit->freq_hz;
129: }
130:
131: trace_grlib_gptimer_set_scaler(scaler, value);
132:
133: for (i = 0; i < unit->nr_timers; i++) {
134: ptimer_set_freq(unit->timers[i].ptimer, value);
135: }
136: }
137:
138: static void grlib_gptimer_hit(void *opaque)
139: {
140: GPTimer *timer = opaque;
141: assert(timer != NULL);
142:
143: trace_grlib_gptimer_hit(timer->id);
144:
145: /* Timer expired */
146:
147: if (timer->config & GPTIMER_INT_ENABLE) {
148: /* Set the pending bit (only unset by write in the config register) */
149: timer->config |= GPTIMER_INT_PENDING;
150: qemu_irq_pulse(timer->irq);
151: }
152:
153: if (timer->config & GPTIMER_RESTART) {
154: grlib_gptimer_restart(timer);
155: }
156: }
157:
1.1.1.4 ! root 158: static uint64_t grlib_gptimer_read(void *opaque, target_phys_addr_t addr,
! 159: unsigned size)
1.1 root 160: {
161: GPTimerUnit *unit = opaque;
162: target_phys_addr_t timer_addr;
163: int id;
164: uint32_t value = 0;
165:
166: addr &= 0xff;
167:
168: /* Unit registers */
169: switch (addr) {
170: case SCALER_OFFSET:
1.1.1.2 root 171: trace_grlib_gptimer_readl(-1, addr, unit->scaler);
1.1 root 172: return unit->scaler;
173:
174: case SCALER_RELOAD_OFFSET:
1.1.1.2 root 175: trace_grlib_gptimer_readl(-1, addr, unit->reload);
1.1 root 176: return unit->reload;
177:
178: case CONFIG_OFFSET:
1.1.1.2 root 179: trace_grlib_gptimer_readl(-1, addr, unit->config);
1.1 root 180: return unit->config;
181:
182: default:
183: break;
184: }
185:
186: timer_addr = (addr % TIMER_BASE);
187: id = (addr - TIMER_BASE) / TIMER_BASE;
188:
189: if (id >= 0 && id < unit->nr_timers) {
190:
191: /* GPTimer registers */
192: switch (timer_addr) {
193: case COUNTER_OFFSET:
194: value = ptimer_get_count(unit->timers[id].ptimer);
1.1.1.2 root 195: trace_grlib_gptimer_readl(id, addr, value);
1.1 root 196: return value;
197:
198: case COUNTER_RELOAD_OFFSET:
199: value = unit->timers[id].reload;
1.1.1.2 root 200: trace_grlib_gptimer_readl(id, addr, value);
1.1 root 201: return value;
202:
203: case CONFIG_OFFSET:
1.1.1.2 root 204: trace_grlib_gptimer_readl(id, addr, unit->timers[id].config);
1.1 root 205: return unit->timers[id].config;
206:
207: default:
208: break;
209: }
210:
211: }
212:
1.1.1.2 root 213: trace_grlib_gptimer_readl(-1, addr, 0);
1.1 root 214: return 0;
215: }
216:
1.1.1.4 ! root 217: static void grlib_gptimer_write(void *opaque, target_phys_addr_t addr,
! 218: uint64_t value, unsigned size)
1.1 root 219: {
220: GPTimerUnit *unit = opaque;
221: target_phys_addr_t timer_addr;
222: int id;
223:
224: addr &= 0xff;
225:
226: /* Unit registers */
227: switch (addr) {
228: case SCALER_OFFSET:
229: value &= 0xFFFF; /* clean up the value */
230: unit->scaler = value;
1.1.1.2 root 231: trace_grlib_gptimer_writel(-1, addr, unit->scaler);
1.1 root 232: return;
233:
234: case SCALER_RELOAD_OFFSET:
235: value &= 0xFFFF; /* clean up the value */
236: unit->reload = value;
1.1.1.2 root 237: trace_grlib_gptimer_writel(-1, addr, unit->reload);
1.1 root 238: grlib_gptimer_set_scaler(unit, value);
239: return;
240:
241: case CONFIG_OFFSET:
242: /* Read Only (disable timer freeze not supported) */
1.1.1.2 root 243: trace_grlib_gptimer_writel(-1, addr, 0);
1.1 root 244: return;
245:
246: default:
247: break;
248: }
249:
250: timer_addr = (addr % TIMER_BASE);
251: id = (addr - TIMER_BASE) / TIMER_BASE;
252:
253: if (id >= 0 && id < unit->nr_timers) {
254:
255: /* GPTimer registers */
256: switch (timer_addr) {
257: case COUNTER_OFFSET:
1.1.1.2 root 258: trace_grlib_gptimer_writel(id, addr, value);
1.1 root 259: unit->timers[id].counter = value;
260: grlib_gptimer_enable(&unit->timers[id]);
261: return;
262:
263: case COUNTER_RELOAD_OFFSET:
1.1.1.2 root 264: trace_grlib_gptimer_writel(id, addr, value);
1.1 root 265: unit->timers[id].reload = value;
266: return;
267:
268: case CONFIG_OFFSET:
1.1.1.2 root 269: trace_grlib_gptimer_writel(id, addr, value);
1.1 root 270:
271: if (value & GPTIMER_INT_PENDING) {
272: /* clear pending bit */
273: value &= ~GPTIMER_INT_PENDING;
274: } else {
275: /* keep pending bit */
276: value |= unit->timers[id].config & GPTIMER_INT_PENDING;
277: }
278:
279: unit->timers[id].config = value;
280:
281: /* gptimer_restart calls gptimer_enable, so if "enable" and "load"
282: bits are present, we just have to call restart. */
283:
284: if (value & GPTIMER_LOAD) {
285: grlib_gptimer_restart(&unit->timers[id]);
286: } else if (value & GPTIMER_ENABLE) {
287: grlib_gptimer_enable(&unit->timers[id]);
288: }
289:
290: /* These fields must always be read as 0 */
291: value &= ~(GPTIMER_LOAD & GPTIMER_DEBUG_HALT);
292:
293: unit->timers[id].config = value;
294: return;
295:
296: default:
297: break;
298: }
299:
300: }
301:
1.1.1.2 root 302: trace_grlib_gptimer_writel(-1, addr, value);
1.1 root 303: }
304:
1.1.1.4 ! root 305: static const MemoryRegionOps grlib_gptimer_ops = {
! 306: .read = grlib_gptimer_read,
! 307: .write = grlib_gptimer_write,
! 308: .endianness = DEVICE_NATIVE_ENDIAN,
! 309: .valid = {
! 310: .min_access_size = 4,
! 311: .max_access_size = 4,
! 312: },
1.1 root 313: };
314:
315: static void grlib_gptimer_reset(DeviceState *d)
316: {
317: GPTimerUnit *unit = container_of(d, GPTimerUnit, busdev.qdev);
318: int i = 0;
319:
320: assert(unit != NULL);
321:
322: unit->scaler = 0;
323: unit->reload = 0;
324: unit->config = 0;
325:
326: unit->config = unit->nr_timers;
327: unit->config |= unit->irq_line << 3;
328: unit->config |= 1 << 8; /* separate interrupt */
329: unit->config |= 1 << 9; /* Disable timer freeze */
330:
331:
332: for (i = 0; i < unit->nr_timers; i++) {
333: GPTimer *timer = &unit->timers[i];
334:
335: timer->counter = 0;
336: timer->reload = 0;
337: timer->config = 0;
338: ptimer_stop(timer->ptimer);
339: ptimer_set_count(timer->ptimer, 0);
340: ptimer_set_freq(timer->ptimer, unit->freq_hz);
341: }
342: }
343:
344: static int grlib_gptimer_init(SysBusDevice *dev)
345: {
346: GPTimerUnit *unit = FROM_SYSBUS(typeof(*unit), dev);
347: unsigned int i;
348:
349: assert(unit->nr_timers > 0);
350: assert(unit->nr_timers <= GPTIMER_MAX_TIMERS);
351:
1.1.1.3 root 352: unit->timers = g_malloc0(sizeof unit->timers[0] * unit->nr_timers);
1.1 root 353:
354: for (i = 0; i < unit->nr_timers; i++) {
355: GPTimer *timer = &unit->timers[i];
356:
357: timer->unit = unit;
358: timer->bh = qemu_bh_new(grlib_gptimer_hit, timer);
359: timer->ptimer = ptimer_init(timer->bh);
360: timer->id = i;
361:
362: /* One IRQ line for each timer */
363: sysbus_init_irq(dev, &timer->irq);
364:
365: ptimer_set_freq(timer->ptimer, unit->freq_hz);
366: }
367:
1.1.1.4 ! root 368: memory_region_init_io(&unit->iomem, &grlib_gptimer_ops, unit, "gptimer",
! 369: UNIT_REG_SIZE + GPTIMER_REG_SIZE * unit->nr_timers);
1.1 root 370:
1.1.1.4 ! root 371: sysbus_init_mmio(dev, &unit->iomem);
1.1 root 372: return 0;
373: }
374:
1.1.1.4 ! root 375: static Property grlib_gptimer_properties[] = {
! 376: DEFINE_PROP_UINT32("frequency", GPTimerUnit, freq_hz, 40000000),
! 377: DEFINE_PROP_UINT32("irq-line", GPTimerUnit, irq_line, 8),
! 378: DEFINE_PROP_UINT32("nr-timers", GPTimerUnit, nr_timers, 2),
! 379: DEFINE_PROP_END_OF_LIST(),
! 380: };
! 381:
! 382: static void grlib_gptimer_class_init(ObjectClass *klass, void *data)
! 383: {
! 384: DeviceClass *dc = DEVICE_CLASS(klass);
! 385: SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
! 386:
! 387: k->init = grlib_gptimer_init;
! 388: dc->reset = grlib_gptimer_reset;
! 389: dc->props = grlib_gptimer_properties;
! 390: }
! 391:
! 392: static TypeInfo grlib_gptimer_info = {
! 393: .name = "grlib,gptimer",
! 394: .parent = TYPE_SYS_BUS_DEVICE,
! 395: .instance_size = sizeof(GPTimerUnit),
! 396: .class_init = grlib_gptimer_class_init,
1.1 root 397: };
398:
1.1.1.4 ! root 399: static void grlib_gptimer_register_types(void)
1.1 root 400: {
1.1.1.4 ! root 401: type_register_static(&grlib_gptimer_info);
1.1 root 402: }
403:
1.1.1.4 ! root 404: type_init(grlib_gptimer_register_types)
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.