106e55dc8SNicolas Le Bayon /*
26851fd9eSNicolas Le Bayon * Copyright (C) 2022-2025, 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
get_base_addr(const struct stm32mp_ddr_priv * priv,enum stm32mp_ddr_base_type base)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
stm32mp_ddr_set_reg(const struct stm32mp_ddr_priv * priv,enum stm32mp_ddr_reg_type type,const void * param,const struct stm32mp_ddr_reg_info * ddr_registers)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 */
stm32mp_ddr_start_sw_done(struct stm32mp_ddrctl * ctl)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 */
stm32mp_ddr_wait_sw_done_ack(struct stm32mp_ddrctl * ctl)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
stm32mp_ddr_enable_axi_port(struct stm32mp_ddrctl * ctl)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
stm32mp_ddr_disable_axi_port(struct stm32mp_ddrctl * ctl)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
ddr_is_axi_port_enabled(struct stm32mp_ddrctl * ctl)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
stm32mp_ddr_enable_host_interface(struct stm32mp_ddrctl * ctl)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
stm32mp_ddr_disable_host_interface(struct stm32mp_ddrctl * ctl)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
ddr_is_host_interface_enabled(struct stm32mp_ddrctl * ctl)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
stm32mp_ddr_sw_selfref_entry(struct stm32mp_ddrctl * ctl)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
stm32mp_ddr_sw_selfref_exit(struct stm32mp_ddrctl * ctl)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
stm32mp_ddr_set_qd3_update_conditions(struct stm32mp_ddrctl * ctl)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
stm32mp_ddr_unset_qd3_update_conditions(struct stm32mp_ddrctl * ctl)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
stm32mp_ddr_wait_refresh_update_done_ack(struct stm32mp_ddrctl * ctl)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_clrbits_32((uintptr_t)&ctl->rfshctl3, refresh_update_level);
2816851fd9eSNicolas Le Bayon } else {
2826851fd9eSNicolas Le Bayon mmio_setbits_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 }
2966851fd9eSNicolas 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