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 17d596023bSNicolas Le Bayon static bool axi_port_reenable_request; 18d596023bSNicolas Le Bayon static bool host_interface_reenable_request; 19d596023bSNicolas Le Bayon 2006e55dc8SNicolas Le Bayon static uintptr_t get_base_addr(const struct stm32mp_ddr_priv *priv, enum stm32mp_ddr_base_type base) 2106e55dc8SNicolas Le Bayon { 2206e55dc8SNicolas Le Bayon if (base == DDRPHY_BASE) { 2306e55dc8SNicolas Le Bayon return (uintptr_t)priv->phy; 2406e55dc8SNicolas Le Bayon } else { 2506e55dc8SNicolas Le Bayon return (uintptr_t)priv->ctl; 2606e55dc8SNicolas Le Bayon } 2706e55dc8SNicolas Le Bayon } 2806e55dc8SNicolas Le Bayon 2906e55dc8SNicolas Le Bayon void stm32mp_ddr_set_reg(const struct stm32mp_ddr_priv *priv, enum stm32mp_ddr_reg_type type, 3006e55dc8SNicolas Le Bayon const void *param, const struct stm32mp_ddr_reg_info *ddr_registers) 3106e55dc8SNicolas Le Bayon { 3206e55dc8SNicolas Le Bayon unsigned int i; 3306e55dc8SNicolas Le Bayon unsigned int value; 3406e55dc8SNicolas Le Bayon enum stm32mp_ddr_base_type base = ddr_registers[type].base; 3506e55dc8SNicolas Le Bayon uintptr_t base_addr = get_base_addr(priv, base); 3606e55dc8SNicolas Le Bayon const struct stm32mp_ddr_reg_desc *desc = ddr_registers[type].desc; 3706e55dc8SNicolas Le Bayon 3806e55dc8SNicolas Le Bayon VERBOSE("init %s\n", ddr_registers[type].name); 3906e55dc8SNicolas Le Bayon for (i = 0; i < ddr_registers[type].size; i++) { 4006e55dc8SNicolas Le Bayon uintptr_t ptr = base_addr + desc[i].offset; 4106e55dc8SNicolas Le Bayon 4206e55dc8SNicolas Le Bayon if (desc[i].par_offset == INVALID_OFFSET) { 431483b3c3SYann Gautier ERROR("invalid parameter offset for %s - index %u", 441483b3c3SYann Gautier ddr_registers[type].name, i); 4506e55dc8SNicolas Le Bayon panic(); 4606e55dc8SNicolas Le Bayon } else { 47*701178dcSMaxime Méré #ifdef STM32MP2X 4879629b1aSNicolas Le Bayon if (desc[i].qd) { 4979629b1aSNicolas Le Bayon stm32mp_ddr_start_sw_done(priv->ctl); 5079629b1aSNicolas Le Bayon } 5179629b1aSNicolas Le Bayon #endif 5206e55dc8SNicolas Le Bayon value = *((uint32_t *)((uintptr_t)param + 5306e55dc8SNicolas Le Bayon desc[i].par_offset)); 5406e55dc8SNicolas Le Bayon mmio_write_32(ptr, value); 55*701178dcSMaxime Méré #ifdef STM32MP2X 5679629b1aSNicolas Le Bayon if (desc[i].qd) { 5779629b1aSNicolas Le Bayon stm32mp_ddr_wait_sw_done_ack(priv->ctl); 5879629b1aSNicolas Le Bayon } 5979629b1aSNicolas Le Bayon #endif 6006e55dc8SNicolas Le Bayon } 6106e55dc8SNicolas Le Bayon } 6206e55dc8SNicolas Le Bayon } 6306e55dc8SNicolas Le Bayon 6406e55dc8SNicolas Le Bayon /* Start quasi dynamic register update */ 6506e55dc8SNicolas Le Bayon void stm32mp_ddr_start_sw_done(struct stm32mp_ddrctl *ctl) 6606e55dc8SNicolas Le Bayon { 6706e55dc8SNicolas Le Bayon mmio_clrbits_32((uintptr_t)&ctl->swctl, DDRCTRL_SWCTL_SW_DONE); 6806e55dc8SNicolas Le Bayon VERBOSE("[0x%lx] swctl = 0x%x\n", 6906e55dc8SNicolas Le Bayon (uintptr_t)&ctl->swctl, mmio_read_32((uintptr_t)&ctl->swctl)); 7006e55dc8SNicolas Le Bayon } 7106e55dc8SNicolas Le Bayon 7206e55dc8SNicolas Le Bayon /* Wait quasi dynamic register update */ 7306e55dc8SNicolas Le Bayon void stm32mp_ddr_wait_sw_done_ack(struct stm32mp_ddrctl *ctl) 7406e55dc8SNicolas Le Bayon { 7506e55dc8SNicolas Le Bayon uint64_t timeout; 7606e55dc8SNicolas Le Bayon uint32_t swstat; 7706e55dc8SNicolas Le Bayon 7806e55dc8SNicolas Le Bayon mmio_setbits_32((uintptr_t)&ctl->swctl, DDRCTRL_SWCTL_SW_DONE); 7906e55dc8SNicolas Le Bayon VERBOSE("[0x%lx] swctl = 0x%x\n", 8006e55dc8SNicolas Le Bayon (uintptr_t)&ctl->swctl, mmio_read_32((uintptr_t)&ctl->swctl)); 8106e55dc8SNicolas Le Bayon 82066a5958SYann Gautier timeout = timeout_init_us(DDR_TIMEOUT_US_1S); 8306e55dc8SNicolas Le Bayon do { 8406e55dc8SNicolas Le Bayon swstat = mmio_read_32((uintptr_t)&ctl->swstat); 8506e55dc8SNicolas Le Bayon VERBOSE("[0x%lx] swstat = 0x%x ", 8606e55dc8SNicolas Le Bayon (uintptr_t)&ctl->swstat, swstat); 8706e55dc8SNicolas Le Bayon if (timeout_elapsed(timeout)) { 8806e55dc8SNicolas Le Bayon panic(); 8906e55dc8SNicolas Le Bayon } 9006e55dc8SNicolas Le Bayon } while ((swstat & DDRCTRL_SWSTAT_SW_DONE_ACK) == 0U); 9106e55dc8SNicolas Le Bayon 9206e55dc8SNicolas Le Bayon VERBOSE("[0x%lx] swstat = 0x%x\n", 9306e55dc8SNicolas Le Bayon (uintptr_t)&ctl->swstat, swstat); 9406e55dc8SNicolas Le Bayon } 9506e55dc8SNicolas Le Bayon 9606e55dc8SNicolas Le Bayon void stm32mp_ddr_enable_axi_port(struct stm32mp_ddrctl *ctl) 9706e55dc8SNicolas Le Bayon { 9806e55dc8SNicolas Le Bayon /* Enable uMCTL2 AXI port 0 */ 9906e55dc8SNicolas Le Bayon mmio_setbits_32((uintptr_t)&ctl->pctrl_0, DDRCTRL_PCTRL_N_PORT_EN); 10006e55dc8SNicolas Le Bayon VERBOSE("[0x%lx] pctrl_0 = 0x%x\n", (uintptr_t)&ctl->pctrl_0, 10106e55dc8SNicolas Le Bayon mmio_read_32((uintptr_t)&ctl->pctrl_0)); 10206e55dc8SNicolas Le Bayon 10306e55dc8SNicolas Le Bayon #if STM32MP_DDR_DUAL_AXI_PORT 10406e55dc8SNicolas Le Bayon /* Enable uMCTL2 AXI port 1 */ 10506e55dc8SNicolas Le Bayon mmio_setbits_32((uintptr_t)&ctl->pctrl_1, DDRCTRL_PCTRL_N_PORT_EN); 10606e55dc8SNicolas Le Bayon VERBOSE("[0x%lx] pctrl_1 = 0x%x\n", (uintptr_t)&ctl->pctrl_1, 10706e55dc8SNicolas Le Bayon mmio_read_32((uintptr_t)&ctl->pctrl_1)); 10806e55dc8SNicolas Le Bayon #endif 109d596023bSNicolas Le Bayon } 11006e55dc8SNicolas Le Bayon 111d596023bSNicolas Le Bayon int stm32mp_ddr_disable_axi_port(struct stm32mp_ddrctl *ctl) 112d596023bSNicolas Le Bayon { 113d596023bSNicolas Le Bayon uint64_t timeout; 114d596023bSNicolas Le Bayon uint32_t pstat; 115d596023bSNicolas Le Bayon 116d596023bSNicolas Le Bayon /* Disable uMCTL2 AXI port 0 */ 117d596023bSNicolas Le Bayon mmio_clrbits_32((uintptr_t)&ctl->pctrl_0, DDRCTRL_PCTRL_N_PORT_EN); 118d596023bSNicolas Le Bayon VERBOSE("[0x%lx] pctrl_0 = 0x%x\n", (uintptr_t)&ctl->pctrl_0, 119d596023bSNicolas Le Bayon mmio_read_32((uintptr_t)&ctl->pctrl_0)); 120d596023bSNicolas Le Bayon 121d596023bSNicolas Le Bayon #if STM32MP_DDR_DUAL_AXI_PORT 122d596023bSNicolas Le Bayon /* Disable uMCTL2 AXI port 1 */ 123d596023bSNicolas Le Bayon mmio_clrbits_32((uintptr_t)&ctl->pctrl_1, DDRCTRL_PCTRL_N_PORT_EN); 124d596023bSNicolas Le Bayon VERBOSE("[0x%lx] pctrl_1 = 0x%x\n", (uintptr_t)&ctl->pctrl_1, 125d596023bSNicolas Le Bayon mmio_read_32((uintptr_t)&ctl->pctrl_1)); 126d596023bSNicolas Le Bayon #endif 127d596023bSNicolas Le Bayon 128d596023bSNicolas Le Bayon /* 129d596023bSNicolas Le Bayon * Waits until all AXI ports are idle 130d596023bSNicolas Le Bayon * Poll PSTAT.rd_port_busy_n = 0 131d596023bSNicolas Le Bayon * Poll PSTAT.wr_port_busy_n = 0 132d596023bSNicolas Le Bayon */ 133d596023bSNicolas Le Bayon timeout = timeout_init_us(DDR_TIMEOUT_US_1S); 134d596023bSNicolas Le Bayon do { 135d596023bSNicolas Le Bayon pstat = mmio_read_32((uintptr_t)&ctl->pstat); 136d596023bSNicolas Le Bayon VERBOSE("[0x%lx] pstat = 0x%x ", 137d596023bSNicolas Le Bayon (uintptr_t)&ctl->pstat, pstat); 138d596023bSNicolas Le Bayon if (timeout_elapsed(timeout)) { 139d596023bSNicolas Le Bayon return -1; 140d596023bSNicolas Le Bayon } 141d596023bSNicolas Le Bayon } while (pstat != 0U); 142d596023bSNicolas Le Bayon 143d596023bSNicolas Le Bayon return 0; 144d596023bSNicolas Le Bayon } 145d596023bSNicolas Le Bayon 146d596023bSNicolas Le Bayon static bool ddr_is_axi_port_enabled(struct stm32mp_ddrctl *ctl) 147d596023bSNicolas Le Bayon { 148d596023bSNicolas Le Bayon return (mmio_read_32((uintptr_t)&ctl->pctrl_0) & DDRCTRL_PCTRL_N_PORT_EN) != 0U; 149d596023bSNicolas Le Bayon } 150d596023bSNicolas Le Bayon 151d596023bSNicolas Le Bayon void stm32mp_ddr_enable_host_interface(struct stm32mp_ddrctl *ctl) 152d596023bSNicolas Le Bayon { 153d596023bSNicolas Le Bayon mmio_clrbits_32((uintptr_t)&ctl->dbg1, DDRCTRL_DBG1_DIS_HIF); 154d596023bSNicolas Le Bayon VERBOSE("[0x%lx] dbg1 = 0x%x\n", 155d596023bSNicolas Le Bayon (uintptr_t)&ctl->dbg1, 156d596023bSNicolas Le Bayon mmio_read_32((uintptr_t)&ctl->dbg1)); 157d596023bSNicolas Le Bayon } 158d596023bSNicolas Le Bayon 159d596023bSNicolas Le Bayon void stm32mp_ddr_disable_host_interface(struct stm32mp_ddrctl *ctl) 160d596023bSNicolas Le Bayon { 161d596023bSNicolas Le Bayon uint64_t timeout; 162d596023bSNicolas Le Bayon uint32_t dbgcam; 163d596023bSNicolas Le Bayon int count = 0; 164d596023bSNicolas Le Bayon 165d596023bSNicolas Le Bayon mmio_setbits_32((uintptr_t)&ctl->dbg1, DDRCTRL_DBG1_DIS_HIF); 166d596023bSNicolas Le Bayon VERBOSE("[0x%lx] dbg1 = 0x%x\n", 167d596023bSNicolas Le Bayon (uintptr_t)&ctl->dbg1, 168d596023bSNicolas Le Bayon mmio_read_32((uintptr_t)&ctl->dbg1)); 169d596023bSNicolas Le Bayon 170d596023bSNicolas Le Bayon /* 171d596023bSNicolas Le Bayon * Waits until all queues and pipelines are empty 172d596023bSNicolas Le Bayon * Poll DBGCAM.dbg_wr_q_empty = 1 173d596023bSNicolas Le Bayon * Poll DBGCAM.dbg_rd_q_empty = 1 174d596023bSNicolas Le Bayon * Poll DBGCAM.dbg_wr_data_pipeline_empty = 1 175d596023bSNicolas Le Bayon * Poll DBGCAM.dbg_rd_data_pipeline_empty = 1 176d596023bSNicolas Le Bayon * 177d596023bSNicolas Le Bayon * data_pipeline fields must be polled twice to ensure 178d596023bSNicolas Le Bayon * value propoagation, so count is added to loop condition. 179d596023bSNicolas Le Bayon */ 180d596023bSNicolas Le Bayon timeout = timeout_init_us(DDR_TIMEOUT_US_1S); 181d596023bSNicolas Le Bayon do { 182d596023bSNicolas Le Bayon dbgcam = mmio_read_32((uintptr_t)&ctl->dbgcam); 183d596023bSNicolas Le Bayon VERBOSE("[0x%lx] dbgcam = 0x%x ", 184d596023bSNicolas Le Bayon (uintptr_t)&ctl->dbgcam, dbgcam); 185d596023bSNicolas Le Bayon if (timeout_elapsed(timeout)) { 186d596023bSNicolas Le Bayon panic(); 187d596023bSNicolas Le Bayon } 188d596023bSNicolas Le Bayon count++; 189d596023bSNicolas Le Bayon } while (((dbgcam & DDRCTRL_DBG_Q_AND_DATA_PIPELINE_EMPTY) != 190d596023bSNicolas Le Bayon DDRCTRL_DBG_Q_AND_DATA_PIPELINE_EMPTY) || (count < 2)); 191d596023bSNicolas Le Bayon } 192d596023bSNicolas Le Bayon 193d596023bSNicolas Le Bayon static bool ddr_is_host_interface_enabled(struct stm32mp_ddrctl *ctl) 194d596023bSNicolas Le Bayon { 195d596023bSNicolas Le Bayon return (mmio_read_32((uintptr_t)&ctl->dbg1) & DDRCTRL_DBG1_DIS_HIF) == 0U; 196d596023bSNicolas Le Bayon } 197d596023bSNicolas Le Bayon 198d596023bSNicolas Le Bayon int stm32mp_ddr_sw_selfref_entry(struct stm32mp_ddrctl *ctl) 199d596023bSNicolas Le Bayon { 200d596023bSNicolas Le Bayon uint64_t timeout; 201d596023bSNicolas Le Bayon uint32_t stat; 202d596023bSNicolas Le Bayon uint32_t operating_mode; 203d596023bSNicolas Le Bayon uint32_t selref_type; 204d596023bSNicolas Le Bayon 205d596023bSNicolas Le Bayon mmio_setbits_32((uintptr_t)&ctl->pwrctl, DDRCTRL_PWRCTL_SELFREF_SW); 206d596023bSNicolas Le Bayon VERBOSE("[0x%lx] pwrctl = 0x%x\n", 207d596023bSNicolas Le Bayon (uintptr_t)&ctl->pwrctl, 208d596023bSNicolas Le Bayon mmio_read_32((uintptr_t)&ctl->pwrctl)); 209d596023bSNicolas Le Bayon 210d596023bSNicolas Le Bayon /* 211d596023bSNicolas Le Bayon * Wait operating mode change in self-refresh mode 212d596023bSNicolas Le Bayon * with STAT.operating_mode[1:0]==11. 213d596023bSNicolas Le Bayon * Ensure transition to self-refresh was due to software 214d596023bSNicolas Le Bayon * by checking also that STAT.selfref_type[1:0]=2. 215d596023bSNicolas Le Bayon */ 216d596023bSNicolas Le Bayon timeout = timeout_init_us(DDR_TIMEOUT_500US); 217d596023bSNicolas Le Bayon while (!timeout_elapsed(timeout)) { 218d596023bSNicolas Le Bayon stat = mmio_read_32((uintptr_t)&ctl->stat); 219d596023bSNicolas Le Bayon operating_mode = stat & DDRCTRL_STAT_OPERATING_MODE_MASK; 220d596023bSNicolas Le Bayon selref_type = stat & DDRCTRL_STAT_SELFREF_TYPE_MASK; 221d596023bSNicolas Le Bayon 222d596023bSNicolas Le Bayon if ((operating_mode == DDRCTRL_STAT_OPERATING_MODE_SR) && 223d596023bSNicolas Le Bayon (selref_type == DDRCTRL_STAT_SELFREF_TYPE_SR)) { 224d596023bSNicolas Le Bayon return 0; 225d596023bSNicolas Le Bayon } 226d596023bSNicolas Le Bayon } 227d596023bSNicolas Le Bayon 228d596023bSNicolas Le Bayon return -1; 229d596023bSNicolas Le Bayon } 230d596023bSNicolas Le Bayon 231d596023bSNicolas Le Bayon void stm32mp_ddr_sw_selfref_exit(struct stm32mp_ddrctl *ctl) 232d596023bSNicolas Le Bayon { 233d596023bSNicolas Le Bayon mmio_clrbits_32((uintptr_t)&ctl->pwrctl, DDRCTRL_PWRCTL_SELFREF_SW); 234d596023bSNicolas Le Bayon VERBOSE("[0x%lx] pwrctl = 0x%x\n", 235d596023bSNicolas Le Bayon (uintptr_t)&ctl->pwrctl, 236d596023bSNicolas Le Bayon mmio_read_32((uintptr_t)&ctl->pwrctl)); 237d596023bSNicolas Le Bayon } 238d596023bSNicolas Le Bayon 239d596023bSNicolas Le Bayon void stm32mp_ddr_set_qd3_update_conditions(struct stm32mp_ddrctl *ctl) 240d596023bSNicolas Le Bayon { 241d596023bSNicolas Le Bayon if (ddr_is_axi_port_enabled(ctl)) { 242d596023bSNicolas Le Bayon if (stm32mp_ddr_disable_axi_port(ctl) != 0) { 243d596023bSNicolas Le Bayon panic(); 244d596023bSNicolas Le Bayon } 245d596023bSNicolas Le Bayon axi_port_reenable_request = true; 246d596023bSNicolas Le Bayon } 247d596023bSNicolas Le Bayon 248d596023bSNicolas Le Bayon if (ddr_is_host_interface_enabled(ctl)) { 249d596023bSNicolas Le Bayon stm32mp_ddr_disable_host_interface(ctl); 250d596023bSNicolas Le Bayon host_interface_reenable_request = true; 251d596023bSNicolas Le Bayon } 252d596023bSNicolas Le Bayon 253d596023bSNicolas Le Bayon stm32mp_ddr_start_sw_done(ctl); 254d596023bSNicolas Le Bayon } 255d596023bSNicolas Le Bayon 256d596023bSNicolas Le Bayon void stm32mp_ddr_unset_qd3_update_conditions(struct stm32mp_ddrctl *ctl) 257d596023bSNicolas Le Bayon { 258d596023bSNicolas Le Bayon stm32mp_ddr_wait_sw_done_ack(ctl); 259d596023bSNicolas Le Bayon 260d596023bSNicolas Le Bayon if (host_interface_reenable_request) { 261d596023bSNicolas Le Bayon stm32mp_ddr_enable_host_interface(ctl); 262d596023bSNicolas Le Bayon host_interface_reenable_request = false; 263d596023bSNicolas Le Bayon } 264d596023bSNicolas Le Bayon 265d596023bSNicolas Le Bayon if (axi_port_reenable_request) { 266d596023bSNicolas Le Bayon stm32mp_ddr_enable_axi_port(ctl); 267d596023bSNicolas Le Bayon axi_port_reenable_request = false; 268d596023bSNicolas Le Bayon } 269d596023bSNicolas Le Bayon } 270d596023bSNicolas Le Bayon 271d596023bSNicolas Le Bayon void stm32mp_ddr_wait_refresh_update_done_ack(struct stm32mp_ddrctl *ctl) 272d596023bSNicolas Le Bayon { 273d596023bSNicolas Le Bayon uint64_t timeout; 274d596023bSNicolas Le Bayon uint32_t rfshctl3; 275d596023bSNicolas Le Bayon uint32_t refresh_update_level = DDRCTRL_RFSHCTL3_REFRESH_UPDATE_LEVEL; 276d596023bSNicolas Le Bayon 277d596023bSNicolas Le Bayon /* Toggle rfshctl3.refresh_update_level */ 278d596023bSNicolas Le Bayon rfshctl3 = mmio_read_32((uintptr_t)&ctl->rfshctl3); 279d596023bSNicolas Le Bayon if ((rfshctl3 & refresh_update_level) == refresh_update_level) { 280d596023bSNicolas Le Bayon mmio_setbits_32((uintptr_t)&ctl->rfshctl3, refresh_update_level); 281d596023bSNicolas Le Bayon } else { 282d596023bSNicolas Le Bayon mmio_clrbits_32((uintptr_t)&ctl->rfshctl3, refresh_update_level); 283d596023bSNicolas Le Bayon refresh_update_level = 0U; 284d596023bSNicolas Le Bayon } 285d596023bSNicolas Le Bayon 286d596023bSNicolas Le Bayon VERBOSE("[0x%lx] rfshctl3 = 0x%x\n", 287d596023bSNicolas Le Bayon (uintptr_t)&ctl->rfshctl3, mmio_read_32((uintptr_t)&ctl->rfshctl3)); 288d596023bSNicolas Le Bayon 289d596023bSNicolas Le Bayon timeout = timeout_init_us(DDR_TIMEOUT_US_1S); 290d596023bSNicolas Le Bayon do { 291d596023bSNicolas Le Bayon rfshctl3 = mmio_read_32((uintptr_t)&ctl->rfshctl3); 292d596023bSNicolas Le Bayon VERBOSE("[0x%lx] rfshctl3 = 0x%x ", (uintptr_t)&ctl->rfshctl3, rfshctl3); 293d596023bSNicolas Le Bayon if (timeout_elapsed(timeout)) { 294d596023bSNicolas Le Bayon panic(); 295d596023bSNicolas Le Bayon } 296d596023bSNicolas Le Bayon } while ((rfshctl3 & DDRCTRL_RFSHCTL3_REFRESH_UPDATE_LEVEL) != refresh_update_level); 297d596023bSNicolas Le Bayon 298d596023bSNicolas Le Bayon VERBOSE("[0x%lx] rfshctl3 = 0x%x\n", (uintptr_t)&ctl->rfshctl3, rfshctl3); 29906e55dc8SNicolas Le Bayon } 300