123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527 |
- /*
- * Copyright (c) 2024, STMicroelectronics - All Rights Reserved
- *
- * 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);
- }
|