blob: 5302e45b691c1b83b1b70334599f20174d07ff3a [file] [log] [blame] [edit]
/*
* Copyright (C) 2023-2024, STMicroelectronics - All Rights Reserved
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <assert.h>
#include <errno.h>
#include <stdint.h>
#include <common/fdt_wrappers.h>
#include <drivers/delay_timer.h>
#include <drivers/st/regulator.h>
#include <drivers/st/stm32mp_ddr.h>
#include <libfdt.h>
#include <platform_def.h>
#if STM32MP_DDR3_TYPE
struct ddr3_supply {
struct rdev *vdd;
struct rdev *vref;
struct rdev *vtt;
};
static void ddr3_supply_read(void *fdt, int node, struct ddr3_supply *supply)
{
supply->vdd = regulator_get_by_supply_name(fdt, node, "vdd");
supply->vref = regulator_get_by_supply_name(fdt, node, "vref");
supply->vtt = regulator_get_by_supply_name(fdt, node, "vtt");
}
static int ddr_power_init(void *fdt, int node)
{
int status;
struct ddr3_supply supply;
ddr3_supply_read(fdt, node, &supply);
if ((supply.vdd == NULL) || (supply.vref == NULL) || (supply.vtt == NULL)) {
return -ENOENT;
}
/*
* DDR3 power on sequence is:
* enable VREF_DDR, VTT_DDR, VPP_DDR
*/
status = regulator_set_min_voltage(supply.vdd);
if (status != 0) {
return status;
}
status = regulator_enable(supply.vdd);
if (status != 0) {
return status;
}
status = regulator_enable(supply.vref);
if (status != 0) {
return status;
}
return regulator_enable(supply.vtt);
}
#endif /* STM32MP_DDR3_TYPE */
#if STM32MP_DDR4_TYPE
struct ddr4_supply {
struct rdev *vdd;
struct rdev *vref;
struct rdev *vtt;
struct rdev *vpp;
};
static void ddr4_supply_read(void *fdt, int node, struct ddr4_supply *supply)
{
supply->vpp = regulator_get_by_supply_name(fdt, node, "vpp");
supply->vdd = regulator_get_by_supply_name(fdt, node, "vdd");
supply->vref = regulator_get_by_supply_name(fdt, node, "vref");
supply->vtt = regulator_get_by_supply_name(fdt, node, "vtt");
}
static int ddr_power_init(void *fdt, int node)
{
int status;
struct ddr4_supply supply;
ddr4_supply_read(fdt, node, &supply);
if ((supply.vpp == NULL) || (supply.vdd == NULL) || (supply.vref == NULL) ||
(supply.vtt == NULL)) {
return -ENOENT;
}
/*
* DDR4 power on sequence is:
* enable VPP_DDR
* enable VREF_DDR, VTT_DDR, VPP_DDR
*/
status = regulator_set_min_voltage(supply.vpp);
if (status != 0) {
return status;
}
status = regulator_set_min_voltage(supply.vdd);
if (status != 0) {
return status;
}
status = regulator_enable(supply.vpp);
if (status != 0) {
return status;
}
status = regulator_enable(supply.vdd);
if (status != 0) {
return status;
}
status = regulator_enable(supply.vref);
if (status != 0) {
return status;
}
return regulator_enable(supply.vtt);
}
#endif /* STM32MP_DDR4_TYPE */
#if STM32MP_LPDDR4_TYPE
struct lpddr4_supply {
struct rdev *vdd1;
struct rdev *vdd2;
struct rdev *vddq;
};
static void lpddr4_supply_read(void *fdt, int node, struct lpddr4_supply *supply)
{
supply->vdd1 = regulator_get_by_supply_name(fdt, node, "vdd1");
supply->vdd2 = regulator_get_by_supply_name(fdt, node, "vdd2");
supply->vddq = regulator_get_by_supply_name(fdt, node, "vddq");
}
static int ddr_power_init(void *fdt, int node)
{
int status;
struct lpddr4_supply supply;
lpddr4_supply_read(fdt, node, &supply);
if ((supply.vdd1 == NULL) || (supply.vdd2 == NULL) || (supply.vddq == NULL)) {
return -ENOENT;
}
/*
* LPDDR4 power on sequence is:
* enable VDD1_DDR
* enable VDD2_DDR
* enable VDDQ_DDR
*/
status = regulator_set_min_voltage(supply.vdd1);
if (status != 0) {
return status;
}
status = regulator_set_min_voltage(supply.vdd2);
if (status != 0) {
return status;
}
status = regulator_set_min_voltage(supply.vddq);
if (status != 0) {
return status;
}
status = regulator_enable(supply.vdd1);
if (status != 0) {
return status;
}
status = regulator_enable(supply.vdd2);
if (status != 0) {
return status;
}
return regulator_enable(supply.vddq);
}
#endif /* STM32MP_LPDDR4_TYPE */
int stm32mp_board_ddr_power_init(enum ddr_type ddr_type)
{
void *fdt = NULL;
int node;
VERBOSE("DDR power init, ddr_type = %u\n", ddr_type);
#if STM32MP_DDR3_TYPE
assert(ddr_type == STM32MP_DDR3);
#elif STM32MP_DDR4_TYPE
assert(ddr_type == STM32MP_DDR4);
#elif STM32MP_LPDDR4_TYPE
assert(ddr_type == STM32MP_LPDDR4);
#else
ERROR("DDR type (%u) not supported\n", ddr_type);
panic();
#endif
if (fdt_get_address(&fdt) == 0) {
return -FDT_ERR_NOTFOUND;
}
node = fdt_node_offset_by_compatible(fdt, -1, DT_DDR_COMPAT);
if (node < 0) {
ERROR("%s: Cannot read DDR node in DT\n", __func__);
return -EINVAL;
}
return ddr_power_init(fdt, node);
}