/* * Copyright (C) 2023-2024, STMicroelectronics - All Rights Reserved * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #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); }