* [Qemu-devel] Add ARM S3C SOC core, drivers and boards - v3
@ 2009-05-23 16:35 Vincent Sanders
2009-05-23 16:35 ` [Qemu-devel] [PATCH 01/16] Add ARM 920T CPU identifier Vincent Sanders
` (14 more replies)
0 siblings, 15 replies; 16+ messages in thread
From: Vincent Sanders @ 2009-05-23 16:35 UTC (permalink / raw)
To: qemu-devel
This is an updated series integrating the feedback from Jean-Christophe
plagniol-villard and rebased to current git head.
The following series adds Samsung S3C support to Qemu. The approach
taken is to create a series of generic s3c24xx peripheral blocks and
then to create a SOC device which collects a number of these generic
blocks together.
The SOC device is then instansiated by the board driver and additional
external peripherals added as appropriate.
Two actual SOC are currently implemented (however the generic
peripherals are used throughout the entire Samsung range from S3C2400
to S3C6410) are the S3C2410 and S3C2440.
These two SOC were chosen as representative samples because they are
two of the most popular ARM 9 class devices and have been used in many
devices from handhelds to the openmoko phones.
These SOC also have extremely good Linux kernel support, a single
default configuration covers 22 boards.
Only a pair of boards have been included in this series purely to
demostrate the most basic intended usage of the implementation. A
subsequent series will introduce all the omited peripherals for these
boards.
This series is the smallest set of changes required to support these
devices and is current against git head. The implementation
of some peripheral blocks although not complete is sufficient to
successfully run Linux kernels. Improved peripheral support is
envisaged after the core support is merged.
^ permalink raw reply [flat|nested] 16+ messages in thread
* [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
end of thread, other threads:[~2009-05-23 16:35 UTC | newest]
Thread overview: 16+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
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 ` [Qemu-devel] [PATCH 03/16] Peripheral driver for S3C SOC SDRAM controller Vincent Sanders
2009-05-23 16:35 ` [Qemu-devel] [PATCH 04/16] Peripheral driver for S3C SOC IRQ controller Vincent Sanders
2009-05-23 16:35 ` [Qemu-devel] [PATCH 05/16] Peripheral driver for S3C SOC clock control Vincent Sanders
2009-05-23 16:35 ` [Qemu-devel] [PATCH 06/16] Peripheral driver for S3C SOC timers Vincent Sanders
2009-05-23 16:35 ` [Qemu-devel] [PATCH 07/16] Peripheral driver for S3C SOC Serial ports Vincent Sanders
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 ` [Qemu-devel] [PATCH 09/16] Peripheral driver for S3C SOC general purpose I/O Vincent Sanders
2009-05-23 16:35 ` [Qemu-devel] [PATCH 10/16] Peripheral driver for S3C SOC I2C controller Vincent Sanders
2009-05-23 16:35 ` [Qemu-devel] [PATCH 11/16] Peripheral driver for S3C SOC LCD controller Vincent Sanders
2009-05-23 16:35 ` [Qemu-devel] [PATCH 12/16] Peripheral driver for S3C SOC NAND controller Vincent Sanders
2009-05-23 16:35 ` [Qemu-devel] [PATCH 13/16] Peripheral driver for S3C OHCI controller 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
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).