* [Qemu-devel] [PATCH 01/16] Add ARM 920T CPU identifier
2009-05-23 16:35 [Qemu-devel] Add ARM S3C SOC core, drivers and boards - v3 Vincent Sanders
@ 2009-05-23 16:35 ` Vincent Sanders
2009-05-23 16:35 ` [Qemu-devel] [PATCH 02/16] S3C2410 and S3C2440 core SOC implementation Vincent Sanders
` (13 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: Vincent Sanders @ 2009-05-23 16:35 UTC (permalink / raw)
To: qemu-devel; +Cc: Vincent Sanders
Add the CPU Identifier required for ARM 920T cpu cores
Signed-off-by: Vincent Sanders <vince@simtec.co.uk>
---
target-arm/cpu.h | 1 +
target-arm/helper.c | 5 +++++
2 files changed, 6 insertions(+), 0 deletions(-)
diff --git a/target-arm/cpu.h b/target-arm/cpu.h
index f98655f..eafaeaf 100644
--- a/target-arm/cpu.h
+++ b/target-arm/cpu.h
@@ -370,6 +370,7 @@ void cpu_arm_set_cp_io(CPUARMState *env, int cpnum,
#define ARM_CPUID_ARM1026 0x4106a262
#define ARM_CPUID_ARM926 0x41069265
#define ARM_CPUID_ARM946 0x41059461
+#define ARM_CPUID_ARM920T 0x41129200
#define ARM_CPUID_TI915T 0x54029152
#define ARM_CPUID_TI925T 0x54029252
#define ARM_CPUID_PXA250 0x69052100
diff --git a/target-arm/helper.c b/target-arm/helper.c
index 701629a..2b05d15 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -37,6 +37,10 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
{
env->cp15.c0_cpuid = id;
switch (id) {
+ case ARM_CPUID_ARM920T:
+ env->cp15.c0_cachetype = 0x0d172172;
+ env->cp15.c1_sys = 0x00000078;
+ break;
case ARM_CPUID_ARM926:
set_feature(env, ARM_FEATURE_VFP);
env->vfp.xregs[ARM_VFP_FPSID] = 0x41011090;
@@ -277,6 +281,7 @@ struct arm_cpu_t {
};
static const struct arm_cpu_t arm_cpu_names[] = {
+ { ARM_CPUID_ARM920T, "arm920t"},
{ ARM_CPUID_ARM926, "arm926"},
{ ARM_CPUID_ARM946, "arm946"},
{ ARM_CPUID_ARM1026, "arm1026"},
--
1.6.0.4
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [Qemu-devel] [PATCH 02/16] S3C2410 and S3C2440 core SOC implementation.
2009-05-23 16:35 [Qemu-devel] Add ARM S3C SOC core, drivers and boards - v3 Vincent Sanders
2009-05-23 16:35 ` [Qemu-devel] [PATCH 01/16] Add ARM 920T CPU identifier Vincent Sanders
@ 2009-05-23 16:35 ` Vincent Sanders
2009-05-23 16:35 ` [Qemu-devel] [PATCH 03/16] Peripheral driver for S3C SOC SDRAM controller Vincent Sanders
` (12 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: Vincent Sanders @ 2009-05-23 16:35 UTC (permalink / raw)
To: qemu-devel; +Cc: Vincent Sanders
Signed-off-by: Vincent Sanders <vince@simtec.co.uk>
---
Makefile.target | 1 +
hw/s3c2410x.c | 41 +++++++++++++++++++++++++++++++++++++++++
hw/s3c2410x.h | 38 ++++++++++++++++++++++++++++++++++++++
hw/s3c2440.c | 40 ++++++++++++++++++++++++++++++++++++++++
hw/s3c2440.h | 38 ++++++++++++++++++++++++++++++++++++++
hw/s3c24xx.h | 19 +++++++++++++++++++
6 files changed, 177 insertions(+), 0 deletions(-)
create mode 100644 hw/s3c2410x.c
create mode 100644 hw/s3c2410x.h
create mode 100644 hw/s3c2440.c
create mode 100644 hw/s3c2440.h
create mode 100644 hw/s3c24xx.h
diff --git a/Makefile.target b/Makefile.target
index 664a1e3..2e4c0f2 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -648,6 +648,7 @@ OBJS+= omap_sx1.o palm.o tsc210x.o
OBJS+= nseries.o blizzard.o onenand.o vga.o cbus.o tusb6010.o usb-musb.o
OBJS+= mst_fpga.o mainstone.o
OBJS+= musicpal.o pflash_cfi02.o
+OBJS+= s3c2410x.o s3c2440.o
OBJS+= framebuffer.o
OBJS+= syborg.o syborg_fb.o syborg_interrupt.o syborg_keyboard.o
OBJS+= syborg_serial.o syborg_timer.o syborg_pointer.o syborg_rtc.o
diff --git a/hw/s3c2410x.c b/hw/s3c2410x.c
new file mode 100644
index 0000000..0461095
--- /dev/null
+++ b/hw/s3c2410x.c
@@ -0,0 +1,41 @@
+/* hw/s3c2410x.c
+ *
+ * Samsung S3C2410X emulation
+ *
+ * Copyright 2009 Daniel Silverstone and Vincent Sanders
+ *
+ * This file is under the terms of the GNU General Public
+ * License Version 2
+ */
+
+#include "hw.h"
+
+#include "s3c2410x.h"
+
+/* Integrated peripherals */
+#define CPU_S3C2410X_SRAM_BASE (CPU_S3C2410X_PERIPHERAL + 0x00000000)
+#define CPU_S3C2410X_SRAM_SIZE 4096
+
+/* Initialise a Samsung S3C2410X SOC ARM core and internal peripherals. */
+S3CState *
+s3c2410x_init(int sdram_size)
+{
+ S3CState *s = (S3CState *)qemu_mallocz(sizeof(S3CState));
+
+ /* Prepare the ARM 920T core */
+ s->cpu_env = cpu_init("arm920t");
+
+ /* S3C2410X SDRAM memory is always at the same physical location */
+ cpu_register_physical_memory(CPU_S3C2410X_DRAM,
+ ram_size,
+ qemu_ram_alloc(sdram_size) | IO_MEM_RAM);
+
+
+ /* S3C2410X SRAM */
+ cpu_register_physical_memory(CPU_S3C2410X_SRAM_BASE,
+ CPU_S3C2410X_SRAM_SIZE,
+ qemu_ram_alloc(CPU_S3C2410X_SRAM_SIZE) | IO_MEM_RAM);
+
+
+ return s;
+}
diff --git a/hw/s3c2410x.h b/hw/s3c2410x.h
new file mode 100644
index 0000000..f21bf9c
--- /dev/null
+++ b/hw/s3c2410x.h
@@ -0,0 +1,38 @@
+/* hw/s3c2410x.h
+ *
+ * Samsung s3c2410x cpu register definitions
+ *
+ * Copyright 2006, 2007, 2008 Daniel Silverstone and Vincent Sanders
+ *
+ * This file is under the terms of the GNU General Public
+ * License Version 2.
+ */
+
+#ifndef S3C2410X_H
+#define S3C2410X_H 1
+
+#include "s3c24xx.h"
+
+/* S3C2410 Physical memory areas */
+
+/* Chip select 0, Read only, not wired for write */
+#define CPU_S3C2410X_CS0 (0x00000000)
+/* Chip select 1 */
+#define CPU_S3C2410X_CS1 (0x08000000)
+/* Chip select 2 */
+#define CPU_S3C2410X_CS2 (0x10000000)
+/* Chip select 3 */
+#define CPU_S3C2410X_CS3 (0x18000000)
+/* Chip select 4 */
+#define CPU_S3C2410X_CS4 (0x20000000)
+/* Chip select 5 */
+#define CPU_S3C2410X_CS5 (0x28000000)
+/* Dynamic RAM */
+#define CPU_S3C2410X_DRAM (0x30000000)
+/* SOC Internal peripherals */
+#define CPU_S3C2410X_PERIPHERAL (0x40000000)
+
+/* s3c2410 SOC initialisation */
+S3CState *s3c2410x_init(int sdram_size);
+
+#endif /* S3C2410X_H */
diff --git a/hw/s3c2440.c b/hw/s3c2440.c
new file mode 100644
index 0000000..0d01ac6
--- /dev/null
+++ b/hw/s3c2440.c
@@ -0,0 +1,40 @@
+/* hw/s3c2440.c
+ *
+ * Samsung S3C2440 emulation
+ *
+ * Copyright 2009 Daniel Silverstone and Vincent Sanders
+ *
+ * This file is under the terms of the GNU General Public
+ * License Version 2
+ */
+
+#include "hw.h"
+
+#include "s3c2440.h"
+
+/* Integrated peripherals */
+#define CPU_S3C2440_SRAM_BASE (CPU_S3C2440_PERIPHERAL + 0x00000000)
+#define CPU_S3C2440_SRAM_SIZE 4096
+
+
+/* Initialise a Samsung S3C2440 SOC ARM core and internal peripherals. */
+S3CState *
+s3c2440_init(int sdram_size)
+{
+ S3CState *s = (S3CState *)qemu_mallocz(sizeof(S3CState));
+
+ /* Prepare the ARM 920T core */
+ s->cpu_env = cpu_init("arm920t");
+
+ /* S3C2440X SDRAM memory is always at the same physical location */
+ cpu_register_physical_memory(CPU_S3C2440_DRAM,
+ ram_size,
+ qemu_ram_alloc(sdram_size) | IO_MEM_RAM);
+
+ /* S3C2440 SRAM */
+ cpu_register_physical_memory(CPU_S3C2440_SRAM_BASE,
+ CPU_S3C2440_SRAM_SIZE,
+ qemu_ram_alloc(CPU_S3C2440_SRAM_SIZE) | IO_MEM_RAM);
+
+ return s;
+}
diff --git a/hw/s3c2440.h b/hw/s3c2440.h
new file mode 100644
index 0000000..d60ba44
--- /dev/null
+++ b/hw/s3c2440.h
@@ -0,0 +1,38 @@
+/* hw/s3c2410x.h
+ *
+ * Samsung s3c2410x cpu register definitions
+ *
+ * Copyright 2009 Daniel Silverstone and Vincent Sanders
+ *
+ * This file is under the terms of the GNU General Public
+ * License Version 2.
+ */
+
+#ifndef S3C2440_H
+#define S3C2440_H 1
+
+#include "s3c24xx.h"
+
+/* S3C2440 Physical memory areas */
+
+/* Chip select 0 */
+#define CPU_S3C2440_CS0 (0x00000000)
+/* Chip select 1 */
+#define CPU_S3C2440_CS1 (0x08000000)
+/* Chip select 2 */
+#define CPU_S3C2440_CS2 (0x10000000)
+/* Chip select 3 */
+#define CPU_S3C2440_CS3 (0x18000000)
+/* Chip select 4 */
+#define CPU_S3C2440_CS4 (0x20000000)
+/* Chip select 5 */
+#define CPU_S3C2440_CS5 (0x28000000)
+/* Dynamic RAM */
+#define CPU_S3C2440_DRAM (0x30000000)
+/* SOC Integrated peripherals */
+#define CPU_S3C2440_PERIPHERAL (0x40000000)
+
+/* s3c2440 SOC initialisation */
+S3CState *s3c2440_init(int sdram_size);
+
+#endif /* S3C2440_H */
diff --git a/hw/s3c24xx.h b/hw/s3c24xx.h
new file mode 100644
index 0000000..0b933c9
--- /dev/null
+++ b/hw/s3c24xx.h
@@ -0,0 +1,19 @@
+/* hw/s3c24xx.h
+ *
+ * Samsung s3c24xx cpu state and functions.
+ *
+ * Copyright 2006, 2007, 2008 Daniel Silverstone and Vincent Sanders
+ *
+ * This file is under the terms of the GNU General Public
+ * License Version 2.
+ */
+
+#ifndef S3C24XX_H
+#define S3C24XX_H 1
+
+/* This structure type encapsulates the state of a S3C24XX SoC. */
+typedef struct S3CState_s {
+ CPUState *cpu_env;
+} S3CState;
+
+#endif /* S3C24XX_H */
--
1.6.0.4
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [Qemu-devel] [PATCH 03/16] Peripheral driver for S3C SOC SDRAM controller.
2009-05-23 16:35 [Qemu-devel] Add ARM S3C SOC core, drivers and boards - v3 Vincent Sanders
2009-05-23 16:35 ` [Qemu-devel] [PATCH 01/16] Add ARM 920T CPU identifier Vincent Sanders
2009-05-23 16:35 ` [Qemu-devel] [PATCH 02/16] S3C2410 and S3C2440 core SOC implementation Vincent Sanders
@ 2009-05-23 16:35 ` Vincent Sanders
2009-05-23 16:35 ` [Qemu-devel] [PATCH 04/16] Peripheral driver for S3C SOC IRQ controller Vincent Sanders
` (11 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: Vincent Sanders @ 2009-05-23 16:35 UTC (permalink / raw)
To: qemu-devel; +Cc: Vincent Sanders
Peripheral driver for SDRAM controller on s3c24xx SOC. Very similar to
the implementation of other such controllers in that it just backs the
registers.
Signed-off-by: Vincent Sanders <vince@simtec.co.uk>
---
Makefile.target | 1 +
hw/s3c2410x.c | 9 +++++
hw/s3c2440.c | 8 ++++
hw/s3c24xx.h | 8 ++++
hw/s3c24xx_memc.c | 96 +++++++++++++++++++++++++++++++++++++++++++++++++++++
5 files changed, 122 insertions(+), 0 deletions(-)
create mode 100644 hw/s3c24xx_memc.c
diff --git a/Makefile.target b/Makefile.target
index 2e4c0f2..2ecfeca 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -648,6 +648,7 @@ OBJS+= omap_sx1.o palm.o tsc210x.o
OBJS+= nseries.o blizzard.o onenand.o vga.o cbus.o tusb6010.o usb-musb.o
OBJS+= mst_fpga.o mainstone.o
OBJS+= musicpal.o pflash_cfi02.o
+OBJS+= s3c24xx_memc.o
OBJS+= s3c2410x.o s3c2440.o
OBJS+= framebuffer.o
OBJS+= syborg.o syborg_fb.o syborg_interrupt.o syborg_keyboard.o
diff --git a/hw/s3c2410x.c b/hw/s3c2410x.c
index 0461095..74c61ac 100644
--- a/hw/s3c2410x.c
+++ b/hw/s3c2410x.c
@@ -13,9 +13,15 @@
#include "s3c2410x.h"
/* Integrated peripherals */
+
+/* SRAM */
#define CPU_S3C2410X_SRAM_BASE (CPU_S3C2410X_PERIPHERAL + 0x00000000)
#define CPU_S3C2410X_SRAM_SIZE 4096
+/* Memory control */
+#define CPU_S3C2410X_MEMC_BASE (CPU_S3C2410X_PERIPHERAL + 0x8000000)
+
+
/* Initialise a Samsung S3C2410X SOC ARM core and internal peripherals. */
S3CState *
s3c2410x_init(int sdram_size)
@@ -37,5 +43,8 @@ s3c2410x_init(int sdram_size)
qemu_ram_alloc(CPU_S3C2410X_SRAM_SIZE) | IO_MEM_RAM);
+ /* SDRAM memory controller */
+ s->memc = s3c24xx_memc_init(CPU_S3C2410X_MEMC_BASE);
+
return s;
}
diff --git a/hw/s3c2440.c b/hw/s3c2440.c
index 0d01ac6..18d8715 100644
--- a/hw/s3c2440.c
+++ b/hw/s3c2440.c
@@ -13,9 +13,14 @@
#include "s3c2440.h"
/* Integrated peripherals */
+
+/* SRAM */
#define CPU_S3C2440_SRAM_BASE (CPU_S3C2440_PERIPHERAL + 0x00000000)
#define CPU_S3C2440_SRAM_SIZE 4096
+/* Memory control */
+#define CPU_S3C2440_MEMC_BASE (CPU_S3C2440_PERIPHERAL + 0x8000000)
+
/* Initialise a Samsung S3C2440 SOC ARM core and internal peripherals. */
S3CState *
@@ -36,5 +41,8 @@ s3c2440_init(int sdram_size)
CPU_S3C2440_SRAM_SIZE,
qemu_ram_alloc(CPU_S3C2440_SRAM_SIZE) | IO_MEM_RAM);
+ /* SDRAM memory controller */
+ s->memc = s3c24xx_memc_init(CPU_S3C2440_MEMC_BASE);
+
return s;
}
diff --git a/hw/s3c24xx.h b/hw/s3c24xx.h
index 0b933c9..475bb2e 100644
--- a/hw/s3c24xx.h
+++ b/hw/s3c24xx.h
@@ -14,6 +14,14 @@
/* This structure type encapsulates the state of a S3C24XX SoC. */
typedef struct S3CState_s {
CPUState *cpu_env;
+
+ /* Memory controller state */
+ struct s3c24xx_memc_state_s *memc;
+
} S3CState;
+
+/* initialise memory controller peripheral */
+struct s3c24xx_memc_state_s *s3c24xx_memc_init(target_phys_addr_t base_addr);
+
#endif /* S3C24XX_H */
diff --git a/hw/s3c24xx_memc.c b/hw/s3c24xx_memc.c
new file mode 100644
index 0000000..26964ca
--- /dev/null
+++ b/hw/s3c24xx_memc.c
@@ -0,0 +1,96 @@
+/* hw/s3c24xx_memc.c
+ *
+ * Samsung S3C24XX memory controller emulation.
+ *
+ * The SDRAM controller on several S3C SOC is generic, the emulation needs to
+ * be little more than backing the registers.
+ *
+ * Copyright 2006, 2007 Daniel Silverstone and Vincent Sanders
+ *
+ * This file is under the terms of the GNU General Public
+ * License Version 2
+ */
+
+#include "hw.h"
+
+#include "s3c24xx.h"
+
+/* Memory controller state */
+struct s3c24xx_memc_state_s {
+ uint32_t memc_reg[13];
+};
+
+static void
+s3c24xx_memc_write_f(void *opaque, target_phys_addr_t addr_, uint32_t value)
+{
+ struct s3c24xx_memc_state_s *s = (struct s3c24xx_memc_state_s *)opaque;
+ int addr = (addr_ & 0x3f) >> 2;
+
+ if (addr < 0 || addr > 12)
+ addr = 12;
+
+ s->memc_reg[addr] = value;
+}
+
+static uint32_t
+s3c24xx_memc_read_f(void *opaque, target_phys_addr_t addr_)
+{
+ struct s3c24xx_memc_state_s *s = (struct s3c24xx_memc_state_s *)opaque;
+ int addr = (addr_ & 0x3f) >> 2;
+
+ if (addr < 0 || addr > 12)
+ addr = 12;
+
+ return s->memc_reg[addr];
+}
+
+static CPUReadMemoryFunc *s3c24xx_memc_read[] = {
+ &s3c24xx_memc_read_f,
+ &s3c24xx_memc_read_f,
+ &s3c24xx_memc_read_f,
+};
+
+static CPUWriteMemoryFunc *s3c24xx_memc_write[] = {
+ &s3c24xx_memc_write_f,
+ &s3c24xx_memc_write_f,
+ &s3c24xx_memc_write_f,
+};
+
+static void s3c24xx_memc_save(QEMUFile *f, void *opaque)
+{
+ struct s3c24xx_memc_state_s *s = (struct s3c24xx_memc_state_s *)opaque;
+ int i;
+
+ for (i = 0; i < 13; i ++)
+ qemu_put_be32s(f, &s->memc_reg[i]);
+}
+
+static int s3c24xx_memc_load(QEMUFile *f, void *opaque, int version_id)
+{
+ struct s3c24xx_memc_state_s *s = (struct s3c24xx_memc_state_s *)opaque;
+ int i;
+
+ for (i = 0; i < 13; i ++)
+ qemu_get_be32s(f, &s->memc_reg[i]);
+
+ return 0;
+}
+
+struct s3c24xx_memc_state_s *
+s3c24xx_memc_init(target_phys_addr_t base_addr)
+{
+ /* Memory controller is simple SDRAM control. As SDRAM is emulated and
+ * requires no setup the emulation needs to be nothing more than memory
+ * backing the registers.
+ *
+ * There are 13 registers, each 4 bytes.
+ */
+ struct s3c24xx_memc_state_s *s = qemu_mallocz(sizeof(struct s3c24xx_memc_state_s));
+
+ int tag;
+ tag = cpu_register_io_memory(0, s3c24xx_memc_read, s3c24xx_memc_write, s);
+ cpu_register_physical_memory(base_addr, 13 * 4, tag);
+ register_savevm("s3c24xx_memc", 0, 0, s3c24xx_memc_save, s3c24xx_memc_load, s);
+
+ return s;
+}
--
1.6.0.4
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [Qemu-devel] [PATCH 04/16] Peripheral driver for S3C SOC IRQ controller.
2009-05-23 16:35 [Qemu-devel] Add ARM S3C SOC core, drivers and boards - v3 Vincent Sanders
` (2 preceding siblings ...)
2009-05-23 16:35 ` [Qemu-devel] [PATCH 03/16] Peripheral driver for S3C SOC SDRAM controller Vincent Sanders
@ 2009-05-23 16:35 ` Vincent Sanders
2009-05-23 16:35 ` [Qemu-devel] [PATCH 05/16] Peripheral driver for S3C SOC clock control Vincent Sanders
` (10 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: Vincent Sanders @ 2009-05-23 16:35 UTC (permalink / raw)
To: qemu-devel; +Cc: Vincent Sanders
IRQ controller emulation for the s3c24xx SOC.
Signed-off-by: Vincent Sanders <vince@simtec.co.uk>
---
Makefile.target | 2 +-
hw/s3c2410x.c | 5 +
hw/s3c2440.c | 5 +
hw/s3c24xx.h | 10 ++
hw/s3c24xx_irq.c | 250 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
5 files changed, 271 insertions(+), 1 deletions(-)
create mode 100644 hw/s3c24xx_irq.c
diff --git a/Makefile.target b/Makefile.target
index 2ecfeca..1201cd3 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -648,7 +648,7 @@ OBJS+= omap_sx1.o palm.o tsc210x.o
OBJS+= nseries.o blizzard.o onenand.o vga.o cbus.o tusb6010.o usb-musb.o
OBJS+= mst_fpga.o mainstone.o
OBJS+= musicpal.o pflash_cfi02.o
-OBJS+= s3c24xx_memc.o
+OBJS+= s3c24xx_memc.o s3c24xx_irq.o
OBJS+= s3c2410x.o s3c2440.o
OBJS+= framebuffer.o
OBJS+= syborg.o syborg_fb.o syborg_interrupt.o syborg_keyboard.o
diff --git a/hw/s3c2410x.c b/hw/s3c2410x.c
index 74c61ac..987b14b 100644
--- a/hw/s3c2410x.c
+++ b/hw/s3c2410x.c
@@ -21,6 +21,8 @@
/* Memory control */
#define CPU_S3C2410X_MEMC_BASE (CPU_S3C2410X_PERIPHERAL + 0x8000000)
+/* Interrupt controller */
+#define CPU_S3C2410X_IRQ_BASE (CPU_S3C2410X_PERIPHERAL + 0xA000000)
/* Initialise a Samsung S3C2410X SOC ARM core and internal peripherals. */
S3CState *
@@ -46,5 +48,8 @@ s3c2410x_init(int sdram_size)
/* SDRAM memory controller */
s->memc = s3c24xx_memc_init(CPU_S3C2410X_MEMC_BASE);
+ /* Interrupt controller */
+ s->irq = s3c24xx_irq_init(s, CPU_S3C2410X_IRQ_BASE);
+
return s;
}
diff --git a/hw/s3c2440.c b/hw/s3c2440.c
index 18d8715..1f86c0f 100644
--- a/hw/s3c2440.c
+++ b/hw/s3c2440.c
@@ -21,6 +21,8 @@
/* Memory control */
#define CPU_S3C2440_MEMC_BASE (CPU_S3C2440_PERIPHERAL + 0x8000000)
+/* Interrupt controller */
+#define CPU_S3C2440_IRQ_BASE (CPU_S3C2440_PERIPHERAL + 0xA000000)
/* Initialise a Samsung S3C2440 SOC ARM core and internal peripherals. */
S3CState *
@@ -44,5 +46,8 @@ s3c2440_init(int sdram_size)
/* SDRAM memory controller */
s->memc = s3c24xx_memc_init(CPU_S3C2440_MEMC_BASE);
+ /* Interrupt controller */
+ s->irq = s3c24xx_irq_init(s, CPU_S3C2440_IRQ_BASE);
+
return s;
}
diff --git a/hw/s3c24xx.h b/hw/s3c24xx.h
index 475bb2e..8233757 100644
--- a/hw/s3c24xx.h
+++ b/hw/s3c24xx.h
@@ -18,10 +18,20 @@ typedef struct S3CState_s {
/* Memory controller state */
struct s3c24xx_memc_state_s *memc;
+ /* IRQ controller state */
+ struct s3c24xx_irq_state_s *irq;
+
} S3CState;
/* initialise memory controller peripheral */
struct s3c24xx_memc_state_s *s3c24xx_memc_init(target_phys_addr_t base_addr);
+/* initialise the IRQ controller */
+struct s3c24xx_irq_state_s *s3c24xx_irq_init(S3CState *soc, target_phys_addr_t base_addr);
+
+/* get the qemu interrupt from an irq number */
+qemu_irq s3c24xx_get_irq(struct s3c24xx_irq_state_s *s, int inum);
+
+
#endif /* S3C24XX_H */
diff --git a/hw/s3c24xx_irq.c b/hw/s3c24xx_irq.c
new file mode 100644
index 0000000..ed967fe
--- /dev/null
+++ b/hw/s3c24xx_irq.c
@@ -0,0 +1,250 @@
+/* hw/s3c24xx_irq.c
+ *
+ * Samsung S3C24XX IRQ controller emulation
+ *
+ * Copyright 2009 Daniel Silverstone and Vincent Sanders
+ *
+ * This file is under the terms of the GNU General Public
+ * License Version 2
+ */
+
+#include "hw.h"
+
+#include "s3c24xx.h"
+
+/* IRQ request status RW WORD */
+#define S3C_IRQ_SRCPND 0
+/* Interrupt mode control WR WORD */
+#define S3C_IRQ_INTMOD 1
+/* Interrupt mask control RW WORD */
+#define S3C_IRQ_INTMSK 2
+/* IRQ priority control WR WORD */
+#define S3C_IRQ_PRIORITY 3
+/* Interrupt request status RW WORD */
+#define S3C_IRQ_INTPND 4
+/* Interrupt request source offset RO WORD */
+#define S3C_IRQ_OFFSET 5
+/* Sub-source pending RW WORD */
+#define S3C_IRQ_SUBSRCPND 6
+/* Interrupt sub-mask RW WORD */
+#define S3C_IRQ_INTSUBMSK 7
+
+/* Interrupt controller state */
+struct s3c24xx_irq_state_s {
+ CPUState *cpu_env;
+
+ qemu_irq *irqs;
+
+ uint32_t irq_main_level, irq_subsrc_level;
+ uint32_t irq_reg[8];
+};
+
+
+/* Take the status of the srcpnd register, percolate it through, raise to CPU
+ * if necessary
+ */
+static void
+s3c24xx_percolate_interrupt(struct s3c24xx_irq_state_s *s)
+{
+ uint32_t ints = (s->irq_reg[S3C_IRQ_SRCPND] & ~s->irq_reg[S3C_IRQ_INTMSK]);
+ int fsb = ffs(ints);
+
+ /* TODO: Priority encoder could go here */
+ if (ints & s->irq_reg[S3C_IRQ_INTMOD]) {
+ /* Detected a FIQ */
+ cpu_interrupt(s->cpu_env, CPU_INTERRUPT_FIQ);
+ return;
+ } else {
+ /* No FIQ here today */
+ cpu_reset_interrupt(s->cpu_env, CPU_INTERRUPT_FIQ);
+ }
+
+ /* No FIQ, check for a normal IRQ */
+ if (fsb) {
+ if ((s->irq_reg[S3C_IRQ_INTPND] == 0) ||
+ (s->irq_reg[S3C_IRQ_INTPND] > 1<<(fsb-1))) {
+ /* Current INTPND is lower priority than fsb of ints (or empty) */
+ s->irq_reg[S3C_IRQ_INTPND] = 1<<(fsb-1);
+ s->irq_reg[S3C_IRQ_OFFSET] = fsb-1;
+ }
+ } else {
+ /* No FSB, thus no IRQ, thus nothing to do yet */
+ }
+
+ if (s->irq_reg[S3C_IRQ_INTPND] != 0) {
+ cpu_interrupt(s->cpu_env, CPU_INTERRUPT_HARD);
+ } else {
+ cpu_reset_interrupt(s->cpu_env, CPU_INTERRUPT_HARD);
+ }
+}
+
+static void
+s3c24xx_percolate_subsrc_interrupt(struct s3c24xx_irq_state_s *s)
+{
+ uint32_t ints;
+
+ s->irq_reg[S3C_IRQ_SRCPND] |= s->irq_main_level;
+ s->irq_reg[S3C_IRQ_SUBSRCPND] |= s->irq_subsrc_level;
+
+ ints = (s->irq_reg[S3C_IRQ_SUBSRCPND] &
+ ~s->irq_reg[S3C_IRQ_INTSUBMSK]);
+
+ /* If UART0 has asserted, raise that */
+ if (ints & 0x7) {
+ s->irq_reg[S3C_IRQ_SRCPND] |= (1<<28);
+ }
+
+ /* Ditto UART1 */
+ if (ints & 0x7<<3)
+ s->irq_reg[S3C_IRQ_SRCPND] |= (1<<23);
+
+ /* Ditto UART2 */
+ if (ints & 0x7<<6)
+ s->irq_reg[S3C_IRQ_SRCPND] |= (1<<15);
+
+ /* And percolate it through */
+ s3c24xx_percolate_interrupt(s);
+}
+
+static void
+s3c24xx_irq_write_f(void *opaque, target_phys_addr_t addr_, uint32_t value)
+{
+ struct s3c24xx_irq_state_s *s = (struct s3c24xx_irq_state_s *)opaque;
+ int addr = (addr_ >> 2) & 7;
+
+ if (addr == S3C_IRQ_SRCPND ||
+ addr == S3C_IRQ_INTPND ||
+ addr == S3C_IRQ_SUBSRCPND) {
+ s->irq_reg[addr] &= ~value;
+ } else {
+ s->irq_reg[addr] = value;
+ }
+
+ /* Start at the subsrc irqs and percolate from there */
+ s3c24xx_percolate_subsrc_interrupt(s);
+}
+
+static uint32_t
+s3c24xx_irq_read_f(void *opaque, target_phys_addr_t addr_)
+{
+ struct s3c24xx_irq_state_s *s = (struct s3c24xx_irq_state_s *)opaque;
+ int addr = (addr_ >> 2) & 0x7;
+
+ return s->irq_reg[addr];
+}
+
+
+static CPUReadMemoryFunc *s3c24xx_irq_read[] = {
+ &s3c24xx_irq_read_f,
+ &s3c24xx_irq_read_f,
+ &s3c24xx_irq_read_f,
+};
+
+static CPUWriteMemoryFunc *s3c24xx_irq_write[] = {
+ &s3c24xx_irq_write_f,
+ &s3c24xx_irq_write_f,
+ &s3c24xx_irq_write_f,
+};
+
+static void
+s3c24xx_irq_set_interrupt_level(struct s3c24xx_irq_state_s *s, int irq_num, int level, int set_level)
+{
+ if (level) {
+ if (set_level)
+ s->irq_main_level |= 1<<irq_num;
+ s->irq_reg[S3C_IRQ_SRCPND] |= 1<<irq_num;
+ } else {
+ s->irq_main_level &= ~(1<<irq_num);
+ s->irq_reg[S3C_IRQ_SRCPND] &= ~(1<<irq_num);
+ }
+ s3c24xx_percolate_subsrc_interrupt(s);
+}
+
+static void
+s3c24xx_irq_set_subsrc_interrupt_level(struct s3c24xx_irq_state_s *s, int irq_num, int level, int set_level)
+{
+ if (level) {
+ if (set_level)
+ s->irq_subsrc_level |= 1<<irq_num;
+ s->irq_reg[S3C_IRQ_SUBSRCPND] |= 1<<irq_num;
+ } else {
+ s->irq_subsrc_level &= ~(1<<irq_num);
+ s->irq_reg[S3C_IRQ_SUBSRCPND] &= ~(1<<irq_num);
+ }
+ s3c24xx_percolate_subsrc_interrupt(s);
+}
+
+static void
+s3c24xx_irq_handler(void *opaque, int _n, int level)
+{
+ struct s3c24xx_irq_state_s *s = (struct s3c24xx_irq_state_s *)opaque;
+ int irq_num = _n % 32;
+ int is_subsrc = (_n & 32)?1:0;
+ int is_level = (_n & 64)?1:0;
+
+ if (is_subsrc == 0)
+ s3c24xx_irq_set_interrupt_level(s, irq_num, level, is_level);
+ else
+ s3c24xx_irq_set_subsrc_interrupt_level(s, irq_num, level, is_level);
+}
+
+static void s3c24xx_irq_save(QEMUFile *f, void *opaque)
+{
+ struct s3c24xx_irq_state_s *s = (struct s3c24xx_irq_state_s *)opaque;
+ int i;
+
+ for (i = 0; i < 8; i ++)
+ qemu_put_be32s(f, &s->irq_reg[i]);
+}
+
+static int s3c24xx_irq_load(QEMUFile *f, void *opaque, int version_id)
+{
+ struct s3c24xx_irq_state_s *s = (struct s3c24xx_irq_state_s *)opaque;
+ int i;
+
+ for (i = 0; i < 8; i ++)
+ qemu_get_be32s(f, &s->irq_reg[i]);
+
+ return 0;
+}
+
+struct s3c24xx_irq_state_s *
+s3c24xx_irq_init(S3CState *soc, target_phys_addr_t base_addr)
+{
+ struct s3c24xx_irq_state_s * s;
+ int tag;
+
+ s = qemu_mallocz(sizeof(struct s3c24xx_irq_state_s));
+
+ /* Samsung S3C24XX IRQ registration. */
+ tag = cpu_register_io_memory(0, s3c24xx_irq_read, s3c24xx_irq_write, s);
+ cpu_register_physical_memory(base_addr, 8 * 4, tag);
+ register_savevm("s3c24xx_irq", 0, 0, s3c24xx_irq_save, s3c24xx_irq_load, s);
+
+ s->cpu_env = soc->cpu_env;
+
+ /* Set up registers to power on values */
+ s->irq_reg[S3C_IRQ_SRCPND] = 0x00;
+ s->irq_reg[S3C_IRQ_INTMOD] = 0x00;
+ s->irq_reg[S3C_IRQ_INTMSK] = 0xFFFFFFFF;
+ s->irq_reg[S3C_IRQ_PRIORITY] = 0x7F;
+ s->irq_reg[S3C_IRQ_INTPND] = 0x00;
+ s->irq_reg[S3C_IRQ_OFFSET] = 0x00;
+ s->irq_reg[S3C_IRQ_SUBSRCPND] = 0x00;
+ s->irq_reg[S3C_IRQ_INTSUBMSK] = 0x7FF;
+
+ /* Allocate the interrupts and return them. All 64 potential ones.
+ * We return them doubled up because the latter half are level where
+ * the former half are edge.
+ */
+ s->irqs = qemu_allocate_irqs(s3c24xx_irq_handler, s, 128);
+
+ return s;
+}
+
+/* get the qemu interrupt from an irq number */
+qemu_irq
+s3c24xx_get_irq(struct s3c24xx_irq_state_s *s, int inum)
+{
+ return s->irqs[inum];
+}
--
1.6.0.4
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [Qemu-devel] [PATCH 05/16] Peripheral driver for S3C SOC clock control.
2009-05-23 16:35 [Qemu-devel] Add ARM S3C SOC core, drivers and boards - v3 Vincent Sanders
` (3 preceding siblings ...)
2009-05-23 16:35 ` [Qemu-devel] [PATCH 04/16] Peripheral driver for S3C SOC IRQ controller Vincent Sanders
@ 2009-05-23 16:35 ` Vincent Sanders
2009-05-23 16:35 ` [Qemu-devel] [PATCH 06/16] Peripheral driver for S3C SOC timers Vincent Sanders
` (9 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: Vincent Sanders @ 2009-05-23 16:35 UTC (permalink / raw)
To: qemu-devel; +Cc: Vincent Sanders
emulation of the S3c24xx SOC clock and power management controller
Signed-off-by: Vincent Sanders <vince@simtec.co.uk>
---
Makefile.target | 2 +-
hw/s3c2410x.c | 6 ++
hw/s3c2440.c | 6 ++
hw/s3c24xx.h | 6 ++
hw/s3c24xx_clkcon.c | 134 +++++++++++++++++++++++++++++++++++++++++++++++++++
5 files changed, 153 insertions(+), 1 deletions(-)
create mode 100644 hw/s3c24xx_clkcon.c
diff --git a/Makefile.target b/Makefile.target
index 1201cd3..d08bb36 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -648,7 +648,7 @@ OBJS+= omap_sx1.o palm.o tsc210x.o
OBJS+= nseries.o blizzard.o onenand.o vga.o cbus.o tusb6010.o usb-musb.o
OBJS+= mst_fpga.o mainstone.o
OBJS+= musicpal.o pflash_cfi02.o
-OBJS+= s3c24xx_memc.o s3c24xx_irq.o
+OBJS+= s3c24xx_memc.o s3c24xx_irq.o s3c24xx_clkcon.o
OBJS+= s3c2410x.o s3c2440.o
OBJS+= framebuffer.o
OBJS+= syborg.o syborg_fb.o syborg_interrupt.o syborg_keyboard.o
diff --git a/hw/s3c2410x.c b/hw/s3c2410x.c
index 987b14b..fe685e8 100644
--- a/hw/s3c2410x.c
+++ b/hw/s3c2410x.c
@@ -24,6 +24,9 @@
/* Interrupt controller */
#define CPU_S3C2410X_IRQ_BASE (CPU_S3C2410X_PERIPHERAL + 0xA000000)
+/* Clock control */
+#define CPU_S3C2410X_CLKCON_BASE (CPU_S3C2410X_PERIPHERAL + 0xC000000)
+
/* Initialise a Samsung S3C2410X SOC ARM core and internal peripherals. */
S3CState *
s3c2410x_init(int sdram_size)
@@ -51,5 +54,8 @@ s3c2410x_init(int sdram_size)
/* Interrupt controller */
s->irq = s3c24xx_irq_init(s, CPU_S3C2410X_IRQ_BASE);
+ /* Clock and power control */
+ s->clkcon = s3c24xx_clkcon_init(s, CPU_S3C2410X_CLKCON_BASE, 12000000);
+
return s;
}
diff --git a/hw/s3c2440.c b/hw/s3c2440.c
index 1f86c0f..b79451e 100644
--- a/hw/s3c2440.c
+++ b/hw/s3c2440.c
@@ -24,6 +24,9 @@
/* Interrupt controller */
#define CPU_S3C2440_IRQ_BASE (CPU_S3C2440_PERIPHERAL + 0xA000000)
+/* Clock control */
+#define CPU_S3C2440_CLKCON_BASE (CPU_S3C2440_PERIPHERAL + 0xC000000)
+
/* Initialise a Samsung S3C2440 SOC ARM core and internal peripherals. */
S3CState *
s3c2440_init(int sdram_size)
@@ -49,5 +52,8 @@ s3c2440_init(int sdram_size)
/* Interrupt controller */
s->irq = s3c24xx_irq_init(s, CPU_S3C2440_IRQ_BASE);
+ /* Clock and power control */
+ s->clkcon = s3c24xx_clkcon_init(s, CPU_S3C2440_CLKCON_BASE, 12000000);
+
return s;
}
diff --git a/hw/s3c24xx.h b/hw/s3c24xx.h
index 8233757..000c9ba 100644
--- a/hw/s3c24xx.h
+++ b/hw/s3c24xx.h
@@ -21,6 +21,9 @@ typedef struct S3CState_s {
/* IRQ controller state */
struct s3c24xx_irq_state_s *irq;
+ /* Clock and power control */
+ struct s3c24xx_clkcon_state_s *clkcon;
+
} S3CState;
@@ -33,5 +36,8 @@ struct s3c24xx_irq_state_s *s3c24xx_irq_init(S3CState *soc, target_phys_addr_t b
/* get the qemu interrupt from an irq number */
qemu_irq s3c24xx_get_irq(struct s3c24xx_irq_state_s *s, int inum);
+/* initialise clock controller */
+struct s3c24xx_clkcon_state_s *s3c24xx_clkcon_init(S3CState *soc, target_phys_addr_t base_addr, uint32_t ref_freq);
+
#endif /* S3C24XX_H */
diff --git a/hw/s3c24xx_clkcon.c b/hw/s3c24xx_clkcon.c
new file mode 100644
index 0000000..439ddbb
--- /dev/null
+++ b/hw/s3c24xx_clkcon.c
@@ -0,0 +1,134 @@
+/* hw/s3c24xx_clkcon.c
+ *
+ * Samsung S3C24XX Clock control emulation
+ *
+ * Copyright 2006, 2007, 2008 Daniel Silverstone and Vincent Sanders
+ *
+ * This file is under the terms of the GNU General Public
+ * License Version 2
+ */
+
+#include "hw.h"
+
+#include "s3c24xx.h"
+
+/* Lock time RW */
+#define S3C_REG_LOCKTIME 0
+
+/* MPLL Control RW */
+#define S3C_REG_MPLLCON 1
+
+/* UPLL Control RW */
+#define S3C_REG_UPLLCON 2
+
+/* Clock Generator Control RW */
+#define S3C_REG_CLKCON 3
+
+/* CLKCON IDLE */
+#define S3C_REG_CLKCON_IDLE (1<<2)
+
+/* Slow Clock Control RW */
+#define S3C_REG_CLKSLOW 4
+
+/* Clock divider control RW */
+#define S3C_REG_CLKDIVN 5
+
+/* Clock controller state */
+struct s3c24xx_clkcon_state_s {
+ CPUState *cpu_env;
+ uint32_t ref_freq; /* frequency of reference xtal or extclock */
+ uint32_t clkcon_reg[6];
+};
+
+static void
+s3c24xx_clkcon_write_f(void *opaque, target_phys_addr_t addr_, uint32_t value)
+{
+ struct s3c24xx_clkcon_state_s *s = (struct s3c24xx_clkcon_state_s *)opaque;
+ int addr = (addr_ & 0x1F) >> 2;
+ int idle_rising_edge = 0;
+
+ if (addr < 0 || addr > 5)
+ addr = 5;
+
+ if (addr == S3C_REG_CLKCON) {
+ if (!(s->clkcon_reg[addr] & S3C_REG_CLKCON_IDLE) &&
+ (value & S3C_REG_CLKCON_IDLE))
+ idle_rising_edge = 1;
+ }
+
+ s->clkcon_reg[addr] = value;
+
+ if (idle_rising_edge) {
+ cpu_interrupt(s->cpu_env, CPU_INTERRUPT_HALT);
+ }
+}
+
+static uint32_t
+s3c24xx_clkcon_read_f(void *opaque, target_phys_addr_t addr_)
+{
+ struct s3c24xx_clkcon_state_s *s = (struct s3c24xx_clkcon_state_s *)opaque;
+ int addr = (addr_ & 0x1F) >> 2;
+
+ if (addr < 0 || addr > 5)
+ addr = 5;
+
+ return s->clkcon_reg[addr];
+}
+
+static CPUReadMemoryFunc *s3c24xx_clkcon_read[] = {
+ &s3c24xx_clkcon_read_f,
+ &s3c24xx_clkcon_read_f,
+ &s3c24xx_clkcon_read_f,
+};
+
+static CPUWriteMemoryFunc *s3c24xx_clkcon_write[] = {
+ &s3c24xx_clkcon_write_f,
+ &s3c24xx_clkcon_write_f,
+ &s3c24xx_clkcon_write_f,
+};
+
+static void s3c24xx_clkcon_save(QEMUFile *f, void *opaque)
+{
+ struct s3c24xx_clkcon_state_s *s = (struct s3c24xx_clkcon_state_s *)opaque;
+ int i;
+
+ for (i = 0; i < 6; i ++)
+ qemu_put_be32s(f, &s->clkcon_reg[i]);
+}
+
+static int s3c24xx_clkcon_load(QEMUFile *f, void *opaque, int version_id)
+{
+ struct s3c24xx_clkcon_state_s *s = (struct s3c24xx_clkcon_state_s *)opaque;
+ int i;
+
+ for (i = 0; i < 6; i ++)
+ qemu_get_be32s(f, &s->clkcon_reg[i]);
+
+ return 0;
+}
+
+struct s3c24xx_clkcon_state_s *
+s3c24xx_clkcon_init(S3CState *soc, target_phys_addr_t base_addr, uint32_t ref_freq)
+{
+ int tag;
+ struct s3c24xx_clkcon_state_s *s;
+
+ s = qemu_mallocz(sizeof(struct s3c24xx_clkcon_state_s));
+
+ tag = cpu_register_io_memory(0, s3c24xx_clkcon_read, s3c24xx_clkcon_write, s);
+ cpu_register_physical_memory(base_addr, 6 * 4, tag);
+ register_savevm("s3c24xx_clkcon", 0, 0, s3c24xx_clkcon_save, s3c24xx_clkcon_load, s);
+
+ s->cpu_env = soc->cpu_env;
+ s->ref_freq = ref_freq;
+
+ /* initialise register values to power on defaults */
+ s->clkcon_reg[S3C_REG_LOCKTIME] = 0x00FFFFFF;
+ s->clkcon_reg[S3C_REG_MPLLCON] = 0x0005C080;
+ s->clkcon_reg[S3C_REG_UPLLCON] = 0x00028080;
+ s->clkcon_reg[S3C_REG_CLKCON] = 0x0007FFF0;
+ s->clkcon_reg[S3C_REG_CLKSLOW] = 0x00000004;
+ s->clkcon_reg[S3C_REG_CLKDIVN] = 0x00000000;
+
+ return s;
+}
--
1.6.0.4
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [Qemu-devel] [PATCH 06/16] Peripheral driver for S3C SOC timers.
2009-05-23 16:35 [Qemu-devel] Add ARM S3C SOC core, drivers and boards - v3 Vincent Sanders
` (4 preceding siblings ...)
2009-05-23 16:35 ` [Qemu-devel] [PATCH 05/16] Peripheral driver for S3C SOC clock control Vincent Sanders
@ 2009-05-23 16:35 ` Vincent Sanders
2009-05-23 16:35 ` [Qemu-devel] [PATCH 07/16] Peripheral driver for S3C SOC Serial ports Vincent Sanders
` (8 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: Vincent Sanders @ 2009-05-23 16:35 UTC (permalink / raw)
To: qemu-devel; +Cc: Vincent Sanders
Signed-off-by: Vincent Sanders <vince@simtec.co.uk>
---
Makefile.target | 2 +-
hw/s3c2410x.c | 6 ++
hw/s3c2440.c | 6 ++
hw/s3c24xx.h | 4 +
hw/s3c24xx_timers.c | 206 +++++++++++++++++++++++++++++++++++++++++++++++++++
5 files changed, 223 insertions(+), 1 deletions(-)
create mode 100644 hw/s3c24xx_timers.c
diff --git a/Makefile.target b/Makefile.target
index d08bb36..81fbc34 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -648,7 +648,7 @@ OBJS+= omap_sx1.o palm.o tsc210x.o
OBJS+= nseries.o blizzard.o onenand.o vga.o cbus.o tusb6010.o usb-musb.o
OBJS+= mst_fpga.o mainstone.o
OBJS+= musicpal.o pflash_cfi02.o
-OBJS+= s3c24xx_memc.o s3c24xx_irq.o s3c24xx_clkcon.o
+OBJS+= s3c24xx_memc.o s3c24xx_irq.o s3c24xx_clkcon.o s3c24xx_timers.o
OBJS+= s3c2410x.o s3c2440.o
OBJS+= framebuffer.o
OBJS+= syborg.o syborg_fb.o syborg_interrupt.o syborg_keyboard.o
diff --git a/hw/s3c2410x.c b/hw/s3c2410x.c
index fe685e8..d61abe2 100644
--- a/hw/s3c2410x.c
+++ b/hw/s3c2410x.c
@@ -27,6 +27,9 @@
/* Clock control */
#define CPU_S3C2410X_CLKCON_BASE (CPU_S3C2410X_PERIPHERAL + 0xC000000)
+/* Timer controller */
+#define CPU_S3C2410X_TIMERS_BASE (CPU_S3C2410X_PERIPHERAL + 0x11000000)
+
/* Initialise a Samsung S3C2410X SOC ARM core and internal peripherals. */
S3CState *
s3c2410x_init(int sdram_size)
@@ -57,5 +60,8 @@ s3c2410x_init(int sdram_size)
/* Clock and power control */
s->clkcon = s3c24xx_clkcon_init(s, CPU_S3C2410X_CLKCON_BASE, 12000000);
+ /* Timer controller */
+ s->timers = s3c24xx_timers_init(s, CPU_S3C2410X_TIMERS_BASE, 0, 12000000);
+
return s;
}
diff --git a/hw/s3c2440.c b/hw/s3c2440.c
index b79451e..1e947df 100644
--- a/hw/s3c2440.c
+++ b/hw/s3c2440.c
@@ -27,6 +27,9 @@
/* Clock control */
#define CPU_S3C2440_CLKCON_BASE (CPU_S3C2440_PERIPHERAL + 0xC000000)
+/* Timer controller */
+#define CPU_S3C2440_TIMERS_BASE (CPU_S3C2440_PERIPHERAL + 0x11000000)
+
/* Initialise a Samsung S3C2440 SOC ARM core and internal peripherals. */
S3CState *
s3c2440_init(int sdram_size)
@@ -55,5 +58,8 @@ s3c2440_init(int sdram_size)
/* Clock and power control */
s->clkcon = s3c24xx_clkcon_init(s, CPU_S3C2440_CLKCON_BASE, 12000000);
+ /* Timer controller */
+ s->timers = s3c24xx_timers_init(s, CPU_S3C2440_TIMERS_BASE, 0, 12000000);
+
return s;
}
diff --git a/hw/s3c24xx.h b/hw/s3c24xx.h
index 000c9ba..9cc7f37 100644
--- a/hw/s3c24xx.h
+++ b/hw/s3c24xx.h
@@ -24,6 +24,8 @@ typedef struct S3CState_s {
/* Clock and power control */
struct s3c24xx_clkcon_state_s *clkcon;
+ /* timer controller */
+ struct s3c24xx_timers_state_s *timers;
} S3CState;
@@ -39,5 +41,7 @@ qemu_irq s3c24xx_get_irq(struct s3c24xx_irq_state_s *s, int inum);
/* initialise clock controller */
struct s3c24xx_clkcon_state_s *s3c24xx_clkcon_init(S3CState *soc, target_phys_addr_t base_addr, uint32_t ref_freq);
+/* initialise timer controller */
+struct s3c24xx_timers_state_s *s3c24xx_timers_init(S3CState *soc, target_phys_addr_t base_addr, uint32_t tclk0, uint32_t tclk1);
#endif /* S3C24XX_H */
diff --git a/hw/s3c24xx_timers.c b/hw/s3c24xx_timers.c
new file mode 100644
index 0000000..b1cafbe
--- /dev/null
+++ b/hw/s3c24xx_timers.c
@@ -0,0 +1,206 @@
+/* hw/s3c24xx_timers.c
+ *
+ * Samsung S3C24XX PWM emulation
+ *
+ * Copyright 2009 Daniel Silverstone and Vincent Sanders
+ *
+ * This file is under the terms of the GNU General Public
+ * License Version 2
+ */
+
+#include "hw.h"
+#include "qemu-timer.h"
+
+#include "s3c24xx.h"
+
+/* The S3c24xx timer peripheral has five seperate timers. The first four (0-3)
+ * have physical external connections and can be used for PWM control. The
+ * fifth has no external connection but can generate interrupts because of this
+ * it is almost always used to generate the Operating system clock tick
+ * interrupt.
+ *
+ * The timers can be fed from the peripheral clock (pclk) or from one of two
+ * external inputs (tclk0 and 1). The external inputs are split so tclk0 is
+ * used for timer 0 and 1 and tclk1 feeds the remaining three timers.
+ *
+ * The emulation presented here only iplements the fifth timer (timer 4) as
+ * there is no sensible way to interpret the external physical PWM signals from
+ * timers 0 to 4 yet.
+ *
+ * ticks_per_sec is ticks per second for the qemu clocks
+ * TCLK1 is the assumed input for timer4
+ * Thus, period in ticks of timer4 is:
+ *
+ * (timer4_period * ticks_per_sec) / TCLK1
+ */
+
+/* Timer configuration 0 */
+#define S3C_TIMERS_TCFG0 0
+/* Timer configuration 1 */
+#define S3C_TIMERS_TCFG1 1
+/* Timer control */
+#define S3C_TIMERS_TCON 2
+/* Timer count buffer 0 */
+#define S3C_TIMERS_TCNTB0 3
+/* Timer compare buffer 0 */
+#define S3C_TIMERS_TCMPB0 4
+/* Timer count observation 0 */
+#define S3C_TIMERS_TCNTO0 5
+/* Timer count buffer 1 */
+#define S3C_TIMERS_TCNTB1 6
+/* Timer compare buffer 1 */
+#define S3C_TIMERS_TCMPB1 7
+/* Timer count observation 1 */
+#define S3C_TIMERS_TCNTO1 8
+/* Timer count buffer 2 */
+#define S3C_TIMERS_TCNTB2 9
+/* Timer compare buffer 2 */
+#define S3C_TIMERS_TCMPB2 10
+/* Timer count observation 2 */
+#define S3C_TIMERS_TCNTO2 11
+/* Timer count buffer 3 */
+#define S3C_TIMERS_TCNTB3 12
+/* Timer compare buffer 3 */
+#define S3C_TIMERS_TCMPB3 13
+/* Timer count observation 3 */
+#define S3C_TIMERS_TCNTO3 14
+/* Timer count buffer 4 */
+#define S3C_TIMERS_TCNTB4 15
+/* Timer count observation 4 */
+#define S3C_TIMERS_TCNTO4 16
+
+/* timer controller state */
+struct s3c24xx_timers_state_s {
+ uint32_t tclk0; /* first timer clock source frequency */
+ uint32_t tclk1; /* second timer clock source frequency */
+
+ uint32_t timers_reg[17]; /* registers */
+
+ /* resources for each timer */
+ QEMUTimer *timer[5];
+ qemu_irq irqs[5];
+ uint32_t timer_reload_value[5];
+ int64_t timer_last_ticked[5];
+
+};
+
+
+static void
+s3c24xx_schedule_timer(struct s3c24xx_timers_state_s *s, int num)
+{
+ s->timers_reg[S3C_TIMERS_TCNTB4] = s->timer_reload_value[num];
+ s->timer_last_ticked[num] = qemu_get_clock(vm_clock);
+ qemu_mod_timer(s->timer[num],
+ s->timer_last_ticked[num] +
+ ((s->timer_reload_value[num] * ticks_per_sec) / s->tclk1));
+}
+
+static void
+s3c24xx_timer4_tick(void *opaque)
+{
+ struct s3c24xx_timers_state_s *s = (struct s3c24xx_timers_state_s *)opaque;
+
+ /* set IRQ */
+ qemu_set_irq(s->irqs[4], 1);
+
+ /* if auto reload is set rescedule the next tick */
+ if (s->timers_reg[S3C_TIMERS_TCON] && (1<<22)) {
+ s3c24xx_schedule_timer(s, 4);
+ }
+}
+
+static void
+s3c24xx_timers_write_f(void *opaque, target_phys_addr_t addr_, uint32_t value)
+{
+ struct s3c24xx_timers_state_s *s = (struct s3c24xx_timers_state_s *)opaque;
+ int addr = (addr_ >> 2) & 0x1f;
+
+ s->timers_reg[addr] = value;
+
+ if (addr == S3C_TIMERS_TCON) {
+ if (value & (1 << 21)) {
+ /* Timer4 manual update is set, copy in the reload value */
+ s->timer_reload_value[4] = s->timers_reg[S3C_TIMERS_TCNTB4];
+ } else {
+ /* Timer4 manual update is not set */
+ if (value & (1 << 20)) {
+ /* The timer is supposed to be running so start it */
+ s3c24xx_schedule_timer(s, 4);
+ }
+ }
+ }
+}
+
+static uint32_t
+s3c24xx_timers_read_f(void *opaque, target_phys_addr_t addr_)
+{
+ struct s3c24xx_timers_state_s *s = (struct s3c24xx_timers_state_s *)opaque;
+ int addr = (addr_ >> 2) & 0x1f;
+
+ if (addr == S3C_TIMERS_TCNTO4 ) {
+ return s->timer_reload_value[4] - (((qemu_get_clock(vm_clock) - s->timer_last_ticked[4]) * s->tclk1) / ticks_per_sec);
+ }
+ return s->timers_reg[addr];
+}
+
+
+static CPUReadMemoryFunc *s3c24xx_timers_read[] = {
+ &s3c24xx_timers_read_f,
+ &s3c24xx_timers_read_f,
+ &s3c24xx_timers_read_f,
+};
+
+static CPUWriteMemoryFunc *s3c24xx_timers_write[] = {
+ &s3c24xx_timers_write_f,
+ &s3c24xx_timers_write_f,
+ &s3c24xx_timers_write_f,
+};
+
+static void s3c24xx_timers_save(QEMUFile *f, void *opaque)
+{
+ struct s3c24xx_timers_state_s *s = (struct s3c24xx_timers_state_s *)opaque;
+ int i;
+
+ for (i = 0; i < 17; i ++)
+ qemu_put_be32s(f, &s->timers_reg[i]);
+}
+
+static int s3c24xx_timers_load(QEMUFile *f, void *opaque, int version_id)
+{
+ struct s3c24xx_timers_state_s *s = (struct s3c24xx_timers_state_s *)opaque;
+ int i;
+
+ for (i = 0; i < 17; i ++)
+ qemu_get_be32s(f, &s->timers_reg[i]);
+
+ return 0;
+}
+
+/* S3c24xx timer initialisation */
+struct s3c24xx_timers_state_s *
+s3c24xx_timers_init(S3CState *soc, target_phys_addr_t base_addr, uint32_t tclk0, uint32_t tclk1)
+{
+ struct s3c24xx_timers_state_s *s;
+ int tag;
+ int i;
+
+ s = qemu_mallocz(sizeof(struct s3c24xx_timers_state_s));
+
+ tag = cpu_register_io_memory(0, s3c24xx_timers_read, s3c24xx_timers_write, s);
+ cpu_register_physical_memory(base_addr, 17 * 4, tag);
+ register_savevm("s3c24xx_timers", 0, 0, s3c24xx_timers_save, s3c24xx_timers_load, s);
+
+ s->tclk0 = tclk0;
+ s->tclk1 = tclk1;
+
+ /* set up per timer values */
+ for (i = 0; i < 5; i++) {
+ s->irqs[i] = s3c24xx_get_irq(soc->irq, 10 + i);
+ s->timer_reload_value[i] = 0;
+ s->timer_last_ticked[i] = 0;
+ }
+
+ s->timer[4] = qemu_new_timer(vm_clock, s3c24xx_timer4_tick, s);
+
+ return s;
+}
--
1.6.0.4
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [Qemu-devel] [PATCH 07/16] Peripheral driver for S3C SOC Serial ports.
2009-05-23 16:35 [Qemu-devel] Add ARM S3C SOC core, drivers and boards - v3 Vincent Sanders
` (5 preceding siblings ...)
2009-05-23 16:35 ` [Qemu-devel] [PATCH 06/16] Peripheral driver for S3C SOC timers Vincent Sanders
@ 2009-05-23 16:35 ` Vincent Sanders
2009-05-23 16:35 ` [Qemu-devel] [PATCH 08/16] Peripheral driver for S3C SOC real time clock Vincent Sanders
` (7 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: Vincent Sanders @ 2009-05-23 16:35 UTC (permalink / raw)
To: qemu-devel; +Cc: Vincent Sanders
Signed-off-by: Vincent Sanders <vince@simtec.co.uk>
---
Makefile.target | 1 +
hw/s3c2410x.c | 11 ++
hw/s3c2440.c | 11 ++
hw/s3c24xx.h | 7 ++
hw/s3c24xx_serial.c | 261 +++++++++++++++++++++++++++++++++++++++++++++++++++
5 files changed, 291 insertions(+), 0 deletions(-)
create mode 100644 hw/s3c24xx_serial.c
diff --git a/Makefile.target b/Makefile.target
index 81fbc34..2888e86 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -649,6 +649,7 @@ OBJS+= nseries.o blizzard.o onenand.o vga.o cbus.o tusb6010.o usb-musb.o
OBJS+= mst_fpga.o mainstone.o
OBJS+= musicpal.o pflash_cfi02.o
OBJS+= s3c24xx_memc.o s3c24xx_irq.o s3c24xx_clkcon.o s3c24xx_timers.o
+OBJS+= s3c24xx_serial.o
OBJS+= s3c2410x.o s3c2440.o
OBJS+= framebuffer.o
OBJS+= syborg.o syborg_fb.o syborg_interrupt.o syborg_keyboard.o
diff --git a/hw/s3c2410x.c b/hw/s3c2410x.c
index d61abe2..084f9ec 100644
--- a/hw/s3c2410x.c
+++ b/hw/s3c2410x.c
@@ -9,6 +9,7 @@
*/
#include "hw.h"
+#include "sysemu.h"
#include "s3c2410x.h"
@@ -27,6 +28,11 @@
/* Clock control */
#define CPU_S3C2410X_CLKCON_BASE (CPU_S3C2410X_PERIPHERAL + 0xC000000)
+/* serial port bases */
+#define CPU_S3C2410X_SERIAL0_BASE (CPU_S3C2410X_PERIPHERAL + 0x10000000)
+#define CPU_S3C2410X_SERIAL1_BASE (CPU_S3C2410X_PERIPHERAL + 0x10004000)
+#define CPU_S3C2410X_SERIAL2_BASE (CPU_S3C2410X_PERIPHERAL + 0x10008000)
+
/* Timer controller */
#define CPU_S3C2410X_TIMERS_BASE (CPU_S3C2410X_PERIPHERAL + 0x11000000)
@@ -63,5 +69,10 @@ s3c2410x_init(int sdram_size)
/* Timer controller */
s->timers = s3c24xx_timers_init(s, CPU_S3C2410X_TIMERS_BASE, 0, 12000000);
+ /* Serial port controllers */
+ s->uart[0] = s3c24xx_serial_init(s, serial_hds[0], CPU_S3C2410X_SERIAL0_BASE, 32);
+ s->uart[1] = s3c24xx_serial_init(s, serial_hds[1], CPU_S3C2410X_SERIAL1_BASE, 35);
+ s->uart[2] = s3c24xx_serial_init(s, serial_hds[2], CPU_S3C2410X_SERIAL2_BASE, 38);
+
return s;
}
diff --git a/hw/s3c2440.c b/hw/s3c2440.c
index 1e947df..3896965 100644
--- a/hw/s3c2440.c
+++ b/hw/s3c2440.c
@@ -9,6 +9,7 @@
*/
#include "hw.h"
+#include "sysemu.h"
#include "s3c2440.h"
@@ -27,6 +28,11 @@
/* Clock control */
#define CPU_S3C2440_CLKCON_BASE (CPU_S3C2440_PERIPHERAL + 0xC000000)
+/* serial port bases */
+#define CPU_S3C2440_SERIAL0_BASE (CPU_S3C2440_PERIPHERAL + 0x10000000)
+#define CPU_S3C2440_SERIAL1_BASE (CPU_S3C2440_PERIPHERAL + 0x10004000)
+#define CPU_S3C2440_SERIAL2_BASE (CPU_S3C2440_PERIPHERAL + 0x10008000)
+
/* Timer controller */
#define CPU_S3C2440_TIMERS_BASE (CPU_S3C2440_PERIPHERAL + 0x11000000)
@@ -61,5 +67,10 @@ s3c2440_init(int sdram_size)
/* Timer controller */
s->timers = s3c24xx_timers_init(s, CPU_S3C2440_TIMERS_BASE, 0, 12000000);
+ /* Serial port controllers */
+ s->uart[0] = s3c24xx_serial_init(s, serial_hds[0], CPU_S3C2440_SERIAL0_BASE, 32);
+ s->uart[1] = s3c24xx_serial_init(s, serial_hds[1], CPU_S3C2440_SERIAL1_BASE, 35);
+ s->uart[2] = s3c24xx_serial_init(s, serial_hds[2], CPU_S3C2440_SERIAL2_BASE, 38);
+
return s;
}
diff --git a/hw/s3c24xx.h b/hw/s3c24xx.h
index 9cc7f37..5a2e806 100644
--- a/hw/s3c24xx.h
+++ b/hw/s3c24xx.h
@@ -26,6 +26,10 @@ typedef struct S3CState_s {
/* timer controller */
struct s3c24xx_timers_state_s *timers;
+
+ /* Serial ports */
+ struct s3c24xx_serial_dev_s *uart[3];
+
} S3CState;
@@ -44,4 +48,7 @@ struct s3c24xx_clkcon_state_s *s3c24xx_clkcon_init(S3CState *soc, target_phys_ad
/* initialise timer controller */
struct s3c24xx_timers_state_s *s3c24xx_timers_init(S3CState *soc, target_phys_addr_t base_addr, uint32_t tclk0, uint32_t tclk1);
+/* initialise a serial port controller */
+struct s3c24xx_serial_dev_s *s3c24xx_serial_init(S3CState *soc, CharDriverState *chr, target_phys_addr_t base_addr, int irqn);
+
#endif /* S3C24XX_H */
diff --git a/hw/s3c24xx_serial.c b/hw/s3c24xx_serial.c
new file mode 100644
index 0000000..2b379de
--- /dev/null
+++ b/hw/s3c24xx_serial.c
@@ -0,0 +1,261 @@
+/* hw/s3c24xx_serial.c
+ *
+ * Samsung S3C24XX Serial block
+ *
+ * Copyright 2006, 2007 Daniel Silverstone and Vincent Sanders
+ *
+ * This file is under the terms of the GNU General Public
+ * License Version 2
+ */
+
+#include "hw.h"
+#include "qemu-char.h"
+#include "sysemu.h"
+
+#include "s3c24xx.h"
+
+/* S3C24XX serial port registers */
+
+/* Line control RW WORD */
+#define S3C_SERIAL_ULCON 0x00
+/* General control RW WORD */
+#define S3C_SERIAL_UCON 0x04
+/* Fifo control RW WORD */
+#define S3C_SERIAL_UFCON 0x08
+/* Modem control RW WORD */
+#define S3C_SERIAL_UMCON 0x0C
+/* TX/RX Status RO WORD */
+#define S3C_SERIAL_UTRSTAT 0x10
+/* Receive Error Status RO WORD */
+#define S3C_SERIAL_UERSTAT 0x14
+/* FiFo Status RO WORD */
+#define S3C_SERIAL_UFSTAT 0x18
+/* Modem Status RO WORD */
+#define S3C_SERIAL_UMSTAT 0x1C
+/* TX buffer WR BYTE */
+#define S3C_SERIAL_UTXH 0x20
+/* RX buffer RO BYTE */
+#define S3C_SERIAL_URXH 0x24
+/* BAUD Divisor RW WORD */
+#define S3C_SERIAL_UBRDIV 0x28
+
+/* S3C24XX serial port state */
+typedef struct s3c24xx_serial_dev_s {
+ uint32_t ulcon, ucon, ufcon, umcon, ubrdiv;
+ unsigned char rx_byte;
+ /* Byte is available to be read */
+ unsigned int rx_available : 1;
+ CharDriverState *chr;
+ qemu_irq tx_irq;
+ qemu_irq rx_irq;
+ qemu_irq tx_level;
+ qemu_irq rx_level;
+} s3c24xx_serial_dev;
+
+static void
+s3c24xx_serial_write_f(void *opaque, target_phys_addr_t addr, uint32_t value)
+{
+ s3c24xx_serial_dev *s = opaque;
+ int reg = addr & 0x3f;
+
+ switch(reg) {
+ case S3C_SERIAL_ULCON:
+ s->ulcon = value;
+ break;
+
+ case S3C_SERIAL_UCON:
+ s->ucon = value;
+ if( s->ucon & 1<<9 ) {
+ qemu_set_irq(s->tx_level, 1);
+ } else {
+ qemu_set_irq(s->tx_level, 0);
+ }
+ if( !(s->ucon & 1<<8) ) {
+ qemu_set_irq(s->rx_level, 0);
+ }
+ break;
+
+ case S3C_SERIAL_UFCON:
+ s->ufcon = (value & ~6);
+ break;
+
+ case S3C_SERIAL_UMCON:
+ s->umcon = value;
+ break;
+
+ case S3C_SERIAL_UTRSTAT:
+ break;
+
+ case S3C_SERIAL_UERSTAT:
+ break;
+
+ case S3C_SERIAL_UFSTAT:
+ break;
+
+ case S3C_SERIAL_UMSTAT:
+ break;
+
+ case S3C_SERIAL_UTXH: {
+ unsigned char ch = value & 0xff;
+ if (s->chr && ((s->ucon & 1<<5)==0)) {
+ qemu_chr_write(s->chr, &ch, 1);
+ } else {
+ s->rx_byte = ch;
+ s->rx_available = 1;
+ if( s->ucon & 1<<8 ) {
+ qemu_set_irq(s->rx_level, 1);
+ } else {
+ qemu_set_irq(s->rx_irq, 1);
+ }
+ }
+ if (s->ucon & 1<<9) {
+ qemu_set_irq(s->tx_level, 1);
+ } else {
+ qemu_set_irq(s->tx_irq, 1);
+ }
+ break;
+ }
+
+ case S3C_SERIAL_URXH:
+ break;
+
+ case S3C_SERIAL_UBRDIV:
+ s->ubrdiv = value;
+ break;
+
+ default:
+ break;
+ };
+}
+
+static uint32_t
+s3c24xx_serial_read_f(void *opaque, target_phys_addr_t addr)
+{
+ s3c24xx_serial_dev *s = opaque;
+ int reg = addr & 0x3f;
+
+ switch (reg) {
+ case S3C_SERIAL_ULCON:
+ return s->ulcon;
+
+ case S3C_SERIAL_UCON:
+ return s->ucon;
+
+ case S3C_SERIAL_UFCON:
+ return s->ufcon & ~0x8; /* bit 3 is reserved, must be zero */
+
+ case S3C_SERIAL_UMCON:
+ return s->umcon & 0x11; /* Rest are reserved, must be zero */
+
+ case S3C_SERIAL_UTRSTAT:
+ return 6 | s->rx_available; /* TX always clear, RX when available */
+
+ case S3C_SERIAL_UERSTAT:
+ return 0; /* Later, break detect comes in here */
+
+ case S3C_SERIAL_UFSTAT:
+ return s->rx_available; /* TXFIFO, always empty, RXFIFO 0 or 1 bytes */
+
+ case S3C_SERIAL_UMSTAT:
+ return 0;
+
+ case S3C_SERIAL_UTXH:
+ return 0;
+
+ case S3C_SERIAL_URXH:
+ s->rx_available = 0;
+ if (s->ucon & 1<<8) {
+ qemu_set_irq(s->rx_level, 0);
+ }
+ return s->rx_byte;
+
+ case S3C_SERIAL_UBRDIV:
+ return s->ubrdiv;
+
+ default:
+ return 0;
+ };
+}
+
+static CPUReadMemoryFunc *s3c24xx_serial_read[] = {
+ &s3c24xx_serial_read_f,
+ &s3c24xx_serial_read_f,
+ &s3c24xx_serial_read_f,
+};
+
+static CPUWriteMemoryFunc *s3c24xx_serial_write[] = {
+ &s3c24xx_serial_write_f,
+ &s3c24xx_serial_write_f,
+ &s3c24xx_serial_write_f,
+};
+
+
+static void s3c24xx_serial_event(void *opaque, int event)
+{
+}
+
+static int
+s3c24xx_serial_can_receive(void *opaque)
+{
+ s3c24xx_serial_dev *s = opaque;
+
+ /* If there's no byte to be read, we can receive a new one */
+ return !s->rx_available;
+}
+
+static void
+s3c24xx_serial_receive(void *opaque, const uint8_t *buf, int size)
+{
+ s3c24xx_serial_dev *s = opaque;
+ s->rx_byte = buf[0];
+ s->rx_available = 1;
+ if ( s->ucon & 1 << 8 ) {
+ qemu_set_irq(s->rx_level, 1);
+ } else {
+ /* Is there something we can do here to ensure it's just a pulse ? */
+ qemu_set_irq(s->rx_irq, 1);
+ }
+}
+
+/* Create a S3C serial port, the port implementation is common to all
+ * current s3c devices only differing in the I/O base address and number of
+ * ports.
+ */
+struct s3c24xx_serial_dev_s *
+s3c24xx_serial_init(S3CState *soc,
+ CharDriverState *chr,
+ target_phys_addr_t base_addr,
+ int irqn)
+{
+ /* Initialise a serial port at the given port address */
+ s3c24xx_serial_dev *s;
+ int serial_io;
+
+ s = qemu_mallocz(sizeof(s3c24xx_serial_dev));
+ if (!s)
+ return NULL;
+
+ /* initialise serial port context */
+ s->rx_irq = s3c24xx_get_irq(soc->irq, irqn);
+ s->rx_level = s3c24xx_get_irq(soc->irq, irqn + 64);
+
+ s->tx_irq = s3c24xx_get_irq(soc->irq, irqn + 1);
+ s->tx_level = s3c24xx_get_irq(soc->irq, irqn + 1 + 64);
+
+ /* Prepare our MMIO tag */
+ serial_io = cpu_register_io_memory(0, s3c24xx_serial_read, s3c24xx_serial_write, s);
+ /* Register the region with the tag */
+ cpu_register_physical_memory(base_addr, 44, serial_io);
+
+ if (chr) {
+ /* If the port is present add to the character device's IO handlers. */
+ s->chr = chr;
+
+ qemu_chr_add_handlers(s->chr,
+ s3c24xx_serial_can_receive,
+ s3c24xx_serial_receive,
+ s3c24xx_serial_event,
+ s);
+ }
+ return s;
+}
--
1.6.0.4
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [Qemu-devel] [PATCH 08/16] Peripheral driver for S3C SOC real time clock.
2009-05-23 16:35 [Qemu-devel] Add ARM S3C SOC core, drivers and boards - v3 Vincent Sanders
` (6 preceding siblings ...)
2009-05-23 16:35 ` [Qemu-devel] [PATCH 07/16] Peripheral driver for S3C SOC Serial ports Vincent Sanders
@ 2009-05-23 16:35 ` Vincent Sanders
2009-05-23 16:35 ` [Qemu-devel] [PATCH 09/16] Peripheral driver for S3C SOC general purpose I/O Vincent Sanders
` (6 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: Vincent Sanders @ 2009-05-23 16:35 UTC (permalink / raw)
To: qemu-devel; +Cc: Vincent Sanders
Signed-off-by: Vincent Sanders <vince@simtec.co.uk>
---
Makefile.target | 2 +-
hw/s3c2410x.c | 6 ++
hw/s3c2440.c | 6 ++
hw/s3c24xx.h | 7 +++
hw/s3c24xx_rtc.c | 135 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
5 files changed, 155 insertions(+), 1 deletions(-)
create mode 100644 hw/s3c24xx_rtc.c
diff --git a/Makefile.target b/Makefile.target
index 2888e86..2596943 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -649,7 +649,7 @@ OBJS+= nseries.o blizzard.o onenand.o vga.o cbus.o tusb6010.o usb-musb.o
OBJS+= mst_fpga.o mainstone.o
OBJS+= musicpal.o pflash_cfi02.o
OBJS+= s3c24xx_memc.o s3c24xx_irq.o s3c24xx_clkcon.o s3c24xx_timers.o
-OBJS+= s3c24xx_serial.o
+OBJS+= s3c24xx_serial.o s3c24xx_rtc.o
OBJS+= s3c2410x.o s3c2440.o
OBJS+= framebuffer.o
OBJS+= syborg.o syborg_fb.o syborg_interrupt.o syborg_keyboard.o
diff --git a/hw/s3c2410x.c b/hw/s3c2410x.c
index 084f9ec..21ecec2 100644
--- a/hw/s3c2410x.c
+++ b/hw/s3c2410x.c
@@ -36,6 +36,9 @@
/* Timer controller */
#define CPU_S3C2410X_TIMERS_BASE (CPU_S3C2410X_PERIPHERAL + 0x11000000)
+/* Real time clock */
+#define CPU_S3C2410X_RTC_BASE (CPU_S3C2410X_PERIPHERAL + 0x17000000)
+
/* Initialise a Samsung S3C2410X SOC ARM core and internal peripherals. */
S3CState *
s3c2410x_init(int sdram_size)
@@ -74,5 +77,8 @@ s3c2410x_init(int sdram_size)
s->uart[1] = s3c24xx_serial_init(s, serial_hds[1], CPU_S3C2410X_SERIAL1_BASE, 35);
s->uart[2] = s3c24xx_serial_init(s, serial_hds[2], CPU_S3C2410X_SERIAL2_BASE, 38);
+ /* Real time clcok */
+ s->rtc = s3c24xx_rtc_init(CPU_S3C2410X_RTC_BASE);
+
return s;
}
diff --git a/hw/s3c2440.c b/hw/s3c2440.c
index 3896965..91f4341 100644
--- a/hw/s3c2440.c
+++ b/hw/s3c2440.c
@@ -36,6 +36,9 @@
/* Timer controller */
#define CPU_S3C2440_TIMERS_BASE (CPU_S3C2440_PERIPHERAL + 0x11000000)
+/* Real time clock */
+#define CPU_S3C2440_RTC_BASE (CPU_S3C2440_PERIPHERAL + 0x17000000)
+
/* Initialise a Samsung S3C2440 SOC ARM core and internal peripherals. */
S3CState *
s3c2440_init(int sdram_size)
@@ -72,5 +75,8 @@ s3c2440_init(int sdram_size)
s->uart[1] = s3c24xx_serial_init(s, serial_hds[1], CPU_S3C2440_SERIAL1_BASE, 35);
s->uart[2] = s3c24xx_serial_init(s, serial_hds[2], CPU_S3C2440_SERIAL2_BASE, 38);
+ /* Real time clcok */
+ s->rtc = s3c24xx_rtc_init(CPU_S3C2440_RTC_BASE);
+
return s;
}
diff --git a/hw/s3c24xx.h b/hw/s3c24xx.h
index 5a2e806..643d841 100644
--- a/hw/s3c24xx.h
+++ b/hw/s3c24xx.h
@@ -30,6 +30,9 @@ typedef struct S3CState_s {
/* Serial ports */
struct s3c24xx_serial_dev_s *uart[3];
+ /* Real time clock */
+ struct s3c24xx_rtc_state_s *rtc;
+
} S3CState;
@@ -51,4 +54,8 @@ struct s3c24xx_timers_state_s *s3c24xx_timers_init(S3CState *soc, target_phys_ad
/* initialise a serial port controller */
struct s3c24xx_serial_dev_s *s3c24xx_serial_init(S3CState *soc, CharDriverState *chr, target_phys_addr_t base_addr, int irqn);
+/* Initialise real time clock */
+struct s3c24xx_rtc_state_s *s3c24xx_rtc_init(target_phys_addr_t base_addr);
+
+
#endif /* S3C24XX_H */
diff --git a/hw/s3c24xx_rtc.c b/hw/s3c24xx_rtc.c
new file mode 100644
index 0000000..2a2124f
--- /dev/null
+++ b/hw/s3c24xx_rtc.c
@@ -0,0 +1,135 @@
+/* hw/s3c24xx_rtc.c
+ *
+ * Samsung S3C24XX RTC emulation
+ *
+ * Copyright 2006, 2007, 2008 Daniel Silverstone and Vincent Sanders
+ *
+ * This file is under the terms of the GNU General Public
+ * License Version 2
+ */
+
+#include "hw.h"
+
+#include "s3c24xx.h"
+
+
+/* RTC Control RW Byte */
+#define S3C_REG_RTCCON 0
+/* Tick time count RW Byte */
+#define S3C_REG_TICNT 1
+/* RTC Alarm Control RW Byte */
+#define S3C_REG_RTCALM 4
+/* Alarm second */
+#define S3C_REG_ALMSEC 5
+/* Alarm minute */
+#define S3C_REG_ALMMIN 6
+/* Alarm hour */
+#define S3C_REG_ALMHOUR 7
+/* Alarm day */
+#define S3C_REG_ALMDATE 8
+/* Alarm month */
+#define S3C_REG_ALMMON 9
+/* Alarm year */
+#define S3C_REG_ALMYEAR 10
+/* RTC Round Reset */
+#define S3C_REG_RTCRST 11
+/* BCD Second */
+#define S3C_REG_BCDSEC 12
+/* BCD Minute */
+#define S3C_REG_BCDMIN 13
+/* BCD Hour */
+#define S3C_REG_BCDHOUR 14
+/* BCD Day */
+#define S3C_REG_BCDDATE 15
+/* BCD Day of week */
+#define S3C_REG_BCDDAY 16
+/* BCD Month */
+#define S3C_REG_BCDMON 17
+/* BCD Year */
+#define S3C_REG_BCDYEAR 18
+
+/* Real Time clock state */
+struct s3c24xx_rtc_state_s {
+ uint32_t rtc_reg[19];
+};
+
+
+static inline int to_bcd(int a)
+{
+ return ((a/10)<<4) | (a%10);
+}
+
+static void update_time(struct s3c24xx_rtc_state_s *s)
+{
+ time_t ti;
+ struct tm *tm;
+ /* update the RTC registers from system time */
+ time(&ti);
+ tm = gmtime(&ti);
+ s->rtc_reg[S3C_REG_BCDSEC] = to_bcd(tm->tm_sec);
+ s->rtc_reg[S3C_REG_BCDMIN] = to_bcd(tm->tm_min);
+ s->rtc_reg[S3C_REG_BCDHOUR] = to_bcd(tm->tm_hour);
+ s->rtc_reg[S3C_REG_BCDDATE] = to_bcd(tm->tm_mday);
+ s->rtc_reg[S3C_REG_BCDDAY] = to_bcd(tm->tm_wday + 1);
+ s->rtc_reg[S3C_REG_BCDMON] = to_bcd(tm->tm_mon + 1);
+ s->rtc_reg[S3C_REG_BCDYEAR] = to_bcd(tm->tm_year - 100);
+}
+
+static void
+s3c24xx_rtc_write_f(void *opaque, target_phys_addr_t addr_, uint32_t value)
+{
+ struct s3c24xx_rtc_state_s *s = (struct s3c24xx_rtc_state_s *)opaque;
+ int addr = (addr_ - 0x40) >> 2;
+ if (addr < 0 || addr > 18)
+ addr = 18;
+
+ s->rtc_reg[addr] = value;
+}
+
+static uint32_t
+s3c24xx_rtc_read_f(void *opaque, target_phys_addr_t addr_)
+{
+ struct s3c24xx_rtc_state_s *s = (struct s3c24xx_rtc_state_s *)opaque;
+ int addr = (addr_ - 0x40) >> 2;
+
+ if (addr < 0 || addr > 18)
+ addr = 18;
+
+ update_time(s);
+
+ return s->rtc_reg[addr];
+}
+
+static CPUReadMemoryFunc *s3c24xx_rtc_read[] = {
+ &s3c24xx_rtc_read_f,
+ &s3c24xx_rtc_read_f,
+ &s3c24xx_rtc_read_f,
+};
+
+static CPUWriteMemoryFunc *s3c24xx_rtc_write[] = {
+ &s3c24xx_rtc_write_f,
+ &s3c24xx_rtc_write_f,
+ &s3c24xx_rtc_write_f,
+};
+
+
+struct s3c24xx_rtc_state_s *
+s3c24xx_rtc_init(target_phys_addr_t base_addr)
+{
+ int tag;
+ struct s3c24xx_rtc_state_s *s;
+
+ s = qemu_mallocz(sizeof(struct s3c24xx_rtc_state_s));
+
+ tag = cpu_register_io_memory(0, s3c24xx_rtc_read, s3c24xx_rtc_write, s);
+
+ /* there are only 19 real registers but they start at offset 0x40 into the
+ * range so we have 35 registers mapped
+ */
+ cpu_register_physical_memory(base_addr, 35 * 4, tag);
+
+ /* set the RTC so it appears active */
+ s->rtc_reg[S3C_REG_RTCCON] = 1;
+
+ return s;
+}
--
1.6.0.4
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [Qemu-devel] [PATCH 09/16] Peripheral driver for S3C SOC general purpose I/O
2009-05-23 16:35 [Qemu-devel] Add ARM S3C SOC core, drivers and boards - v3 Vincent Sanders
` (7 preceding siblings ...)
2009-05-23 16:35 ` [Qemu-devel] [PATCH 08/16] Peripheral driver for S3C SOC real time clock Vincent Sanders
@ 2009-05-23 16:35 ` Vincent Sanders
2009-05-23 16:35 ` [Qemu-devel] [PATCH 10/16] Peripheral driver for S3C SOC I2C controller Vincent Sanders
` (5 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: Vincent Sanders @ 2009-05-23 16:35 UTC (permalink / raw)
To: qemu-devel; +Cc: Vincent Sanders
Provides general purpose I/O handling, SOC identification registers
and external interrupt support
Signed-off-by: Vincent Sanders <vince@simtec.co.uk>
---
Makefile.target | 2 +-
hw/s3c2410x.c | 10 +++
hw/s3c2440.c | 9 ++
hw/s3c24xx.h | 7 ++
hw/s3c24xx_gpio.c | 225 +++++++++++++++++++++++++++++++++++++++++++++++++++++
5 files changed, 252 insertions(+), 1 deletions(-)
create mode 100644 hw/s3c24xx_gpio.c
diff --git a/Makefile.target b/Makefile.target
index 2596943..52dcf4c 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -649,7 +649,7 @@ OBJS+= nseries.o blizzard.o onenand.o vga.o cbus.o tusb6010.o usb-musb.o
OBJS+= mst_fpga.o mainstone.o
OBJS+= musicpal.o pflash_cfi02.o
OBJS+= s3c24xx_memc.o s3c24xx_irq.o s3c24xx_clkcon.o s3c24xx_timers.o
-OBJS+= s3c24xx_serial.o s3c24xx_rtc.o
+OBJS+= s3c24xx_serial.o s3c24xx_rtc.o s3c24xx_gpio.o
OBJS+= s3c2410x.o s3c2440.o
OBJS+= framebuffer.o
OBJS+= syborg.o syborg_fb.o syborg_interrupt.o syborg_keyboard.o
diff --git a/hw/s3c2410x.c b/hw/s3c2410x.c
index 21ecec2..c3b84a0 100644
--- a/hw/s3c2410x.c
+++ b/hw/s3c2410x.c
@@ -13,6 +13,10 @@
#include "s3c2410x.h"
+/* S3C2410 SoC IDs */
+#define CPU_S3C2410X_IDENT_S3C2410X 0x32410000
+#define CPU_S3C2410X_IDENT_S3C2410A 0x32410002
+
/* Integrated peripherals */
/* SRAM */
@@ -36,6 +40,9 @@
/* Timer controller */
#define CPU_S3C2410X_TIMERS_BASE (CPU_S3C2410X_PERIPHERAL + 0x11000000)
+/* GPIO */
+#define CPU_S3C2410X_GPIO_BASE (CPU_S3C2410X_PERIPHERAL + 0x16000000)
+
/* Real time clock */
#define CPU_S3C2410X_RTC_BASE (CPU_S3C2410X_PERIPHERAL + 0x17000000)
@@ -80,5 +87,8 @@ s3c2410x_init(int sdram_size)
/* Real time clcok */
s->rtc = s3c24xx_rtc_init(CPU_S3C2410X_RTC_BASE);
+ /* GPIO */
+ s->gpio = s3c24xx_gpio_init(s, CPU_S3C2410X_GPIO_BASE, CPU_S3C2410X_IDENT_S3C2410A);
+
return s;
}
diff --git a/hw/s3c2440.c b/hw/s3c2440.c
index 91f4341..b53f010 100644
--- a/hw/s3c2440.c
+++ b/hw/s3c2440.c
@@ -13,6 +13,9 @@
#include "s3c2440.h"
+/* S3C2440 SoC ID */
+#define CPU_S3C2440_IDENT_S3C2440A 0x32440001
+
/* Integrated peripherals */
/* SRAM */
@@ -36,6 +39,9 @@
/* Timer controller */
#define CPU_S3C2440_TIMERS_BASE (CPU_S3C2440_PERIPHERAL + 0x11000000)
+/* GPIO */
+#define CPU_S3C2440_GPIO_BASE (CPU_S3C2440_PERIPHERAL + 0x16000000)
+
/* Real time clock */
#define CPU_S3C2440_RTC_BASE (CPU_S3C2440_PERIPHERAL + 0x17000000)
@@ -78,5 +84,8 @@ s3c2440_init(int sdram_size)
/* Real time clcok */
s->rtc = s3c24xx_rtc_init(CPU_S3C2440_RTC_BASE);
+ /* And some GPIO */
+ s->gpio = s3c24xx_gpio_init(s, CPU_S3C2440_GPIO_BASE, CPU_S3C2440_IDENT_S3C2440A);
+
return s;
}
diff --git a/hw/s3c24xx.h b/hw/s3c24xx.h
index 643d841..b9d8dfe 100644
--- a/hw/s3c24xx.h
+++ b/hw/s3c24xx.h
@@ -33,6 +33,8 @@ typedef struct S3CState_s {
/* Real time clock */
struct s3c24xx_rtc_state_s *rtc;
+ /* GPIO */
+ struct s3c24xx_gpio_state_s *gpio;
} S3CState;
@@ -57,5 +59,10 @@ struct s3c24xx_serial_dev_s *s3c24xx_serial_init(S3CState *soc, CharDriverState
/* Initialise real time clock */
struct s3c24xx_rtc_state_s *s3c24xx_rtc_init(target_phys_addr_t base_addr);
+/* initialise GPIO */
+struct s3c24xx_gpio_state_s *s3c24xx_gpio_init(S3CState *soc, target_phys_addr_t base_addr, uint32_t cpu_id);
+
+/* get the qemu interrupt from an eirq number */
+qemu_irq s3c24xx_get_eirq(struct s3c24xx_gpio_state_s *s, int einum);
#endif /* S3C24XX_H */
diff --git a/hw/s3c24xx_gpio.c b/hw/s3c24xx_gpio.c
new file mode 100644
index 0000000..1f9134d
--- /dev/null
+++ b/hw/s3c24xx_gpio.c
@@ -0,0 +1,225 @@
+/* hw/s3c24xx_gpio.c
+ *
+ * Samsung S3C24XX GPIO emulation (mostly for E-INT)
+ *
+ * Copyright 2006, 2007 Daniel Silverstone and Vincent Sanders
+ *
+ * This file is under the terms of the GNU General Public
+ * License Version 2
+ */
+
+#include "hw.h"
+#include "s3c24xx.h"
+
+#define S3C_GPIO_GPECON (0x40)
+#define S3C_GPIO_GPEDAT (0x44)
+#define S3C_GPIO_GPEUP (0x48)
+
+#define S3C_GPIO_EINT_MASK (0xA4)
+#define S3C_GPIO_EINT_PEND (0xA8)
+#define S3C_GPIO_GSTATUS0 (0xAC)
+#define S3C_GPIO_GSTATUS1 (0xB0)
+#define S3C_GPIO_GSTATUS2 (0xB4)
+#define S3C_GPIO_GSTATUS3 (0xB8)
+#define S3C_GPIO_GSTATUS4 (0xBC)
+
+
+#define GPRN(r) (r>>2)
+#define GPR(P) s->gpio_reg[P>>2]
+
+/* GPIO controller state */
+struct s3c24xx_gpio_state_s {
+ uint32_t gpio_reg[47];
+
+ qemu_irq *eirqs; /* gpio external interrupts */
+
+ qemu_irq irqs[6]; /* cpu irqs to cascade */
+};
+
+static void
+s3c24xx_gpio_propogate_eint(struct s3c24xx_gpio_state_s *s)
+{
+ uint32_t ints, i;
+
+ ints = GPR(S3C_GPIO_EINT_PEND) & ~GPR(S3C_GPIO_EINT_MASK);
+
+ /* EINT0 - EINT3 are INT0 - INT3 */
+ for (i=0; i < 4; ++i)
+ qemu_set_irq(s->irqs[i], (ints & (1<<i))?1:0);
+
+ /* EINT4 - EINT7 are INT4 */
+ qemu_set_irq(s->irqs[4], (ints & 0xf0)?1:0);
+
+ /* EINT8 - EINT23 are INT5 */
+ qemu_set_irq(s->irqs[5], (ints & 0x00ffff00)?1:0);
+}
+
+static uint32_t
+gpio_con_to_mask(uint32_t con)
+{
+ uint32_t mask = 0x0;
+ int bit;
+
+ for (bit = 0; bit < 16; bit++) {
+ if (((con >> (bit*2)) & 0x3) == 0x01)
+ mask |= 1 << bit;
+ }
+
+ return mask;
+}
+
+static void
+s3c24xx_gpio_write_f(void *opaque, target_phys_addr_t addr_, uint32_t value)
+{
+ struct s3c24xx_gpio_state_s *s = (struct s3c24xx_gpio_state_s *)opaque;
+ int addr = (addr_ >> 2) & 0x3f;
+
+ if (addr < 0 || addr > 47)
+ addr = 47;
+
+ if (addr == (S3C_GPIO_EINT_MASK>>2))
+ value &= ~0xf; /* cannot mask EINT0-EINT3 */
+
+ if (addr == (S3C_GPIO_EINT_PEND>>2)) {
+ s->gpio_reg[addr] &= ~value;
+ } else {
+ if (addr < (0x80/4) && (addr_ & 0xf) == 0x04) {
+ uint32_t mask = gpio_con_to_mask(s->gpio_reg[addr - 1]);
+
+ value &= mask;
+
+ s->gpio_reg[addr] &= ~mask;
+ s->gpio_reg[addr] |= value;
+ } else
+ s->gpio_reg[addr] = value;
+ }
+
+ if ((addr == (S3C_GPIO_EINT_MASK)>>2) ||
+ (addr == (S3C_GPIO_EINT_PEND)>>2)) {
+ /* A write to the EINT regs leads us to determine the interrupts to
+ * propagate
+ */
+ s3c24xx_gpio_propogate_eint(s);
+ }
+}
+
+static uint32_t
+s3c24xx_gpio_read_f(void *opaque, target_phys_addr_t addr_)
+{
+ struct s3c24xx_gpio_state_s *s = (struct s3c24xx_gpio_state_s *)opaque;
+ uint32_t addr = (addr_ >> 2);
+ uint32_t ret;
+
+ if (addr > GPRN(S3C_GPIO_GSTATUS4))
+ addr = GPRN(S3C_GPIO_GSTATUS4);
+
+ ret = s->gpio_reg[addr];
+
+ if (addr == GPRN(S3C_GPIO_GPEDAT)) {
+ /* IIC pins are special function pins on GPE14 and GPE15. If GPE is is
+ * in input mode make the IIC lines appear to be pulled high. This is
+ * neccissary because OS i2c drivers use this to ensure the I2C bus is
+ * clear.
+ */
+ if ((GPR(S3C_GPIO_GPECON) & (3<<28)) == 0)
+ ret |= 1 << 14;
+
+ if ((GPR(S3C_GPIO_GPECON) & (3<<30)) == 0)
+ ret |= 1 << 15;
+ }
+
+ return ret;
+}
+
+
+static CPUReadMemoryFunc *s3c24xx_gpio_read[] = {
+ &s3c24xx_gpio_read_f,
+ &s3c24xx_gpio_read_f,
+ &s3c24xx_gpio_read_f,
+};
+
+static CPUWriteMemoryFunc *s3c24xx_gpio_write[] = {
+ &s3c24xx_gpio_write_f,
+ &s3c24xx_gpio_write_f,
+ &s3c24xx_gpio_write_f,
+};
+
+static void
+s3c24xx_gpio_irq_handler(void *opaque, int n, int level)
+{
+ struct s3c24xx_gpio_state_s *s = (struct s3c24xx_gpio_state_s *)opaque;
+
+ if (level)
+ GPR(S3C_GPIO_EINT_PEND) |= (1<<n);
+
+ s3c24xx_gpio_propogate_eint(s);
+}
+
+static void s3c24xx_gpio_save(QEMUFile *f, void *opaque)
+{
+ struct s3c24xx_gpio_state_s *s = (struct s3c24xx_gpio_state_s *)opaque;
+ int i;
+
+ for (i = 0; i < 47; i ++)
+ qemu_put_be32s(f, &s->gpio_reg[i]);
+}
+
+static int s3c24xx_gpio_load(QEMUFile *f, void *opaque, int version_id)
+{
+ struct s3c24xx_gpio_state_s *s = (struct s3c24xx_gpio_state_s *)opaque;
+ int i;
+
+ for (i = 0; i < 47; i ++)
+ qemu_get_be32s(f, &s->gpio_reg[i]);
+
+ return 0;
+}
+
+struct s3c24xx_gpio_state_s *
+s3c24xx_gpio_init(S3CState *soc, target_phys_addr_t base_addr, uint32_t cpu_id)
+{
+ /* Samsung S3C24XX GPIO
+ *
+ * The primary operation here is the ID register and IRQs
+ */
+ struct s3c24xx_gpio_state_s *s;
+ int tag;
+ int i;
+
+ s = qemu_mallocz(sizeof(struct s3c24xx_gpio_state_s));
+ if (!s)
+ return NULL;
+
+ tag = cpu_register_io_memory(0, s3c24xx_gpio_read, s3c24xx_gpio_write, s);
+ cpu_register_physical_memory(base_addr, 47 * 4, tag);
+ register_savevm("s3c24xx_gpio", 0, 0, s3c24xx_gpio_save, s3c24xx_gpio_load, s);
+
+ /* set non zero default values */
+ GPR(0x00) = 0x7fffff;
+ GPR(0x34) = 0xfefc;
+ GPR(0x38) = 0xf000;
+ GPR(0x68) = 0xf800;
+ GPR(0x80) = 0x10330;
+ GPR(0xA4) = 0xfffff0;
+ GPR(S3C_GPIO_GSTATUS1) = cpu_id;
+ GPR(S3C_GPIO_GSTATUS2) = 1;
+ GPR(S3C_GPIO_GSTATUS3) = 0;
+ GPR(S3C_GPIO_GSTATUS4) = 0;
+
+ /* obtain first level IRQs for cascade */
+ for (i = 0; i <= 5; i++) {
+ s->irqs[i] = s3c24xx_get_irq(soc->irq, i);
+ }
+
+ /* EINTs 0-23 -- Only 24, not 48 because EINTs are not level */
+ s->eirqs = qemu_allocate_irqs(s3c24xx_gpio_irq_handler, s, 24);
+
+ return s;
+}
+
+/* get the qemu interrupt from an eirq number */
+qemu_irq
+s3c24xx_get_eirq(struct s3c24xx_gpio_state_s *s, int einum)
+{
+ return s->eirqs[einum];
+}
--
1.6.0.4
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [Qemu-devel] [PATCH 10/16] Peripheral driver for S3C SOC I2C controller.
2009-05-23 16:35 [Qemu-devel] Add ARM S3C SOC core, drivers and boards - v3 Vincent Sanders
` (8 preceding siblings ...)
2009-05-23 16:35 ` [Qemu-devel] [PATCH 09/16] Peripheral driver for S3C SOC general purpose I/O Vincent Sanders
@ 2009-05-23 16:35 ` Vincent Sanders
2009-05-23 16:35 ` [Qemu-devel] [PATCH 11/16] Peripheral driver for S3C SOC LCD controller Vincent Sanders
` (4 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: Vincent Sanders @ 2009-05-23 16:35 UTC (permalink / raw)
To: qemu-devel; +Cc: Vincent Sanders
Signed-off-by: Vincent Sanders <vince@simtec.co.uk>
---
Makefile.target | 2 +-
hw/s3c2410x.c | 7 ++
hw/s3c2440.c | 7 ++
hw/s3c24xx.h | 9 ++
hw/s3c24xx_iic.c | 255 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
5 files changed, 279 insertions(+), 1 deletions(-)
create mode 100644 hw/s3c24xx_iic.c
diff --git a/Makefile.target b/Makefile.target
index 52dcf4c..c9af461 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -649,7 +649,7 @@ OBJS+= nseries.o blizzard.o onenand.o vga.o cbus.o tusb6010.o usb-musb.o
OBJS+= mst_fpga.o mainstone.o
OBJS+= musicpal.o pflash_cfi02.o
OBJS+= s3c24xx_memc.o s3c24xx_irq.o s3c24xx_clkcon.o s3c24xx_timers.o
-OBJS+= s3c24xx_serial.o s3c24xx_rtc.o s3c24xx_gpio.o
+OBJS+= s3c24xx_serial.o s3c24xx_rtc.o s3c24xx_gpio.o s3c24xx_iic.o
OBJS+= s3c2410x.o s3c2440.o
OBJS+= framebuffer.o
OBJS+= syborg.o syborg_fb.o syborg_interrupt.o syborg_keyboard.o
diff --git a/hw/s3c2410x.c b/hw/s3c2410x.c
index c3b84a0..f3057f8 100644
--- a/hw/s3c2410x.c
+++ b/hw/s3c2410x.c
@@ -40,6 +40,9 @@
/* Timer controller */
#define CPU_S3C2410X_TIMERS_BASE (CPU_S3C2410X_PERIPHERAL + 0x11000000)
+/* IIC */
+#define CPU_S3C2410X_IIC_BASE (CPU_S3C2410X_PERIPHERAL + 0x14000000)
+
/* GPIO */
#define CPU_S3C2410X_GPIO_BASE (CPU_S3C2410X_PERIPHERAL + 0x16000000)
@@ -90,5 +93,9 @@ s3c2410x_init(int sdram_size)
/* GPIO */
s->gpio = s3c24xx_gpio_init(s, CPU_S3C2410X_GPIO_BASE, CPU_S3C2410X_IDENT_S3C2410A);
+ /* I2C */
+ s->iic = s3c24xx_iic_init(s3c24xx_get_irq(s->irq, 27),
+ CPU_S3C2410X_IIC_BASE);
+
return s;
}
diff --git a/hw/s3c2440.c b/hw/s3c2440.c
index b53f010..f8d6f63 100644
--- a/hw/s3c2440.c
+++ b/hw/s3c2440.c
@@ -39,6 +39,9 @@
/* Timer controller */
#define CPU_S3C2440_TIMERS_BASE (CPU_S3C2440_PERIPHERAL + 0x11000000)
+/* IIC */
+#define CPU_S3C2440_IIC_BASE (CPU_S3C2440_PERIPHERAL + 0x14000000)
+
/* GPIO */
#define CPU_S3C2440_GPIO_BASE (CPU_S3C2440_PERIPHERAL + 0x16000000)
@@ -87,5 +90,9 @@ s3c2440_init(int sdram_size)
/* And some GPIO */
s->gpio = s3c24xx_gpio_init(s, CPU_S3C2440_GPIO_BASE, CPU_S3C2440_IDENT_S3C2440A);
+ /* I2C */
+ s->iic = s3c24xx_iic_init(s3c24xx_get_irq(s->irq, 27),
+ CPU_S3C2440_IIC_BASE);
+
return s;
}
diff --git a/hw/s3c24xx.h b/hw/s3c24xx.h
index b9d8dfe..bb52c00 100644
--- a/hw/s3c24xx.h
+++ b/hw/s3c24xx.h
@@ -35,6 +35,9 @@ typedef struct S3CState_s {
/* GPIO */
struct s3c24xx_gpio_state_s *gpio;
+
+ /* I2C */
+ struct s3c24xx_i2c_state_s *iic;
} S3CState;
@@ -65,4 +68,10 @@ struct s3c24xx_gpio_state_s *s3c24xx_gpio_init(S3CState *soc, target_phys_addr_t
/* get the qemu interrupt from an eirq number */
qemu_irq s3c24xx_get_eirq(struct s3c24xx_gpio_state_s *s, int einum);
+/* Initialise I2c controller */
+struct s3c24xx_i2c_state_s *s3c24xx_iic_init(qemu_irq irq, target_phys_addr_t base_addr);
+
+/* aquire bus from controller state */
+i2c_bus *s3c24xx_i2c_bus(struct s3c24xx_i2c_state_s *s);
+
#endif /* S3C24XX_H */
diff --git a/hw/s3c24xx_iic.c b/hw/s3c24xx_iic.c
new file mode 100644
index 0000000..56945f7
--- /dev/null
+++ b/hw/s3c24xx_iic.c
@@ -0,0 +1,255 @@
+/* hw/s3c24xx_iic.c
+ *
+ * Samsung S3C24XX i2c peripheral emulation
+ *
+ * Copyright 2006, 2007, 2008 Daniel Silverstone, Ben Dooks
+ * and Vincent Sanders
+ *
+ * This file is under the terms of the GNU General Public
+ * License Version 2
+ */
+
+#include "hw.h"
+#include "i2c.h"
+
+#include "s3c24xx.h"
+
+/* i2c controller registers */
+#define S3C_IICCON (0x00)
+#define S3C_IICSTAT (0x04)
+#define S3C_IICADD (0x08)
+#define S3C_IICDS (0x0C)
+#define S3C_IICLC (0x10)
+
+#define S3C_IICCON_ACKEN (1<<7)
+#define S3C_IICCON_TXDIV_16 (0<<6)
+#define S3C_IICCON_TXDIV_512 (1<<6)
+#define S3C_IICCON_IRQEN (1<<5)
+#define S3C_IICCON_IRQPEND (1<<4)
+#define S3C_IICCON_SCALE(x) ((x)&15)
+#define S3C_IICCON_SCALEMASK (0xf)
+
+#define S3C_IICSTAT_MASTER_RX (2<<6)
+#define S3C_IICSTAT_MASTER_TX (3<<6)
+#define S3C_IICSTAT_SLAVE_RX (0<<6)
+#define S3C_IICSTAT_SLAVE_TX (1<<6)
+#define S3C_IICSTAT_MODEMASK (3<<6)
+
+#define S3C_IICSTAT_START (1<<5)
+#define S3C_IICSTAT_BUSBUSY (1<<5)
+#define S3C_IICSTAT_TXRXEN (1<<4)
+#define S3C_IICSTAT_ARBITR (1<<3)
+#define S3C_IICSTAT_ASSLAVE (1<<2)
+#define S3C_IICSTAT_ADDR0 (1<<1)
+#define S3C_IICSTAT_LASTBIT (1<<0)
+
+#define S3C_IICLC_SDA_DELAY0 (0 << 0)
+#define S3C_IICLC_SDA_DELAY5 (1 << 0)
+#define S3C_IICLC_SDA_DELAY10 (2 << 0)
+#define S3C_IICLC_SDA_DELAY15 (3 << 0)
+#define S3C_IICLC_SDA_DELAY_MASK (3 << 0)
+
+#define S3C_IICLC_FILTER_ON (1<<2)
+
+/* IIC-bus serial interface */
+struct s3c24xx_i2c_state_s {
+ i2c_bus *bus;
+ qemu_irq irq;
+
+ uint8_t control;
+ uint8_t status;
+ uint8_t data;
+ uint8_t addy;
+ int busy;
+ int newstart;
+};
+
+static void s3c24xx_i2c_irq(struct s3c24xx_i2c_state_s *s)
+{
+ s->control |= 1 << 4;
+
+ if (s->control & (1 << 5)) {
+ qemu_irq_raise(s->irq);
+ }
+}
+
+static void s3c24xx_i2c_reset(struct s3c24xx_i2c_state_s *s)
+{
+ s->control = 0x00;
+ s->status = 0x00;
+ s->busy = 0;
+ s->newstart = 0;
+}
+
+
+static void s3c_master_work(void *opaque)
+{
+ struct s3c24xx_i2c_state_s *s = (struct s3c24xx_i2c_state_s *) opaque;
+ int start = 0, stop = 0, ack = 1;
+
+ if (s->control & (1 << 4)) /* Interrupt pending */
+ return;
+ if ((s->status & 0x90) != 0x90) /* Master */
+ return;
+
+ stop = ~s->status & (1 << 5);
+ if (s->newstart && s->status & (1 << 5)) { /* START */
+ s->busy = 1;
+ start = 1;
+ }
+ s->newstart = 0;
+
+ if (!s->busy) {
+ return;
+ }
+
+ if (start) {
+ ack = !i2c_start_transfer(s->bus, s->data >> 1, (~s->status >> 6) & 1);
+ } else if (stop) {
+ i2c_end_transfer(s->bus);
+ } else if (s->status & (1 << 6)) {
+ ack = !i2c_send(s->bus, s->data);
+ } else {
+ s->data = i2c_recv(s->bus);
+
+ if (!(s->control & (1 << 7))) /* ACK */
+ i2c_nack(s->bus);
+ }
+
+ if (!(s->status & (1 << 5))) {
+ s->busy = 0;
+ return;
+ }
+
+ s->status &= ~1;
+ s->status |= !ack;
+
+ if (!ack) {
+ s->busy = 0;
+ }
+ s3c24xx_i2c_irq(s);
+}
+
+static uint32_t s3c24xx_i2c_read(void *opaque, target_phys_addr_t addr)
+{
+ struct s3c24xx_i2c_state_s *s = (struct s3c24xx_i2c_state_s *) opaque;
+
+ switch (addr) {
+ case S3C_IICCON:
+ return s->control;
+
+ case S3C_IICSTAT:
+ return s->status & ~(1 << 5); /* Busy signal */
+
+ case S3C_IICADD:
+ return s->addy;
+
+ case S3C_IICDS:
+ return s->data;
+
+ default:
+ printf("%s: Bad register 0x%lx\n", __func__, addr);
+ break;
+ }
+ return 0;
+}
+
+static void s3c24xx_i2c_write(void *opaque, target_phys_addr_t addr,
+ uint32_t value)
+{
+ struct s3c24xx_i2c_state_s *s = (struct s3c24xx_i2c_state_s *) opaque;
+
+ switch (addr) {
+ case S3C_IICCON:
+ s->control = (s->control | 0xef) & value;
+ if (s->busy || ((s->control & (1<<4)) == 0))
+ s3c_master_work(s);
+ break;
+
+ case S3C_IICSTAT:
+ s->status &= 0x0f;
+ s->status |= value & 0xf0;
+ if (s->status & (1 << 5))
+ s->newstart = 1;
+ s3c_master_work(s);
+ break;
+
+ case S3C_IICADD:
+ s->addy = value & 0x7f;
+ break;
+
+ case S3C_IICDS:
+ s->data = value & 0xff;
+ s->busy = 1;
+ break;
+
+ default:
+ printf("%s: Bad register 0x%lx\n", __func__, addr);
+ break;
+ }
+}
+
+static CPUReadMemoryFunc *s3c24xx_i2c_readfn[] = {
+ s3c24xx_i2c_read,
+ s3c24xx_i2c_read,
+ s3c24xx_i2c_read,
+};
+
+static CPUWriteMemoryFunc *s3c24xx_i2c_writefn[] = {
+ s3c24xx_i2c_write,
+ s3c24xx_i2c_write,
+ s3c24xx_i2c_write,
+};
+
+static void s3c24xx_i2c_save(QEMUFile *f, void *opaque)
+{
+ struct s3c24xx_i2c_state_s *s = (struct s3c24xx_i2c_state_s *) opaque;
+ qemu_put_8s(f, &s->control);
+ qemu_put_8s(f, &s->status);
+ qemu_put_8s(f, &s->data);
+ qemu_put_8s(f, &s->addy);
+
+ qemu_put_be32(f, s->busy);
+ qemu_put_be32(f, s->newstart);
+
+}
+
+static int s3c24xx_i2c_load(QEMUFile *f, void *opaque, int version_id)
+{
+ struct s3c24xx_i2c_state_s *s = (struct s3c24xx_i2c_state_s *) opaque;
+ qemu_get_8s(f, &s->control);
+ qemu_get_8s(f, &s->status);
+ qemu_get_8s(f, &s->data);
+ qemu_get_8s(f, &s->addy);
+
+ s->busy = qemu_get_be32(f);
+ s->newstart = qemu_get_be32(f);
+
+ return 0;
+}
+
+
+struct s3c24xx_i2c_state_s *
+s3c24xx_iic_init(qemu_irq irq, target_phys_addr_t base_addr)
+{
+ int tag;
+ struct s3c24xx_i2c_state_s *s;
+
+ s = qemu_mallocz(sizeof(struct s3c24xx_i2c_state_s));
+
+ s->irq = irq;
+ s->bus = i2c_init_bus(NULL, "i2c");
+
+ s3c24xx_i2c_reset(s);
+
+ tag = cpu_register_io_memory(0, s3c24xx_i2c_readfn, s3c24xx_i2c_writefn, s);
+ cpu_register_physical_memory(base_addr, 0xffffff, tag);
+ register_savevm("s3c24xx_i2c", 0, 0, s3c24xx_i2c_save, s3c24xx_i2c_load, s);
+
+ return s;
+}
+
+i2c_bus *s3c24xx_i2c_bus(struct s3c24xx_i2c_state_s *s)
+{
+ return s->bus;
+}
--
1.6.0.4
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [Qemu-devel] [PATCH 11/16] Peripheral driver for S3C SOC LCD controller
2009-05-23 16:35 [Qemu-devel] Add ARM S3C SOC core, drivers and boards - v3 Vincent Sanders
` (9 preceding siblings ...)
2009-05-23 16:35 ` [Qemu-devel] [PATCH 10/16] Peripheral driver for S3C SOC I2C controller Vincent Sanders
@ 2009-05-23 16:35 ` Vincent Sanders
2009-05-23 16:35 ` [Qemu-devel] [PATCH 12/16] Peripheral driver for S3C SOC NAND controller Vincent Sanders
` (3 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: Vincent Sanders @ 2009-05-23 16:35 UTC (permalink / raw)
To: qemu-devel; +Cc: Vincent Sanders
Signed-off-by: Vincent Sanders <vince@simtec.co.uk>
---
Makefile.target | 1 +
hw/s3c2410x.c | 7 +
hw/s3c2440.c | 7 +
hw/s3c24xx.h | 7 +
hw/s3c24xx_lcd.c | 560 +++++++++++++++++++++++++++++++++++++++++++++++++
hw/s3c24xx_template.h | 266 +++++++++++++++++++++++
6 files changed, 848 insertions(+), 0 deletions(-)
create mode 100644 hw/s3c24xx_lcd.c
create mode 100644 hw/s3c24xx_template.h
diff --git a/Makefile.target b/Makefile.target
index c9af461..0d33486 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -650,6 +650,7 @@ OBJS+= mst_fpga.o mainstone.o
OBJS+= musicpal.o pflash_cfi02.o
OBJS+= s3c24xx_memc.o s3c24xx_irq.o s3c24xx_clkcon.o s3c24xx_timers.o
OBJS+= s3c24xx_serial.o s3c24xx_rtc.o s3c24xx_gpio.o s3c24xx_iic.o
+OBJS+= s3c24xx_lcd.o
OBJS+= s3c2410x.o s3c2440.o
OBJS+= framebuffer.o
OBJS+= syborg.o syborg_fb.o syborg_interrupt.o syborg_keyboard.o
diff --git a/hw/s3c2410x.c b/hw/s3c2410x.c
index f3057f8..42cd2a8 100644
--- a/hw/s3c2410x.c
+++ b/hw/s3c2410x.c
@@ -32,6 +32,9 @@
/* Clock control */
#define CPU_S3C2410X_CLKCON_BASE (CPU_S3C2410X_PERIPHERAL + 0xC000000)
+/* LCD controller */
+#define CPU_S3C2410X_LCD_BASE (CPU_S3C2410X_PERIPHERAL + 0xD000000)
+
/* serial port bases */
#define CPU_S3C2410X_SERIAL0_BASE (CPU_S3C2410X_PERIPHERAL + 0x10000000)
#define CPU_S3C2410X_SERIAL1_BASE (CPU_S3C2410X_PERIPHERAL + 0x10004000)
@@ -97,5 +100,9 @@ s3c2410x_init(int sdram_size)
s->iic = s3c24xx_iic_init(s3c24xx_get_irq(s->irq, 27),
CPU_S3C2410X_IIC_BASE);
+ /* LCD controller */
+ s->lcd = s3c24xx_lcd_init(CPU_S3C2410X_LCD_BASE,
+ s3c24xx_get_irq(s->irq, 16));
+
return s;
}
diff --git a/hw/s3c2440.c b/hw/s3c2440.c
index f8d6f63..3d32c03 100644
--- a/hw/s3c2440.c
+++ b/hw/s3c2440.c
@@ -31,6 +31,9 @@
/* Clock control */
#define CPU_S3C2440_CLKCON_BASE (CPU_S3C2440_PERIPHERAL + 0xC000000)
+/* LCD controller */
+#define CPU_S3C2440_LCD_BASE (CPU_S3C2440_PERIPHERAL + 0xD000000)
+
/* serial port bases */
#define CPU_S3C2440_SERIAL0_BASE (CPU_S3C2440_PERIPHERAL + 0x10000000)
#define CPU_S3C2440_SERIAL1_BASE (CPU_S3C2440_PERIPHERAL + 0x10004000)
@@ -94,5 +97,9 @@ s3c2440_init(int sdram_size)
s->iic = s3c24xx_iic_init(s3c24xx_get_irq(s->irq, 27),
CPU_S3C2440_IIC_BASE);
+ /* LCD controller */
+ s->lcd = s3c24xx_lcd_init(CPU_S3C2440_LCD_BASE,
+ s3c24xx_get_irq(s->irq, 16));
+
return s;
}
diff --git a/hw/s3c24xx.h b/hw/s3c24xx.h
index bb52c00..2fdc3e8 100644
--- a/hw/s3c24xx.h
+++ b/hw/s3c24xx.h
@@ -38,6 +38,10 @@ typedef struct S3CState_s {
/* I2C */
struct s3c24xx_i2c_state_s *iic;
+
+ /* LCD controller state */
+ struct s3c24xx_lcd_state_s *lcd;
+
} S3CState;
@@ -74,4 +78,7 @@ struct s3c24xx_i2c_state_s *s3c24xx_iic_init(qemu_irq irq, target_phys_addr_t ba
/* aquire bus from controller state */
i2c_bus *s3c24xx_i2c_bus(struct s3c24xx_i2c_state_s *s);
+/* Initialise LCD controller */
+struct s3c24xx_lcd_state_s *s3c24xx_lcd_init(target_phys_addr_t base, qemu_irq irq);
+
#endif /* S3C24XX_H */
diff --git a/hw/s3c24xx_lcd.c b/hw/s3c24xx_lcd.c
new file mode 100644
index 0000000..bb74531
--- /dev/null
+++ b/hw/s3c24xx_lcd.c
@@ -0,0 +1,560 @@
+/*
+ * Samsung S3C24xx series LCD controller.
+ *
+ * Copyright (c) 2007 OpenMoko, Inc.
+ * Author: Andrzej Zaborowski <andrew@openedhand.com>
+ *
+ * This code is licenced under the GNU GPL v2.
+ */
+
+#include "hw.h"
+#include "console.h"
+#include "framebuffer.h"
+
+#include "s3c24xx.h"
+
+struct s3c24xx_lcd_state_s {
+ target_phys_addr_t base;
+ void *irq;
+ DisplayState *ds;
+ drawfn *line_fn;
+
+ uint32_t con[5];
+ uint32_t saddr[3];
+ uint32_t r;
+ uint32_t g;
+ uint16_t b;
+ uint32_t dithmode;
+ uint32_t tpal;
+ uint8_t intpnd;
+ uint8_t srcpnd;
+ uint8_t intmsk;
+ uint8_t lpcsel;
+
+ uint16_t raw_pal[0x100];
+
+ int width;
+ int height;
+ int bpp;
+ int enable;
+ int msb;
+ int frm565;
+ target_phys_addr_t fb;
+ uint32_t palette[0x100];
+ int invalidate;
+ int invalidatep;
+ int src_width;
+ int dest_width;
+ drawfn fn;
+};
+
+static void s3c24xx_lcd_update(struct s3c24xx_lcd_state_s *s)
+{
+ s->intpnd |= s->srcpnd & ~s->intmsk;
+ qemu_set_irq(s->irq, !!s->intpnd);
+}
+
+static void s3c24xx_lcd_reset(struct s3c24xx_lcd_state_s *s)
+{
+ s->enable = 0;
+ s->invalidate = 1;
+ s->invalidatep = 1;
+ s->width = -1;
+ s->height = -1;
+
+ s->con[0] = 0x00000000;
+ s->con[1] = 0x00000000;
+ s->con[2] = 0x00000000;
+ s->con[3] = 0x00000000;
+ s->con[4] = 0x00000000;
+ s->saddr[0] = 0x00000000;
+ s->saddr[1] = 0x00000000;
+ s->saddr[2] = 0x00000000;
+ s->r = 0x00000000;
+ s->g = 0x00000000;
+ s->b = 0x0000;
+ s->dithmode = 0x00000;
+ s->tpal = 0x00000000;
+ s->intpnd = 0;
+ s->srcpnd = 0;
+ s->intmsk = 3;
+ s->lpcsel = 4;
+ s3c24xx_lcd_update(s);
+}
+
+#define S3C24XX_LCDCON1 0x00 /* LCD Control register 1 */
+#define S3C24XX_LCDCON2 0x04 /* LCD Control register 2 */
+#define S3C24XX_LCDCON3 0x08 /* LCD Control register 3 */
+#define S3C24XX_LCDCON4 0x0c /* LCD Control register 4 */
+#define S3C24XX_LCDCON5 0x10 /* LCD Control register 5 */
+#define S3C24XX_LCDSADDR1 0x14 /* Framebuffer Start Address 1 register */
+#define S3C24XX_LCDSADDR2 0x18 /* Framebuffer Start Address 2 register */
+#define S3C24XX_LCDSADDR3 0x1c /* Framebuffer Start Address 3 register */
+#define S3C24XX_REDLUT 0x20 /* Red Lookup Table register */
+#define S3C24XX_GREENLUT 0x24 /* Green Lookup Table register */
+#define S3C24XX_BLUELUT 0x28 /* Blue Lookup Table register */
+#define S3C24XX_DITHMODE 0x4c /* Dithering Mode register */
+#define S3C24XX_TPAL 0x50 /* Temporary Palette register */
+#define S3C24XX_LCDINTPND 0x54 /* LCD Interrupt Pending register */
+#define S3C24XX_LCDSRCPND 0x58 /* LCD Interrupt Source Pending register */
+#define S3C24XX_LCDINTMSK 0x5c /* LCD Interrupt Mask register */
+#define S3C24XX_LPCSEL 0x60 /* LPC3600 Control register */
+
+#define S3C24XX_PALETTE 0x400 /* Palette IO start offset */
+#define S3C24XX_PALETTEEND 0x7fc /* Palette IO end offset */
+
+static uint32_t s3c24xx_lcd_read(void *opaque, target_phys_addr_t addr)
+{
+ struct s3c24xx_lcd_state_s *s = (struct s3c24xx_lcd_state_s *) opaque;
+
+ switch (addr) {
+ case S3C24XX_LCDCON1:
+ return s->con[0]; /* XXX Return random LINECNT? */
+ case S3C24XX_LCDCON2:
+ return s->con[1];
+ case S3C24XX_LCDCON3:
+ return s->con[2];
+ case S3C24XX_LCDCON4:
+ return s->con[3];
+ case S3C24XX_LCDCON5:
+ return s->con[4]; /* XXX Return random STATUS? */
+ case S3C24XX_LCDSADDR1:
+ return s->saddr[0];
+ case S3C24XX_LCDSADDR2:
+ return s->saddr[1];
+ case S3C24XX_LCDSADDR3:
+ return s->saddr[2];
+ case S3C24XX_REDLUT:
+ return s->r;
+ case S3C24XX_GREENLUT:
+ return s->g;
+ case S3C24XX_BLUELUT:
+ return s->b;
+ case S3C24XX_DITHMODE:
+ return s->dithmode;
+ case S3C24XX_TPAL:
+ return s->tpal;
+ case S3C24XX_LCDINTPND:
+ return s->intpnd;
+ case S3C24XX_LCDSRCPND:
+ return s->srcpnd;
+ case S3C24XX_LCDINTMSK:
+ return s->intmsk;
+ case S3C24XX_LPCSEL:
+ return s->lpcsel;
+ case S3C24XX_PALETTE ... S3C24XX_PALETTEEND:
+ /* XXX assuming 16bit access */
+ return s->raw_pal[(addr - S3C24XX_PALETTE) >> 2];
+ default:
+ printf("%s: Bad register 0x%lx\n", __FUNCTION__, addr);
+ break;
+ }
+ return 0;
+}
+
+static void s3c24xx_lcd_write(void *opaque, target_phys_addr_t addr,
+ uint32_t value)
+{
+ struct s3c24xx_lcd_state_s *s = (struct s3c24xx_lcd_state_s *) opaque;
+
+ switch (addr) {
+ case S3C24XX_LCDCON1:
+ s->con[0] = value & 0x0003ffff;
+ s->enable = value & 1;
+ s->bpp = (value >> 1) & 0xf;
+ s->invalidate = 1;
+ s->invalidatep = 1;
+ break;
+ case S3C24XX_LCDCON2:
+ s->con[1] = value;
+ s->invalidate = 1;
+ break;
+ case S3C24XX_LCDCON3:
+ s->con[2] = value;
+ s->invalidate = 1;
+ break;
+ case S3C24XX_LCDCON4:
+ s->con[3] = value & 0xffff;
+ break;
+ case S3C24XX_LCDCON5:
+ s->con[4] = value & 0x1fff;
+ s->frm565 = (value >> 11) & 1;
+ s->msb = (value >> 12) & 1;
+ s->invalidatep = 1;
+ s->invalidate = 1;
+ break;
+ case S3C24XX_LCDSADDR1:
+ s->saddr[0] = value;
+ s->fb = ((s->saddr[0] << 1) & 0x7ffffffe);
+ s->invalidate = 1;
+ break;
+ case S3C24XX_LCDSADDR2:
+ s->saddr[1] = value;
+ s->invalidate = 1;
+ break;
+ case S3C24XX_LCDSADDR3:
+ s->saddr[2] = value;
+ s->invalidate = 1;
+ break;
+ case S3C24XX_REDLUT:
+ s->r = value;
+ s->invalidatep = 1;
+ s->invalidate = 1;
+ break;
+ case S3C24XX_GREENLUT:
+ s->g = value;
+ s->invalidatep = 1;
+ s->invalidate = 1;
+ break;
+ case S3C24XX_BLUELUT:
+ s->b = value;
+ s->invalidatep = 1;
+ s->invalidate = 1;
+ break;
+ case S3C24XX_DITHMODE:
+ s->dithmode = value;
+ break;
+ case S3C24XX_TPAL:
+ s->tpal = value;
+ s->invalidatep = 1;
+ s->invalidate = 1;
+ break;
+ case S3C24XX_LCDINTPND:
+ s->intpnd = value & 3;
+ break;
+ case S3C24XX_LCDSRCPND:
+ s->srcpnd = value & 3;
+ break;
+ case S3C24XX_LCDINTMSK:
+ s->intmsk = value & 7;
+ s3c24xx_lcd_update(s);
+ break;
+ case S3C24XX_LPCSEL:
+ s->lpcsel = (value & 3) | 4;
+ if (value & 1)
+ printf("%s: attempt to enable LPC3600\n", __FUNCTION__);
+ break;
+ case S3C24XX_PALETTE ... S3C24XX_PALETTEEND:
+ /* XXX assuming 16bit access */
+ s->raw_pal[(addr - S3C24XX_PALETTE) >> 2] = value;
+ break;
+ default:
+ printf("%s: Bad register 0x%lx\n", __FUNCTION__, addr);
+ }
+}
+
+static CPUReadMemoryFunc *s3c24xx_lcd_readfn[] = {
+ s3c24xx_lcd_read,
+ s3c24xx_lcd_read,
+ s3c24xx_lcd_read,
+};
+
+static CPUWriteMemoryFunc *s3c24xx_lcd_writefn[] = {
+ s3c24xx_lcd_write,
+ s3c24xx_lcd_write,
+ s3c24xx_lcd_write,
+};
+
+static inline void s3c24xx_lcd_resize(struct s3c24xx_lcd_state_s *s)
+{
+ int new_width, new_height;
+ new_height = ((s->con[1] >> 14) & 0x3ff) + 1;
+ new_width = ((s->con[2] >> 8) & 0x7ff) + 1;
+ if (s->width != new_width || s->height != new_height) {
+ s->width = new_width;
+ s->height = new_height;
+ qemu_console_resize(s->ds, s->width, s->height);
+ s->invalidate = 1;
+ }
+}
+
+static inline
+uint32_t s3c24xx_rgb_to_pixel8(unsigned int r, unsigned int g, unsigned b)
+{
+ return ((r >> 5) << 5) | ((g >> 5) << 2) | (b >> 6);
+}
+
+static inline
+uint32_t s3c24xx_rgb_to_pixel15(unsigned int r, unsigned int g, unsigned b)
+{
+ return ((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3);
+}
+
+static inline
+uint32_t s3c24xx_rgb_to_pixel16(unsigned int r, unsigned int g, unsigned b)
+{
+ return ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
+}
+
+static inline
+uint32_t s3c24xx_rgb_to_pixel24(unsigned int r, unsigned int g, unsigned b)
+{
+ return (r << 16) | (g << 8) | b;
+}
+
+static inline
+uint32_t s3c24xx_rgb_to_pixel32(unsigned int r, unsigned int g, unsigned b)
+{
+ return (r << 16) | (g << 8) | b;
+}
+
+static inline uint32_t s3c24xx_rgb(struct s3c24xx_lcd_state_s *s,
+ unsigned int r, unsigned int g, unsigned b)
+{
+ switch (ds_get_bits_per_pixel(s->ds)) {
+ case 8:
+ return s3c24xx_rgb_to_pixel32(r << 2, g << 2, b << 2);
+ case 15:
+ return s3c24xx_rgb_to_pixel15(r << 2, g << 2, b << 2);
+ case 16:
+ return s3c24xx_rgb_to_pixel16(r << 2, g << 2, b << 2);
+ case 24:
+ return s3c24xx_rgb_to_pixel24(r << 2, g << 2, b << 2);
+ case 32:
+ return s3c24xx_rgb_to_pixel32(r << 2, g << 2, b << 2);
+ default:
+ fprintf(stderr, "%s: Bad color depth\n", __FUNCTION__);
+ exit(1);
+ }
+}
+
+static void s3c24xx_lcd_palette_load(struct s3c24xx_lcd_state_s *s)
+{
+ int i, n;
+ switch (s->bpp) {
+ case 0:
+ case 8:
+ n = 2;
+ s->src_width = s->width >> 3;
+ s->fn = s->line_fn[0];
+ break;
+ case 1:
+ case 9:
+ n = 4;
+ s->src_width = s->width >> 2;
+ s->fn = s->line_fn[1];
+ break;
+ case 2:
+ case 10:
+ n = 16;
+ s->src_width = s->width >> 1;
+ s->fn = s->line_fn[2];
+ break;
+ case 3:
+ case 11:
+ n = 256;
+ s->src_width = s->width >> 0;
+ s->fn = s->line_fn[3];
+ break;
+ case 6:
+ s->src_width = (s->width * 3) >> 1;
+ s->fn = s->line_fn[4];
+ return;
+ case 12:
+ s->src_width = s->width << 1;
+ if (s->frm565)
+ s->fn = s->line_fn[5];
+ else
+ s->fn = s->line_fn[6];
+ return;
+ case 13:
+ s->src_width = s->width << 2;
+ s->fn = s->line_fn[7];
+ return;
+ default:
+ return;
+ }
+ if (s->bpp & 8) {
+ for (i = 0; i < n; i ++)
+ if (s->frm565)
+ s->palette[i] = s3c24xx_rgb(s,
+ (s->raw_pal[i] >> 10) & 0x3e,
+ (s->raw_pal[i] >> 5) & 0x3f,
+ (s->raw_pal[i] << 1) & 0x3e);
+ else
+ s->palette[i] = s3c24xx_rgb(s,
+ ((s->raw_pal[i] >> 10) & 0x3e) | (s->raw_pal[i] & 1),
+ ((s->raw_pal[i] >> 6) & 0x3e) | (s->raw_pal[i] & 1),
+ s->raw_pal[i] & 0x3f);
+ } else {
+ for (i = 0; i < n; i ++)
+ if (n < 256)
+ s->palette[i] = s3c24xx_rgb(s,
+ ((s->r >> (i * 4)) & 0xf) << 2,
+ ((s->g >> (i * 4)) & 0xf) << 2,
+ ((s->b >> (i * 4)) & 0xf) << 2);
+ else
+ s->palette[i] = s3c24xx_rgb(s,
+ ((s->r >> (((i >> 5) & 7) * 4)) & 0xf) << 2,
+ ((s->g >> (((i >> 2) & 7) * 4)) & 0xf) << 2,
+ ((s->b >> ((i & 3) * 4)) & 0xf) << 2);
+ }
+}
+
+static void s3c24xx_update_display(void *opaque)
+{
+ struct s3c24xx_lcd_state_s *s = (struct s3c24xx_lcd_state_s *) opaque;
+ int src_width, dest_width, miny = 0, maxy = 0;
+ target_phys_addr_t addr;
+
+ addr = s->fb;
+
+ if (!s->enable || !s->dest_width)
+ return;
+
+ s3c24xx_lcd_resize(s);
+
+ if (s->invalidatep) {
+ s3c24xx_lcd_palette_load(s);
+ s->invalidatep = 0;
+ }
+
+ src_width = s->src_width;
+ dest_width = s->width * s->dest_width;
+
+ framebuffer_update_display(s->ds,
+ addr, s->width, s->height,
+ src_width, dest_width, s->dest_width,
+ s->invalidate,
+ s->fn, s->palette, &miny, &maxy);
+
+
+ s->srcpnd |= (1 << 1); /* INT_FrSyn */
+ s3c24xx_lcd_update(s);
+ dpy_update(s->ds, 0, miny, s->width, maxy);
+}
+
+static void s3c24xx_invalidate_display(void *opaque)
+{
+ struct s3c24xx_lcd_state_s *s = (struct s3c24xx_lcd_state_s *) opaque;
+ s->invalidate = 1;
+}
+
+static void s3c24xx_screen_dump(void *opaque, const char *filename)
+{
+ /* TODO */
+}
+
+#define BITS 8
+#include "s3c24xx_template.h"
+#define BITS 15
+#include "s3c24xx_template.h"
+#define BITS 16
+#include "s3c24xx_template.h"
+#define BITS 24
+#include "s3c24xx_template.h"
+#define BITS 32
+#include "s3c24xx_template.h"
+
+static void s3c24xx_lcd_save(QEMUFile *f, void *opaque)
+{
+ struct s3c24xx_lcd_state_s *s = (struct s3c24xx_lcd_state_s *) opaque;
+ int i;
+ for (i = 0; i < 5; i ++)
+ qemu_put_be32s(f, &s->con[i]);
+ for (i = 0; i < 3; i ++)
+ qemu_put_be32s(f, &s->saddr[i]);
+ qemu_put_be32s(f, &s->r);
+ qemu_put_be32s(f, &s->g);
+ qemu_put_be16s(f, &s->b);
+ qemu_put_be32s(f, &s->dithmode);
+ qemu_put_be32s(f, &s->tpal);
+ qemu_put_8s(f, &s->intpnd);
+ qemu_put_8s(f, &s->srcpnd);
+ qemu_put_8s(f, &s->intmsk);
+ qemu_put_8s(f, &s->lpcsel);
+ for (i = 0; i < 0x100; i ++)
+ qemu_put_be16s(f, &s->raw_pal[i]);
+}
+
+static int s3c24xx_lcd_load(QEMUFile *f, void *opaque, int version_id)
+{
+ struct s3c24xx_lcd_state_s *s = (struct s3c24xx_lcd_state_s *) opaque;
+ int i;
+ for (i = 0; i < 5; i ++)
+ qemu_get_be32s(f, &s->con[i]);
+ for (i = 0; i < 3; i ++)
+ qemu_get_be32s(f, &s->saddr[i]);
+ qemu_get_be32s(f, &s->r);
+ qemu_get_be32s(f, &s->g);
+ qemu_get_be16s(f, &s->b);
+ qemu_get_be32s(f, &s->dithmode);
+ qemu_get_be32s(f, &s->tpal);
+ qemu_get_8s(f, &s->intpnd);
+ qemu_get_8s(f, &s->srcpnd);
+ qemu_get_8s(f, &s->intmsk);
+ qemu_get_8s(f, &s->lpcsel);
+
+ s->invalidate = 1;
+ s->invalidatep = 1;
+ s->width = -1;
+ s->height = -1;
+ s->bpp = (s->con[0] >> 1) & 0xf;
+ s->enable = s->con[0] & 1;
+ s->msb = (s->con[4] >> 12) & 1;
+ s->frm565 = (s->con[4] >> 11) & 1;
+ s->fb = ((s->saddr[0] << 1) & 0x7ffffffe);
+
+ for (i = 0; i < 0x100; i ++)
+ qemu_get_be16s(f, &s->raw_pal[i]);
+
+ return 0;
+}
+
+struct s3c24xx_lcd_state_s *s3c24xx_lcd_init(target_phys_addr_t base, qemu_irq irq)
+{
+ int iomemtype;
+ struct s3c24xx_lcd_state_s *s = (struct s3c24xx_lcd_state_s *)
+ qemu_mallocz(sizeof(struct s3c24xx_lcd_state_s));
+
+ s->base = base;
+ s->irq = irq;
+
+ s3c24xx_lcd_reset(s);
+
+ s->ds = graphic_console_init(s3c24xx_update_display,
+ s3c24xx_invalidate_display,
+ s3c24xx_screen_dump, NULL, s);
+
+ iomemtype = cpu_register_io_memory(0, s3c24xx_lcd_readfn,
+ s3c24xx_lcd_writefn, s);
+ cpu_register_physical_memory(s->base, 0xffffff, iomemtype);
+
+ register_savevm("s3c24xx_lcd", 0, 0, s3c24xx_lcd_save, s3c24xx_lcd_load, s);
+
+ switch (ds_get_bits_per_pixel(s->ds)) {
+ case 0:
+ s->dest_width = 0;
+ break;
+
+ case 8:
+ s->line_fn = s3c24xx_draw_fn_8;
+ s->dest_width = 1;
+ break;
+
+ case 15:
+ s->line_fn = s3c24xx_draw_fn_15;
+ s->dest_width = 2;
+ break;
+
+ case 16:
+ s->line_fn = s3c24xx_draw_fn_16;
+ s->dest_width = 2;
+ break;
+
+ case 24:
+ s->line_fn = s3c24xx_draw_fn_24;
+ s->dest_width = 3;
+ break;
+
+ case 32:
+ s->line_fn = s3c24xx_draw_fn_32;
+ s->dest_width = 4;
+ break;
+
+ default:
+ fprintf(stderr, "%s: Bad color depth\n", __FUNCTION__);
+ exit(1);
+ }
+ return s;
+}
diff --git a/hw/s3c24xx_template.h b/hw/s3c24xx_template.h
new file mode 100644
index 0000000..f6cbf44
--- /dev/null
+++ b/hw/s3c24xx_template.h
@@ -0,0 +1,266 @@
+/*
+ * Samsung S3C2410A LCD controller emulation.
+ *
+ * Copyright (c) 2007 OpenMoko, Inc.
+ * Author: Andrzej Zaborowski <andrew@openedhand.com>
+ *
+ * This code is licensed under the GNU GPL v2.
+ *
+ * Framebuffer format conversion routines.
+ */
+
+# define SKIP_PIXEL(to) to += deststep
+#if BITS == 8
+# define COPY_PIXEL(to, from) *to = from; SKIP_PIXEL(to)
+#elif BITS == 15 || BITS == 16
+# define COPY_PIXEL(to, from) *(uint16_t *) to = from; SKIP_PIXEL(to)
+#elif BITS == 24
+# define COPY_PIXEL(to, from) \
+ *(uint16_t *) to = from; *(to + 2) = (from) >> 16; SKIP_PIXEL(to)
+#elif BITS == 32
+# define COPY_PIXEL(to, from) *(uint32_t *) to = from; SKIP_PIXEL(to)
+#else
+# error unknown bit depth
+#endif
+
+#ifdef WORDS_BIGENDIAN
+# define SWAP_WORDS 1
+#endif
+
+#define FN_2(x) FN(x + 1) FN(x)
+#define FN_4(x) FN_2(x + 2) FN_2(x)
+#define FN_8(x) FN_4(x + 4) FN_4(x)
+
+static void glue(s3c24xx_draw_line1_, BITS)(void *opaque,
+ uint8_t *dest, const uint8_t *src, int width, int deststep)
+{
+ uint32_t *palette = opaque;
+ uint32_t data;
+ while (width > 0) {
+ data = *(uint32_t *) src;
+#define FN(x) COPY_PIXEL(dest, palette[(data >> (x)) & 1]);
+#ifdef SWAP_WORDS
+ FN_8(24)
+ FN_8(16)
+ FN_8(8)
+ FN_8(0)
+#else
+ FN_8(0)
+ FN_8(8)
+ FN_8(16)
+ FN_8(24)
+#endif
+#undef FN
+ width -= 32;
+ src += 4;
+ }
+}
+
+static void glue(s3c24xx_draw_line2_, BITS)(void *opaque,
+ uint8_t *dest, const uint8_t *src, int width, int deststep)
+{
+ uint32_t *palette = opaque;
+ uint32_t data;
+ while (width > 0) {
+ data = *(uint32_t *) src;
+#define FN(x) COPY_PIXEL(dest, palette[(data >> ((x) * 2)) & 3]);
+#ifdef SWAP_WORDS
+ FN_4(12)
+ FN_4(8)
+ FN_4(4)
+ FN_4(0)
+#else
+ FN_4(0)
+ FN_4(4)
+ FN_4(8)
+ FN_4(12)
+#endif
+#undef FN
+ width -= 16;
+ src += 4;
+ }
+}
+
+static void glue(s3c24xx_draw_line4_, BITS)(void *opaque,
+ uint8_t *dest, const uint8_t *src, int width, int deststep)
+{
+ uint32_t *palette = opaque;
+ uint32_t data;
+ while (width > 0) {
+ data = *(uint32_t *) src;
+#define FN(x) COPY_PIXEL(dest, palette[(data >> ((x) * 4)) & 0xf]);
+#ifdef SWAP_WORDS
+ FN_2(6)
+ FN_2(4)
+ FN_2(2)
+ FN_2(0)
+#else
+ FN_2(0)
+ FN_2(2)
+ FN_2(4)
+ FN_2(6)
+#endif
+#undef FN
+ width -= 8;
+ src += 4;
+ }
+}
+
+static void glue(s3c24xx_draw_line8_, BITS)(void *opaque,
+ uint8_t *dest, const uint8_t *src, int width, int deststep)
+{
+ uint32_t *palette = opaque;
+ uint32_t data;
+ while (width > 0) {
+ data = *(uint32_t *) src;
+#define FN(x) COPY_PIXEL(dest, palette[(data >> (x)) & 0xff]);
+#ifdef SWAP_WORDS
+ FN(24)
+ FN(16)
+ FN(8)
+ FN(0)
+#else
+ FN(0)
+ FN(8)
+ FN(16)
+ FN(24)
+#endif
+#undef FN
+ width -= 4;
+ src += 4;
+ }
+}
+
+static void glue(s3c24xx_draw_line16a_, BITS)(void *opaque,
+ uint8_t *dest, const uint8_t *src, int width, int deststep)
+{
+ uint32_t data;
+ unsigned int r, g, b;
+ while (width > 0) {
+ data = *(uint32_t *) src;
+#ifdef SWAP_WORDS
+ data = bswap32(data);
+#endif
+ b = (data & 0x1f) << 3;
+ data >>= 5;
+ g = (data & 0x3f) << 2;
+ data >>= 6;
+ r = (data & 0x1f) << 3;
+ data >>= 5;
+ COPY_PIXEL(dest, glue(s3c24xx_rgb_to_pixel, BITS)(r, g, b));
+ b = (data & 0x1f) << 3;
+ data >>= 5;
+ g = (data & 0x3f) << 2;
+ data >>= 6;
+ r = (data & 0x1f) << 3;
+ COPY_PIXEL(dest, glue(s3c24xx_rgb_to_pixel, BITS)(r, g, b));
+ width -= 2;
+ src += 4;
+ }
+}
+
+static void glue(s3c24xx_draw_line16b_, BITS)(void *opaque,
+ uint8_t *dest, const uint8_t *src, int width, int deststep)
+{
+ uint32_t data;
+ unsigned int r, g, b;
+ while (width > 0) {
+ data = *(uint32_t *) src;
+#ifdef SWAP_WORDS
+ data = bswap32(data);
+#endif
+ b = (data & 0x1f) << 3;
+ data >>= 5;
+ g = (data & 0x1f) << 3;
+ data >>= 5;
+ r = (data & 0x3f) << 2;
+ data >>= 5;
+ COPY_PIXEL(dest, glue(s3c24xx_rgb_to_pixel, BITS)(r, g, b));
+ b = (data & 0x1f) << 3;
+ data >>= 5;
+ g = (data & 0x1f) << 3;
+ data >>= 5;
+ r = (data & 0x3f) << 2;
+ COPY_PIXEL(dest, glue(s3c24xx_rgb_to_pixel, BITS)(r, g, b));
+ width -= 2;
+ src += 4;
+ }
+}
+
+static void glue(s3c24xx_draw_line12_, BITS)(void *opaque,
+ uint8_t *dest, const uint8_t *src, int width, int deststep)
+{
+ uint32_t data;
+ unsigned int r, g, b;
+ while (width > 0) {
+ data = *(uint32_t *) src;
+ src += 3;
+#ifdef SWAP_WORDS
+ data = bswap32(data);
+#endif
+ /* XXX should use (x & 0xf) << 4) | (x & 0xf) for natural
+ * colours. Otherwise the image may be a bit darkened. */
+ b = (data & 0xf00) >> 4;
+ g = (data & 0xf0) << 0;
+ r = (data & 0xf) << 4;
+ data >>= 12;
+ COPY_PIXEL(dest, glue(s3c24xx_rgb_to_pixel, BITS)(r, g, b));
+ b = (data & 0xf00) >> 4;
+ g = (data & 0xf0) << 0;
+ r = (data & 0xf) << 4;
+ data >>= 12;
+ COPY_PIXEL(dest, glue(s3c24xx_rgb_to_pixel, BITS)(r, g, b));
+ b = (data & 0xf00) >> 4;
+ g = (data & 0xf0) << 0;
+ r = (data & 0xf) << 4;
+ data >>= 12;
+ COPY_PIXEL(dest, glue(s3c24xx_rgb_to_pixel, BITS)(r, g, b));
+ b = (data & 0xf00) >> 4;
+ g = (data & 0xf0) << 0;
+ r = (data & 0xf) << 4;
+ data >>= 12;
+ COPY_PIXEL(dest, glue(s3c24xx_rgb_to_pixel, BITS)(r, g, b));
+ width -= 4;
+ }
+}
+
+static void glue(s3c24xx_draw_line24_, BITS)(void *opaque,
+ uint8_t *dest, const uint8_t *src, int width, int deststep)
+{
+ uint32_t data;
+ unsigned int r, g, b;
+ while (width > 0) {
+ data = *(uint32_t *) src;
+#ifdef SWAP_WORDS
+ data = bswap32(data);
+#endif
+ b = data & 0xff;
+ data >>= 8;
+ g = data & 0xff;
+ data >>= 8;
+ r = data & 0xff;
+ COPY_PIXEL(dest, glue(s3c24xx_rgb_to_pixel, BITS)(r, g, b));
+ width -= 1;
+ src += 4;
+ }
+}
+
+static drawfn glue(s3c24xx_draw_fn_, BITS)[] =
+{
+ glue(s3c24xx_draw_line1_, BITS),
+ glue(s3c24xx_draw_line2_, BITS),
+ glue(s3c24xx_draw_line4_, BITS),
+ glue(s3c24xx_draw_line8_, BITS),
+ glue(s3c24xx_draw_line12_, BITS),
+ glue(s3c24xx_draw_line16a_, BITS),
+ glue(s3c24xx_draw_line16b_, BITS),
+ glue(s3c24xx_draw_line24_, BITS),
+};
+
+#undef BITS
+#undef COPY_PIXEL
+#undef SKIP_PIXEL
+
+#ifdef SWAP_WORDS
+# undef SWAP_WORDS
+#endif
--
1.6.0.4
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [Qemu-devel] [PATCH 12/16] Peripheral driver for S3C SOC NAND controller
2009-05-23 16:35 [Qemu-devel] Add ARM S3C SOC core, drivers and boards - v3 Vincent Sanders
` (10 preceding siblings ...)
2009-05-23 16:35 ` [Qemu-devel] [PATCH 11/16] Peripheral driver for S3C SOC LCD controller Vincent Sanders
@ 2009-05-23 16:35 ` Vincent Sanders
2009-05-23 16:35 ` [Qemu-devel] [PATCH 13/16] Peripheral driver for S3C OHCI controller Vincent Sanders
` (2 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: Vincent Sanders @ 2009-05-23 16:35 UTC (permalink / raw)
To: qemu-devel; +Cc: Vincent Sanders
Signed-off-by: Vincent Sanders <vince@simtec.co.uk>
---
Makefile.target | 2 +-
hw/s3c2410x.c | 6 ++
hw/s3c2440.c | 6 ++
hw/s3c24xx.h | 10 ++++
hw/s3c24xx_nand.c | 147 +++++++++++++++++++++++++++++++++++++++++++++++++++++
5 files changed, 170 insertions(+), 1 deletions(-)
create mode 100644 hw/s3c24xx_nand.c
diff --git a/Makefile.target b/Makefile.target
index 0d33486..535b4a2 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -650,7 +650,7 @@ OBJS+= mst_fpga.o mainstone.o
OBJS+= musicpal.o pflash_cfi02.o
OBJS+= s3c24xx_memc.o s3c24xx_irq.o s3c24xx_clkcon.o s3c24xx_timers.o
OBJS+= s3c24xx_serial.o s3c24xx_rtc.o s3c24xx_gpio.o s3c24xx_iic.o
-OBJS+= s3c24xx_lcd.o
+OBJS+= s3c24xx_lcd.o s3c24xx_nand.o
OBJS+= s3c2410x.o s3c2440.o
OBJS+= framebuffer.o
OBJS+= syborg.o syborg_fb.o syborg_interrupt.o syborg_keyboard.o
diff --git a/hw/s3c2410x.c b/hw/s3c2410x.c
index 42cd2a8..78b9ee0 100644
--- a/hw/s3c2410x.c
+++ b/hw/s3c2410x.c
@@ -35,6 +35,9 @@
/* LCD controller */
#define CPU_S3C2410X_LCD_BASE (CPU_S3C2410X_PERIPHERAL + 0xD000000)
+/* NAND */
+#define CPU_S3C2410X_NAND_BASE (CPU_S3C2410X_PERIPHERAL + 0xE000000)
+
/* serial port bases */
#define CPU_S3C2410X_SERIAL0_BASE (CPU_S3C2410X_PERIPHERAL + 0x10000000)
#define CPU_S3C2410X_SERIAL1_BASE (CPU_S3C2410X_PERIPHERAL + 0x10004000)
@@ -104,5 +107,8 @@ s3c2410x_init(int sdram_size)
s->lcd = s3c24xx_lcd_init(CPU_S3C2410X_LCD_BASE,
s3c24xx_get_irq(s->irq, 16));
+ /* NAND controller */
+ s->nand = s3c24xx_nand_init(CPU_S3C2410X_NAND_BASE);
+
return s;
}
diff --git a/hw/s3c2440.c b/hw/s3c2440.c
index 3d32c03..fdb107b 100644
--- a/hw/s3c2440.c
+++ b/hw/s3c2440.c
@@ -34,6 +34,9 @@
/* LCD controller */
#define CPU_S3C2440_LCD_BASE (CPU_S3C2440_PERIPHERAL + 0xD000000)
+/* NAND */
+#define CPU_S3C2440_NAND_BASE (CPU_S3C2440_PERIPHERAL + 0xE000000)
+
/* serial port bases */
#define CPU_S3C2440_SERIAL0_BASE (CPU_S3C2440_PERIPHERAL + 0x10000000)
#define CPU_S3C2440_SERIAL1_BASE (CPU_S3C2440_PERIPHERAL + 0x10004000)
@@ -101,5 +104,8 @@ s3c2440_init(int sdram_size)
s->lcd = s3c24xx_lcd_init(CPU_S3C2440_LCD_BASE,
s3c24xx_get_irq(s->irq, 16));
+ /* NAND controller */
+ s->nand = s3c24xx_nand_init(CPU_S3C2440_NAND_BASE);
+
return s;
}
diff --git a/hw/s3c24xx.h b/hw/s3c24xx.h
index 2fdc3e8..af73ce5 100644
--- a/hw/s3c24xx.h
+++ b/hw/s3c24xx.h
@@ -11,6 +11,8 @@
#ifndef S3C24XX_H
#define S3C24XX_H 1
+#include "flash.h"
+
/* This structure type encapsulates the state of a S3C24XX SoC. */
typedef struct S3CState_s {
CPUState *cpu_env;
@@ -42,6 +44,8 @@ typedef struct S3CState_s {
/* LCD controller state */
struct s3c24xx_lcd_state_s *lcd;
+ /* NAND controller */
+ struct s3c24xx_nand_state_s *nand;
} S3CState;
@@ -81,4 +85,10 @@ i2c_bus *s3c24xx_i2c_bus(struct s3c24xx_i2c_state_s *s);
/* Initialise LCD controller */
struct s3c24xx_lcd_state_s *s3c24xx_lcd_init(target_phys_addr_t base, qemu_irq irq);
+/* Initialise nand controller */
+struct s3c24xx_nand_state_s *s3c24xx_nand_init(target_phys_addr_t base_addr);
+
+/* set nand controller context */
+void s3c24xx_nand_attach(struct s3c24xx_nand_state_s *s, NANDFlashState *nand);
+
#endif /* S3C24XX_H */
diff --git a/hw/s3c24xx_nand.c b/hw/s3c24xx_nand.c
new file mode 100644
index 0000000..3c1ffa4
--- /dev/null
+++ b/hw/s3c24xx_nand.c
@@ -0,0 +1,147 @@
+/* hw/s3c24xx_nand.c
+ *
+ * Samsung S3C24XX NAND emulation
+ *
+ * Copyright 2006, 2008 Ben Dooks, Daniel Silverstone and Vincent Sanders
+ *
+ * This file is under the terms of the GNU General Public
+ * License Version 2
+ */
+
+#include "hw.h"
+
+#include "s3c24xx.h"
+
+#define NFCONF 0
+#define NFCMD 1
+#define NFADDR 2
+#define NFDATA 3
+#define NFSTAT 4
+#define NFECC 5
+
+#define NFCE ((s->nand_reg[NFCONF] & 1<<11) != 0)
+
+/* NAND controller state */
+struct s3c24xx_nand_state_s {
+ uint32_t nand_reg[13];
+
+ NANDFlashState *nand;
+};
+
+static void
+s3c24xx_nand_write_f(void *opaque, target_phys_addr_t addr,
+ uint32_t value)
+{
+ struct s3c24xx_nand_state_s *s = (struct s3c24xx_nand_state_s *)opaque;
+ int reg = (addr & 0x1f) >> 2;
+
+ if ((reg != NFCONF) && ((s->nand_reg[NFCONF] & 1<<15) == 0)) {
+ return; /* Ignore the write, the nand is not enabled */
+ }
+
+ switch (reg) {
+ case NFCONF:
+ s->nand_reg[reg] = value;
+ if (s->nand != NULL)
+ nand_setpins(s->nand, 0, 0, NFCE, 1, 0);
+ break;
+
+ case NFCMD:
+ s->nand_reg[reg] = value;
+ if (s->nand != NULL) {
+ nand_setpins(s->nand, 1, 0, NFCE, 1, 0);
+ nand_setio(s->nand, value);
+ }
+ break;
+
+ case NFADDR:
+ s->nand_reg[reg] = value;
+ if (s->nand != NULL) {
+ nand_setpins(s->nand, 0, 1, NFCE, 1, 0);
+ nand_setio(s->nand, value);
+ }
+ break;
+
+ case NFDATA:
+ s->nand_reg[reg] = value;
+ if (s->nand != NULL) {
+ nand_setpins(s->nand, 0, 0, NFCE, 1, 0);
+ nand_setio(s->nand, value);
+ }
+ break;
+
+ default:
+ /* Do nothing because the other registers are read only */
+ break;
+ }
+}
+
+static uint32_t
+s3c24xx_nand_read_f(void *opaque, target_phys_addr_t addr)
+{
+ struct s3c24xx_nand_state_s *s = (struct s3c24xx_nand_state_s *)opaque;
+ int reg = (addr & 0x1f) >> 2;
+ uint32_t ret = s->nand_reg[reg];
+
+ switch (reg) {
+ case NFDATA:
+ if (s->nand != NULL) {
+ nand_setpins(s->nand, 0, 0, NFCE, 1, 0);
+ ret = s->nand_reg[reg] = nand_getio(s->nand);
+ } else {
+ ret = s->nand_reg[ret] = 0;
+ }
+ break;
+
+ case NFSTAT:
+ if (s->nand != NULL) {
+ nand_getpins(s->nand, (int *)&ret);
+ s->nand_reg[reg] = ret;
+ } else {
+ ret = s->nand_reg[ret] = 0;
+ }
+
+ default:
+ /* The rest read-back what was written to them */
+ break;
+ }
+
+ return ret;
+}
+
+static CPUReadMemoryFunc *s3c24xx_nand_read[] = {
+ &s3c24xx_nand_read_f,
+ &s3c24xx_nand_read_f,
+ &s3c24xx_nand_read_f,
+};
+
+static CPUWriteMemoryFunc *s3c24xx_nand_write[] = {
+ &s3c24xx_nand_write_f,
+ &s3c24xx_nand_write_f,
+ &s3c24xx_nand_write_f,
+};
+
+struct s3c24xx_nand_state_s *
+s3c24xx_nand_init(target_phys_addr_t base_addr)
+{
+ struct s3c24xx_nand_state_s *s;
+ int tag;
+
+ s = qemu_mallocz(sizeof(struct s3c24xx_nand_state_s));
+
+ tag = cpu_register_io_memory(0, s3c24xx_nand_read, s3c24xx_nand_write, s);
+ cpu_register_physical_memory(base_addr, 0x40, tag);
+
+ return s;
+}
+
+void
+s3c24xx_nand_attach(struct s3c24xx_nand_state_s *s, NANDFlashState *nand)
+{
+ if (s->nand != NULL) {
+ /* Detach current nand device */
+ /* no cmd, no addr, not enabled, write protected, no 'gnd' */
+ nand_setpins(s->nand, 0, 0, 1, 0, 0);
+ }
+ s->nand = nand;
+}
--
1.6.0.4
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [Qemu-devel] [PATCH 13/16] Peripheral driver for S3C OHCI controller
2009-05-23 16:35 [Qemu-devel] Add ARM S3C SOC core, drivers and boards - v3 Vincent Sanders
` (11 preceding siblings ...)
2009-05-23 16:35 ` [Qemu-devel] [PATCH 12/16] Peripheral driver for S3C SOC NAND controller Vincent Sanders
@ 2009-05-23 16:35 ` Vincent Sanders
2009-05-23 16:35 ` [Qemu-devel] [PATCH 14/16] Add bast board support Vincent Sanders
2009-05-23 16:35 ` [Qemu-devel] [PATCH 15/16] Add SMDK2410 " Vincent Sanders
14 siblings, 0 replies; 16+ messages in thread
From: Vincent Sanders @ 2009-05-23 16:35 UTC (permalink / raw)
To: qemu-devel; +Cc: Vincent Sanders
Add the USB host port OHCI controller useing the existing pxa driver
Signed-off-by: Vincent Sanders <vince@simtec.co.uk>
---
hw/s3c2410x.c | 9 +++++++++
hw/s3c2440.c | 9 +++++++++
2 files changed, 18 insertions(+), 0 deletions(-)
diff --git a/hw/s3c2410x.c b/hw/s3c2410x.c
index 78b9ee0..79978bf 100644
--- a/hw/s3c2410x.c
+++ b/hw/s3c2410x.c
@@ -13,6 +13,9 @@
#include "s3c2410x.h"
+/* Use the PXA OHCI USB mapping */
+#include "pxa.h"
+
/* S3C2410 SoC IDs */
#define CPU_S3C2410X_IDENT_S3C2410X 0x32410000
#define CPU_S3C2410X_IDENT_S3C2410A 0x32410002
@@ -26,6 +29,9 @@
/* Memory control */
#define CPU_S3C2410X_MEMC_BASE (CPU_S3C2410X_PERIPHERAL + 0x8000000)
+/* USB controller */
+#define CPU_S3C2410X_OHCI_BASE (CPU_S3C2410X_PERIPHERAL + 0x9000000)
+
/* Interrupt controller */
#define CPU_S3C2410X_IRQ_BASE (CPU_S3C2410X_PERIPHERAL + 0xA000000)
@@ -110,5 +116,8 @@ s3c2410x_init(int sdram_size)
/* NAND controller */
s->nand = s3c24xx_nand_init(CPU_S3C2410X_NAND_BASE);
+ /* A two port OHCI controller */
+ usb_ohci_init_pxa(CPU_S3C2410X_OHCI_BASE, 2, -1, s3c24xx_get_irq(s->irq, 26));
+
return s;
}
diff --git a/hw/s3c2440.c b/hw/s3c2440.c
index fdb107b..515f270 100644
--- a/hw/s3c2440.c
+++ b/hw/s3c2440.c
@@ -13,6 +13,9 @@
#include "s3c2440.h"
+/* Use the PXA OHCI USB mapping */
+#include "pxa.h"
+
/* S3C2440 SoC ID */
#define CPU_S3C2440_IDENT_S3C2440A 0x32440001
@@ -25,6 +28,9 @@
/* Memory control */
#define CPU_S3C2440_MEMC_BASE (CPU_S3C2440_PERIPHERAL + 0x8000000)
+/* USB controller */
+#define CPU_S3C2440_OHCI_BASE (CPU_S3C2440_PERIPHERAL + 0x9000000)
+
/* Interrupt controller */
#define CPU_S3C2440_IRQ_BASE (CPU_S3C2440_PERIPHERAL + 0xA000000)
@@ -107,5 +113,8 @@ s3c2440_init(int sdram_size)
/* NAND controller */
s->nand = s3c24xx_nand_init(CPU_S3C2440_NAND_BASE);
+ /* A two port OHCI controller */
+ usb_ohci_init_pxa(CPU_S3C2440_OHCI_BASE, 2, -1, s3c24xx_get_irq(s->irq, 26));
+
return s;
}
--
1.6.0.4
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [Qemu-devel] [PATCH 14/16] Add bast board support
2009-05-23 16:35 [Qemu-devel] Add ARM S3C SOC core, drivers and boards - v3 Vincent Sanders
` (12 preceding siblings ...)
2009-05-23 16:35 ` [Qemu-devel] [PATCH 13/16] Peripheral driver for S3C OHCI controller Vincent Sanders
@ 2009-05-23 16:35 ` Vincent Sanders
2009-05-23 16:35 ` [Qemu-devel] [PATCH 15/16] Add SMDK2410 " Vincent Sanders
14 siblings, 0 replies; 16+ messages in thread
From: Vincent Sanders @ 2009-05-23 16:35 UTC (permalink / raw)
To: qemu-devel; +Cc: Vincent Sanders
---
Makefile.target | 1 +
hw/bast.c | 191 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 192 insertions(+), 0 deletions(-)
create mode 100644 hw/bast.c
diff --git a/Makefile.target b/Makefile.target
index 535b4a2..4cb49e1 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -652,6 +652,7 @@ OBJS+= s3c24xx_memc.o s3c24xx_irq.o s3c24xx_clkcon.o s3c24xx_timers.o
OBJS+= s3c24xx_serial.o s3c24xx_rtc.o s3c24xx_gpio.o s3c24xx_iic.o
OBJS+= s3c24xx_lcd.o s3c24xx_nand.o
OBJS+= s3c2410x.o s3c2440.o
+OBJS+= bast.o
OBJS+= framebuffer.o
OBJS+= syborg.o syborg_fb.o syborg_interrupt.o syborg_keyboard.o
OBJS+= syborg_serial.o syborg_timer.o syborg_pointer.o syborg_rtc.o
diff --git a/hw/bast.c b/hw/bast.c
new file mode 100644
index 0000000..02984a6
--- /dev/null
+++ b/hw/bast.c
@@ -0,0 +1,191 @@
+/* hw/bast.c
+ *
+ * System emulation for the Simtec Electronics BAST
+ *
+ * Copyright 2006, 2008 Daniel Silverstone and Vincent Sanders
+ *
+ * This file is under the terms of the GNU General Public
+ * License Version 2.
+ */
+
+#include "hw.h"
+#include "sysemu.h"
+#include "arm-misc.h"
+#include "net.h"
+#include "smbus.h"
+#include "devices.h"
+#include "boards.h"
+
+#include "s3c2410x.h"
+
+#define BIOS_FILENAME "able.bin"
+
+typedef struct {
+ S3CState *soc;
+ unsigned char cpld_ctrl2;
+ NANDFlashState *nand[4];
+} STCBState;
+
+/* Bytes in a Kilobyte */
+#define KILO 1024
+/* Bytes in a megabyte */
+#define MEGA 1024 * KILO
+/* Bytes */
+#define BYTE 1
+/* Bits in a byte */
+#define BIT 8
+
+/* Useful defines */
+#define BAST_NOR_RO_BASE CPU_S3C2410X_CS0
+#define BAST_NOR_RW_BASE (CPU_S3C2410X_CS1 + 0x4000000)
+#define BAST_NOR_SIZE 16 * MEGA / BIT
+#define BAST_BOARD_ID 331
+
+#define BAST_CS1_CPLD_BASE ((target_phys_addr_t)(CPU_S3C2410X_CS1 | (0xc << 23)))
+#define BAST_CS5_CPLD_BASE ((target_phys_addr_t)(CPU_S3C2410X_CS5 | (0xc << 23)))
+#define BAST_CPLD_SIZE (4<<23)
+
+static uint32_t cpld_read(void *opaque, target_phys_addr_t address)
+{
+ STCBState *stcb = (STCBState *)opaque;
+ int reg = (address >> 23) & 0xf;
+ if (reg == 0xc)
+ return stcb->cpld_ctrl2;
+ return 0;
+}
+
+static void cpld_write(void *opaque, target_phys_addr_t address,
+ uint32_t value)
+{
+ STCBState *stcb = (STCBState *)opaque;
+ int reg = (address >> 23) & 0xf;
+ if (reg == 0xc) {
+ stcb->cpld_ctrl2 = value;
+ s3c24xx_nand_attach(stcb->soc->nand, stcb->nand[stcb->cpld_ctrl2 & 3]);
+ }
+}
+
+static CPUReadMemoryFunc *cpld_readfn[] = {
+ cpld_read,
+ cpld_read,
+ cpld_read
+};
+
+static CPUWriteMemoryFunc *cpld_writefn[] = {
+ cpld_write,
+ cpld_write,
+ cpld_write
+};
+
+static void stcb_cpld_register(STCBState *stcb)
+{
+ int tag = cpu_register_io_memory(0, cpld_readfn, cpld_writefn, stcb);
+ cpu_register_physical_memory(BAST_CS1_CPLD_BASE, BAST_CPLD_SIZE, tag);
+ cpu_register_physical_memory(BAST_CS5_CPLD_BASE, BAST_CPLD_SIZE, tag);
+ stcb->cpld_ctrl2 = 0;
+}
+
+static void stcb_i2c_setup(STCBState *stcb)
+{
+ i2c_bus *bus = s3c24xx_i2c_bus(stcb->soc->iic);
+}
+
+static struct arm_boot_info bast_binfo = {
+ .board_id = BAST_BOARD_ID,
+ .ram_size = 0x10000000, /* 256MB */
+};
+
+static void stcb_init(ram_addr_t _ram_size,
+ const char *boot_device,
+ const char *kernel_filename, const char *kernel_cmdline,
+ const char *initrd_filename, const char *cpu_model)
+{
+ STCBState *stcb;
+ int ret, index;
+ ram_addr_t flash_mem;
+ BlockDriverState *flash_bds = NULL;
+
+ /* ensure memory is limited to 256MB */
+ if (_ram_size > (256 * MEGA * BYTE))
+ _ram_size = 256 * MEGA * BYTE;
+ ram_size = _ram_size;
+
+ /* initialise board informations */
+ bast_binfo.ram_size = ram_size;
+ bast_binfo.kernel_filename = kernel_filename;
+ bast_binfo.kernel_cmdline = kernel_cmdline;
+ bast_binfo.initrd_filename = initrd_filename;
+ bast_binfo.nb_cpus = 1;
+ bast_binfo.loader_start = BAST_NOR_RO_BASE;
+
+ /* allocate storage for board state */
+ stcb = malloc(sizeof(STCBState));
+
+ /* initialise SOC */
+ stcb->soc = s3c2410x_init(ram_size);
+
+ /* Register the NOR flash ROM */
+ flash_mem = qemu_ram_alloc(BAST_NOR_SIZE);
+
+ /* Read only ROM type mapping */
+ cpu_register_physical_memory(BAST_NOR_RO_BASE,
+ BAST_NOR_SIZE,
+ flash_mem | IO_MEM_ROM);
+
+ /* Aquire flash contents and register pflash device */
+ index = drive_get_index(IF_PFLASH, 0, 0);
+ if (index != -1) {
+ /* load from specified flash device */
+ flash_bds = drives_table[index].bdrv;
+ } else {
+ /* Try and load default bootloader image */
+ char buf[PATH_MAX];
+
+ snprintf(buf, sizeof(buf), "%s/%s", bios_dir, BIOS_FILENAME);
+ ret = load_image_targphys(buf, BAST_NOR_RO_BASE, BAST_NOR_SIZE);
+ }
+ pflash_cfi02_register(BAST_NOR_RW_BASE, flash_mem, flash_bds,
+ 65536, 32, 1, 2,
+ 0x00BF, 0x234B, 0x0000, 0x0000, 0x5555, 0x2AAA);
+
+
+ /* if kernel is given, boot that directly */
+ if (kernel_filename != NULL) {
+ bast_binfo.loader_start = CPU_S3C2410X_DRAM;
+ arm_load_kernel(stcb->soc->cpu_env, &bast_binfo);
+ }
+
+ /* Setup initial (reset) program counter */
+ stcb->soc->cpu_env->regs[15] = bast_binfo.loader_start;
+
+ /* Initialise the BAST CPLD */
+ stcb_cpld_register(stcb);
+
+ /* attach i2c devices */
+ stcb_i2c_setup(stcb);
+
+ /* Attach some NAND devices */
+ stcb->nand[0] = NULL;
+ stcb->nand[1] = NULL;
+ index = drive_get_index(IF_MTD, 0, 0);
+ if (index == -1)
+ stcb->nand[2] = NULL;
+ else
+ stcb->nand[2] = nand_init(0xEC, 0x79); /* 128MiB small-page */
+
+}
+
+
+static QEMUMachine bast_machine = {
+ .name = "bast",
+ .desc = "Simtec Electronics BAST (S3C2410A, ARM920T)",
+ .init = stcb_init,
+ .max_cpus = 1,
+};
+
+static void bast_machine_init(void)
+{
+ qemu_register_machine(&bast_machine);
+}
+
+machine_init(bast_machine_init);
--
1.6.0.4
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [Qemu-devel] [PATCH 15/16] Add SMDK2410 board support
2009-05-23 16:35 [Qemu-devel] Add ARM S3C SOC core, drivers and boards - v3 Vincent Sanders
` (13 preceding siblings ...)
2009-05-23 16:35 ` [Qemu-devel] [PATCH 14/16] Add bast board support Vincent Sanders
@ 2009-05-23 16:35 ` Vincent Sanders
14 siblings, 0 replies; 16+ messages in thread
From: Vincent Sanders @ 2009-05-23 16:35 UTC (permalink / raw)
To: qemu-devel; +Cc: Vincent Sanders
Signed-off-by: Vincent Sanders <vince@simtec.co.uk>
---
Makefile.target | 2 +-
hw/smdk2410.c | 125 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 126 insertions(+), 1 deletions(-)
create mode 100644 hw/smdk2410.c
diff --git a/Makefile.target b/Makefile.target
index 4cb49e1..b30e90a 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -652,7 +652,7 @@ OBJS+= s3c24xx_memc.o s3c24xx_irq.o s3c24xx_clkcon.o s3c24xx_timers.o
OBJS+= s3c24xx_serial.o s3c24xx_rtc.o s3c24xx_gpio.o s3c24xx_iic.o
OBJS+= s3c24xx_lcd.o s3c24xx_nand.o
OBJS+= s3c2410x.o s3c2440.o
-OBJS+= bast.o
+OBJS+= bast.o smdk2410.o
OBJS+= framebuffer.o
OBJS+= syborg.o syborg_fb.o syborg_interrupt.o syborg_keyboard.o
OBJS+= syborg_serial.o syborg_timer.o syborg_pointer.o syborg_rtc.o
diff --git a/hw/smdk2410.c b/hw/smdk2410.c
new file mode 100644
index 0000000..2c13faf
--- /dev/null
+++ b/hw/smdk2410.c
@@ -0,0 +1,125 @@
+/* hw/smdk2410.c
+ *
+ * System emulation for the Samsung SMDK2410
+ *
+ * Copyright 2006, 2008 Daniel Silverstone and Vincent Sanders
+ *
+ * This file is under the terms of the GNU General Public
+ * License Version 2.
+ */
+
+#include "hw.h"
+#include "sysemu.h"
+#include "arm-misc.h"
+#include "net.h"
+#include "smbus.h"
+#include "devices.h"
+#include "boards.h"
+
+#include "s3c2410x.h"
+
+#define BIOS_FILENAME "smdk2410.bin"
+
+typedef struct {
+ S3CState *soc;
+ unsigned char cpld_ctrl2;
+ NANDFlashState *nand[4];
+} SMDK2410State;
+
+/* Bytes in a Kilobyte */
+#define KILO 1024
+/* Bytes in a megabyte */
+#define MEGA 1024 * KILO
+/* Bytes */
+#define BYTE 1
+/* Bits in a byte */
+#define BIT 8
+
+/* Useful defines */
+#define SMDK2410_NOR_BASE CPU_S3C2410X_CS0
+#define SMDK2410_NOR_SIZE 16 * MEGA / BIT
+#define SMDK2410_BOARD_ID 193
+
+static struct arm_boot_info smdk2410_binfo = {
+ .board_id = SMDK2410_BOARD_ID,
+ .ram_size = 0x10000000, /* 256MB */
+};
+
+static void smdk2410_init(ram_addr_t _ram_size,
+ const char *boot_device,
+ const char *kernel_filename, const char *kernel_cmdline,
+ const char *initrd_filename, const char *cpu_model)
+{
+ SMDK2410State *stcb;
+ int ret, index;
+
+ /* ensure memory is limited to 256MB */
+ if (_ram_size > (256 * MEGA * BYTE))
+ _ram_size = 256 * MEGA * BYTE;
+ ram_size = _ram_size;
+
+ /* allocate storage for board state */
+ stcb = malloc(sizeof(SMDK2410State));
+
+ /* initialise CPU and memory */
+ stcb->soc = s3c2410x_init(ram_size);
+
+ /* Register the NOR flash ROM */
+ cpu_register_physical_memory(SMDK2410_NOR_BASE,
+ SMDK2410_NOR_SIZE,
+ qemu_ram_alloc(SMDK2410_NOR_SIZE) | IO_MEM_ROM);
+
+ /* initialise board informations */
+ smdk2410_binfo.ram_size = ram_size;
+ smdk2410_binfo.kernel_filename = kernel_filename;
+ smdk2410_binfo.kernel_cmdline = kernel_cmdline;
+ smdk2410_binfo.initrd_filename = initrd_filename;
+ smdk2410_binfo.nb_cpus = 1;
+ smdk2410_binfo.loader_start = SMDK2410_NOR_BASE;
+
+ if (kernel_filename == NULL) {
+ /* No kernel given so try and aquire a bootloader */
+ char buf[PATH_MAX];
+
+ snprintf(buf, sizeof(buf), "%s/%s", bios_dir, BIOS_FILENAME);
+ ret = load_image_targphys(buf, smdk2410_binfo.loader_start, SMDK2410_NOR_SIZE);
+ if (ret <= 0) {
+ perror("qemu");
+ fprintf(stderr, "qemu: warning, could not load SMDK2410 BIOS from %s\n", buf);
+ exit (1);
+ } else {
+ fprintf(stdout, "qemu: info, loaded SMDK2410 BIOS %d bytes from %s\n", ret, buf);
+ }
+ } else {
+ smdk2410_binfo.loader_start = CPU_S3C2410X_DRAM;
+ arm_load_kernel(stcb->soc->cpu_env, &smdk2410_binfo);
+ }
+
+ /* Setup initial (reset) program counter */
+ stcb->soc->cpu_env->regs[15] = smdk2410_binfo.loader_start;
+
+ /* Attach some NAND devices */
+ stcb->nand[0] = NULL;
+ stcb->nand[1] = NULL;
+ index = drive_get_index(IF_MTD, 0, 0);
+ if (index == -1)
+ stcb->nand[2] = NULL;
+ else
+ stcb->nand[2] = nand_init(0xEC, 0x79); /* 128MiB small-page */
+
+}
+
+
+static QEMUMachine smdk2410_machine = {
+ .name = "smdk2410",
+ .desc = "Samsung SMDK2410 (S3C2410A, ARM920T)",
+ .init = smdk2410_init,
+ .max_cpus = 1,
+};
+
+static void smdk2410_machine_init(void)
+{
+ qemu_register_machine(&smdk2410_machine);
+}
+
+machine_init(smdk2410_machine_init);
--
1.6.0.4
^ permalink raw reply related [flat|nested] 16+ messages in thread