1:
2:
3:
4:
5:
6:
7:
8:
9:
10: #include "hw.h"
11: #include "qemu-timer.h"
12: #include "primecell.h"
13:
14: #define MPCORE_PRIV_BASE 0x10100000
15: #define NCPU 4
16:
17:
18:
19: #define GIC_NIRQ 64
20:
21: static inline int
22: gic_get_current_cpu(void)
23: {
24: return cpu_single_env->cpu_index;
25: }
26:
27: #include "arm_gic.c"
28:
29:
30:
31: typedef struct {
32: uint32_t count;
33: uint32_t load;
34: uint32_t control;
35: uint32_t status;
36: uint32_t old_status;
37: int64_t tick;
38: QEMUTimer *timer;
39: struct mpcore_priv_state *mpcore;
40: int id;
41: } mpcore_timer_state;
42:
43: typedef struct mpcore_priv_state {
44: gic_state *gic;
45: uint32_t scu_control;
46: mpcore_timer_state timer[8];
47: } mpcore_priv_state;
48:
49:
50:
51: static inline void mpcore_timer_update_irq(mpcore_timer_state *s)
52: {
53: if (s->status & ~s->old_status) {
54: gic_set_pending_private(s->mpcore->gic, s->id >> 1, 29 + (s->id & 1));
55: }
56: s->old_status = s->status;
57: }
58:
59:
60: static inline uint32_t mpcore_timer_scale(mpcore_timer_state *s)
61: {
62: return (((s->control >> 8) & 0xff) + 1) * 10;
63: }
64:
65: static void mpcore_timer_reload(mpcore_timer_state *s, int restart)
66: {
67: if (s->count == 0)
68: return;
69: if (restart)
70: s->tick = qemu_get_clock(vm_clock);
71: s->tick += (int64_t)s->count * mpcore_timer_scale(s);
72: qemu_mod_timer(s->timer, s->tick);
73: }
74:
75: static void mpcore_timer_tick(void *opaque)
76: {
77: mpcore_timer_state *s = (mpcore_timer_state *)opaque;
78: s->status = 1;
79: if (s->control & 2) {
80: s->count = s->load;
81: mpcore_timer_reload(s, 0);
82: } else {
83: s->count = 0;
84: }
85: mpcore_timer_update_irq(s);
86: }
87:
88: static uint32_t mpcore_timer_read(mpcore_timer_state *s, int offset)
89: {
90: int64_t val;
91: switch (offset) {
92: case 0:
93: return s->load;
94:
95: case 4:
96: if (((s->control & 1) == 0) || (s->count == 0))
97: return 0;
98:
99: val = s->tick - qemu_get_clock(vm_clock);
100: val /= mpcore_timer_scale(s);
101: if (val < 0)
102: val = 0;
103: return val;
104: case 8:
105: return s->control;
106: case 12:
107: return s->status;
108: }
109: }
110:
111: static void mpcore_timer_write(mpcore_timer_state *s, int offset,
112: uint32_t value)
113: {
114: int64_t old;
115: switch (offset) {
116: case 0:
117: s->load = value;
118:
119: case 4:
120: if ((s->control & 1) && s->count) {
121:
122: qemu_del_timer(s->timer);
123: }
124: s->count = value;
125: if (s->control & 1) {
126: mpcore_timer_reload(s, 1);
127: }
128: break;
129: case 8:
130: old = s->control;
131: s->control = value;
132: if (((old & 1) == 0) && (value & 1)) {
133: if (s->count == 0 && (s->control & 2))
134: s->count = s->load;
135: mpcore_timer_reload(s, 1);
136: }
137: break;
138: case 12:
139: s->status &= ~value;
140: mpcore_timer_update_irq(s);
141: break;
142: }
143: }
144:
145: static void mpcore_timer_init(mpcore_priv_state *mpcore,
146: mpcore_timer_state *s, int id)
147: {
148: s->id = id;
149: s->mpcore = mpcore;
150: s->timer = qemu_new_timer(vm_clock, mpcore_timer_tick, s);
151: }
152:
153:
154:
155:
156: static uint32_t mpcore_priv_read(void *opaque, target_phys_addr_t offset)
157: {
158: mpcore_priv_state *s = (mpcore_priv_state *)opaque;
159: int id;
160: offset &= 0xfff;
161: if (offset < 0x100) {
162:
163: switch (offset) {
164: case 0x00:
165: return s->scu_control;
166: case 0x04:
167: return 0xf3;
168: case 0x08:
169: return 0;
170: case 0x0c:
171: return 0;
172: default:
173: goto bad_reg;
174: }
175: } else if (offset < 0x600) {
176:
177: if (offset < 0x200) {
178: id = gic_get_current_cpu();
179: } else {
180: id = (offset - 0x200) >> 8;
181: }
182: return gic_cpu_read(s->gic, id, offset & 0xff);
183: } else if (offset < 0xb00) {
184:
185: if (offset < 0x700) {
186: id = gic_get_current_cpu();
187: } else {
188: id = (offset - 0x700) >> 8;
189: }
190: id <<= 1;
191: if (offset & 0x20)
192: id++;
193: return mpcore_timer_read(&s->timer[id], offset & 0xf);
194: }
195: bad_reg:
196: cpu_abort(cpu_single_env, "mpcore_priv_read: Bad offset %x\n",
197: (int)offset);
198: return 0;
199: }
200:
201: static void mpcore_priv_write(void *opaque, target_phys_addr_t offset,
202: uint32_t value)
203: {
204: mpcore_priv_state *s = (mpcore_priv_state *)opaque;
205: int id;
206: offset &= 0xfff;
207: if (offset < 0x100) {
208:
209: switch (offset) {
210: case 0:
211: s->scu_control = value & 1;
212: break;
213: case 0x0c:
214:
215: break;
216: default:
217: goto bad_reg;
218: }
219: } else if (offset < 0x600) {
220:
221: if (offset < 0x200) {
222: id = gic_get_current_cpu();
223: } else {
224: id = (offset - 0x200) >> 8;
225: }
226: gic_cpu_write(s->gic, id, offset & 0xff, value);
227: } else if (offset < 0xb00) {
228:
229: if (offset < 0x700) {
230: id = gic_get_current_cpu();
231: } else {
232: id = (offset - 0x700) >> 8;
233: }
234: id <<= 1;
235: if (offset & 0x20)
236: id++;
237: mpcore_timer_write(&s->timer[id], offset & 0xf, value);
238: return;
239: }
240: return;
241: bad_reg:
242: cpu_abort(cpu_single_env, "mpcore_priv_read: Bad offset %x\n",
243: (int)offset);
244: }
245:
246: static CPUReadMemoryFunc *mpcore_priv_readfn[] = {
247: mpcore_priv_read,
248: mpcore_priv_read,
249: mpcore_priv_read
250: };
251:
252: static CPUWriteMemoryFunc *mpcore_priv_writefn[] = {
253: mpcore_priv_write,
254: mpcore_priv_write,
255: mpcore_priv_write
256: };
257:
258:
259: static qemu_irq *mpcore_priv_init(uint32_t base, qemu_irq *pic_irq)
260: {
261: mpcore_priv_state *s;
262: int iomemtype;
263: int i;
264:
265: s = (mpcore_priv_state *)qemu_mallocz(sizeof(mpcore_priv_state));
266: if (!s)
267: return NULL;
268: s->gic = gic_init(base, pic_irq);
269: if (!s->gic)
270: return NULL;
271: iomemtype = cpu_register_io_memory(0, mpcore_priv_readfn,
272: mpcore_priv_writefn, s);
273: cpu_register_physical_memory(base, 0x00001000, iomemtype);
274: for (i = 0; i < 8; i++) {
275: mpcore_timer_init(s, &s->timer[i], i);
276: }
277: return s->gic->in;
278: }
279:
280:
281:
282:
283: typedef struct {
284: qemu_irq *cpuic;
285: qemu_irq *rvic[4];
286: } mpcore_rirq_state;
287:
288:
289: static const int mpcore_irq_map[32] = {
290: -1, -1, -1, -1, 1, 2, -1, -1,
291: -1, -1, 6, -1, 4, 5, -1, -1,
292: -1, 14, 15, 0, 7, 8, -1, -1,
293: -1, -1, -1, -1, 9, 3, -1, -1,
294: };
295:
296: static void mpcore_rirq_set_irq(void *opaque, int irq, int level)
297: {
298: mpcore_rirq_state *s = (mpcore_rirq_state *)opaque;
299: int i;
300:
301: for (i = 0; i < 4; i++) {
302: qemu_set_irq(s->rvic[i][irq], level);
303: }
304: if (irq < 32) {
305: irq = mpcore_irq_map[irq];
306: if (irq >= 0) {
307: qemu_set_irq(s->cpuic[irq], level);
308: }
309: }
310: }
311:
312: qemu_irq *mpcore_irq_init(qemu_irq *cpu_irq)
313: {
314: mpcore_rirq_state *s;
315: int n;
316:
317:
318: s = qemu_mallocz(sizeof(mpcore_rirq_state));
319: s->cpuic = mpcore_priv_init(MPCORE_PRIV_BASE, cpu_irq);
320: for (n = 0; n < 4; n++) {
321: s->rvic[n] = realview_gic_init(0x10040000 + n * 0x10000,
322: s->cpuic[10 + n]);
323: }
324: return qemu_allocate_irqs(mpcore_rirq_set_irq, s, 64);
325: }