s5pc110: suspend/resume support
authorMyungJoo Ham <MyungJoo.Ham@samsung.com>
Wed, 25 Nov 2009 10:50:50 +0000 (19:50 +0900)
committerMyungJoo Ham <MyungJoo.Ham@samsung.com>
Wed, 25 Nov 2009 10:50:50 +0000 (19:50 +0900)
KNOWN ISSUES:
- unstable resume (freezes occasionally)
- unnecessary wake-up routines (needs to be cleaned)
- current mismatch between before-suspend and after-suspend
- current not low enough (will follow kernel suspend/resume)
- HW Revision number corruption (probably GPIO related issue)

board/samsung/universal/universal.c
common/lcd.c
common/stdio.c
cpu/arm_cortexa8/s5pc1xx/Makefile
cpu/arm_cortexa8/s5pc1xx/sleep.c
lib_arm/board.c

index d253d36..3158f63 100644 (file)
@@ -400,7 +400,7 @@ static void check_hw_revision(void)
        }
 }
 
-static void show_hw_revision(void)
+void show_hw_revision(void)
 {
        int board;
 
@@ -697,6 +697,7 @@ static void check_battery(void)
                printf("i2c_write error: %x\n", addr);
                return;
        }
+       i2c_read(addr, 0x06, 1, val, 2);
 
        if (i2c_read(addr, 0x04, 1, val, 1)) {
                printf("i2c_read error: %x\n", addr);
@@ -741,6 +742,7 @@ static void check_mhl(void)
         */
        val[0] = 0x35;
        i2c_write((0x72 >> 1), 0x08, 1, val, 1);
+       i2c_read((0x72 >> 1), 0x08, 1, val, 1);
 
        /*
         * MHL TX Control #1
@@ -750,6 +752,7 @@ static void check_mhl(void)
         */
        val[0] = 0xd0;
        i2c_write((0x72 >> 1), 0xa0, 1, val, 1);
+       i2c_read((0x72 >> 1), 0xa0, 1, val, 1);
 }
 
 static void check_micro_usb(void)
@@ -793,6 +796,7 @@ static void check_micro_usb(void)
                val[0] &= ~(0x7 << 0);
                val[0] |= 5;            /* 600mA */
                i2c_write(addr, 0x0C, 1, val, 1);
+               i2c_read(addr, 0x0C, 1, val, 1);
        }
 
        /* If Factory Mode is Boot ON-USB, go to download mode */
@@ -840,6 +844,7 @@ static void init_pmic(void)
        val[0] &= ~(MAX8998_LDO10 | MAX8998_LDO11 |
                        MAX8998_LDO12 | MAX8998_LDO13);
        i2c_write(addr, MAX8998_REG_ONOFF2, 1, val, 1);
+       i2c_read(addr, MAX8998_REG_ONOFF2, 1, val, 1);
        /* ONOFF3 */
        i2c_read(addr, MAX8998_REG_ONOFF3, 1, val, 1);
        /*
@@ -849,6 +854,7 @@ static void init_pmic(void)
        val[0] &= ~(MAX8998_LDO14 | MAX8998_LDO15 |
                        MAX8998_LDO16 | MAX8998_LDO17);
        i2c_write(addr, MAX8998_REG_ONOFF3, 1, val, 1);
+       i2c_read(addr, MAX8998_REG_ONOFF3, 1, val, 1);
 }
 
 #define PDN_MASK(x)            (0x3 << ((x) << 1))
@@ -901,7 +907,9 @@ static struct gpio_powermode powerdown_modes[] = {
                PULL_DIS(0) | PULL_DIS(1) | PULL_DIS(2) | PULL_DIS(3) |
                PULL_DIS(4),
        }, {    /* S5PC110_GPIO_C1_OFFSET */
-               OUTPUT0(0) | OUTPUT0(1) | OUTPUT0(2) | OUTPUT0(3) |
+               /* OUTPUT0(0) | OUTPUT0(1) | OUTPUT0(2) | OUTPUT0(3) |
+               OUTPUT0(4), */
+               OUTPUT0(0) | OUTPUT0(1) | OUTPUT0(2) | INPUT(3) |
                OUTPUT0(4),
                PULL_DIS(0) | PULL_DIS(1) | PULL_DIS(2) | PULL_DIS(3) |
                PULL_DIS(4),
@@ -980,7 +988,7 @@ static struct gpio_powermode powerdown_modes[] = {
                PULL_DIS(4) | PULL_DIS(5) | PULL_DIS(6) | PULL_DIS(7),
        }, {    /* S5PC110_GPIO_J2_OFFSET */
                OUTPUT0(0) | OUTPUT0(1) | OUTPUT0(2) | OUTPUT0(3) |
-               INPUT(4) | OUTPUT1(5) | OUTPUT0(6) | INPUT(7),
+               INPUT(4) | OUTPUT0(5) | OUTPUT0(6) | INPUT(7),
                PULL_DIS(0) | PULL_DIS(1) | PULL_DIS(2) | PULL_DIS(3) |
                PULL_DIS(4) | PULL_DIS(5) | PULL_DIS(6) | PULL_DOWN(7),
        }, {    /* S5PC110_GPIO_J3_OFFSET */
@@ -1002,12 +1010,19 @@ static struct gpio_external external_powerdown_modes[] = {
                CON_OUTPUT(4) | CON_OUTPUT(5) | CON_INPUT(6) | CON_INPUT(7),
                DAT_SET(0) | DAT_CLEAR(2) | DAT_CLEAR(3) |
                DAT_CLEAR(4) | DAT_CLEAR(5),
+               PULL_DIS(0) | PULL_DIS(1) | PULL_DIS(2) | PULL_DIS(3) |
+               PULL_DIS(4) | PULL_DIS(5),
        }, {    /* S5PC110_GPIO_H1_OFFSET */
-               CON_INPUT(0) | CON_INPUT(1) | CON_OUTPUT(2) | CON_IRQ(3) |
+               /* CON_INPUT(0) | CON_INPUT(1) | CON_OUTPUT(2) | CON_IRQ(3) |
                CON_IRQ(4) | CON_INPUT(5) | CON_INPUT(6) | CON_INPUT(7),
                DAT_CLEAR(2),
                PULL_DOWN(0) | PULL_DOWN(1) |
-               PULL_DOWN(6),
+               PULL_DOWN(6),           */
+               CON_INPUT(0) | CON_INPUT(1) | CON_OUTPUT(2) | CON_IRQ(3) |
+               CON_INPUT(4) | CON_INPUT(5) | CON_OUTPUT(6) | CON_INPUT(7),
+               DAT_SET(0),
+               PULL_DIS(0) | PULL_DIS(1) | PULL_DIS(2) | PULL_DIS(3) |
+               PULL_DOWN(4),
        }, {    /* S5PC110_GPIO_H2_OFFSET */
                CON_OUTPUT(0) | CON_OUTPUT(1) | CON_OUTPUT(2) | CON_OUTPUT(3) |
                CON_IRQ(4) | CON_IRQ(5) | CON_IRQ(6) | CON_IRQ(7),
@@ -1066,6 +1081,11 @@ static void setup_power_down_mode_registers(void)
        writel(0x0000, &bank->pdn_con);
        writel(0x0000, &bank->pdn_pull);
 
+       /* M299 */
+       writel(0xff0022b0, (unsigned int*) 0xF0000000);
+       writel(0xff0022b0, (unsigned int*) 0xF1400000);
+
+
        bank = &gpio->gpio_h0;
        ge = external_powerdown_modes;
 
@@ -1090,6 +1110,7 @@ int misc_init_r(void)
        else
                setenv("lcd", "lcd=tl2796-dual");
 #endif
+
        show_hw_revision();
 
        /* Set proper PMIC pins */
@@ -1178,11 +1199,13 @@ int dram_init(void)
 }
 
 /* Used for sleep test */
+static unsigned char saved_val[3][2];
 void board_sleep_init(void)
 {
        unsigned int value;
        unsigned char addr;
        unsigned char val[2];
+       unsigned char dummy = 0;
 
        /* Set wakeup mask register */
        value = 0xFFFF;
@@ -1205,25 +1228,56 @@ void board_sleep_init(void)
 
        /* Set ONOFF1 */
        i2c_read(addr, 0x11, 1, val, 1);
+       saved_val[0][0] = val[0];
+       saved_val[0][1] = val[1];
        val[0] &= ~((1 << 7) | (1 << 6) | (1 << 4) | (1 << 2) |
                        (1 << 1) | (1 << 0));
        i2c_write(addr, 0x11, 1, val, 1);
        i2c_read(addr, 0x11, 1, val, 1);
-       printf("ONOFF1 0x%02x\n", val[0]);
        /* Set ONOFF2 */
        i2c_read(addr, 0x12, 1, val, 1);
+       saved_val[1][0] = val[0];
+       saved_val[1][1] = val[1];
        val[0] &= ~((1 << 7) | (1 << 6) | (1 << 5) | (1 << 3) |
                        (1 << 2) | (1 << 1) | (1 << 0));
        i2c_write(addr, 0x12, 1, val, 1);
        i2c_read(addr, 0x12, 1, val, 1);
-       printf("ONOFF2 0x%02x\n", val[0]);
        /* Set ONOFF3 */
        i2c_read(addr, 0x13, 1, val, 1);
+       saved_val[2][0] = val[0];
+       saved_val[2][1] = val[1];
        val[0] &= ~((1 << 7) | (1 << 6) | (1 << 5) | (1 << 4));
        val[0] = 0x0;
        i2c_write(addr, 0x13, 1, val, 1);
        i2c_read(addr, 0x13, 1, val, 1);
-       printf("ONOFF3 0x%02x\n", val[0]);
+       printf("Preparing to sleep.\n");
+       /* Strangely, unless printf is used,
+        * it does not work. (i2c_read seems to be ignored)
+        * Probably, the compiler's optimization mechanism is
+        * doing this. */
+}
+void board_sleep_resume(void)
+{
+       unsigned char addr;
+       unsigned char val[2];
+
+       i2c_gpio_set_bus(I2C_PMIC);
+       addr = 0xCC >> 1;
+       if (i2c_probe(addr)) {
+               printf("Can't found max8998\n");
+               return;
+       }
+
+       /* Set ONOFF1 */
+       i2c_write(addr, 0x11, 1, saved_val[0], 1);
+       i2c_read(addr, 0x11, 1, val, 1);
+       /* Set ONOFF2 */
+       i2c_write(addr, 0x12, 1, saved_val[1], 1);
+       i2c_read(addr, 0x12, 1, val, 1);
+       /* Set ONOFF3 */
+       i2c_write(addr, 0x13, 1, saved_val[2], 1);
+       i2c_read(addr, 0x13, 1, val, 1);
+       printf("Waked up.\n");
 }
 
 #ifdef CONFIG_CMD_USBDOWN
@@ -1246,6 +1300,7 @@ int usb_board_init(void)
                        printf("i2c_write error\n");
                        return 1;
                }
