 6ebbf2ce43
			
		
	
	
	6ebbf2ce43
	
	
	
		
			
			ARMv6 and greater introduced a new instruction ("bx") which can be used
to return from function calls.  Recent CPUs perform better when the
"bx lr" instruction is used rather than the "mov pc, lr" instruction,
and this sequence is strongly recommended to be used by the ARM
architecture manual (section A.4.1.1).
We provide a new macro "ret" with all its variants for the condition
code which will resolve to the appropriate instruction.
Rather than doing this piecemeal, and miss some instances, change all
the "mov pc" instances to use the new macro, with the exception of
the "movs" instruction and the kprobes code.  This allows us to detect
the "mov pc, lr" case and fix it up - and also gives us the possibility
of deploying this for other registers depending on the CPU selection.
Reported-by: Will Deacon <will.deacon@arm.com>
Tested-by: Stephen Warren <swarren@nvidia.com> # Tegra Jetson TK1
Tested-by: Robert Jarzmik <robert.jarzmik@free.fr> # mioa701_bootresume.S
Tested-by: Andrew Lunn <andrew@lunn.ch> # Kirkwood
Tested-by: Shawn Guo <shawn.guo@freescale.com>
Tested-by: Tony Lindgren <tony@atomide.com> # OMAPs
Tested-by: Gregory CLEMENT <gregory.clement@free-electrons.com> # Armada XP, 375, 385
Acked-by: Sekhar Nori <nsekhar@ti.com> # DaVinci
Acked-by: Christoffer Dall <christoffer.dall@linaro.org> # kvm/hyp
Acked-by: Haojian Zhuang <haojian.zhuang@gmail.com> # PXA3xx
Acked-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com> # Xen
Tested-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> # ARMv7M
Tested-by: Simon Horman <horms+renesas@verge.net.au> # Shmobile
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
		
	
			
		
			
				
	
	
		
			228 lines
		
	
	
	
		
			5.4 KiB
			
		
	
	
	
		
			ArmAsm
		
	
	
	
	
	
			
		
		
	
	
			228 lines
		
	
	
	
		
			5.4 KiB
			
		
	
	
	
		
			ArmAsm
		
	
	
	
	
	
| /*
 | |
|  * (C) Copyright 2009, Texas Instruments, Inc. http://www.ti.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
 | |
|  */
 | |
| 
 | |
| /* replicated define because linux/bitops.h cannot be included in assembly */
 | |
| #define BIT(nr)			(1 << (nr))
 | |
| 
 | |
| #include <linux/linkage.h>
 | |
| #include <asm/assembler.h>
 | |
| #include <mach/psc.h>
 | |
| #include <mach/ddr2.h>
 | |
| 
 | |
| #include "clock.h"
 | |
| 
 | |
| /* Arbitrary, hardware currently does not update PHYRDY correctly */
 | |
| #define PHYRDY_CYCLES		0x1000
 | |
| 
 | |
| /* Assume 25 MHz speed for the cycle conversions since PLLs are bypassed */
 | |
| #define PLL_BYPASS_CYCLES	(PLL_BYPASS_TIME * 25)
 | |
| #define PLL_RESET_CYCLES	(PLL_RESET_TIME	* 25)
 | |
| #define PLL_LOCK_CYCLES		(PLL_LOCK_TIME * 25)
 | |
| 
 | |
| #define DEEPSLEEP_SLEEPENABLE_BIT	BIT(31)
 | |
| 
 | |
| 	.text
 | |
| /*
 | |
|  * Move DaVinci into deep sleep state
 | |
|  *
 | |
|  * Note: This code is copied to internal SRAM by PM code. When the DaVinci
 | |
|  *	 wakes up it continues execution at the point it went to sleep.
 | |
|  * Register Usage:
 | |
|  * 	r0: contains virtual base for DDR2 controller
 | |
|  * 	r1: contains virtual base for DDR2 Power and Sleep controller (PSC)
 | |
|  * 	r2: contains PSC number for DDR2
 | |
|  * 	r3: contains virtual base DDR2 PLL controller
 | |
|  * 	r4: contains virtual address of the DEEPSLEEP register
 | |
|  */
 | |
| ENTRY(davinci_cpu_suspend)
 | |
| 	stmfd	sp!, {r0-r12, lr}		@ save registers on stack
 | |
| 
 | |
| 	ldr 	ip, CACHE_FLUSH
 | |
| 	blx	ip
 | |
| 
 | |
