13c0e1947SKevin Wells /* 23c0e1947SKevin Wells * arch/arm/mach-lpc32xx/pm.c 33c0e1947SKevin Wells * 43c0e1947SKevin Wells * Original authors: Vitaly Wool, Dmitry Chigirev <source@mvista.com> 53c0e1947SKevin Wells * Modified by Kevin Wells <kevin.wells@nxp.com> 63c0e1947SKevin Wells * 73c0e1947SKevin Wells * 2005 (c) MontaVista Software, Inc. This file is licensed under 83c0e1947SKevin Wells * the terms of the GNU General Public License version 2. This program 93c0e1947SKevin Wells * is licensed "as is" without any warranty of any kind, whether express 103c0e1947SKevin Wells * or implied. 113c0e1947SKevin Wells */ 123c0e1947SKevin Wells 133c0e1947SKevin Wells /* 143c0e1947SKevin Wells * LPC32XX CPU and system power management 153c0e1947SKevin Wells * 16cfac337bSRoland Stigge * The LPC32XX has three CPU modes for controlling system power: run, 173c0e1947SKevin Wells * direct-run, and halt modes. When switching between halt and run modes, 183c0e1947SKevin Wells * the CPU transistions through direct-run mode. For Linux, direct-run 193c0e1947SKevin Wells * mode is not used in normal operation. Halt mode is used when the 203c0e1947SKevin Wells * system is fully suspended. 213c0e1947SKevin Wells * 223c0e1947SKevin Wells * Run mode: 233c0e1947SKevin Wells * The ARM CPU clock (HCLK_PLL), HCLK bus clock, and PCLK bus clocks are 243c0e1947SKevin Wells * derived from the HCLK PLL. The HCLK and PCLK bus rates are divided from 253c0e1947SKevin Wells * the HCLK_PLL rate. Linux runs in this mode. 263c0e1947SKevin Wells * 273c0e1947SKevin Wells * Direct-run mode: 283c0e1947SKevin Wells * The ARM CPU clock, HCLK bus clock, and PCLK bus clocks are driven from 293c0e1947SKevin Wells * SYSCLK. SYSCLK is usually around 13MHz, but may vary based on SYSCLK 303c0e1947SKevin Wells * source or the frequency of the main oscillator. In this mode, the 313c0e1947SKevin Wells * HCLK_PLL can be safely enabled, changed, or disabled. 323c0e1947SKevin Wells * 333c0e1947SKevin Wells * Halt mode: 343c0e1947SKevin Wells * SYSCLK is gated off and the CPU and system clocks are halted. 353c0e1947SKevin Wells * Peripherals based on the 32KHz oscillator clock (ie, RTC, touch, 363c0e1947SKevin Wells * key scanner, etc.) still operate if enabled. In this state, an enabled 373c0e1947SKevin Wells * system event (ie, GPIO state change, RTC match, key press, etc.) will 383c0e1947SKevin Wells * wake the system up back into direct-run mode. 393c0e1947SKevin Wells * 403c0e1947SKevin Wells * DRAM refresh 413c0e1947SKevin Wells * DRAM clocking and refresh are slightly different for systems with DDR 423c0e1947SKevin Wells * DRAM or regular SDRAM devices. If SDRAM is used in the system, the 433c0e1947SKevin Wells * SDRAM will still be accessible in direct-run mode. In DDR based systems, 4425985edcSLucas De Marchi * a transition to direct-run mode will stop all DDR accesses (no clocks). 453c0e1947SKevin Wells * Because of this, the code to switch power modes and the code to enter 463c0e1947SKevin Wells * and exit DRAM self-refresh modes must not be executed in DRAM. A small 473c0e1947SKevin Wells * section of IRAM is used instead for this. 483c0e1947SKevin Wells * 493c0e1947SKevin Wells * Suspend is handled with the following logic: 503c0e1947SKevin Wells * Backup a small area of IRAM used for the suspend code 513c0e1947SKevin Wells * Copy suspend code to IRAM 523c0e1947SKevin Wells * Transfer control to code in IRAM 533c0e1947SKevin Wells * Places DRAMs in self-refresh mode 543c0e1947SKevin Wells * Enter direct-run mode 553c0e1947SKevin Wells * Save state of HCLK_PLL PLL 563c0e1947SKevin Wells * Disable HCLK_PLL PLL 573c0e1947SKevin Wells * Enter halt mode - CPU and buses will stop 583c0e1947SKevin Wells * System enters direct-run mode when an enabled event occurs 593c0e1947SKevin Wells * HCLK PLL state is restored 603c0e1947SKevin Wells * Run mode is entered 613c0e1947SKevin Wells * DRAMS are placed back into normal mode 623c0e1947SKevin Wells * Code execution returns from IRAM 633c0e1947SKevin Wells * IRAM code are used for suspend is restored 643c0e1947SKevin Wells * Suspend mode is exited 653c0e1947SKevin Wells */ 663c0e1947SKevin Wells 673c0e1947SKevin Wells #include <linux/suspend.h> 683c0e1947SKevin Wells #include <linux/io.h> 693c0e1947SKevin Wells #include <linux/slab.h> 703c0e1947SKevin Wells 713c0e1947SKevin Wells #include <asm/cacheflush.h> 723c0e1947SKevin Wells 733c0e1947SKevin Wells #include <mach/hardware.h> 743c0e1947SKevin Wells #include <mach/platform.h> 753c0e1947SKevin Wells #include "common.h" 763c0e1947SKevin Wells 773c0e1947SKevin Wells #define TEMP_IRAM_AREA IO_ADDRESS(LPC32XX_IRAM_BASE) 783c0e1947SKevin Wells 793c0e1947SKevin Wells /* 803c0e1947SKevin Wells * Both STANDBY and MEM suspend states are handled the same with no 813c0e1947SKevin Wells * loss of CPU or memory state 823c0e1947SKevin Wells */ 833c0e1947SKevin Wells static int lpc32xx_pm_enter(suspend_state_t state) 843c0e1947SKevin Wells { 853c0e1947SKevin Wells int (*lpc32xx_suspend_ptr) (void); 863c0e1947SKevin Wells void *iram_swap_area; 873c0e1947SKevin Wells 883c0e1947SKevin Wells /* Allocate some space for temporary IRAM storage */ 893c0e1947SKevin Wells iram_swap_area = kmalloc(lpc32xx_sys_suspend_sz, GFP_KERNEL); 90*ac04fd65SMarkus Elfring if (!iram_swap_area) 913c0e1947SKevin Wells return -ENOMEM; 923c0e1947SKevin Wells 933c0e1947SKevin Wells /* Backup a small area of IRAM used for the suspend code */ 943c0e1947SKevin Wells memcpy(iram_swap_area, (void *) TEMP_IRAM_AREA, 953c0e1947SKevin Wells lpc32xx_sys_suspend_sz); 963c0e1947SKevin Wells 973c0e1947SKevin Wells /* 983c0e1947SKevin Wells * Copy code to suspend system into IRAM. The suspend code 993c0e1947SKevin Wells * needs to run from IRAM as DRAM may no longer be available 1003c0e1947SKevin Wells * when the PLL is stopped. 1013c0e1947SKevin Wells */ 1023c0e1947SKevin Wells memcpy((void *) TEMP_IRAM_AREA, &lpc32xx_sys_suspend, 1033c0e1947SKevin Wells lpc32xx_sys_suspend_sz); 1043c0e1947SKevin Wells flush_icache_range((unsigned long)TEMP_IRAM_AREA, 1053c0e1947SKevin Wells (unsigned long)(TEMP_IRAM_AREA) + lpc32xx_sys_suspend_sz); 1063c0e1947SKevin Wells 1073c0e1947SKevin Wells /* Transfer to suspend code in IRAM */ 1083c0e1947SKevin Wells lpc32xx_suspend_ptr = (void *) TEMP_IRAM_AREA; 1093c0e1947SKevin Wells flush_cache_all(); 1103c0e1947SKevin Wells (void) lpc32xx_suspend_ptr(); 1113c0e1947SKevin Wells 1123c0e1947SKevin Wells /* Restore original IRAM contents */ 1133c0e1947SKevin Wells memcpy((void *) TEMP_IRAM_AREA, iram_swap_area, 1143c0e1947SKevin Wells lpc32xx_sys_suspend_sz); 1153c0e1947SKevin Wells 1163c0e1947SKevin Wells kfree(iram_swap_area); 1173c0e1947SKevin Wells 1183c0e1947SKevin Wells return 0; 1193c0e1947SKevin Wells } 1203c0e1947SKevin Wells 1212f55ac07SLionel Debroux static const struct platform_suspend_ops lpc32xx_pm_ops = { 1223c0e1947SKevin Wells .valid = suspend_valid_only_mem, 1233c0e1947SKevin Wells .enter = lpc32xx_pm_enter, 1243c0e1947SKevin Wells }; 1253c0e1947SKevin Wells 1263c0e1947SKevin Wells #define EMC_DYN_MEM_CTRL_OFS 0x20 1273c0e1947SKevin Wells #define EMC_SRMMC (1 << 3) 1283c0e1947SKevin Wells #define EMC_CTRL_REG io_p2v(LPC32XX_EMC_BASE + EMC_DYN_MEM_CTRL_OFS) 1293c0e1947SKevin Wells static int __init lpc32xx_pm_init(void) 1303c0e1947SKevin Wells { 1313c0e1947SKevin Wells /* 1323c0e1947SKevin Wells * Setup SDRAM self-refresh clock to automatically disable o 1333c0e1947SKevin Wells * start of self-refresh. This only needs to be done once. 1343c0e1947SKevin Wells */ 1353c0e1947SKevin Wells __raw_writel(__raw_readl(EMC_CTRL_REG) | EMC_SRMMC, EMC_CTRL_REG); 1363c0e1947SKevin Wells 1373c0e1947SKevin Wells suspend_set_ops(&lpc32xx_pm_ops); 1383c0e1947SKevin Wells 1393c0e1947SKevin Wells return 0; 1403c0e1947SKevin Wells } 1413c0e1947SKevin Wells arch_initcall(lpc32xx_pm_init); 142