1/* 2 * (C) Copyright 2009, Texas Instruments, Inc. http://www.ti.com/ 3 * 4 * This program is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU General Public License 6 * version 2 as published by the Free Software Foundation. 7 * 8 * This program is distributed in the hope that it will be useful, 9 * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR /PURPOSE. See the 11 * GNU General Public License for more details. 12 * 13 * You should have received a copy of the GNU General Public License 14 * along with this program; if not, write to the Free Software 15 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 16 * MA 02111-1307 USA 17 */ 18 19/* replicated define because linux/bitops.h cannot be included in assembly */ 20#define BIT(nr) (1 << (nr)) 21 22#include <linux/linkage.h> 23#include <asm/assembler.h> 24#include <mach/psc.h> 25#include <mach/memory.h> 26 27#include "clock.h" 28 29/* Arbitrary, hardware currently does not update PHYRDY correctly */ 30#define PHYRDY_CYCLES 0x1000 31 32/* Assume 25 MHz speed for the cycle conversions since PLLs are bypassed */ 33#define PLL_BYPASS_CYCLES (PLL_BYPASS_TIME * 25) 34#define PLL_RESET_CYCLES (PLL_RESET_TIME * 25) 35#define PLL_LOCK_CYCLES (PLL_LOCK_TIME * 25) 36 37#define DEEPSLEEP_SLEEPENABLE_BIT BIT(31) 38 39 .text 40/* 41 * Move DaVinci into deep sleep state 42 * 43 * Note: This code is copied to internal SRAM by PM code. When the DaVinci 44 * wakes up it continues execution at the point it went to sleep. 45 * Register Usage: 46 * r0: contains virtual base for DDR2 controller 47 * r1: contains virtual base for DDR2 Power and Sleep controller (PSC) 48 * r2: contains PSC number for DDR2 49 * r3: contains virtual base DDR2 PLL controller 50 * r4: contains virtual address of the DEEPSLEEP register 51 */ 52ENTRY(davinci_cpu_suspend) 53 stmfd sp!, {r0-r12, lr} @ save registers on stack 54 55 ldr ip, CACHE_FLUSH 56 blx ip 57 58 ldmia r0, {r0-r4} 59 60 /* 61 * Switch DDR to self-refresh mode. 62 */ 63 64 /* calculate SDRCR address */ 65 ldr ip, [r0, #DDR2_SDRCR_OFFSET] 66 bic ip, ip, #DDR2_SRPD_BIT 67 orr ip, ip, #DDR2_LPMODEN_BIT 68 str ip, [r0, #DDR2_SDRCR_OFFSET] 69 70 ldr ip, [r0, #DDR2_SDRCR_OFFSET] 71 orr ip, ip, #DDR2_MCLKSTOPEN_BIT 72 str ip, [r0, #DDR2_SDRCR_OFFSET] 73 74 mov ip, #PHYRDY_CYCLES 751: subs ip, ip, #0x1 76 bne 1b 77 78 /* Disable DDR2 LPSC */ 79 mov r7, r0 80 mov r0, #0x2 81 bl davinci_ddr_psc_config 82 mov r0, r7 83 84 /* Disable clock to DDR PHY */ 85 ldr ip, [r3, #PLLDIV1] 86 bic ip, ip, #PLLDIV_EN 87 str ip, [r3, #PLLDIV1] 88 89 /* Put the DDR PLL in bypass and power down */ 90 ldr ip, [r3, #PLLCTL] 91 bic ip, ip, #PLLCTL_PLLENSRC 92 bic ip, ip, #PLLCTL_PLLEN 93 str ip, [r3, #PLLCTL] 94 95 /* Wait for PLL to switch to bypass */ 96 mov ip, #PLL_BYPASS_CYCLES 972: subs ip, ip, #0x1 98 bne 2b 99 100 /* Power down the PLL */ 101 ldr ip, [r3, #PLLCTL] 102 orr ip, ip, #PLLCTL_PLLPWRDN 103 str ip, [r3, #PLLCTL] 104 105 /* Go to deep sleep */ 106 ldr ip, [r4] 107 orr ip, ip, #DEEPSLEEP_SLEEPENABLE_BIT 108 /* System goes to sleep beyond after this instruction */ 109 str ip, [r4] 110 111 /* Wake up from sleep */ 112 113 /* Clear sleep enable */ 114 ldr ip, [r4] 115 bic ip, ip, #DEEPSLEEP_SLEEPENABLE_BIT 116 str ip, [r4] 117 118 /* initialize the DDR PLL controller */ 119 120 /* Put PLL in reset */ 121 ldr ip, [r3, #PLLCTL] 122 bic ip, ip, #PLLCTL_PLLRST 123 str ip, [r3, #PLLCTL] 124 125 /* Clear PLL power down */ 126 ldr ip, [r3, #PLLCTL] 127 bic ip, ip, #PLLCTL_PLLPWRDN 128 str ip, [r3, #PLLCTL] 129 130 mov ip, #PLL_RESET_CYCLES 1313: subs ip, ip, #0x1 132 bne 3b 133 134 /* Bring PLL out of reset */ 135 ldr ip, [r3, #PLLCTL] 136 orr ip, ip, #PLLCTL_PLLRST 137 str ip, [r3, #PLLCTL] 138 139 /* Wait for PLL to lock (assume prediv = 1, 25MHz OSCIN) */ 140 mov ip, #PLL_LOCK_CYCLES 1414: subs ip, ip, #0x1 142 bne 4b 143 144 /* Remove PLL from bypass mode */ 145 ldr ip, [r3, #PLLCTL] 146 bic ip, ip, #PLLCTL_PLLENSRC 147 orr ip, ip, #PLLCTL_PLLEN 148 str ip, [r3, #PLLCTL] 149 150 /* Start 2x clock to DDR2 */ 151 152 ldr ip, [r3, #PLLDIV1] 153 orr ip, ip, #PLLDIV_EN 154 str ip, [r3, #PLLDIV1] 155 156 /* Enable VCLK */ 157 158 /* Enable DDR2 LPSC */ 159 mov r7, r0 160 mov r0, #0x3 161 bl davinci_ddr_psc_config 162 mov r0, r7 163 164 /* clear MCLKSTOPEN */ 165 166 ldr ip, [r0, #DDR2_SDRCR_OFFSET] 167 bic ip, ip, #DDR2_MCLKSTOPEN_BIT 168 str ip, [r0, #DDR2_SDRCR_OFFSET] 169 170 ldr ip, [r0, #DDR2_SDRCR_OFFSET] 171 bic ip, ip, #DDR2_LPMODEN_BIT 172 str ip, [r0, #DDR2_SDRCR_OFFSET] 173 174 /* Restore registers and return */ 175 ldmfd sp!, {r0-r12, pc} 176 177ENDPROC(davinci_cpu_suspend) 178 179/* 180 * Disables or Enables DDR2 LPSC 181 * Register Usage: 182 * r0: Enable or Disable LPSC r0 = 0x3 => Enable, r0 = 0x2 => Disable LPSC 183 * r1: contains virtual base for DDR2 Power and Sleep controller (PSC) 184 * r2: contains PSC number for DDR2 185 */ 186ENTRY(davinci_ddr_psc_config) 187 /* Set next state in mdctl for DDR2 */ 188 mov r6, #MDCTL 189 add r6, r6, r2, lsl #2 190 ldr ip, [r1, r6] 191 bic ip, ip, #MDSTAT_STATE_MASK 192 orr ip, ip, r0 193 str ip, [r1, r6] 194 195 /* Enable the Power Domain Transition Command */ 196 ldr ip, [r1, #PTCMD] 197 orr ip, ip, #0x1 198 str ip, [r1, #PTCMD] 199 200 /* Check for Transition Complete (PTSTAT) */ 201ptstat_done: 202 ldr ip, [r1, #PTSTAT] 203 and ip, ip, #0x1 204 cmp ip, #0x0 205 bne ptstat_done 206 207 /* Check for DDR2 clock disable completion; */ 208 mov r6, #MDSTAT 209 add r6, r6, r2, lsl #2 210ddr2clk_stop_done: 211 ldr ip, [r1, r6] 212 and ip, ip, #MDSTAT_STATE_MASK 213 cmp ip, r0 214 bne ddr2clk_stop_done 215 216 mov pc, lr 217ENDPROC(davinci_ddr_psc_config) 218 219CACHE_FLUSH: 220 .word arm926_flush_kern_cache_all 221 222ENTRY(davinci_cpu_suspend_sz) 223 .word . - davinci_cpu_suspend 224ENDPROC(davinci_cpu_suspend_sz) 225