/* * 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 ddr4_enter_retention(void) { volatile unsigned int tmp; /* 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 */ mmio_write_32(DDRC_PWRCTL(0), 0x000000aa); tmp=0; /* self-refresh state */ while (tmp!=0x23) { tmp = 0x3f & (mmio_read_32((DDRC_STAT(0)))); } 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 */ while (1 == (0x1 & mmio_read_32(DDRC_DFISTAT(0)))) ; mmio_write_32(DDRC_DFIMISC(0), 0x00001f00); /* wait DFISTAT.dfi_init_complete to 1 */ while (0 == (0x1 & mmio_read_32(DDRC_DFISTAT(0)))) ; /* 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) printf("C: PhyInLP3 = 1\n"); else printf("vt_fail\n"); dwc_ddrphy_apb_wr(0xd0000,0x1); /* pwrdnreqn_async adbm/adbs of ddr */ mmio_clrbits_32(GPC_PU_PWRHSK, (1 << 2)); do { tmp = mmio_read_32(GPC_PU_PWRHSK); } while (tmp & (0x1 << 20)); /* wait untill pwrdnackn_async=0 */ mmio_setbits_32(GPC_PU_PWRHSK, (1 << 2)); /* remove PowerOk: assert [3]ddr1_phy_pwrokin_n */ mmio_write_32(SRC_DDRC_RCR_ADDR, 0x8F000008); mmio_write_32(CCM_CCGR(5), 0); mmio_write_32(CCM_SRC_CTRL(15), 2); mmio_setbits_32(0x303A0D40, 1); mmio_setbits_32(0x303A0104, (1 << 5)); } void ddr4_exit_retention(void) { volatile unsigned int tmp, tmp_t, i; for (i = 0; i < 20; i++){ } /* assert all reset */ mmio_write_32(SRC_DDRC_RCR_ADDR, 0x8F00003F); mmio_write_32(CCM_CCGR(5), 2); mmio_write_32(CCM_SRC_CTRL(15), 2); printf("C: enable all DRAM clocks \n"); mmio_write_32(0x303A00EC, 0x0000ffff); /* PGC_CPU_MAPPING */ mmio_setbits_32(0x303A00F8, (1 << 5)); mmio_write_32(SRC_DDRC_RCR_ADDR, 0x8F00000F); /* release [4]src_system_rst_b! */ mmio_write_32(SRC_DDRC_RCR_ADDR, 0x8F000006); /* release [0]ddr1_preset_n, [3]ddr1_phy_pwrokin_n */ /* RESET: ASSERTED (ACTIVE LOW) */ /* RESET: ASSERTED (ACTIVE LOW) */ /* RESET: for Port 0 ASSERTED (ACTIVE LOW) */ /* RESET: DEASSERTED */ mmio_write_32(DDRC_DBG1(0), 0x00000001); mmio_write_32(DDRC_PWRCTL(0), 0x00000001); while (0 != (0x7 & mmio_read_32(DDRC_STAT(0)))) ; /* ddrc 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), 0x000001a8); mmio_clrbits_32(DDRC_DFIMISC(0), 1); mmio_write_32(SRC_DDRC_RCR_ADDR, 0x8F000004); mmio_write_32(SRC_DDRC_RCR_ADDR, 0x8F000000); /* release all reset */ /* restore the ddr phy config */ dram_phy_init(); do { tmp_t = mmio_read_32(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4*0x00020097); } while (tmp_t != 0); /* 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 */ while(0 == (0x1 & mmio_read_32(DDRC_DFISTAT(0)))) ; /* clear DFIMISC.dfi_init_complete_en */ mmio_write_32(DDRC_DFIMISC(0), 0x00000000); /* set DFIMISC.dfi_init_complete_en again */ mmio_setbits_32(DDRC_DFIMISC(0), 1); mmio_clrbits_32(DDRC_PWRCTL(0), (1 << 5)); /* 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 */ while(0 == (0x1 & mmio_read_32(DDRC_SWSTAT(0)))); /* wait STAT to normal state */ while(0x1 != (0x7 & mmio_read_32(DDRC_STAT(0)))); 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) printf("C: PhyInLP3 = 0\n"); else printf("vt_fail\n"); mmio_write_32(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4*0xd0000, 0x1); }