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