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