2 * mini2440 development board support
4 * Copyright Michel Pollet <buserror@gmail.com>
6 * This code is licensed under the GNU GPL v2.
14 #include "qemu-timer.h"
16 #include "audio/audio.h"
23 #include "eeprom24c0x.h"
25 #define mini2440_printf(format, ...) \
26 fprintf(stderr, "%s: " format, __FUNCTION__, ##__VA_ARGS__)
28 #define MINI2440_GPIO_BACKLIGHT S3C_GPG(4)
29 #define MINI2440_GPIO_LCD_RESET S3C_GPC(6)
30 #define MINI2440_GPIO_nSD_DETECT S3C_GPG(8)
31 #define MINI2440_GPIO_WP_SD S3C_GPH(8)
32 #define MINI2440_GPIO_DM9000 S3C_GPF(7)
33 #define MINI2440_GPIO_USB_PULLUP S3C_GPC(5)
35 #define MINI2440_IRQ_nSD_DETECT S3C_EINT(16)
36 #define MINI2440_IRQ_DM9000 S3C_EINT(7)
39 #define MINI2440_GPIO_SDMMC_ON S3C_GPB(2)
40 #define MINI2440_GPIO_USB_ATTACH S3C_GPB(10)
43 struct mini2440_board_s
{
44 struct s3c_state_s
*cpu
;
46 struct ee24c08_s
* eeprom
;
49 struct nand_flash_s
*nand
;
54 * the 24c08 sits on 4 addresses on the bus, and uses the lower address bits
55 * to address the 256 byte "page" of the eeprom. We thus need to use 4 i2c_slaves
56 * and keep track of which one was used to set the read/write pointer into the data
59 struct ee24c08_slave_s
{
61 struct ee24c08_s
* eeprom
;
65 /* that memory takes 4 addresses */
66 struct ee24c08_slave_s
* slave
[4];
72 static void ee24c08_event(i2c_slave
*i2c
, enum i2c_event event
)
74 struct ee24c08_slave_s
*s
= (struct ee24c08_slave_s
*) i2c
;
76 s
->eeprom
->ptr
= s
->page
* 256;
80 static int ee24c08_tx(i2c_slave
*i2c
, uint8_t data
)
82 struct ee24c08_slave_s
*s
= (struct ee24c08_slave_s
*) i2c
;
83 if (s
->eeprom
->count
++ == 0) {
84 /* first byte is address offset */
85 s
->eeprom
->ptr
= (s
->page
* 256) + data
;
87 printf("%s: write %04x=%02x\n", __FUNCTION__
, s
->eeprom
->ptr
, data
);
88 s
->eeprom
->data
[s
->eeprom
->ptr
] = data
;
89 s
->eeprom
->ptr
= (s
->eeprom
->ptr
& ~0xff) | ((s
->eeprom
->ptr
+ 1) & 0xff);
95 static int ee24c08_rx(i2c_slave
*i2c
)
97 struct ee24c08_slave_s
*s
= (struct ee24c08_slave_s
*) i2c
;
98 uint8_t res
= s
->eeprom
->data
[s
->eeprom
->ptr
];
100 s
->eeprom
->ptr
= (s
->eeprom
->ptr
& ~0xff) | ((s
->eeprom
->ptr
+ 1) & 0xff);
105 static void ee24c08_save(QEMUFile
*f
, void *opaque
)
107 struct ee24c08_s
*s
= (struct ee24c08_s
*) opaque
;
110 qemu_put_be16s(f
, &s
->ptr
);
111 qemu_put_be16s(f
, &s
->count
);
112 qemu_put_buffer(f
, s
->data
, sizeof(s
->data
));
114 for (i
= 0; i
< 4; i
++)
115 i2c_slave_save(f
, &s
->slave
[i
]->slave
);
118 static int ee24c08_load(QEMUFile
*f
, void *opaque
, int version_id
)
120 struct ee24c08_s
*s
= (struct ee24c08_s
*) opaque
;
123 qemu_get_be16s(f
, &s
->ptr
);
124 qemu_get_be16s(f
, &s
->count
);
125 qemu_get_buffer(f
, s
->data
, sizeof(s
->data
));
127 for (i
= 0; i
< 4; i
++)
128 i2c_slave_load(f
, &s
->slave
[i
]->slave
);
132 static struct ee24c08_s
* ee24c08_init(i2c_bus
*bus
)
134 struct ee24c08_s
*s
= (struct ee24c08_s
*)
135 qemu_mallocz(sizeof(struct ee24c08_s
));
137 memset(s
->data
, 0xff, sizeof(s
->data
));
139 for (i
= 0; i
< 4; i
++) {
140 struct ee24c08_slave_s
* ss
= (struct ee24c08_slave_s
*)
141 i2c_slave_init(bus
, 0x50 + i
, sizeof(struct ee24c08_slave_s
));
142 ss
->slave
.event
= ee24c08_event
;
143 ss
->slave
.recv
= ee24c08_rx
;
144 ss
->slave
.send
= ee24c08_tx
;
149 register_savevm("ee24c08", -1, 0, ee24c08_save
, ee24c08_load
, s
);
154 /* Handlers for output ports */
155 static void mini2440_bl_switch(void *opaque
, int line
, int level
)
157 printf("%s: LCD Backlight now %s (%d).\n", __FUNCTION__
, level
? "on" : "off", level
);
160 static void mini2440_bl_intensity(int line
, int level
, void *opaque
)
162 struct mini2440_board_s
*s
= (struct mini2440_board_s
*) opaque
;
164 if ((level
>> 8) != s
->bl_level
) {
165 s
->bl_level
= level
>> 8;
166 printf("%s: LCD Backlight now at %04x\n", __FUNCTION__
, level
);
170 static void mini2440_gpio_setup(struct mini2440_board_s
*s
)
172 /* set the "input" pin values */
173 s3c_gpio_set_dat(s
->cpu
->io
, S3C_GPG(13), 1);
174 s3c_gpio_set_dat(s
->cpu
->io
, S3C_GPG(14), 1);
175 s3c_gpio_set_dat(s
->cpu
->io
, S3C_GPG(15), 0);
177 s3c_gpio_out_set(s
->cpu
->io
, MINI2440_GPIO_BACKLIGHT
,
178 *qemu_allocate_irqs(mini2440_bl_switch
, s
, 1));
180 s3c_timers_cmp_handler_set(s
->cpu
->timers
, 1, mini2440_bl_intensity
, s
);
182 /* Register the SD card pins to the lower SD driver */
184 s3c_gpio_in_get(s
->cpu
->io
)[MINI2440_GPIO_WP_SD
],
185 qemu_irq_invert(s3c_gpio_in_get(s
->cpu
->io
)[MINI2440_IRQ_nSD_DETECT
]));
190 static void hexdump(const void* address
, uint32_t len
)
192 const unsigned char* p
= address
;
195 for (i
= 0; i
< len
; i
+= 16) {
196 for (j
= 0; j
< 16 && i
+ j
< len
; j
++)
197 fprintf(stderr
, "%02x ", p
[i
+ j
]);
199 fprintf(stderr
, " ");
200 fprintf(stderr
, " ");
201 for (j
= 0; j
< 16 && i
+ j
< len
; j
++)
202 fprintf(stderr
, "%c", (p
[i
+ j
] < ' ' || p
[i
+ j
] > 0x7f) ? '.' : p
[i
+ j
]);
203 fprintf(stderr
, "\n");
208 static int mini2440_load_from_nand(struct nand_flash_s
*nand
,
209 uint32_t nand_offset
, uint32_t s3c_base_offset
, uint32_t size
)
219 for (page
= 0; page
< (size
/ 512); page
++, src
+= 512 + 16, dst
+= 512) {
220 if (nand_readraw(nand
, nand_offset
+ src
, buffer
, 512)) {
221 cpu_physical_memory_write(s3c_base_offset
+ dst
, buffer
, 512);
223 fprintf(stderr
, "%s: failed to load nand %d:%d\n", __FUNCTION__
,
224 nand_offset
+ src
, 512 + 16);
231 static void mini2440_reset(void *opaque
)
233 struct mini2440_board_s
*s
= (struct mini2440_board_s
*) opaque
;
237 * Normally we would load 4 KB of nand to SRAM and jump there, but
238 * it is not working perfectly as expected, so we cheat and load
239 * it from nand directly relocated to 0x33f80000 and jump there
241 if (mini2440_load_from_nand(s
->nand
, 0, S3C_RAM_BASE
| 0x03f80000, 256*1024)> 0) {
242 fprintf(stderr
, "%s: loaded default u-boot from NAND\n", __FUNCTION__
);
243 s
->cpu
->env
->regs
[15] = S3C_RAM_BASE
| 0x03f80000; /* start address, u-boot already relocated */
245 #if 0 && defined(LATER)
246 if (mini2440_load_from_nand(s
->nand
, 0, S3C_SRAM_BASE_NANDBOOT
, S3C_SRAM_SIZE
) > 0) {
247 s
->cpu
->env
->regs
[15] = S3C_SRAM_BASE_NANDBOOT
; /* start address, u-boot relocating code */
248 fprintf(stderr
, "%s: 4KB SteppingStone loaded from NAND\n", __FUNCTION__
);
252 * if a u--boot is available as a file, we always use it
255 image_size
= load_image("mini2440/u-boot.bin", phys_ram_base
+ 0x03f80000);
257 image_size
= load_image("u-boot.bin", phys_ram_base
+ 0x03f80000);
258 if (image_size
> 0) {
259 if (image_size
& (512 -1)) /* round size to a NAND block size */
260 image_size
= (image_size
+ 512) & ~(512-1);
261 fprintf(stderr
, "%s: loaded override u-boot (size %x)\n", __FUNCTION__
, image_size
);
262 s
->cpu
->env
->regs
[15] = S3C_RAM_BASE
| 0x03f80000; /* start address, u-boot already relocated */
266 * if a kernel was explicitly specified, we load it too
269 image_size
= load_image(s
->kernel
, phys_ram_base
+ 0x02000000);
270 if (image_size
> 0) {
271 if (image_size
& (512 -1)) /* round size to a NAND block size */
272 image_size
= (image_size
+ 512) & ~(512-1);
273 fprintf(stderr
, "%s: loaded %s (size %x)\n", __FUNCTION__
, s
->kernel
, image_size
);
278 /* Typical touchscreen calibration values */
279 static const int mini2440_ts_scale
[6] = {
280 0, (90 - 960) * 256 / 1021, -90 * 256 * 32,
281 (940 - 75) * 256 / 1021, 0, 75 * 256 * 32,
285 static struct mini2440_board_s
*mini2440_init_common(int ram_size
,
286 const char *kernel_filename
, const char *cpu_model
,
289 struct mini2440_board_s
*s
= (struct mini2440_board_s
*)
290 qemu_mallocz(sizeof(struct mini2440_board_s
));
293 s
->kernel
= kernel_filename
;
296 /* Setup CPU & memory */
297 if (ram_size
< s
->ram
+ S3C_SRAM_SIZE
) {
298 fprintf(stderr
, "This platform requires %i bytes of memory (not %d)\n",
299 s
->ram
+ S3C_SRAM_SIZE
, ram_size
);
302 if (cpu_model
&& strcmp(cpu_model
, "arm920t")) {
303 fprintf(stderr
, "This platform requires an ARM920T core\n");
306 s
->cpu
= s3c24xx_init(S3C_CPU_2440
, 12000000 /* 12 mhz */, s
->ram
, S3C_SRAM_BASE_NANDBOOT
, s
->mmc
);
308 /* Setup peripherals */
309 mini2440_gpio_setup(s
);
311 s
->eeprom
= ee24c08_init(s3c_i2c_bus(s
->cpu
->i2c
));
317 nd
->model
= "dm9000";
318 if (strcmp(nd
->model
, "dm9000") == 0) {
319 dm9000_init(nd
, 0x20000000, 0x300, 0x304, s3c_gpio_in_get(s
->cpu
->io
)[MINI2440_IRQ_DM9000
]);
323 s3c_adc_setscale(s
->cpu
->adc
, mini2440_ts_scale
);
325 /* Setup initial (reset) machine state */
326 qemu_register_reset(mini2440_reset
, s
);
331 static void mini2440_init(ram_addr_t ram_size
, int vga_ram_size
,
332 const char *boot_device
,
333 const char *kernel_filename
, const char *kernel_cmdline
,
334 const char *initrd_filename
, const char *cpu_model
)
336 struct mini2440_board_s
*mini
;
337 int sd_idx
= drive_get_index(IF_SD
, 0, 0);
341 sd
= sd_init(drives_table
[sd_idx
].bdrv
, 0);
343 mini
= mini2440_init_common(ram_size
,
344 kernel_filename
, cpu_model
, sd
);
346 mini
->nand
= nand_init(NAND_MFR_SAMSUNG
, 0x76);
347 mini
->cpu
->nand
->reg(mini
->cpu
->nand
, mini
->nand
);
349 mini2440_reset(mini
);
352 QEMUMachine mini2440_machine
= {
354 "MINI2440 Chinese Samsung SoC dev board (S3C2440A)",
355 .init
= mini2440_init
,
356 .ram_require
= (0x04000000 + S3C_SRAM_SIZE
) | RAMSIZE_FIXED