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