82db38ddfdb7e8abfb9fed40c9644ef976470cbc
[qemu] / hw / mcf5208.c
1 /*
2  * Motorola ColdFire MCF5208 SoC emulation.
3  *
4  * Copyright (c) 2007 CodeSourcery.
5  *
6  * This code is licenced under the GPL
7  */
8 #include "hw.h"
9 #include "mcf.h"
10 #include "qemu-timer.h"
11 #include "sysemu.h"
12 #include "net.h"
13 #include "boards.h"
14
15 #define SYS_FREQ 66000000
16
17 #define PCSR_EN         0x0001
18 #define PCSR_RLD        0x0002
19 #define PCSR_PIF        0x0004
20 #define PCSR_PIE        0x0008
21 #define PCSR_OVW        0x0010
22 #define PCSR_DBG        0x0020
23 #define PCSR_DOZE       0x0040
24 #define PCSR_PRE_SHIFT  8
25 #define PCSR_PRE_MASK   0x0f00
26
27 typedef struct {
28     qemu_irq irq;
29     ptimer_state *timer;
30     uint16_t pcsr;
31     uint16_t pmr;
32     uint16_t pcntr;
33 } m5208_timer_state;
34
35 static void m5208_timer_update(m5208_timer_state *s)
36 {
37     if ((s->pcsr & (PCSR_PIE | PCSR_PIF)) == (PCSR_PIE | PCSR_PIF))
38         qemu_irq_raise(s->irq);
39     else
40         qemu_irq_lower(s->irq);
41 }
42
43 static void m5208_timer_write(m5208_timer_state *s, int offset,
44                               uint32_t value)
45 {
46     int prescale;
47     int limit;
48     switch (offset) {
49     case 0:
50         /* The PIF bit is set-to-clear.  */
51         if (value & PCSR_PIF) {
52             s->pcsr &= ~PCSR_PIF;
53             value &= ~PCSR_PIF;
54         }
55         /* Avoid frobbing the timer if we're just twiddling IRQ bits. */
56         if (((s->pcsr ^ value) & ~PCSR_PIE) == 0) {
57             s->pcsr = value;
58             m5208_timer_update(s);
59             return;
60         }
61
62         if (s->pcsr & PCSR_EN)
63             ptimer_stop(s->timer);
64
65         s->pcsr = value;
66
67         prescale = 1 << ((s->pcsr & PCSR_PRE_MASK) >> PCSR_PRE_SHIFT);
68         ptimer_set_freq(s->timer, (SYS_FREQ / 2) / prescale);
69         if (s->pcsr & PCSR_RLD)
70             limit = s->pmr;
71         else
72             limit = 0xffff;
73         ptimer_set_limit(s->timer, limit, 0);
74
75         if (s->pcsr & PCSR_EN)
76             ptimer_run(s->timer, 0);
77         break;
78     case 2:
79         s->pmr = value;
80         s->pcsr &= ~PCSR_PIF;
81         if ((s->pcsr & PCSR_RLD) == 0) {
82             if (s->pcsr & PCSR_OVW)
83                 ptimer_set_count(s->timer, value);
84         } else {
85             ptimer_set_limit(s->timer, value, s->pcsr & PCSR_OVW);
86         }
87         break;
88     case 4:
89         break;
90     default:
91         /* Should never happen.  */
92         abort();
93     }
94     m5208_timer_update(s);
95 }
96
97 static void m5208_timer_trigger(void *opaque)
98 {
99     m5208_timer_state *s = (m5208_timer_state *)opaque;
100     s->pcsr |= PCSR_PIF;
101     m5208_timer_update(s);
102 }
103
104 typedef struct {
105     m5208_timer_state timer[2];
106 } m5208_sys_state;
107
108 static uint32_t m5208_sys_read(void *opaque, target_phys_addr_t addr)
109 {
110     m5208_sys_state *s = (m5208_sys_state *)opaque;
111     switch (addr) {
112     /* PIT0 */
113     case 0xfc080000:
114         return s->timer[0].pcsr;
115     case 0xfc080002:
116         return s->timer[0].pmr;
117     case 0xfc080004:
118         return ptimer_get_count(s->timer[0].timer);
119     /* PIT1 */
120     case 0xfc084000:
121         return s->timer[1].pcsr;
122     case 0xfc084002:
123         return s->timer[1].pmr;
124     case 0xfc084004:
125         return ptimer_get_count(s->timer[1].timer);
126
127     /* SDRAM Controller.  */
128     case 0xfc0a8110: /* SDCS0 */
129         {
130             int n;
131             for (n = 0; n < 32; n++) {
132                 if (ram_size < (2u << n))
133                     break;
134             }
135             return (n - 1)  | 0x40000000;
136         }
137     case 0xfc0a8114: /* SDCS1 */
138         return 0;
139
140     default:
141         cpu_abort(cpu_single_env, "m5208_sys_read: Bad offset 0x%x\n",
142                   (int)addr);
143         return 0;
144     }
145 }
146
147 static void m5208_sys_write(void *opaque, target_phys_addr_t addr,
148                             uint32_t value)
149 {
150     m5208_sys_state *s = (m5208_sys_state *)opaque;
151     switch (addr) {
152     /* PIT0 */
153     case 0xfc080000:
154     case 0xfc080002:
155     case 0xfc080004:
156         m5208_timer_write(&s->timer[0], addr & 0xf, value);
157         return;
158     /* PIT1 */
159     case 0xfc084000:
160     case 0xfc084002:
161     case 0xfc084004:
162         m5208_timer_write(&s->timer[1], addr & 0xf, value);
163         return;
164     default:
165         cpu_abort(cpu_single_env, "m5208_sys_write: Bad offset 0x%x\n",
166                   (int)addr);
167         break;
168     }
169 }
170
171 static CPUReadMemoryFunc *m5208_sys_readfn[] = {
172    m5208_sys_read,
173    m5208_sys_read,
174    m5208_sys_read
175 };
176
177 static CPUWriteMemoryFunc *m5208_sys_writefn[] = {
178    m5208_sys_write,
179    m5208_sys_write,
180    m5208_sys_write
181 };
182
183 static void mcf5208_sys_init(qemu_irq *pic)
184 {
185     int iomemtype;
186     m5208_sys_state *s;
187     QEMUBH *bh;
188     int i;
189
190     s = (m5208_sys_state *)qemu_mallocz(sizeof(m5208_sys_state));
191     iomemtype = cpu_register_io_memory(0, m5208_sys_readfn,
192                                        m5208_sys_writefn, s);
193     /* SDRAMC.  */
194     cpu_register_physical_memory(0xfc0a8000, 0x00004000, iomemtype);
195     /* Timers.  */
196     for (i = 0; i < 2; i++) {
197         bh = qemu_bh_new(m5208_timer_trigger, &s->timer[i]);
198         s->timer[i].timer = ptimer_init(bh);
199         cpu_register_physical_memory(0xfc080000 + 0x4000 * i, 0x00004000,
200                                      iomemtype);
201         s->timer[i].irq = pic[4 + i];
202     }
203 }
204
205 static void mcf5208evb_init(ram_addr_t ram_size, int vga_ram_size,
206                      const char *boot_device, DisplayState *ds,
207                      const char *kernel_filename, const char *kernel_cmdline,
208                      const char *initrd_filename, const char *cpu_model)
209 {
210     CPUState *env;
211     int kernel_size;
212     uint64_t elf_entry;
213     target_ulong entry;
214     qemu_irq *pic;
215
216     if (!cpu_model)
217         cpu_model = "m5208";
218     env = cpu_init(cpu_model);
219     if (!env) {
220         fprintf(stderr, "Unable to find m68k CPU definition\n");
221         exit(1);
222     }
223
224     /* Initialize CPU registers.  */
225     env->vbr = 0;
226     /* TODO: Configure BARs.  */
227
228     /* DRAM at 0x20000000 */
229     cpu_register_physical_memory(0x40000000, ram_size,
230         qemu_ram_alloc(ram_size) | IO_MEM_RAM);
231
232     /* Internal SRAM.  */
233     cpu_register_physical_memory(0x80000000, 16384,
234         qemu_ram_alloc(16384) | IO_MEM_RAM);
235
236     /* Internal peripherals.  */
237     pic = mcf_intc_init(0xfc048000, env);
238
239     mcf_uart_mm_init(0xfc060000, pic[26], serial_hds[0]);
240     mcf_uart_mm_init(0xfc064000, pic[27], serial_hds[1]);
241     mcf_uart_mm_init(0xfc068000, pic[28], serial_hds[2]);
242
243     mcf5208_sys_init(pic);
244
245     if (nb_nics > 1) {
246         fprintf(stderr, "Too many NICs\n");
247         exit(1);
248     }
249     if (nd_table[0].vlan) {
250         if (nd_table[0].model == NULL
251             || strcmp(nd_table[0].model, "mcf_fec") == 0) {
252             mcf_fec_init(&nd_table[0], 0xfc030000, pic + 36);
253         } else if (strcmp(nd_table[0].model, "?") == 0) {
254             fprintf(stderr, "qemu: Supported NICs: mcf_fec\n");
255             exit (1);
256         } else {
257             fprintf(stderr, "qemu: Unsupported NIC: %s\n", nd_table[0].model);
258             exit (1);
259         }
260     }
261
262     /*  0xfc000000 SCM.  */
263     /*  0xfc004000 XBS.  */
264     /*  0xfc008000 FlexBus CS.  */
265     /* 0xfc030000 FEC.  */
266     /*  0xfc040000 SCM + Power management.  */
267     /*  0xfc044000 eDMA.  */
268     /* 0xfc048000 INTC.  */
269     /*  0xfc058000 I2C.  */
270     /*  0xfc05c000 QSPI.  */
271     /* 0xfc060000 UART0.  */
272     /* 0xfc064000 UART0.  */
273     /* 0xfc068000 UART0.  */
274     /*  0xfc070000 DMA timers.  */
275     /* 0xfc080000 PIT0.  */
276     /* 0xfc084000 PIT1.  */
277     /*  0xfc088000 EPORT.  */
278     /*  0xfc08c000 Watchdog.  */
279     /*  0xfc090000 clock module.  */
280     /*  0xfc0a0000 CCM + reset.  */
281     /*  0xfc0a4000 GPIO.  */
282     /* 0xfc0a8000 SDRAM controller.  */
283
284     /* Load kernel.  */
285     if (!kernel_filename) {
286         fprintf(stderr, "Kernel image must be specified\n");
287         exit(1);
288     }
289
290     kernel_size = load_elf(kernel_filename, 0, &elf_entry, NULL, NULL);
291     entry = elf_entry;
292     if (kernel_size < 0) {
293         kernel_size = load_uboot(kernel_filename, &entry, NULL, NULL);
294     }
295     if (kernel_size < 0) {
296         kernel_size = load_image(kernel_filename, phys_ram_base);
297         entry = 0x20000000;
298     }
299     if (kernel_size < 0) {
300         fprintf(stderr, "qemu: could not load kernel '%s'\n", kernel_filename);
301         exit(1);
302     }
303
304     env->pc = entry;
305 }
306
307 QEMUMachine mcf5208evb_machine = {
308     .name = "mcf5208evb",
309     .desc = "MCF5206EVB",
310     .init = mcf5208evb_init,
311     .ram_require = 16384,
312 };