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