| pm-upd2.patch | | Files affected: | Documentation/arm/Samsung-S3C24XX/Suspend.txt | 24 21 + 3 - 0 ! | arch/arm/mach-s3c2410/pm.c | 92 78 + 14 - 0 ! | arch/arm/mach-s3c2410/sleep.S | 14 13 + 1 - 0 ! | include/asm-arm/arch-s3c2410/regs-gpio.h | 2 1 + 1 - 0 ! | 4 files changed, 113 insertions(+), 19 deletions(-) | | Ben Dooks, Fri, 05 Nov 2004 12:50:47 +0000 diff -urN -X ../dontdiff linux-2.6.10-rc1-bk14/Documentation/arm/Samsung-S3C24XX/Suspend.txt linux-2.6.10-rc1-bk14-serial1-work/Documentation/arm/Samsung-S3C24XX/Suspend.txt --- linux-2.6.10-rc1-bk14/Documentation/arm/Samsung-S3C24XX/Suspend.txt 2004-11-04 16:58:44.000000000 +0000 +++ linux-2.6.10-rc1-bk14-serial1-work/Documentation/arm/Samsung-S3C24XX/Suspend.txt 2004-11-05 12:34:37.000000000 +0000 @@ -33,7 +33,8 @@ code to resume Linux operation. GSTATUS4 is currently left alone by the sleep code, and is free to - use for any other purposes. + use for any other purposes (for example, the EB2410ITX uses this to + save memory configuration in). Machine Support @@ -41,9 +42,9 @@ The machine specific functions must call the s3c2410_pm_init() function to say that it's bootloader is capable of resuming. This can be as - simple as adding the following to the file: + simple as adding the following to the machine's definition: - late_initcall(s3c2410_pm_init); + INITMACHINE(s3c2410_pm_init) A board can do its own setup before calling s3c2410_pm_init, if it needs to setup anything else for power management support. @@ -52,6 +53,23 @@ saving the resume address, if your board requires it, then contact the maintainer and discuss what is required. + Note, the origianal method of adding an late_initcall() is wrong, + and will end up initialising all compiled machine's pm init! + + +Debugging +--------- + + There are several important things to rember when using PM suspend: + + 1) The uart drivers will disable the clocks to the UART blocks when + suspending, which means that use of printascii() or similar direct + access to the UARTs will cause the debug to stop. + + 2) Whilst the pm code itself will attempt to re-enabled the UART clocks, + care should be taken that any external clock sources that the UARTs + rely on are still enabled at that point + Configuration ------------- --- linux-2.6.10-rc1-bk14/arch/arm/mach-s3c2410/sleep.S 2004-11-04 16:58:44.000000000 +0000 +++ linux-2.6.10-rc1-bk14-serial1-work/arch/arm/mach-s3c2410/sleep.S 2004-11-05 12:34:37.000000000 +0000 @@ -35,7 +35,10 @@ #include #include -#define CONFIG_DEBUG_RESUME +/* CONFIG_DEBUG_RESUME is dangerous if your bootloader does not + * reset the UART configuration, only enable if you really need this! +*/ +//#define CONFIG_DEBUG_RESUME .text @@ -133,6 +136,15 @@ mov r2, #S3C2410_PA_UART & 0xff000000 orr r2, r2, #S3C2410_PA_UART & 0xff000 +#if 0 + /* SMDK2440 LED set */ + mov r14, #S3C2410_PA_GPIO + ldr r12, [ r14, #0x54 ] + bic r12, r12, #3<<4 + orr r12, r12, #1<<7 + str r12, [ r14, #0x54 ] +#endif + #ifdef CONFIG_DEBUG_RESUME mov r3, #'L' strb r3, [ r2, #S3C2410_UTXH ] --- linux-2.6.10-rc1-bk14/arch/arm/mach-s3c2410/pm.c 2004-11-04 16:58:44.000000000 +0000 +++ linux-2.6.10-rc1-bk14-serial1-work/arch/arm/mach-s3c2410/pm.c 2004-11-05 12:36:04.000000000 +0000 @@ -23,6 +23,7 @@ * * Parts based on arch/arm/mach-pxa/pm.c * + * Thanks to Dimitry Andric for debugging */ #include @@ -33,10 +34,12 @@ #include #include #include +#include #include #include +#include #include #include #include @@ -68,7 +71,21 @@ static struct sleep_save core_save[] = { SAVE_ITEM(S3C2410_LOCKTIME), - SAVE_ITEM(S3C2410_CLKCON) + SAVE_ITEM(S3C2410_CLKCON), + + /* we restore the timings here, with the proviso that the board + * brings the system up in an slower, or equal frequency setting + * to the original system. + * + * if we cannot guarantee this, then things are going to go very + * wrong here, as we modify the refresh and both pll settings. + */ + + SAVE_ITEM(S3C2410_REFRESH), + SAVE_ITEM(S3C2410_MPLLCON), + SAVE_ITEM(S3C2410_UPLLCON), + SAVE_ITEM(S3C2410_CLKDIVN), + SAVE_ITEM(S3C2410_CLKSLOW), }; /* this lot should be really saved by the IRQ code */ @@ -115,6 +132,20 @@ }; #ifdef CONFIG_S3C2410_PM_DEBUG + +#define SAVE_UART(va) \ + SAVE_ITEM((va) + S3C2410_ULCON), \ + SAVE_ITEM((va) + S3C2410_UCON), \ + SAVE_ITEM((va) + S3C2410_UFCON), \ + SAVE_ITEM((va) + S3C2410_UMCON), \ + SAVE_ITEM((va) + S3C2410_UBRDIV) + +static struct sleep_save uart_save[] = { + SAVE_UART(S3C2410_VA_UART0), + SAVE_UART(S3C2410_VA_UART1), + SAVE_UART(S3C2410_VA_UART2), +}; + /* debug * * we send the debug to printascii() to allow it to be seen if the @@ -135,10 +166,24 @@ printascii(buff); } +static void s3c2410_pm_debug_init(void) +{ + unsigned long tmp = __raw_readl(S3C2410_CLKCON); + + /* re-start uart clocks */ + tmp |= S3C2410_CLKCON_UART0; + tmp |= S3C2410_CLKCON_UART1; + tmp |= S3C2410_CLKCON_UART2; + + __raw_writel(tmp, S3C2410_CLKCON); + udelay(10); +} #define DBG(fmt...) pm_dbg(fmt) #else #define DBG(fmt...) printk(KERN_DEBUG fmt) + +#define s3c2410_pm_debug_init() do { } while(0) #endif #if defined(CONFIG_S3C2410_PM_CHECK) && CONFIG_S3C2410_PM_CHECK_CHUNKSIZE != 0 @@ -329,6 +374,9 @@ } #else + +static struct sleep_save uart_save[] = {}; + #define s3c2410_pm_check_prepare() do { } while(0) #define s3c2410_pm_check_restore() do { } while(0) #define s3c2410_pm_check_store() do { } while(0) @@ -344,12 +392,20 @@ } } +/* s3c2410_pm_do_restore + * + * restore the system from the given list of saved registers + * + * Note, we do not use DBG() in here, as the system may not have + * restore the UARTs state yet +*/ static void s3c2410_pm_do_restore(struct sleep_save *ptr, int count) { for (; count > 0; count--, ptr++) { - DBG("restore %08lx (restore %08lx, current %08x)\n", - ptr->reg, ptr->val, __raw_readl(ptr->reg)); + printk(KERN_DEBUG "restore %08lx (restore %08lx, was %08x)\n", + ptr->reg, ptr->val, __raw_readl(ptr->reg)); + __raw_writel(ptr->val, ptr->reg); } } @@ -434,11 +490,15 @@ * central control for sleep/resume process */ -static int s3c2410_pm_enter(u32 state) +static int s3c2410_pm_enter(suspend_state_t state) { unsigned long regs_save[16]; unsigned long tmp; + /* ensure the debug is initialised (if enabled) */ + + s3c2410_pm_debug_init(); + DBG("s3c2410_pm_enter(%d)\n", state); if (state != PM_SUSPEND_MEM) { @@ -480,6 +540,7 @@ s3c2410_pm_do_save(gpio_save, ARRAY_SIZE(gpio_save)); s3c2410_pm_do_save(irq_save, ARRAY_SIZE(irq_save)); s3c2410_pm_do_save(core_save, ARRAY_SIZE(core_save)); + s3c2410_pm_do_save(uart_save, ARRAY_SIZE(uart_save)); /* set the irq configuration for wake */ @@ -493,7 +554,7 @@ /* ack any outstanding external interrupts before we go to sleep */ - __raw_writel(S3C2410_EINTPEND, __raw_readl(S3C2410_EINTPEND)); + __raw_writel(__raw_readl(S3C2410_EINTPEND), S3C2410_EINTPEND); /* flush cache back to ram */ @@ -512,9 +573,18 @@ /* unset the return-from-sleep flag, to ensure reset */ tmp = __raw_readl(S3C2410_GSTATUS2); - tmp &= S3C2410_GSTATUs2_OFFRESET; + tmp &= S3C2410_GSTATUS2_OFFRESET; __raw_writel(tmp, S3C2410_GSTATUS2); + /* restore the system state */ + + s3c2410_pm_do_restore(core_save, ARRAY_SIZE(core_save)); + s3c2410_pm_do_restore(gpio_save, ARRAY_SIZE(gpio_save)); + s3c2410_pm_do_restore(irq_save, ARRAY_SIZE(irq_save)); + s3c2410_pm_do_restore(uart_save, ARRAY_SIZE(uart_save)); + + s3c2410_pm_debug_init(); + /* check what irq (if any) restored the system */ DBG("post sleep: IRQs 0x%08x, 0x%08x\n", @@ -527,12 +597,6 @@ s3c2410_pm_show_resume_irqs(IRQ_EINT4-4, __raw_readl(S3C2410_EINTPEND), s3c_irqwake_eintmask); - DBG("post sleep, restoring state...\n"); - - s3c2410_pm_do_restore(core_save, ARRAY_SIZE(core_save)); - s3c2410_pm_do_restore(gpio_save, ARRAY_SIZE(gpio_save)); - s3c2410_pm_do_restore(irq_save, ARRAY_SIZE(irq_save)); - DBG("post sleep, preparing to return\n"); s3c2410_pm_check_restore(); @@ -546,7 +610,7 @@ /* * Called after processes are frozen, but before we shut down devices. */ -static int s3c2410_pm_prepare(u32 state) +static int s3c2410_pm_prepare(suspend_state_t state) { return 0; } @@ -554,7 +618,7 @@ /* * Called after devices are re-setup, but before processes are thawed. */ -static int s3c2410_pm_finish(u32 state) +static int s3c2410_pm_finish(suspend_state_t state) { return 0; } --- linux-2.6.10-rc1-bk14/include/asm-arm/arch-s3c2410/regs-gpio.h 2004-10-25 09:53:38.000000000 +0100 +++ linux-2.6.10-rc1-bk14-serial1-work/include/asm-arm/arch-s3c2410/regs-gpio.h 2004-11-05 12:34:37.000000000 +0000 @@ -812,7 +812,7 @@ #define S3C2410_GSTATUS1_2440 (0x32440000) #define S3C2410_GSTATUS2_WTRESET (1<<2) -#define S3C2410_GSTATUs2_OFFRESET (1<<1) +#define S3C2410_GSTATUS2_OFFRESET (1<<1) #define S3C2410_GSTATUS2_PONRESET (1<<0) #endif /* __ASM_ARCH_REGS_GPIO_H */