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 "psc.h" 25#include "ddr2.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 .arch armv5te 41/* 42 * Move DaVinci into deep sleep state 43 * 44 * Note: This code is copied to internal SRAM by PM code. When the DaVinci 45 * wakes up it continues execution at the point it went to sleep. 46 * Register Usage: 47 * r0: contains virtual base for DDR2 controller 48 * r1: contains virtual base for DDR2 Power and Sleep controller (PSC) 49 * r2: contains PSC number for DDR2 50 * r3: contains virtual base DDR2 PLL controller 51 * r4: contains virtual address of the DEEPSLEEP register 52 */ 53ENTRY(davinci_cpu_suspend) 54 stmfd sp!, {r0-r12, lr} @ save registers on stack 55 56 ldr ip, CACHE_FLUSH 57 blx ip 58 59 ldmia r0, {r0-r4} 60 61 /* 62 * Switch DDR to self-refresh mode. 63 */ 64 65 /* calculate SDRCR address */ 66 ldr ip, [r0, #DDR2_SDRCR_OFFSET] 67 bic ip, ip, #DDR2_SRPD_BIT 68 orr ip, ip, #DDR2_LPMODEN_BIT 69 str ip, [r0, #DDR2_SDRCR_OFFSET] 70 71 ldr ip, [r0, #DDR2_SDRCR_OFFSET] 72 orr ip, ip, #DDR2_MCLKSTOPEN_BIT 73 str ip, [r0, #DDR2_SDRCR_OFFSET] 74 75 mov ip, #PHYRDY_CYCLES 761: subs ip, ip, #0x1 77 bne 1b 78 79 /* Disable DDR2 LPSC */ 80 mov r7, r0 81 mov r0, #0x2 82 bl davinci_ddr_psc_config 83 mov r0, r7 84 85 /* Disable clock to DDR PHY */ 86 ldr ip, [r3, #PLLDIV1] 87 bic ip, ip, #PLLDIV_EN 88 str ip, [r3, #PLLDIV1] 89 90 /* Put the DDR PLL in bypass and power down */ 91 ldr ip, [r3, #PLLCTL] 92 bic ip, ip, #PLLCTL_PLLENSRC 93 bic ip, ip, #PLLCTL_PLLEN 94 str ip, [r3, #PLLCTL] 95 96 /* Wait for PLL to switch to bypass */ 97 mov ip, #PLL_BYPASS_CYCLES 982: subs ip, ip, #0x1 99 bne 2b 100 101 /* Power down the PLL */ 102 ldr ip, [r3, #PLLCTL] 103 orr ip, ip, #PLLCTL_PLLPWRDN 104 str ip, [r3, #PLLCTL] 105 106 /* Go to deep sleep */ 107 ldr ip, [r4] 108 orr ip, ip, #DEEPSLEEP_SLEEPENABLE_BIT 109 /* System goes to sleep beyond after this instruction */ 110 str ip, [r4] 111 112 /* Wake up from sleep */ 113 114 /* Clear sleep enable */ 115 ldr ip, [r4] 116 bic ip, ip, #DEEPSLEEP_SLEEPENABLE_BIT 117 str ip, [r4] 118 119 /* initialize the DDR PLL controller */ 120 121 /* Put PLL in reset */ 122 ldr ip, [r3, #PLLCTL] 123 bic ip, ip, #PLLCTL_PLLRST 124 str ip, [r3, #PLLCTL] 125 126 /* Clear PLL power down */ 127 ldr ip, [r3, #PLLCTL] 128 bic ip, ip, #PLLCTL_PLLPWRDN 129 str ip, [r3, #PLLCTL] 130 131 mov ip, #PLL_RESET_CYCLES 1323: subs ip, ip, #0x1 133 bne 3b 134 135 /* Bring PLL out of reset */ 136 ldr ip, [r3, #PLLCTL] 137 orr ip, ip, #PLLCTL_PLLRST 138 str ip, [r3, #PLLCTL] 139 140 /* Wait for PLL to lock (assume prediv = 1, 25MHz OSCIN) */ 141 mov ip, #PLL_LOCK_CYCLES 1424: subs ip, ip, #0x1 143 bne 4b 144 145 /* Remove PLL from bypass mode */ 146 ldr ip, [r3, #PLLCTL] 147 bic ip, ip, #PLLCTL_PLLENSRC 148 orr ip, ip, #PLLCTL_PLLEN 149 str ip, [r3, #PLLCTL] 150 151 /* Start 2x clock to DDR2 */ 152 153 ldr ip, [r3, #PLLDIV1] 154 orr ip, ip, #PLLDIV_EN 155 str ip, [r3, #PLLDIV1] 156 157 /* Enable VCLK */ 158 159 /* Enable DDR2 LPSC */ 160 mov r7, r0 161 mov r0, #0x3 162 bl davinci_ddr_psc_config 163 mov r0, r7 164 165 /* clear MCLKSTOPEN */ 166 167 ldr ip, [r0, #DDR2_SDRCR_OFFSET] 168 bic ip, ip, #DDR2_MCLKSTOPEN_BIT 169 str ip, [r0, #DDR2_SDRCR_OFFSET] 170 171 ldr ip, [r0, #DDR2_SDRCR_OFFSET] 172 bic ip, ip, #DDR2_LPMODEN_BIT 173 str ip, [r0, #DDR2_SDRCR_OFFSET] 174 175 /* Restore registers and return */ 176 ldmfd sp!, {r0-r12, pc} 177 178ENDPROC(davinci_cpu_suspend) 179 180/* 181 * Disables or Enables DDR2 LPSC 182 * Register Usage: 183 * r0: Enable or Disable LPSC r0 = 0x3 => Enable, r0 = 0x2 => Disable LPSC 184 * r1: contains virtual base for DDR2 Power and Sleep controller (PSC) 185 * r2: contains PSC number for DDR2 186 */ 187ENTRY(davinci_ddr_psc_config) 188 /* Set next state in mdctl for DDR2 */ 189 mov r6, #MDCTL 190 add r6, r6, r2, lsl #2 191 ldr ip, [r1, r6] 192 bic ip, ip, #MDSTAT_STATE_MASK 193 orr ip, ip, r0 194 str ip, [r1, r6] 195 196 /* Enable the Power Domain Transition Command */ 197 ldr ip, [r1, #PTCMD] 198 orr ip, ip, #0x1 199 str ip, [r1, #PTCMD] 200 201 /* Check for Transition Complete (PTSTAT) */ 202ptstat_done: 203 ldr ip, [r1, #PTSTAT] 204 and ip, ip, #0x1 205 cmp ip, #0x0 206 bne ptstat_done 207 208 /* Check for DDR2 clock disable completion; */ 209 mov r6, #MDSTAT 210 add r6, r6, r2, lsl #2 211ddr2clk_stop_done: 212 ldr ip, [r1, r6] 213 and ip, ip, #MDSTAT_STATE_MASK 214 cmp ip, r0 215 bne ddr2clk_stop_done 216 217 ret lr 218ENDPROC(davinci_ddr_psc_config) 219 220CACHE_FLUSH: 221#ifdef CONFIG_CPU_V6 222 .word v6_flush_kern_cache_all 223#else 224 .word arm926_flush_kern_cache_all 225#endif 226 227ENTRY(davinci_cpu_suspend_sz) 228 .word . - davinci_cpu_suspend 229ENDPROC(davinci_cpu_suspend_sz) 230