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