xref: /openbmc/qemu/hw/m68k/mcf5208.c (revision 77b535cf)
1 /*
2  * Motorola ColdFire MCF5208 SoC emulation.
3  *
4  * Copyright (c) 2007 CodeSourcery.
5  *
6  * This code is licensed under the GPL
7  *
8  * This file models both the MCF5208 SoC, and the
9  * MCF5208EVB evaluation board. For details see
10  *
11  * "MCF5208 Reference Manual"
12  * https://www.nxp.com/docs/en/reference-manual/MCF5208RM.pdf
13  * "M5208EVB-RevB 32-bit Microcontroller User Manual"
14  * https://www.nxp.com/docs/en/reference-manual/M5208EVBUM.pdf
15  */
16 
17 #include "qemu/osdep.h"
18 #include "qemu/units.h"
19 #include "qemu/error-report.h"
20 #include "qemu/log.h"
21 #include "qapi/error.h"
22 #include "qemu/datadir.h"
23 #include "cpu.h"
24 #include "hw/irq.h"
25 #include "hw/m68k/mcf.h"
26 #include "hw/m68k/mcf_fec.h"
27 #include "qemu/timer.h"
28 #include "hw/ptimer.h"
29 #include "sysemu/sysemu.h"
30 #include "sysemu/qtest.h"
31 #include "net/net.h"
32 #include "hw/boards.h"
33 #include "hw/loader.h"
34 #include "hw/sysbus.h"
35 #include "elf.h"
36 
37 #define SYS_FREQ 166666666
38 
39 #define ROM_SIZE 0x200000
40 
41 #define PCSR_EN         0x0001
42 #define PCSR_RLD        0x0002
43 #define PCSR_PIF        0x0004
44 #define PCSR_PIE        0x0008
45 #define PCSR_OVW        0x0010
46 #define PCSR_DBG        0x0020
47 #define PCSR_DOZE       0x0040
48 #define PCSR_PRE_SHIFT  8
49 #define PCSR_PRE_MASK   0x0f00
50 
51 #define RCR_SOFTRST     0x80
52 
53 typedef struct {
54     MemoryRegion iomem;
55     qemu_irq irq;
56     ptimer_state *timer;
57     uint16_t pcsr;
58     uint16_t pmr;
59     uint16_t pcntr;
60 } m5208_timer_state;
61 
m5208_timer_update(m5208_timer_state * s)62 static void m5208_timer_update(m5208_timer_state *s)
63 {
64     if ((s->pcsr & (PCSR_PIE | PCSR_PIF)) == (PCSR_PIE | PCSR_PIF))
65         qemu_irq_raise(s->irq);
66     else
67         qemu_irq_lower(s->irq);
68 }
69 
m5208_timer_write(void * opaque,hwaddr offset,uint64_t value,unsigned size)70 static void m5208_timer_write(void *opaque, hwaddr offset,
71                               uint64_t value, unsigned size)
72 {
73     m5208_timer_state *s = (m5208_timer_state *)opaque;
74     int prescale;
75     int limit;
76     switch (offset) {
77     case 0:
78         /* The PIF bit is set-to-clear.  */
79         if (value & PCSR_PIF) {
80             s->pcsr &= ~PCSR_PIF;
81             value &= ~PCSR_PIF;
82         }
83         /* Avoid frobbing the timer if we're just twiddling IRQ bits. */
84         if (((s->pcsr ^ value) & ~PCSR_PIE) == 0) {
85             s->pcsr = value;
86             m5208_timer_update(s);
87             return;
88         }
89 
90         ptimer_transaction_begin(s->timer);
91         if (s->pcsr & PCSR_EN)
92             ptimer_stop(s->timer);
93 
94         s->pcsr = value;
95 
96         prescale = 1 << ((s->pcsr & PCSR_PRE_MASK) >> PCSR_PRE_SHIFT);
97         ptimer_set_freq(s->timer, (SYS_FREQ / 2) / prescale);
98         if (s->pcsr & PCSR_RLD)
99             limit = s->pmr;
100         else
101             limit = 0xffff;
102         ptimer_set_limit(s->timer, limit, 0);
103 
104         if (s->pcsr & PCSR_EN)
105             ptimer_run(s->timer, 0);
106         ptimer_transaction_commit(s->timer);
107         break;
108     case 2:
109         ptimer_transaction_begin(s->timer);
110         s->pmr = value;
111         s->pcsr &= ~PCSR_PIF;
112         if ((s->pcsr & PCSR_RLD) == 0) {
113             if (s->pcsr & PCSR_OVW)
114                 ptimer_set_count(s->timer, value);
115         } else {
116             ptimer_set_limit(s->timer, value, s->pcsr & PCSR_OVW);
117         }
118         ptimer_transaction_commit(s->timer);
119         break;
120     case 4:
121         break;
122     default:
123         qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIX "\n",
124                       __func__, offset);
125         return;
126     }
127     m5208_timer_update(s);
128 }
129 
m5208_timer_trigger(void * opaque)130 static void m5208_timer_trigger(void *opaque)
131 {
132     m5208_timer_state *s = (m5208_timer_state *)opaque;
133     s->pcsr |= PCSR_PIF;
134     m5208_timer_update(s);
135 }
136 
m5208_timer_read(void * opaque,hwaddr addr,unsigned size)137 static uint64_t m5208_timer_read(void *opaque, hwaddr addr,
138                                  unsigned size)
139 {
140     m5208_timer_state *s = (m5208_timer_state *)opaque;
141     switch (addr) {
142     case 0:
143         return s->pcsr;
144     case 2:
145         return s->pmr;
146     case 4:
147         return ptimer_get_count(s->timer);
148     default:
149         qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIX "\n",
150                       __func__, addr);
151         return 0;
152     }
153 }
154 
155 static const MemoryRegionOps m5208_timer_ops = {
156     .read = m5208_timer_read,
157     .write = m5208_timer_write,
158     .endianness = DEVICE_NATIVE_ENDIAN,
159 };
160 
m5208_sys_read(void * opaque,hwaddr addr,unsigned size)161 static uint64_t m5208_sys_read(void *opaque, hwaddr addr,
162                                unsigned size)
163 {
164     switch (addr) {
165     case 0x110: /* SDCS0 */
166         {
167             int n;
168             for (n = 0; n < 32; n++) {
169                 if (current_machine->ram_size < (2ULL << n)) {
170                     break;
171                 }
172             }
173             return (n - 1)  | 0x40000000;
174         }
175     case 0x114: /* SDCS1 */
176         return 0;
177 
178     default:
179         qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIX "\n",
180                       __func__, addr);
181         return 0;
182     }
183 }
184 
m5208_sys_write(void * opaque,hwaddr addr,uint64_t value,unsigned size)185 static void m5208_sys_write(void *opaque, hwaddr addr,
186                             uint64_t value, unsigned size)
187 {
188     qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIX "\n",
189                   __func__, addr);
190 }
191 
192 static const MemoryRegionOps m5208_sys_ops = {
193     .read = m5208_sys_read,
194     .write = m5208_sys_write,
195     .endianness = DEVICE_NATIVE_ENDIAN,
196 };
197 
m5208_rcm_read(void * opaque,hwaddr addr,unsigned size)198 static uint64_t m5208_rcm_read(void *opaque, hwaddr addr,
199                                unsigned size)
200 {
201     return 0;
202 }
203 
m5208_rcm_write(void * opaque,hwaddr addr,uint64_t value,unsigned size)204 static void m5208_rcm_write(void *opaque, hwaddr addr,
205                             uint64_t value, unsigned size)
206 {
207     M68kCPU *cpu = opaque;
208     CPUState *cs = CPU(cpu);
209     switch (addr) {
210     case 0x0: /* RCR */
211         if (value & RCR_SOFTRST) {
212             cpu_reset(cs);
213             cpu->env.aregs[7] = ldl_phys(cs->as, 0);
214             cpu->env.pc = ldl_phys(cs->as, 4);
215         }
216         break;
217     default:
218         qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIX "\n",
219                       __func__, addr);
220         break;
221     }
222 }
223 
224 static const MemoryRegionOps m5208_rcm_ops = {
225     .read = m5208_rcm_read,
226     .write = m5208_rcm_write,
227     .endianness = DEVICE_NATIVE_ENDIAN,
228 };
229 
mcf5208_sys_init(MemoryRegion * address_space,qemu_irq * pic,M68kCPU * cpu)230 static void mcf5208_sys_init(MemoryRegion *address_space, qemu_irq *pic,
231                              M68kCPU *cpu)
232 {
233     MemoryRegion *iomem = g_new(MemoryRegion, 1);
234     MemoryRegion *iomem_rcm = g_new(MemoryRegion, 1);
235     m5208_timer_state *s;
236     int i;
237 
238     /* RCM */
239     memory_region_init_io(iomem_rcm, NULL, &m5208_rcm_ops, cpu,
240                           "m5208-rcm", 0x00000080);
241     memory_region_add_subregion(address_space, 0xfc0a0000, iomem_rcm);
242     /* SDRAMC.  */
243     memory_region_init_io(iomem, NULL, &m5208_sys_ops, NULL, "m5208-sys", 0x00004000);
244     memory_region_add_subregion(address_space, 0xfc0a8000, iomem);
245     /* Timers.  */
246     for (i = 0; i < 2; i++) {
247         s = g_new0(m5208_timer_state, 1);
248         s->timer = ptimer_init(m5208_timer_trigger, s, PTIMER_POLICY_LEGACY);
249         memory_region_init_io(&s->iomem, NULL, &m5208_timer_ops, s,
250                               "m5208-timer", 0x00004000);
251         memory_region_add_subregion(address_space, 0xfc080000 + 0x4000 * i,
252                                     &s->iomem);
253         s->irq = pic[4 + i];
254     }
255 }
256 
mcf_fec_init(MemoryRegion * sysmem,hwaddr base,qemu_irq * irqs)257 static void mcf_fec_init(MemoryRegion *sysmem, hwaddr base, qemu_irq *irqs)
258 {
259     DeviceState *dev;
260     SysBusDevice *s;
261     int i;
262 
263     dev = qemu_create_nic_device(TYPE_MCF_FEC_NET, true, NULL);
264     if (!dev) {
265         return;
266     }
267 
268     s = SYS_BUS_DEVICE(dev);
269     sysbus_realize_and_unref(s, &error_fatal);
270     for (i = 0; i < FEC_NUM_IRQ; i++) {
271         sysbus_connect_irq(s, i, irqs[i]);
272     }
273 
274     memory_region_add_subregion(sysmem, base, sysbus_mmio_get_region(s, 0));
275 }
276 
mcf5208evb_init(MachineState * machine)277 static void mcf5208evb_init(MachineState *machine)
278 {
279     ram_addr_t ram_size = machine->ram_size;
280     const char *kernel_filename = machine->kernel_filename;
281     M68kCPU *cpu;
282     CPUM68KState *env;
283     int kernel_size;
284     uint64_t elf_entry;
285     hwaddr entry;
286     qemu_irq *pic;
287     MemoryRegion *address_space_mem = get_system_memory();
288     MemoryRegion *rom = g_new(MemoryRegion, 1);
289     MemoryRegion *sram = g_new(MemoryRegion, 1);
290 
291     cpu = M68K_CPU(cpu_create(machine->cpu_type));
292     env = &cpu->env;
293 
294     /* Initialize CPU registers.  */
295     env->vbr = 0;
296     /* TODO: Configure BARs.  */
297 
298     /* ROM at 0x00000000 */
299     memory_region_init_rom(rom, NULL, "mcf5208.rom", ROM_SIZE, &error_fatal);
300     memory_region_add_subregion(address_space_mem, 0x00000000, rom);
301 
302     /* DRAM at 0x40000000 */
303     memory_region_add_subregion(address_space_mem, 0x40000000, machine->ram);
304 
305     /* Internal SRAM.  */
306     memory_region_init_ram(sram, NULL, "mcf5208.sram", 16 * KiB, &error_fatal);
307     memory_region_add_subregion(address_space_mem, 0x80000000, sram);
308 
309     /* Internal peripherals.  */
310     pic = mcf_intc_init(address_space_mem, 0xfc048000, cpu);
311 
312     mcf_uart_create_mmap(0xfc060000, pic[26], serial_hd(0));
313     mcf_uart_create_mmap(0xfc064000, pic[27], serial_hd(1));
314     mcf_uart_create_mmap(0xfc068000, pic[28], serial_hd(2));
315 
316     mcf5208_sys_init(address_space_mem, pic, cpu);
317 
318     mcf_fec_init(address_space_mem, 0xfc030000, pic + 36);
319 
320     g_free(pic);
321 
322     /*  0xfc000000 SCM.  */
323     /*  0xfc004000 XBS.  */
324     /*  0xfc008000 FlexBus CS.  */
325     /* 0xfc030000 FEC.  */
326     /*  0xfc040000 SCM + Power management.  */
327     /*  0xfc044000 eDMA.  */
328     /* 0xfc048000 INTC.  */
329     /*  0xfc058000 I2C.  */
330     /*  0xfc05c000 QSPI.  */
331     /* 0xfc060000 UART0.  */
332     /* 0xfc064000 UART0.  */
333     /* 0xfc068000 UART0.  */
334     /*  0xfc070000 DMA timers.  */
335     /* 0xfc080000 PIT0.  */
336     /* 0xfc084000 PIT1.  */
337     /*  0xfc088000 EPORT.  */
338     /*  0xfc08c000 Watchdog.  */
339     /*  0xfc090000 clock module.  */
340     /*  0xfc0a0000 CCM + reset.  */
341     /*  0xfc0a4000 GPIO.  */
342     /* 0xfc0a8000 SDRAM controller.  */
343 
344     /* Load firmware */
345     if (machine->firmware) {
346         char *fn;
347         uint8_t *ptr;
348 
349         fn = qemu_find_file(QEMU_FILE_TYPE_BIOS, machine->firmware);
350         if (!fn) {
351             error_report("Could not find ROM image '%s'", machine->firmware);
352             exit(1);
353         }
354         if (load_image_targphys(fn, 0x0, ROM_SIZE) < 8) {
355             error_report("Could not load ROM image '%s'", machine->firmware);
356             exit(1);
357         }
358         g_free(fn);
359         /* Initial PC is always at offset 4 in firmware binaries */
360         ptr = rom_ptr(0x4, 4);
361         assert(ptr != NULL);
362         env->pc = ldl_be_p(ptr);
363     }
364 
365     /* Load kernel.  */
366     if (!kernel_filename) {
367         if (qtest_enabled() || machine->firmware) {
368             return;
369         }
370         error_report("Kernel image must be specified");
371         exit(1);
372     }
373 
374     kernel_size = load_elf(kernel_filename, NULL, NULL, NULL, &elf_entry,
375                            NULL, NULL, NULL, 1, EM_68K, 0, 0);
376     entry = elf_entry;
377     if (kernel_size < 0) {
378         kernel_size = load_uimage(kernel_filename, &entry, NULL, NULL,
379                                   NULL, NULL);
380     }
381     if (kernel_size < 0) {
382         kernel_size = load_image_targphys(kernel_filename, 0x40000000,
383                                           ram_size);
384         entry = 0x40000000;
385     }
386     if (kernel_size < 0) {
387         error_report("Could not load kernel '%s'", kernel_filename);
388         exit(1);
389     }
390 
391     env->pc = entry;
392 }
393 
mcf5208evb_machine_init(MachineClass * mc)394 static void mcf5208evb_machine_init(MachineClass *mc)
395 {
396     mc->desc = "MCF5208EVB";
397     mc->init = mcf5208evb_init;
398     mc->is_default = true;
399     mc->default_cpu_type = M68K_CPU_TYPE_NAME("m5208");
400     mc->default_ram_id = "mcf5208.ram";
401 }
402 
403 DEFINE_MACHINE("mcf5208evb", mcf5208evb_machine_init)
404