3 * Samsung S3C2440 emulation
5 * Copyright 2009 Daniel Silverstone and Vincent Sanders
7 * Copyright 2010, 2013 Stefan Weil
9 * This file is under the terms of the GNU General Public License Version 2.
12 #include "qemu/osdep.h"
14 #include "hw/sysbus.h"
15 #include "qapi/error.h" /* error_abort */
16 #include "sysemu/sysemu.h"
17 #include "exec/address-spaces.h" /* get_system_memory */
21 #define logout(fmt, ...) \
22 fprintf(stderr, "S3C24xx\t%-24s" fmt, __func__, ##__VA_ARGS__)
24 #define TODO() logout("%s:%u: missing\n", __FILE__, __LINE__)
27 #define CPU_S3C2440_IDENT_S3C2440A 0x32440001
29 /* Integrated peripherals */
32 #define CPU_S3C2440_SRAM_BASE (CPU_S3C2440_PERIPHERAL + 0x00000000)
33 #define CPU_S3C2440_SRAM_SIZE 4096
36 #define CPU_S3C2440_MEMC_BASE (CPU_S3C2440_PERIPHERAL + 0x8000000)
39 #define CPU_S3C2440_OHCI_BASE (CPU_S3C2440_PERIPHERAL + 0x9000000)
41 /* Interrupt controller */
42 #define CPU_S3C2440_IRQ_BASE (CPU_S3C2440_PERIPHERAL + 0xA000000)
45 #define CPU_S3C2440_CLKCON_BASE (CPU_S3C2440_PERIPHERAL + 0x0c000000)
48 #define CPU_S3C2440_LCD_BASE (CPU_S3C2440_PERIPHERAL + 0xD000000)
51 #define CPU_S3C2440_NAND_BASE (CPU_S3C2440_PERIPHERAL + 0xE000000)
53 /* serial port bases */
54 #define CPU_S3C2440_SERIAL0_BASE (CPU_S3C2440_PERIPHERAL + 0x10000000)
55 #define CPU_S3C2440_SERIAL1_BASE (CPU_S3C2440_PERIPHERAL + 0x10004000)
56 #define CPU_S3C2440_SERIAL2_BASE (CPU_S3C2440_PERIPHERAL + 0x10008000)
58 /* Timer controller */
59 #define CPU_S3C2440_TIMERS_BASE (CPU_S3C2440_PERIPHERAL + 0x11000000)
62 #define CPU_S3C2440_IIC_BASE (CPU_S3C2440_PERIPHERAL + 0x14000000)
65 #define CPU_S3C2440_GPIO_BASE (CPU_S3C2440_PERIPHERAL + 0x16000000)
68 #define CPU_S3C2440_RTC_BASE (CPU_S3C2440_PERIPHERAL + 0x17000000)
69 #define CPU_S3C2440_ADC_BASE (CPU_S3C2440_PERIPHERAL + 0x18000000)
71 /*----------------------------------------------------------------------------*/
73 /* Camera interface. */
75 #define TYPE_S3C24XX_CAM "s3c24xx_cam"
76 #define S3C24XX_CAM(obj) OBJECT_CHECK(S3C24xxCamState, (obj), TYPE_S3C24XX_CAM)
83 static uint64_t s3c24xx_cam_read(void *opaque
, hwaddr offset
,
86 //~ S3C24xxCamState *s = opaque;
87 logout("0x" TARGET_FMT_plx
"\n", offset
);
95 static void s3c24xx_cam_write(void *opaque
, hwaddr offset
,
96 uint64_t value
, unsigned size
)
98 //~ S3C24xxCamState *s = opaque;
100 logout("0x" TARGET_FMT_plx
" 0x%08" PRIx64
"\n", offset
, value
);
106 static void s3c24xx_cam_reset(DeviceState
*d
)
108 //~ S3C24xxCamState *s = S3C24XX_CAM(d);
111 static const MemoryRegionOps s3c24xx_cam_ops
= {
112 .read
= s3c24xx_cam_read
,
113 .write
= s3c24xx_cam_write
,
114 .endianness
= DEVICE_NATIVE_ENDIAN
,
116 .min_access_size
= 4,
121 static int s3c24xx_cam_init(SysBusDevice
*sbd
)
123 DeviceState
*dev
= DEVICE(sbd
);
124 S3C24xxCamState
*s
= S3C24XX_CAM(dev
);
127 memory_region_init_io(&s
->mmio
, OBJECT(s
), &s3c24xx_cam_ops
, s
, "s3c24xx-cam", 3 * 4);
128 sysbus_init_mmio(sbd
, &s
->mmio
);
130 //~ qdev_init_gpio_in(dev, mv88w8618_pic_set_irq, 32);
131 //~ sysbus_init_irq(sbd, &s->parent_irq);
135 static const VMStateDescription s3c24xx_cam_vmsd
= {
136 .name
= TYPE_S3C24XX_CAM
,
138 .minimum_version_id
= 1,
139 .minimum_version_id_old
= 1,
140 .fields
= (VMStateField
[]) {
141 VMSTATE_END_OF_LIST()
145 static void s3c24xx_cam_class_init(ObjectClass
*klass
, void *data
)
147 DeviceClass
*dc
= DEVICE_CLASS(klass
);
148 SysBusDeviceClass
*k
= SYS_BUS_DEVICE_CLASS(klass
);
149 dc
->reset
= s3c24xx_cam_reset
;
150 dc
->vmsd
= &s3c24xx_cam_vmsd
;
151 k
->init
= s3c24xx_cam_init
;
154 static const TypeInfo s3c24xx_cam_info
= {
155 .name
= TYPE_S3C24XX_CAM
,
156 .parent
= TYPE_SYS_BUS_DEVICE
,
157 .instance_size
= sizeof(S3C24xxCamState
),
158 .class_init
= s3c24xx_cam_class_init
161 static void s3c24xx_cam_register_types(void)
163 type_register_static(&s3c24xx_cam_info
);
166 type_init(s3c24xx_cam_register_types
)
168 /*----------------------------------------------------------------------------*/
170 /* Watchdog timer. */
172 #define TYPE_S3C24XX_WDG "s3c24xx_wdg"
173 #define S3C24XX_WDG(obj) OBJECT_CHECK(S3C24xxWdgState, (obj), TYPE_S3C24XX_WDG)
180 static uint64_t s3c24xx_wdg_read(void *opaque
, hwaddr offset
,
183 //~ S3C24xxWdgState *s = opaque;
184 logout("0x" TARGET_FMT_plx
"\n", offset
);
192 static void s3c24xx_wdg_write(void *opaque
, hwaddr offset
,
193 uint64_t value
, unsigned size
)
195 //~ S3C24xxWdgState *s = opaque;
197 logout("0x" TARGET_FMT_plx
" 0x%08" PRIx64
"\n", offset
, value
);
203 static void s3c24xx_wdg_reset(DeviceState
*d
)
205 //~ S3C24xxWdgState *s = S3C24XX_WDG(d);
208 static const MemoryRegionOps s3c24xx_wdg_ops
= {
209 .read
= s3c24xx_wdg_read
,
210 .write
= s3c24xx_wdg_write
,
211 .endianness
= DEVICE_NATIVE_ENDIAN
,
213 .min_access_size
= 4,
218 static int s3c24xx_wdg_init(SysBusDevice
*sbd
)
220 DeviceState
*dev
= DEVICE(sbd
);
221 S3C24xxWdgState
*s
= S3C24XX_WDG(dev
);
224 memory_region_init_io(&s
->mmio
, OBJECT(s
),
225 &s3c24xx_wdg_ops
, s
, "s3c24xx-wdg", 3 * 4);
226 sysbus_init_mmio(sbd
, &s
->mmio
);
228 //~ qdev_init_gpio_in(&dev->qdev, mv88w8618_pic_set_irq, 32);
229 //~ sysbus_init_irq(dev, &s->parent_irq);
233 static const VMStateDescription s3c24xx_wdg_vmsd
= {
234 .name
= TYPE_S3C24XX_WDG
,
236 .minimum_version_id
= 1,
237 .minimum_version_id_old
= 1,
238 .fields
= (VMStateField
[]) {
239 VMSTATE_END_OF_LIST()
243 static void s3c24xx_wdg_class_init(ObjectClass
*klass
, void *data
)
245 DeviceClass
*dc
= DEVICE_CLASS(klass
);
246 SysBusDeviceClass
*k
= SYS_BUS_DEVICE_CLASS(klass
);
247 dc
->reset
= s3c24xx_wdg_reset
;
248 dc
->vmsd
= &s3c24xx_wdg_vmsd
;
249 k
->init
= s3c24xx_wdg_init
;
252 static const TypeInfo s3c24xx_wdg_info
= {
253 .name
= TYPE_S3C24XX_WDG
,
254 .parent
= TYPE_SYS_BUS_DEVICE
,
255 .instance_size
= sizeof(S3C24xxWdgState
),
256 .class_init
= s3c24xx_wdg_class_init
259 static void s3c24xx_wdg_register_types(void)
261 type_register_static(&s3c24xx_wdg_info
);
264 type_init(s3c24xx_wdg_register_types
)
266 /*----------------------------------------------------------------------------*/
270 #define TYPE_S3C24XX_ADC "s3c24xx_adc"
271 #define S3C24XX_ADC(obj) OBJECT_CHECK(S3C24xxAdcState, (obj), TYPE_S3C24XX_ADC)
278 static uint64_t s3c24xx_adc_read(void *opaque
, hwaddr offset
,
281 //~ S3C24xxAdcState *s = opaque;
282 logout("0x" TARGET_FMT_plx
"\n", offset
);
285 //~ case MP_PIC_STATUS:
286 //~ return s->level & s->enabled;
293 static void s3c24xx_adc_write(void *opaque
, hwaddr offset
,
294 uint64_t value
, unsigned size
)
296 //~ S3C24xxAdcState *s = opaque;
298 logout("0x" TARGET_FMT_plx
" 0x%08" PRIx64
"\n", offset
, value
);
301 //~ case MP_PIC_ENABLE_SET:
302 //~ s->enabled |= value;
305 //~ case MP_PIC_ENABLE_CLR:
306 //~ s->enabled &= ~value;
307 //~ s->level &= ~value;
310 //~ mv88w8618_pic_update(s);
313 static void s3c24xx_adc_reset(DeviceState
*d
)
315 //~ S3C24xxAdcState *s = S3C24XX_ADC(d);
318 static const MemoryRegionOps s3c24xx_adc_ops
= {
319 .read
= s3c24xx_adc_read
,
320 .write
= s3c24xx_adc_write
,
321 .endianness
= DEVICE_NATIVE_ENDIAN
,
323 .min_access_size
= 4,
328 static int s3c24xx_adc_init(SysBusDevice
*sbd
)
330 DeviceState
*dev
= DEVICE(sbd
);
331 S3C24xxAdcState
*s
= S3C24XX_ADC(dev
);
334 memory_region_init_io(&s
->mmio
, OBJECT(s
),
335 &s3c24xx_adc_ops
, s
, "s3c24xx-adc", 7 * 4);
336 sysbus_init_mmio(sbd
, &s
->mmio
);
338 //~ qdev_init_gpio_in(&dev->qdev, mv88w8618_pic_set_irq, 32);
339 //~ sysbus_init_irq(dev, &s->parent_irq);
343 static const VMStateDescription s3c24xx_adc_vmsd
= {
344 .name
= TYPE_S3C24XX_ADC
,
346 .minimum_version_id
= 1,
347 .minimum_version_id_old
= 1,
348 .fields
= (VMStateField
[]) {
349 VMSTATE_END_OF_LIST()
353 static void s3c24xx_adc_class_init(ObjectClass
*klass
, void *data
)
355 DeviceClass
*dc
= DEVICE_CLASS(klass
);
356 SysBusDeviceClass
*k
= SYS_BUS_DEVICE_CLASS(klass
);
357 dc
->reset
= s3c24xx_adc_reset
;
358 dc
->vmsd
= &s3c24xx_adc_vmsd
;
359 k
->init
= s3c24xx_adc_init
;
362 static const TypeInfo s3c24xx_adc_info
= {
363 .name
= TYPE_S3C24XX_ADC
,
364 .parent
= TYPE_SYS_BUS_DEVICE
,
365 .instance_size
= sizeof(S3C24xxAdcState
),
366 .class_init
= s3c24xx_adc_class_init
369 static void s3c24xx_adc_register_types(void)
371 type_register_static(&s3c24xx_adc_info
);
374 type_init(s3c24xx_adc_register_types
)
376 /*----------------------------------------------------------------------------*/
378 /* Initialise a Samsung S3C2440 SOC ARM core and internal peripherals. */
380 s3c2440_init(int sdram_size
)
383 MemoryRegion
*sysmem
= get_system_memory();
384 S3CState
*s
= g_new0(S3CState
, 1);
386 /* Prepare the ARM 920T core. */
387 s
->cpu
= ARM_CPU(cpu_generic_init(TYPE_ARM_CPU
, "arm920t"));
389 /* S3C2440X SDRAM memory is always at the same physical location. */
390 memory_region_init_ram(&s
->sdram0
, OBJECT(s
), "s3c2440.sdram0",
391 sdram_size
, &error_abort
);
392 memory_region_init_alias(&s
->sdram1
, NULL
, "s3c2440.sdram1",
393 &s
->sdram0
, 0, sdram_size
);
394 memory_region_init_alias(&s
->sdram2
, NULL
, "s3c2440.sdram2",
395 &s
->sdram0
, 0, sdram_size
);
396 memory_region_add_subregion(sysmem
, CPU_S3C2440_DRAM
, &s
->sdram0
);
397 memory_region_add_subregion(sysmem
,
398 CPU_S3C2440_DRAM
+ 0x80000000, &s
->sdram1
);
399 memory_region_add_subregion(sysmem
,
400 CPU_S3C2440_DRAM
+ 0x90000000, &s
->sdram2
);
403 memory_region_init_ram(&s
->sram
, OBJECT(s
), "s3c2440.sram",
404 CPU_S3C2440_SRAM_SIZE
, &error_abort
);
405 memory_region_add_subregion(sysmem
, CPU_S3C2440_SRAM_BASE
, &s
->sram
);
407 /* SDRAM memory controller */
408 s
->memc
= s3c24xx_memc_init(CPU_S3C2440_MEMC_BASE
);
410 /* Interrupt controller */
411 s
->irq
= s3c24xx_irq_init(s
, CPU_S3C2440_IRQ_BASE
);
413 /* Clock and power control */
414 s
->clkcon
= s3c24xx_clkcon_init(s
, CPU_S3C2440_CLKCON_BASE
, 12000000);
416 /* Timer controller */
417 s
->timers
= s3c24xx_timers_init(s
, CPU_S3C2440_TIMERS_BASE
, 0, 12000000);
419 /* Serial port controllers */
420 s
->uart
[0] = s3c24xx_serial_init(s
, serial_hds
[0], CPU_S3C2440_SERIAL0_BASE
, 32);
421 s
->uart
[1] = s3c24xx_serial_init(s
, serial_hds
[1], CPU_S3C2440_SERIAL1_BASE
, 35);
422 s
->uart
[2] = s3c24xx_serial_init(s
, serial_hds
[2], CPU_S3C2440_SERIAL2_BASE
, 38);
424 /* Real time clock */
425 s
->rtc
= s3c24xx_rtc_init(CPU_S3C2440_RTC_BASE
);
428 //~ dev = sysbus_create_simple("s3c24xx_gpio", CPU_S3C2440_GPIO_BASE, NULL);
429 s
->gpio
= s3c24xx_gpio_init(s
, CPU_S3C2440_GPIO_BASE
, CPU_S3C2440_IDENT_S3C2440A
);
432 s
->iic
= s3c24xx_iic_init(s3c24xx_get_irq(s
->irq
, 27),
433 CPU_S3C2440_IIC_BASE
);
436 dev
= sysbus_create_simple("s3c24xx_lcd", CPU_S3C2440_LCD_BASE
,
437 s3c24xx_get_irq(s
->irq
, 16));
439 /* NAND controller */
440 s
->nand
= s3c24xx_nand_init(CPU_S3C2440_NAND_BASE
);
442 /* A two port OHCI controller */
443 dev
= qdev_create(NULL
, "sysbus-ohci");
444 qdev_prop_set_uint32(dev
, "num-ports", 2);
445 //~ qdev_prop_set_taddr(dev, "dma-offset", base);
446 qdev_init_nofail(dev
);
447 sysbus_mmio_map(SYS_BUS_DEVICE(dev
), 0, CPU_S3C2440_OHCI_BASE
);
448 sysbus_connect_irq(SYS_BUS_DEVICE(dev
), 0, s3c24xx_get_irq(s
->irq
, 26));
450 dev
= sysbus_create_simple(TYPE_S3C24XX_ADC
, CPU_S3C2440_ADC_BASE
, NULL
);