r1951 - trunk/src/host/qemu-neo1973/hw
andrew at sita.openmoko.org
andrew at sita.openmoko.org
Sat May 12 18:21:13 CEST 2007
Author: andrew
Date: 2007-05-12 18:21:11 +0200 (Sat, 12 May 2007)
New Revision: 1951
Modified:
trunk/src/host/qemu-neo1973/hw/neo1973.c
trunk/src/host/qemu-neo1973/hw/s3c.h
trunk/src/host/qemu-neo1973/hw/s3c2410.c
Log:
Implement the S3C2410 watchdog timer. Clean-up the machine reset code and make it work.
Modified: trunk/src/host/qemu-neo1973/hw/neo1973.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/neo1973.c 2007-05-12 14:16:49 UTC (rev 1950)
+++ trunk/src/host/qemu-neo1973/hw/neo1973.c 2007-05-12 16:21:11 UTC (rev 1951)
@@ -65,11 +65,13 @@
struct neo_board_s {
struct s3c_state_s *cpu;
+ unsigned int ram;
i2c_slave *pmu;
i2c_slave *wm;
i2c_slave *lcm;
CharDriverState *modem;
qemu_irq *kbd_pic;
+ const char *kernel;
};
/* Handlers for output ports */
@@ -348,8 +350,19 @@
static void neo_reset(void *opaque)
{
struct neo_board_s *s = (struct neo_board_s *) opaque;
- s3c2410_reset(s->cpu);
- s->cpu->env->regs[15] = S3C_RAM_BASE;
+#if 0
+ s->cpu->env->regs[15] = S3C_SRAM_BASE;
+#else
+ load_image("u-boot.bin", phys_ram_base + 0x03f80000);
+ load_image(s->kernel, phys_ram_base + 0x02000000);
+ s->cpu->env->regs[15] = S3C_RAM_BASE | 0x03f80000;
+#endif
+
+ /* Imitate ONKEY wakeup */
+ pcf_onkey_set(s->pmu, 0);
+ pcf_onkey_set(s->pmu, 1);
+ /* Connect the charger */
+ pcf_exton_set(s->pmu, 1);
}
/* Board init. */
@@ -358,21 +371,22 @@
const char *kernel_filename, const char *kernel_cmdline,
const char *initrd_filename, const char *cpu_model)
{
- uint32_t neo_ram = 0x08000000;
struct neo_board_s *s = (struct neo_board_s *)
qemu_mallocz(sizeof(struct neo_board_s));
+ s->ram = 0x08000000;
+ s->kernel = kernel_filename;
/* Setup CPU & memory */
- if (ram_size < neo_ram + S3C_SRAM_SIZE) {
+ if (ram_size < s->ram + S3C_SRAM_SIZE) {
fprintf(stderr, "This platform requires %i bytes of memory\n",
- neo_ram + S3C_SRAM_SIZE);
+ s->ram + S3C_SRAM_SIZE);
exit(1);
}
if (cpu_model && strcmp(cpu_model, "arm920t")) {
fprintf(stderr, "This platform requires an ARM920T core\n");
exit(2);
}
- s->cpu = s3c2410_init(neo_ram, ds);
+ s->cpu = s3c2410_init(s->ram, ds);
s3c_nand_register(s->cpu, nand_init(NAND_MFR_SAMSUNG, 0x76));
@@ -387,27 +401,13 @@
neo_gsm_setup(s);
+ /* Setup initial (reset) machine state */
qemu_register_reset(neo_reset, s);
-
- /* Setup initial (reset) machine state */
#if 0
- cpu->env->regs[15] = S3C_SRAM_BASE;
-
- arm_load_kernel(neo_ram, kernel_filename, kernel_cmdline,
+ arm_load_kernel(s->ram, kernel_filename, kernel_cmdline,
initrd_filename, 0x49e, S3C_RAM_BASE);
-#else
- load_image("u-boot.bin",
- phys_ram_base + 0x03f80000);
- load_image(kernel_filename,
- phys_ram_base + 0x02000000);
- s->cpu->env->regs[15] = S3C_RAM_BASE | 0x03f80000;
#endif
-
- /* Imitate ONKEY wakeup */
- pcf_onkey_set(s->pmu, 0);
- pcf_onkey_set(s->pmu, 1);
- /* Connect the charger */
- pcf_exton_set(s->pmu, 1);
+ neo_reset(s);
}
QEMUMachine neo1973_machine = {
Modified: trunk/src/host/qemu-neo1973/hw/s3c.h
===================================================================
--- trunk/src/host/qemu-neo1973/hw/s3c.h 2007-05-12 14:16:49 UTC (rev 1950)
+++ trunk/src/host/qemu-neo1973/hw/s3c.h 2007-05-12 16:21:11 UTC (rev 1951)
@@ -132,6 +132,9 @@
struct s3c_i2s_state_s;
struct s3c_i2s_state_s *s3c_i2s_init(target_phys_addr_t base, qemu_irq *dma);
+struct s3c_wdt_state_s;
+struct s3c_wdt_state_s *s3c_wdt_init(target_phys_addr_t base, qemu_irq irq);
+
/* s3c24xx_gpio.c */
struct s3c_gpio_state_s;
struct s3c_gpio_state_s *s3c_gpio_init(target_phys_addr_t base, qemu_irq *pic);
@@ -192,6 +195,7 @@
struct s3c_rtc_state_s *rtc;
struct s3c_spi_state_s *spi;
struct s3c_udc_state_s *udc;
+ struct s3c_wdt_state_s *wdt;
/* Memory controller */
target_phys_addr_t mc_base;
@@ -212,7 +216,6 @@
};
/* s3c2410.c */
-void s3c2410_reset(struct s3c_state_s *s);
struct s3c_state_s *s3c2410_init(unsigned int sdram_size, DisplayState *ds);
void s3c_nand_register(struct s3c_state_s *s, struct nand_flash_s *chip);
void s3c_nand_setwp(struct s3c_state_s *s, int wp);
Modified: trunk/src/host/qemu-neo1973/hw/s3c2410.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/s3c2410.c 2007-05-12 14:16:49 UTC (rev 1950)
+++ trunk/src/host/qemu-neo1973/hw/s3c2410.c 2007-05-12 16:21:11 UTC (rev 1951)
@@ -2153,6 +2153,142 @@
return s;
}
+/* Watchdog Timer */
+struct s3c_wdt_state_s {
+ target_phys_addr_t base;
+ qemu_irq irq;
+ uint16_t control;
+ uint16_t data;
+ uint16_t count;
+ QEMUTimer *tm;
+ int64_t timestamp;
+};
+
+static void s3c_wdt_start(struct s3c_wdt_state_s *s)
+{
+ int enable = s->control & (1 << 5);
+ int prescaler = (s->control >> 8) + 1;
+ int divider = prescaler << (((s->control >> 3) & 3) + 4);
+ if (enable) {
+ s->timestamp = qemu_get_clock(vm_clock);
+ qemu_mod_timer(s->tm, s->timestamp + muldiv64(divider * s->count,
+ ticks_per_sec, S3C_PCLK_FREQ));
+ } else
+ qemu_del_timer(s->tm);
+}
+
+static void s3c_wdt_stop(struct s3c_wdt_state_s *s)
+{
+ int prescaler = (s->control >> 8) + 1;
+ int divider = prescaler << (((s->control >> 3) & 3) + 4);
+ int diff;
+
+ diff = muldiv64(qemu_get_clock(vm_clock) - s->timestamp, S3C_PCLK_FREQ,
+ ticks_per_sec) / divider;
+ s->count -= MIN(s->count, diff);
+ s->timestamp = qemu_get_clock(vm_clock);
+}
+
+static void s3c_wdt_reset(struct s3c_wdt_state_s *s)
+{
+ s->control = 0x8021;
+ s->data = 0x8000;
+ s->count = 0x8000;
+ s3c_wdt_start(s);
+}
+
+static void s3c_wdt_timeout(void *opaque)
+{
+ struct s3c_wdt_state_s *s = (struct s3c_wdt_state_s *) opaque;
+ if (s->control & (1 << 0)) {
+ qemu_system_reset_request();
+ return;
+ }
+ if (s->control & (1 << 2))
+ qemu_irq_raise(s->irq);
+ s->count = s->data;
+ s3c_wdt_start(s);
+}
+
+#define S3C_WTCON 0x00 /* Watchdog timer control register */
+#define S3C_WTDAT 0x04 /* Watchdog timer data register */
+#define S3C_WTCNT 0x08 /* Watchdog timer count register */
+
+static uint32_t s3c_wdt_read(void *opaque, target_phys_addr_t addr)
+{
+ struct s3c_wdt_state_s *s = (struct s3c_wdt_state_s *) opaque;
+ addr -= s->base;
+
+ switch (addr) {
+ case S3C_WTCON:
+ return s->control;
+ case S3C_WTDAT:
+ return s->data;
+ case S3C_WTCNT:
+ s3c_wdt_stop(s);
+ return s->count;
+ default:
+ printf("%s: Bad register 0x%lx\n", __FUNCTION__, addr);
+ break;
+ }
+ return 0;
+}
+
+static void s3c_wdt_write(void *opaque, target_phys_addr_t addr,
+ uint32_t value)
+{
+ struct s3c_wdt_state_s *s = (struct s3c_wdt_state_s *) opaque;
+ addr -= s->base;
+
+ switch (addr) {
+ case S3C_WTCON:
+ s3c_wdt_stop(s);
+ s->control = value;
+ s3c_wdt_start(s);
+ break;
+ case S3C_WTDAT:
+ s->data = value;
+ break;
+ case S3C_WTCNT:
+ s->count = value;
+ s3c_wdt_start(s);
+ break;
+ default:
+ printf("%s: Bad register 0x%lx\n", __FUNCTION__, addr);
+ }
+}
+
+static CPUReadMemoryFunc *s3c_wdt_readfn[] = {
+ s3c_wdt_read,
+ s3c_wdt_read,
+ s3c_wdt_read,
+};
+
+static CPUWriteMemoryFunc *s3c_wdt_writefn[] = {
+ s3c_wdt_write,
+ s3c_wdt_write,
+ s3c_wdt_write,
+};
+
+struct s3c_wdt_state_s *s3c_wdt_init(target_phys_addr_t base, qemu_irq irq)
+{
+ int iomemtype;
+ struct s3c_wdt_state_s *s = (struct s3c_wdt_state_s *)
+ qemu_mallocz(sizeof(struct s3c_wdt_state_s));
+
+ s->base = base;
+ s->irq = irq;
+ s->tm = qemu_new_timer(vm_clock, s3c_wdt_timeout, s);
+
+ s3c_wdt_reset(s);
+
+ iomemtype = cpu_register_io_memory(0, s3c_wdt_readfn,
+ s3c_wdt_writefn, s);
+ cpu_register_physical_memory(s->base, 0xffffff, iomemtype);
+
+ return s;
+}
+
/* On-chip UARTs */
static struct {
target_phys_addr_t base;
@@ -2178,8 +2314,9 @@
};
/* General CPU reset */
-inline void s3c2410_reset(struct s3c_state_s *s)
+void s3c2410_reset(void *opaque)
{
+ struct s3c_state_s *s = (struct s3c_state_s *) opaque;
int i;
s3c_mc_reset(s);
s3c_pic_reset(s->pic);
@@ -2194,6 +2331,7 @@
s3c_rtc_reset(s->rtc);
s3c_spi_reset(s->spi);
s3c_udc_reset(s->udc);
+ s3c_wdt_reset(s->wdt);
s3c_clkpwr_reset(s);
s3c_nand_reset(s);
for (i = 0; s3c2410_uart[i].base; i ++)
@@ -2255,7 +2393,7 @@
s->udc = s3c_udc_init(0x52000000, s->irq[S3C_PIC_USBD], s->drq);
- /* Watchdog at 0x53000000 */
+ s->wdt = s3c_wdt_init(0x53000000, s->irq[S3C_PIC_WDT]);
s->i2c = s3c_i2c_init(0x54000000, s->irq[S3C_PIC_IIC]);
@@ -2278,6 +2416,8 @@
usb_ohci_init_memio(0x49000000, 3, -1, s->irq[S3C_PIC_USBH]);
}
+ qemu_register_reset(s3c2410_reset, s);
+
s3c_nand_setwp(s, 1);
/* Power on reset */
More information about the commitlog
mailing list