|
|
1.1 root 1: /*
2: * Xilinx Zynq cadence TTC model
3: *
4: * Copyright (c) 2011 Xilinx Inc.
5: * Copyright (c) 2012 Peter A.G. Crosthwaite ([email protected])
6: * Copyright (c) 2012 PetaLogix Pty Ltd.
7: * Written By Haibing Ma
8: * M. Habib
9: *
10: * This program is free software; you can redistribute it and/or
11: * modify it under the terms of the GNU General Public License
12: * as published by the Free Software Foundation; either version
13: * 2 of the License, or (at your option) any later version.
14: *
15: * You should have received a copy of the GNU General Public License along
16: * with this program; if not, see <http://www.gnu.org/licenses/>.
17: */
18:
19: #include "sysbus.h"
20: #include "qemu-timer.h"
21:
22: #ifdef CADENCE_TTC_ERR_DEBUG
23: #define DB_PRINT(...) do { \
24: fprintf(stderr, ": %s: ", __func__); \
25: fprintf(stderr, ## __VA_ARGS__); \
26: } while (0);
27: #else
28: #define DB_PRINT(...)
29: #endif
30:
31: #define COUNTER_INTR_IV 0x00000001
32: #define COUNTER_INTR_M1 0x00000002
33: #define COUNTER_INTR_M2 0x00000004
34: #define COUNTER_INTR_M3 0x00000008
35: #define COUNTER_INTR_OV 0x00000010
36: #define COUNTER_INTR_EV 0x00000020
37:
38: #define COUNTER_CTRL_DIS 0x00000001
39: #define COUNTER_CTRL_INT 0x00000002
40: #define COUNTER_CTRL_DEC 0x00000004
41: #define COUNTER_CTRL_MATCH 0x00000008
42: #define COUNTER_CTRL_RST 0x00000010
43:
44: #define CLOCK_CTRL_PS_EN 0x00000001
45: #define CLOCK_CTRL_PS_V 0x0000001e
46:
47: typedef struct {
48: QEMUTimer *timer;
49: int freq;
50:
51: uint32_t reg_clock;
52: uint32_t reg_count;
53: uint32_t reg_value;
54: uint16_t reg_interval;
55: uint16_t reg_match[3];
56: uint32_t reg_intr;
57: uint32_t reg_intr_en;
58: uint32_t reg_event_ctrl;
59: uint32_t reg_event;
60:
61: uint64_t cpu_time;
62: unsigned int cpu_time_valid;
63:
64: qemu_irq irq;
65: } CadenceTimerState;
66:
67: typedef struct {
68: SysBusDevice busdev;
69: MemoryRegion iomem;
70: CadenceTimerState timer[3];
71: } CadenceTTCState;
72:
73: static void cadence_timer_update(CadenceTimerState *s)
74: {
75: qemu_set_irq(s->irq, !!(s->reg_intr & s->reg_intr_en));
76: }
77:
78: static CadenceTimerState *cadence_timer_from_addr(void *opaque,
79: target_phys_addr_t offset)
80: {
81: unsigned int index;
82: CadenceTTCState *s = (CadenceTTCState *)opaque;
83:
84: index = (offset >> 2) % 3;
85:
86: return &s->timer[index];
87: }
88:
89: static uint64_t cadence_timer_get_ns(CadenceTimerState *s, uint64_t timer_steps)
90: {
91: /* timer_steps has max value of 0x100000000. double check it
92: * (or overflow can happen below) */
93: assert(timer_steps <= 1ULL << 32);
94:
95: uint64_t r = timer_steps * 1000000000ULL;
96: if (s->reg_clock & CLOCK_CTRL_PS_EN) {
97: r >>= 16 - (((s->reg_clock & CLOCK_CTRL_PS_V) >> 1) + 1);
98: } else {
99: r >>= 16;
100: }
101: r /= (uint64_t)s->freq;
102: return r;
103: }
104:
105: static uint64_t cadence_timer_get_steps(CadenceTimerState *s, uint64_t ns)
106: {
107: uint64_t to_divide = 1000000000ULL;
108:
109: uint64_t r = ns;
110: /* for very large intervals (> 8s) do some division first to stop
111: * overflow (costs some prescision) */
112: while (r >= 8ULL << 30 && to_divide > 1) {
113: r /= 1000;
114: to_divide /= 1000;
115: }
116: r <<= 16;
117: /* keep early-dividing as needed */
118: while (r >= 8ULL << 30 && to_divide > 1) {
119: r /= 1000;
120: to_divide /= 1000;
121: }
122: r *= (uint64_t)s->freq;
123: if (s->reg_clock & CLOCK_CTRL_PS_EN) {
124: r /= 1 << (((s->reg_clock & CLOCK_CTRL_PS_V) >> 1) + 1);
125: }
126:
127: r /= to_divide;
128: return r;
129: }
130:
131: /* determine if x is in between a and b, exclusive of a, inclusive of b */
132:
133: static inline int64_t is_between(int64_t x, int64_t a, int64_t b)
134: {
135: if (a < b) {
136: return x > a && x <= b;
137: }
138: return x < a && x >= b;
139: }
140:
141: static void cadence_timer_run(CadenceTimerState *s)
142: {
143: int i;
144: int64_t event_interval, next_value;
145:
146: assert(s->cpu_time_valid); /* cadence_timer_sync must be called first */
147:
148: if (s->reg_count & COUNTER_CTRL_DIS) {
149: s->cpu_time_valid = 0;
150: return;
151: }
152:
153: { /* figure out what's going to happen next (rollover or match) */
154: int64_t interval = (uint64_t)((s->reg_count & COUNTER_CTRL_INT) ?
155: (int64_t)s->reg_interval + 1 : 0x10000ULL) << 16;
156: next_value = (s->reg_count & COUNTER_CTRL_DEC) ? -1ULL : interval;
157: for (i = 0; i < 3; ++i) {
158: int64_t cand = (uint64_t)s->reg_match[i] << 16;
159: if (is_between(cand, (uint64_t)s->reg_value, next_value)) {
160: next_value = cand;
161: }
162: }
163: }
164: DB_PRINT("next timer event value: %09llx\n",
165: (unsigned long long)next_value);
166:
167: event_interval = next_value - (int64_t)s->reg_value;
168: event_interval = (event_interval < 0) ? -event_interval : event_interval;
169:
170: qemu_mod_timer(s->timer, s->cpu_time +
171: cadence_timer_get_ns(s, event_interval));
172: }
173:
174: static void cadence_timer_sync(CadenceTimerState *s)
175: {
176: int i;
177: int64_t r, x;
178: int64_t interval = ((s->reg_count & COUNTER_CTRL_INT) ?
179: (int64_t)s->reg_interval + 1 : 0x10000ULL) << 16;
180: uint64_t old_time = s->cpu_time;
181:
182: s->cpu_time = qemu_get_clock_ns(vm_clock);
183: DB_PRINT("cpu time: %lld ns\n", (long long)old_time);
184:
185: if (!s->cpu_time_valid || old_time == s->cpu_time) {
186: s->cpu_time_valid = 1;
187: return;
188: }
189:
190: r = (int64_t)cadence_timer_get_steps(s, s->cpu_time - old_time);
191: x = (int64_t)s->reg_value + ((s->reg_count & COUNTER_CTRL_DEC) ? -r : r);
192:
193: for (i = 0; i < 3; ++i) {
194: int64_t m = (int64_t)s->reg_match[i] << 16;
195: if (m > interval) {
196: continue;
197: }
198: /* check to see if match event has occurred. check m +/- interval
199: * to account for match events in wrap around cases */
200: if (is_between(m, s->reg_value, x) ||
201: is_between(m + interval, s->reg_value, x) ||
202: is_between(m - interval, s->reg_value, x)) {
203: s->reg_intr |= (2 << i);
204: }
205: }
206: while (x < 0) {
207: x += interval;
208: }
209: s->reg_value = (uint32_t)(x % interval);
210:
211: if (s->reg_value != x) {
212: s->reg_intr |= (s->reg_count & COUNTER_CTRL_INT) ?
213: COUNTER_INTR_IV : COUNTER_INTR_OV;
214: }
215: cadence_timer_update(s);
216: }
217:
218: static void cadence_timer_tick(void *opaque)
219: {
220: CadenceTimerState *s = opaque;
221:
222: DB_PRINT("\n");
223: cadence_timer_sync(s);
224: cadence_timer_run(s);
225: }
226:
227: static uint32_t cadence_ttc_read_imp(void *opaque, target_phys_addr_t offset)
228: {
229: CadenceTimerState *s = cadence_timer_from_addr(opaque, offset);
230: uint32_t value;
231:
232: cadence_timer_sync(s);
233: cadence_timer_run(s);
234:
235: switch (offset) {
236: case 0x00: /* clock control */
237: case 0x04:
238: case 0x08:
239: return s->reg_clock;
240:
241: case 0x0c: /* counter control */
242: case 0x10:
243: case 0x14:
244: return s->reg_count;
245:
246: case 0x18: /* counter value */
247: case 0x1c:
248: case 0x20:
249: return (uint16_t)(s->reg_value >> 16);
250:
251: case 0x24: /* reg_interval counter */
252: case 0x28:
253: case 0x2c:
254: return s->reg_interval;
255:
256: case 0x30: /* match 1 counter */
257: case 0x34:
258: case 0x38:
259: return s->reg_match[0];
260:
261: case 0x3c: /* match 2 counter */
262: case 0x40:
263: case 0x44:
264: return s->reg_match[1];
265:
266: case 0x48: /* match 3 counter */
267: case 0x4c:
268: case 0x50:
269: return s->reg_match[2];
270:
271: case 0x54: /* interrupt register */
272: case 0x58:
273: case 0x5c:
274: /* cleared after read */
275: value = s->reg_intr;
276: s->reg_intr = 0;
277: return value;
278:
279: case 0x60: /* interrupt enable */
280: case 0x64:
281: case 0x68:
282: return s->reg_intr_en;
283:
284: case 0x6c:
285: case 0x70:
286: case 0x74:
287: return s->reg_event_ctrl;
288:
289: case 0x78:
290: case 0x7c:
291: case 0x80:
292: return s->reg_event;
293:
294: default:
295: return 0;
296: }
297: }
298:
299: static uint64_t cadence_ttc_read(void *opaque, target_phys_addr_t offset,
300: unsigned size)
301: {
302: uint32_t ret = cadence_ttc_read_imp(opaque, offset);
303:
304: DB_PRINT("addr: %08x data: %08x\n", offset, ret);
305: return ret;
306: }
307:
308: static void cadence_ttc_write(void *opaque, target_phys_addr_t offset,
309: uint64_t value, unsigned size)
310: {
311: CadenceTimerState *s = cadence_timer_from_addr(opaque, offset);
312:
313: DB_PRINT("addr: %08x data %08x\n", offset, (unsigned)value);
314:
315: cadence_timer_sync(s);
316:
317: switch (offset) {
318: case 0x00: /* clock control */
319: case 0x04:
320: case 0x08:
321: s->reg_clock = value & 0x3F;
322: break;
323:
324: case 0x0c: /* counter control */
325: case 0x10:
326: case 0x14:
327: if (value & COUNTER_CTRL_RST) {
328: s->reg_value = 0;
329: }
330: s->reg_count = value & 0x3f & ~COUNTER_CTRL_RST;
331: break;
332:
333: case 0x24: /* interval register */
334: case 0x28:
335: case 0x2c:
336: s->reg_interval = value & 0xffff;
337: break;
338:
339: case 0x30: /* match register */
340: case 0x34:
341: case 0x38:
342: s->reg_match[0] = value & 0xffff;
343:
344: case 0x3c: /* match register */
345: case 0x40:
346: case 0x44:
347: s->reg_match[1] = value & 0xffff;
348:
349: case 0x48: /* match register */
350: case 0x4c:
351: case 0x50:
352: s->reg_match[2] = value & 0xffff;
353: break;
354:
355: case 0x54: /* interrupt register */
356: case 0x58:
357: case 0x5c:
358: s->reg_intr &= (~value & 0xfff);
359: break;
360:
361: case 0x60: /* interrupt enable */
362: case 0x64:
363: case 0x68:
364: s->reg_intr_en = value & 0x3f;
365: break;
366:
367: case 0x6c: /* event control */
368: case 0x70:
369: case 0x74:
370: s->reg_event_ctrl = value & 0x07;
371: break;
372:
373: default:
374: return;
375: }
376:
377: cadence_timer_run(s);
378: cadence_timer_update(s);
379: }
380:
381: static const MemoryRegionOps cadence_ttc_ops = {
382: .read = cadence_ttc_read,
383: .write = cadence_ttc_write,
384: .endianness = DEVICE_NATIVE_ENDIAN,
385: };
386:
387: static void cadence_timer_reset(CadenceTimerState *s)
388: {
389: s->reg_count = 0x21;
390: }
391:
392: static void cadence_timer_init(uint32_t freq, CadenceTimerState *s)
393: {
394: memset(s, 0, sizeof(CadenceTimerState));
395: s->freq = freq;
396:
397: cadence_timer_reset(s);
398:
399: s->timer = qemu_new_timer_ns(vm_clock, cadence_timer_tick, s);
400: }
401:
402: static int cadence_ttc_init(SysBusDevice *dev)
403: {
404: CadenceTTCState *s = FROM_SYSBUS(CadenceTTCState, dev);
405: int i;
406:
407: for (i = 0; i < 3; ++i) {
408: cadence_timer_init(2500000, &s->timer[i]);
409: sysbus_init_irq(dev, &s->timer[i].irq);
410: }
411:
412: memory_region_init_io(&s->iomem, &cadence_ttc_ops, s, "timer", 0x1000);
413: sysbus_init_mmio(dev, &s->iomem);
414:
415: return 0;
416: }
417:
418: static void cadence_timer_pre_save(void *opaque)
419: {
420: cadence_timer_sync((CadenceTimerState *)opaque);
421: }
422:
423: static int cadence_timer_post_load(void *opaque, int version_id)
424: {
425: CadenceTimerState *s = opaque;
426:
427: s->cpu_time_valid = 0;
428: cadence_timer_sync(s);
429: cadence_timer_run(s);
430: cadence_timer_update(s);
431: return 0;
432: }
433:
434: static const VMStateDescription vmstate_cadence_timer = {
435: .name = "cadence_timer",
436: .version_id = 1,
437: .minimum_version_id = 1,
438: .minimum_version_id_old = 1,
439: .pre_save = cadence_timer_pre_save,
440: .post_load = cadence_timer_post_load,
441: .fields = (VMStateField[]) {
442: VMSTATE_UINT32(reg_clock, CadenceTimerState),
443: VMSTATE_UINT32(reg_count, CadenceTimerState),
444: VMSTATE_UINT32(reg_value, CadenceTimerState),
445: VMSTATE_UINT16(reg_interval, CadenceTimerState),
446: VMSTATE_UINT16_ARRAY(reg_match, CadenceTimerState, 3),
447: VMSTATE_UINT32(reg_intr, CadenceTimerState),
448: VMSTATE_UINT32(reg_intr_en, CadenceTimerState),
449: VMSTATE_UINT32(reg_event_ctrl, CadenceTimerState),
450: VMSTATE_UINT32(reg_event, CadenceTimerState),
451: VMSTATE_END_OF_LIST()
452: }
453: };
454:
455: static const VMStateDescription vmstate_cadence_ttc = {
456: .name = "cadence_TTC",
457: .version_id = 1,
458: .minimum_version_id = 1,
459: .minimum_version_id_old = 1,
460: .fields = (VMStateField[]) {
461: VMSTATE_STRUCT_ARRAY(timer, CadenceTTCState, 3, 0,
462: vmstate_cadence_timer,
463: CadenceTimerState),
464: VMSTATE_END_OF_LIST()
465: }
466: };
467:
468: static void cadence_ttc_class_init(ObjectClass *klass, void *data)
469: {
470: DeviceClass *dc = DEVICE_CLASS(klass);
471: SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
472:
473: sdc->init = cadence_ttc_init;
474: dc->vmsd = &vmstate_cadence_ttc;
475: }
476:
477: static TypeInfo cadence_ttc_info = {
478: .name = "cadence_ttc",
479: .parent = TYPE_SYS_BUS_DEVICE,
480: .instance_size = sizeof(CadenceTTCState),
481: .class_init = cadence_ttc_class_init,
482: };
483:
484: static void cadence_ttc_register_types(void)
485: {
486: type_register_static(&cadence_ttc_info);
487: }
488:
489: type_init(cadence_ttc_register_types)
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.