| 	ldmia	r0, {r0-r4}
 | |
| 
 | |
| 	/*
 | |
| 	 * Switch DDR to self-refresh mode.
 | |
| 	 */
 | |
| 
 | |
| 	/* calculate SDRCR address */
 | |
| 	ldr	ip, [r0, #DDR2_SDRCR_OFFSET]
 | |
| 	bic	ip, ip, #DDR2_SRPD_BIT
 | |
| 	orr	ip, ip, #DDR2_LPMODEN_BIT
 | |
| 	str	ip, [r0, #DDR2_SDRCR_OFFSET]
 | |
| 
 | |
| 	ldr	ip, [r0, #DDR2_SDRCR_OFFSET]
 | |
| 	orr	ip, ip, #DDR2_MCLKSTOPEN_BIT
 | |
| 	str	ip, [r0, #DDR2_SDRCR_OFFSET]
 | |
| 
 | |
|        mov	ip, #PHYRDY_CYCLES
 | |
| 1:     subs	ip, ip, #0x1
 | |
|        bne	1b
 | |
| 
 | |
|        /* Disable DDR2 LPSC */
 | |
| 	mov	r7, r0
 | |
| 	mov	r0, #0x2
 | |
| 	bl davinci_ddr_psc_config
 | |
| 	mov	r0, r7
 | |
| 
 | |
| 	/* Disable clock to DDR PHY */
 | |
| 	ldr	ip, [r3, #PLLDIV1]
 | |
| 	bic	ip, ip, #PLLDIV_EN
 | |
| 	str	ip, [r3, #PLLDIV1]
 | |
| 
 | |
| 	/* Put the DDR PLL in bypass and power down */
 | |
| 	ldr	ip, [r3, #PLLCTL]
 | |
| 	bic	ip, ip, #PLLCTL_PLLENSRC
 | |
| 	bic	ip, ip, #PLLCTL_PLLEN
 | |
| 	str	ip, [r3, #PLLCTL]
 | |
| 
 | |
| 	/* Wait for PLL to switch to bypass */
 | |
|        mov	ip, #PLL_BYPASS_CYCLES
 | |
| 2:     subs	ip, ip, #0x1
 | |
|        bne	2b
 | |
| 
 | |
|        /* Power down the PLL */
 | |
| 	ldr	ip, [r3, #PLLCTL]
 | |
| 	orr	ip, ip, #PLLCTL_PLLPWRDN
 | |
| 	str	ip, [r3, #PLLCTL]
 | |
| 
 | |
| 	/* Go to deep sleep */
 | |
| 	ldr	ip, [r4]
 | |
| 	orr	ip, ip, #DEEPSLEEP_SLEEPENABLE_BIT
 | |
| 	/* System goes to sleep beyond after this instruction */
 | |
| 	str	ip, [r4]
 | |
| 
 | |
| 	/* Wake up from sleep */
 | |
| 
 | |
| 	/* Clear sleep enable */
 | |
| 	ldr	ip, [r4]
 | |
| 	bic	ip, ip, #DEEPSLEEP_SLEEPENABLE_BIT
 | |
| 	str	ip, [r4]
 | |
| 
 | |
| 	/* initialize the DDR PLL controller */
 | |
| 
 | |
| 	/* Put PLL in reset */
 | |
| 	ldr	ip, [r3, #PLLCTL]
 | |
| 	bic	ip, ip, #PLLCTL_PLLRST
 | |
| 	str	ip, [r3, #PLLCTL]
 | |
| 
 | |
| 	/* Clear PLL power down */
 | |
| 	ldr	ip, [r3, #PLLCTL]
 | |
| 	bic	ip, ip, #PLLCTL_PLLPWRDN
 | |
| 	str	ip, [r3, #PLLCTL]
 | |
| 
 | |
|        mov	ip, #PLL_RESET_CYCLES
 | |
| 3:     subs	ip, ip, #0x1
 | |
|        bne	3b
 | |
| 
 | |
|        /* Bring PLL out of reset */
 | |
| 	ldr	ip, [r3, #PLLCTL]
 | |
| 	orr	ip, ip, #PLLCTL_PLLRST
 | |
| 	str	ip, [r3, #PLLCTL]
 | |
| 
 | |
| 	/* Wait for PLL to lock (assume prediv = 1, 25MHz OSCIN) */
 | |
|        mov	ip, #PLL_LOCK_CYCLES
 | |
| 4:     subs	ip, ip, #0x1
 | |
|        bne	4b
 | |
| 
 | |
|        /* Remove PLL from bypass mode */
 | |
| 	ldr	ip, [r3, #PLLCTL]
 | |
| 	bic	ip, ip, #PLLCTL_PLLENSRC
 | |
| 	orr	ip, ip, #PLLCTL_PLLEN
 | |
| 	str	ip, [r3, #PLLCTL]
 | |
| 
 | |
| 	/* Start 2x clock to DDR2 */
 | |
| 
 | |
| 	ldr	ip, [r3, #PLLDIV1]
 | |
| 	orr	ip, ip, #PLLDIV_EN
 | |
| 	str	ip, [r3, #PLLDIV1]
 | |
| 
 | |
| 	/* Enable VCLK */
 | |
| 
 | |
|        /* Enable DDR2 LPSC */
 | |
| 	mov	r7, r0
 | |
| 	mov	r0, #0x3
 | |
| 	bl davinci_ddr_psc_config
 | |
| 	mov	r0, r7
 | |
| 
 | |
| 	/* clear  MCLKSTOPEN */
 | |
| 
 | |
| 	ldr	ip, [r0, #DDR2_SDRCR_OFFSET]
 | |
| 	bic	ip, ip, #DDR2_MCLKSTOPEN_BIT
 | |
| 	str	ip, [r0, #DDR2_SDRCR_OFFSET]
 | |
| 
 | |
| 	ldr	ip, [r0, #DDR2_SDRCR_OFFSET]
 | |
| 	bic	ip, ip, #DDR2_LPMODEN_BIT
 | |
| 	str	ip, [r0, #DDR2_SDRCR_OFFSET]
 | |
| 
 | |
| 	/* Restore registers and return */
 | |
| 	ldmfd   sp!, {r0-r12, pc}
 | |
| 
 | |
| ENDPROC(davinci_cpu_suspend)
 | |
| 
 | |
| /*
 | |
|  * Disables or Enables DDR2 LPSC
 | |
|  * Register Usage:
 | |
|  * 	r0: Enable or Disable LPSC r0 = 0x3 => Enable, r0 = 0x2 => Disable LPSC
 | |
|  * 	r1: contains virtual base for DDR2 Power and Sleep controller (PSC)
 | |
|  * 	r2: contains PSC number for DDR2
 | |
|  */
 | |
| ENTRY(davinci_ddr_psc_config)
 | |
| 	/* Set next state in mdctl for DDR2 */
 | |
| 	mov	r6, #MDCTL
 | |
| 	add	r6, r6, r2, lsl #2
 | |
| 	ldr	ip, [r1, r6]
 | |
| 	bic	ip, ip, #MDSTAT_STATE_MASK
 | |
| 	orr	ip, ip, r0
 | |
| 	str	ip, [r1, r6]
 | |
| 
 | |
| 	/* Enable the Power Domain Transition Command */
 | |
| 	ldr	ip, [r1, #PTCMD]
 | |
| 	orr	ip, ip, #0x1
 | |
| 	str	ip, [r1, #PTCMD]
 | |
| 
 | |
| 	/* Check for Transition Complete (PTSTAT) */
 | |
| ptstat_done:
 | |
| 	ldr	ip, [r1, #PTSTAT]
 | |
| 	and	ip, ip, #0x1
 | |
| 	cmp 	ip, #0x0
 | |
| 	bne	ptstat_done
 | |
| 
 | |
| 	/* Check for DDR2 clock disable completion; */
 | |
| 	mov	r6, #MDSTAT
 | |
| 	add	r6, r6, r2, lsl #2
 | |
| ddr2clk_stop_done:
 | |
| 	ldr	ip, [r1, r6]
 | |
| 	and	ip, ip, #MDSTAT_STATE_MASK
 | |
| 	cmp	ip, r0
 | |
| 	bne	ddr2clk_stop_done
 | |
| 
 | |
| 	ret	lr
 | |
| ENDPROC(davinci_ddr_psc_config)
 | |
| 
 | |
| CACHE_FLUSH:
 | |
| #ifdef CONFIG_CPU_V6
 | |
| 	.word	v6_flush_kern_cache_all
 | |
| #else
 | |
| 	.word   arm926_flush_kern_cache_all
 | |
| #endif
 | |
| 
 | |
| ENTRY(davinci_cpu_suspend_sz)
 | |
| 	.word	. - davinci_cpu_suspend
 | |
| ENDPROC(davinci_cpu_suspend_sz)
 |