1*036935a8SXiaoDong Huang // SPDX-License-Identifier: BSD-3-Clause 2*036935a8SXiaoDong Huang /* 3*036935a8SXiaoDong Huang * Copyright (c) 2025, Rockchip Electronics Co., Ltd. 4*036935a8SXiaoDong Huang */ 5*036935a8SXiaoDong Huang 6*036935a8SXiaoDong Huang #include <assert.h> 7*036935a8SXiaoDong Huang #include <errno.h> 8*036935a8SXiaoDong Huang 9*036935a8SXiaoDong Huang #include <arch_helpers.h> 10*036935a8SXiaoDong Huang #include <bl31/bl31.h> 11*036935a8SXiaoDong Huang #include <common/debug.h> 12*036935a8SXiaoDong Huang #include <drivers/console.h> 13*036935a8SXiaoDong Huang #include <drivers/delay_timer.h> 14*036935a8SXiaoDong Huang #include <lib/mmio.h> 15*036935a8SXiaoDong Huang #include <platform.h> 16*036935a8SXiaoDong Huang #include <platform_def.h> 17*036935a8SXiaoDong Huang 18*036935a8SXiaoDong Huang #include <dmc_rk3576.h> 19*036935a8SXiaoDong Huang #include <rk3576_def.h> 20*036935a8SXiaoDong Huang #include <soc.h> 21*036935a8SXiaoDong Huang 22*036935a8SXiaoDong Huang struct rk3576_dmc_config dmc_config; 23*036935a8SXiaoDong Huang 24*036935a8SXiaoDong Huang /* DDR_PHY */ 25*036935a8SXiaoDong Huang #define LP_CON0 0x0018 26*036935a8SXiaoDong Huang #define DFI_LP_CON0 0x0e04 27*036935a8SXiaoDong Huang /* DDR_CTL */ 28*036935a8SXiaoDong Huang #define DDRCTL_STAT 0x10014 29*036935a8SXiaoDong Huang #define DDRCTL_PWRCTL 0x10180 30*036935a8SXiaoDong Huang #define DDRCTL_CLKGATECTL 0x1018c 31*036935a8SXiaoDong Huang 32*036935a8SXiaoDong Huang /* LP_CON0 */ 33*036935a8SXiaoDong Huang #define DS_IO_PD BIT(14) 34*036935a8SXiaoDong Huang #define SCHD_HW_CLOCK_GATING_DISABLE BIT(13) 35*036935a8SXiaoDong Huang #define PCL_PD BIT(12) 36*036935a8SXiaoDong Huang #define DQS_ENABLE BIT(10) 37*036935a8SXiaoDong Huang #define WCK_ENABLE BIT(9) 38*036935a8SXiaoDong Huang #define CTRL_DQS_DRV_OFF BIT(8) 39*036935a8SXiaoDong Huang #define CTRL_SCHEDULER_EN BIT(6) 40*036935a8SXiaoDong Huang 41*036935a8SXiaoDong Huang /* DFI_LP_CON0 0x0e04 */ 42*036935a8SXiaoDong Huang #define DFI_LP_MODE_APB BIT(31) 43*036935a8SXiaoDong Huang 44*036935a8SXiaoDong Huang /* DDRCTL_STAT 0x10014 */ 45*036935a8SXiaoDong Huang #define CTL_SELFREF_STATE_SHIFT (12) 46*036935a8SXiaoDong Huang #define CTL_SELFREF_STATE_MASK (0x7 << CTL_SELFREF_STATE_SHIFT) 47*036935a8SXiaoDong Huang #define CTL_NOT_IN_SELF_REFRESH (0x0 << CTL_SELFREF_STATE_SHIFT) 48*036935a8SXiaoDong Huang #define CTL_SELF_REFRESH_1 (0x1 << CTL_SELFREF_STATE_SHIFT) 49*036935a8SXiaoDong Huang #define CTL_SELF_REFRESH_POWER_DOWN (0x2 << CTL_SELFREF_STATE_SHIFT) 50*036935a8SXiaoDong Huang #define CTL_SELF_REFRESH_2 (0x3 << CTL_SELFREF_STATE_SHIFT) 51*036935a8SXiaoDong Huang #define CTL_SELF_REFRESH_DEEP_SLEEP (0x4 << CTL_SELFREF_STATE_SHIFT) 52*036935a8SXiaoDong Huang #define CTL_SELFREF_TYPE_SHIFT (4) 53*036935a8SXiaoDong Huang #define CTL_SELFREF_TYPE_MASK (0x3 << CTL_SELFREF_TYPE_SHIFT) 54*036935a8SXiaoDong Huang #define CTL_SELFREF_NOT_BY_PHY (0x1 << CTL_SELFREF_TYPE_SHIFT) 55*036935a8SXiaoDong Huang #define CTL_SELFREF_NOT_BY_AUTO (0x2 << CTL_SELFREF_TYPE_SHIFT) 56*036935a8SXiaoDong Huang #define CTL_SELFREF_BY_AUTO (0x3 << CTL_SELFREF_TYPE_SHIFT) 57*036935a8SXiaoDong Huang #define CTL_OPERATING_MODE_MASK (0x7) 58*036935a8SXiaoDong Huang #define CTL_OPERATING_MODE_INIT (0x0) 59*036935a8SXiaoDong Huang #define CTL_OPERATING_MODE_NORMAL (0x1) 60*036935a8SXiaoDong Huang #define CTL_OPERATING_MODE_PD (0x2) 61*036935a8SXiaoDong Huang #define CTL_OPERATING_MODE_SR_SRPD (0x3) 62*036935a8SXiaoDong Huang 63*036935a8SXiaoDong Huang /* DDRCTL_PWRCTL 0x10180 */ 64*036935a8SXiaoDong Huang #define CTL_DSM_EN BIT(18) 65*036935a8SXiaoDong Huang #define CTL_STAY_IN_SELFREF BIT(15) 66*036935a8SXiaoDong Huang #define CTL_SELFREF_SW BIT(11) 67*036935a8SXiaoDong Huang #define CTL_EN_DFI_DRAM_CLK_DISABLE BIT(9) 68*036935a8SXiaoDong Huang #define CTL_POWERDOWN_EN_MASK (0xf) 69*036935a8SXiaoDong Huang #define CTL_POWERDOWN_EN_SHIFT (4) 70*036935a8SXiaoDong Huang #define CTL_SELFREF_EN_MASK (0xf) 71*036935a8SXiaoDong Huang #define CTL_SELFREF_EN_SHIFT (0) 72*036935a8SXiaoDong Huang 73*036935a8SXiaoDong Huang #define SYS_REG_DEC_CHINFO(n, ch) (((n) >> (28 + (ch))) & 0x1) 74*036935a8SXiaoDong Huang #define SYS_REG_DEC_CHINFO_V3(reg2, ch) SYS_REG_DEC_CHINFO(reg2, ch) 75*036935a8SXiaoDong Huang 76*036935a8SXiaoDong Huang #define SYS_REG_DEC_NUM_CH(n) (1 + (((n) >> 12) & 0x1)) 77*036935a8SXiaoDong Huang #define SYS_REG_DEC_NUM_CH_V3(reg2) SYS_REG_DEC_NUM_CH(reg2) 78*036935a8SXiaoDong Huang 79*036935a8SXiaoDong Huang static void exit_low_power(uint32_t ch, struct rk3576_dmc_config *configs) 80*036935a8SXiaoDong Huang { 81*036935a8SXiaoDong Huang /* LP_CON0: [12]pcl_pd */ 82*036935a8SXiaoDong Huang configs->low_power[ch].pcl_pd = mmio_read_32(DDRPHY_BASE_CH(0) + LP_CON0) & PCL_PD; 83*036935a8SXiaoDong Huang mmio_clrbits_32(DDRPHY_BASE_CH(ch) + LP_CON0, PCL_PD); 84*036935a8SXiaoDong Huang 85*036935a8SXiaoDong Huang /* Disable low power activities */ 86*036935a8SXiaoDong Huang configs->low_power[ch].pwrctl = mmio_read_32(UMCTL_BASE_CH(ch) + DDRCTL_PWRCTL); 87*036935a8SXiaoDong Huang mmio_clrbits_32(UMCTL_BASE_CH(ch) + DDRCTL_PWRCTL, 88*036935a8SXiaoDong Huang CTL_DSM_EN | (CTL_POWERDOWN_EN_MASK << CTL_POWERDOWN_EN_SHIFT) | 89*036935a8SXiaoDong Huang (CTL_SELFREF_EN_MASK << CTL_SELFREF_EN_SHIFT)); 90*036935a8SXiaoDong Huang while ((mmio_read_32(UMCTL_BASE_CH(ch) + DDRCTL_STAT) & CTL_OPERATING_MODE_MASK) != 91*036935a8SXiaoDong Huang CTL_OPERATING_MODE_NORMAL) 92*036935a8SXiaoDong Huang continue; 93*036935a8SXiaoDong Huang 94*036935a8SXiaoDong Huang /* DDR_GRF_CHA_CON6: [6:0]rd_lat_delay, [14:8]wr_lat_delay, [15]cmd_dly_eq0_en */ 95*036935a8SXiaoDong Huang configs->low_power[ch].grf_ddr_con6 = 96*036935a8SXiaoDong Huang mmio_read_32(DDR_GRF_BASE + GRF_CH_CON(ch, 6)) & 0xff7f; 97*036935a8SXiaoDong Huang mmio_write_32(DDR_GRF_BASE + GRF_CH_CON(ch, 6), (0x1ul << (15 + 16))); 98*036935a8SXiaoDong Huang 99*036935a8SXiaoDong Huang /* DDR_GRF_CHA_CON0: [12:8]ddrctl_axi_cg_en */ 100*036935a8SXiaoDong Huang configs->low_power[ch].grf_ddr_con0 = 101*036935a8SXiaoDong Huang mmio_read_32(DDR_GRF_BASE + GRF_CH_CON(ch, 0)) & 0x1f00; 102*036935a8SXiaoDong Huang mmio_write_32(DDR_GRF_BASE + GRF_CH_CON(ch, 0), 0x1f000000); 103*036935a8SXiaoDong Huang 104*036935a8SXiaoDong Huang /* 105*036935a8SXiaoDong Huang * DDR_GRF_CHA_CON1: 106*036935a8SXiaoDong Huang * [15]ddrctl_apb_pclk_cg_en, [12]ddrmon_pclk_cg_en, [7]dfi_scramble_cg_en, 107*036935a8SXiaoDong Huang * [6]ddrctl_mem_cg_en, [5]bsm_clk_cg_en, [2]ddrctl_core_cg_en, [1]ddrctl_apb_cg_en 108*036935a8SXiaoDong Huang */ 109*036935a8SXiaoDong Huang configs->low_power[ch].grf_ddr_con1 = 110*036935a8SXiaoDong Huang mmio_read_32(DDR_GRF_BASE + GRF_CH_CON(ch, 1)) & 0x90e6; 111*036935a8SXiaoDong Huang mmio_write_32(DDR_GRF_BASE + GRF_CH_CON(ch, 1), 0x90e60000); 112*036935a8SXiaoDong Huang 113*036935a8SXiaoDong Huang configs->low_power[ch].hwlp_0 = mmio_read_32(HWLP_BASE_CH(ch) + 0x0); 114*036935a8SXiaoDong Huang mmio_write_32(HWLP_BASE_CH(ch) + 0x0, 0x0); 115*036935a8SXiaoDong Huang configs->low_power[ch].hwlp_c = mmio_read_32(HWLP_BASE_CH(ch) + 0xc); 116*036935a8SXiaoDong Huang mmio_write_32(HWLP_BASE_CH(ch) + 0xc, 0x0); 117*036935a8SXiaoDong Huang 118*036935a8SXiaoDong Huang /* DDR_GRF_CHA_PHY_CON0: [14]ddrphy_pclk_cg_en */ 119*036935a8SXiaoDong Huang configs->low_power[ch].grf_ddrphy_con0 = 120*036935a8SXiaoDong Huang mmio_read_32(DDR_GRF_BASE + GRF_DDRPHY_CON0(ch)) & BIT(14); 121*036935a8SXiaoDong Huang mmio_write_32(DDR_GRF_BASE + GRF_DDRPHY_CON0(ch), BIT(14 + 16)); 122*036935a8SXiaoDong Huang 123*036935a8SXiaoDong Huang /* CLKGATECTL: [5:0]bsm_clk_on */ 124*036935a8SXiaoDong Huang configs->low_power[ch].clkgatectl = 125*036935a8SXiaoDong Huang mmio_read_32(UMCTL_BASE_CH(ch) + DDRCTL_CLKGATECTL) & 0x3f; 126*036935a8SXiaoDong Huang /* DFI_LP_CON0: [31]dfi_lp_mode_apb */ 127*036935a8SXiaoDong Huang configs->low_power[ch].dfi_lp_mode_apb = 128*036935a8SXiaoDong Huang (mmio_read_32(DDRPHY_BASE_CH(ch) + DFI_LP_CON0) >> 31) & 0x1; 129*036935a8SXiaoDong Huang } 130*036935a8SXiaoDong Huang 131*036935a8SXiaoDong Huang static void resume_low_power(uint32_t ch, struct rk3576_dmc_config *configs) 132*036935a8SXiaoDong Huang { 133*036935a8SXiaoDong Huang /* DFI_LP_CON0: [31]dfi_lp_mode_apb */ 134*036935a8SXiaoDong Huang if (configs->low_power[ch].dfi_lp_mode_apb != 0) 135*036935a8SXiaoDong Huang mmio_setbits_32(DDRPHY_BASE_CH(ch) + DFI_LP_CON0, DFI_LP_MODE_APB); 136*036935a8SXiaoDong Huang 137*036935a8SXiaoDong Huang /* CLKGATECTL: [5:0]bsm_clk_on */ 138*036935a8SXiaoDong Huang mmio_clrsetbits_32(UMCTL_BASE_CH(ch) + DDRCTL_CLKGATECTL, 139*036935a8SXiaoDong Huang 0x3f, configs->low_power[ch].clkgatectl & 0x3f); 140*036935a8SXiaoDong Huang 141*036935a8SXiaoDong Huang /* DDR_GRF_CHA_CON6: [6:0]rd_lat_delay, [14:8]wr_lat_delay, [15]cmd_dly_eq0_en */ 142*036935a8SXiaoDong Huang mmio_write_32(DDR_GRF_BASE + GRF_CH_CON(ch, 6), 143*036935a8SXiaoDong Huang (0xff7ful << 16) | configs->low_power[ch].grf_ddr_con6); 144*036935a8SXiaoDong Huang 145*036935a8SXiaoDong Huang mmio_write_32(HWLP_BASE_CH(ch) + 0xc, configs->low_power[ch].hwlp_c); 146*036935a8SXiaoDong Huang mmio_write_32(HWLP_BASE_CH(ch) + 0x0, configs->low_power[ch].hwlp_0); 147*036935a8SXiaoDong Huang 148*036935a8SXiaoDong Huang /* DDR_GRF_CHA_CON0: [12:8]ddrctl_axi_cg_en */ 149*036935a8SXiaoDong Huang mmio_write_32(DDR_GRF_BASE + GRF_CH_CON(ch, 0), 150*036935a8SXiaoDong Huang (0x1f00ul << 16) | configs->low_power[ch].grf_ddr_con0); 151*036935a8SXiaoDong Huang 152*036935a8SXiaoDong Huang /* 153*036935a8SXiaoDong Huang * DDR_GRF_CHA_CON1: 154*036935a8SXiaoDong Huang * [15]ddrctl_apb_pclk_cg_en, [12]ddrmon_pclk_cg_en, [7]dfi_scramble_cg_en, 155*036935a8SXiaoDong Huang * [6]ddrctl_mem_cg_en, [5]bsm_clk_cg_en, [2]ddrctl_core_cg_en, [1]ddrctl_apb_cg_en 156*036935a8SXiaoDong Huang */ 157*036935a8SXiaoDong Huang mmio_write_32(DDR_GRF_BASE + GRF_CH_CON(ch, 1), 158*036935a8SXiaoDong Huang (0x90e6ul << 16) | configs->low_power[ch].grf_ddr_con1); 159*036935a8SXiaoDong Huang 160*036935a8SXiaoDong Huang /* DDR_GRF_CHA_PHY_CON0: [14]ddrphy_pclk_cg_en */ 161*036935a8SXiaoDong Huang mmio_write_32(DDR_GRF_BASE + GRF_DDRPHY_CON0(ch), 162*036935a8SXiaoDong Huang BIT(14 + 16) | configs->low_power[ch].grf_ddrphy_con0); 163*036935a8SXiaoDong Huang 164*036935a8SXiaoDong Huang /* reset low power activities */ 165*036935a8SXiaoDong Huang mmio_write_32(UMCTL_BASE_CH(ch) + DDRCTL_PWRCTL, configs->low_power[ch].pwrctl); 166*036935a8SXiaoDong Huang 167*036935a8SXiaoDong Huang /* LP_CON0: [12]pcl_pd */ 168*036935a8SXiaoDong Huang if (configs->low_power[ch].pcl_pd != 0) 169*036935a8SXiaoDong Huang mmio_setbits_32(DDRPHY_BASE_CH(ch) + LP_CON0, PCL_PD); 170*036935a8SXiaoDong Huang } 171*036935a8SXiaoDong Huang 172*036935a8SXiaoDong Huang void dmc_save(void) 173*036935a8SXiaoDong Huang { 174*036935a8SXiaoDong Huang uint32_t i, channel_num; 175*036935a8SXiaoDong Huang 176*036935a8SXiaoDong Huang channel_num = 177*036935a8SXiaoDong Huang SYS_REG_DEC_NUM_CH_V3(mmio_read_32(PMU1_GRF_BASE + PMUGRF_OS_REG(2))); 178*036935a8SXiaoDong Huang 179*036935a8SXiaoDong Huang for (i = 0; i < channel_num; i++) 180*036935a8SXiaoDong Huang exit_low_power(i, &dmc_config); 181*036935a8SXiaoDong Huang } 182*036935a8SXiaoDong Huang 183*036935a8SXiaoDong Huang void dmc_restore(void) 184*036935a8SXiaoDong Huang { 185*036935a8SXiaoDong Huang uint32_t i, channel_num; 186*036935a8SXiaoDong Huang 187*036935a8SXiaoDong Huang channel_num = SYS_REG_DEC_NUM_CH_V3(mmio_read_32(PMU1_GRF_BASE + PMUGRF_OS_REG(2))); 188*036935a8SXiaoDong Huang 189*036935a8SXiaoDong Huang for (i = 0; i < channel_num; i++) 190*036935a8SXiaoDong Huang resume_low_power(i, &dmc_config); 191*036935a8SXiaoDong Huang } 192