Loading...
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 | /* SPDX-License-Identifier: GPL-2.0-only */ /* * (C) Copyright 2009, Texas Instruments, Inc. https://www.ti.com/ */ /* 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_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 ret lr ENDPROC(davinci_ddr_psc_config) CACHE_FLUSH: #ifdef CONFIG_CPU_V6 .word v6_flush_kern_cache_all #else .word arm926_flush_kern_cache_all #endif ENTRY(davinci_cpu_suspend_sz) .word . - davinci_cpu_suspend ENDPROC(davinci_cpu_suspend_sz) |