mirror of
https://github.com/ARM-software/arm-trusted-firmware.git
synced 2025-05-08 18:41:22 +00:00
feat(st-ddr): add STM32MP2 driver
Add driver to support DDR on STM32MP2 platform. It drives the DDR PHY and its firmware, as well as the DDR controller. Signed-off-by: Nicolas Le Bayon <nicolas.le.bayon@st.com> Signed-off-by: Maxime Méré <maxime.mere@foss.st.com> Change-Id: I93de2db1b9378d5654e76b3bf6f3407d80bc4ca5
This commit is contained in:
parent
d596023bff
commit
79629b1a79
41 changed files with 18361 additions and 31 deletions
|
@ -4,12 +4,524 @@
|
|||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#include <arch_helpers.h>
|
||||
#include <common/debug.h>
|
||||
|
||||
#include <drivers/delay_timer.h>
|
||||
#include <drivers/st/stm32mp2_ddr.h>
|
||||
#include <drivers/st/stm32mp2_ddr_helpers.h>
|
||||
#include <drivers/st/stm32mp2_ddr_regs.h>
|
||||
#include <drivers/st/stm32mp_ddr.h>
|
||||
|
||||
#include <lib/mmio.h>
|
||||
|
||||
#include <platform_def.h>
|
||||
|
||||
/* HW idle period (unit: Multiples of 32 DFI clock cycles) */
|
||||
#define HW_IDLE_PERIOD 0x3U
|
||||
|
||||
static enum stm32mp2_ddr_sr_mode saved_ddr_sr_mode;
|
||||
|
||||
#pragma weak stm32_ddrdbg_get_base
|
||||
uintptr_t stm32_ddrdbg_get_base(void)
|
||||
{
|
||||
return 0U;
|
||||
}
|
||||
|
||||
static void set_qd1_qd3_update_conditions(struct stm32mp_ddrctl *ctl)
|
||||
{
|
||||
mmio_setbits_32((uintptr_t)&ctl->dbg1, DDRCTRL_DBG1_DIS_DQ);
|
||||
|
||||
stm32mp_ddr_set_qd3_update_conditions(ctl);
|
||||
}
|
||||
|
||||
static void unset_qd1_qd3_update_conditions(struct stm32mp_ddrctl *ctl)
|
||||
{
|
||||
stm32mp_ddr_unset_qd3_update_conditions(ctl);
|
||||
|
||||
mmio_clrbits_32((uintptr_t)&ctl->dbg1, DDRCTRL_DBG1_DIS_DQ);
|
||||
}
|
||||
|
||||
static void wait_dfi_init_complete(struct stm32mp_ddrctl *ctl)
|
||||
{
|
||||
uint64_t timeout;
|
||||
uint32_t dfistat;
|
||||
|
||||
timeout = timeout_init_us(DDR_TIMEOUT_US_1S);
|
||||
do {
|
||||
dfistat = mmio_read_32((uintptr_t)&ctl->dfistat);
|
||||
VERBOSE("[0x%lx] dfistat = 0x%x ", (uintptr_t)&ctl->dfistat, dfistat);
|
||||
|
||||
if (timeout_elapsed(timeout)) {
|
||||
panic();
|
||||
}
|
||||
} while ((dfistat & DDRCTRL_DFISTAT_DFI_INIT_COMPLETE) == 0U);
|
||||
|
||||
VERBOSE("[0x%lx] dfistat = 0x%x\n", (uintptr_t)&ctl->dfistat, dfistat);
|
||||
}
|
||||
|
||||
static void disable_dfi_low_power_interface(struct stm32mp_ddrctl *ctl)
|
||||
{
|
||||
uint64_t timeout;
|
||||
uint32_t dfistat;
|
||||
uint32_t stat;
|
||||
|
||||
mmio_clrbits_32((uintptr_t)&ctl->dfilpcfg0, DDRCTRL_DFILPCFG0_DFI_LP_EN_SR);
|
||||
|
||||
timeout = timeout_init_us(DDR_TIMEOUT_US_1S);
|
||||
do {
|
||||
dfistat = mmio_read_32((uintptr_t)&ctl->dfistat);
|
||||
stat = mmio_read_32((uintptr_t)&ctl->stat);
|
||||
VERBOSE("[0x%lx] dfistat = 0x%x ", (uintptr_t)&ctl->dfistat, dfistat);
|
||||
VERBOSE("[0x%lx] stat = 0x%x ", (uintptr_t)&ctl->stat, stat);
|
||||
|
||||
if (timeout_elapsed(timeout)) {
|
||||
panic();
|
||||
}
|
||||
} while (((dfistat & DDRCTRL_DFISTAT_DFI_LP_ACK) != 0U) ||
|
||||
((stat & DDRCTRL_STAT_OPERATING_MODE_MASK) == DDRCTRL_STAT_OPERATING_MODE_SR));
|
||||
|
||||
VERBOSE("[0x%lx] dfistat = 0x%x\n", (uintptr_t)&ctl->dfistat, dfistat);
|
||||
VERBOSE("[0x%lx] stat = 0x%x\n", (uintptr_t)&ctl->stat, stat);
|
||||
}
|
||||
|
||||
void ddr_activate_controller(struct stm32mp_ddrctl *ctl, bool sr_entry)
|
||||
{
|
||||
/*
|
||||
* Manage quasi-dynamic registers modification
|
||||
* dfimisc.dfi_frequency : Group 1
|
||||
* dfimisc.dfi_init_complete_en and dfimisc.dfi_init_start : Group 3
|
||||
*/
|
||||
set_qd1_qd3_update_conditions(ctl);
|
||||
|
||||
if (sr_entry) {
|
||||
mmio_setbits_32((uintptr_t)&ctl->dfimisc, DDRCTRL_DFIMISC_DFI_FREQUENCY);
|
||||
} else {
|
||||
mmio_clrbits_32((uintptr_t)&ctl->dfimisc, DDRCTRL_DFIMISC_DFI_FREQUENCY);
|
||||
}
|
||||
|
||||
mmio_setbits_32((uintptr_t)&ctl->dfimisc, DDRCTRL_DFIMISC_DFI_INIT_START);
|
||||
mmio_clrbits_32((uintptr_t)&ctl->dfimisc, DDRCTRL_DFIMISC_DFI_INIT_START);
|
||||
|
||||
wait_dfi_init_complete(ctl);
|
||||
|
||||
udelay(DDR_DELAY_1US);
|
||||
|
||||
if (sr_entry) {
|
||||
mmio_clrbits_32((uintptr_t)&ctl->dfimisc, DDRCTRL_DFIMISC_DFI_INIT_COMPLETE_EN);
|
||||
} else {
|
||||
mmio_setbits_32((uintptr_t)&ctl->dfimisc, DDRCTRL_DFIMISC_DFI_INIT_COMPLETE_EN);
|
||||
}
|
||||
|
||||
udelay(DDR_DELAY_1US);
|
||||
|
||||
unset_qd1_qd3_update_conditions(ctl);
|
||||
}
|
||||
|
||||
#if STM32MP_LPDDR4_TYPE
|
||||
static void disable_phy_ddc(void)
|
||||
{
|
||||
/* Enable APB access to internal CSR registers */
|
||||
mmio_write_32(stm32mp_ddrphyc_base() + DDRPHY_APBONLY0_MICROCONTMUXSEL, 0U);
|
||||
mmio_write_32(stm32mp_ddrphyc_base() + DDRPHY_DRTUB0_UCCLKHCLKENABLES,
|
||||
DDRPHY_DRTUB0_UCCLKHCLKENABLES_UCCLKEN |
|
||||
DDRPHY_DRTUB0_UCCLKHCLKENABLES_HCLKEN);
|
||||
|
||||
/* Disable DRAM drift compensation */
|
||||
mmio_write_32(stm32mp_ddrphyc_base() + DDRPHY_INITENG0_P0_SEQ0BDISABLEFLAG6, 0xFFFFU);
|
||||
|
||||
/* Disable APB access to internal CSR registers */
|
||||
mmio_write_32(stm32mp_ddrphyc_base() + DDRPHY_DRTUB0_UCCLKHCLKENABLES,
|
||||
DDRPHY_DRTUB0_UCCLKHCLKENABLES_HCLKEN);
|
||||
mmio_write_32(stm32mp_ddrphyc_base() + DDRPHY_APBONLY0_MICROCONTMUXSEL,
|
||||
DDRPHY_APBONLY0_MICROCONTMUXSEL_MICROCONTMUXSEL);
|
||||
}
|
||||
#endif /* STM32MP_LPDDR4_TYPE */
|
||||
|
||||
void ddr_wait_lp3_mode(bool sr_entry)
|
||||
{
|
||||
uint64_t timeout;
|
||||
bool repeat_loop = false;
|
||||
|
||||
/* Enable APB access to internal CSR registers */
|
||||
mmio_write_32(stm32mp_ddrphyc_base() + DDRPHY_APBONLY0_MICROCONTMUXSEL, 0U);
|
||||
mmio_write_32(stm32mp_ddrphyc_base() + DDRPHY_DRTUB0_UCCLKHCLKENABLES,
|
||||
DDRPHY_DRTUB0_UCCLKHCLKENABLES_UCCLKEN |
|
||||
DDRPHY_DRTUB0_UCCLKHCLKENABLES_HCLKEN);
|
||||
|
||||
timeout = timeout_init_us(DDR_TIMEOUT_US_1S);
|
||||
do {
|
||||
uint16_t phyinlpx = mmio_read_32(stm32mp_ddrphyc_base() +
|
||||
DDRPHY_INITENG0_P0_PHYINLPX);
|
||||
|
||||
if (timeout_elapsed(timeout)) {
|
||||
panic();
|
||||
}
|
||||
|
||||
if (sr_entry) {
|
||||
repeat_loop = (phyinlpx & DDRPHY_INITENG0_P0_PHYINLPX_PHYINLP3) == 0U;
|
||||
} else {
|
||||
repeat_loop = (phyinlpx & DDRPHY_INITENG0_P0_PHYINLPX_PHYINLP3) != 0U;
|
||||
}
|
||||
} while (repeat_loop);
|
||||
|
||||
/* Disable APB access to internal CSR registers */
|
||||
#if STM32MP_DDR3_TYPE || STM32MP_DDR4_TYPE
|
||||
mmio_write_32(stm32mp_ddrphyc_base() + DDRPHY_DRTUB0_UCCLKHCLKENABLES, 0U);
|
||||
#else /* STM32MP_LPDDR4_TYPE */
|
||||
mmio_write_32(stm32mp_ddrphyc_base() + DDRPHY_DRTUB0_UCCLKHCLKENABLES,
|
||||
DDRPHY_DRTUB0_UCCLKHCLKENABLES_HCLKEN);
|
||||
#endif /* STM32MP_DDR3_TYPE || STM32MP_DDR4_TYPE */
|
||||
mmio_write_32(stm32mp_ddrphyc_base() + DDRPHY_APBONLY0_MICROCONTMUXSEL,
|
||||
DDRPHY_APBONLY0_MICROCONTMUXSEL_MICROCONTMUXSEL);
|
||||
}
|
||||
|
||||
static int sr_loop(bool is_entry)
|
||||
{
|
||||
uint32_t type;
|
||||
uint32_t state __maybe_unused;
|
||||
uint64_t timeout = timeout_init_us(DDR_TIMEOUT_US_1S);
|
||||
bool repeat_loop = false;
|
||||
|
||||
/*
|
||||
* Wait for DDRCTRL to be out of or back to "normal/mission mode".
|
||||
* Consider also SRPD mode for LPDDR4 only.
|
||||
*/
|
||||
do {
|
||||
type = mmio_read_32(stm32mp_ddrctrl_base() + DDRCTRL_STAT) &
|
||||
DDRCTRL_STAT_SELFREF_TYPE_MASK;
|
||||
#if STM32MP_LPDDR4_TYPE
|
||||
state = mmio_read_32(stm32mp_ddrctrl_base() + DDRCTRL_STAT) &
|
||||
DDRCTRL_STAT_SELFREF_STATE_MASK;
|
||||
#endif /* STM32MP_LPDDR4_TYPE */
|
||||
|
||||
if (timeout_elapsed(timeout)) {
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
if (is_entry) {
|
||||
#if STM32MP_LPDDR4_TYPE
|
||||
repeat_loop = (type == 0x0U) || (state != DDRCTRL_STAT_SELFREF_STATE_SRPD);
|
||||
#else /* !STM32MP_LPDDR4_TYPE */
|
||||
repeat_loop = (type == 0x0U);
|
||||
#endif /* STM32MP_LPDDR4_TYPE */
|
||||
} else {
|
||||
#if STM32MP_LPDDR4_TYPE
|
||||
repeat_loop = (type != 0x0U) || (state != 0x0U);
|
||||
#else /* !STM32MP_LPDDR4_TYPE */
|
||||
repeat_loop = (type != 0x0U);
|
||||
#endif /* STM32MP_LPDDR4_TYPE */
|
||||
}
|
||||
} while (repeat_loop);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sr_entry_loop(void)
|
||||
{
|
||||
return sr_loop(true);
|
||||
}
|
||||
|
||||
int ddr_sr_exit_loop(void)
|
||||
{
|
||||
return sr_loop(false);
|
||||
}
|
||||
|
||||
static int sr_ssr_set(void)
|
||||
{
|
||||
uintptr_t ddrctrl_base = stm32mp_ddrctrl_base();
|
||||
|
||||
/*
|
||||
* Disable Clock disable with LP modes
|
||||
* (used in RUN mode for LPDDR2 with specific timing).
|
||||
*/
|
||||
mmio_clrbits_32(ddrctrl_base + DDRCTRL_PWRCTL, DDRCTRL_PWRCTL_EN_DFI_DRAM_CLK_DISABLE);
|
||||
|
||||
/* Disable automatic Self-Refresh mode */
|
||||
mmio_clrbits_32(ddrctrl_base + DDRCTRL_PWRCTL, DDRCTRL_PWRCTL_SELFREF_EN);
|
||||
|
||||
mmio_write_32(stm32_ddrdbg_get_base() + DDRDBG_LP_DISABLE,
|
||||
DDRDBG_LP_DISABLE_LPI_XPI_DISABLE | DDRDBG_LP_DISABLE_LPI_DDRC_DISABLE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sr_ssr_entry(bool standby)
|
||||
{
|
||||
uintptr_t ddrctrl_base = stm32mp_ddrctrl_base();
|
||||
uintptr_t rcc_base = stm32mp_rcc_base();
|
||||
|
||||
if (stm32mp_ddr_disable_axi_port((struct stm32mp_ddrctl *)ddrctrl_base) != 0) {
|
||||
panic();
|
||||
}
|
||||
|
||||
#if STM32MP_LPDDR4_TYPE
|
||||
if (standby) {
|
||||
/* Disable DRAM drift compensation */
|
||||
disable_phy_ddc();
|
||||
}
|
||||
#endif /* STM32MP_LPDDR4_TYPE */
|
||||
|
||||
disable_dfi_low_power_interface((struct stm32mp_ddrctl *)ddrctrl_base);
|
||||
|
||||
/* SW self refresh entry prequested */
|
||||
mmio_setbits_32(ddrctrl_base + DDRCTRL_PWRCTL, DDRCTRL_PWRCTL_SELFREF_SW);
|
||||
#if STM32MP_LPDDR4_TYPE
|
||||
mmio_clrbits_32(ddrctrl_base + DDRCTRL_PWRCTL, DDRCTRL_PWRCTL_STAY_IN_SELFREF);
|
||||
#endif /* STM32MP_LPDDR4_TYPE */
|
||||
|
||||
if (sr_entry_loop() != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
ddr_activate_controller((struct stm32mp_ddrctl *)ddrctrl_base, true);
|
||||
|
||||
/* Poll on ddrphy_initeng0_phyinlpx.phyinlp3 = 1 */
|
||||
ddr_wait_lp3_mode(true);
|
||||
|
||||
if (standby) {
|
||||
mmio_clrbits_32(stm32mp_pwr_base() + PWR_CR11, PWR_CR11_DDRRETDIS);
|
||||
}
|
||||
|
||||
mmio_clrsetbits_32(rcc_base + RCC_DDRCPCFGR, RCC_DDRCPCFGR_DDRCPLPEN,
|
||||
RCC_DDRCPCFGR_DDRCPEN);
|
||||
mmio_setbits_32(rcc_base + RCC_DDRPHYCCFGR, RCC_DDRPHYCCFGR_DDRPHYCEN);
|
||||
mmio_setbits_32(rcc_base + RCC_DDRITFCFGR, RCC_DDRITFCFGR_DDRPHYDLP);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sr_ssr_exit(void)
|
||||
{
|
||||
uintptr_t ddrctrl_base = stm32mp_ddrctrl_base();
|
||||
uintptr_t rcc_base = stm32mp_rcc_base();
|
||||
|
||||
mmio_setbits_32(rcc_base + RCC_DDRCPCFGR,
|
||||
RCC_DDRCPCFGR_DDRCPLPEN | RCC_DDRCPCFGR_DDRCPEN);
|
||||
mmio_clrbits_32(rcc_base + RCC_DDRITFCFGR, RCC_DDRITFCFGR_DDRPHYDLP);
|
||||
mmio_setbits_32(rcc_base + RCC_DDRPHYCCFGR, RCC_DDRPHYCCFGR_DDRPHYCEN);
|
||||
|
||||
udelay(DDR_DELAY_1US);
|
||||
|
||||
ddr_activate_controller((struct stm32mp_ddrctl *)ddrctrl_base, false);
|
||||
|
||||
/* Poll on ddrphy_initeng0_phyinlpx.phyinlp3 = 0 */
|
||||
ddr_wait_lp3_mode(false);
|
||||
|
||||
/* SW self refresh exit prequested */
|
||||
mmio_clrbits_32(ddrctrl_base + DDRCTRL_PWRCTL, DDRCTRL_PWRCTL_SELFREF_SW);
|
||||
|
||||
if (ddr_sr_exit_loop() != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Re-enable DFI low-power interface */
|
||||
mmio_setbits_32(ddrctrl_base + DDRCTRL_DFILPCFG0, DDRCTRL_DFILPCFG0_DFI_LP_EN_SR);
|
||||
|
||||
stm32mp_ddr_enable_axi_port((struct stm32mp_ddrctl *)ddrctrl_base);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sr_hsr_set(void)
|
||||
{
|
||||
uintptr_t ddrctrl_base = stm32mp_ddrctrl_base();
|
||||
|
||||
mmio_clrsetbits_32(stm32mp_rcc_base() + RCC_DDRITFCFGR,
|
||||
RCC_DDRITFCFGR_DDRCKMOD_MASK, RCC_DDRITFCFGR_DDRCKMOD_HSR);
|
||||
|
||||
/*
|
||||
* manage quasi-dynamic registers modification
|
||||
* hwlpctl.hw_lp_en : Group 2
|
||||
*/
|
||||
if (stm32mp_ddr_sw_selfref_entry((struct stm32mp_ddrctl *)ddrctrl_base) != 0) {
|
||||
panic();
|
||||
}
|
||||
stm32mp_ddr_start_sw_done((struct stm32mp_ddrctl *)ddrctrl_base);
|
||||
|
||||
mmio_write_32(ddrctrl_base + DDRCTRL_HWLPCTL,
|
||||
DDRCTRL_HWLPCTL_HW_LP_EN | DDRCTRL_HWLPCTL_HW_LP_EXIT_IDLE_EN |
|
||||
(HW_IDLE_PERIOD << DDRCTRL_HWLPCTL_HW_LP_IDLE_X32_SHIFT));
|
||||
|
||||
stm32mp_ddr_wait_sw_done_ack((struct stm32mp_ddrctl *)ddrctrl_base);
|
||||
stm32mp_ddr_sw_selfref_exit((struct stm32mp_ddrctl *)ddrctrl_base);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sr_hsr_entry(void)
|
||||
{
|
||||
mmio_write_32(stm32mp_rcc_base() + RCC_DDRCPCFGR, RCC_DDRCPCFGR_DDRCPLPEN);
|
||||
|
||||
return sr_entry_loop(); /* read_data should be equal to 0x223 */
|
||||
}
|
||||
|
||||
static int sr_hsr_exit(void)
|
||||
{
|
||||
mmio_write_32(stm32mp_rcc_base() + RCC_DDRCPCFGR,
|
||||
RCC_DDRCPCFGR_DDRCPLPEN | RCC_DDRCPCFGR_DDRCPEN);
|
||||
|
||||
/* TODO: check if ddr_sr_exit_loop() is needed here */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sr_asr_set(void)
|
||||
{
|
||||
mmio_write_32(stm32_ddrdbg_get_base() + DDRDBG_LP_DISABLE, 0U);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sr_asr_entry(void)
|
||||
{
|
||||
/*
|
||||
* Automatically enter into self refresh when there is no ddr traffic
|
||||
* for the delay programmed into SYSCONF_DDRC_AUTO_SR_DELAY register.
|
||||
* Default value is 0x20 (unit: Multiples of 32 DFI clock cycles).
|
||||
*/
|
||||
return sr_entry_loop();
|
||||
}
|
||||
|
||||
static int sr_asr_exit(void)
|
||||
{
|
||||
return ddr_sr_exit_loop();
|
||||
}
|
||||
|
||||
uint32_t ddr_get_io_calibration_val(void)
|
||||
{
|
||||
/* TODO create related service */
|
||||
|
||||
return 0U;
|
||||
}
|
||||
|
||||
int ddr_sr_entry(bool standby)
|
||||
{
|
||||
int ret = -EINVAL;
|
||||
|
||||
switch (saved_ddr_sr_mode) {
|
||||
case DDR_SSR_MODE:
|
||||
ret = sr_ssr_entry(standby);
|
||||
break;
|
||||
case DDR_HSR_MODE:
|
||||
ret = sr_hsr_entry();
|
||||
break;
|
||||
case DDR_ASR_MODE:
|
||||
ret = sr_asr_entry();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ddr_sr_exit(void)
|
||||
{
|
||||
int ret = -EINVAL;
|
||||
|
||||
switch (saved_ddr_sr_mode) {
|
||||
case DDR_SSR_MODE:
|
||||
ret = sr_ssr_exit();
|
||||
break;
|
||||
case DDR_HSR_MODE:
|
||||
ret = sr_hsr_exit();
|
||||
break;
|
||||
case DDR_ASR_MODE:
|
||||
ret = sr_asr_exit();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
enum stm32mp2_ddr_sr_mode ddr_read_sr_mode(void)
|
||||
{
|
||||
uint32_t pwrctl = mmio_read_32(stm32mp_ddrctrl_base() + DDRCTRL_PWRCTL);
|
||||
enum stm32mp2_ddr_sr_mode mode = DDR_SR_MODE_INVALID;
|
||||
|
||||
switch (pwrctl & (DDRCTRL_PWRCTL_EN_DFI_DRAM_CLK_DISABLE |
|
||||
DDRCTRL_PWRCTL_SELFREF_EN)) {
|
||||
case 0U:
|
||||
mode = DDR_SSR_MODE;
|
||||
break;
|
||||
case DDRCTRL_PWRCTL_EN_DFI_DRAM_CLK_DISABLE:
|
||||
mode = DDR_HSR_MODE;
|
||||
break;
|
||||
case DDRCTRL_PWRCTL_EN_DFI_DRAM_CLK_DISABLE | DDRCTRL_PWRCTL_SELFREF_EN:
|
||||
mode = DDR_ASR_MODE;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return mode;
|
||||
}
|
||||
|
||||
void ddr_set_sr_mode(enum stm32mp2_ddr_sr_mode mode)
|
||||
{
|
||||
int ret = -EINVAL;
|
||||
|
||||
if (mode == saved_ddr_sr_mode) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (mode) {
|
||||
case DDR_SSR_MODE:
|
||||
ret = sr_ssr_set();
|
||||
break;
|
||||
case DDR_HSR_MODE:
|
||||
ret = sr_hsr_set();
|
||||
break;
|
||||
case DDR_ASR_MODE:
|
||||
ret = sr_asr_set();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (ret != 0) {
|
||||
ERROR("Unknown Self Refresh mode\n");
|
||||
panic();
|
||||
}
|
||||
|
||||
saved_ddr_sr_mode = mode;
|
||||
}
|
||||
|
||||
void ddr_save_sr_mode(void)
|
||||
{
|
||||
saved_ddr_sr_mode = ddr_read_sr_mode();
|
||||
}
|
||||
|
||||
void ddr_restore_sr_mode(void)
|
||||
{
|
||||
ddr_set_sr_mode(saved_ddr_sr_mode);
|
||||
}
|
||||
|
||||
void ddr_sub_system_clk_init(void)
|
||||
{
|
||||
mmio_write_32(stm32mp_rcc_base() + RCC_DDRCPCFGR,
|
||||
RCC_DDRCPCFGR_DDRCPEN | RCC_DDRCPCFGR_DDRCPLPEN);
|
||||
}
|
||||
|
||||
void ddr_sub_system_clk_off(void)
|
||||
{
|
||||
uintptr_t rcc_base = stm32mp_rcc_base();
|
||||
|
||||
/* Clear DDR IO retention */
|
||||
mmio_clrbits_32(stm32mp_pwr_base() + PWR_CR11, PWR_CR11_DDRRETDIS);
|
||||
|
||||
/* Reset DDR sub system */
|
||||
mmio_write_32(rcc_base + RCC_DDRCPCFGR, RCC_DDRCPCFGR_DDRCPRST);
|
||||
mmio_write_32(rcc_base + RCC_DDRITFCFGR, RCC_DDRITFCFGR_DDRRST);
|
||||
mmio_write_32(rcc_base + RCC_DDRPHYCAPBCFGR, RCC_DDRPHYCAPBCFGR_DDRPHYCAPBRST);
|
||||
mmio_write_32(rcc_base + RCC_DDRCAPBCFGR, RCC_DDRCAPBCFGR_DDRCAPBRST);
|
||||
|
||||
/* Deactivate clocks and PLL2 */
|
||||
mmio_clrbits_32(rcc_base + RCC_DDRPHYCCFGR, RCC_DDRPHYCCFGR_DDRPHYCEN);
|
||||
mmio_clrbits_32(rcc_base + RCC_PLL2CFGR1, RCC_PLL2CFGR1_PLLEN);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue