feat(imx8ulp): ddrc switch auto low power and software interface

Enable switch between DDRC Auto low power and software/hardware
control modes DDRC Auto low-power mode is used when system is
active, software/hardware control mode is used when going into
suspend. Enable switching between Auto mode and SW/HW mode in
enter/exit retention routines.

Set LPI_SRPD_LONG_MCCLK_GATE_WAKEUP_F2 Max setting to allow
LPDDR_EN_CLKGATE reload LPI_SRPD_LONG_MCCLK_GATE_WAKEUP_F2 to
exit retention mode

Signed-off-by: Pascal Mareau <pascal.mareau@nxp.com>
Signed-off-by: Adrian Alonso <adrian.alonso@nxp.com>
Signed-off-by: Hongting Ting <hongting.dong@nxp.com>
Signed-off-by: Jacky Bai <ping.bai@nxp.com>
Change-Id: I3c4b6f7bc6ca02649ff27cd3d9a0c50dab3a3ad0
This commit is contained in:
Adrian Alonso 2023-04-13 21:55:10 -05:00 committed by Jacky Bai
parent c514d3cfa7
commit ee25e6a51b
3 changed files with 130 additions and 6 deletions

View file

@ -25,13 +25,22 @@
#define IMX_DDRC_BASE U(0x2E060000)
#define SAVED_DRAM_DATA_BASE U(0x20055000)
#define DENALI_CTL_144 0x240
#define IMX_DRAM_BASE U(0x80000000)
#define DENALI_CTL_143 U(0x23C)
#define DENALI_CTL_144 U(0x240)
#define DENALI_CTL_146 U(0x248)
#define LP_STATE_CS_IDLE U(0x404000)
#define LP_STATE_CS_PD_CG U(0x4F4F00)
#define LPI_WAKEUP_EN_SHIFT U(8)
#define IMX_LPAV_SIM_BASE 0x2DA50000
#define LPDDR_CTRL 0x14
#define LPDDR_AUTO_LP_MODE_DISABLE BIT(24)
#define SOC_LP_CMD_SHIFT U(15)
#define LPDDR_CTRL2 0x18
#define LPDDR_EN_CLKGATE (0x1<<17)
#define LPDDR_MAX_CLKDIV_EN (0x1 << 16)
#define LP_AUTO_ENTRY_EN 0x4
#define LP_AUTO_EXIT_EN 0xF
#define DENALI_CTL_00 U(0x0)
#define DENALI_CTL_23 U(0x5c)
@ -106,6 +115,9 @@ struct dram_timing_info {
/* phy freq2 config */
struct dram_cfg_param *phy_f2_cfg;
unsigned int phy_f2_cfg_num;
/* automatic low power config */
struct dram_cfg_param *auto_lp_cfg;
unsigned int auto_lp_cfg_num;
/* initialized drate table */
unsigned int fsp_table[3];
};
@ -114,11 +126,13 @@ struct dram_timing_info {
#define PI_NUM U(298)
#define PHY_NUM U(1654)
#define PHY_DIFF_NUM U(49)
#define AUTO_LP_NUM U(3)
struct dram_cfg {
uint32_t ctl_cfg[CTL_NUM];
uint32_t pi_cfg[PI_NUM];
uint32_t phy_full[PHY_NUM];
uint32_t phy_diff[PHY_DIFF_NUM];
uint32_t auto_lp_cfg[AUTO_LP_NUM];
};
struct dram_timing_info *info;
@ -126,7 +140,8 @@ struct dram_cfg *dram_timing_cfg;
/* mark if dram cfg is already saved */
static bool dram_cfg_saved;
static uint32_t dram_class;
static bool dram_auto_lp_true;
static uint32_t dram_class, dram_ctl_143;
/* PHY register index for frequency diff */
uint32_t freq_specific_reg_array[PHY_DIFF_NUM] = {
@ -198,10 +213,115 @@ static void ddr_init(void)
mmio_write_32(IMX_DDRC_BASE + DENALI_PHY_1537, PHY_FREQ_MULTICAST_EN(1));
}
void dram_lp_auto_disable(void)
{
uint32_t lp_auto_en;
dram_timing_cfg = (struct dram_cfg *)(SAVED_DRAM_DATA_BASE +
sizeof(struct dram_timing_info));
lp_auto_en = (mmio_read_32(IMX_DDRC_BASE + DENALI_CTL_146) & (LP_AUTO_ENTRY_EN << 24));
/* Save initial config */
dram_ctl_143 = mmio_read_32(IMX_DDRC_BASE + DENALI_CTL_143);
if (lp_auto_en && !dram_auto_lp_true) {
/* 0.a Save DDRC auto low-power mode parameter */
dram_timing_cfg->auto_lp_cfg[0] = mmio_read_32(IMX_DDRC_BASE + DENALI_CTL_144);
dram_timing_cfg->auto_lp_cfg[1] = mmio_read_32(IMX_DDRC_BASE + DENALI_CTL_147);
dram_timing_cfg->auto_lp_cfg[2] = mmio_read_32(IMX_DDRC_BASE + DENALI_CTL_146);
/* Set LPI_SRPD_LONG_MCCLK_GATE_WAKEUP_F2 to Maximum */
mmio_setbits_32(IMX_DDRC_BASE + DENALI_CTL_143, 0xF << 24);
/* 0.b Disable DDRC auto low-power mode interface */
mmio_clrbits_32(IMX_DDRC_BASE + DENALI_CTL_146, LP_AUTO_ENTRY_EN << 24);
/* 0.c Read any location to get DRAM out of Self-refresh */
mmio_read_32(IMX_DRAM_BASE);
/* 0.d Confirm DRAM is out of Self-refresh */
while ((mmio_read_32(IMX_DDRC_BASE + DENALI_CTL_146) &
LP_STATE_CS_PD_CG) != LP_STATE_CS_IDLE) {
;
}
/* 0.e Disable DDRC auto low-power exit */
mmio_clrbits_32(IMX_DDRC_BASE + DENALI_CTL_147, LP_AUTO_EXIT_EN);
/* dram low power mode flag */
dram_auto_lp_true = true;
}
}
void dram_lp_auto_enable(void)
{
/* Switch back to Auto Low-power mode */
if (dram_auto_lp_true) {
/* 12.a Confirm DRAM is out of Self-refresh */
while ((mmio_read_32(IMX_DDRC_BASE + DENALI_CTL_146) &
LP_STATE_CS_PD_CG) != LP_STATE_CS_IDLE) {
;
}
/* 12.b Enable DDRC auto low-power exit */
/*
* 12.c TBC! : Set DENALI_CTL_144 [LPI_CTRL_REQ_EN[24]] and
* [DFI_LP_VERSION[16]] back to default settings = 1b'1.
*/
/*
* 12.d Reconfigure DENALI_CTL_144 [LPI_WAKEUP_EN[5:0]] bit
* LPI_WAKEUP_EN[3] = 1b'1.
*/
mmio_write_32(IMX_DDRC_BASE + DENALI_CTL_144, dram_timing_cfg->auto_lp_cfg[0]);
mmio_write_32(IMX_DDRC_BASE + DENALI_CTL_147, dram_timing_cfg->auto_lp_cfg[1]);
/* 12.e Re-enable DDRC auto low-power mode interface */
mmio_write_32(IMX_DDRC_BASE + DENALI_CTL_146, dram_timing_cfg->auto_lp_cfg[2]);
/* restore ctl config */
mmio_write_32(IMX_DDRC_BASE + DENALI_CTL_143, dram_ctl_143);
/* dram low power mode flag */
dram_auto_lp_true = false;
}
}
void dram_enter_self_refresh(void)
{
/* disable auto low power interface */
dram_lp_auto_disable();
/* 1. config the PCC_LPDDR4[SSADO] to 2b'11 for ACK domain 0/1's STOP */
mmio_setbits_32(IMX_PCC5_BASE + 0x108, 0x2 << 22);
/* 1.a Clock gate PCC_LPDDR4[CGC] and no software reset PCC_LPDDR4[SWRST] */
mmio_setbits_32(IMX_PCC5_BASE + 0x108, (BIT(30) | BIT(28)));
/*
* 2. Make sure the DENALI_CTL_144[LPI_WAKEUP_EN[5:0]] has the bit
* LPI_WAKEUP_EN[3] = 1b'1. This enables the option 'self-refresh
* long with mem and ctlr clk gating or self-refresh power-down long
* with mem and ctlr clk gating'
*/
mmio_setbits_32(IMX_DDRC_BASE + DENALI_CTL_144, BIT(3) << LPI_WAKEUP_EN_SHIFT);
/* TODO: Needed ? 2.a DENALI_CTL_144[LPI_TIMER_WAKEUP_F2] */
//mmio_setbits_32(IMX_DDRC_BASE + DENALI_CTL_144, BIT(0));
/*
* 3a. Config SIM_LPAV LPDDR_CTRL[LPDDR_AUTO_LP_MODE_DISABLE] to 1b'0(enable
* the logic to automatic handles low power entry/exit. This is the recommended
* option over handling through software.
* 3b. Config the SIM_LPAV LPDDR_CTRL[SOC_LP_CMD] to 6b'101001(encoding for
* self_refresh with both DDR controller and DRAM clock gate. THis is mandatory
* since LPPDR logic will be power gated).
*/
mmio_clrbits_32(IMX_LPAV_SIM_BASE + LPDDR_CTRL, LPDDR_AUTO_LP_MODE_DISABLE);
mmio_clrsetbits_32(IMX_LPAV_SIM_BASE + LPDDR_CTRL,
0x3f << SOC_LP_CMD_SHIFT, 0x29 << SOC_LP_CMD_SHIFT);
/* 3.c clock gate ddr controller */
mmio_setbits_32(IMX_LPAV_SIM_BASE + LPDDR_CTRL2, LPDDR_EN_CLKGATE);
/* 3.d lpddr max clk div en */
mmio_clrbits_32(IMX_LPAV_SIM_BASE + LPDDR_CTRL2, LPDDR_MAX_CLKDIV_EN);
}
void dram_exit_self_refresh(void)
{
dram_lp_auto_enable();
}
void dram_enter_retention(void)
{
unsigned int i;
dram_lp_auto_disable();
/* 1. config the PCC_LPDDR4[SSADO] to 2b'11 for ACK domain 0/1's STOP */
mmio_setbits_32(IMX_PCC5_BASE + 0x108, 0x2 << 22);
@ -438,6 +558,8 @@ void dram_exit_retention(void)
;
}
}
dram_lp_auto_enable();
}
#define LPDDR_DONE (0x1<<4)
@ -446,8 +568,6 @@ void dram_exit_retention(void)
#define LPI_WAKEUP_EN (0x4<<8)
#define SOC_FREQ_REQ (0x1<<11)
#define LPDDR_EN_CLKGATE (0x1<<17)
static void set_cgc2_ddrclk(uint8_t src, uint8_t div)
{

View file

@ -39,8 +39,8 @@
#define TRUSTY_PARAMS_LEN_BYTES (4096*2)
static const mmap_region_t imx_mmap[] = {
DEVICE0_MAP, DEVICE1_MAP, ELE_MAP,
SEC_SIM_MAP, SRAM0_MAP,
DEVICE0_MAP, DEVICE1_MAP, DEVICE2_MAP,
ELE_MAP, SEC_SIM_MAP, SRAM0_MAP,
{0}
};

View file

@ -52,6 +52,8 @@
#define DEVICE0_SIZE U(0x10000000)
#define DEVICE1_BASE U(0x30000000)
#define DEVICE1_SIZE U(0x10000000)
#define DEVICE2_BASE U(0x80000000)
#define DEVICE2_SIZE U(0x01000000)
#define IMX_LPUART4_BASE U(0x29390000)
#define IMX_LPUART5_BASE U(0x293a0000)
#define IMX_LPUART_BASE IMX_LPUART5_BASE
@ -106,6 +108,8 @@
/* system memory map define */
#define DEVICE0_MAP MAP_REGION_FLAT(DEVICE0_BASE, DEVICE0_SIZE, MT_DEVICE | MT_RW)
#define DEVICE1_MAP MAP_REGION_FLAT(DEVICE1_BASE, DEVICE1_SIZE, MT_DEVICE | MT_RW)
/* Map partial DRAM space for DRAM low-power mode control */
#define DEVICE2_MAP MAP_REGION_FLAT(DEVICE2_BASE, DEVICE2_SIZE, MT_DEVICE | MT_RW)
/* MU and FSB */
#define ELE_MAP MAP_REGION_FLAT(0x27010000, 0x20000, MT_DEVICE | MT_RW | MT_NS)
#define SEC_SIM_MAP MAP_REGION_FLAT(0x2802B000, 0x1000, MT_DEVICE | MT_RW | MT_NS) /* SEC SIM */