xref: /rk3399_ARM-atf/drivers/st/ddr/stm32mp_ddr.c (revision 066a5958e72860b9945e1416174c22ff0d83b5e5)
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) {
4006e55dc8SNicolas Le Bayon 			ERROR("invalid parameter offset for %s", desc[i].name);
4106e55dc8SNicolas Le Bayon 			panic();
4206e55dc8SNicolas Le Bayon 		} else {
4306e55dc8SNicolas Le Bayon 			value = *((uint32_t *)((uintptr_t)param +
4406e55dc8SNicolas Le Bayon 					       desc[i].par_offset));
4506e55dc8SNicolas Le Bayon 			mmio_write_32(ptr, value);
4606e55dc8SNicolas Le Bayon 		}
4706e55dc8SNicolas Le Bayon 	}
4806e55dc8SNicolas Le Bayon }
4906e55dc8SNicolas Le Bayon 
5006e55dc8SNicolas Le Bayon /* Start quasi dynamic register update */
5106e55dc8SNicolas Le Bayon void stm32mp_ddr_start_sw_done(struct stm32mp_ddrctl *ctl)
5206e55dc8SNicolas Le Bayon {
5306e55dc8SNicolas Le Bayon 	mmio_clrbits_32((uintptr_t)&ctl->swctl, DDRCTRL_SWCTL_SW_DONE);
5406e55dc8SNicolas Le Bayon 	VERBOSE("[0x%lx] swctl = 0x%x\n",
5506e55dc8SNicolas Le Bayon 		(uintptr_t)&ctl->swctl,  mmio_read_32((uintptr_t)&ctl->swctl));
5606e55dc8SNicolas Le Bayon }
5706e55dc8SNicolas Le Bayon 
5806e55dc8SNicolas Le Bayon /* Wait quasi dynamic register update */
5906e55dc8SNicolas Le Bayon void stm32mp_ddr_wait_sw_done_ack(struct stm32mp_ddrctl *ctl)
6006e55dc8SNicolas Le Bayon {
6106e55dc8SNicolas Le Bayon 	uint64_t timeout;
6206e55dc8SNicolas Le Bayon 	uint32_t swstat;
6306e55dc8SNicolas Le Bayon 
6406e55dc8SNicolas Le Bayon 	mmio_setbits_32((uintptr_t)&ctl->swctl, DDRCTRL_SWCTL_SW_DONE);
6506e55dc8SNicolas Le Bayon 	VERBOSE("[0x%lx] swctl = 0x%x\n",
6606e55dc8SNicolas Le Bayon 		(uintptr_t)&ctl->swctl, mmio_read_32((uintptr_t)&ctl->swctl));
6706e55dc8SNicolas Le Bayon 
68*066a5958SYann Gautier 	timeout = timeout_init_us(DDR_TIMEOUT_US_1S);
6906e55dc8SNicolas Le Bayon 	do {
7006e55dc8SNicolas Le Bayon 		swstat = mmio_read_32((uintptr_t)&ctl->swstat);
7106e55dc8SNicolas Le Bayon 		VERBOSE("[0x%lx] swstat = 0x%x ",
7206e55dc8SNicolas Le Bayon 			(uintptr_t)&ctl->swstat, swstat);
7306e55dc8SNicolas Le Bayon 		if (timeout_elapsed(timeout)) {
7406e55dc8SNicolas Le Bayon 			panic();
7506e55dc8SNicolas Le Bayon 		}
7606e55dc8SNicolas Le Bayon 	} while ((swstat & DDRCTRL_SWSTAT_SW_DONE_ACK) == 0U);
7706e55dc8SNicolas Le Bayon 
7806e55dc8SNicolas Le Bayon 	VERBOSE("[0x%lx] swstat = 0x%x\n",
7906e55dc8SNicolas Le Bayon 		(uintptr_t)&ctl->swstat, swstat);
8006e55dc8SNicolas Le Bayon }
8106e55dc8SNicolas Le Bayon 
8206e55dc8SNicolas Le Bayon void stm32mp_ddr_enable_axi_port(struct stm32mp_ddrctl *ctl)
8306e55dc8SNicolas Le Bayon {
8406e55dc8SNicolas Le Bayon 	/* Enable uMCTL2 AXI port 0 */
8506e55dc8SNicolas Le Bayon 	mmio_setbits_32((uintptr_t)&ctl->pctrl_0, DDRCTRL_PCTRL_N_PORT_EN);
8606e55dc8SNicolas Le Bayon 	VERBOSE("[0x%lx] pctrl_0 = 0x%x\n", (uintptr_t)&ctl->pctrl_0,
8706e55dc8SNicolas Le Bayon 		mmio_read_32((uintptr_t)&ctl->pctrl_0));
8806e55dc8SNicolas Le Bayon 
8906e55dc8SNicolas Le Bayon #if STM32MP_DDR_DUAL_AXI_PORT
9006e55dc8SNicolas Le Bayon 	/* Enable uMCTL2 AXI port 1 */
9106e55dc8SNicolas Le Bayon 	mmio_setbits_32((uintptr_t)&ctl->pctrl_1, DDRCTRL_PCTRL_N_PORT_EN);
9206e55dc8SNicolas Le Bayon 	VERBOSE("[0x%lx] pctrl_1 = 0x%x\n", (uintptr_t)&ctl->pctrl_1,
9306e55dc8SNicolas Le Bayon 		mmio_read_32((uintptr_t)&ctl->pctrl_1));
9406e55dc8SNicolas Le Bayon #endif
9506e55dc8SNicolas Le Bayon 
9606e55dc8SNicolas Le Bayon }
97