123684d0eSYann Gautier /* 242822844SBenjamin Gaignard * Copyright (c) 2017-2021, STMicroelectronics - All Rights Reserved 323684d0eSYann Gautier * 423684d0eSYann Gautier * SPDX-License-Identifier: BSD-3-Clause 523684d0eSYann Gautier */ 623684d0eSYann Gautier 723684d0eSYann Gautier #include <errno.h> 823684d0eSYann Gautier 923684d0eSYann Gautier #include <libfdt.h> 1023684d0eSYann Gautier 1123684d0eSYann Gautier #include <platform_def.h> 1223684d0eSYann Gautier 1323684d0eSYann Gautier #include <common/debug.h> 1423684d0eSYann Gautier #include <drivers/delay_timer.h> 15d82d4ff0SYann Gautier #include <drivers/st/stm32_i2c.h> 1623684d0eSYann Gautier #include <drivers/st/stm32mp_pmic.h> 1723684d0eSYann Gautier #include <drivers/st/stpmic1.h> 1823684d0eSYann Gautier #include <lib/mmio.h> 1923684d0eSYann Gautier #include <lib/utils_def.h> 2023684d0eSYann Gautier 2123684d0eSYann Gautier #define STPMIC1_LDO12356_OUTPUT_MASK (uint8_t)(GENMASK(6, 2)) 2223684d0eSYann Gautier #define STPMIC1_LDO12356_OUTPUT_SHIFT 2 2323684d0eSYann Gautier #define STPMIC1_LDO3_MODE (uint8_t)(BIT(7)) 2423684d0eSYann Gautier #define STPMIC1_LDO3_DDR_SEL 31U 2523684d0eSYann Gautier #define STPMIC1_LDO3_1800000 (9U << STPMIC1_LDO12356_OUTPUT_SHIFT) 2623684d0eSYann Gautier 2723684d0eSYann Gautier #define STPMIC1_BUCK_OUTPUT_SHIFT 2 2823684d0eSYann Gautier #define STPMIC1_BUCK3_1V8 (39U << STPMIC1_BUCK_OUTPUT_SHIFT) 2923684d0eSYann Gautier 3023684d0eSYann Gautier #define STPMIC1_DEFAULT_START_UP_DELAY_MS 1 3123684d0eSYann Gautier 3223684d0eSYann Gautier static struct i2c_handle_s i2c_handle; 3323684d0eSYann Gautier static uint32_t pmic_i2c_addr; 3423684d0eSYann Gautier 3523684d0eSYann Gautier static int dt_get_pmic_node(void *fdt) 3623684d0eSYann Gautier { 3723684d0eSYann Gautier return fdt_node_offset_by_compatible(fdt, -1, "st,stpmic1"); 3823684d0eSYann Gautier } 3923684d0eSYann Gautier 40d82d4ff0SYann Gautier int dt_pmic_status(void) 4123684d0eSYann Gautier { 4223684d0eSYann Gautier int node; 4323684d0eSYann Gautier void *fdt; 4423684d0eSYann Gautier 4523684d0eSYann Gautier if (fdt_get_address(&fdt) == 0) { 46d82d4ff0SYann Gautier return -ENOENT; 4723684d0eSYann Gautier } 4823684d0eSYann Gautier 4923684d0eSYann Gautier node = dt_get_pmic_node(fdt); 50d82d4ff0SYann Gautier if (node <= 0) { 51d82d4ff0SYann Gautier return -FDT_ERR_NOTFOUND; 5223684d0eSYann Gautier } 5323684d0eSYann Gautier 541fc2130cSYann Gautier return fdt_get_status(node); 5523684d0eSYann Gautier } 5623684d0eSYann Gautier 57f564d439SEtienne Carriere static bool dt_pmic_is_secure(void) 58f564d439SEtienne Carriere { 59f564d439SEtienne Carriere int status = dt_pmic_status(); 60f564d439SEtienne Carriere 61f564d439SEtienne Carriere return (status >= 0) && 62f564d439SEtienne Carriere (status == DT_SECURE) && 63f564d439SEtienne Carriere (i2c_handle.dt_status == DT_SECURE); 64f564d439SEtienne Carriere } 65f564d439SEtienne Carriere 66d82d4ff0SYann Gautier /* 67d82d4ff0SYann Gautier * Get PMIC and its I2C bus configuration from the device tree. 68d82d4ff0SYann Gautier * Return 0 on success, negative on error, 1 if no PMIC node is found. 69d82d4ff0SYann Gautier */ 70d82d4ff0SYann Gautier static int dt_pmic_i2c_config(struct dt_node_info *i2c_info, 71d82d4ff0SYann Gautier struct stm32_i2c_init_s *init) 7223684d0eSYann Gautier { 7323684d0eSYann Gautier int pmic_node, i2c_node; 7423684d0eSYann Gautier void *fdt; 7523684d0eSYann Gautier const fdt32_t *cuint; 7623684d0eSYann Gautier 7723684d0eSYann Gautier if (fdt_get_address(&fdt) == 0) { 7823684d0eSYann Gautier return -ENOENT; 7923684d0eSYann Gautier } 8023684d0eSYann Gautier 8123684d0eSYann Gautier pmic_node = dt_get_pmic_node(fdt); 8223684d0eSYann Gautier if (pmic_node < 0) { 83d82d4ff0SYann Gautier return 1; 8423684d0eSYann Gautier } 8523684d0eSYann Gautier 8623684d0eSYann Gautier cuint = fdt_getprop(fdt, pmic_node, "reg", NULL); 8723684d0eSYann Gautier if (cuint == NULL) { 8823684d0eSYann Gautier return -FDT_ERR_NOTFOUND; 8923684d0eSYann Gautier } 9023684d0eSYann Gautier 9123684d0eSYann Gautier pmic_i2c_addr = fdt32_to_cpu(*cuint) << 1; 9223684d0eSYann Gautier if (pmic_i2c_addr > UINT16_MAX) { 9323684d0eSYann Gautier return -EINVAL; 9423684d0eSYann Gautier } 9523684d0eSYann Gautier 9623684d0eSYann Gautier i2c_node = fdt_parent_offset(fdt, pmic_node); 9723684d0eSYann Gautier if (i2c_node < 0) { 9823684d0eSYann Gautier return -FDT_ERR_NOTFOUND; 9923684d0eSYann Gautier } 10023684d0eSYann Gautier 10123684d0eSYann Gautier dt_fill_device_info(i2c_info, i2c_node); 10223684d0eSYann Gautier if (i2c_info->base == 0U) { 10323684d0eSYann Gautier return -FDT_ERR_NOTFOUND; 10423684d0eSYann Gautier } 10523684d0eSYann Gautier 106d82d4ff0SYann Gautier return stm32_i2c_get_setup_from_fdt(fdt, i2c_node, init); 10723684d0eSYann Gautier } 10823684d0eSYann Gautier 109d82d4ff0SYann Gautier int dt_pmic_configure_boot_on_regulators(void) 11023684d0eSYann Gautier { 11123684d0eSYann Gautier int pmic_node, regulators_node, regulator_node; 11223684d0eSYann Gautier void *fdt; 11323684d0eSYann Gautier 11423684d0eSYann Gautier if (fdt_get_address(&fdt) == 0) { 11523684d0eSYann Gautier return -ENOENT; 11623684d0eSYann Gautier } 11723684d0eSYann Gautier 11823684d0eSYann Gautier pmic_node = dt_get_pmic_node(fdt); 11923684d0eSYann Gautier if (pmic_node < 0) { 12023684d0eSYann Gautier return -FDT_ERR_NOTFOUND; 12123684d0eSYann Gautier } 12223684d0eSYann Gautier 12323684d0eSYann Gautier regulators_node = fdt_subnode_offset(fdt, pmic_node, "regulators"); 124*a4bcfe94SNicolas Le Bayon if (regulators_node < 0) { 125*a4bcfe94SNicolas Le Bayon return -ENOENT; 126*a4bcfe94SNicolas Le Bayon } 12723684d0eSYann Gautier 12823684d0eSYann Gautier fdt_for_each_subnode(regulator_node, fdt, regulators_node) { 12923684d0eSYann Gautier const fdt32_t *cuint; 130d82d4ff0SYann Gautier const char *node_name = fdt_get_name(fdt, regulator_node, NULL); 13123684d0eSYann Gautier uint16_t voltage; 132d82d4ff0SYann Gautier int status; 13323684d0eSYann Gautier 134d82d4ff0SYann Gautier #if defined(IMAGE_BL2) 135d82d4ff0SYann Gautier if ((fdt_getprop(fdt, regulator_node, "regulator-boot-on", 136d82d4ff0SYann Gautier NULL) == NULL) && 137d82d4ff0SYann Gautier (fdt_getprop(fdt, regulator_node, "regulator-always-on", 138d82d4ff0SYann Gautier NULL) == NULL)) { 139d82d4ff0SYann Gautier #else 14023684d0eSYann Gautier if (fdt_getprop(fdt, regulator_node, "regulator-boot-on", 14123684d0eSYann Gautier NULL) == NULL) { 142d82d4ff0SYann Gautier #endif 14323684d0eSYann Gautier continue; 14423684d0eSYann Gautier } 14523684d0eSYann Gautier 146d82d4ff0SYann Gautier if (fdt_getprop(fdt, regulator_node, "regulator-pull-down", 147d82d4ff0SYann Gautier NULL) != NULL) { 148d82d4ff0SYann Gautier 149d82d4ff0SYann Gautier status = stpmic1_regulator_pull_down_set(node_name); 150d82d4ff0SYann Gautier if (status != 0) { 151d82d4ff0SYann Gautier return status; 152d82d4ff0SYann Gautier } 153d82d4ff0SYann Gautier } 154d82d4ff0SYann Gautier 155d82d4ff0SYann Gautier if (fdt_getprop(fdt, regulator_node, "st,mask-reset", 156d82d4ff0SYann Gautier NULL) != NULL) { 157d82d4ff0SYann Gautier 158d82d4ff0SYann Gautier status = stpmic1_regulator_mask_reset_set(node_name); 159d82d4ff0SYann Gautier if (status != 0) { 160d82d4ff0SYann Gautier return status; 161d82d4ff0SYann Gautier } 162d82d4ff0SYann Gautier } 163d82d4ff0SYann Gautier 16423684d0eSYann Gautier cuint = fdt_getprop(fdt, regulator_node, 16523684d0eSYann Gautier "regulator-min-microvolt", NULL); 16623684d0eSYann Gautier if (cuint == NULL) { 16723684d0eSYann Gautier continue; 16823684d0eSYann Gautier } 16923684d0eSYann Gautier 17023684d0eSYann Gautier /* DT uses microvolts, whereas driver awaits millivolts */ 17123684d0eSYann Gautier voltage = (uint16_t)(fdt32_to_cpu(*cuint) / 1000U); 17223684d0eSYann Gautier 173d82d4ff0SYann Gautier status = stpmic1_regulator_voltage_set(node_name, voltage); 17423684d0eSYann Gautier if (status != 0) { 17523684d0eSYann Gautier return status; 17623684d0eSYann Gautier } 17723684d0eSYann Gautier 178d82d4ff0SYann Gautier if (stpmic1_is_regulator_enabled(node_name) == 0U) { 17923684d0eSYann Gautier status = stpmic1_regulator_enable(node_name); 18023684d0eSYann Gautier if (status != 0) { 18123684d0eSYann Gautier return status; 18223684d0eSYann Gautier } 18323684d0eSYann Gautier } 18423684d0eSYann Gautier } 18523684d0eSYann Gautier 18623684d0eSYann Gautier return 0; 18723684d0eSYann Gautier } 18823684d0eSYann Gautier 189d82d4ff0SYann Gautier bool initialize_pmic_i2c(void) 19023684d0eSYann Gautier { 19123684d0eSYann Gautier int ret; 19223684d0eSYann Gautier struct dt_node_info i2c_info; 193d82d4ff0SYann Gautier struct i2c_handle_s *i2c = &i2c_handle; 194d82d4ff0SYann Gautier struct stm32_i2c_init_s i2c_init; 19523684d0eSYann Gautier 196d82d4ff0SYann Gautier ret = dt_pmic_i2c_config(&i2c_info, &i2c_init); 197d82d4ff0SYann Gautier if (ret < 0) { 198d82d4ff0SYann Gautier ERROR("I2C configuration failed %d\n", ret); 19923684d0eSYann Gautier panic(); 20023684d0eSYann Gautier } 20123684d0eSYann Gautier 202d82d4ff0SYann Gautier if (ret != 0) { 203d82d4ff0SYann Gautier return false; 20423684d0eSYann Gautier } 20523684d0eSYann Gautier 20623684d0eSYann Gautier /* Initialize PMIC I2C */ 207d82d4ff0SYann Gautier i2c->i2c_base_addr = i2c_info.base; 208d82d4ff0SYann Gautier i2c->dt_status = i2c_info.status; 209d82d4ff0SYann Gautier i2c->clock = i2c_info.clock; 21042822844SBenjamin Gaignard i2c->i2c_state = I2C_STATE_RESET; 211d82d4ff0SYann Gautier i2c_init.own_address1 = pmic_i2c_addr; 212d82d4ff0SYann Gautier i2c_init.addressing_mode = I2C_ADDRESSINGMODE_7BIT; 213d82d4ff0SYann Gautier i2c_init.dual_address_mode = I2C_DUALADDRESS_DISABLE; 214d82d4ff0SYann Gautier i2c_init.own_address2 = 0; 215d82d4ff0SYann Gautier i2c_init.own_address2_masks = I2C_OAR2_OA2NOMASK; 216d82d4ff0SYann Gautier i2c_init.general_call_mode = I2C_GENERALCALL_DISABLE; 217d82d4ff0SYann Gautier i2c_init.no_stretch_mode = I2C_NOSTRETCH_DISABLE; 218d82d4ff0SYann Gautier i2c_init.analog_filter = 1; 219d82d4ff0SYann Gautier i2c_init.digital_filter_coef = 0; 22023684d0eSYann Gautier 221d82d4ff0SYann Gautier ret = stm32_i2c_init(i2c, &i2c_init); 22223684d0eSYann Gautier if (ret != 0) { 22323684d0eSYann Gautier ERROR("Cannot initialize I2C %x (%d)\n", 224d82d4ff0SYann Gautier i2c->i2c_base_addr, ret); 22523684d0eSYann Gautier panic(); 22623684d0eSYann Gautier } 22723684d0eSYann Gautier 228d82d4ff0SYann Gautier if (!stm32_i2c_is_device_ready(i2c, pmic_i2c_addr, 1, 229d82d4ff0SYann Gautier I2C_TIMEOUT_BUSY_MS)) { 230d82d4ff0SYann Gautier ERROR("I2C device not ready\n"); 23123684d0eSYann Gautier panic(); 23223684d0eSYann Gautier } 23323684d0eSYann Gautier 234d82d4ff0SYann Gautier stpmic1_bind_i2c(i2c, (uint16_t)pmic_i2c_addr); 23523684d0eSYann Gautier 236d82d4ff0SYann Gautier return true; 23723684d0eSYann Gautier } 23823684d0eSYann Gautier 239f564d439SEtienne Carriere static void register_pmic_shared_peripherals(void) 240f564d439SEtienne Carriere { 241f564d439SEtienne Carriere uintptr_t i2c_base = i2c_handle.i2c_base_addr; 242f564d439SEtienne Carriere 243f564d439SEtienne Carriere if (dt_pmic_is_secure()) { 244f564d439SEtienne Carriere stm32mp_register_secure_periph_iomem(i2c_base); 245f564d439SEtienne Carriere } else { 246f564d439SEtienne Carriere if (i2c_base != 0U) { 247f564d439SEtienne Carriere stm32mp_register_non_secure_periph_iomem(i2c_base); 248f564d439SEtienne Carriere } 249f564d439SEtienne Carriere } 250f564d439SEtienne Carriere } 251f564d439SEtienne Carriere 25223684d0eSYann Gautier void initialize_pmic(void) 25323684d0eSYann Gautier { 254d82d4ff0SYann Gautier unsigned long pmic_version; 25523684d0eSYann Gautier 256d82d4ff0SYann Gautier if (!initialize_pmic_i2c()) { 257d82d4ff0SYann Gautier VERBOSE("No PMIC\n"); 258d82d4ff0SYann Gautier return; 259d82d4ff0SYann Gautier } 26023684d0eSYann Gautier 261f564d439SEtienne Carriere register_pmic_shared_peripherals(); 262f564d439SEtienne Carriere 263d82d4ff0SYann Gautier if (stpmic1_get_version(&pmic_version) != 0) { 264d82d4ff0SYann Gautier ERROR("Failed to access PMIC\n"); 26523684d0eSYann Gautier panic(); 26623684d0eSYann Gautier } 26723684d0eSYann Gautier 268d82d4ff0SYann Gautier INFO("PMIC version = 0x%02lx\n", pmic_version); 269d82d4ff0SYann Gautier stpmic1_dump_regulators(); 27023684d0eSYann Gautier 271d82d4ff0SYann Gautier #if defined(IMAGE_BL2) 272d82d4ff0SYann Gautier if (dt_pmic_configure_boot_on_regulators() != 0) { 27323684d0eSYann Gautier panic(); 274d82d4ff0SYann Gautier }; 275d82d4ff0SYann Gautier #endif 27623684d0eSYann Gautier } 27723684d0eSYann Gautier 27823684d0eSYann Gautier int pmic_ddr_power_init(enum ddr_type ddr_type) 27923684d0eSYann Gautier { 28023684d0eSYann Gautier bool buck3_at_1v8 = false; 28123684d0eSYann Gautier uint8_t read_val; 28223684d0eSYann Gautier int status; 28323684d0eSYann Gautier 28423684d0eSYann Gautier switch (ddr_type) { 28523684d0eSYann Gautier case STM32MP_DDR3: 28623684d0eSYann Gautier /* Set LDO3 to sync mode */ 28723684d0eSYann Gautier status = stpmic1_register_read(LDO3_CONTROL_REG, &read_val); 28823684d0eSYann Gautier if (status != 0) { 28923684d0eSYann Gautier return status; 29023684d0eSYann Gautier } 29123684d0eSYann Gautier 29223684d0eSYann Gautier read_val &= ~STPMIC1_LDO3_MODE; 29323684d0eSYann Gautier read_val &= ~STPMIC1_LDO12356_OUTPUT_MASK; 29423684d0eSYann Gautier read_val |= STPMIC1_LDO3_DDR_SEL << 29523684d0eSYann Gautier STPMIC1_LDO12356_OUTPUT_SHIFT; 29623684d0eSYann Gautier 29723684d0eSYann Gautier status = stpmic1_register_write(LDO3_CONTROL_REG, read_val); 29823684d0eSYann Gautier if (status != 0) { 29923684d0eSYann Gautier return status; 30023684d0eSYann Gautier } 30123684d0eSYann Gautier 30223684d0eSYann Gautier status = stpmic1_regulator_voltage_set("buck2", 1350); 30323684d0eSYann Gautier if (status != 0) { 30423684d0eSYann Gautier return status; 30523684d0eSYann Gautier } 30623684d0eSYann Gautier 30723684d0eSYann Gautier status = stpmic1_regulator_enable("buck2"); 30823684d0eSYann Gautier if (status != 0) { 30923684d0eSYann Gautier return status; 31023684d0eSYann Gautier } 31123684d0eSYann Gautier 31223684d0eSYann Gautier mdelay(STPMIC1_DEFAULT_START_UP_DELAY_MS); 31323684d0eSYann Gautier 31423684d0eSYann Gautier status = stpmic1_regulator_enable("vref_ddr"); 31523684d0eSYann Gautier if (status != 0) { 31623684d0eSYann Gautier return status; 31723684d0eSYann Gautier } 31823684d0eSYann Gautier 31923684d0eSYann Gautier mdelay(STPMIC1_DEFAULT_START_UP_DELAY_MS); 32023684d0eSYann Gautier 32123684d0eSYann Gautier status = stpmic1_regulator_enable("ldo3"); 32223684d0eSYann Gautier if (status != 0) { 32323684d0eSYann Gautier return status; 32423684d0eSYann Gautier } 32523684d0eSYann Gautier 32623684d0eSYann Gautier mdelay(STPMIC1_DEFAULT_START_UP_DELAY_MS); 32723684d0eSYann Gautier break; 32823684d0eSYann Gautier 32923684d0eSYann Gautier case STM32MP_LPDDR2: 3304b549b21SYann Gautier case STM32MP_LPDDR3: 33123684d0eSYann Gautier /* 33223684d0eSYann Gautier * Set LDO3 to 1.8V 33323684d0eSYann Gautier * Set LDO3 to bypass mode if BUCK3 = 1.8V 33423684d0eSYann Gautier * Set LDO3 to normal mode if BUCK3 != 1.8V 33523684d0eSYann Gautier */ 33623684d0eSYann Gautier status = stpmic1_register_read(BUCK3_CONTROL_REG, &read_val); 33723684d0eSYann Gautier if (status != 0) { 33823684d0eSYann Gautier return status; 33923684d0eSYann Gautier } 34023684d0eSYann Gautier 34123684d0eSYann Gautier if ((read_val & STPMIC1_BUCK3_1V8) == STPMIC1_BUCK3_1V8) { 34223684d0eSYann Gautier buck3_at_1v8 = true; 34323684d0eSYann Gautier } 34423684d0eSYann Gautier 34523684d0eSYann Gautier status = stpmic1_register_read(LDO3_CONTROL_REG, &read_val); 34623684d0eSYann Gautier if (status != 0) { 34723684d0eSYann Gautier return status; 34823684d0eSYann Gautier } 34923684d0eSYann Gautier 35023684d0eSYann Gautier read_val &= ~STPMIC1_LDO3_MODE; 35123684d0eSYann Gautier read_val &= ~STPMIC1_LDO12356_OUTPUT_MASK; 35223684d0eSYann Gautier read_val |= STPMIC1_LDO3_1800000; 35323684d0eSYann Gautier if (buck3_at_1v8) { 35423684d0eSYann Gautier read_val |= STPMIC1_LDO3_MODE; 35523684d0eSYann Gautier } 35623684d0eSYann Gautier 35723684d0eSYann Gautier status = stpmic1_register_write(LDO3_CONTROL_REG, read_val); 35823684d0eSYann Gautier if (status != 0) { 35923684d0eSYann Gautier return status; 36023684d0eSYann Gautier } 36123684d0eSYann Gautier 36223684d0eSYann Gautier status = stpmic1_regulator_voltage_set("buck2", 1200); 36323684d0eSYann Gautier if (status != 0) { 36423684d0eSYann Gautier return status; 36523684d0eSYann Gautier } 36623684d0eSYann Gautier 36723684d0eSYann Gautier status = stpmic1_regulator_enable("ldo3"); 36823684d0eSYann Gautier if (status != 0) { 36923684d0eSYann Gautier return status; 37023684d0eSYann Gautier } 37123684d0eSYann Gautier 37223684d0eSYann Gautier mdelay(STPMIC1_DEFAULT_START_UP_DELAY_MS); 37323684d0eSYann Gautier 37423684d0eSYann Gautier status = stpmic1_regulator_enable("buck2"); 37523684d0eSYann Gautier if (status != 0) { 37623684d0eSYann Gautier return status; 37723684d0eSYann Gautier } 37823684d0eSYann Gautier 37923684d0eSYann Gautier mdelay(STPMIC1_DEFAULT_START_UP_DELAY_MS); 38023684d0eSYann Gautier 38123684d0eSYann Gautier status = stpmic1_regulator_enable("vref_ddr"); 38223684d0eSYann Gautier if (status != 0) { 38323684d0eSYann Gautier return status; 38423684d0eSYann Gautier } 38523684d0eSYann Gautier 38623684d0eSYann Gautier mdelay(STPMIC1_DEFAULT_START_UP_DELAY_MS); 38723684d0eSYann Gautier break; 38823684d0eSYann Gautier 38923684d0eSYann Gautier default: 39023684d0eSYann Gautier break; 39123684d0eSYann Gautier }; 39223684d0eSYann Gautier 39323684d0eSYann Gautier return 0; 39423684d0eSYann Gautier } 395