/* * Copyright 2018 NXP * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #define SRC_IPS_BASE_ADDR IMX_SRC_BASE #define SRC_DDRC_RCR_ADDR (SRC_IPS_BASE_ADDR + 0x1000) #define GPC_PU_PWRHSK (IMX_GPC_BASE + 0x01FC) #define CCM_SRC_CTRL_OFFSET (IMX_CCM_BASE + 0x800) #define CCM_CCGR_OFFSET (IMX_CCM_BASE + 0x4000) #define CCM_SRC_CTRL(n) (CCM_SRC_CTRL_OFFSET + 0x10 * n) #define CCM_CCGR(n) (CCM_CCGR_OFFSET + 0x10 * n) void lpddr4_enter_retention(void) { unsigned int tmp, tmp_t, i; INFO("enter lpddr4 retention\n"); /* wait DBGCAM to be empty */ do { tmp = mmio_read_32(DDRC_DBGCAM(0)); } while(tmp != 0x36000000); /* Blocks AXI ports from taking anymore transactions */ mmio_write_32(DDRC_PCTRL_0(0), 0x00000000); /* Waits unit all AXI ports are idle */ do { tmp = mmio_read_32(DDRC_PSTAT(0)); } while(tmp & 0x10001); /* enters self refresh */ //reg32setbit(DDRC_PWRCTL(0), 5); mmio_write_32(DDRC_PWRCTL(0), 0x000000aa); tmp=0; /* self-refresh state */ while (tmp!=0x223) { tmp = 0x33f & (mmio_read_32((DDRC_STAT(0)))); INFO("C: waiting for STAT selfref_type= Self Refresh\n"); } mmio_write_32(DDRC_DFIMISC(0), 0x00000000); /* set SWCTL.sw_done to disable quasi-dynamic register programming outside reset. */ mmio_write_32(DDRC_SWCTL(0), 0x00000000); mmio_write_32(DDRC_DFIMISC(0), 0x00001f00); mmio_write_32(DDRC_DFIMISC(0), 0x00001f20); /* wait DFISTAT.dfi_init_complete to 0 */ tmp_t = 0; while (tmp_t==1) { tmp = mmio_read_32(DDRC_DFISTAT(0)); tmp_t = tmp & 0x01; } mmio_write_32(DDRC_DFIMISC(0), 0x00001f00); /* wait DFISTAT.dfi_init_complete to 1 */ tmp_t = 0; while (tmp_t==0) { tmp = mmio_read_32(DDRC_DFISTAT(0)); tmp_t = tmp & 0x01; } /* set SWCTL.sw_done to enable quasi-dynamic register programming outside reset. */ mmio_write_32(DDRC_SWCTL(0), 0x00000001); /* should check PhyInLP3 pub reg */ dwc_ddrphy_apb_wr(0xd0000,0x0); tmp = mmio_read_32(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4*0x00090028); tmp = tmp & 0x1; if (tmp) INFO("C: PhyInLP3 = 1\n"); else INFO("vt_fail5\n"); dwc_ddrphy_apb_wr(0xd0000,0x1); for (i=0; i<20; i++){ } #if defined(PLAT_IMX8M) /* pwrdnreqn_async adbm/adbs of ddr */ mmio_clrbits_32(GPC_PU_PWRHSK, (1 << 1)); do { tmp = mmio_read_32(GPC_PU_PWRHSK); // printf("C: wait pwrdnackn_async clr\n"); } while(tmp&(0x1<<18));//wait untill pwrdnackn_async=0 mmio_setbits_32(GPC_PU_PWRHSK, (1 << 1)); #else /* pwrdnreqn_async adbm/adbs of ddr */ mmio_clrbits_32(GPC_PU_PWRHSK, (1 << 2)); do { tmp = mmio_read_32(GPC_PU_PWRHSK); INFO("C: wait pwrdnackn_async clr\n"); } while(tmp&(0x1<<20));//wait untill pwrdnackn_async=0 mmio_setbits_32(GPC_PU_PWRHSK, (1 << 2)); #endif /* remove PowerOk */ mmio_write_32(SRC_DDRC_RCR_ADDR, 0x8F000008); INFO("vt_event1\n"); for (i=0; i<20; i++) { } mmio_write_32(CCM_CCGR(5),0); mmio_write_32(CCM_SRC_CTRL(15),2);// when test on chip, this should be 0x2 INFO("C: gated all DRAM clocks \n"); for (i=0; i<20; i++) { } /* enable the phy iso */ mmio_setbits_32(0x303a0d40, 1); mmio_setbits_32(0x303a0104, (1 << 5)); } void lpddr4_exit_retention(void) { unsigned int tmp, tmp_t, i; INFO("exit lpddr4 retention\n"); for (i=0; i<50; i++) { } for (i=0; i<50; i++) { } /*assert all reset */ #if defined(PLAT_IMX8M) mmio_write_32(SRC_DDRC_RCR_ADDR+0x4, 0x8F000003); // assert [0]src_system_rst_b! mmio_write_32(SRC_DDRC_RCR_ADDR, 0x8F00000F); // assert [0]ddr1_preset_n, [1]ddr1_core_reset_n, [2]ddr1_phy_reset, [3]ddr1_phy_pwrokin_n, mmio_write_32(SRC_DDRC_RCR_ADDR+0x4, 0x8F000000); // deassert [4]src_system_rst_b! #else mmio_write_32(SRC_DDRC_RCR_ADDR, 0x8F00001F); // assert [0]ddr1_preset_n, [1]ddr1_core_reset_n, [2]ddr1_phy_reset, [3]ddr1_phy_pwrokin_n mmio_write_32(SRC_DDRC_RCR_ADDR, 0x8F00000F); // assert [0]ddr1_preset_n, [1]ddr1_core_reset_n, [2]ddr1_phy_reset, [3]ddr1_phy_pwrokin_n #endif mmio_write_32(CCM_CCGR(5),2); mmio_write_32(CCM_SRC_CTRL(15),2); INFO("C: enable all DRAM clocks \n"); /* change the clock source of dram_apb_clk_root */ mmio_write_32(0x3038a088, (0x7<<24)|(0x7<<16)); mmio_write_32(0x3038a084, (0x4<<24)|(0x3<<16)); /* disable iso */ mmio_write_32(0x303A00EC,0x0000ffff); //PGC_CPU_MAPPING mmio_setbits_32(0x303a00f8, (1 << 5)); mmio_write_32(SRC_DDRC_RCR_ADDR, 0x8F000006); // release [0]ddr1_preset_n, [3]ddr1_phy_pwrokin_n /* ddrc re-init */ dram_umctl2_init(); /* * Skips the DRAM init routine and starts up in selfrefresh mode * Program INIT0.skip_dram_init = 2'b11 */ mmio_write_32(DDRC_INIT0(0), 0xc0000000 | (mmio_read_32(DDRC_INIT0(0)))); mmio_write_32(DDRC_MSTR2(0), 0x0); /* Keeps the controller in self-refresh mode */ mmio_write_32(DDRC_PWRCTL(0), 0x000000aa); mmio_write_32(SRC_DDRC_RCR_ADDR, 0x8F000004); /* release all reset */ mmio_write_32(SRC_DDRC_RCR_ADDR, 0x8F000000); /* release all reset */ mmio_write_32(DDRC_DBG1(0), 0x00000000); /* before write Dynamic reg, sw_done should be 0 */ mmio_write_32(DDRC_SWCTL(0), 0x00000000); mmio_write_32(DDRC_DDR_SS_GPR0, 0x01); /*LPDDR4 mode */ mmio_write_32(DDRC_DFIMISC(0), 0x00000000); /* dram phy re-init */ dram_phy_init(); INFO("ddrphy config to 3000mts\n"); /* DWC_DDRPHYA_APBONLY0_MicroContMuxSel */ dwc_ddrphy_apb_wr(0xd0000,0x0); do { tmp_t = mmio_read_32(IP2APB_DDRPHY_IPS_BASE_ADDR(0)+4*0x00020097); INFO("C: Waiting for CalBusy = 0x%x\n",tmp_t); } while (tmp_t != 0); dwc_ddrphy_apb_wr(0xd0000,0x1); /* before write Dynamic reg, sw_done should be 0 */ mmio_write_32(DDRC_SWCTL(0), 0x00000000); mmio_write_32(DDRC_DFIMISC(0), 0x00000020); /* wait DFISTAT.dfi_init_complete to 1 */ tmp_t = 0; while (tmp_t==0) { tmp = mmio_read_32(DDRC_DFISTAT(0)); tmp_t = tmp & 0x01; INFO("wait DFISTAT.dfi_init_complete to 1\n"); } /* clear DFIMISC.dfi_init_start */ mmio_write_32(DDRC_DFIMISC(0), 0x00000000); /* set DFIMISC.dfi_init_complete_en */ mmio_write_32(DDRC_DFIMISC(0), 0x00000001); /* set SWCTL.sw_done to enable quasi-dynamic register programming outside reset. */ mmio_write_32(DDRC_SWCTL(0), 0x00000001); /* wait SWSTAT.sw_done_ack to 1 */ tmp_t = 0; while(tmp_t!=0x1){ tmp = mmio_read_32(DDRC_SWSTAT(0)); tmp_t = tmp & 0x1; INFO("1wait SWSTAT.sw_done_ack to 1\n"); } mmio_write_32(DDRC_PWRCTL(0), 0x000000aa); mmio_write_32(DDRC_SWCTL(0), 0x00000000); mmio_write_32(DDRC_DFIMISC(0), 0x00000001); mmio_write_32(DDRC_SWCTL(0), 0x00000001); /* wait SWSTAT.sw_done_ack to 1 */ tmp_t = 0; while(tmp_t!=0x1){ tmp = mmio_read_32(DDRC_SWSTAT(0)); tmp_t = tmp & 0x1; INFO("2wait SWSTAT.sw_done_ack to 1\n"); } mmio_write_32(DDRC_PWRCTL(0), 0x00000088); /* wait STAT to normal state */ tmp_t = 0; while(tmp_t!=0x1) { tmp = mmio_read_32(DDRC_STAT(0)); tmp_t = tmp & 0x7; INFO("wait STAT to normal state\n"); } mmio_write_32(DDRC_DERATEEN(0), 0x00000302); mmio_write_32(DDRC_PCTRL_0(0), 0x00000001); /* dis_auto-refresh is set to 0 */ mmio_write_32(DDRC_RFSHCTL3(0), 0x00000000); /* should check PhyInLP3 pub reg */ mmio_write_32(IP2APB_DDRPHY_IPS_BASE_ADDR(0)+4*0xd0000,0x0); tmp = mmio_read_32(IP2APB_DDRPHY_IPS_BASE_ADDR(0)+4*0x00090028); tmp = tmp & 0x1; if(!tmp) INFO("C: PhyInLP3 = 0\n"); else INFO("vt_fail6\n"); mmio_write_32(IP2APB_DDRPHY_IPS_BASE_ADDR(0)+4*0xd0000,0x1); }