]> git.proxmox.com Git - qemu.git/blob - hw/xtensa_lx60.c
xtensa_lx60: add FLASH support
[qemu.git] / hw / xtensa_lx60.c
1 /*
2 * Copyright (c) 2011, Max Filippov, Open Source and Linux Lab.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the Open Source and Linux Lab nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28 #include "sysemu.h"
29 #include "boards.h"
30 #include "loader.h"
31 #include "elf.h"
32 #include "memory.h"
33 #include "exec-memory.h"
34 #include "pc.h"
35 #include "sysbus.h"
36 #include "flash.h"
37
38 typedef struct LxBoardDesc {
39 size_t flash_size;
40 size_t flash_sector_size;
41 size_t sram_size;
42 } LxBoardDesc;
43
44 typedef struct Lx60FpgaState {
45 MemoryRegion iomem;
46 uint32_t leds;
47 uint32_t switches;
48 } Lx60FpgaState;
49
50 static void lx60_fpga_reset(void *opaque)
51 {
52 Lx60FpgaState *s = opaque;
53
54 s->leds = 0;
55 s->switches = 0;
56 }
57
58 static uint64_t lx60_fpga_read(void *opaque, target_phys_addr_t addr,
59 unsigned size)
60 {
61 Lx60FpgaState *s = opaque;
62
63 switch (addr) {
64 case 0x0: /*build date code*/
65 return 0x27092011;
66
67 case 0x4: /*processor clock frequency, Hz*/
68 return 10000000;
69
70 case 0x8: /*LEDs (off = 0, on = 1)*/
71 return s->leds;
72
73 case 0xc: /*DIP switches (off = 0, on = 1)*/
74 return s->switches;
75 }
76 return 0;
77 }
78
79 static void lx60_fpga_write(void *opaque, target_phys_addr_t addr,
80 uint64_t val, unsigned size)
81 {
82 Lx60FpgaState *s = opaque;
83
84 switch (addr) {
85 case 0x8: /*LEDs (off = 0, on = 1)*/
86 s->leds = val;
87 break;
88
89 case 0x10: /*board reset*/
90 if (val == 0xdead) {
91 qemu_system_reset_request();
92 }
93 break;
94 }
95 }
96
97 static const MemoryRegionOps lx60_fpga_ops = {
98 .read = lx60_fpga_read,
99 .write = lx60_fpga_write,
100 .endianness = DEVICE_NATIVE_ENDIAN,
101 };
102
103 static Lx60FpgaState *lx60_fpga_init(MemoryRegion *address_space,
104 target_phys_addr_t base)
105 {
106 Lx60FpgaState *s = g_malloc(sizeof(Lx60FpgaState));
107
108 memory_region_init_io(&s->iomem, &lx60_fpga_ops, s,
109 "lx60-fpga", 0x10000);
110 memory_region_add_subregion(address_space, base, &s->iomem);
111 lx60_fpga_reset(s);
112 qemu_register_reset(lx60_fpga_reset, s);
113 return s;
114 }
115
116 static void lx60_net_init(MemoryRegion *address_space,
117 target_phys_addr_t base,
118 target_phys_addr_t descriptors,
119 target_phys_addr_t buffers,
120 qemu_irq irq, NICInfo *nd)
121 {
122 DeviceState *dev;
123 SysBusDevice *s;
124 MemoryRegion *ram;
125
126 dev = qdev_create(NULL, "open_eth");
127 qdev_set_nic_properties(dev, nd);
128 qdev_init_nofail(dev);
129
130 s = sysbus_from_qdev(dev);
131 sysbus_connect_irq(s, 0, irq);
132 memory_region_add_subregion(address_space, base,
133 sysbus_mmio_get_region(s, 0));
134 memory_region_add_subregion(address_space, descriptors,
135 sysbus_mmio_get_region(s, 1));
136
137 ram = g_malloc(sizeof(*ram));
138 memory_region_init_ram(ram, NULL, "open_eth.ram", 16384);
139 memory_region_add_subregion(address_space, buffers, ram);
140 }
141
142 static uint64_t translate_phys_addr(void *env, uint64_t addr)
143 {
144 return cpu_get_phys_page_debug(env, addr);
145 }
146
147 static void lx60_reset(void *env)
148 {
149 cpu_reset(env);
150 }
151
152 static void lx_init(const LxBoardDesc *board,
153 ram_addr_t ram_size, const char *boot_device,
154 const char *kernel_filename, const char *kernel_cmdline,
155 const char *initrd_filename, const char *cpu_model)
156 {
157 #ifdef TARGET_WORDS_BIGENDIAN
158 int be = 1;
159 #else
160 int be = 0;
161 #endif
162 MemoryRegion *system_memory = get_system_memory();
163 CPUState *env = NULL;
164 MemoryRegion *ram, *rom, *system_io;
165 DriveInfo *dinfo;
166 pflash_t *flash = NULL;
167 int n;
168
169 if (!cpu_model) {
170 cpu_model = "dc232b";
171 }
172
173 for (n = 0; n < smp_cpus; n++) {
174 env = cpu_init(cpu_model);
175 if (!env) {
176 fprintf(stderr, "Unable to find CPU definition\n");
177 exit(1);
178 }
179 env->sregs[PRID] = n;
180 qemu_register_reset(lx60_reset, env);
181 /* Need MMU initialized prior to ELF loading,
182 * so that ELF gets loaded into virtual addresses
183 */
184 cpu_reset(env);
185 }
186
187 ram = g_malloc(sizeof(*ram));
188 memory_region_init_ram(ram, NULL, "xtensa.sram", ram_size);
189 memory_region_add_subregion(system_memory, 0, ram);
190
191 rom = g_malloc(sizeof(*rom));
192 memory_region_init_ram(rom, NULL, "xtensa.rom", 0x1000);
193 memory_region_add_subregion(system_memory, 0xfe000000, rom);
194
195 system_io = g_malloc(sizeof(*system_io));
196 memory_region_init(system_io, "system.io", 224 * 1024 * 1024);
197 memory_region_add_subregion(system_memory, 0xf0000000, system_io);
198 lx60_fpga_init(system_io, 0x0d020000);
199 if (nd_table[0].vlan) {
200 lx60_net_init(system_io, 0x0d030000, 0x0d030400, 0x0d800000,
201 xtensa_get_extint(env, 1), nd_table);
202 }
203
204 if (!serial_hds[0]) {
205 serial_hds[0] = qemu_chr_new("serial0", "null", NULL);
206 }
207
208 serial_mm_init(system_io, 0x0d050020, 2, xtensa_get_extint(env, 0),
209 115200, serial_hds[0], DEVICE_NATIVE_ENDIAN);
210
211 dinfo = drive_get(IF_PFLASH, 0, 0);
212 if (dinfo) {
213 flash = pflash_cfi01_register(0xf8000000,
214 NULL, "lx60.io.flash", board->flash_size,
215 dinfo->bdrv, board->flash_sector_size,
216 board->flash_size / board->flash_sector_size,
217 4, 0x0000, 0x0000, 0x0000, 0x0000, be);
218 if (flash == NULL) {
219 fprintf(stderr, "Unable to mount pflash\n");
220 exit(1);
221 }
222 }
223
224 /* Use presence of kernel file name as 'boot from SRAM' switch. */
225 if (kernel_filename) {
226 uint64_t elf_entry;
227 uint64_t elf_lowaddr;
228 int success = load_elf(kernel_filename, translate_phys_addr, env,
229 &elf_entry, &elf_lowaddr, NULL, be, ELF_MACHINE, 0);
230 if (success > 0) {
231 env->pc = elf_entry;
232 }
233 } else {
234 if (flash) {
235 MemoryRegion *flash_mr = pflash_cfi01_get_memory(flash);
236 MemoryRegion *flash_io = g_malloc(sizeof(*flash_io));
237
238 memory_region_init_alias(flash_io, "lx60.flash",
239 flash_mr, 0, board->flash_size);
240 memory_region_add_subregion(system_memory, 0xfe000000,
241 flash_io);
242 }
243 }
244 }
245
246 static void xtensa_lx60_init(ram_addr_t ram_size,
247 const char *boot_device,
248 const char *kernel_filename, const char *kernel_cmdline,
249 const char *initrd_filename, const char *cpu_model)
250 {
251 static const LxBoardDesc lx60_board = {
252 .flash_size = 0x400000,
253 .flash_sector_size = 0x10000,
254 .sram_size = 0x20000,
255 };
256 lx_init(&lx60_board, ram_size, boot_device,
257 kernel_filename, kernel_cmdline,
258 initrd_filename, cpu_model);
259 }
260
261 static void xtensa_lx200_init(ram_addr_t ram_size,
262 const char *boot_device,
263 const char *kernel_filename, const char *kernel_cmdline,
264 const char *initrd_filename, const char *cpu_model)
265 {
266 static const LxBoardDesc lx200_board = {
267 .flash_size = 0x1000000,
268 .flash_sector_size = 0x20000,
269 .sram_size = 0x2000000,
270 };
271 lx_init(&lx200_board, ram_size, boot_device,
272 kernel_filename, kernel_cmdline,
273 initrd_filename, cpu_model);
274 }
275
276 static QEMUMachine xtensa_lx60_machine = {
277 .name = "lx60",
278 .desc = "lx60 EVB (dc232b)",
279 .init = xtensa_lx60_init,
280 .max_cpus = 4,
281 };
282
283 static QEMUMachine xtensa_lx200_machine = {
284 .name = "lx200",
285 .desc = "lx200 EVB (dc232b)",
286 .init = xtensa_lx200_init,
287 .max_cpus = 4,
288 };
289
290 static void xtensa_lx_machines_init(void)
291 {
292 qemu_register_machine(&xtensa_lx60_machine);
293 qemu_register_machine(&xtensa_lx200_machine);
294 }
295
296 machine_init(xtensa_lx_machines_init);