106e55dc8SNicolas Le Bayon /* 247e62314SPatrick Delaunay * Copyright (C) 2022-2024, STMicroelectronics - All Rights Reserved 306e55dc8SNicolas Le Bayon * 406e55dc8SNicolas Le Bayon * SPDX-License-Identifier: BSD-3-Clause 506e55dc8SNicolas Le Bayon */ 606e55dc8SNicolas Le Bayon 715ca2c5eSYann Gautier #include <common/debug.h> 806e55dc8SNicolas Le Bayon #include <drivers/delay_timer.h> 906e55dc8SNicolas Le Bayon #include <drivers/st/stm32mp_ddr.h> 1006e55dc8SNicolas Le Bayon #include <drivers/st/stm32mp_ddrctrl_regs.h> 1106e55dc8SNicolas Le Bayon #include <lib/mmio.h> 1206e55dc8SNicolas Le Bayon 1306e55dc8SNicolas Le Bayon #include <platform_def.h> 1406e55dc8SNicolas Le Bayon 1506e55dc8SNicolas Le Bayon #define INVALID_OFFSET 0xFFU 1606e55dc8SNicolas Le Bayon 1706e55dc8SNicolas Le Bayon static uintptr_t get_base_addr(const struct stm32mp_ddr_priv *priv, enum stm32mp_ddr_base_type base) 1806e55dc8SNicolas Le Bayon { 1906e55dc8SNicolas Le Bayon if (base == DDRPHY_BASE) { 2006e55dc8SNicolas Le Bayon return (uintptr_t)priv->phy; 2106e55dc8SNicolas Le Bayon } else { 2206e55dc8SNicolas Le Bayon return (uintptr_t)priv->ctl; 2306e55dc8SNicolas Le Bayon } 2406e55dc8SNicolas Le Bayon } 2506e55dc8SNicolas Le Bayon 2606e55dc8SNicolas Le Bayon void stm32mp_ddr_set_reg(const struct stm32mp_ddr_priv *priv, enum stm32mp_ddr_reg_type type, 2706e55dc8SNicolas Le Bayon const void *param, const struct stm32mp_ddr_reg_info *ddr_registers) 2806e55dc8SNicolas Le Bayon { 2906e55dc8SNicolas Le Bayon unsigned int i; 3006e55dc8SNicolas Le Bayon unsigned int value; 3106e55dc8SNicolas Le Bayon enum stm32mp_ddr_base_type base = ddr_registers[type].base; 3206e55dc8SNicolas Le Bayon uintptr_t base_addr = get_base_addr(priv, base); 3306e55dc8SNicolas Le Bayon const struct stm32mp_ddr_reg_desc *desc = ddr_registers[type].desc; 3406e55dc8SNicolas Le Bayon 3506e55dc8SNicolas Le Bayon VERBOSE("init %s\n", ddr_registers[type].name); 3606e55dc8SNicolas Le Bayon for (i = 0; i < ddr_registers[type].size; i++) { 3706e55dc8SNicolas Le Bayon uintptr_t ptr = base_addr + desc[i].offset; 3806e55dc8SNicolas Le Bayon 3906e55dc8SNicolas Le Bayon if (desc[i].par_offset == INVALID_OFFSET) { 40*1483b3c3SYann Gautier ERROR("invalid parameter offset for %s - index %u", 41*1483b3c3SYann Gautier ddr_registers[type].name, i); 4206e55dc8SNicolas Le Bayon panic(); 4306e55dc8SNicolas Le Bayon } else { 4406e55dc8SNicolas Le Bayon value = *((uint32_t *)((uintptr_t)param + 4506e55dc8SNicolas Le Bayon desc[i].par_offset)); 4606e55dc8SNicolas Le Bayon mmio_write_32(ptr, value); 4706e55dc8SNicolas Le Bayon } 4806e55dc8SNicolas Le Bayon } 4906e55dc8SNicolas Le Bayon } 5006e55dc8SNicolas Le Bayon 5106e55dc8SNicolas Le Bayon /* Start quasi dynamic register update */ 5206e55dc8SNicolas Le Bayon void stm32mp_ddr_start_sw_done(struct stm32mp_ddrctl *ctl) 5306e55dc8SNicolas Le Bayon { 5406e55dc8SNicolas Le Bayon mmio_clrbits_32((uintptr_t)&ctl->swctl, DDRCTRL_SWCTL_SW_DONE); 5506e55dc8SNicolas Le Bayon VERBOSE("[0x%lx] swctl = 0x%x\n", 5606e55dc8SNicolas Le Bayon (uintptr_t)&ctl->swctl, mmio_read_32((uintptr_t)&ctl->swctl)); 5706e55dc8SNicolas Le Bayon } 5806e55dc8SNicolas Le Bayon 5906e55dc8SNicolas Le Bayon /* Wait quasi dynamic register update */ 6006e55dc8SNicolas Le Bayon void stm32mp_ddr_wait_sw_done_ack(struct stm32mp_ddrctl *ctl) 6106e55dc8SNicolas Le Bayon { 6206e55dc8SNicolas Le Bayon uint64_t timeout; 6306e55dc8SNicolas Le Bayon uint32_t swstat; 6406e55dc8SNicolas Le Bayon 6506e55dc8SNicolas Le Bayon mmio_setbits_32((uintptr_t)&ctl->swctl, DDRCTRL_SWCTL_SW_DONE); 6606e55dc8SNicolas Le Bayon VERBOSE("[0x%lx] swctl = 0x%x\n", 6706e55dc8SNicolas Le Bayon (uintptr_t)&ctl->swctl, mmio_read_32((uintptr_t)&ctl->swctl)); 6806e55dc8SNicolas Le Bayon 69066a5958SYann Gautier timeout = timeout_init_us(DDR_TIMEOUT_US_1S); 7006e55dc8SNicolas Le Bayon do { 7106e55dc8SNicolas Le Bayon swstat = mmio_read_32((uintptr_t)&ctl->swstat); 7206e55dc8SNicolas Le Bayon VERBOSE("[0x%lx] swstat = 0x%x ", 7306e55dc8SNicolas Le Bayon (uintptr_t)&ctl->swstat, swstat); 7406e55dc8SNicolas Le Bayon if (timeout_elapsed(timeout)) { 7506e55dc8SNicolas Le Bayon panic(); 7606e55dc8SNicolas Le Bayon } 7706e55dc8SNicolas Le Bayon } while ((swstat & DDRCTRL_SWSTAT_SW_DONE_ACK) == 0U); 7806e55dc8SNicolas Le Bayon 7906e55dc8SNicolas Le Bayon VERBOSE("[0x%lx] swstat = 0x%x\n", 8006e55dc8SNicolas Le Bayon (uintptr_t)&ctl->swstat, swstat); 8106e55dc8SNicolas Le Bayon } 8206e55dc8SNicolas Le Bayon 8306e55dc8SNicolas Le Bayon void stm32mp_ddr_enable_axi_port(struct stm32mp_ddrctl *ctl) 8406e55dc8SNicolas Le Bayon { 8506e55dc8SNicolas Le Bayon /* Enable uMCTL2 AXI port 0 */ 8606e55dc8SNicolas Le Bayon mmio_setbits_32((uintptr_t)&ctl->pctrl_0, DDRCTRL_PCTRL_N_PORT_EN); 8706e55dc8SNicolas Le Bayon VERBOSE("[0x%lx] pctrl_0 = 0x%x\n", (uintptr_t)&ctl->pctrl_0, 8806e55dc8SNicolas Le Bayon mmio_read_32((uintptr_t)&ctl->pctrl_0)); 8906e55dc8SNicolas Le Bayon 9006e55dc8SNicolas Le Bayon #if STM32MP_DDR_DUAL_AXI_PORT 9106e55dc8SNicolas Le Bayon /* Enable uMCTL2 AXI port 1 */ 9206e55dc8SNicolas Le Bayon mmio_setbits_32((uintptr_t)&ctl->pctrl_1, DDRCTRL_PCTRL_N_PORT_EN); 9306e55dc8SNicolas Le Bayon VERBOSE("[0x%lx] pctrl_1 = 0x%x\n", (uintptr_t)&ctl->pctrl_1, 9406e55dc8SNicolas Le Bayon mmio_read_32((uintptr_t)&ctl->pctrl_1)); 9506e55dc8SNicolas Le Bayon #endif 9606e55dc8SNicolas Le Bayon 9706e55dc8SNicolas Le Bayon } 98