| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229 | /* * (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 "psc.h"#include "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	.arch	armv5te/* * 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_CYCLES1:     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_CYCLES2:     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_CYCLES3:     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_CYCLES4:     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 #2ddr2clk_stop_done:	ldr	ip, [r1, r6]	and	ip, ip, #MDSTAT_STATE_MASK	cmp	ip, r0	bne	ddr2clk_stop_done	ret	lrENDPROC(davinci_ddr_psc_config)CACHE_FLUSH:#ifdef CONFIG_CPU_V6	.word	v6_flush_kern_cache_all#else	.word   arm926_flush_kern_cache_all#endifENTRY(davinci_cpu_suspend_sz)	.word	. - davinci_cpu_suspendENDPROC(davinci_cpu_suspend_sz)
 |