sleep.S 5.4 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224
/*
 * (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/memory.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

	mov	pc, lr
ENDPROC(davinci_ddr_psc_config)

CACHE_FLUSH:
	.word	arm926_flush_kern_cache_all

ENTRY(davinci_cpu_suspend_sz)
	.word	. - davinci_cpu_suspend
ENDPROC(davinci_cpu_suspend_sz)