1/* 2 * Suspend support for Zynq 3 * 4 * Copyright (C) 2012 Xilinx 5 * 6 * Soren Brinkmann <soren.brinkmann@xilinx.com> 7 * 8 * This software is licensed under the terms of the GNU General Public 9 * License version 2, as published by the Free Software Foundation, and 10 * may be copied, distributed, and modified under those terms. 11 * 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 */ 17 18#include <linux/linkage.h> 19 20#define ARMPLL_CTRL_OFFS 0x100 21#define DDRPLL_CTRL_OFFS 0x104 22#define PLLSTATUS_OFFS 0x10c 23#define DDR_CLK_CTRL_OFFS 0x124 24#define DCI_CLK_CTRL_OFFS 0x128 25#define MODE_STS_OFFS 0x54 26 27#define PLL_RESET_MASK 1 28#define PLL_PWRDWN_MASK (1 << 1) 29#define PLL_BYPASS_MASK (1 << 4) 30#define DCICLK_ENABLE_MASK 1 31#define DDRCLK_ENABLE_MASK 3 32#define ARM_LOCK_MASK (1 << 0) 33#define DDR_LOCK_MASK (1 << 1) 34#define DDRC_STATUS_MASK 7 35 36#define DDRC_OPMODE_SR 3 37#define MAXTRIES 100 38 39 .text 40 .align 3 41 42/** 43 * zynq_sys_suspend - Enter suspend 44 * @ddrc_base: Base address of the DDRC 45 * @slcr_base: Base address of the SLCR 46 * Returns -1 if DRAM subsystem is not gated off, 0 otherwise. 47 * 48 * This function is moved into OCM and finishes the suspend operation. I.e. DDR 49 * related clocks are gated off and the DDR PLL is bypassed. 50 */ 51ENTRY(zynq_sys_suspend) 52 push {r4 - r7} 53 54 /* Check DDRC is in self-refresh mode */ 55 ldr r2, [r0, #MODE_STS_OFFS] 56 and r2, #DDRC_STATUS_MASK 57 cmp r2, #DDRC_OPMODE_SR 58 movweq r3, #0xff00 59 bne suspend 60 61 mov r3, #MAXTRIES 62 movw r4, #0xfff0 63 movt r4, #0x1f 64 /* Wait for command queue empty */ 651: subs r3, #1 66 movweq r3, #0xff00 67 beq suspend 68 dsb sy 69 ldr r2, [r0, #MODE_STS_OFFS] 70 ands r2, r4 71 bne 1b 72 73 dsb sy 74 75 /* 76 * Wait for DDRC pipeline/queues to drain. 77 * We should wait ~40 DDR cycles. DDR is still at full speed while the 78 * CPU might already run in PLL bypass mode. The fastest speed the CPU 79 * runs at is ~1 GHz ~ 2 * DDR speed. 80 */ 81 mov r3, #160 821: nop 83 subs r3, #1 84 bne 1b 85 86 dsb sy 87 88 /* read back CAM status once more */ 89 ldr r2, [r0, #MODE_STS_OFFS] 90 ands r2, r4 91 movwne r3, #0xff00 92 bne suspend 93 94 /* Stop DDR clocks */ 95 ldr r2, [r1, #DDR_CLK_CTRL_OFFS] 96 bic r2, #DDRCLK_ENABLE_MASK 97 str r2, [r1, #DDR_CLK_CTRL_OFFS] 98 99 dmb st 100 101 ldr r2, [r1, #DCI_CLK_CTRL_OFFS] 102 bic r2, #DCICLK_ENABLE_MASK 103 str r2, [r1, #DCI_CLK_CTRL_OFFS] 104 105 dmb st 106 107 /* Bypass and powerdown DDR PLL */ 108 ldr r2, [r1, #DDRPLL_CTRL_OFFS] 109 orr r2, #PLL_BYPASS_MASK 110 str r2, [r1, #DDRPLL_CTRL_OFFS] 111 orr r2, #(PLL_PWRDWN_MASK | PLL_RESET_MASK) 112 str r2, [r1, #DDRPLL_CTRL_OFFS] 113 114 /* Bypass and powerdown ARM PLL */ 115 ldr r2, [r1, #ARMPLL_CTRL_OFFS] 116 orr r2, #PLL_BYPASS_MASK 117 str r2, [r1, #ARMPLL_CTRL_OFFS] 118 orr r2, #(PLL_PWRDWN_MASK | PLL_RESET_MASK) 119 str r2, [r1, #ARMPLL_CTRL_OFFS] 120 121suspend: 122 dsb sy 123 wfi 124 dsb sy 125 cmp r3, #0xff00 126 moveq r0, #-1 127 beq exit 128 129 /* Power up ARM PLL */ 130 ldr r2, [r1, #ARMPLL_CTRL_OFFS] 131 bic r2, #(PLL_PWRDWN_MASK | PLL_RESET_MASK) 132 str r2, [r1, #ARMPLL_CTRL_OFFS] 133 /* wait for lock */ 1341: ldr r2, [r1, #PLLSTATUS_OFFS] 135 ands r2, #ARM_LOCK_MASK 136 beq 1b 137 138 dsb sy 139 140 /* Disable ARM PLL bypass */ 141 ldr r2, [r1, #ARMPLL_CTRL_OFFS] 142 bic r2, #PLL_BYPASS_MASK 143 str r2, [r1, #ARMPLL_CTRL_OFFS] 144 145 dmb st 146 147 /* Power up DDR PLL */ 148 ldr r2, [r1, #DDRPLL_CTRL_OFFS] 149 bic r2, #(PLL_PWRDWN_MASK | PLL_RESET_MASK) 150 str r2, [r1, #DDRPLL_CTRL_OFFS] 151 /* wait for lock */ 1521: ldr r2, [r1, #PLLSTATUS_OFFS] 153 ands r2, #DDR_LOCK_MASK 154 beq 1b 155 156 dsb sy 157 158 /* Disable DDR PLL bypass */ 159 ldr r2, [r1, #DDRPLL_CTRL_OFFS] 160 bic r2, #PLL_BYPASS_MASK 161 str r2, [r1, #DDRPLL_CTRL_OFFS] 162 163 dmb st 164 165 /* Start DDR clocks */ 166 ldr r2, [r1, #DCI_CLK_CTRL_OFFS] 167 orr r2, #DCICLK_ENABLE_MASK 168 str r2, [r1, #DCI_CLK_CTRL_OFFS] 169 170 dmb st 171 172 ldr r2, [r1, #DDR_CLK_CTRL_OFFS] 173 orr r2, #DDRCLK_ENABLE_MASK 174 str r2, [r1, #DDR_CLK_CTRL_OFFS] 175 176 dsb sy 177 178 mov r0, #0 179exit: pop {r4 - r7} 180 bx lr 181 182ENTRY(zynq_sys_suspend_sz) 183 .word . - zynq_sys_suspend 184 185 ENDPROC(zynq_sys_suspend) 186