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