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 17*d596023bSNicolas Le Bayon static bool axi_port_reenable_request; 18*d596023bSNicolas Le Bayon static bool host_interface_reenable_request; 19*d596023bSNicolas 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 { 4706e55dc8SNicolas Le Bayon value = *((uint32_t *)((uintptr_t)param + 4806e55dc8SNicolas Le Bayon desc[i].par_offset)); 4906e55dc8SNicolas Le Bayon mmio_write_32(ptr, value); 5006e55dc8SNicolas Le Bayon } 5106e55dc8SNicolas Le Bayon } 5206e55dc8SNicolas Le Bayon } 5306e55dc8SNicolas Le Bayon 5406e55dc8SNicolas Le Bayon /* Start quasi dynamic register update */ 5506e55dc8SNicolas Le Bayon void stm32mp_ddr_start_sw_done(struct stm32mp_ddrctl *ctl) 5606e55dc8SNicolas Le Bayon { 5706e55dc8SNicolas Le Bayon mmio_clrbits_32((uintptr_t)&ctl->swctl, DDRCTRL_SWCTL_SW_DONE); 5806e55dc8SNicolas Le Bayon VERBOSE("[0x%lx] swctl = 0x%x\n", 5906e55dc8SNicolas Le Bayon (uintptr_t)&ctl->swctl, mmio_read_32((uintptr_t)&ctl->swctl)); 6006e55dc8SNicolas Le Bayon } 6106e55dc8SNicolas Le Bayon 6206e55dc8SNicolas Le Bayon /* Wait quasi dynamic register update */ 6306e55dc8SNicolas Le Bayon void stm32mp_ddr_wait_sw_done_ack(struct stm32mp_ddrctl *ctl) 6406e55dc8SNicolas Le Bayon { 6506e55dc8SNicolas Le Bayon uint64_t timeout; 6606e55dc8SNicolas Le Bayon uint32_t swstat; 6706e55dc8SNicolas Le Bayon 6806e55dc8SNicolas Le Bayon mmio_setbits_32((uintptr_t)&ctl->swctl, DDRCTRL_SWCTL_SW_DONE); 6906e55dc8SNicolas Le Bayon VERBOSE("[0x%lx] swctl = 0x%x\n", 7006e55dc8SNicolas Le Bayon (uintptr_t)&ctl->swctl, mmio_read_32((uintptr_t)&ctl->swctl)); 7106e55dc8SNicolas Le Bayon 72066a5958SYann Gautier timeout = timeout_init_us(DDR_TIMEOUT_US_1S); 7306e55dc8SNicolas Le Bayon do { 7406e55dc8SNicolas Le Bayon swstat = mmio_read_32((uintptr_t)&ctl->swstat); 7506e55dc8SNicolas Le Bayon VERBOSE("[0x%lx] swstat = 0x%x ", 7606e55dc8SNicolas Le Bayon (uintptr_t)&ctl->swstat, swstat); 7706e55dc8SNicolas Le Bayon if (timeout_elapsed(timeout)) { 7806e55dc8SNicolas Le Bayon panic(); 7906e55dc8SNicolas Le Bayon } 8006e55dc8SNicolas Le Bayon } while ((swstat & DDRCTRL_SWSTAT_SW_DONE_ACK) == 0U); 8106e55dc8SNicolas Le Bayon 8206e55dc8SNicolas Le Bayon VERBOSE("[0x%lx] swstat = 0x%x\n", 8306e55dc8SNicolas Le Bayon (uintptr_t)&ctl->swstat, swstat); 8406e55dc8SNicolas Le Bayon } 8506e55dc8SNicolas Le Bayon 8606e55dc8SNicolas Le Bayon void stm32mp_ddr_enable_axi_port(struct stm32mp_ddrctl *ctl) 8706e55dc8SNicolas Le Bayon { 8806e55dc8SNicolas Le Bayon /* Enable uMCTL2 AXI port 0 */ 8906e55dc8SNicolas Le Bayon mmio_setbits_32((uintptr_t)&ctl->pctrl_0, DDRCTRL_PCTRL_N_PORT_EN); 9006e55dc8SNicolas Le Bayon VERBOSE("[0x%lx] pctrl_0 = 0x%x\n", (uintptr_t)&ctl->pctrl_0, 9106e55dc8SNicolas Le Bayon mmio_read_32((uintptr_t)&ctl->pctrl_0)); 9206e55dc8SNicolas Le Bayon 9306e55dc8SNicolas Le Bayon #if STM32MP_DDR_DUAL_AXI_PORT 9406e55dc8SNicolas Le Bayon /* Enable uMCTL2 AXI port 1 */ 9506e55dc8SNicolas Le Bayon mmio_setbits_32((uintptr_t)&ctl->pctrl_1, DDRCTRL_PCTRL_N_PORT_EN); 9606e55dc8SNicolas Le Bayon VERBOSE("[0x%lx] pctrl_1 = 0x%x\n", (uintptr_t)&ctl->pctrl_1, 9706e55dc8SNicolas Le Bayon mmio_read_32((uintptr_t)&ctl->pctrl_1)); 9806e55dc8SNicolas Le Bayon #endif 99*d596023bSNicolas Le Bayon } 10006e55dc8SNicolas Le Bayon 101*d596023bSNicolas Le Bayon int stm32mp_ddr_disable_axi_port(struct stm32mp_ddrctl *ctl) 102*d596023bSNicolas Le Bayon { 103*d596023bSNicolas Le Bayon uint64_t timeout; 104*d596023bSNicolas Le Bayon uint32_t pstat; 105*d596023bSNicolas Le Bayon 106*d596023bSNicolas Le Bayon /* Disable uMCTL2 AXI port 0 */ 107*d596023bSNicolas Le Bayon mmio_clrbits_32((uintptr_t)&ctl->pctrl_0, DDRCTRL_PCTRL_N_PORT_EN); 108*d596023bSNicolas Le Bayon VERBOSE("[0x%lx] pctrl_0 = 0x%x\n", (uintptr_t)&ctl->pctrl_0, 109*d596023bSNicolas Le Bayon mmio_read_32((uintptr_t)&ctl->pctrl_0)); 110*d596023bSNicolas Le Bayon 111*d596023bSNicolas Le Bayon #if STM32MP_DDR_DUAL_AXI_PORT 112*d596023bSNicolas Le Bayon /* Disable uMCTL2 AXI port 1 */ 113*d596023bSNicolas Le Bayon mmio_clrbits_32((uintptr_t)&ctl->pctrl_1, DDRCTRL_PCTRL_N_PORT_EN); 114*d596023bSNicolas Le Bayon VERBOSE("[0x%lx] pctrl_1 = 0x%x\n", (uintptr_t)&ctl->pctrl_1, 115*d596023bSNicolas Le Bayon mmio_read_32((uintptr_t)&ctl->pctrl_1)); 116*d596023bSNicolas Le Bayon #endif 117*d596023bSNicolas Le Bayon 118*d596023bSNicolas Le Bayon /* 119*d596023bSNicolas Le Bayon * Waits until all AXI ports are idle 120*d596023bSNicolas Le Bayon * Poll PSTAT.rd_port_busy_n = 0 121*d596023bSNicolas Le Bayon * Poll PSTAT.wr_port_busy_n = 0 122*d596023bSNicolas Le Bayon */ 123*d596023bSNicolas Le Bayon timeout = timeout_init_us(DDR_TIMEOUT_US_1S); 124*d596023bSNicolas Le Bayon do { 125*d596023bSNicolas Le Bayon pstat = mmio_read_32((uintptr_t)&ctl->pstat); 126*d596023bSNicolas Le Bayon VERBOSE("[0x%lx] pstat = 0x%x ", 127*d596023bSNicolas Le Bayon (uintptr_t)&ctl->pstat, pstat); 128*d596023bSNicolas Le Bayon if (timeout_elapsed(timeout)) { 129*d596023bSNicolas Le Bayon return -1; 130*d596023bSNicolas Le Bayon } 131*d596023bSNicolas Le Bayon } while (pstat != 0U); 132*d596023bSNicolas Le Bayon 133*d596023bSNicolas Le Bayon return 0; 134*d596023bSNicolas Le Bayon } 135*d596023bSNicolas Le Bayon 136*d596023bSNicolas Le Bayon static bool ddr_is_axi_port_enabled(struct stm32mp_ddrctl *ctl) 137*d596023bSNicolas Le Bayon { 138*d596023bSNicolas Le Bayon return (mmio_read_32((uintptr_t)&ctl->pctrl_0) & DDRCTRL_PCTRL_N_PORT_EN) != 0U; 139*d596023bSNicolas Le Bayon } 140*d596023bSNicolas Le Bayon 141*d596023bSNicolas Le Bayon void stm32mp_ddr_enable_host_interface(struct stm32mp_ddrctl *ctl) 142*d596023bSNicolas Le Bayon { 143*d596023bSNicolas Le Bayon mmio_clrbits_32((uintptr_t)&ctl->dbg1, DDRCTRL_DBG1_DIS_HIF); 144*d596023bSNicolas Le Bayon VERBOSE("[0x%lx] dbg1 = 0x%x\n", 145*d596023bSNicolas Le Bayon (uintptr_t)&ctl->dbg1, 146*d596023bSNicolas Le Bayon mmio_read_32((uintptr_t)&ctl->dbg1)); 147*d596023bSNicolas Le Bayon } 148*d596023bSNicolas Le Bayon 149*d596023bSNicolas Le Bayon void stm32mp_ddr_disable_host_interface(struct stm32mp_ddrctl *ctl) 150*d596023bSNicolas Le Bayon { 151*d596023bSNicolas Le Bayon uint64_t timeout; 152*d596023bSNicolas Le Bayon uint32_t dbgcam; 153*d596023bSNicolas Le Bayon int count = 0; 154*d596023bSNicolas Le Bayon 155*d596023bSNicolas Le Bayon mmio_setbits_32((uintptr_t)&ctl->dbg1, DDRCTRL_DBG1_DIS_HIF); 156*d596023bSNicolas Le Bayon VERBOSE("[0x%lx] dbg1 = 0x%x\n", 157*d596023bSNicolas Le Bayon (uintptr_t)&ctl->dbg1, 158*d596023bSNicolas Le Bayon mmio_read_32((uintptr_t)&ctl->dbg1)); 159*d596023bSNicolas Le Bayon 160*d596023bSNicolas Le Bayon /* 161*d596023bSNicolas Le Bayon * Waits until all queues and pipelines are empty 162*d596023bSNicolas Le Bayon * Poll DBGCAM.dbg_wr_q_empty = 1 163*d596023bSNicolas Le Bayon * Poll DBGCAM.dbg_rd_q_empty = 1 164*d596023bSNicolas Le Bayon * Poll DBGCAM.dbg_wr_data_pipeline_empty = 1 165*d596023bSNicolas Le Bayon * Poll DBGCAM.dbg_rd_data_pipeline_empty = 1 166*d596023bSNicolas Le Bayon * 167*d596023bSNicolas Le Bayon * data_pipeline fields must be polled twice to ensure 168*d596023bSNicolas Le Bayon * value propoagation, so count is added to loop condition. 169*d596023bSNicolas Le Bayon */ 170*d596023bSNicolas Le Bayon timeout = timeout_init_us(DDR_TIMEOUT_US_1S); 171*d596023bSNicolas Le Bayon do { 172*d596023bSNicolas Le Bayon dbgcam = mmio_read_32((uintptr_t)&ctl->dbgcam); 173*d596023bSNicolas Le Bayon VERBOSE("[0x%lx] dbgcam = 0x%x ", 174*d596023bSNicolas Le Bayon (uintptr_t)&ctl->dbgcam, dbgcam); 175*d596023bSNicolas Le Bayon if (timeout_elapsed(timeout)) { 176*d596023bSNicolas Le Bayon panic(); 177*d596023bSNicolas Le Bayon } 178*d596023bSNicolas Le Bayon count++; 179*d596023bSNicolas Le Bayon } while (((dbgcam & DDRCTRL_DBG_Q_AND_DATA_PIPELINE_EMPTY) != 180*d596023bSNicolas Le Bayon DDRCTRL_DBG_Q_AND_DATA_PIPELINE_EMPTY) || (count < 2)); 181*d596023bSNicolas Le Bayon } 182*d596023bSNicolas Le Bayon 183*d596023bSNicolas Le Bayon static bool ddr_is_host_interface_enabled(struct stm32mp_ddrctl *ctl) 184*d596023bSNicolas Le Bayon { 185*d596023bSNicolas Le Bayon return (mmio_read_32((uintptr_t)&ctl->dbg1) & DDRCTRL_DBG1_DIS_HIF) == 0U; 186*d596023bSNicolas Le Bayon } 187*d596023bSNicolas Le Bayon 188*d596023bSNicolas Le Bayon int stm32mp_ddr_sw_selfref_entry(struct stm32mp_ddrctl *ctl) 189*d596023bSNicolas Le Bayon { 190*d596023bSNicolas Le Bayon uint64_t timeout; 191*d596023bSNicolas Le Bayon uint32_t stat; 192*d596023bSNicolas Le Bayon uint32_t operating_mode; 193*d596023bSNicolas Le Bayon uint32_t selref_type; 194*d596023bSNicolas Le Bayon 195*d596023bSNicolas Le Bayon mmio_setbits_32((uintptr_t)&ctl->pwrctl, DDRCTRL_PWRCTL_SELFREF_SW); 196*d596023bSNicolas Le Bayon VERBOSE("[0x%lx] pwrctl = 0x%x\n", 197*d596023bSNicolas Le Bayon (uintptr_t)&ctl->pwrctl, 198*d596023bSNicolas Le Bayon mmio_read_32((uintptr_t)&ctl->pwrctl)); 199*d596023bSNicolas Le Bayon 200*d596023bSNicolas Le Bayon /* 201*d596023bSNicolas Le Bayon * Wait operating mode change in self-refresh mode 202*d596023bSNicolas Le Bayon * with STAT.operating_mode[1:0]==11. 203*d596023bSNicolas Le Bayon * Ensure transition to self-refresh was due to software 204*d596023bSNicolas Le Bayon * by checking also that STAT.selfref_type[1:0]=2. 205*d596023bSNicolas Le Bayon */ 206*d596023bSNicolas Le Bayon timeout = timeout_init_us(DDR_TIMEOUT_500US); 207*d596023bSNicolas Le Bayon while (!timeout_elapsed(timeout)) { 208*d596023bSNicolas Le Bayon stat = mmio_read_32((uintptr_t)&ctl->stat); 209*d596023bSNicolas Le Bayon operating_mode = stat & DDRCTRL_STAT_OPERATING_MODE_MASK; 210*d596023bSNicolas Le Bayon selref_type = stat & DDRCTRL_STAT_SELFREF_TYPE_MASK; 211*d596023bSNicolas Le Bayon 212*d596023bSNicolas Le Bayon if ((operating_mode == DDRCTRL_STAT_OPERATING_MODE_SR) && 213*d596023bSNicolas Le Bayon (selref_type == DDRCTRL_STAT_SELFREF_TYPE_SR)) { 214*d596023bSNicolas Le Bayon return 0; 215*d596023bSNicolas Le Bayon } 216*d596023bSNicolas Le Bayon } 217*d596023bSNicolas Le Bayon 218*d596023bSNicolas Le Bayon return -1; 219*d596023bSNicolas Le Bayon } 220*d596023bSNicolas Le Bayon 221*d596023bSNicolas Le Bayon void stm32mp_ddr_sw_selfref_exit(struct stm32mp_ddrctl *ctl) 222*d596023bSNicolas Le Bayon { 223*d596023bSNicolas Le Bayon mmio_clrbits_32((uintptr_t)&ctl->pwrctl, DDRCTRL_PWRCTL_SELFREF_SW); 224*d596023bSNicolas Le Bayon VERBOSE("[0x%lx] pwrctl = 0x%x\n", 225*d596023bSNicolas Le Bayon (uintptr_t)&ctl->pwrctl, 226*d596023bSNicolas Le Bayon mmio_read_32((uintptr_t)&ctl->pwrctl)); 227*d596023bSNicolas Le Bayon } 228*d596023bSNicolas Le Bayon 229*d596023bSNicolas Le Bayon void stm32mp_ddr_set_qd3_update_conditions(struct stm32mp_ddrctl *ctl) 230*d596023bSNicolas Le Bayon { 231*d596023bSNicolas Le Bayon if (ddr_is_axi_port_enabled(ctl)) { 232*d596023bSNicolas Le Bayon if (stm32mp_ddr_disable_axi_port(ctl) != 0) { 233*d596023bSNicolas Le Bayon panic(); 234*d596023bSNicolas Le Bayon } 235*d596023bSNicolas Le Bayon axi_port_reenable_request = true; 236*d596023bSNicolas Le Bayon } 237*d596023bSNicolas Le Bayon 238*d596023bSNicolas Le Bayon if (ddr_is_host_interface_enabled(ctl)) { 239*d596023bSNicolas Le Bayon stm32mp_ddr_disable_host_interface(ctl); 240*d596023bSNicolas Le Bayon host_interface_reenable_request = true; 241*d596023bSNicolas Le Bayon } 242*d596023bSNicolas Le Bayon 243*d596023bSNicolas Le Bayon stm32mp_ddr_start_sw_done(ctl); 244*d596023bSNicolas Le Bayon } 245*d596023bSNicolas Le Bayon 246*d596023bSNicolas Le Bayon void stm32mp_ddr_unset_qd3_update_conditions(struct stm32mp_ddrctl *ctl) 247*d596023bSNicolas Le Bayon { 248*d596023bSNicolas Le Bayon stm32mp_ddr_wait_sw_done_ack(ctl); 249*d596023bSNicolas Le Bayon 250*d596023bSNicolas Le Bayon if (host_interface_reenable_request) { 251*d596023bSNicolas Le Bayon stm32mp_ddr_enable_host_interface(ctl); 252*d596023bSNicolas Le Bayon host_interface_reenable_request = false; 253*d596023bSNicolas Le Bayon } 254*d596023bSNicolas Le Bayon 255*d596023bSNicolas Le Bayon if (axi_port_reenable_request) { 256*d596023bSNicolas Le Bayon stm32mp_ddr_enable_axi_port(ctl); 257*d596023bSNicolas Le Bayon axi_port_reenable_request = false; 258*d596023bSNicolas Le Bayon } 259*d596023bSNicolas Le Bayon } 260*d596023bSNicolas Le Bayon 261*d596023bSNicolas Le Bayon void stm32mp_ddr_wait_refresh_update_done_ack(struct stm32mp_ddrctl *ctl) 262*d596023bSNicolas Le Bayon { 263*d596023bSNicolas Le Bayon uint64_t timeout; 264*d596023bSNicolas Le Bayon uint32_t rfshctl3; 265*d596023bSNicolas Le Bayon uint32_t refresh_update_level = DDRCTRL_RFSHCTL3_REFRESH_UPDATE_LEVEL; 266*d596023bSNicolas Le Bayon 267*d596023bSNicolas Le Bayon /* Toggle rfshctl3.refresh_update_level */ 268*d596023bSNicolas Le Bayon rfshctl3 = mmio_read_32((uintptr_t)&ctl->rfshctl3); 269*d596023bSNicolas Le Bayon if ((rfshctl3 & refresh_update_level) == refresh_update_level) { 270*d596023bSNicolas Le Bayon mmio_setbits_32((uintptr_t)&ctl->rfshctl3, refresh_update_level); 271*d596023bSNicolas Le Bayon } else { 272*d596023bSNicolas Le Bayon mmio_clrbits_32((uintptr_t)&ctl->rfshctl3, refresh_update_level); 273*d596023bSNicolas Le Bayon refresh_update_level = 0U; 274*d596023bSNicolas Le Bayon } 275*d596023bSNicolas Le Bayon 276*d596023bSNicolas Le Bayon VERBOSE("[0x%lx] rfshctl3 = 0x%x\n", 277*d596023bSNicolas Le Bayon (uintptr_t)&ctl->rfshctl3, mmio_read_32((uintptr_t)&ctl->rfshctl3)); 278*d596023bSNicolas Le Bayon 279*d596023bSNicolas Le Bayon timeout = timeout_init_us(DDR_TIMEOUT_US_1S); 280*d596023bSNicolas Le Bayon do { 281*d596023bSNicolas Le Bayon rfshctl3 = mmio_read_32((uintptr_t)&ctl->rfshctl3); 282*d596023bSNicolas Le Bayon VERBOSE("[0x%lx] rfshctl3 = 0x%x ", (uintptr_t)&ctl->rfshctl3, rfshctl3); 283*d596023bSNicolas Le Bayon if (timeout_elapsed(timeout)) { 284*d596023bSNicolas Le Bayon panic(); 285*d596023bSNicolas Le Bayon } 286*d596023bSNicolas Le Bayon } while ((rfshctl3 & DDRCTRL_RFSHCTL3_REFRESH_UPDATE_LEVEL) != refresh_update_level); 287*d596023bSNicolas Le Bayon 288*d596023bSNicolas Le Bayon VERBOSE("[0x%lx] rfshctl3 = 0x%x\n", (uintptr_t)&ctl->rfshctl3, rfshctl3); 28906e55dc8SNicolas Le Bayon } 290