+               i2c_read(0x66, 0, 1, val, 2);
 #endif
                return 0;
        }
index 4e31618..191cf5b 100644 (file)
@@ -319,6 +319,18 @@ static void test_pattern (void)
 /************************************************************************/
 /* ** GENERIC Initialization Routines                                  */
 /************************************************************************/
+int drv_lcd_init_resume (void)
+{
+       int rc;
+
+       lcd_base = (void *)(gd->fb_base);
+
+       lcd_line_length = (panel_info.vl_col * NBITS (panel_info.vl_bpix)) / 8;
+
+       lcd_init (lcd_base);            /* LCD initialization */
+
+       return 0;
+}
 
 int drv_lcd_init (void)
 {
index 870ddfd..d855dea 100644 (file)
@@ -199,6 +199,21 @@ int stdio_deregister(char *devname)
 }
 #endif /* CONFIG_SYS_STDIO_DEREGISTER */
 
+
+int stdio_init_resume (void)
+{
+#if defined(CONFIG_HARD_I2C) || defined(CONFIG_SOFT_I2C)
+       i2c_init (CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE);
+#endif
+#ifdef CONFIG_LCD
+       drv_lcd_init_resume ();
+#endif
+#if defined(CONFIG_VIDEO) || defined(CONFIG_CFB_CONSOLE)
+       drv_video_init ();
+#endif
+       return 0;
+}
+
 int stdio_init (void)
 {
 #if !defined(CONFIG_RELOC_FIXUP_WORKS)
index ca55560..3e11d4a 100644 (file)
@@ -36,6 +36,7 @@ COBJS-y               += cpu_info.o
 COBJS-y                += gpio.o
 COBJS-y                += timer.o
 COBJS-y                += sleep.o
+COBJS-y                += sleep_asm.o
 COBJS-$(CONFIG_SOFT_I2C)       += i2c-gpio.o
 COBJS-$(CONFIG_CMD_USBDOWN)    += usb-hs-otg.o usb_downloader.o
 
index 7d76d02..19e6d24 100644 (file)
 #include <asm/arch/cpu.h>
 #include <asm/arch/power.h>
 
+#define CONFIG_CPU_S5PC110_EVT0_ERRATA
+
+#include <common.h>
+#include "sleep.h"
+
+extern int s5pc110_cpu_save(unsigned long *saveblk);
+extern void s5pc110_cpu_resume(void);
+extern unsigned int s5pc110_sleep_return_addr;
+extern unsigned int s5pc110_sleep_save_phys;
+
+struct stack {
+       u32 irq[3];
+       u32 abt[3];
+       u32 und[3];
+} ____cacheline_aligned;
+
+static struct stack stacks[1];
+
 enum {
        SLEEP_WFI,
        SLEEP_REGISTER,
@@ -28,42 +46,325 @@ static void __board_sleep_init(void) { }
 void board_sleep_init(void)
        __attribute__((weak, alias("__board_sleep_init")));
 
+struct regs_to_save {
+       unsigned int    start_address;
+       unsigned int    size;
+};
+static struct regs_to_save core_save[] = {
+       { .start_address=0xE0100200, .size=7},
+       { .start_address=0xE0100280, .size=2},
+       { .start_address=0xE0100300, .size=7},
+       { .start_address=0xE0100460, .size=5},
+       { .start_address=0xE0100480, .size=3},
+       { .start_address=0xE0100500, .size=1},
+       { .start_address=0xE0107008, .size=1},
+};
+static unsigned int buf_core_save[7+2+7+5+3+1+1];
+static struct regs_to_save gpio_save[] = {
+       { .start_address=0xE0200000, .size=6},
+       { .start_address=0xE0200020, .size=6},
+       { .start_address=0xE0200040, .size=6},
+       { .start_address=0xE0200060, .size=6},
+       { .start_address=0xE0200080, .size=6},
+       { .start_address=0xE02000A0, .size=6},
+       { .start_address=0xE02000C0, .size=6},
+       { .start_address=0xE02000E0, .size=6},
+       { .start_address=0xE0200100, .size=6},
+       { .start_address=0xE0200120, .size=6},
+       { .start_address=0xE0200140, .size=6},
+       { .start_address=0xE0200160, .size=6},
+       { .start_address=0xE0200180, .size=6},
+       { .start_address=0xE02001A0, .size=6},
+       { .start_address=0xE02001C0, .size=6},
+       { .start_address=0xE02001E0, .size=6},
+       { .start_address=0xE0200200, .size=6},
+       { .start_address=0xE0200220, .size=6},
+       { .start_address=0xE0200240, .size=6},
+       { .start_address=0xE0200260, .size=6},
+       { .start_address=0xE0200280, .size=6},
+       { .start_address=0xE02002A0, .size=6},
+       { .start_address=0xE02002C0, .size=6},
+       { .start_address=0xE02002E0, .size=6},
+       { .start_address=0xE0200300, .size=6},
+       { .start_address=0xE0200320, .size=6},
+       { .start_address=0xE0200340, .size=6},
+       { .start_address=0xE0200360, .size=6},
+       { .start_address=0xE0200380, .size=6},
+       { .start_address=0xE02003A0, .size=6},
+       { .start_address=0xE02003C0, .size=6},
+       { .start_address=0xE02003E0, .size=6},
+       { .start_address=0xE0200400, .size=6},
+       { .start_address=0xE0200420, .size=6},
+       { .start_address=0xE0200440, .size=6},
+       { .start_address=0xE0200460, .size=6},
+       { .start_address=0xE0200480, .size=6},
+       { .start_address=0xE02004A0, .size=6},
+       { .start_address=0xE02004C0, .size=6},
+       { .start_address=0xE02004E0, .size=6},
+       { .start_address=0xE0200500, .size=6},
+       { .start_address=0xE0200520, .size=6},
+       { .start_address=0xE0200540, .size=6},
+       { .start_address=0xE0200560, .size=6},
+       { .start_address=0xE0200580, .size=6},
+       { .start_address=0xE02005A0, .size=6},
+       { .start_address=0xE02005C0, .size=6},
+       { .start_address=0xE02005E0, .size=6},
+       { .start_address=0xE0200700, .size=22},
+       { .start_address=0xE0200900, .size=22},
+       { .start_address=0xE0200A00, .size=22},
+};
+static unsigned int buf_gpio_save[ 6*8*6 + 22*3 ];
+static struct regs_to_save irq_save[] = {
+       { .start_address=0xF200000C, .size=2},
+       { .start_address=0xF2000018, .size=1},
+       { .start_address=0xF210000C, .size=2},
+       { .start_address=0xF2100018, .size=1},
+       { .start_address=0xF220000C, .size=2},
+       { .start_address=0xF2200018, .size=1},
+       { .start_address=0xF230000C, .size=2},
+       { .start_address=0xF2300018, .size=1},
+};
+static unsigned int buf_irq_save[ (2+1)*4 ];
+static struct regs_to_save sromc_save[] = {
+       { .start_address=0xE8000000, .size=7},
+};
+static unsigned int buf_sromc_save[7];
+static struct regs_to_save uart_save[] = {
+       { .start_address=0xE2900000, .size=4},
+       { .start_address=0xE2900028, .size=2},
+       { .start_address=0xE2900038, .size=1},
+       { .start_address=0xE2900400, .size=4},
+       { .start_address=0xE2900428, .size=2},
+       { .start_address=0xE2900438, .size=1},
+       { .start_address=0xE2900800, .size=4},
+       { .start_address=0xE2900828, .size=2},
+       { .start_address=0xE2900838, .size=1},
+       { .start_address=0xE2900C00, .size=4},
+       { .start_address=0xE2900C28, .size=2},
+       { .start_address=0xE2900C38, .size=1},
+};
+static unsigned int buf_uart_save[(4+2+1)*4];
+
+static unsigned int reg_others;
+
+void s5pc110_save_reg(struct regs_to_save * list, unsigned int * buf, int length)
+{
+       int i;
+       int counter = 0;
+       for (i=0; i<length; i++) {
+               int j;
+               for (j=0; j<list[i].size; j++) {
+                       (*buf) = readl((unsigned int *)(list[i].start_address+j*4));
+                       buf++;
+                       counter++;
+               }
+       }
+}
+void s5pc110_save_regs(void)
+{
+       reg_others = readl(S5PC110_OTHERS);
+       s5pc110_save_reg(gpio_save, buf_gpio_save, ARRAY_SIZE(gpio_save));
+       s5pc110_save_reg(irq_save, buf_irq_save, ARRAY_SIZE(irq_save));
+       s5pc110_save_reg(core_save, buf_core_save, ARRAY_SIZE(core_save));
+       s5pc110_save_reg(sromc_save, buf_sromc_save, ARRAY_SIZE(sromc_save));
+       s5pc110_save_reg(uart_save, buf_uart_save, ARRAY_SIZE(uart_save));
+}
+void s5pc110_restore_reg(struct regs_to_save * list, unsigned int * buf, int length)
+{
+       int i;
+       for (i=0; i<length; i++) {
+               int j;
+               for (j=0; j<list[i].size; j++) {
+                       writel(*buf, (unsigned int *)(list[i].start_address+j*4));
+#ifdef CONFIG_CPU_S5PC110_EVT0_ERRATA
+                       readl((unsigned int *)(list[i].start_address+j*4));
+#endif
+                       buf++;
+               }
+       }
+
+}
+void s5pc110_restore_regs(void)
+{
+       s5pc110_restore_reg(uart_save, buf_uart_save, ARRAY_SIZE(uart_save));
+       s5pc110_restore_reg(sromc_save, buf_sromc_save, ARRAY_SIZE(sromc_save));
+       s5pc110_restore_reg(core_save, buf_core_save, ARRAY_SIZE(core_save));
+       s5pc110_restore_reg(irq_save, buf_irq_save, ARRAY_SIZE(irq_save));
+       s5pc110_restore_reg(gpio_save, buf_gpio_save, ARRAY_SIZE(gpio_save));
+}
+
+void s5pc110_wakeup(void)
+{
+       struct stack *stk = &stacks[0];
+       __asm__ (
+                       "msr    cpsr_c, %1\n\t"
+                       "add    sp, %0, %2\n\t"
+                       "msr    cpsr_c, %3\n\t"
+                       "add    sp, %0, %4\n\t"
+                       "msr    cpsr_c, %5\n\t"
+                       "add    sp, %0, %6\n\t"
+                       "msr    cpsr_c, %7"
+                       :
+                       : "r" (stk),
+                       "I" (PSR_F_BIT | PSR_I_BIT | IRQ_MODE),
+                       "I" (offsetof(struct stack, irq[0])),
+                       "I" (PSR_F_BIT | PSR_I_BIT | ABT_MODE),
+                       "I" (offsetof(struct stack, abt[0])),
+                       "I" (PSR_F_BIT | PSR_I_BIT | UND_MODE),
+                       "I" (offsetof(struct stack, und[0])),
+                       "I" (PSR_F_BIT | PSR_I_BIT | SVC_MODE)
+                       : "r14");
+
+
+       s5pc110_restore_regs();
+
+       reg_others |= 1<<28;
+       writel(reg_others, S5PC110_OTHERS);
+
+       printf("%s: Waking up...\n", __func__);
+
+       start_armboot_resume();
+
+       return;
+}
+
 static int s5pc110_sleep(int mode)
 {
+       unsigned long regs_save[16];
        unsigned int value;
+       int i;
+
+       printf("Entering s5pc110_sleep();\n");
 
        board_sleep_init();
 
-       writel(0x0badcafe, S5PC110_INFORM0);
+       value = readl(S5PC110_WAKEUP_MASK);
+       value |= (1 << 15);
+       value |= (1 << 14);
+       value |= (1 << 13);
+       value |= (1 << 12);
+       value |= (1 << 11);
+       value |= (1 << 10);
+       value |= (1 << 9);
+       value |= (1 << 5);
+       value |= (1 << 4);
+       value |= (1 << 3);
+       value |= (1 << 2);
+       value |= (1 << 1);
+       writel(value, S5PC110_WAKEUP_MASK);
+
+       value = __raw_readl(S5PC110_EINT_WAKEUP_MASK);
+       value = 0xFFFFFFFF;
+       value &= ~(1 << 7);       /* AP_PMIC_IRQ */
+       value &= ~(1 << 22);      /* nPOWER */
+       writel(value, S5PC110_EINT_WAKEUP_MASK);
+#ifdef CONFIG_CPU_S5PC110_EVT0_ERRATA
+       readl(S5PC110_EINT_WAKEUP_MASK);
+        for (i = 0; i < 4; i++)
+               readl(0xE0200F40+i*4);
+#endif
+
+       s5pc110_save_regs();
+       writel((unsigned long) s5pc110_cpu_resume, S5PC110_INFORM0);
+
+#ifdef CONFIG_CPU_S5PC110_EVT0_ERRATA
+       value = readl(S5PC110_SLEEP_CFG);
+       value &= ~(1 << 0); /* OSC_EN off */
+       value &= ~(1 << 1); /* USBOSC_EN off */
+       writel(value, S5PC110_SLEEP_CFG);
+#endif
 
        value = readl(S5PC110_PWR_CFG);
        value &= ~S5PC110_CFG_STANDBYWFI_MASK;
        if (mode == SLEEP_WFI)
+#ifdef CONFIG_CPU_S5PC110_EVT0_ERRATA
+       {
+               printf("ERRATA MODE\n");
+               value |= S5PC110_CFG_STANDBYWFI_IGNORE;
+       }
+#else
                value |= S5PC110_CFG_STANDBYWFI_SLEEP;
+#endif
        else
                value |= S5PC110_CFG_STANDBYWFI_IGNORE;
        writel(value, S5PC110_PWR_CFG);
 
+       /* F2000000: VICIRQSTATUS-irq0 */
+       writel(0xffffffff, 0xF2000000 + 0x14); /* VIC_INT_ENABLE_CLEAR */
+       writel(0xffffffff, 0xF2100000 + 0x14);
+       writel(0xffffffff, 0xF2200000 + 0x14);
+       writel(0xffffffff, 0xF2300000 + 0x14);
+       writel(0xffffffff, 0xF2000000 + 0x1c); /* VIC_INT_SOFT_CLEAR */
+       writel(0xffffffff, 0xF2100000 + 0x1c);
+       writel(0xffffffff, 0xF2200000 + 0x1c);
+       writel(0xffffffff, 0xF2300000 + 0x1c);
+
+       /* Clear all EINT PENDING bit */
+       writel(0xff, 0xE0200000 + 0xF40);
+       value = readl(0xE0200000 + 0xF40);
+       writel(0xff, 0xE0200000 + 0xF44);
+       value = readl(0xE0200000 + 0xF44);
+       writel(0xff, 0xE0200000 + 0xF48);
+       value = readl(0xE0200000 + 0xF48);
+       writel(0xff, 0xE0200000 + 0xF4C);
+       value = readl(0xE0200000 + 0xF4C);
+       writel(0xFFFF , S5PC110_WAKEUP_STAT);
+
+
        value = readl(S5PC110_OTHERS);
        value |= S5PC110_OTHERS_SYSCON_INT_DISABLE;
        writel(value, S5PC110_OTHERS);
 
-       printf("%s[%d] sleep enter mode %d\n\n", __func__, __LINE__, mode);
-
        if (mode == SLEEP_WFI) {
                value = 0;
+               s5pc110_sleep_save_phys = (unsigned int) regs_save;
+
+               value = readl(S5PC110_OTHERS);
+               value |= 1;
+               writel(value, S5PC110_OTHERS);
+
+#ifdef CONFIG_CPU_S5PC110_EVT0_ERRATA
+               if (s5pc110_cpu_save(regs_save) == 0) {
+                       /* cache flush */
+                       asm ("mcr p15, 0, %0, c7, c5, 0": :"r" (0)); 
+                       l2_cache_disable();
+                       invalidate_dcache(get_device_type());
+
+                       value = (1 << 2);
+                       writel(value, S5PC110_PWR_MODE);
+                       while(1);
+               }
+
+               s5pc110_wakeup();
+
+               writel(0, S5PC110_EINT_WAKEUP_MASK);
+#ifdef CONFIG_CPU_S5PC110_EVT0_ERRATA
+               readl(S5PC110_EINT_WAKEUP_MASK);
+               for (i = 0; i < 4; i++)
+                       readl(0xE0200F40+i*4);
+#endif
+               value = readl(S5PC110_WAKEUP_STAT);
+               writel(0xFFFF & value, S5PC110_WAKEUP_STAT);
+
+               printf("Wakeup Source: 0x%08x\n", value);
+               value = readl(S5PC110_WAKEUP_STAT);
+
+#else
                asm("b  1f\n\t"
                        ".align 5\n\t"
                        "1:\n\t"
                        "mcr p15, 0, %0, c7, c10, 5\n\t"
                        "mcr p15, 0, %0, c7, c10, 4\n\t"
                        ".word 0xe320f003" :: "r" (value));
+#endif
        } else {
                value = S5PC110_PWR_MODE_SLEEP;
                writel(value, S5PC110_PWR_MODE);
        }
 
-       printf("%s[%d] sleep success\n", __func__, __LINE__);
+       show_hw_revision();
+
+       board_sleep_resume();
        return 0;
 }
 
index 5e3d7f6..8943120 100644 (file)
@@ -265,6 +265,149 @@ init_fnc_t *init_sequence[] = {
        NULL,
 };
 
+void start_armboot_resume(void)
+{
+       init_fnc_t **init_fnc_ptr;
+       char *s;
+#if defined(CONFIG_VFD) || defined(CONFIG_LCD)
+       unsigned long addr;
+#endif
+
+       /* Pointer is writable since we allocated a register for it */
+       gd = (gd_t*)(_armboot_start - CONFIG_SYS_MALLOC_LEN - sizeof(gd_t));
+       /* compiler optimization barrier needed for GCC >= 3.4 */
+       __asm__ __volatile__("": : :"memory");
+
+       memset ((void*)gd, 0, sizeof (gd_t));
+       gd->bd = (bd_t*)((char*)gd - sizeof(bd_t));
+       memset (gd->bd, 0, sizeof (bd_t));
+
+       gd->flags |= GD_FLG_RELOC;
+
+       monitor_flash_len = _bss_start - _armboot_start;
+
+       for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {
+               if ((*init_fnc_ptr)() != 0) {
+                       hang ();
+               }
+       }
+
+#ifdef CONFIG_VFD
+#      ifndef PAGE_SIZE
+#        define PAGE_SIZE 4096
+#      endif
+       /*
+        * reserve memory for VFD display (always full pages)
+        */
+       /* bss_end is defined in the board-specific linker script */
+       addr = (_bss_end + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1);
+       vfd_setmem (addr);
+       gd->fb_base = addr;
+#endif /* CONFIG_VFD */
+
+#ifdef CONFIG_LCD
+       /* board init may have inited fb_base */
+       if (!gd->fb_base) {
+#              ifndef PAGE_SIZE
+#                define PAGE_SIZE 4096
+#              endif
+               /*
+                * reserve memory for LCD display (always full pages)
+                */
+               /* bss_end is defined in the board-specific linker script */
+               addr = (_bss_end + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1);
+               lcd_setmem (addr);
+               gd->fb_base = addr;
+       }
+#endif /* CONFIG_LCD */
+
+#if defined(CONFIG_CMD_NAND)
+       puts ("NAND:  ");
+       nand_init();            /* go init the NAND */
+#endif
+
+#if defined(CONFIG_CMD_ONENAND)
+       onenand_init();
+#endif
+
+#ifdef CONFIG_HAS_DATAFLASH
+       AT91F_DataflashInit();
+       dataflash_print_info();
+#endif
+
+       /* initialize environment */
+       env_relocate ();
+
+#ifdef CONFIG_VFD
+       /* must do this after the framebuffer is allocated */
+       drv_vfd_init();
+#endif /* CONFIG_VFD */
+
+#ifdef CONFIG_SERIAL_MULTI
+       serial_initialize();
+#endif
+
+       stdio_init_resume ();   /* get the devices list going. */
+
+#if defined(CONFIG_ARCH_MISC_INIT)
+       /* miscellaneous arch dependent initialisations */
+       arch_misc_init ();
+#endif
+
+#if defined(CONFIG_MISC_INIT_R)
+       /* miscellaneous platform dependent initialisations */
+       misc_init_r ();
+#endif
+
+       /* enable exceptions */
+       enable_interrupts ();
+
+       /* Perform network card initialisation if necessary */
+#ifdef CONFIG_DRIVER_TI_EMAC
+       /* XXX: this needs to be moved to board init */
+extern void davinci_eth_set_mac_addr (const u_int8_t *addr);
+       if (getenv ("ethaddr")) {
+               uchar enetaddr[6];
+               eth_getenv_enetaddr("ethaddr", enetaddr);
+               davinci_eth_set_mac_addr(enetaddr);
+       }
+#endif
+
+#if defined(CONFIG_DRIVER_SMC91111) || defined (CONFIG_DRIVER_LAN91C96)
+       /* XXX: this needs to be moved to board init */
+       if (getenv ("ethaddr")) {
+               uchar enetaddr[6];
+               eth_getenv_enetaddr("ethaddr", enetaddr);
+               smc_set_mac_addr(enetaddr);
+       }
+#endif /* CONFIG_DRIVER_SMC91111 || CONFIG_DRIVER_LAN91C96 */
+
+       /* Initialize from environment */
+       if ((s = getenv ("loadaddr")) != NULL) {
+               load_addr = simple_strtoul (s, NULL, 16);
+       }
+
+#ifdef BOARD_LATE_INIT
+       board_late_init ();
+#endif
+
+#ifdef CONFIG_GENERIC_MMC
+       puts ("MMC:   ");
+       mmc_initialize (gd->bd);
+#endif
+
+#ifdef CONFIG_BITBANGMII
+       bb_miiphy_init();
+#endif
+#if defined(CONFIG_CMD_NET)
+#if defined(CONFIG_NET_MULTI)
+       puts ("Net:   ");
+#endif
+       eth_initialize(gd->bd);
+#endif
+
+}
+
 void start_armboot (void)
 {
        init_fnc_t **init_fnc_ptr;