xref: /rk3399_ARM-atf/drivers/st/ddr/stm32mp_ddr.c (revision 1483b3c3d2e4b56695da8b6301731b7dea83b40e)
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