blob: cf46b7f911084ecac714f3cc0add98d131447cb0 [file] [log] [blame]
/*
* Copyright (c) 2013-2017, ARM Limited and Contributors. All rights reserved.
* Copyright 2017-2018 NXP.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
void lpddr4_dvfs_hwffc(int init_vrcg, int init_fsp, int target_freq,
int discamdrain)
{
uint32_t tmp, tmp_t;
INFO("hwffc enter\n");
/* step 1: hwffc flow enter, set the HWFCCCTL */
tmp = ((init_fsp << 4) & 0x10) | ((init_vrcg << 5) & 0x20) | 0x40;
tmp |= 0x3;
mmio_write_32(IMX_DDRC_BASE + DDRC_HWFFCCTL, tmp);
/*
* set SWCTL.sw_done to disable quasi-dynamic register programming
* outside reset
*/
mmio_write_32(IMX_DDRC_BASE + DDRC_SWCTL, 0x0);
mmio_write_32(IMX_DDRC_BASE + DDRC_DFIMISC, 0x11);
/*
* set SWCTL.sw_done to enable quasi-dynamic register programming
* outside reset.
*/
mmio_write_32(IMX_DDRC_BASE + DDRC_SWCTL, 0x1);
/*wait SWSTAT.sw_done_ack to 1 */
while (!(mmio_read_32(IMX_DDRC_BASE + DDRC_SWSTAT) & 0x1))
;
/* wait for DBGCAM is empty */
if (discamdrain)
while ((mmio_read_32(IMX_DDRC_BASE + DDRC_DBGCAM) &
0x30000000) != 0x30000000)
;
/* set HWFFC requirements, ddrc_csysfreqency_ddrc[1:0] = 2b'10;
* [15]: ccmsrcgpcmix_ddrc_csysdisdrain_ddrc;
* [14:13]: ccmsrcgpcmix_ddrc_csysfrequency_ddrc[1:0];
* [12]: ccmsrcgpcmix_ddrc_csysmode_ddrc;
*/
tmp = mmio_read_32(0x303a0164);
tmp &= 0xFFFF0FFF;
tmp |= ((discamdrain << 15) & 0x8000);
tmp |= ((target_freq << 13) & 0x6000);
tmp |= 0x1000;
mmio_write_32(0x303a0164, tmp);
/* set the gpc_ddr1_core_csysreq to active low */
tmp = mmio_read_32(0x303a01fc);
tmp &= 0xfffffffe;
mmio_write_32(0x303a01fc, tmp);
/* wait gpc_ddr1_core_csysack to active low */
while ((mmio_read_32(0x303a01fc) & 0x10000))
;
/* step B: switch the clock */
if (target_freq == 0x1) {
/* change the clock source of dram_alt_clk_root to source 5 --400MHz */
mmio_write_32(0x3038a008, (0x7 << 24) | (0x7 << 16));
mmio_write_32(0x303aa004, (0x5 << 24));
/* change the clock source of dram_apb_clk_root to source 2 --40MHz/2 */
mmio_write_32(0x3038a088, (0x7 << 24) | (0x7 << 16));
mmio_write_32(0x3038a084, (0x2 << 24) | (0x1 << 16));;
/* bypass the DRAM PLL */
mmio_write_32(0x30389804, 1 << 24);
} else if (target_freq == 0x2) {
/* change the clock source of dram_alt_clk_root to source 2 --100MHz */
mmio_write_32(0x3038a008, (0x7 << 24) | (0x7 << 16));
mmio_write_32(0x3038a004, (0x2 << 24));
/* change the clock source of dram_apb_clk_root to source 2 --40Mhz/2 */
mmio_write_32(0x3038a088, (0x7 << 24) | (0x7 << 16));
mmio_write_32(0x3038a084, (0x2 << 24) | (0x1 << 16));;
/* bypass the DRAM PLL */
mmio_write_32(0x30389804, 1 << 24);
} else {
/* switch to the default freq fsp = 0x1 3200mts */
mmio_write_32(0x3038a088,(0x7<<24)|(0x7<<16));
/* to source 4 --800MHz/ 4 */
mmio_write_32(0x3038a084,(0x4<<24)|(0x3<<16));
mmio_write_32(0x30389808, 1<<24);
}
/* step C: exit hwffc flow */
tmp = mmio_read_32(0x303a01fc);
tmp |= 0x1;
mmio_write_32(0x303a01fc, tmp);
/* wait gpc_ddr1_core_csysack to high */
while (!(mmio_read_32(0x303a01fc) & 0x10000))
;
/* [1:0]-->2b'10, to disable HWFFC */
mmio_write_32(IMX_DDRC_BASE + DDRC_HWFFCCTL, 0x72);
/*wait until hwffc_in_progress = 0 */
while(mmio_read_32(IMX_DDRC_BASE + DDRC_HWFFCSTAT) & 0x1)
;
mmio_write_32(IMX_DDRC_BASE + DDRC_SWCTL, 0x0);
/* set MSTR.frequency_mode MSTR.[29], MSTR2.target_frequency[1:0] */
tmp = mmio_read_32(IMX_DDRC_BASE + DDRC_MSTR);
tmp |= 0x20000000;
mmio_write_32(IMX_DDRC_BASE + DDRC_MSTR, tmp);
tmp = mmio_read_32(IMX_DDRC_BASE + DDRC_HWFFCSTAT);
tmp_t = (tmp >> 4) & 0x3;
tmp = mmio_read_32(IMX_DDRC_BASE + DDRC_MSTR2);
tmp = (tmp & 0xfffffffc) | tmp_t;
mmio_write_32(IMX_DDRC_BASE + DDRC_MSTR2, tmp);
mmio_write_32(IMX_DDRC_BASE + DDRC_SWCTL, 0x1);
mmio_write_32(IMX_DDRC_BASE + DDRC_HWFFCCTL, 0x70);
/* why we need below flow */
mmio_write_32(IMX_DDRC_BASE + DDRC_PWRCTL, 0x1a8);
while ((mmio_read_32(IMX_DDRC_BASE + DDRC_STAT) & 0x3) != 0x3)
;
/* wait SDRAM into self refresh state */
while(!(mmio_read_32(IMX_DDRC_BASE + DDRC_STAT) & 0x30))
;
tmp = mmio_read_32(IMX_DDRC_BASE + DDRC_CRCPARSTAT);
tmp = mmio_read_32(IMX_DDRC_BASE + DDRC_CRCPARSTAT);
mmio_write_32(IMX_DDRC_BASE + DDRC_PWRCTL, 0x188);
/* wait STAT to normal mode */
while ((mmio_read_32(IMX_DDRC_BASE + DDRC_STAT) & 0x3) != 0x1)
;
INFO("hwffc exit\n");
}