1*06e55dc8SNicolas Le Bayon /* 2*06e55dc8SNicolas Le Bayon * Copyright (C) 2022, STMicroelectronics - All Rights Reserved 3*06e55dc8SNicolas Le Bayon * 4*06e55dc8SNicolas Le Bayon * SPDX-License-Identifier: BSD-3-Clause 5*06e55dc8SNicolas Le Bayon */ 6*06e55dc8SNicolas Le Bayon 7*06e55dc8SNicolas Le Bayon #include <drivers/delay_timer.h> 8*06e55dc8SNicolas Le Bayon #include <drivers/st/stm32mp_ddr.h> 9*06e55dc8SNicolas Le Bayon #include <drivers/st/stm32mp_ddrctrl_regs.h> 10*06e55dc8SNicolas Le Bayon #include <drivers/st/stm32mp_pmic.h> 11*06e55dc8SNicolas Le Bayon #include <lib/mmio.h> 12*06e55dc8SNicolas Le Bayon 13*06e55dc8SNicolas Le Bayon #include <platform_def.h> 14*06e55dc8SNicolas Le Bayon 15*06e55dc8SNicolas Le Bayon #define INVALID_OFFSET 0xFFU 16*06e55dc8SNicolas Le Bayon 17*06e55dc8SNicolas Le Bayon static uintptr_t get_base_addr(const struct stm32mp_ddr_priv *priv, enum stm32mp_ddr_base_type base) 18*06e55dc8SNicolas Le Bayon { 19*06e55dc8SNicolas Le Bayon if (base == DDRPHY_BASE) { 20*06e55dc8SNicolas Le Bayon return (uintptr_t)priv->phy; 21*06e55dc8SNicolas Le Bayon } else { 22*06e55dc8SNicolas Le Bayon return (uintptr_t)priv->ctl; 23*06e55dc8SNicolas Le Bayon } 24*06e55dc8SNicolas Le Bayon } 25*06e55dc8SNicolas Le Bayon 26*06e55dc8SNicolas Le Bayon void stm32mp_ddr_set_reg(const struct stm32mp_ddr_priv *priv, enum stm32mp_ddr_reg_type type, 27*06e55dc8SNicolas Le Bayon const void *param, const struct stm32mp_ddr_reg_info *ddr_registers) 28*06e55dc8SNicolas Le Bayon { 29*06e55dc8SNicolas Le Bayon unsigned int i; 30*06e55dc8SNicolas Le Bayon unsigned int value; 31*06e55dc8SNicolas Le Bayon enum stm32mp_ddr_base_type base = ddr_registers[type].base; 32*06e55dc8SNicolas Le Bayon uintptr_t base_addr = get_base_addr(priv, base); 33*06e55dc8SNicolas Le Bayon const struct stm32mp_ddr_reg_desc *desc = ddr_registers[type].desc; 34*06e55dc8SNicolas Le Bayon 35*06e55dc8SNicolas Le Bayon VERBOSE("init %s\n", ddr_registers[type].name); 36*06e55dc8SNicolas Le Bayon for (i = 0; i < ddr_registers[type].size; i++) { 37*06e55dc8SNicolas Le Bayon uintptr_t ptr = base_addr + desc[i].offset; 38*06e55dc8SNicolas Le Bayon 39*06e55dc8SNicolas Le Bayon if (desc[i].par_offset == INVALID_OFFSET) { 40*06e55dc8SNicolas Le Bayon ERROR("invalid parameter offset for %s", desc[i].name); 41*06e55dc8SNicolas Le Bayon panic(); 42*06e55dc8SNicolas Le Bayon } else { 43*06e55dc8SNicolas Le Bayon value = *((uint32_t *)((uintptr_t)param + 44*06e55dc8SNicolas Le Bayon desc[i].par_offset)); 45*06e55dc8SNicolas Le Bayon mmio_write_32(ptr, value); 46*06e55dc8SNicolas Le Bayon } 47*06e55dc8SNicolas Le Bayon } 48*06e55dc8SNicolas Le Bayon } 49*06e55dc8SNicolas Le Bayon 50*06e55dc8SNicolas Le Bayon /* Start quasi dynamic register update */ 51*06e55dc8SNicolas Le Bayon void stm32mp_ddr_start_sw_done(struct stm32mp_ddrctl *ctl) 52*06e55dc8SNicolas Le Bayon { 53*06e55dc8SNicolas Le Bayon mmio_clrbits_32((uintptr_t)&ctl->swctl, DDRCTRL_SWCTL_SW_DONE); 54*06e55dc8SNicolas Le Bayon VERBOSE("[0x%lx] swctl = 0x%x\n", 55*06e55dc8SNicolas Le Bayon (uintptr_t)&ctl->swctl, mmio_read_32((uintptr_t)&ctl->swctl)); 56*06e55dc8SNicolas Le Bayon } 57*06e55dc8SNicolas Le Bayon 58*06e55dc8SNicolas Le Bayon /* Wait quasi dynamic register update */ 59*06e55dc8SNicolas Le Bayon void stm32mp_ddr_wait_sw_done_ack(struct stm32mp_ddrctl *ctl) 60*06e55dc8SNicolas Le Bayon { 61*06e55dc8SNicolas Le Bayon uint64_t timeout; 62*06e55dc8SNicolas Le Bayon uint32_t swstat; 63*06e55dc8SNicolas Le Bayon 64*06e55dc8SNicolas Le Bayon mmio_setbits_32((uintptr_t)&ctl->swctl, DDRCTRL_SWCTL_SW_DONE); 65*06e55dc8SNicolas Le Bayon VERBOSE("[0x%lx] swctl = 0x%x\n", 66*06e55dc8SNicolas Le Bayon (uintptr_t)&ctl->swctl, mmio_read_32((uintptr_t)&ctl->swctl)); 67*06e55dc8SNicolas Le Bayon 68*06e55dc8SNicolas Le Bayon timeout = timeout_init_us(TIMEOUT_US_1S); 69*06e55dc8SNicolas Le Bayon do { 70*06e55dc8SNicolas Le Bayon swstat = mmio_read_32((uintptr_t)&ctl->swstat); 71*06e55dc8SNicolas Le Bayon VERBOSE("[0x%lx] swstat = 0x%x ", 72*06e55dc8SNicolas Le Bayon (uintptr_t)&ctl->swstat, swstat); 73*06e55dc8SNicolas Le Bayon if (timeout_elapsed(timeout)) { 74*06e55dc8SNicolas Le Bayon panic(); 75*06e55dc8SNicolas Le Bayon } 76*06e55dc8SNicolas Le Bayon } while ((swstat & DDRCTRL_SWSTAT_SW_DONE_ACK) == 0U); 77*06e55dc8SNicolas Le Bayon 78*06e55dc8SNicolas Le Bayon VERBOSE("[0x%lx] swstat = 0x%x\n", 79*06e55dc8SNicolas Le Bayon (uintptr_t)&ctl->swstat, swstat); 80*06e55dc8SNicolas Le Bayon } 81*06e55dc8SNicolas Le Bayon 82*06e55dc8SNicolas Le Bayon void stm32mp_ddr_enable_axi_port(struct stm32mp_ddrctl *ctl) 83*06e55dc8SNicolas Le Bayon { 84*06e55dc8SNicolas Le Bayon /* Enable uMCTL2 AXI port 0 */ 85*06e55dc8SNicolas Le Bayon mmio_setbits_32((uintptr_t)&ctl->pctrl_0, DDRCTRL_PCTRL_N_PORT_EN); 86*06e55dc8SNicolas Le Bayon VERBOSE("[0x%lx] pctrl_0 = 0x%x\n", (uintptr_t)&ctl->pctrl_0, 87*06e55dc8SNicolas Le Bayon mmio_read_32((uintptr_t)&ctl->pctrl_0)); 88*06e55dc8SNicolas Le Bayon 89*06e55dc8SNicolas Le Bayon #if STM32MP_DDR_DUAL_AXI_PORT 90*06e55dc8SNicolas Le Bayon /* Enable uMCTL2 AXI port 1 */ 91*06e55dc8SNicolas Le Bayon mmio_setbits_32((uintptr_t)&ctl->pctrl_1, DDRCTRL_PCTRL_N_PORT_EN); 92*06e55dc8SNicolas Le Bayon VERBOSE("[0x%lx] pctrl_1 = 0x%x\n", (uintptr_t)&ctl->pctrl_1, 93*06e55dc8SNicolas Le Bayon mmio_read_32((uintptr_t)&ctl->pctrl_1)); 94*06e55dc8SNicolas Le Bayon #endif 95*06e55dc8SNicolas Le Bayon 96*06e55dc8SNicolas Le Bayon } 97*06e55dc8SNicolas Le Bayon 98*06e55dc8SNicolas Le Bayon int stm32mp_board_ddr_power_init(enum ddr_type ddr_type) 99*06e55dc8SNicolas Le Bayon { 100*06e55dc8SNicolas Le Bayon if (dt_pmic_status() > 0) { 101*06e55dc8SNicolas Le Bayon return pmic_ddr_power_init(ddr_type); 102*06e55dc8SNicolas Le Bayon } 103*06e55dc8SNicolas Le Bayon 104*06e55dc8SNicolas Le Bayon return 0; 105*06e55dc8SNicolas Le Bayon } 106