Commit | Line | Data |
---|---|---|
44fd8c7d AT |
1 | /* |
2 | * Copyright (C) 2014-2015 Altera Corporation. All rights reserved. | |
3 | * | |
4 | * This program is free software; you can redistribute it and/or modify it | |
5 | * under the terms and conditions 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 it will be useful, but WITHOUT | |
9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
11 | * more details. | |
12 | * | |
13 | * You should have received a copy of the GNU General Public License along with | |
14 | * this program. If not, see <http://www.gnu.org/licenses/>. | |
15 | */ | |
16 | #include <linux/linkage.h> | |
17 | #include <asm/assembler.h> | |
18 | ||
19 | #define MAX_LOOP_COUNT 1000 | |
20 | ||
21 | /* Register offset */ | |
22 | #define SDR_CTRLGRP_LOWPWREQ_ADDR 0x54 | |
23 | #define SDR_CTRLGRP_LOWPWRACK_ADDR 0x58 | |
24 | ||
25 | /* Bitfield positions */ | |
26 | #define SELFRSHREQ_POS 3 | |
27 | #define SELFRSHREQ_MASK 0x8 | |
28 | ||
29 | #define SELFRFSHACK_POS 1 | |
30 | #define SELFRFSHACK_MASK 0x2 | |
31 | ||
32 | /* | |
33 | * This code assumes that when the bootloader configured | |
34 | * the sdram controller for the DDR on the board it | |
35 | * configured the following fields depending on the DDR | |
36 | * vendor/configuration: | |
37 | * | |
38 | * sdr.ctrlcfg.lowpwreq.selfrfshmask | |
39 | * sdr.ctrlcfg.lowpwrtiming.clkdisablecycles | |
40 | * sdr.ctrlcfg.dramtiming4.selfrfshexit | |
41 | */ | |
42 | ||
43 | .arch armv7-a | |
44 | .text | |
45 | .align 3 | |
46 | ||
47 | /* | |
48 | * socfpga_sdram_self_refresh | |
49 | * | |
50 | * r0 : sdr_ctl_base_addr | |
51 | * r1 : temp storage of return value | |
52 | * r2 : temp storage of register values | |
53 | * r3 : loop counter | |
54 | * | |
55 | * return value: lower 16 bits: loop count going into self refresh | |
56 | * upper 16 bits: loop count exiting self refresh | |
57 | */ | |
58 | ENTRY(socfpga_sdram_self_refresh) | |
59 | /* Enable dynamic clock gating in the Power Control Register. */ | |
60 | mrc p15, 0, r2, c15, c0, 0 | |
61 | orr r2, r2, #1 | |
62 | mcr p15, 0, r2, c15, c0, 0 | |
63 | ||
64 | /* Enable self refresh: set sdr.ctrlgrp.lowpwreq.selfrshreq = 1 */ | |
65 | ldr r2, [r0, #SDR_CTRLGRP_LOWPWREQ_ADDR] | |
66 | orr r2, r2, #SELFRSHREQ_MASK | |
67 | str r2, [r0, #SDR_CTRLGRP_LOWPWREQ_ADDR] | |
68 | ||
69 | /* Poll until sdr.ctrlgrp.lowpwrack.selfrfshack == 1 or hit max loops */ | |
70 | mov r3, #0 | |
71 | while_ack_0: | |
72 | ldr r2, [r0, #SDR_CTRLGRP_LOWPWRACK_ADDR] | |
73 | and r2, r2, #SELFRFSHACK_MASK | |
74 | cmp r2, #SELFRFSHACK_MASK | |
75 | beq ack_1 | |
76 | ||
77 | add r3, #1 | |
78 | cmp r3, #MAX_LOOP_COUNT | |
79 | bne while_ack_0 | |
80 | ||
81 | ack_1: | |
82 | mov r1, r3 | |
83 | ||
84 | /* | |
85 | * Execute an ISB instruction to ensure that all of the | |
86 | * CP15 register changes have been committed. | |
87 | */ | |
88 | isb | |
89 | ||
90 | /* | |
91 | * Execute a barrier instruction to ensure that all cache, | |
92 | * TLB and branch predictor maintenance operations issued | |
93 | * by any CPU in the cluster have completed. | |
94 | */ | |
95 | dsb | |
96 | dmb | |
97 | ||
98 | wfi | |
99 | ||
100 | /* Disable self-refresh: set sdr.ctrlgrp.lowpwreq.selfrshreq = 0 */ | |
101 | ldr r2, [r0, #SDR_CTRLGRP_LOWPWREQ_ADDR] | |
102 | bic r2, r2, #SELFRSHREQ_MASK | |
103 | str r2, [r0, #SDR_CTRLGRP_LOWPWREQ_ADDR] | |
104 | ||
105 | /* Poll until sdr.ctrlgrp.lowpwrack.selfrfshack == 0 or hit max loops */ | |
106 | mov r3, #0 | |
107 | while_ack_1: | |
108 | ldr r2, [r0, #SDR_CTRLGRP_LOWPWRACK_ADDR] | |
109 | and r2, r2, #SELFRFSHACK_MASK | |
110 | cmp r2, #SELFRFSHACK_MASK | |
111 | bne ack_0 | |
112 | ||
113 | add r3, #1 | |
114 | cmp r3, #MAX_LOOP_COUNT | |
115 | bne while_ack_1 | |
116 | ||
117 | ack_0: | |
118 | /* | |
119 | * Prepare return value: | |
120 | * Shift loop count for exiting self refresh into upper 16 bits. | |
121 | * Leave loop count for requesting self refresh in lower 16 bits. | |
122 | */ | |
123 | mov r3, r3, lsl #16 | |
124 | add r1, r1, r3 | |
125 | ||
126 | /* Disable dynamic clock gating in the Power Control Register. */ | |
127 | mrc p15, 0, r2, c15, c0, 0 | |
128 | bic r2, r2, #1 | |
129 | mcr p15, 0, r2, c15, c0, 0 | |
130 | ||
131 | mov r0, r1 @ return value | |
132 | bx lr @ return | |
133 | ||
134 | ENDPROC(socfpga_sdram_self_refresh) | |
135 | ENTRY(socfpga_sdram_self_refresh_sz) | |
136 | .word . - socfpga_sdram_self_refresh |