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