added cpu_model parameter to cpu_init()
[qemu] / hw / ppc4xx_devs.c
1 /*
2  * QEMU PowerPC 4xx embedded processors shared devices emulation
3  *
4  * Copyright (c) 2007 Jocelyn Mayer
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 #include "vl.h"
25 #include "ppc4xx.h"
26
27 extern int loglevel;
28 extern FILE *logfile;
29
30 //#define DEBUG_MMIO
31 #define DEBUG_UIC
32
33 /*****************************************************************************/
34 /* Generic PowerPC 4xx processor instanciation */
35 CPUState *ppc4xx_init (const unsigned char *cpu_model,
36                        clk_setup_t *cpu_clk, clk_setup_t *tb_clk,
37                        uint32_t sysclk)
38 {
39     CPUState *env;
40
41     /* init CPUs */
42     env = cpu_init(cpu_model);
43     if (!env) {
44         fprintf(stderr, "Unable to find PowerPC %s CPU definition\n",
45                 cpu_model);
46         exit(1);
47     }
48     cpu_clk->cb = NULL; /* We don't care about CPU clock frequency changes */
49     cpu_clk->opaque = env;
50     /* Set time-base frequency to sysclk */
51     tb_clk->cb = ppc_emb_timers_init(env, sysclk);
52     tb_clk->opaque = env;
53     ppc_dcr_init(env, NULL, NULL);
54     /* Register qemu callbacks */
55     qemu_register_reset(&cpu_ppc_reset, env);
56     register_savevm("cpu", 0, 3, cpu_save, cpu_load, env);
57
58     return env;
59 }
60
61 /*****************************************************************************/
62 /* Fake device used to map multiple devices in a single memory page */
63 #define MMIO_AREA_BITS 8
64 #define MMIO_AREA_LEN (1 << MMIO_AREA_BITS)
65 #define MMIO_AREA_NB (1 << (TARGET_PAGE_BITS - MMIO_AREA_BITS))
66 #define MMIO_IDX(addr) (((addr) >> MMIO_AREA_BITS) & (MMIO_AREA_NB - 1))
67 struct ppc4xx_mmio_t {
68     target_phys_addr_t base;
69     CPUReadMemoryFunc **mem_read[MMIO_AREA_NB];
70     CPUWriteMemoryFunc **mem_write[MMIO_AREA_NB];
71     void *opaque[MMIO_AREA_NB];
72 };
73
74 static uint32_t unassigned_mmio_readb (void *opaque, target_phys_addr_t addr)
75 {
76 #ifdef DEBUG_UNASSIGNED
77     ppc4xx_mmio_t *mmio;
78
79     mmio = opaque;
80     printf("Unassigned mmio read 0x" PADDRX " base " PADDRX "\n",
81            addr, mmio->base);
82 #endif
83
84     return 0;
85 }
86
87 static void unassigned_mmio_writeb (void *opaque,
88                                     target_phys_addr_t addr, uint32_t val)
89 {
90 #ifdef DEBUG_UNASSIGNED
91     ppc4xx_mmio_t *mmio;
92
93     mmio = opaque;
94     printf("Unassigned mmio write 0x" PADDRX " = 0x%x base " PADDRX "\n",
95            addr, val, mmio->base);
96 #endif
97 }
98
99 static CPUReadMemoryFunc *unassigned_mmio_read[3] = {
100     unassigned_mmio_readb,
101     unassigned_mmio_readb,
102     unassigned_mmio_readb,
103 };
104
105 static CPUWriteMemoryFunc *unassigned_mmio_write[3] = {
106     unassigned_mmio_writeb,
107     unassigned_mmio_writeb,
108     unassigned_mmio_writeb,
109 };
110
111 static uint32_t mmio_readlen (ppc4xx_mmio_t *mmio,
112                               target_phys_addr_t addr, int len)
113 {
114     CPUReadMemoryFunc **mem_read;
115     uint32_t ret;
116     int idx;
117
118     idx = MMIO_IDX(addr - mmio->base);
119 #if defined(DEBUG_MMIO)
120     printf("%s: mmio %p len %d addr " PADDRX " idx %d\n", __func__,
121            mmio, len, addr, idx);
122 #endif
123     mem_read = mmio->mem_read[idx];
124     ret = (*mem_read[len])(mmio->opaque[idx], addr - mmio->base);
125
126     return ret;
127 }
128
129 static void mmio_writelen (ppc4xx_mmio_t *mmio,
130                            target_phys_addr_t addr, uint32_t value, int len)
131 {
132     CPUWriteMemoryFunc **mem_write;
133     int idx;
134
135     idx = MMIO_IDX(addr - mmio->base);
136 #if defined(DEBUG_MMIO)
137     printf("%s: mmio %p len %d addr " PADDRX " idx %d value %08x\n", __func__,
138            mmio, len, addr, idx, value);
139 #endif
140     mem_write = mmio->mem_write[idx];
141     (*mem_write[len])(mmio->opaque[idx], addr - mmio->base, value);
142 }
143
144 static uint32_t mmio_readb (void *opaque, target_phys_addr_t addr)
145 {
146 #if defined(DEBUG_MMIO)
147     printf("%s: addr " PADDRX "\n", __func__, addr);
148 #endif
149
150     return mmio_readlen(opaque, addr, 0);
151 }
152
153 static void mmio_writeb (void *opaque,
154                          target_phys_addr_t addr, uint32_t value)
155 {
156 #if defined(DEBUG_MMIO)
157     printf("%s: addr " PADDRX " val %08x\n", __func__, addr, value);
158 #endif
159     mmio_writelen(opaque, addr, value, 0);
160 }
161
162 static uint32_t mmio_readw (void *opaque, target_phys_addr_t addr)
163 {
164 #if defined(DEBUG_MMIO)
165     printf("%s: addr " PADDRX "\n", __func__, addr);
166 #endif
167
168     return mmio_readlen(opaque, addr, 1);
169 }
170
171 static void mmio_writew (void *opaque,
172                          target_phys_addr_t addr, uint32_t value)
173 {
174 #if defined(DEBUG_MMIO)
175     printf("%s: addr " PADDRX " val %08x\n", __func__, addr, value);
176 #endif
177     mmio_writelen(opaque, addr, value, 1);
178 }
179
180 static uint32_t mmio_readl (void *opaque, target_phys_addr_t addr)
181 {
182 #if defined(DEBUG_MMIO)
183     printf("%s: addr " PADDRX "\n", __func__, addr);
184 #endif
185
186     return mmio_readlen(opaque, addr, 2);
187 }
188
189 static void mmio_writel (void *opaque,
190                          target_phys_addr_t addr, uint32_t value)
191 {
192 #if defined(DEBUG_MMIO)
193     printf("%s: addr " PADDRX " val %08x\n", __func__, addr, value);
194 #endif
195     mmio_writelen(opaque, addr, value, 2);
196 }
197
198 static CPUReadMemoryFunc *mmio_read[] = {
199     &mmio_readb,
200     &mmio_readw,
201     &mmio_readl,
202 };
203
204 static CPUWriteMemoryFunc *mmio_write[] = {
205     &mmio_writeb,
206     &mmio_writew,
207     &mmio_writel,
208 };
209
210 int ppc4xx_mmio_register (CPUState *env, ppc4xx_mmio_t *mmio,
211                           target_phys_addr_t offset, uint32_t len,
212                           CPUReadMemoryFunc **mem_read,
213                           CPUWriteMemoryFunc **mem_write, void *opaque)
214 {
215     uint32_t end;
216     int idx, eidx;
217
218     if ((offset + len) > TARGET_PAGE_SIZE)
219         return -1;
220     idx = MMIO_IDX(offset);
221     end = offset + len - 1;
222     eidx = MMIO_IDX(end);
223 #if defined(DEBUG_MMIO)
224     printf("%s: offset %08x len %08x %08x %d %d\n", __func__, offset, len,
225            end, idx, eidx);
226 #endif
227     for (; idx <= eidx; idx++) {
228         mmio->mem_read[idx] = mem_read;
229         mmio->mem_write[idx] = mem_write;
230         mmio->opaque[idx] = opaque;
231     }
232
233     return 0;
234 }
235
236 ppc4xx_mmio_t *ppc4xx_mmio_init (CPUState *env, target_phys_addr_t base)
237 {
238     ppc4xx_mmio_t *mmio;
239     int mmio_memory;
240
241     mmio = qemu_mallocz(sizeof(ppc4xx_mmio_t));
242     if (mmio != NULL) {
243         mmio->base = base;
244         mmio_memory = cpu_register_io_memory(0, mmio_read, mmio_write, mmio);
245 #if defined(DEBUG_MMIO)
246         printf("%s: %p base %08x len %08x %d\n", __func__,
247                mmio, base, TARGET_PAGE_SIZE, mmio_memory);
248 #endif
249         cpu_register_physical_memory(base, TARGET_PAGE_SIZE, mmio_memory);
250         ppc4xx_mmio_register(env, mmio, 0, TARGET_PAGE_SIZE,
251                              unassigned_mmio_read, unassigned_mmio_write,
252                              mmio);
253     }
254
255     return mmio;
256 }
257
258 /*****************************************************************************/
259 /* "Universal" Interrupt controller */
260 enum {
261     DCR_UICSR  = 0x000,
262     DCR_UICSRS = 0x001,
263     DCR_UICER  = 0x002,
264     DCR_UICCR  = 0x003,
265     DCR_UICPR  = 0x004,
266     DCR_UICTR  = 0x005,
267     DCR_UICMSR = 0x006,
268     DCR_UICVR  = 0x007,
269     DCR_UICVCR = 0x008,
270     DCR_UICMAX = 0x009,
271 };
272
273 #define UIC_MAX_IRQ 32
274 typedef struct ppcuic_t ppcuic_t;
275 struct ppcuic_t {
276     uint32_t dcr_base;
277     int use_vectors;
278     uint32_t uicsr;  /* Status register */
279     uint32_t uicer;  /* Enable register */
280     uint32_t uiccr;  /* Critical register */
281     uint32_t uicpr;  /* Polarity register */
282     uint32_t uictr;  /* Triggering register */
283     uint32_t uicvcr; /* Vector configuration register */
284     uint32_t uicvr;
285     qemu_irq *irqs;
286 };
287
288 static void ppcuic_trigger_irq (ppcuic_t *uic)
289 {
290     uint32_t ir, cr;
291     int start, end, inc, i;
292
293     /* Trigger interrupt if any is pending */
294     ir = uic->uicsr & uic->uicer & (~uic->uiccr);
295     cr = uic->uicsr & uic->uicer & uic->uiccr;
296 #ifdef DEBUG_UIC
297     if (loglevel & CPU_LOG_INT) {
298         fprintf(logfile, "%s: uicsr %08x uicer %08x uiccr %08x\n"
299                 "   %08x ir %08x cr %08x\n", __func__,
300                 uic->uicsr, uic->uicer, uic->uiccr,
301                 uic->uicsr & uic->uicer, ir, cr);
302     }
303 #endif
304     if (ir != 0x0000000) {
305 #ifdef DEBUG_UIC
306         if (loglevel & CPU_LOG_INT) {
307             fprintf(logfile, "Raise UIC interrupt\n");
308         }
309 #endif
310         qemu_irq_raise(uic->irqs[PPCUIC_OUTPUT_INT]);
311     } else {
312 #ifdef DEBUG_UIC
313         if (loglevel & CPU_LOG_INT) {
314             fprintf(logfile, "Lower UIC interrupt\n");
315         }
316 #endif
317         qemu_irq_lower(uic->irqs[PPCUIC_OUTPUT_INT]);
318     }
319     /* Trigger critical interrupt if any is pending and update vector */
320     if (cr != 0x0000000) {
321         qemu_irq_raise(uic->irqs[PPCUIC_OUTPUT_CINT]);
322         if (uic->use_vectors) {
323             /* Compute critical IRQ vector */
324             if (uic->uicvcr & 1) {
325                 start = 31;
326                 end = 0;
327                 inc = -1;
328             } else {
329                 start = 0;
330                 end = 31;
331                 inc = 1;
332             }
333             uic->uicvr = uic->uicvcr & 0xFFFFFFFC;
334             for (i = start; i <= end; i += inc) {
335                 if (cr & (1 << i)) {
336                     uic->uicvr += (i - start) * 512 * inc;
337                     break;
338                 }
339             }
340         }
341 #ifdef DEBUG_UIC
342         if (loglevel & CPU_LOG_INT) {
343             fprintf(logfile, "Raise UIC critical interrupt - vector %08x\n",
344                     uic->uicvr);
345         }
346 #endif
347     } else {
348 #ifdef DEBUG_UIC
349         if (loglevel & CPU_LOG_INT) {
350             fprintf(logfile, "Lower UIC critical interrupt\n");
351         }
352 #endif
353         qemu_irq_lower(uic->irqs[PPCUIC_OUTPUT_CINT]);
354         uic->uicvr = 0x00000000;
355     }
356 }
357
358 static void ppcuic_set_irq (void *opaque, int irq_num, int level)
359 {
360     ppcuic_t *uic;
361     uint32_t mask, sr;
362
363     uic = opaque;
364     mask = 1 << irq_num;
365 #ifdef DEBUG_UIC
366     if (loglevel & CPU_LOG_INT) {
367         fprintf(logfile, "%s: irq %d level %d uicsr %08x mask %08x => %08x "
368                 "%08x\n", __func__, irq_num, level,
369                 uic->uicsr, mask, uic->uicsr & mask, level << irq_num);
370     }
371 #endif
372     if (irq_num < 0 || irq_num > 31)
373         return;
374     sr = uic->uicsr;
375     if (!(uic->uicpr & mask)) {
376         /* Negatively asserted IRQ */
377         level = level == 0 ? 1 : 0;
378     }
379     /* Update status register */
380     if (uic->uictr & mask) {
381         /* Edge sensitive interrupt */
382         if (level == 1)
383             uic->uicsr |= mask;
384     } else {
385         /* Level sensitive interrupt */
386         if (level == 1)
387             uic->uicsr |= mask;
388         else
389             uic->uicsr &= ~mask;
390     }
391 #ifdef DEBUG_UIC
392     if (loglevel & CPU_LOG_INT) {
393         fprintf(logfile, "%s: irq %d level %d sr %08x => %08x\n", __func__,
394                 irq_num, level, uic->uicsr, sr);
395     }
396 #endif
397     if (sr != uic->uicsr)
398         ppcuic_trigger_irq(uic);
399 }
400
401 static target_ulong dcr_read_uic (void *opaque, int dcrn)
402 {
403     ppcuic_t *uic;
404     target_ulong ret;
405
406     uic = opaque;
407     dcrn -= uic->dcr_base;
408     switch (dcrn) {
409     case DCR_UICSR:
410     case DCR_UICSRS:
411         ret = uic->uicsr;
412         break;
413     case DCR_UICER:
414         ret = uic->uicer;
415         break;
416     case DCR_UICCR:
417         ret = uic->uiccr;
418         break;
419     case DCR_UICPR:
420         ret = uic->uicpr;
421         break;
422     case DCR_UICTR:
423         ret = uic->uictr;
424         break;
425     case DCR_UICMSR:
426         ret = uic->uicsr & uic->uicer;
427         break;
428     case DCR_UICVR:
429         if (!uic->use_vectors)
430             goto no_read;
431         ret = uic->uicvr;
432         break;
433     case DCR_UICVCR:
434         if (!uic->use_vectors)
435             goto no_read;
436         ret = uic->uicvcr;
437         break;
438     default:
439     no_read:
440         ret = 0x00000000;
441         break;
442     }
443
444     return ret;
445 }
446
447 static void dcr_write_uic (void *opaque, int dcrn, target_ulong val)
448 {
449     ppcuic_t *uic;
450
451     uic = opaque;
452     dcrn -= uic->dcr_base;
453 #ifdef DEBUG_UIC
454     if (loglevel & CPU_LOG_INT) {
455         fprintf(logfile, "%s: dcr %d val " ADDRX "\n", __func__, dcrn, val);
456     }
457 #endif
458     switch (dcrn) {
459     case DCR_UICSR:
460         uic->uicsr &= ~val;
461         ppcuic_trigger_irq(uic);
462         break;
463     case DCR_UICSRS:
464         uic->uicsr |= val;
465         ppcuic_trigger_irq(uic);
466         break;
467     case DCR_UICER:
468         uic->uicer = val;
469         ppcuic_trigger_irq(uic);
470         break;
471     case DCR_UICCR:
472         uic->uiccr = val;
473         ppcuic_trigger_irq(uic);
474         break;
475     case DCR_UICPR:
476         uic->uicpr = val;
477         ppcuic_trigger_irq(uic);
478         break;
479     case DCR_UICTR:
480         uic->uictr = val;
481         ppcuic_trigger_irq(uic);
482         break;
483     case DCR_UICMSR:
484         break;
485     case DCR_UICVR:
486         break;
487     case DCR_UICVCR:
488         uic->uicvcr = val & 0xFFFFFFFD;
489         ppcuic_trigger_irq(uic);
490         break;
491     }
492 }
493
494 static void ppcuic_reset (void *opaque)
495 {
496     ppcuic_t *uic;
497
498     uic = opaque;
499     uic->uiccr = 0x00000000;
500     uic->uicer = 0x00000000;
501     uic->uicpr = 0x00000000;
502     uic->uicsr = 0x00000000;
503     uic->uictr = 0x00000000;
504     if (uic->use_vectors) {
505         uic->uicvcr = 0x00000000;
506         uic->uicvr = 0x0000000;
507     }
508 }
509
510 qemu_irq *ppcuic_init (CPUState *env, qemu_irq *irqs,
511                        uint32_t dcr_base, int has_ssr, int has_vr)
512 {
513     ppcuic_t *uic;
514     int i;
515
516     uic = qemu_mallocz(sizeof(ppcuic_t));
517     if (uic != NULL) {
518         uic->dcr_base = dcr_base;
519         uic->irqs = irqs;
520         if (has_vr)
521             uic->use_vectors = 1;
522         for (i = 0; i < DCR_UICMAX; i++) {
523             ppc_dcr_register(env, dcr_base + i, uic,
524                              &dcr_read_uic, &dcr_write_uic);
525         }
526         qemu_register_reset(ppcuic_reset, uic);
527         ppcuic_reset(uic);
528     }
529
530     return qemu_allocate_irqs(&ppcuic_set_irq, uic, UIC_MAX_IRQ);
531 }