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