[MINI2440] Refactored the default u-boot loading
[qemu/mini2440.git] / hw / mini2440.c
blob1fb3991f1bb6c06fa8fd1830fda4e6e6c427db38
1 /*
2 * mini2440 development board support
4 * Copyright Michel Pollet <buserror@gmail.com>
6 * This code is licensed under the GNU GPL v2.
7 */
9 #include "hw.h"
10 #include "s3c.h"
11 #include "arm-misc.h"
12 #include "sysemu.h"
13 #include "i2c.h"
14 #include "qemu-timer.h"
15 #include "devices.h"
16 #include "audio/audio.h"
17 #include "boards.h"
18 #include "console.h"
19 #include "usb.h"
20 #include "net.h"
21 #include "sd.h"
22 #include "dm9000.h"
23 #include "eeprom24c0x.h"
25 #define mini2440_printf(format, ...) \
26 fprintf(stderr, "%s: " format, __FUNCTION__, ##__VA_ARGS__)
28 /* Wiring common to all revisions */
29 #define MINI2440_GPIO_BACKLIGHT S3C_GPB(1)
30 #define MINI2440_GPIO_LCD_RESET S3C_GPC(6)
31 #define MINI2440_GPIO_nSD_DETECT S3C_GPG(8)
32 #define MINI2440_IRQ_nSD_DETECT S3C_EINT(16)
33 #define MINI2440_IRQ_DM9000 S3C_EINT(7)
34 #define MINI2440_GPIO_DM9000 S3C_GPF(7)
36 #define MINI2440_GPIO_SDMMC_ON S3C_GPB(2)
37 #define MINI2440_GPIO_USB_PULLUP S3C_GPB(9)
38 #define MINI2440_GPIO_USB_ATTACH S3C_GPB(10)
40 struct mini2440_board_s {
41 struct s3c_state_s *cpu;
42 unsigned int ram;
43 struct ee24c08_s * eeprom;
44 const char * kernel;
45 SDState * mmc;
46 struct nand_flash_s *nand;
47 int bl_level;
51 * the 24c08 sits on 4 addresses on the bus, and uses the lower address bits
52 * to address the 256 byte "page" of the eeprom. We thus need to use 4 i2c_slaves
53 * and keep track of which one was used to set the read/write pointer into the data
55 struct ee24c08_s;
56 struct ee24c08_slave_s {
57 i2c_slave slave;
58 struct ee24c08_s * eeprom;
59 uint8_t page;
61 struct ee24c08_s {
62 /* that memory takes 4 addresses */
63 struct ee24c08_slave_s * slave[4];
64 uint16_t ptr;
65 uint16_t count;
66 uint8_t data[1024];
69 static void ee24c08_event(i2c_slave *i2c, enum i2c_event event)
71 struct ee24c08_slave_s *s = (struct ee24c08_slave_s *) i2c;
73 s->eeprom->ptr = s->page * 256;
74 s->eeprom->count = 0;
77 static int ee24c08_tx(i2c_slave *i2c, uint8_t data)
79 struct ee24c08_slave_s *s = (struct ee24c08_slave_s *) i2c;
80 if (s->eeprom->count++ == 0) {
81 /* first byte is address offset */
82 s->eeprom->ptr = (s->page * 256) + data;
83 } else {
84 printf("%s: write %04x=%02x\n", __FUNCTION__, s->eeprom->ptr, data);
85 s->eeprom->data[s->eeprom->ptr] = data;
86 s->eeprom->ptr = (s->eeprom->ptr & ~0xff) | ((s->eeprom->ptr + 1) & 0xff);
87 s->eeprom->count++;
89 return 0;
92 static int ee24c08_rx(i2c_slave *i2c)
94 struct ee24c08_slave_s *s = (struct ee24c08_slave_s *) i2c;
95 uint8_t res = s->eeprom->data[s->eeprom->ptr];
97 s->eeprom->ptr = (s->eeprom->ptr & ~0xff) | ((s->eeprom->ptr + 1) & 0xff);
98 s->eeprom->count++;
99 return res;
102 static void ee24c08_save(QEMUFile *f, void *opaque)
104 struct ee24c08_s *s = (struct ee24c08_s *) opaque;
105 int i;
107 qemu_put_be16s(f, &s->ptr);
108 qemu_put_be16s(f, &s->count);
109 qemu_put_buffer(f, s->data, sizeof(s->data));
111 for (i = 0; i < 4; i++)
112 i2c_slave_save(f, &s->slave[i]->slave);
115 static int ee24c08_load(QEMUFile *f, void *opaque, int version_id)
117 struct ee24c08_s *s = (struct ee24c08_s *) opaque;
118 int i;
120 qemu_get_be16s(f, &s->ptr);
121 qemu_get_be16s(f, &s->count);
122 qemu_get_buffer(f, s->data, sizeof(s->data));
124 for (i = 0; i < 4; i++)
125 i2c_slave_load(f, &s->slave[i]->slave);
126 return 0;
129 static struct ee24c08_s * ee24c08_init(i2c_bus *bus)
131 struct ee24c08_s *s = (struct ee24c08_s *)
132 qemu_mallocz(sizeof(struct ee24c08_s));
133 int i = 0;
134 memset(s->data, 0xff, sizeof(s->data));
136 for (i = 0; i < 4; i++) {
137 struct ee24c08_slave_s * ss = (struct ee24c08_slave_s *)
138 i2c_slave_init(bus, 0x50 + i, sizeof(struct ee24c08_slave_s));
139 ss->slave.event = ee24c08_event;
140 ss->slave.recv = ee24c08_rx;
141 ss->slave.send = ee24c08_tx;
142 ss->page = i;
143 ss->eeprom = s;
144 s->slave[i] = ss;
146 register_savevm("ee24c08", -1, 0, ee24c08_save, ee24c08_load, s);
147 return s;
151 /* Handlers for output ports */
152 static void mini2440_bl_switch(void *opaque, int line, int level)
154 printf("%s: LCD Backlight now %s.\n", __FUNCTION__, level ? "on" : "off");
157 static void mini2440_bl_intensity(int line, int level, void *opaque)
159 struct mini2440_board_s *s = (struct mini2440_board_s *) opaque;
161 if ((level >> 8) != s->bl_level) {
162 s->bl_level = level >> 8;
163 printf("%s: LCD Backlight now at %04x\n", __FUNCTION__, s->bl_level);
167 static void mini2440_gpio_setup(struct mini2440_board_s *s)
169 /* set the "input" pin values */
170 s3c_gpio_set_dat(s->cpu->io, S3C_GPG(13), 1);
171 s3c_gpio_set_dat(s->cpu->io, S3C_GPG(14), 1);
172 s3c_gpio_set_dat(s->cpu->io, S3C_GPG(15), 0);
174 s3c_gpio_out_set(s->cpu->io, MINI2440_GPIO_BACKLIGHT,
175 *qemu_allocate_irqs(mini2440_bl_switch, s, 1));
177 s3c_timers_cmp_handler_set(s->cpu->timers, 1, mini2440_bl_intensity, s);
179 /* this confuses the kernel, we will need a way to bridge this IRQ to the SD system
180 * right now without this, qemu will not know how to pass the SD card insert/remove
181 * properly to the kernel
182 sd_set_cb(s->mmc, 0, s3c_gpio_in_get(s->cpu->io)[MINI2440_IRQ_nSD_DETECT]);
186 #if 0
187 static void hexdump(const void* address, uint32_t len)
189 const unsigned char* p = address;
190 int i, j;
192 for (i = 0; i < len; i += 16) {
193 for (j = 0; j < 16 && i + j < len; j++)
194 fprintf(stderr, "%02x ", p[i + j]);
195 for (; j < 16; j++)
196 fprintf(stderr, " ");
197 fprintf(stderr, " ");
198 for (j = 0; j < 16 && i + j < len; j++)
199 fprintf(stderr, "%c", (p[i + j] < ' ' || p[i + j] > 0x7f) ? '.' : p[i + j]);
200 fprintf(stderr, "\n");
203 #endif
205 static int mini2440_load_from_nand(struct nand_flash_s *nand,
206 uint32_t nand_offset, uint32_t s3c_base_offset, uint32_t size)
208 uint8_t buffer[512];
209 uint32_t src = 0;
210 int page = 0;
211 uint32_t dst = 0;
213 if (!nand)
214 return 0;
216 for (page = 0; page < (size / 512); page++, src += 512 + 16, dst += 512)
217 if (nand_readraw(nand, nand_offset + src, buffer, 512) == 0) {
218 fprintf(stderr, "%s: failed to load nand %d:%d\n", __FUNCTION__,
219 nand_offset + src, 512 + 16);
220 return 0;
221 } else
222 cpu_physical_memory_write(s3c_base_offset + dst, buffer, 512);
223 return (int) size;
226 static void mini2440_reset(void *opaque)
228 struct mini2440_board_s *s = (struct mini2440_board_s *) opaque;
229 uint32_t image_size;
232 * Normally we would load 4 KB of nand to SRAM and jump there, but
233 * it is not working perfectly as expected, so we cheat and load
234 * it from nand directly relocated to 0x33f80000 and jump there
236 if (mini2440_load_from_nand(s->nand, 0, S3C_RAM_BASE | 0x03f80000, 256*1024)> 0) {
237 fprintf(stderr, "%s: loaded default u-boot from NAND\n", __FUNCTION__);
238 s->cpu->env->regs[15] = S3C_RAM_BASE | 0x03f80000; /* start address, u-boot already relocated */
240 #if 0 && defined(LATER)
241 if (mini2440_load_from_nand(s->nand, 0, S3C_SRAM_BASE_NANDBOOT, S3C_SRAM_SIZE) > 0) {
242 s->cpu->env->regs[15] = S3C_SRAM_BASE_NANDBOOT; /* start address, u-boot relocating code */
243 fprintf(stderr, "%s: 4KB SteppingStone loaded from NAND\n", __FUNCTION__);
245 #endif
247 * if a u--boot is available as a file, we always use it
250 image_size = load_image("mini2440/u-boot.bin", phys_ram_base + 0x03f80000);
251 if (image_size < 0)
252 image_size = load_image("u-boot.bin", phys_ram_base + 0x03f80000);
253 if (image_size > 0) {
254 if (image_size & (512 -1)) /* round size to a NAND block size */
255 image_size = (image_size + 512) & ~(512-1);
256 fprintf(stderr, "%s: loaded override u-boot (size %x)\n", __FUNCTION__, image_size);
257 s->cpu->env->regs[15] = S3C_RAM_BASE | 0x03f80000; /* start address, u-boot already relocated */
261 * if a kernel was explicitly specified, we load it too
263 if (s->kernel) {
264 image_size = load_image(s->kernel, phys_ram_base + 0x02000000);
265 if (image_size > 0) {
266 if (image_size & (512 -1)) /* round size to a NAND block size */
267 image_size = (image_size + 512) & ~(512-1);
268 fprintf(stderr, "%s: loaded %s (size %x)\n", __FUNCTION__, s->kernel, image_size);
273 /* Typical touchscreen calibration values */
274 static const int mini2440_ts_scale[6] = {
275 0, (90 - 960) * 256 / 1021, -90 * 256 * 32,
276 (940 - 75) * 256 / 1021, 0, 75 * 256 * 32,
279 /* Board init. */
280 static struct mini2440_board_s *mini2440_init_common(int ram_size,
281 const char *kernel_filename, const char *cpu_model,
282 SDState *mmc)
284 struct mini2440_board_s *s = (struct mini2440_board_s *)
285 qemu_mallocz(sizeof(struct mini2440_board_s));
287 s->ram = 0x04000000;
288 s->kernel = kernel_filename;
289 s->mmc = mmc;
291 /* Setup CPU & memory */
292 if (ram_size < s->ram + S3C_SRAM_SIZE) {
293 fprintf(stderr, "This platform requires %i bytes of memory (not %d)\n",
294 s->ram + S3C_SRAM_SIZE, ram_size);
295 exit(1);
297 if (cpu_model && strcmp(cpu_model, "arm920t")) {
298 fprintf(stderr, "This platform requires an ARM920T core\n");
299 exit(2);
301 s->cpu = s3c24xx_init(S3C_CPU_2440, s->ram, S3C_SRAM_BASE_NANDBOOT, s->mmc);
303 /* Setup peripherals */
304 mini2440_gpio_setup(s);
306 s->eeprom = ee24c08_init(s3c_i2c_bus(s->cpu->i2c));
309 NICInfo* nd;
310 nd = &nd_table[0];
311 if (!nd->model)
312 nd->model = "dm9000";
313 if (strcmp(nd->model, "dm9000") == 0) {
314 dm9000_init(nd, 0x20000000, 0x300, 0x304, s3c_gpio_in_get(s->cpu->io)[MINI2440_IRQ_DM9000]);
318 s3c_adc_setscale(s->cpu->adc, mini2440_ts_scale);
320 /* Setup initial (reset) machine state */
321 qemu_register_reset(mini2440_reset, s);
322 #if 0
323 arm_load_kernel(s->ram, kernel_filename, kernel_cmdline,
324 initrd_filename, 0x49e, S3C_RAM_BASE);
325 #endif
327 return s;
330 static void mini2440_init(ram_addr_t ram_size, int vga_ram_size,
331 const char *boot_device,
332 const char *kernel_filename, const char *kernel_cmdline,
333 const char *initrd_filename, const char *cpu_model)
335 struct mini2440_board_s *mini;
336 int sd_idx = drive_get_index(IF_SD, 0, 0);
337 SDState *sd = 0;
339 if (sd_idx >= 0)
340 sd = sd_init(drives_table[sd_idx].bdrv, 0);
342 mini = mini2440_init_common(ram_size,
343 kernel_filename, cpu_model, sd);
345 mini->nand = nand_init(NAND_MFR_SAMSUNG, 0x76);
346 mini->cpu->nand->reg(mini->cpu->nand, mini->nand);
348 mini2440_reset(mini);
351 QEMUMachine mini2440_machine = {
352 "mini2440",
353 "MINI2440 Chinese Samsung SoC dev board (S3C2440A)",
354 .init = mini2440_init,
355 .ram_require = (0x04000000 + S3C_SRAM_SIZE) | RAMSIZE_FIXED