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 */ 58ENTRY(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 71while_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 81ack_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 107while_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 117ack_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 134ENDPROC(socfpga_sdram_self_refresh) 135ENTRY(socfpga_sdram_self_refresh_sz) 136 .word . - socfpga_sdram_self_refresh 137