diff options
author | Eric Miao <eric.miao@linaro.org> | 2012-01-12 10:21:31 +0800 |
---|---|---|
committer | Eric Miao <eric.miao@linaro.org> | 2012-01-12 10:21:31 +0800 |
commit | a48f11ebb784e84f06ddb0e1a181a7379ee8915e (patch) | |
tree | e9ba399a0f41633c390a8160c4ec564aae2a0584 | |
parent | 9362902ae4bfa1ee0a67e715b506e19eb980f835 (diff) | |
parent | e4ed928467699690d1d67e96961c1f11644174ee (diff) |
Merge branch 'topic/lt-3.2-imx6-pm' into lt-3.2-imx6
* topic/lt-3.2-imx6-pm:
ARM: 7198/1: arm/imx6: add restart support for imx6q
ARM: reset: implement soft_restart for jumping to a physical address
ARM: restart: only perform setup for restart when soft-restarting
ARM: restart: remove argument to setup_mm_for_reboot()
ARM: restart: move reboot failure handing into machine_restart()
ARM: restart: add restart hook to machine_desc record
ARM: lib: add call_with_stack function for safely changing stack
ARM: imx6: remove __CPUINIT annotation from v7_invalidate_l1
ARM: imx6q: add cpu suspend/resume support in IRAM
ARM: imx6q: add compatible name of iomuxc
tty: serial: imx: Allow UART to be a source for wakeup
40 files changed, 696 insertions, 68 deletions
diff --git a/arch/arm/boot/dts/imx6q.dtsi b/arch/arm/boot/dts/imx6q.dtsi index 263e8f3664b..2b255ae12b8 100644 --- a/arch/arm/boot/dts/imx6q.dtsi +++ b/arch/arm/boot/dts/imx6q.dtsi @@ -386,6 +386,7 @@ }; iomuxc@020e0000 { + compatible = "fsl,imx6q-iomuxc"; reg = <0x020e0000 0x4000>; }; diff --git a/arch/arm/include/asm/mach/arch.h b/arch/arm/include/asm/mach/arch.h index 2b0efc3104a..61ae6bb42c5 100644 --- a/arch/arm/include/asm/mach/arch.h +++ b/arch/arm/include/asm/mach/arch.h @@ -46,6 +46,7 @@ struct machine_desc { #ifdef CONFIG_MULTI_IRQ_HANDLER void (*handle_irq)(struct pt_regs *); #endif + void (*restart)(char, const char *); }; /* diff --git a/arch/arm/include/asm/system.h b/arch/arm/include/asm/system.h index 984014b9264..fe7de7571ba 100644 --- a/arch/arm/include/asm/system.h +++ b/arch/arm/include/asm/system.h @@ -101,6 +101,7 @@ extern int __pure cpu_architecture(void); extern void cpu_init(void); void arm_machine_restart(char mode, const char *cmd); +void soft_restart(unsigned long); extern void (*arm_pm_restart)(char str, const char *cmd); #define UDBG_UNDEFINED (1 << 0) diff --git a/arch/arm/kernel/machine_kexec.c b/arch/arm/kernel/machine_kexec.c index e59bbd496c3..29620b632ed 100644 --- a/arch/arm/kernel/machine_kexec.c +++ b/arch/arm/kernel/machine_kexec.c @@ -16,7 +16,7 @@ extern const unsigned char relocate_new_kernel[]; extern const unsigned int relocate_new_kernel_size; -extern void setup_mm_for_reboot(char mode); +extern void setup_mm_for_reboot(void); extern unsigned long kexec_start_address; extern unsigned long kexec_indirection_page; @@ -113,7 +113,7 @@ void machine_kexec(struct kimage *image) kexec_reinit(); local_irq_disable(); local_fiq_disable(); - setup_mm_for_reboot(0); /* mode is not used, so just pass 0*/ + setup_mm_for_reboot(); flush_cache_all(); outer_flush_all(); outer_disable(); diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c index 3d0c6fb74ae..423bb201945 100644 --- a/arch/arm/kernel/process.c +++ b/arch/arm/kernel/process.c @@ -57,7 +57,7 @@ static const char *isa_modes[] = { "ARM" , "Thumb" , "Jazelle", "ThumbEE" }; -extern void setup_mm_for_reboot(char mode); +extern void setup_mm_for_reboot(void); static volatile int hlt_counter; @@ -92,18 +92,24 @@ static int __init hlt_setup(char *__unused) __setup("nohlt", nohlt_setup); __setup("hlt", hlt_setup); -void arm_machine_restart(char mode, const char *cmd) +extern void call_with_stack(void (*fn)(void *), void *arg, void *sp); +typedef void (*phys_reset_t)(unsigned long); + +/* + * A temporary stack to use for CPU reset. This is static so that we + * don't clobber it with the identity mapping. When running with this + * stack, any references to the current task *will not work* so you + * should really do as little as possible before jumping to your reset + * code. + */ +static u64 soft_restart_stack[16]; + +static void __soft_restart(void *addr) { - /* Disable interrupts first */ - local_irq_disable(); - local_fiq_disable(); + phys_reset_t phys_reset; - /* - * Tell the mm system that we are going to reboot - - * we may need it to insert some 1:1 mappings so that - * soft boot works. - */ - setup_mm_for_reboot(mode); + /* Take out a flat memory mapping. */ + setup_mm_for_reboot(); /* Clean and invalidate caches */ flush_cache_all(); @@ -114,18 +120,41 @@ void arm_machine_restart(char mode, const char *cmd) /* Push out any further dirty data, and ensure cache is empty */ flush_cache_all(); - /* - * Now call the architecture specific reboot code. - */ - arch_reset(mode, cmd); + /* Switch to the identity mapping. */ + phys_reset = (phys_reset_t)(unsigned long)virt_to_phys(cpu_reset); + phys_reset((unsigned long)addr); - /* - * Whoops - the architecture was unable to reboot. - * Tell the user! - */ - mdelay(1000); - printk("Reboot failed -- System halted\n"); - while (1); + /* Should never get here. */ + BUG(); +} + +void soft_restart(unsigned long addr) +{ + u64 *stack = soft_restart_stack + ARRAY_SIZE(soft_restart_stack); + + /* Disable interrupts first */ + local_irq_disable(); + local_fiq_disable(); + + /* Disable the L2 if we're the last man standing. */ + if (num_online_cpus() == 1) + outer_disable(); + + /* Change to the new stack and continue with the reset. */ + call_with_stack(__soft_restart, (void *)addr, (void *)stack); + + /* Should never get here. */ + BUG(); +} + +void arm_machine_restart(char mode, const char *cmd) +{ + /* Disable interrupts first */ + local_irq_disable(); + local_fiq_disable(); + + /* Call the architecture specific reboot code. */ + arch_reset(mode, cmd); } /* @@ -253,7 +282,15 @@ void machine_power_off(void) void machine_restart(char *cmd) { machine_shutdown(); + arm_pm_restart(reboot_mode, cmd); + + /* Give a grace period for failure to restart of 1s */ + mdelay(1000); + + /* Whoops - the platform was unable to reboot. Tell the user! */ + printk("Reboot failed -- System halted\n"); + while (1); } void __show_regs(struct pt_regs *regs) diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c index 8fc2c8fcbdc..d662dca774d 100644 --- a/arch/arm/kernel/setup.c +++ b/arch/arm/kernel/setup.c @@ -928,6 +928,9 @@ void __init setup_arch(char **cmdline_p) paging_init(mdesc); request_standard_resources(mdesc); + if (mdesc->restart) + arm_pm_restart = mdesc->restart; + unflatten_device_tree(); #ifdef CONFIG_SMP diff --git a/arch/arm/lib/Makefile b/arch/arm/lib/Makefile index cf73a7f742d..0ade0acc1ed 100644 --- a/arch/arm/lib/Makefile +++ b/arch/arm/lib/Makefile @@ -13,7 +13,8 @@ lib-y := backtrace.o changebit.o csumipv6.o csumpartial.o \ testchangebit.o testclearbit.o testsetbit.o \ ashldi3.o ashrdi3.o lshrdi3.o muldi3.o \ ucmpdi2.o lib1funcs.o div64.o \ - io-readsb.o io-writesb.o io-readsl.o io-writesl.o + io-readsb.o io-writesb.o io-readsl.o io-writesl.o \ + call_with_stack.o mmu-y := clear_user.o copy_page.o getuser.o putuser.o diff --git a/arch/arm/lib/call_with_stack.S b/arch/arm/lib/call_with_stack.S new file mode 100644 index 00000000000..916c80f13ae --- /dev/null +++ b/arch/arm/lib/call_with_stack.S @@ -0,0 +1,44 @@ +/* + * arch/arm/lib/call_with_stack.S + * + * Copyright (C) 2011 ARM Ltd. + * Written by Will Deacon <will.deacon@arm.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <linux/linkage.h> +#include <asm/assembler.h> + +/* + * void call_with_stack(void (*fn)(void *), void *arg, void *sp) + * + * Change the stack to that pointed at by sp, then invoke fn(arg) with + * the new stack. + */ +ENTRY(call_with_stack) + str sp, [r2, #-4]! + str lr, [r2, #-4]! + + mov sp, r2 + mov r2, r0 + mov r0, r1 + + adr lr, BSYM(1f) + mov pc, r2 + +1: ldr lr, [sp] + ldr sp, [sp, #4] + mov pc, lr +ENDPROC(call_with_stack) diff --git a/arch/arm/mach-clps711x/include/mach/system.h b/arch/arm/mach-clps711x/include/mach/system.h index f916cd7a477..6c119937d39 100644 --- a/arch/arm/mach-clps711x/include/mach/system.h +++ b/arch/arm/mach-clps711x/include/mach/system.h @@ -34,7 +34,7 @@ static inline void arch_idle(void) static inline void arch_reset(char mode, const char *cmd) { - cpu_reset(0); + soft_restart(0); } #endif diff --git a/arch/arm/mach-ebsa110/include/mach/system.h b/arch/arm/mach-ebsa110/include/mach/system.h index 9a26245bf1f..0d5df72a03f 100644 --- a/arch/arm/mach-ebsa110/include/mach/system.h +++ b/arch/arm/mach-ebsa110/include/mach/system.h @@ -34,6 +34,6 @@ static inline void arch_idle(void) asm volatile ("mcr p15, 0, ip, c15, c1, 2" : : : "cc"); } -#define arch_reset(mode, cmd) cpu_reset(0x80000000) +#define arch_reset(mode, cmd) soft_restart(0x80000000) #endif diff --git a/arch/arm/mach-footbridge/include/mach/system.h b/arch/arm/mach-footbridge/include/mach/system.h index 0b293156620..249f895910f 100644 --- a/arch/arm/mach-footbridge/include/mach/system.h +++ b/arch/arm/mach-footbridge/include/mach/system.h @@ -24,7 +24,7 @@ static inline void arch_reset(char mode, const char *cmd) /* * Jump into the ROM */ - cpu_reset(0x41000000); + soft_restart(0x41000000); } else { if (machine_is_netwinder()) { /* open up the SuperIO chip diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile index f5920c24f7d..2901584d47f 100644 --- a/arch/arm/mach-imx/Makefile +++ b/arch/arm/mach-imx/Makefile @@ -73,5 +73,5 @@ obj-$(CONFIG_LOCAL_TIMERS) += localtimer.o obj-$(CONFIG_SOC_IMX6Q) += clock-imx6q.o mach-imx6q.o ifeq ($(CONFIG_PM),y) -obj-$(CONFIG_SOC_IMX6Q) += pm-imx6q.o +obj-$(CONFIG_SOC_IMX6Q) += pm-imx6q.o suspend-imx6q.o endif diff --git a/arch/arm/mach-imx/clock-imx6q.c b/arch/arm/mach-imx/clock-imx6q.c index b347a847c64..c246712948c 100644 --- a/arch/arm/mach-imx/clock-imx6q.c +++ b/arch/arm/mach-imx/clock-imx6q.c @@ -115,6 +115,8 @@ #define CG14 28 #define CG15 30 +#define BM_CCR_RBC_EN (0x1 << 27) + #define BM_CCSR_PLL1_SW_SEL (0x1 << 2) #define BM_CCSR_STEP_SEL (0x1 << 8) @@ -1916,35 +1918,44 @@ static struct clk_lookup lookups[] = { int imx6q_set_lpm(enum mxc_cpu_pwr_mode mode) { - u32 val = readl_relaxed(CLPCR); + u32 clpcr = readl_relaxed(CLPCR); + u32 ccr = readl_relaxed(CCR); - val &= ~BM_CLPCR_LPM; + clpcr &= ~(BM_CLPCR_LPM | BM_CLPCR_VSTBY | BM_CLPCR_SBYOS + | BM_CLPCR_STBY_COUNT | BM_CLPCR_WB_PER_AT_LPM); + ccr &= ~(BM_CCR_RBC_EN); switch (mode) { case WAIT_CLOCKED: break; case WAIT_UNCLOCKED: - val |= 0x1 << BP_CLPCR_LPM; + clpcr |= 0x1 << BP_CLPCR_LPM; break; case STOP_POWER_ON: - val |= 0x2 << BP_CLPCR_LPM; + clpcr |= 0x2 << BP_CLPCR_LPM; break; case WAIT_UNCLOCKED_POWER_OFF: - val |= 0x1 << BP_CLPCR_LPM; - val &= ~BM_CLPCR_VSTBY; - val &= ~BM_CLPCR_SBYOS; - val |= BM_CLPCR_BYP_MMDC_CH1_LPM_HS; + clpcr |= 0x1 << BP_CLPCR_LPM; break; case STOP_POWER_OFF: - val |= 0x2 << BP_CLPCR_LPM; - val |= 0x3 << BP_CLPCR_STBY_COUNT; - val |= BM_CLPCR_VSTBY; - val |= BM_CLPCR_SBYOS; - val |= BM_CLPCR_BYP_MMDC_CH1_LPM_HS; + clpcr |= 0x2 << BP_CLPCR_LPM; + clpcr |= 0x3 << BP_CLPCR_STBY_COUNT; + clpcr |= BM_CLPCR_VSTBY; + clpcr |= BM_CLPCR_SBYOS; break; + case ARM_POWER_OFF: + clpcr |= 0x2 << BP_CLPCR_LPM; + clpcr |= 0x3 << BP_CLPCR_STBY_COUNT; + clpcr |= BM_CLPCR_VSTBY; + clpcr |= BM_CLPCR_SBYOS; + clpcr |= BM_CLPCR_WB_PER_AT_LPM; + /* assert anatop_reg_bypass signal */ + ccr |= BM_CCR_RBC_EN; + break; default: return -EINVAL; } - writel_relaxed(val, CLPCR); + writel_relaxed(clpcr, CLPCR); + writel_relaxed(ccr, CCR); return 0; } diff --git a/arch/arm/mach-imx/gpc.c b/arch/arm/mach-imx/gpc.c index e1537f9e45b..8fc255b6daa 100644 --- a/arch/arm/mach-imx/gpc.c +++ b/arch/arm/mach-imx/gpc.c @@ -17,15 +17,36 @@ #include <linux/of_irq.h> #include <asm/hardware/gic.h> +#define GPC_CNTR 0x000 #define GPC_IMR1 0x008 +#define GPC_ISR1 0x018 +#define GPC_ISR2 0x01c +#define GPC_ISR3 0x020 +#define GPC_ISR4 0x024 #define GPC_PGC_CPU_PDN 0x2a0 #define IMR_NUM 4 +#define ISR_NUM 4 static void __iomem *gpc_base; static u32 gpc_wake_irqs[IMR_NUM]; static u32 gpc_saved_imrs[IMR_NUM]; +bool imx_gpc_wake_irq_pending(void) +{ + void __iomem *reg_isr1 = gpc_base + GPC_ISR1; + int i; + u32 val; + + for (i = 0; i < ISR_NUM; i++) { + val = readl_relaxed(reg_isr1 + i * 4); + if (val & gpc_wake_irqs[i]) + return true; + } + + return false; +} + void imx_gpc_pre_suspend(void) { void __iomem *reg_imr1 = gpc_base + GPC_IMR1; diff --git a/arch/arm/mach-imx/head-v7.S b/arch/arm/mach-imx/head-v7.S index ea12b0c4a05..7e49deb128a 100644 --- a/arch/arm/mach-imx/head-v7.S +++ b/arch/arm/mach-imx/head-v7.S @@ -16,7 +16,6 @@ #include <asm/hardware/cache-l2x0.h> .section ".text.head", "ax" - __CPUINIT /* * The secondary kernel init calls v7_flush_dcache_all before it enables diff --git a/arch/arm/mach-imx/mach-imx6q.c b/arch/arm/mach-imx/mach-imx6q.c index d69f99f63dc..36ad689c28f 100644 --- a/arch/arm/mach-imx/mach-imx6q.c +++ b/arch/arm/mach-imx/mach-imx6q.c @@ -10,10 +10,13 @@ * http://www.gnu.org/copyleft/gpl.html */ +#include <linux/delay.h> #include <linux/init.h> +#include <linux/io.h> #include <linux/irq.h> #include <linux/irqdomain.h> #include <linux/of.h> +#include <linux/of_address.h> #include <linux/of_irq.h> #include <linux/of_platform.h> #include <linux/phy.h> @@ -41,6 +44,36 @@ static int ksz9021rn_phy_fixup(struct phy_device *phydev) return 0; } +void imx6q_restart(char mode, const char *cmd) +{ + struct device_node *np; + void __iomem *wdog_base; + + np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-wdt"); + wdog_base = of_iomap(np, 0); + if (!wdog_base) + goto soft; + + imx_src_prepare_restart(); + + /* enable wdog */ + writew_relaxed(1 << 2, wdog_base); + /* write twice to ensure the request will not get ignored */ + writew_relaxed(1 << 2, wdog_base); + + /* wait for reset to assert ... */ + mdelay(500); + + pr_err("Watchdog reset failed to assert reset\n"); + + /* delay to allow the serial port to show the message */ + mdelay(50); + +soft: + /* we'll take a jump through zero as a poor second */ + soft_restart(0); +} + static void __init imx6q_init_machine(void) { if (of_machine_is_compatible("fsl,imx6q-sabrelite")) @@ -108,4 +141,5 @@ DT_MACHINE_START(IMX6Q, "Freescale i.MX6 Quad (Device Tree)") .timer = &imx6q_timer, .init_machine = imx6q_init_machine, .dt_compat = imx6q_dt_compat, + .restart = imx6q_restart, MACHINE_END diff --git a/arch/arm/mach-imx/pm-imx6q.c b/arch/arm/mach-imx/pm-imx6q.c index f20f191d7cc..85b758ec4af 100644 --- a/arch/arm/mach-imx/pm-imx6q.c +++ b/arch/arm/mach-imx/pm-imx6q.c @@ -13,31 +13,73 @@ #include <linux/init.h> #include <linux/io.h> #include <linux/of.h> +#include <linux/of_address.h> #include <linux/suspend.h> +#include <asm/mach/map.h> #include <asm/cacheflush.h> #include <asm/proc-fns.h> #include <asm/suspend.h> #include <asm/hardware/cache-l2x0.h> +#include <mach/iram.h> #include <mach/common.h> #include <mach/hardware.h> +struct imx_iram_pm { + void *iram_cpaddr; + unsigned long suspend_iram_paddr; + unsigned long suspend_iram_size; + void *suspend_iram_vaddr; + void *reg_ptr[4]; +} imx6q_iram_pm; + extern unsigned long phys_l2x0_saved_regs; +extern void imx6q_suspend(void); +static void (*suspend_in_iram)(unsigned long iram_paddr, + unsigned long iram_vaddr, + unsigned long iram_size); static int imx6q_suspend_finish(unsigned long val) { - cpu_do_idle(); + if ((val == PM_SUSPEND_MEM) && suspend_in_iram) { + suspend_in_iram((unsigned long)imx6q_iram_pm.suspend_iram_paddr, + (unsigned long)imx6q_iram_pm.suspend_iram_vaddr, + (unsigned long)imx6q_iram_pm.suspend_iram_size); + } else + cpu_do_idle(); + return 0; } +static void imx6q_prepare_suspend_iram(void) +{ + unsigned long *iram_stack = imx6q_iram_pm.suspend_iram_vaddr + + imx6q_iram_pm.suspend_iram_size; + + *(--iram_stack) = (unsigned long)imx6q_iram_pm.reg_ptr[3]; + *(--iram_stack) = (unsigned long)imx6q_iram_pm.reg_ptr[2]; + *(--iram_stack) = (unsigned long)imx6q_iram_pm.reg_ptr[1]; + *(--iram_stack) = (unsigned long)imx6q_iram_pm.reg_ptr[0]; +} + static int imx6q_pm_enter(suspend_state_t state) { switch (state) { + case PM_SUSPEND_STANDBY: case PM_SUSPEND_MEM: - imx6q_set_lpm(STOP_POWER_OFF); + if (imx_gpc_wake_irq_pending()) + return 0; + + if (state == PM_SUSPEND_STANDBY) + imx6q_set_lpm(STOP_POWER_OFF); + else + imx6q_set_lpm(ARM_POWER_OFF); + imx_gpc_pre_suspend(); imx_set_cpu_jump(0, v7_cpu_resume); + if (state == PM_SUSPEND_MEM) + imx6q_prepare_suspend_iram(); /* Zzz ... */ - cpu_suspend(0, imx6q_suspend_finish); + cpu_suspend(state, imx6q_suspend_finish); imx_smp_prepare(); imx_gpc_post_resume(); break; @@ -48,11 +90,55 @@ static int imx6q_pm_enter(suspend_state_t state) return 0; } +static int imx6q_pm_valid(suspend_state_t state) +{ + return (state > PM_SUSPEND_ON && state <= PM_SUSPEND_MAX); +} + static const struct platform_suspend_ops imx6q_pm_ops = { .enter = imx6q_pm_enter, - .valid = suspend_valid_only_mem, + .valid = imx6q_pm_valid, }; +static int __init imx6q_pm_iram_of_init(void) +{ + struct device_node *np; + + /* + * these register may already ioremaped, need figure out + * one way to save vmalloc space. + */ + np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-src"); + imx6q_iram_pm.reg_ptr[0] = of_iomap(np, 0); + if (!imx6q_iram_pm.reg_ptr[0]) + goto err0; + + np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-iomuxc"); + imx6q_iram_pm.reg_ptr[1] = of_iomap(np, 0); + if (!imx6q_iram_pm.reg_ptr[1]) + goto err1; + + np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-mmdc"); + imx6q_iram_pm.reg_ptr[2] = of_iomap(np, 0); + if (!imx6q_iram_pm.reg_ptr[2]) + goto err2; + + np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-anatop"); + imx6q_iram_pm.reg_ptr[3] = of_iomap(np, 0); + if (!imx6q_iram_pm.reg_ptr[3]) + goto err3; + + return 0; +err3: + iounmap(imx6q_iram_pm.reg_ptr[2]); +err2: + iounmap(imx6q_iram_pm.reg_ptr[1]); +err1: + iounmap(imx6q_iram_pm.reg_ptr[0]); +err0: + return -EINVAL; +} + void __init imx6q_pm_init(void) { /* @@ -67,4 +153,38 @@ void __init imx6q_pm_init(void) phys_l2x0_saved_regs = __pa(&l2x0_saved_regs); suspend_set_ops(&imx6q_pm_ops); + + /* Move suspend routine into iRAM */ + imx6q_iram_pm.suspend_iram_size = SZ_4K; + imx6q_iram_pm.iram_cpaddr = iram_alloc(imx6q_iram_pm.suspend_iram_size, + &imx6q_iram_pm.suspend_iram_paddr); + if (imx6q_iram_pm.iram_cpaddr) { + if (imx6q_pm_iram_of_init() < 0) { + iram_free(imx6q_iram_pm.suspend_iram_paddr, + imx6q_iram_pm.suspend_iram_size); + return; + } + /* + * Need to remap the area here since we want the memory region + * to be noncached & executable. + */ + imx6q_iram_pm.suspend_iram_vaddr = + __arm_ioremap(imx6q_iram_pm.suspend_iram_paddr, + imx6q_iram_pm.suspend_iram_size, + MT_MEMORY_NONCACHED); + pr_info("cpaddr = %p suspend_iram_base=%p\n", + imx6q_iram_pm.iram_cpaddr, + imx6q_iram_pm.suspend_iram_vaddr); + + /* + * Need to run the suspend code from IRAM as the DDR needs + * to be put into low power mode manually. + */ + memcpy(imx6q_iram_pm.iram_cpaddr, imx6q_suspend, + imx6q_iram_pm.suspend_iram_size); + + suspend_in_iram = (void *)imx6q_iram_pm.suspend_iram_vaddr; + + } else + suspend_in_iram = NULL; } diff --git a/arch/arm/mach-imx/src.c b/arch/arm/mach-imx/src.c index a8e33681b73..4bde04f99e3 100644 --- a/arch/arm/mach-imx/src.c +++ b/arch/arm/mach-imx/src.c @@ -19,6 +19,7 @@ #define SRC_SCR 0x000 #define SRC_GPR1 0x020 +#define BP_SRC_SCR_WARM_RESET_ENABLE 0 #define BP_SRC_SCR_CORE1_RST 14 #define BP_SRC_SCR_CORE1_ENABLE 22 @@ -46,11 +47,33 @@ void imx_set_cpu_jump(int cpu, void *jump_addr) src_base + SRC_GPR1 + cpu * 8); } +void imx_src_prepare_restart(void) +{ + u32 val; + + /* clear enable bits of secondary cores */ + val = readl_relaxed(src_base + SRC_SCR); + val &= ~(0x7 << BP_SRC_SCR_CORE1_ENABLE); + writel_relaxed(val, src_base + SRC_SCR); + + /* clear persistent entry register of primary core */ + writel_relaxed(0, src_base + SRC_GPR1); +} + void __init imx_src_init(void) { struct device_node *np; + u32 val; np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-src"); src_base = of_iomap(np, 0); WARN_ON(!src_base); + + /* + * force warm reset sources to generate cold reset + * for a more reliable restart + */ + val = readl_relaxed(src_base + SRC_SCR); + val &= ~(1 << BP_SRC_SCR_WARM_RESET_ENABLE); + writel_relaxed(val, src_base + SRC_SCR); } diff --git a/arch/arm/mach-imx/suspend-imx6q.S b/arch/arm/mach-imx/suspend-imx6q.S new file mode 100644 index 00000000000..f803e2b7b11 --- /dev/null +++ b/arch/arm/mach-imx/suspend-imx6q.S @@ -0,0 +1,308 @@ +/* + * Copyright 2011 Freescale Semiconductor, Inc. + * Copyright 2011 Linaro Ltd. + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#include <linux/linkage.h> +#include <mach/hardware.h> +#include <asm/hardware/cache-l2x0.h> + +#define SRC_GPR1_OFFSET 0x020 +#define SRC_GPR2_OFFSET 0x024 +#define MMDC_MAPSR_OFFSET 0x404 +#define MMDC_MAPSR_PSS (1 << 4) +#define MMDC_MAPSR_PSD (1 << 0) +#define ANATOP_REG_2P5 0x130 + +.macro ddr_io_save + ldr r4, [r9, #0x5ac] /* DRAM_DQM0 */ + ldr r5, [r9, #0x5b4] /* DRAM_DQM1 */ + ldr r6, [r9, #0x528] /* DRAM_DQM2 */ + ldr r7, [r9, #0x520] /* DRAM_DQM3 */ + stmfd sp!, {r4-r7} + + ldr r4, [r9, #0x514] /* DRAM_DQM4 */ + ldr r5, [r9, #0x510] /* DRAM_DQM5 */ + ldr r6, [r9, #0x5bc] /* DRAM_DQM6 */ + ldr r7, [r9, #0x5c4] /* DRAM_DQM7 */ + stmfd sp!, {r4-r7} + + ldr r4, [r9, #0x56c] /* DRAM_CAS */ + ldr r5, [r9, #0x578] /* DRAM_RAS */ + ldr r6, [r9, #0x588] /* DRAM_SDCLK_0 */ + ldr r7, [r9, #0x594] /* DRAM_SDCLK_1 */ + stmfd sp!, {r4-r7} + + ldr r5, [r9, #0x750] /* DDRMODE_CTL */ + ldr r6, [r9, #0x774] /* DDRMODE */ + stmfd sp!, {r5-r6} + + ldr r4, [r9, #0x5a8] /* DRAM_SDQS0 */ + ldr r5, [r9, #0x5b0] /* DRAM_SDQS1 */ + ldr r6, [r9, #0x524] /* DRAM_SDQS2 */ + ldr r7, [r9, #0x51c] /* DRAM_SDQS3 */ + stmfd sp!, {r4-r7} + + ldr r4, [r9, #0x518] /* DRAM_SDQS4 */ + ldr r5, [r9, #0x50c] /* DRAM_SDQS5 */ + ldr r6, [r9, #0x5b8] /* DRAM_SDQS6 */ + ldr r7, [r9, #0x5c0] /* DRAM_SDQS7 */ + stmfd sp!, {r4-r7} + + ldr r4, [r9, #0x784] /* GPR_B0DS */ + ldr r5, [r9, #0x788] /* GPR_B1DS */ + ldr r6, [r9, #0x794] /* GPR_B2DS */ + ldr r7, [r9, #0x79c] /* GPR_B3DS */ + stmfd sp!, {r4-r7} + + ldr r4, [r9, #0x7a0] /* GPR_B4DS */ + ldr r5, [r9, #0x7a4] /* GPR_B5DS */ + ldr r6, [r9, #0x7a8] /* GPR_B6DS */ + ldr r7, [r9, #0x748] /* GPR_B7DS */ + stmfd sp!, {r4-r7} + + ldr r5, [r9, #0x74c] /* GPR_ADDS*/ + ldr r6, [r9, #0x59c] /* DRAM_SODT0*/ + ldr r7, [r9, #0x5a0] /* DRAM_SODT1*/ + stmfd sp!, {r5-r7} +.endm + +.macro ddr_io_restore + ldmfd sp!, {r5-r7} + str r5, [r9, #0x74c] /* GPR_ADDS*/ + str r6, [r9, #0x59c] /* DRAM_SODT0*/ + str r7, [r9, #0x5a0] /* DRAM_SODT1*/ + + ldmfd sp!, {r4-r7} + str r4, [r9, #0x7a0] /* GPR_B4DS */ + str r5, [r9, #0x7a4] /* GPR_B5DS */ + str r6, [r9, #0x7a8] /* GPR_B6DS */ + str r7, [r9, #0x748] /* GPR_B7DS */ + + ldmfd sp!, {r4-r7} + str r4, [r9, #0x784] /* GPR_B0DS */ + str r5, [r9, #0x788] /* GPR_B1DS */ + str r6, [r9, #0x794] /* GPR_B2DS */ + str r7, [r9, #0x79c] /* GPR_B3DS */ + + ldmfd sp!, {r4-r7} + str r4, [r9, #0x518] /* DRAM_SDQS4 */ + str r5, [r9, #0x50c] /* DRAM_SDQS5 */ + str r6, [r9, #0x5b8] /* DRAM_SDQS6 */ + str r7, [r9, #0x5c0] /* DRAM_SDQS7 */ + + ldmfd sp!, {r4-r7} + str r4, [r9, #0x5a8] /* DRAM_SDQS0 */ + str r5, [r9, #0x5b0] /* DRAM_SDQS1 */ + str r6, [r9, #0x524] /* DRAM_SDQS2 */ + str r7, [r9, #0x51c] /* DRAM_SDQS3 */ + + ldmfd sp!, {r5-r6} + str r5, [r9, #0x750] /* DDRMODE_CTL */ + str r6, [r9, #0x774] /* DDRMODE */ + + ldmfd sp!, {r4-r7} + str r4, [r9, #0x56c] /* DRAM_CAS */ + str r5, [r9, #0x578] /* DRAM_RAS */ + str r6, [r9, #0x588] /* DRAM_SDCLK_0 */ + str r7, [r9, #0x594] /* DRAM_SDCLK_1 */ + + ldmfd sp!, {r4-r7} + str r4, [r9, #0x514] /* DRAM_DQM4 */ + str r5, [r9, #0x510] /* DRAM_DQM5 */ + str r6, [r9, #0x5bc] /* DRAM_DQM6 */ + str r7, [r9, #0x5c4] /* DRAM_DQM7 */ + + ldmfd sp!, {r4-r7} + str r4, [r9, #0x5ac] /* DRAM_DQM0 */ + str r5, [r9, #0x5b4] /* DRAM_DQM1 */ + str r6, [r9, #0x528] /* DRAM_DQM2 */ + str r7, [r9, #0x520] /* DRAM_DQM3 */ +.endm + +.macro ddr_io_set_lpm + mov r4, #0 + str r4, [r9, #0x5ac] /* DRAM_DQM0 */ + str r4, [r9, #0x5b4] /* DRAM_DQM1 */ + str r4, [r9, #0x528] /* DRAM_DQM2 */ + str r4, [r9, #0x520] /* DRAM_DQM3 */ + + str r4, [r9, #0x514] /* DRAM_DQM4 */ + str r4, [r9, #0x510] /* DRAM_DQM5 */ + str r4, [r9, #0x5bc] /* DRAM_DQM6 */ + str r4, [r9, #0x5c4] /* DRAM_DQM7 */ + + str r4, [r9, #0x56c] /* DRAM_CAS */ + str r4, [r9, #0x578] /* DRAM_RAS */ + str r4, [r9, #0x588] /* DRAM_SDCLK_0 */ + str r4, [r9, #0x594] /* DRAM_SDCLK_1 */ + + str r4, [r9, #0x750] /* DDRMODE_CTL */ + str r4, [r9, #0x774] /* DDRMODE */ + + str r4, [r9, #0x5a8] /* DRAM_SDQS0 */ + str r4, [r9, #0x5b0] /* DRAM_SDQS1 */ + str r4, [r9, #0x524] /* DRAM_SDQS2 */ + str r4, [r9, #0x51c] /* DRAM_SDQS3 */ + + str r4, [r9, #0x518] /* DRAM_SDQS4 */ + str r4, [r9, #0x50c] /* DRAM_SDQS5 */ + str r4, [r9, #0x5b8] /* DRAM_SDQS6 */ + str r4, [r9, #0x5c0] /* DRAM_SDQS7 */ + + str r4, [r9, #0x784] /* GPR_B0DS */ + str r4, [r9, #0x788] /* GPR_B1DS */ + str r4, [r9, #0x794] /* GPR_B2DS */ + str r4, [r9, #0x79c] /* GPR_B3DS */ + + str r4, [r9, #0x7a0] /* GPR_B4DS */ + str r4, [r9, #0x7a4] /* GPR_B5DS */ + str r4, [r9, #0x7a8] /* GPR_B6DS */ + str r4, [r9, #0x748] /* GPR_B7DS */ + + str r4, [r9, #0x74c] /* GPR_ADDS*/ + str r4, [r9, #0x59c] /* DRAM_SODT0*/ + str r4, [r9, #0x5a0] /* DRAM_SODT1*/ +.endm + +/* + * imx6q_suspend: + * + * Suspend the processor (eg, wait for interrupt). + * Set the DDR into Self Refresh + * IRQs are already disabled. + * + * Registers usage in the imx6q_suspend: + * + * r0: suspend_iram_paddr + * r1: suspend_iram_vaddr + * r2: suspend_iram_size + * + * r8: src_base pointer + * r9: iomux_base pointer + * r10: mmdc_base pointer + * r11: anatop_base pointer + * sp: iram stack + * + * Corrupted registers: r0-r3 + */ + +ENTRY(imx6q_suspend) + mov r3, sp @ save sp + add sp, r1, r2 @ set sp to top iram stack + sub sp, sp, #16 @ 4 regs ptr + stmfd sp!, {r4 - r12, lr} @ save registers + + add r4, r1, r2 + ldr r8, [r4, #-16] @ r8 = src_base pointer + ldr r9, [r4, #-12] @ r9 = iomux_base pointer + ldr r10, [r4, #-8] @ r10 = mmdc_base pointer + ldr r11, [r4, #-4] @ r11 = anatop_base pointer + + /* should not access sp in ddr until resume with cache MMU on */ + stmfd sp!, {r3} @ save old sp + + ldr r4, [r8, #SRC_GPR1_OFFSET] @ r8 = src_base pointer + stmfd sp!, {r4} @ save old resume func + + /* Enable weak 2P5 linear regulator */ + ldr r4, [r11, #ANATOP_REG_2P5] @ r11 = anatop_base pointer + orr r4, r4, #0x40000 + str r4, [r11, #ANATOP_REG_2P5] + mov r6, #1 +wait: ldr r4, [r11, #ANATOP_REG_2P5] + and r4, r4, r6, lsl #17 @ output ok? + cmp r4, #0 + beq wait + + /* save ddr iomux regs */ + ddr_io_save + + /* set ddr to low power mode */ + ldr r4, [r10, #MMDC_MAPSR_OFFSET] @ r10 = mmdc_base pointer + bic r4, #MMDC_MAPSR_PSD + str r4, [r10, #MMDC_MAPSR_OFFSET] +refresh: + ldr r4, [r10, #MMDC_MAPSR_OFFSET] + and r4, r4, #MMDC_MAPSR_PSS + cmp r4, #0 + beq refresh + + ddr_io_set_lpm + + /* save resume pointer into SRC_GPR1, sp pointer into SRC_GPR2 */ + ldr r4, =imx6q_suspend + ldr r5, =imx6q_resume + sub r5, r5, r4 @ r5 = resmue offset + add r5, r0, r5 @ r0 = suspend_iram_paddr, r5 = resmue phy addr + str r5, [r8, #SRC_GPR1_OFFSET] @ r8 = src_base pointer + sub r5, sp, r1 @ r1 = suspend_iram_vaddr, r5 = sp offset + add r5, r0, r5 @ r0 = suspend_iram_paddr, r5 = sp phy addr + str r5, [r8, #SRC_GPR2_OFFSET] @ r8 = src_base pointer + + /* execute a wfi instruction to let SOC go into stop mode */ + dsb + wfi + + nop + nop + nop + nop + + /* + * if go here, means there is a wakeup irq pending, we should resume + * system immediately. + */ + ddr_io_restore + + /* Disable weak 2P5 linear regulator */ + ldr r4, [r11, #ANATOP_REG_2P5] @ r11 = anatop_base pointer + bic r4, #0x40000 + str r4, [r11, #ANATOP_REG_2P5] + + ldmfd sp!, {r4} @ drop old resmue func ptr + ldmfd sp!, {r3} + ldmfd sp!, {r4 - r12, lr} + mov sp, r3 + mov pc, lr + +/* + * when SOC exit stop mode, arm core restart from here, currently + * are running with MMU off. + */ +imx6q_resume: + ldr r0, =MX6Q_SRC_BASE_ADDR + mov r1, #0x0 + str r1, [r0, #SRC_GPR1_OFFSET] @ clear SRC_GPR1 + ldr sp, [r0, #SRC_GPR2_OFFSET] + str r1, [r0, #SRC_GPR2_OFFSET] @ clear SRC_GPR2 + + ldr r9, =MX6Q_IOMUXC_BASE_ADDR + ddr_io_restore + + ldr r0, =MX6Q_MMDC0_BASE_ADDR + ldr r1, [r0, #MMDC_MAPSR_OFFSET] + orr r1, #MMDC_MAPSR_PSD + str r1, [r0, #MMDC_MAPSR_OFFSET] + + /* Disable weak 2P5 linear regulator */ + ldr r0, =MX6Q_ANATOP_BASE_ADDR + ldr r1, [r0, #ANATOP_REG_2P5] + bic r1, #0x40000 + str r1, [r0, #ANATOP_REG_2P5] + + ldmfd sp!, {r2} @ resmue func ptr + ldmfd sp!, {r3} + ldmfd sp!, {r4 - r12, lr} + mov sp, r3 + + /* return back */ + mov pc, r2 +ENDPROC(imx6q_suspend) diff --git a/arch/arm/mach-iop32x/include/mach/system.h b/arch/arm/mach-iop32x/include/mach/system.h index a4b808fe0d8..4865a9bff85 100644 --- a/arch/arm/mach-iop32x/include/mach/system.h +++ b/arch/arm/mach-iop32x/include/mach/system.h @@ -30,5 +30,5 @@ static inline void arch_reset(char mode, const char *cmd) *IOP3XX_PCSR = 0x30; /* Jump into ROM at address 0 */ - cpu_reset(0); + soft_restart(0); } diff --git a/arch/arm/mach-iop33x/include/mach/system.h b/arch/arm/mach-iop33x/include/mach/system.h index f192a34be07..86d1b20dd69 100644 --- a/arch/arm/mach-iop33x/include/mach/system.h +++ b/arch/arm/mach-iop33x/include/mach/system.h @@ -19,5 +19,5 @@ static inline void arch_reset(char mode, const char *cmd) *IOP3XX_PCSR = 0x30; /* Jump into ROM at address 0 */ - cpu_reset(0); + soft_restart(0); } diff --git a/arch/arm/mach-ixp4xx/include/mach/system.h b/arch/arm/mach-ixp4xx/include/mach/system.h index 54c0af7fa2d..24337d9d275 100644 --- a/arch/arm/mach-ixp4xx/include/mach/system.h +++ b/arch/arm/mach-ixp4xx/include/mach/system.h @@ -26,7 +26,7 @@ static inline void arch_reset(char mode, const char *cmd) { if ( 1 && mode == 's') { /* Jump into ROM at address 0 */ - cpu_reset(0); + soft_restart(0); } else { /* Use on-chip reset capability */ diff --git a/arch/arm/mach-ks8695/include/mach/system.h b/arch/arm/mach-ks8695/include/mach/system.h index fb1dda9be2d..ceb19c90aa5 100644 --- a/arch/arm/mach-ks8695/include/mach/system.h +++ b/arch/arm/mach-ks8695/include/mach/system.h @@ -32,7 +32,7 @@ static void arch_reset(char mode, const char *cmd) unsigned int reg; if (mode == 's') - cpu_reset(0); + soft_restart(0); /* disable timer0 */ reg = __raw_readl(KS8695_TMR_VA + KS8695_TMCON); diff --git a/arch/arm/mach-mmp/include/mach/system.h b/arch/arm/mach-mmp/include/mach/system.h index 1a8a25edb1b..cb0637933a8 100644 --- a/arch/arm/mach-mmp/include/mach/system.h +++ b/arch/arm/mach-mmp/include/mach/system.h @@ -19,8 +19,8 @@ static inline void arch_idle(void) static inline void arch_reset(char mode, const char *cmd) { if (cpu_is_pxa168()) - cpu_reset(0xffff0000); + soft_restart(0xffff0000); else - cpu_reset(0); + soft_restart(0); } #endif /* __ASM_MACH_SYSTEM_H */ diff --git a/arch/arm/mach-mxs/system.c b/arch/arm/mach-mxs/system.c index 20ec3bddf7c..cab88364e7c 100644 --- a/arch/arm/mach-mxs/system.c +++ b/arch/arm/mach-mxs/system.c @@ -53,7 +53,7 @@ void arch_reset(char mode, const char *cmd) mdelay(50); /* We'll take a jump through zero as a poor second */ - cpu_reset(0); + soft_restart(0); } static int __init mxs_arch_reset_init(void) diff --git a/arch/arm/mach-pnx4008/include/mach/system.h b/arch/arm/mach-pnx4008/include/mach/system.h index 5dda2bb55f8..5d6384a6128 100644 --- a/arch/arm/mach-pnx4008/include/mach/system.h +++ b/arch/arm/mach-pnx4008/include/mach/system.h @@ -32,7 +32,7 @@ static void arch_idle(void) static inline void arch_reset(char mode, const char *cmd) { - cpu_reset(0); + soft_restart(0); } #endif diff --git a/arch/arm/mach-pxa/reset.c b/arch/arm/mach-pxa/reset.c index 01e9d643394..b8bcda15da8 100644 --- a/arch/arm/mach-pxa/reset.c +++ b/arch/arm/mach-pxa/reset.c @@ -88,7 +88,7 @@ void arch_reset(char mode, const char *cmd) switch (mode) { case 's': /* Jump into ROM at address 0 */ - cpu_reset(0); + soft_restart(0); break; case 'g': do_gpio_reset(); diff --git a/arch/arm/mach-rpc/include/mach/system.h b/arch/arm/mach-rpc/include/mach/system.h index 45c7b935dc4..a354f4d092c 100644 --- a/arch/arm/mach-rpc/include/mach/system.h +++ b/arch/arm/mach-rpc/include/mach/system.h @@ -23,5 +23,5 @@ static inline void arch_reset(char mode, const char *cmd) /* * Jump into the ROM */ - cpu_reset(0); + soft_restart(0); } diff --git a/arch/arm/mach-s3c2410/include/mach/system-reset.h b/arch/arm/mach-s3c2410/include/mach/system-reset.h index 6faadcee772..913893d4465 100644 --- a/arch/arm/mach-s3c2410/include/mach/system-reset.h +++ b/arch/arm/mach-s3c2410/include/mach/system-reset.h @@ -19,7 +19,7 @@ static void arch_reset(char mode, const char *cmd) { if (mode == 's') { - cpu_reset(0); + soft_restart(0); } if (s3c24xx_reset_hook) @@ -28,5 +28,5 @@ arch_reset(char mode, const char *cmd) arch_wdt_reset(); /* we'll take a jump through zero as a poor second */ - cpu_reset(0); + soft_restart(0); } diff --git a/arch/arm/mach-s3c64xx/include/mach/system.h b/arch/arm/mach-s3c64xx/include/mach/system.h index 2e58cb7a714..d8ca5786ba2 100644 --- a/arch/arm/mach-s3c64xx/include/mach/system.h +++ b/arch/arm/mach-s3c64xx/include/mach/system.h @@ -24,7 +24,7 @@ static void arch_reset(char mode, const char *cmd) arch_wdt_reset(); /* if all else fails, or mode was for soft, jump to 0 */ - cpu_reset(0); + soft_restart(0); } #endif /* __ASM_ARCH_IRQ_H */ diff --git a/arch/arm/mach-sa1100/include/mach/system.h b/arch/arm/mach-sa1100/include/mach/system.h index ba9da9f7f18..345d35b7450 100644 --- a/arch/arm/mach-sa1100/include/mach/system.h +++ b/arch/arm/mach-sa1100/include/mach/system.h @@ -14,7 +14,7 @@ static inline void arch_reset(char mode, const char *cmd) { if (mode == 's') { /* Jump into ROM at address 0 */ - cpu_reset(0); + soft_restart(0); } else { /* Use on-chip reset capability */ RSRR = RSRR_SWR; diff --git a/arch/arm/mach-shmobile/include/mach/system.h b/arch/arm/mach-shmobile/include/mach/system.h index 76a687eeaa2..956ac18ddbf 100644 --- a/arch/arm/mach-shmobile/include/mach/system.h +++ b/arch/arm/mach-shmobile/include/mach/system.h @@ -8,7 +8,7 @@ static inline void arch_idle(void) static inline void arch_reset(char mode, const char *cmd) { - cpu_reset(0); + soft_restart(0); } #endif diff --git a/arch/arm/mach-w90x900/include/mach/system.h b/arch/arm/mach-w90x900/include/mach/system.h index ce228bdc66d..68875a1c16b 100644 --- a/arch/arm/mach-w90x900/include/mach/system.h +++ b/arch/arm/mach-w90x900/include/mach/system.h @@ -33,7 +33,7 @@ static void arch_reset(char mode, const char *cmd) { if (mode == 's') { /* Jump into ROM at address 0 */ - cpu_reset(0); + soft_restart(0); } else { __raw_writel(WTE | WTRE | WTCLK, WTCR); } diff --git a/arch/arm/mm/idmap.c b/arch/arm/mm/idmap.c index 2be9139a4ef..296ad2eaddb 100644 --- a/arch/arm/mm/idmap.c +++ b/arch/arm/mm/idmap.c @@ -78,7 +78,7 @@ void identity_mapping_del(pgd_t *pgd, unsigned long addr, unsigned long end) * the user-mode pages. This will then ensure that we have predictable * results when turning the mmu off */ -void setup_mm_for_reboot(char mode) +void setup_mm_for_reboot(void) { /* * We need to access to user-mode page tables here. For kernel threads diff --git a/arch/arm/mm/nommu.c b/arch/arm/mm/nommu.c index 941a98c9e8a..88417514b2c 100644 --- a/arch/arm/mm/nommu.c +++ b/arch/arm/mm/nommu.c @@ -43,7 +43,7 @@ void __init paging_init(struct machine_desc *mdesc) /* * We don't need to do anything here for nommu machines. */ -void setup_mm_for_reboot(char mode) +void setup_mm_for_reboot(void) { } diff --git a/arch/arm/plat-mxc/include/mach/common.h b/arch/arm/plat-mxc/include/mach/common.h index f4ebdb817ab..7365b27ec64 100644 --- a/arch/arm/plat-mxc/include/mach/common.h +++ b/arch/arm/plat-mxc/include/mach/common.h @@ -82,6 +82,7 @@ enum mxc_cpu_pwr_mode { WAIT_UNCLOCKED_POWER_OFF, /* WAIT + SRPG */ STOP_POWER_ON, /* just STOP */ STOP_POWER_OFF, /* STOP + SRPG */ + ARM_POWER_OFF, /* STOP + SRPG + ARM power off */ }; extern void mx5_cpu_lp_set(enum mxc_cpu_pwr_mode mode); @@ -122,7 +123,9 @@ static inline void imx_smp_prepare(void) {} extern void imx_enable_cpu(int cpu, bool enable); extern void imx_set_cpu_jump(int cpu, void *jump_addr); extern void imx_src_init(void); +extern void imx_src_prepare_restart(void); extern void imx_gpc_init(void); +extern bool imx_gpc_wake_irq_pending(void); extern void imx_gpc_pre_suspend(void); extern void imx_gpc_post_resume(void); extern void imx51_babbage_common_init(void); diff --git a/arch/arm/plat-mxc/include/mach/mx6q.h b/arch/arm/plat-mxc/include/mach/mx6q.h index e051ff1f651..8c13004c086 100644 --- a/arch/arm/plat-mxc/include/mach/mx6q.h +++ b/arch/arm/plat-mxc/include/mach/mx6q.h @@ -29,6 +29,12 @@ #define MX6Q_CCM_SIZE 0x4000 #define MX6Q_ANATOP_BASE_ADDR 0x020c8000 #define MX6Q_ANATOP_SIZE 0x1000 +#define MX6Q_SRC_BASE_ADDR 0x020d8000 +#define MX6Q_SRC_SIZE 0x4000 +#define MX6Q_IOMUXC_BASE_ADDR 0x020e0000 +#define MX6Q_IOMUXC_SIZE 0x4000 +#define MX6Q_MMDC0_BASE_ADDR 0x021b0000 +#define MX6Q_MMDC0_SIZE 0x4000 #define MX6Q_UART4_BASE_ADDR 0x021f0000 #define MX6Q_UART4_SIZE 0x4000 diff --git a/arch/arm/plat-mxc/system.c b/arch/arm/plat-mxc/system.c index d65fb31a55c..7e5c76ea446 100644 --- a/arch/arm/plat-mxc/system.c +++ b/arch/arm/plat-mxc/system.c @@ -71,7 +71,7 @@ void arch_reset(char mode, const char *cmd) mdelay(50); /* we'll take a jump through zero as a poor second */ - cpu_reset(0); + soft_restart(0); } void mxc_arch_reset_init(void __iomem *base) diff --git a/arch/arm/plat-spear/include/plat/system.h b/arch/arm/plat-spear/include/plat/system.h index a235fa0ca77..1171f228d71 100644 --- a/arch/arm/plat-spear/include/plat/system.h +++ b/arch/arm/plat-spear/include/plat/system.h @@ -31,7 +31,7 @@ static inline void arch_reset(char mode, const char *cmd) { if (mode == 's') { /* software reset, Jump into ROM at address 0 */ - cpu_reset(0); + soft_restart(0); } else { /* hardware reset, Use on-chip reset capability */ sysctl_soft_reset((void __iomem *)VA_SPEAR_SYS_CTRL_BASE); diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index e018aef88df..0f4ba212fd6 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -566,6 +566,9 @@ static irqreturn_t imx_int(int irq, void *dev_id) if (sts & USR1_RTSD) imx_rtsint(irq, dev_id); + if (sts & USR1_AWAKE) + writel(USR1_AWAKE, sport->port.membase + USR1); + return IRQ_HANDLED; } @@ -1269,6 +1272,12 @@ static struct uart_driver imx_reg = { static int serial_imx_suspend(struct platform_device *dev, pm_message_t state) { struct imx_port *sport = platform_get_drvdata(dev); + unsigned int val; + + /* enable wakeup from i.MX UART */ + val = readl(sport->port.membase + UCR3); + val |= UCR3_AWAKEN; + writel(val, sport->port.membase + UCR3); if (sport) uart_suspend_port(&imx_reg, &sport->port); @@ -1279,6 +1288,12 @@ static int serial_imx_suspend(struct platform_device *dev, pm_message_t state) static int serial_imx_resume(struct platform_device *dev) { struct imx_port *sport = platform_get_drvdata(dev); + unsigned int val; + + /* disable wakeup from i.MX UART */ + val = readl(sport->port.membase + UCR3); + val &= ~UCR3_AWAKEN; + writel(val, sport->port.membase + UCR3); if (sport) uart_resume_port(&imx_reg, &sport->port); |