Back to home page

OSCL-LXR

 
 

    


0001 /* SPDX-License-Identifier: GPL-2.0-only */
0002 /*
0003  * Copyright (C) 2014-2015 Altera Corporation. All rights reserved.
0004  */
0005 #include <linux/linkage.h>
0006 #include <asm/assembler.h>
0007 
0008 #define MAX_LOOP_COUNT      1000
0009 
0010 /* Register offset */
0011 #define SDR_CTRLGRP_LOWPWREQ_ADDR       0x54
0012 #define SDR_CTRLGRP_LOWPWRACK_ADDR      0x58
0013 
0014 /* Bitfield positions */
0015 #define SELFRSHREQ_POS                  3
0016 #define SELFRSHREQ_MASK                 0x8
0017 
0018 #define SELFRFSHACK_POS                 1
0019 #define SELFRFSHACK_MASK                0x2
0020 
0021     /*
0022      * This code assumes that when the bootloader configured
0023      * the sdram controller for the DDR on the board it
0024      * configured the following fields depending on the DDR
0025      * vendor/configuration:
0026      *
0027      * sdr.ctrlcfg.lowpwreq.selfrfshmask
0028      * sdr.ctrlcfg.lowpwrtiming.clkdisablecycles
0029      * sdr.ctrlcfg.dramtiming4.selfrfshexit
0030      */
0031 
0032     .arch   armv7-a
0033     .text
0034     .align 3
0035 
0036     /*
0037      * socfpga_sdram_self_refresh
0038      *
0039      *  r0 : sdr_ctl_base_addr
0040      *  r1 : temp storage of return value
0041      *  r2 : temp storage of register values
0042      *  r3 : loop counter
0043      *
0044      *  return value: lower 16 bits: loop count going into self refresh
0045      *                upper 16 bits: loop count exiting self refresh
0046      */
0047 ENTRY(socfpga_sdram_self_refresh)
0048     /* Enable dynamic clock gating in the Power Control Register. */
0049     mrc p15, 0, r2, c15, c0, 0
0050     orr r2, r2, #1
0051     mcr p15, 0, r2, c15, c0, 0
0052 
0053     /* Enable self refresh: set sdr.ctrlgrp.lowpwreq.selfrshreq = 1 */
0054     ldr r2, [r0, #SDR_CTRLGRP_LOWPWREQ_ADDR]
0055     orr r2, r2, #SELFRSHREQ_MASK
0056     str r2, [r0, #SDR_CTRLGRP_LOWPWREQ_ADDR]
0057 
0058     /* Poll until sdr.ctrlgrp.lowpwrack.selfrfshack == 1 or hit max loops */
0059     mov r3, #0
0060 while_ack_0:
0061     ldr r2, [r0, #SDR_CTRLGRP_LOWPWRACK_ADDR]
0062     and r2, r2, #SELFRFSHACK_MASK
0063     cmp r2, #SELFRFSHACK_MASK
0064     beq ack_1
0065 
0066     add r3, #1
0067     cmp r3, #MAX_LOOP_COUNT
0068     bne while_ack_0
0069 
0070 ack_1:
0071     mov r1, r3
0072 
0073     /*
0074      * Execute an ISB instruction to ensure that all of the
0075      * CP15 register changes have been committed.
0076      */
0077     isb
0078 
0079     /*
0080      * Execute a barrier instruction to ensure that all cache,
0081      * TLB and branch predictor maintenance operations issued
0082      * by any CPU in the cluster have completed.
0083      */
0084     dsb
0085     dmb
0086 
0087     wfi
0088 
0089     /* Disable self-refresh: set sdr.ctrlgrp.lowpwreq.selfrshreq = 0 */
0090     ldr r2, [r0, #SDR_CTRLGRP_LOWPWREQ_ADDR]
0091     bic r2, r2, #SELFRSHREQ_MASK
0092     str r2, [r0, #SDR_CTRLGRP_LOWPWREQ_ADDR]
0093 
0094     /* Poll until sdr.ctrlgrp.lowpwrack.selfrfshack == 0 or hit max loops */
0095     mov r3, #0
0096 while_ack_1:
0097     ldr r2, [r0, #SDR_CTRLGRP_LOWPWRACK_ADDR]
0098     and r2, r2, #SELFRFSHACK_MASK
0099     cmp r2, #SELFRFSHACK_MASK
0100     bne ack_0
0101 
0102     add r3, #1
0103     cmp r3, #MAX_LOOP_COUNT
0104     bne while_ack_1
0105 
0106 ack_0:
0107     /*
0108      * Prepare return value:
0109      * Shift loop count for exiting self refresh into upper 16 bits.
0110      * Leave loop count for requesting self refresh in lower 16 bits.
0111      */
0112     mov r3, r3, lsl #16
0113     add r1, r1, r3
0114 
0115     /* Disable dynamic clock gating in the Power Control Register. */
0116     mrc p15, 0, r2, c15, c0, 0
0117     bic r2, r2, #1
0118     mcr p15, 0, r2, c15, c0, 0
0119 
0120     mov     r0, r1                  @ return value
0121     bx  lr          @ return
0122 
0123 ENDPROC(socfpga_sdram_self_refresh)
0124 ENTRY(socfpga_sdram_self_refresh_sz)
0125     .word   . - socfpga_sdram_self_refresh