diff options
author | Frank Li <Frank.Li@freescale.com> | 2011-02-22 17:34:58 +0800 |
---|---|---|
committer | Jason Liu <r64343@freescale.com> | 2012-07-20 13:10:19 +0800 |
commit | da391dd9bd62d2b471e4730fbfb32317c701067d (patch) | |
tree | 22ce1837a086aef80f1f44610d0016e74f04d7fc /arch/arm/mach-mx5/system.c | |
parent | bf63283de4230e999e50f21c11ca9ad8d0ec6c77 (diff) |
ENGR00141217-3 MX53 MSL part upgrade to 2.6.38
imx51_babbage:
imx53_smd: add i2c device
imx53_smd: add i2c board device info
imx53_smd: add esdhc device support
imx53_smd: Add SRTC devices
imx53_smd: enable the AHCI SATA
imx53_smd: Add GPIO Keypad support
imx53_ard: enable ARD board bootup
imx53_ard: add ethernet pin mux
imx53_ard: add smsc911x device
imx53_loco: add i2c device
imx53_loco: change sii902x i2c device
imx53_loco: register v4l2 output device
imx53_loco: add srtc device
imx53_loco: enable the AHCI SATA
imx53_loco: Add GPIO Keypad support
imx53_evk: add evk and arm2 boards io setting and set up display
imx5: add ipu\vpu
imx5: clock.c: remove RATE_PROPAGATES
imx5: Add clock, dvfs, busfreq, sdram_autogating support.
imx5: fix warnings on boot
imx5: add v4l2 device
imx5: add board_is_rev support
imx5: Add sdma support for i.Mx53 and i.Mx51
imx5: add p1003
imx5: add ipuv3
imx5: add sata
imx5: add pmic board files
imx5: add pm function
imx5: add iram config
imx5: add gpu
imx5: fix clock debug enable_count error
imx53: add gpio irq support for mx53
imx53: change PWM backlight device register method to dynamic
imx53: change v4l2 device register method to dynamic
imx53: add vpu devices support
imx53: add dvfs-core and busfreq devices register method
imx53: Add usb devices
imx53: add i2c pad settings
imx53: add ssi support
Signed-off-by: Richard Zhao <richard.zhao@freescale.com>
Signed-off-by: Frank Li <Frank.Li@freescale.com>
Signed-off-by: Jason Chen <b02280@freescale.com>
Signed-off-by: Zeng Zhaoming <b32542@freescale.com>
Signed-off-by: Richard Zhu <r65037@freescale.com>
Signed-off-by: Zhou Jingyu <Jingyu.Zhou@freescale.com>
Signed-off-by: Zhang Yan <b34916@freescale.com>
Diffstat (limited to 'arch/arm/mach-mx5/system.c')
-rwxr-xr-x[-rw-r--r--] | arch/arm/mach-mx5/system.c | 202 |
1 files changed, 201 insertions, 1 deletions
diff --git a/arch/arm/mach-mx5/system.c b/arch/arm/mach-mx5/system.c index 76ae8dc33e00..70667446cff3 100644..100755 --- a/arch/arm/mach-mx5/system.c +++ b/arch/arm/mach-mx5/system.c @@ -17,7 +17,52 @@ /* set cpu low power mode before WFI instruction. This function is called * mx5 because it can be used for mx50, mx51, and mx53.*/ -void mx5_cpu_lp_set(enum mxc_cpu_pwr_mode mode) + +#include <linux/kernel.h> +#include <linux/clk.h> +#include <linux/platform_device.h> +#include <linux/regulator/consumer.h> +#include <asm/io.h> +#include <mach/common.h> +#include <mach/hardware.h> +#include <mach/clock.h> +#include <asm/proc-fns.h> +#include <asm/system.h> +#include "crm_regs.h" + +/*! + * @defgroup MSL_MX51 i.MX51 Machine Specific Layer (MSL) + */ + +/*! + * @file mach-mx51/system.c + * @brief This file contains idle and reset functions. + * + * @ingroup MSL_MX51 + */ + +extern int mxc_jtag_enabled; +extern int iram_ready; +extern int dvfs_core_is_active; +extern void __iomem *ccm_base; +extern void __iomem *databahn_base; +extern int low_bus_freq_mode; +extern void (*wait_in_iram)(void *ccm_addr, void *databahn_addr); +extern void mx50_wait(u32 ccm_base, u32 databahn_addr); +extern void stop_dvfs(void); +extern void *wait_in_iram_base; +extern void __iomem *apll_base; + +static struct clk *gpc_dvfs_clk; +static struct regulator *vpll; +static struct clk *pll1_sw_clk; +static struct clk *osc; +static struct clk *pll1_main_clk; +static struct clk *ddr_clk ; +static int dvfs_core_paused; + +/* set cpu low power mode before WFI instruction */ +void mxc_cpu_lp_set(enum mxc_cpu_pwr_mode mode) { u32 plat_lpc, arm_srpgcr, ccm_clpcr; u32 empgc0, empgc1; @@ -82,3 +127,158 @@ void mx5_cpu_lp_set(enum mxc_cpu_pwr_mode mode) __raw_writel(empgc1, MXC_SRPG_EMPGC1_SRPGCR); } } + +/* To change the idle power mode, need to set arch_idle_mode to a different + * power mode as in enum mxc_cpu_pwr_mode. + * May allow dynamically changing the idle mode. + */ +static int arch_idle_mode = WAIT_UNCLOCKED_POWER_OFF; +/*! + * This function puts the CPU into idle mode. It is called by default_idle() + * in process.c file. + */ +void arch_idle(void) +{ + if (likely(!mxc_jtag_enabled)) { + if (ddr_clk == NULL) + ddr_clk = clk_get(NULL, "ddr_clk"); + if (gpc_dvfs_clk == NULL) + gpc_dvfs_clk = clk_get(NULL, "gpc_dvfs_clk"); + /* gpc clock is needed for SRPG */ + clk_enable(gpc_dvfs_clk); + mxc_cpu_lp_set(arch_idle_mode); + + if (cpu_is_mx50() && (clk_get_usecount(ddr_clk) == 0)) { + memcpy(wait_in_iram_base, mx50_wait, SZ_4K); + wait_in_iram = (void *)wait_in_iram_base; + if (low_bus_freq_mode) { + u32 reg, cpu_podf; + + reg = __raw_readl(apll_base + 0x50); + reg = 0x120490; + __raw_writel(reg, apll_base + 0x50); + reg = __raw_readl(apll_base + 0x80); + reg |= 1; + __raw_writel(reg, apll_base + 0x80); + + /* Move ARM to be sourced from 24MHz XTAL. + * when ARM is in WFI. + */ + if (pll1_sw_clk == NULL) + pll1_sw_clk = clk_get(NULL, + "pll1_sw_clk"); + if (osc == NULL) + osc = clk_get(NULL, "lp_apm"); + if (pll1_main_clk == NULL) + pll1_main_clk = clk_get(NULL, + "pll1_main_clk"); + + clk_set_parent(pll1_sw_clk, osc); + /* Set the ARM-PODF divider to 1. */ + cpu_podf = __raw_readl(MXC_CCM_CACRR); + __raw_writel(0x01, MXC_CCM_CACRR); + + wait_in_iram(ccm_base, databahn_base); + + /* Set the ARM-POD divider back + * to the original. + */ + __raw_writel(cpu_podf, MXC_CCM_CACRR); + clk_set_parent(pll1_sw_clk, pll1_main_clk); + } else + wait_in_iram(ccm_base, databahn_base); + } else + cpu_do_idle(); + clk_disable(gpc_dvfs_clk); + clk_put(ddr_clk); + } +} + +static int __mxs_reset_block(void __iomem *hwreg, int just_enable) +{ + u32 c; + int timeout; + + /* the process of software reset of IP block is done + in several steps: + + - clear SFTRST and wait for block is enabled; + - clear clock gating (CLKGATE bit); + - set the SFTRST again and wait for block is in reset; + - clear SFTRST and wait for reset completion. + */ + c = __raw_readl(hwreg); + c &= ~(1 << 31); /* clear SFTRST */ + __raw_writel(c, hwreg); + for (timeout = 1000000; timeout > 0; timeout--) + /* still in SFTRST state ? */ + if ((__raw_readl(hwreg) & (1 << 31)) == 0) + break; + if (timeout <= 0) { + printk(KERN_ERR "%s(%p): timeout when enabling\n", + __func__, hwreg); + return -ETIME; + } + + c = __raw_readl(hwreg); + c &= ~(1 << 30); /* clear CLKGATE */ + __raw_writel(c, hwreg); + + if (!just_enable) { + c = __raw_readl(hwreg); + c |= (1 << 31); /* now again set SFTRST */ + __raw_writel(c, hwreg); + for (timeout = 1000000; timeout > 0; timeout--) + /* poll until CLKGATE set */ + if (__raw_readl(hwreg) & (1 << 30)) + break; + if (timeout <= 0) { + printk(KERN_ERR "%s(%p): timeout when resetting\n", + __func__, hwreg); + return -ETIME; + } + + c = __raw_readl(hwreg); + c &= ~(1 << 31); /* clear SFTRST */ + __raw_writel(c, hwreg); + for (timeout = 1000000; timeout > 0; timeout--) + /* still in SFTRST state ? */ + if ((__raw_readl(hwreg) & (1 << 31)) == 0) + break; + if (timeout <= 0) { + printk(KERN_ERR "%s(%p): timeout when enabling " + "after reset\n", __func__, hwreg); + return -ETIME; + } + + c = __raw_readl(hwreg); + c &= ~(1 << 30); /* clear CLKGATE */ + __raw_writel(c, hwreg); + } + for (timeout = 1000000; timeout > 0; timeout--) + /* still in SFTRST state ? */ + if ((__raw_readl(hwreg) & (1 << 30)) == 0) + break; + + if (timeout <= 0) { + printk(KERN_ERR "%s(%p): timeout when unclockgating\n", + __func__, hwreg); + return -ETIME; + } + + return 0; +} + +int mxs_reset_block(void __iomem *hwreg, int just_enable) +{ + int try = 10; + int r; + + while (try--) { + r = __mxs_reset_block(hwreg, just_enable); + if (!r) + break; + pr_debug("%s: try %d failed\n", __func__, 10 - try); + } + return r; +} |