From 1fe2b03c3d3ef5e550fefe361f69bff86bddf698 Mon Sep 17 00:00:00 2001 From: Romuald JEANNE Date: Thu, 28 Oct 2021 15:51:21 +0200 Subject: [PATCH] v2.4-stm32mp-r2 --- bl32/tsp/aarch64/tsp_entrypoint.S | 22 +- docs/license.rst | 10 + drivers/mtd/nand/spi_nand.c | 8 +- drivers/regulator/regulator_core.c | 1142 +++++++++++++++++ drivers/st/clk/stm32mp1_clk.c | 29 +- drivers/st/ddr/stm32mp1_ddr.c | 11 +- drivers/st/ddr/stm32mp1_ram.c | 169 +-- drivers/st/ddr/stm32mp_ddr_test.c | 148 +++ drivers/st/fmc/stm32_fmc2_nand.c | 11 +- drivers/st/gpio/stm32_gpio.c | 9 +- drivers/st/mmc/stm32_sdmmc2.c | 16 +- drivers/st/pmic/stm32mp_pmic.c | 718 +++++------ drivers/st/pmic/stpmic1.c | 158 ++- drivers/st/regulator/regulator_fixed.c | 91 ++ .../st/regulator/stm32mp_dummy_regulator.c | 27 - drivers/st/regulator/stm32mp_regulator.c | 38 - drivers/st/tamper/stm32_tamp.c | 691 +++++++--- drivers/st/uart/aarch32/stm32_console.S | 11 +- fdts/stm32mp15-ddr-512m-fw-config.dts | 63 - fdts/stm32mp15-ddr.dtsi | 266 ++-- fdts/stm32mp15-ddr3-1x4Gb-1066-binG.dtsi | 6 +- fdts/stm32mp15-ddr3-2x4Gb-1066-binG.dtsi | 6 +- ...-fw-config.dts => stm32mp15-fw-config.dts} | 25 +- fdts/stm32mp151.dtsi | 18 + fdts/stm32mp157a-avenger96-fw-config.dts | 3 +- fdts/stm32mp157a-dk1-fw-config.dts | 3 +- fdts/stm32mp157a-ed1-fw-config.dts | 3 +- fdts/stm32mp157a-ev1-fw-config.dts | 3 +- fdts/stm32mp157c-dk2-fw-config.dts | 3 +- fdts/stm32mp157c-ed1-fw-config.dts | 3 +- fdts/stm32mp157c-ev1-fw-config.dts | 3 +- fdts/stm32mp157d-dk1-fw-config.dts | 3 +- fdts/stm32mp157d-ed1-fw-config.dts | 3 +- fdts/stm32mp157d-ev1-fw-config.dts | 3 +- fdts/stm32mp157f-dk2-fw-config.dts | 3 +- fdts/stm32mp157f-ed1-fw-config.dts | 3 +- fdts/stm32mp157f-ev1-fw-config.dts | 3 +- fdts/stm32mp15xx-dkx.dtsi | 8 +- fdts/stm32mp15xx-edx.dtsi | 8 +- include/arch/aarch32/el3_common_macros.S | 13 +- include/arch/aarch64/el3_common_macros.S | 15 +- include/drivers/regulator.h | 160 +++ include/drivers/st/regulator_fixed.h | 12 + include/drivers/st/stm32_gpio.h | 3 +- include/drivers/st/stm32_sdmmc2.h | 4 +- include/drivers/st/stm32_tamp.h | 311 +++-- include/drivers/st/stm32mp1_ddr_regs.h | 1 + include/drivers/st/stm32mp1_rcc.h | 2 + include/drivers/st/stm32mp_ddr_test.h | 15 + include/drivers/st/stm32mp_dummy_regulator.h | 14 - include/drivers/st/stm32mp_pmic.h | 46 +- include/drivers/st/stm32mp_regulator.h | 31 - include/drivers/st/stpmic1.h | 28 + .../interrupt-controller/arm-gic.h | 19 +- .../dt-bindings/interrupt-controller/irq.h | 23 + lib/aarch32/misc_helpers.S | 4 +- licenses/LICENSE.MIT | 21 + plat/st/common/bl2_io_storage.c | 10 +- plat/st/common/include/stm32cubeprogrammer.h | 3 - plat/st/common/include/stm32mp_common.h | 15 +- plat/st/common/include/stm32mp_dt.h | 6 +- plat/st/common/stm32cubeprogrammer_uart.c | 21 +- plat/st/common/stm32mp_common.c | 94 +- plat/st/common/stm32mp_dt.c | 86 +- plat/st/common/stm32mp_trusted_boot.c | 2 +- plat/st/stm32mp1/bl2_plat_setup.c | 49 +- .../stm32mp1/include/stm32mp1_critic_power.h | 8 +- plat/st/stm32mp1/include/stm32mp1_private.h | 4 +- plat/st/stm32mp1/plat_bl2_mem_params_desc.c | 61 +- plat/st/stm32mp1/platform.mk | 23 +- plat/st/stm32mp1/services/bsec_svc.c | 11 +- plat/st/stm32mp1/sp_min/sp_min-stm32mp1.mk | 1 + plat/st/stm32mp1/sp_min/sp_min_setup.c | 157 +-- plat/st/stm32mp1/stm32mp1_context.c | 16 +- plat/st/stm32mp1/stm32mp1_critic_power.c | 49 +- .../stm32mp1/stm32mp1_critic_power_wrapper.S | 16 +- plat/st/stm32mp1/stm32mp1_def.h | 23 +- plat/st/stm32mp1/stm32mp1_helper.S | 4 +- plat/st/stm32mp1/stm32mp1_low_power.c | 51 +- plat/st/stm32mp1/stm32mp1_pm.c | 7 +- plat/st/stm32mp1/stm32mp1_private.c | 234 ++-- plat/st/stm32mp1/stm32mp1_ssp.c | 23 +- plat/st/stm32mp1/stm32mp1_syscfg.c | 130 +- plat/st/stm32mp1/stm32mp1_usb.c | 4 +- 84 files changed, 3675 insertions(+), 1903 deletions(-) create mode 100644 drivers/regulator/regulator_core.c create mode 100644 drivers/st/ddr/stm32mp_ddr_test.c create mode 100644 drivers/st/regulator/regulator_fixed.c delete mode 100644 drivers/st/regulator/stm32mp_dummy_regulator.c delete mode 100644 drivers/st/regulator/stm32mp_regulator.c delete mode 100644 fdts/stm32mp15-ddr-512m-fw-config.dts rename fdts/{stm32mp15-ddr-1g-fw-config.dts => stm32mp15-fw-config.dts} (60%) create mode 100644 include/drivers/regulator.h create mode 100644 include/drivers/st/regulator_fixed.h create mode 100644 include/drivers/st/stm32mp_ddr_test.h delete mode 100644 include/drivers/st/stm32mp_dummy_regulator.h delete mode 100644 include/drivers/st/stm32mp_regulator.h create mode 100644 include/dt-bindings/interrupt-controller/irq.h create mode 100644 licenses/LICENSE.MIT diff --git a/bl32/tsp/aarch64/tsp_entrypoint.S b/bl32/tsp/aarch64/tsp_entrypoint.S index a007bab302..a9d03c379e 100644 --- a/bl32/tsp/aarch64/tsp_entrypoint.S +++ b/bl32/tsp/aarch64/tsp_entrypoint.S @@ -100,11 +100,27 @@ func tsp_entrypoint _align=3 * sections. This is done to safeguard against * possible corruption of this memory by dirty * cache lines in a system cache as a result of - * use by an earlier boot loader stage. + * use by an earlier boot loader stage. If PIE + * is enabled however, RO sections including the + * GOT may be modified during pie fixup. + * Therefore, to be on the safe side, invalidate + * the entire image region if PIE is enabled. * --------------------------------------------- */ - adr x0, __RW_START__ - adr x1, __RW_END__ +#if ENABLE_PIE +#if SEPARATE_CODE_AND_RODATA + adrp x0, __TEXT_START__ + add x0, x0, :lo12:__TEXT_START__ +#else + adrp x0, __RO_START__ + add x0, x0, :lo12:__RO_START__ +#endif /* SEPARATE_CODE_AND_RODATA */ +#else + adrp x0, __RW_START__ + add x0, x0, :lo12:__RW_START__ +#endif /* ENABLE_PIE */ + adrp x1, __RW_END__ + add x1, x1, :lo12:__RW_END__ sub x1, x1, x0 bl inv_dcache_range diff --git a/docs/license.rst b/docs/license.rst index 2f9704335f..80f1118609 100644 --- a/docs/license.rst +++ b/docs/license.rst @@ -76,5 +76,15 @@ license text is included in those source files. BSD-3-Clause license. Any contributions to this code must be made under the terms of both licenses. +- Some source files originating from the Linux source tree, which are + disjunctively dual licensed (GPL-2.0 OR MIT), are redistributed under the + terms of the MIT license. These files are: + + - ``include/dt-bindings/interrupt-controller/arm-gic.h`` + - ``include/dt-bindings/interrupt-controller/irq.h`` + + See the original `Linux MIT license`_. + .. _FreeBSD: http://www.freebsd.org +.. _Linux MIT license: https://raw.githubusercontent.com/torvalds/linux/master/LICENSES/preferred/MIT .. _SCC: http://www.simple-cc.org/ diff --git a/drivers/mtd/nand/spi_nand.c b/drivers/mtd/nand/spi_nand.c index d01a11963f..18913a57db 100644 --- a/drivers/mtd/nand/spi_nand.c +++ b/drivers/mtd/nand/spi_nand.c @@ -286,6 +286,10 @@ int spi_nand_init(unsigned long long *size, unsigned int *erase_size) return -EINVAL; } + assert((spinand_dev.nand_dev->page_size != 0U) && + (spinand_dev.nand_dev->block_size != 0U) && + (spinand_dev.nand_dev->size != 0U)); + ret = spi_nand_reset(); if (ret != 0) { return ret; @@ -301,12 +305,12 @@ int spi_nand_init(unsigned long long *size, unsigned int *erase_size) return ret; } - ret = spi_nand_quad_enable(id[0]); + ret = spi_nand_quad_enable(id[1]); if (ret != 0) { return ret; } - VERBOSE("SPI_NAND Detected ID 0x%x 0x%x\n", id[0], id[1]); + VERBOSE("SPI_NAND Detected ID 0x%x\n", id[1]); VERBOSE("Page size %i, Block size %i, size %lli\n", spinand_dev.nand_dev->page_size, diff --git a/drivers/regulator/regulator_core.c b/drivers/regulator/regulator_core.c new file mode 100644 index 0000000000..67da7d2920 --- /dev/null +++ b/drivers/regulator/regulator_core.c @@ -0,0 +1,1142 @@ +/* + * Copyright (c) 2020-2021, STMicroelectronics - All Rights Reserved + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +#define MAX_PROPERTY_LEN 64 + +static struct rdev rdev_array[PLAT_NB_RDEVS]; + +#pragma weak plat_get_lp_mode_name +const char *plat_get_lp_mode_name(int mode) +{ + return NULL; +} + +#define for_each_rdev(rdev) \ + for (rdev = rdev_array; rdev < (rdev_array + PLAT_NB_RDEVS); rdev++) + +#define for_each_registered_rdev(rdev) \ + for (rdev = rdev_array; \ + (rdev < (rdev_array + PLAT_NB_RDEVS)) && (rdev->desc != NULL); rdev++) + +#if defined(IMAGE_BL32) +static void lock_driver(const struct rdev *rdev) +{ + if (rdev->desc->ops->lock != NULL) { + rdev->desc->ops->lock(rdev->desc); + } +} + +static void unlock_driver(const struct rdev *rdev) +{ + if (rdev->desc->ops->unlock != NULL) { + rdev->desc->ops->unlock(rdev->desc); + } +} +#else +#define lock_driver(desc) {} +#define unlock_driver(desc) {} +#endif + +static struct rdev *regulator_get_by_phandle(int32_t phandle) +{ + struct rdev *rdev; + + for_each_registered_rdev(rdev) { + if (rdev->phandle == phandle) { + return rdev; + } + } + + WARN("%s: phandle %d not found\n", __func__, phandle); + return NULL; +} + +/* + * Get a regulator from its node name + * + * @fdt - pointer to device tree memory + * @node_name - name of the node "ldo1" + * Return pointer to rdev if succeed, NULL else. + */ +struct rdev *regulator_get_by_name(const char *node_name) +{ + struct rdev *rdev; + + assert(node_name != NULL); + VERBOSE("get %s\n", node_name); + + for_each_registered_rdev(rdev) { + if (strcmp(rdev->desc->node_name, node_name) == 0) { + return rdev; + } + } + + WARN("%s: %s not found\n", __func__, node_name); + return NULL; +} + +#if defined(IMAGE_BL32) +/* + * Get a regulator from its regulator name property value + * + * @reg_name - target value of regulator-name property + * Return pointer to rdev if succeed, NULL else. + */ +struct rdev *regulator_get_by_regulator_name(const char *reg_name) +{ + struct rdev *rdev; + + assert(reg_name != NULL); + VERBOSE("get %s\n", reg_name); + + for_each_registered_rdev(rdev) { + if ((rdev->reg_name != NULL) && (strcmp(rdev->reg_name, reg_name) == 0)) { + return rdev; + } + } + + WARN("%s: %s not found\n", __func__, reg_name); + return NULL; +} +#endif + +static int32_t get_supply_phandle(const void *fdt, int node, const char *name) +{ + const fdt32_t *cuint; + int len __unused; + int supply_phandle = -FDT_ERR_NOTFOUND; + char prop_name[MAX_PROPERTY_LEN]; + + len = snprintf(prop_name, MAX_PROPERTY_LEN - 1, "%s-supply", name); + assert((len >= 0) && (len < MAX_PROPERTY_LEN - 1)); + + cuint = fdt_getprop(fdt, node, prop_name, NULL); + if (cuint != NULL) { + supply_phandle = fdt32_to_cpu(*cuint); + VERBOSE("%s: supplied by %d\n", name, supply_phandle); + } + + return supply_phandle; +} + +/* + * Get a regulator from a supply name + * + * @fdt - pointer to device tree memory + * @node - offset of the node that contains the supply description + * @name - name of the supply "vdd" for "vdd-supply' + * Return pointer to rdev if succeed, NULL else. + */ +struct rdev *regulator_get_by_supply_name(const void *fdt, int node, const char *name) +{ + const int p = get_supply_phandle(fdt, node, name); + + if (p < 0) { + return NULL; + } + + return regulator_get_by_phandle(p); +} + +static int __regulator_set_state(struct rdev *rdev, bool state) +{ + if (rdev->desc->ops->set_state == NULL) { + return -ENODEV; + } + + return rdev->desc->ops->set_state(rdev->desc, state); +} + +#if defined(IMAGE_BL32) +/* + * Enable regulator supply + * Enable regulator if use_count == 0 + * Apply ramp delay + * + * @rdev - pointer to rdev struct + * Return 0 if succeed, non 0 else. + */ +static int __regulator_enable(struct rdev *rdev) +{ + VERBOSE("%s: en\n", rdev->desc->node_name); + + if (rdev->desc->ops->set_state == NULL) { + return -ENODEV; + } + + if (rdev->supply_dev != NULL) + regulator_enable(rdev->supply_dev); + + lock_driver(rdev); + + if (rdev->use_count == 0) { + int ret; + + ret = __regulator_set_state(rdev, STATE_ENABLE); + if (ret != 0) { + ERROR("regul %s set state failed: err:%d\n", + rdev->desc->node_name, ret); + unlock_driver(rdev); + return ret; + } + + udelay(rdev->enable_ramp_delay); + } + + rdev->use_count++; + + assert(rdev->use_count != UINT8_MAX); + + VERBOSE("%s: en count:%u\n", rdev->desc->node_name, rdev->use_count); + + unlock_driver(rdev); + + return 0; +} + +/* + * Enable regulator + * + * @rdev - pointer to rdev struct + * Return 0 if succeed, non 0 else. + */ +int regulator_enable(struct rdev *rdev) +{ + assert(rdev != NULL); + + if (rdev->flags & REGUL_ALWAYS_ON) { + return 0; + } + + return __regulator_enable(rdev); +} + +/* + * Disable regulator if use_count fall to zero + * Warn if count is < 0 because too many disable were requested + * Disable regulator supply + * + * @rdev - pointer to rdev struct + * Return 0 if succeed, non 0 else. + */ +static int __regulator_disable(struct rdev *rdev) +{ + VERBOSE("%s: dis\n", rdev->desc->node_name); + + if (rdev->desc->ops->set_state == NULL) { + return -ENODEV; + } + + lock_driver(rdev); + + if (rdev->use_count == 1) { + int ret; + + ret = __regulator_set_state(rdev, STATE_DISABLE); + if (ret != 0) { + ERROR("regul %s set state failed: err:%d\n", + rdev->desc->node_name, ret); + unlock_driver(rdev); + return ret; + } + } + + if (rdev->use_count == 0) { + WARN("regulator %s unbalanced disable\n", rdev->desc->node_name); + } else { + rdev->use_count--; + } + + VERBOSE("%s: dis count:%u\n", rdev->desc->node_name, rdev->use_count); + + unlock_driver(rdev); + + if (rdev->supply_dev != NULL) { + regulator_disable(rdev->supply_dev); + } + + return 0; +} + +/* + * Disable regulator + * + * @rdev - pointer to rdev struct + * Return 0 if succeed, non 0 else. + */ +int regulator_disable(struct rdev *rdev) +{ + assert(rdev != NULL); + + if (rdev->flags & REGUL_ALWAYS_ON) { + return 0; + } + + return __regulator_disable(rdev); +} +#else +/* + * Enable regulator + * + * @rdev - pointer to rdev struct + * Return 0 if succeed, non 0 else. + */ +int regulator_enable(struct rdev *rdev) +{ + int ret; + + assert(rdev != NULL); + + ret = __regulator_set_state(rdev, STATE_ENABLE); + + udelay(rdev->enable_ramp_delay); + + return ret; +} + +/* + * Disable regulator + * + * @rdev - pointer to rdev struct + * Return 0 if succeed, non 0 else. + */ +int regulator_disable(struct rdev *rdev) +{ + int ret; + + assert(rdev != NULL); + + ret = __regulator_set_state(rdev, STATE_DISABLE); + + udelay(rdev->enable_ramp_delay); + + return ret; +} +#endif + +/* + * Regulator enabled query + * + * @rdev - pointer to rdev struct + * Return 0 if disabled, 1 if enabled, <0 else. + */ +int regulator_is_enabled(const struct rdev *rdev) +{ + int ret = 0; + + assert(rdev != NULL); + + VERBOSE("%s: is en\n", rdev->desc->node_name); + + if (rdev->desc->ops->get_state == NULL) { + return -ENODEV; + } + + lock_driver(rdev); + + ret = rdev->desc->ops->get_state(rdev->desc); + if (ret < 0) { + ERROR("regul %s get state failed: err:%d\n", + rdev->desc->node_name, ret); + } + + unlock_driver(rdev); + + return ret; +} + +/* + * Set regulator voltage + * + * @rdev - pointer to rdev struct + * @mvolt - Target voltage level in millivolt + * Return 0 if succeed, non 0 else. + */ +int regulator_set_voltage(struct rdev *rdev, uint16_t mvolt) +{ + int ret = 0; + + assert(rdev != NULL); + + VERBOSE("%s: set mvolt\n", rdev->desc->node_name); + + if (rdev->desc->ops->set_voltage == NULL) { + return -ENODEV; + } + + if ((mvolt < rdev->min_mv) || (mvolt > rdev->max_mv)) { + return -EPERM; + } + + lock_driver(rdev); + + ret = rdev->desc->ops->set_voltage(rdev->desc, mvolt); + if (ret < 0) { + ERROR("regul %s set volt failed: err:%d\n", + rdev->desc->node_name, ret); + } + + unlock_driver(rdev); + + return ret; +} + +/* + * Set regulator min voltage + * + * @rdev - pointer to rdev struct + * Return 0 if succeed, non 0 else. + */ +int regulator_set_min_voltage(struct rdev *rdev) +{ + return regulator_set_voltage(rdev, rdev->min_mv); +} + +/* + * Get regulator voltage + * + * @rdev - pointer to rdev struct + * Return milli volts if succeed, <0 else. + */ +int regulator_get_voltage(const struct rdev *rdev) +{ + int ret = 0; + + assert(rdev != NULL); + + VERBOSE("%s: get volt\n", rdev->desc->node_name); + + if (rdev->desc->ops->get_voltage == NULL) { + return rdev->min_mv; + } + + lock_driver(rdev); + + ret = rdev->desc->ops->get_voltage(rdev->desc); + if (ret < 0) { + ERROR("regul %s get voltage failed: err:%d\n", + rdev->desc->node_name, ret); + } + + unlock_driver(rdev); + + return ret; +} + +/* + * List regulator voltages + * + * @rdev - pointer to rdev struct + * @levels - out: array of supported millitvolt levels from min to max value + * @count - out: number of possible millivolt values + * Return 0 if succeed, non 0 else. + */ +int regulator_list_voltages(const struct rdev *rdev, const uint16_t **levels, size_t *count) +{ + int ret; + size_t n; + + assert(rdev != NULL); + assert(levels != NULL); + assert(count != NULL); + + VERBOSE("%s: list volt\n", rdev->desc->node_name); + + if (rdev->desc->ops->list_voltages == NULL) { + return -ENODEV; + } + + lock_driver(rdev); + + ret = rdev->desc->ops->list_voltages(rdev->desc, levels, count); + + unlock_driver(rdev); + + if (ret < 0) { + ERROR("regul %s list_voltages failed: err: %d\n", + rdev->desc->node_name, ret); + return ret; + } + + /* + * Reduce the possible values depending on min and max from device-tree + */ + n = *count; + while (((*levels)[n - 1U] > rdev->max_mv) && (n > 1U)) { + n--; + } + + /* Verify that max val is a valid value */ + if (rdev->max_mv != (*levels)[n - 1]) { + ERROR("regul %s: max value %u is invalid\n", + rdev->desc->node_name, rdev->max_mv); + return -EINVAL; + } + + while (((*levels[0U]) < rdev->min_mv) && (n > 1U)) { + (*levels)++; + n--; + } + + /* Verify that min is not too high */ + if (n == 0U) { + ERROR("regul %s set min voltage is too high\n", + rdev->desc->node_name); + return -EINVAL; + } + + /* Verify that min val is a valid vlue */ + if (rdev->min_mv != (*levels)[0U]) { + ERROR("regul %s: min value %u is invalid\n", + rdev->desc->node_name, rdev->min_mv); + return -EINVAL; + } + + *count = n; + + VERBOSE("rdev->min_mv=%u rdev->max_mv=%u\n", rdev->min_mv, rdev->max_mv); + + return 0; +} + +/* + * Get regulator voltages range + * + * @rdev - pointer to rdev struct + * @min_mv - out: min possible millivolt value + * @max_mv - out: max possible millivolt value + * Return 0 if succeed, non 0 else. + */ +void regulator_get_range(const struct rdev *rdev, uint16_t *min_mv, uint16_t *max_mv) +{ + assert(rdev != NULL); + + if (min_mv != NULL) { + *min_mv = rdev->min_mv; + } + if (max_mv != NULL) { + *max_mv = rdev->max_mv; + } +} + +/* + * Set regulator flag + * + * @rdev - pointer to rdev struct + * @flag - flag value to set (eg: REGUL_OCP) + * Return 0 if succeed, non 0 else. + */ +int regulator_set_flag(struct rdev *rdev, uint16_t flag) +{ + int ret; + + /* check that only one bit is set on flag */ + if (__builtin_popcount(flag) != 1) { + return -EINVAL; + } + + /* REGUL_ALWAYS_ON and REGUL_BOOT_ON are internal properties of the core */ + if ((flag == REGUL_ALWAYS_ON) || (flag == REGUL_BOOT_ON)) { + rdev->flags |= flag; + return 0; + } + + if (rdev->desc->ops->set_flag == NULL) { + ERROR("%s can not set any flag\n", rdev->desc->node_name); + return -ENODEV; + } + + lock_driver(rdev); + + ret = rdev->desc->ops->set_flag(rdev->desc, flag); + + unlock_driver(rdev); + + if (ret != 0) { + ERROR("%s: could not set flag %d ret=%d\n", + rdev->desc->node_name, flag, ret); + return ret; + } + + rdev->flags |= flag; + + return 0; +} + +#if defined(IMAGE_BL32) + +struct regul_property { + char *name; + uint16_t flag; +}; + +static struct regul_property flag_prop[] = { + { + .name = "regulator-always-on", + .flag = REGUL_ALWAYS_ON, + }, + { + .name = "regulator-boot-on", + .flag = REGUL_BOOT_ON, + }, + { + .name = "regulator-active-discharge", + .flag = REGUL_ACTIVE_DISCHARGE, + }, + { + .name = "regulator-over-current-protection", + .flag = REGUL_OCP, + }, + { + .name = "regulator-pull-down", + .flag = REGUL_PULL_DOWN, + }, + { + .name = "st,mask-reset", + .flag = REGUL_MASK_RESET, + }, + { + .name = "st,regulator-sink-source", + .flag = REGUL_SINK_SOURCE, + }, + { + .name = "st,regulator-bypass", + .flag = REGUL_ENABLE_BYPASS, + }, +}; + +static int parse_properties(const void *fdt, struct rdev *rdev, int node) +{ + const fdt32_t *cuint; + int ret = 0; + struct regul_property *prop; + + for (prop = flag_prop; prop < (flag_prop + ARRAY_SIZE(flag_prop)); prop++) { + if (fdt_getprop(fdt, node, prop->name, NULL) != NULL) { + VERBOSE("%s: prop 0x%x\n", rdev->desc->node_name, prop->flag); + ret = regulator_set_flag(rdev, prop->flag); + if (ret != 0) { + return ret; + } + } + } + + cuint = fdt_getprop(fdt, node, "regulator-enable-ramp-delay", NULL); + if (cuint != NULL) { + rdev->enable_ramp_delay = (uint32_t)(fdt32_to_cpu(*cuint)); + VERBOSE("%s: enable_ramp_delay=%u\n", rdev->desc->node_name, + rdev->enable_ramp_delay); + } + + rdev->reg_name = fdt_getprop(fdt, node, "regulator-name", NULL); + + return 0; +} + +static void parse_supply(const void *fdt, struct rdev *rdev, int node) +{ + const char *name = rdev->desc->supply_name; + + if (name == NULL) { + name = rdev->desc->node_name; + } + + rdev->supply_phandle = get_supply_phandle(fdt, node, name); + if (rdev->supply_phandle < 0) { + node = fdt_parent_offset(fdt, node); + rdev->supply_phandle = get_supply_phandle(fdt, node, name); + } +} + +static void parse_low_power_mode(const void *fdt, struct rdev *rdev, int node, int mode) +{ + const fdt32_t *cuint; + + rdev->lp_state[mode] = 0; + + if (fdt_getprop(fdt, node, "regulator-off-in-suspend", NULL) != NULL) { + VERBOSE("%s: mode:%d OFF\n", rdev->desc->node_name, mode); + rdev->lp_state[mode] |= LP_STATE_OFF; + } else if (fdt_getprop(fdt, node, "regulator-on-in-suspend", NULL) != NULL) { + VERBOSE("%s: mode:%d ON\n", rdev->desc->node_name, mode); + rdev->lp_state[mode] |= LP_STATE_ON; + } else { + rdev->lp_state[mode] |= LP_STATE_UNCHANGED; + } + + cuint = fdt_getprop(fdt, node, "regulator-suspend-microvolt", NULL); + if (cuint != NULL) { + uint16_t mv; + + mv = (uint16_t)(fdt32_to_cpu(*cuint) / 1000U); + VERBOSE("%s: mode:%d suspend mv=%u\n", rdev->desc->node_name, + mode, mv); + + rdev->lp_state[mode] |= LP_STATE_SET_VOLT; + rdev->lp_mv[mode] = mv; + } +} + +static void parse_low_power_modes(const void *fdt, struct rdev *rdev, int node) +{ + int i; + + for (i = 0; i < PLAT_NB_SUSPEND_MODES; i++) { + const char *lp_mode_name = plat_get_lp_mode_name(i); + int n; + + if (lp_mode_name == NULL) { + continue; + } + + /* Get the configs from regulator_state_node subnode */ + n = fdt_subnode_offset(fdt, node, lp_mode_name); + if (n >= 0) { + parse_low_power_mode(fdt, rdev, n, i); + } + } +} +#endif + +/* + * Parse the device-tree for a regulator + * + * Read min/max voltage from dt and check its validity + * Read the properties, and call the driver to set flags + * Read power supply phandle + * Read and store low power mode states + * + * @rdev - pointer to rdev struct + * @node - device-tree node offset of the regulator + * Return 0 if disabled, 1 if enabled, <0 else. + */ +static int parse_dt(struct rdev *rdev, int node) +{ + void *fdt; + const fdt32_t *cuint; + const uint16_t *levels; + size_t size; + int ret = 0; + + VERBOSE("%s: parse dt\n", rdev->desc->node_name); + + if (fdt_get_address(&fdt) == 0) { + return -ENOENT; + } + + rdev->phandle = fdt_get_phandle(fdt, node); + + cuint = fdt_getprop(fdt, node, "regulator-min-microvolt", NULL); + if (cuint != NULL) { + uint16_t min_mv; + + min_mv = (uint16_t)(fdt32_to_cpu(*cuint) / 1000U); + VERBOSE("%s: min_mv=%d\n", rdev->desc->node_name, (int)min_mv); + if (min_mv <= rdev->max_mv) { + rdev->min_mv = min_mv; + } else { + ERROR("%s: min_mv=%d is too high\n", + rdev->desc->node_name, (int)min_mv); + return -EINVAL; + } + } + + cuint = fdt_getprop(fdt, node, "regulator-max-microvolt", NULL); + if (cuint != NULL) { + uint16_t max_mv; + + max_mv = (uint16_t)(fdt32_to_cpu(*cuint) / 1000U); + VERBOSE("%s: max_mv=%d\n", rdev->desc->node_name, (int)max_mv); + if (max_mv >= rdev->min_mv) { + rdev->max_mv = max_mv; + } else { + ERROR("%s: max_mv=%d is too low\n", + rdev->desc->node_name, (int)max_mv); + return -EINVAL; + } + } + + /* validate that min and max values can be used */ + ret = regulator_list_voltages(rdev, &levels, &size); + if ((ret != 0) && (ret != -ENODEV)) { + return ret; + } + +#if defined(IMAGE_BL32) + ret = parse_properties(fdt, rdev, node); + if (ret != 0) { + return ret; + } + + parse_supply(fdt, rdev, node); + + parse_low_power_modes(fdt, rdev, node); +#endif + + return 0; +} + +/* + * Register a regulator driver in regulator framework. + * Initialize voltage range from driver description + * + * @desc - pointer to the regulator description + * @node - device-tree node offset of the regulator + * Return 0 if succeed, non 0 else. + */ +int regulator_register(const struct regul_description *desc, int node) +{ + struct rdev *rdev; + + assert(desc != NULL); + + VERBOSE("register %s\n", desc->node_name); + + for_each_rdev(rdev) { + if (rdev->desc == NULL) { + break; + } + } + + if (rdev == rdev_array + PLAT_NB_RDEVS) { + WARN("out of memory\n"); + return -ENOMEM; + } + + rdev->desc = desc; + rdev->enable_ramp_delay = rdev->desc->enable_ramp_delay; + + if (rdev->desc->ops->list_voltages != NULL) { + int ret = 0; + const uint16_t *levels; + size_t count; + + lock_driver(rdev); + + ret = rdev->desc->ops->list_voltages(rdev->desc, &levels, &count); + + unlock_driver(rdev); + + if (ret < 0) { + ERROR("regul %s set state failed: err:%d\n", + rdev->desc->node_name, ret); + return ret; + } + + rdev->min_mv = levels[0]; + rdev->max_mv = levels[count - 1U]; + } else { + rdev->max_mv = UINT16_MAX; + } + + return parse_dt(rdev, node); +} + +#if defined(IMAGE_BL32) +/* + * Suspend a single regulator before low power entry + * Call regulator suspend call back, + * Enable the regulator if boot_on flag is set as regulator is needed during + * boot/resume from suspend sequences. + * + * @rdev - pointer to rdev struct + * @mode - low power mode index + * Return 0 if succeed, non 0 else. + */ +static int suspend_regulator(struct rdev *rdev, int mode) +{ + int ret = 0; + + if (rdev->desc->ops->suspend != NULL) { + lock_driver(rdev); + ret = rdev->desc->ops->suspend(rdev->desc, + rdev->lp_state[mode], + rdev->lp_mv[mode]); + unlock_driver(rdev); + if (ret != 0) { + ERROR("%s failed to suspend: %d\n", rdev->desc->node_name, ret); + return ret; + } + } + + if (rdev->flags & REGUL_BOOT_ON) { + ret = regulator_enable(rdev); + } + + return ret; +} + +/* + * Resume a single regulator after low power + * + * @rdev - pointer to rdev struct + * Return 0 if succeed, non 0 else. + */ +static int resume_regulator(struct rdev *rdev) +{ + int ret = 0; + + if (rdev->flags & REGUL_BOOT_ON) { + /* Revert to the state it was before suspend */ + ret = regulator_disable(rdev); + if (ret != 0) { + ERROR("%s failed to resume: %d\n", rdev->desc->node_name, ret); + } + } + + return ret; +} + +/* + * Suspend regulators before entering low power + * + * Return 0 if succeed, non 0 else. + */ +int regulator_core_suspend(int mode) +{ + struct rdev *rdev; + + VERBOSE("Regulator core suspend\n"); + + if (mode >= PLAT_NB_SUSPEND_MODES) { + return -EINVAL; + } + + /* Suspend each regulator */ + for_each_registered_rdev(rdev) { + if (suspend_regulator(rdev, mode) != 0) { + panic(); + } + } + +#if LOG_LEVEL >= LOG_LEVEL_VERBOSE + regulator_core_dump(); +#endif + + return 0; +} + +/* + * Resume regulators from low power + * + * Return 0 if succeed, non 0 else. + */ +int regulator_core_resume(void) +{ + struct rdev *rdev; + + VERBOSE("Regulator core resume\n"); + + /* Resume each regulator */ + for_each_registered_rdev(rdev) { + if (resume_regulator(rdev) != 0) { + panic(); + } + } + +#if LOG_LEVEL >= LOG_LEVEL_VERBOSE + regulator_core_dump(); +#endif + + return 0; +} + +/* + * save regulators data + * + * @backup_area - pointer to save data + * @backup_size - size of the backup area + */ +void regulator_core_backup_context(void *backup_area, size_t backup_size) +{ + int8_t *data = (int8_t *)backup_area; + struct rdev *rdev; + + assert(data != NULL); + assert(backup_size == PLAT_BACKUP_REGULATOR_SIZE); + + for_each_rdev(rdev) { + *data = rdev->use_count; + data++; + } +} + +/* + * restore regulators data + * + * @backup_area - pointer to retrieve saved data + * @backup_size - size of the backup area + */ +void regulator_core_restore_context(void *backup_area, size_t backup_size) +{ + int8_t *data = (int8_t *)backup_area; + struct rdev *rdev; + + assert(data != NULL); + assert(backup_size == PLAT_BACKUP_REGULATOR_SIZE); + + for_each_rdev(rdev) { + rdev->use_count = *data; + data++; + } +} + +#if LOG_LEVEL >= LOG_LEVEL_VERBOSE +static void sprint_name(char *dest, const char *src, int len) +{ + int l; + + if (src == NULL) { + src = ""; + } + + l = strlen(src); + if (l > len) { + l = len; + } + + memset(dest, ' ', len); + memcpy(dest, src, l); + dest[len] = 0; +} + +/* + * Log regulators state + */ +void regulator_core_dump(void) +{ + struct rdev *rdev; + + VERBOSE("Dump Regulators\n"); + + INFO("reg name use\ten\tmV\tmin\tmax\tflags\tsupply\n"); + + for_each_registered_rdev(rdev) { + uint16_t min_mv, max_mv; + char reg[9] = ""; + char name[9]; + const char *supply = ""; + + sprint_name(name, rdev->desc->node_name, 8); + sprint_name(reg, rdev->reg_name, 8); + + regulator_get_range(rdev, &min_mv, &max_mv); + if (rdev->supply_dev != NULL) + supply = rdev->supply_dev->desc->node_name; + + INFO("%s %s %d\t%d\t%d\t%d\t%d\t0x%x\t%s\n", + reg, name, + rdev->use_count, + regulator_is_enabled(rdev), + regulator_get_voltage(rdev), min_mv, max_mv, + rdev->flags, supply); + } +} +#endif + +/* + * Connect each regulator to its supply + * Apply min voltage if the voltage is outside the authorized range + * Enable always-on regulators + * + * Return 0 if succeed, non 0 else. + */ +int regulator_core_config(void) +{ + int ret; + struct rdev *rdev; + + VERBOSE("Regul Core config\n"); + + for_each_registered_rdev(rdev) { + if (rdev->supply_phandle >= 0) { + struct rdev *s; + + VERBOSE("%s: connect supply\n", rdev->desc->node_name); + + s = regulator_get_by_phandle(rdev->supply_phandle); + if (s == NULL) { + return -EINVAL; + } + + rdev->supply_dev = s; + } + } + + for_each_registered_rdev(rdev) { + uint16_t mv, min_mv, max_mv; + + regulator_get_range(rdev, &min_mv, &max_mv); + + ret = regulator_get_voltage(rdev); + if (ret >= 0) { + mv = ret; + if ((mv < min_mv) || (mv > max_mv)) { + ret = regulator_set_voltage(rdev, min_mv); + if (ret != 0) { + return ret; + } + } + } else { + return ret; + } + + /* + * Enable always-on regulator and increment its use_count so that + * the regulator is not being disabled during clean-up sequence. + */ + if (rdev->flags & REGUL_ALWAYS_ON) { + ret = __regulator_enable(rdev); + if (ret != 0) { + return ret; + } + } + } + + return 0; +} + +/* + * Sync hardware regulator state with use refcount + * + * Return 0 if succeed, non 0 else. + */ +int regulator_core_cleanup(void) +{ + struct rdev *rdev; + + VERBOSE("Regul Core cleanup\n"); + + for_each_registered_rdev(rdev) { + if (!(rdev->flags & REGUL_BOOT_ON)) { + if ((rdev->use_count == 0) && (regulator_is_enabled(rdev) == 1)) { + VERBOSE("disable %s during cleanup\n", rdev->desc->node_name); + /* force disable to synchronize the framework */ + __regulator_set_state(rdev, STATE_DISABLE); + } + } + } + +#if LOG_LEVEL >= LOG_LEVEL_VERBOSE + regulator_core_dump(); +#endif + + return 0; +} + +#endif diff --git a/drivers/st/clk/stm32mp1_clk.c b/drivers/st/clk/stm32mp1_clk.c index d074a1568c..73c9b147b7 100644 --- a/drivers/st/clk/stm32mp1_clk.c +++ b/drivers/st/clk/stm32mp1_clk.c @@ -71,6 +71,7 @@ enum stm32mp1_parent_id { _HSI_KER = NB_OSC, _HSE_KER, _HSE_KER_DIV2, + _HSE_RTC, _CSI_KER, _PLL1_P, _PLL1_Q, @@ -140,6 +141,7 @@ static const uint8_t parent_id_clock_id[_PARENT_NB] = { [_HSI_KER] = CK_HSI, [_HSE_KER] = CK_HSE, [_HSE_KER_DIV2] = CK_HSE_DIV2, + [_HSE_RTC] = _UNKNOWN_ID, [_CSI_KER] = CK_CSI, [_PLL1_P] = PLL1_P, [_PLL1_Q] = PLL1_Q, @@ -384,21 +386,17 @@ static const struct stm32mp1_clk_gate stm32mp1_clk_gate[] = { #if defined(IMAGE_BL32) _CLK_SC_FIXED(N_S, RCC_MP_APB1ENSETR, 6, TIM12_K, _PCLK1), #endif -#if defined(IMAGE_BL2) _CLK_SC_SELEC(N_S, RCC_MP_APB1ENSETR, 14, USART2_K, _UART24_SEL), _CLK_SC_SELEC(N_S, RCC_MP_APB1ENSETR, 15, USART3_K, _UART35_SEL), _CLK_SC_SELEC(N_S, RCC_MP_APB1ENSETR, 16, UART4_K, _UART24_SEL), _CLK_SC_SELEC(N_S, RCC_MP_APB1ENSETR, 17, UART5_K, _UART35_SEL), _CLK_SC_SELEC(N_S, RCC_MP_APB1ENSETR, 18, UART7_K, _UART78_SEL), _CLK_SC_SELEC(N_S, RCC_MP_APB1ENSETR, 19, UART8_K, _UART78_SEL), -#endif #if defined(IMAGE_BL32) _CLK_SC_FIXED(N_S, RCC_MP_APB2ENSETR, 2, TIM15_K, _PCLK2), #endif -#if defined(IMAGE_BL2) _CLK_SC_SELEC(N_S, RCC_MP_APB2ENSETR, 13, USART6_K, _UART6_SEL), -#endif _CLK_SC_FIXED(N_S, RCC_MP_APB3ENSETR, 11, SYSCFG, _UNKNOWN_ID), @@ -543,7 +541,7 @@ static const uint8_t per_parents[] = { }; static const uint8_t rtc_parents[] = { - _UNKNOWN_ID, _LSE, _LSI, _HSE + _UNKNOWN_ID, _LSE, _LSI, _HSE_RTC }; static const struct stm32mp1_clk_sel stm32mp1_clk_sel[_PARENT_SEL_NB] = { @@ -639,6 +637,7 @@ static const char * const stm32mp1_clk_parent_name[_PARENT_NB] __unused = { [_HSI_KER] = "HSI_KER", [_HSE_KER] = "HSE_KER", [_HSE_KER_DIV2] = "HSE_KER_DIV2", + [_HSE_RTC] = "HSE_RTC", [_CSI_KER] = "CSI_KER", [_PLL1_P] = "PLL1_P", [_PLL1_Q] = "PLL1_Q", @@ -696,6 +695,7 @@ static unsigned int gate_refcounts[NB_GATES]; static struct spinlock refcount_lock; static struct stm32mp1_pll_settings pll1_settings; static uint32_t current_opp_khz; +static uint32_t save_current_opp_khz; static uint32_t pll3cr; static uint32_t pll4cr; static uint32_t mssckselr; @@ -1063,6 +1063,10 @@ static unsigned long get_clock_rate(int p) case _HSE_KER_DIV2: clock = stm32mp1_clk_get_fixed(_HSE) >> 1; break; + case _HSE_RTC: + clock = stm32mp1_clk_get_fixed(_HSE); + clock /= (mmio_read_32(rcc_base + RCC_RTCDIVR) & RCC_DIVR_DIV_MASK) + 1U; + break; case _LSI: clock = stm32mp1_clk_get_fixed(_LSI); break; @@ -2951,6 +2955,7 @@ static void secure_parent_clocks(unsigned long parent_id) case _HSE: case _HSE_KER: case _HSE_KER_DIV2: + case _HSE_RTC: case _LSE: break; @@ -3238,6 +3243,13 @@ void save_clock_pm_context(void) stm32mp1_pm_save_clock_cfg(offset, (uint8_t *)gate_refcounts, sizeof(gate_refcounts)); + offset += sizeof(gate_refcounts); + + save_current_opp_khz = current_opp_khz; + + stm32mp1_pm_save_clock_cfg(offset, + (uint8_t *)&save_current_opp_khz, + sizeof(save_current_opp_khz)); } void restore_clock_pm_context(void) @@ -3267,6 +3279,13 @@ void restore_clock_pm_context(void) stm32mp1_pm_restore_clock_cfg(offset, (uint8_t *)gate_refcounts, sizeof(gate_refcounts)); + offset += sizeof(gate_refcounts); + + stm32mp1_pm_restore_clock_cfg(offset, + (uint8_t *)&save_current_opp_khz, + sizeof(save_current_opp_khz)); + + stm32mp1_set_opp_khz(save_current_opp_khz); } void stm32mp1_clock_suspend(void) diff --git a/drivers/st/ddr/stm32mp1_ddr.c b/drivers/st/ddr/stm32mp1_ddr.c index 7e8041743e..fb0c7d782f 100644 --- a/drivers/st/ddr/stm32mp1_ddr.c +++ b/drivers/st/ddr/stm32mp1_ddr.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018-2020, STMicroelectronics - All Rights Reserved + * Copyright (C) 2018-2021, STMicroelectronics - All Rights Reserved * * SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */ @@ -1017,9 +1017,14 @@ void stm32mp1_ddr_init(struct ddr_info *priv, /* * 10. configure PUBL PIR register to specify which training * step to run - * Warning : RVTRN is not supported by this PUBL + * RVTRN is executed only on LPDDR2/LPDDR3 */ - stm32mp1_ddrphy_init(priv->phy, DDRPHYC_PIR_QSTRN); + pir = DDRPHYC_PIR_QSTRN; + if ((config->c_reg.mstr & DDRCTRL_MSTR_DDR3) == 0U) { + pir |= DDRPHYC_PIR_RVTRN; + } + + stm32mp1_ddrphy_init(priv->phy, pir); /* 11. monitor PUB PGSR.IDONE to poll cpmpletion of training * sequence diff --git a/drivers/st/ddr/stm32mp1_ram.c b/drivers/st/ddr/stm32mp1_ram.c index 3918eb7be5..d7ee35fec9 100644 --- a/drivers/st/ddr/stm32mp1_ram.c +++ b/drivers/st/ddr/stm32mp1_ram.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018-2020, STMicroelectronics - All Rights Reserved + * Copyright (C) 2018-2021, STMicroelectronics - All Rights Reserved * * SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */ @@ -14,14 +14,12 @@ #include #include #include +#include #include #include #include #include -#define DDR_PATTERN 0xAAAAAAAAU -#define DDR_ANTIPATTERN 0x55555555U - static struct ddr_info ddr_priv_data; static bool ddr_self_refresh; @@ -52,139 +50,6 @@ int stm32mp1_ddr_clk_enable(struct ddr_info *priv, uint32_t mem_speed) return 0; } -/******************************************************************************* - * This function tests a simple read/write access to the DDR. - * Note that the previous content is restored after test. - * Returns 0 if success, and address value else. - ******************************************************************************/ -static uint32_t ddr_test_rw_access(void) -{ - uint32_t saved_value = mmio_read_32(STM32MP_DDR_BASE); - - mmio_write_32(STM32MP_DDR_BASE, DDR_PATTERN); - - if (mmio_read_32(STM32MP_DDR_BASE) != DDR_PATTERN) { - return (uint32_t)STM32MP_DDR_BASE; - } - - mmio_write_32(STM32MP_DDR_BASE, saved_value); - - return 0; -} - -/******************************************************************************* - * This function tests the DDR data bus wiring. - * This is inspired from the Data Bus Test algorithm written by Michael Barr - * in "Programming Embedded Systems in C and C++" book. - * resources.oreilly.com/examples/9781565923546/blob/master/Chapter6/ - * File: memtest.c - This source code belongs to Public Domain. - * Returns 0 if success, and address value else. - ******************************************************************************/ -static uint32_t ddr_test_data_bus(void) -{ - uint32_t pattern; - - for (pattern = 1U; pattern != 0U; pattern <<= 1) { - mmio_write_32(STM32MP_DDR_BASE, pattern); - - if (mmio_read_32(STM32MP_DDR_BASE) != pattern) { - return (uint32_t)STM32MP_DDR_BASE; - } - } - - return 0; -} - -/******************************************************************************* - * This function tests the DDR address bus wiring. - * This is inspired from the Data Bus Test algorithm written by Michael Barr - * in "Programming Embedded Systems in C and C++" book. - * resources.oreilly.com/examples/9781565923546/blob/master/Chapter6/ - * File: memtest.c - This source code belongs to Public Domain. - * Returns 0 if success, and address value else. - ******************************************************************************/ -static uint32_t ddr_test_addr_bus(void) -{ - uint64_t addressmask = (ddr_priv_data.info.size - 1U); - uint64_t offset; - uint64_t testoffset = 0; - - /* Write the default pattern at each of the power-of-two offsets. */ - for (offset = sizeof(uint32_t); (offset & addressmask) != 0U; - offset <<= 1) { - mmio_write_32(STM32MP_DDR_BASE + (uint32_t)offset, - DDR_PATTERN); - } - - /* Check for address bits stuck high. */ - mmio_write_32(STM32MP_DDR_BASE + (uint32_t)testoffset, - DDR_ANTIPATTERN); - - for (offset = sizeof(uint32_t); (offset & addressmask) != 0U; - offset <<= 1) { - if (mmio_read_32(STM32MP_DDR_BASE + (uint32_t)offset) != - DDR_PATTERN) { - return (uint32_t)(STM32MP_DDR_BASE + offset); - } - } - - mmio_write_32(STM32MP_DDR_BASE + (uint32_t)testoffset, DDR_PATTERN); - - /* Check for address bits stuck low or shorted. */ - for (testoffset = sizeof(uint32_t); (testoffset & addressmask) != 0U; - testoffset <<= 1) { - mmio_write_32(STM32MP_DDR_BASE + (uint32_t)testoffset, - DDR_ANTIPATTERN); - - if (mmio_read_32(STM32MP_DDR_BASE) != DDR_PATTERN) { - return STM32MP_DDR_BASE; - } - - for (offset = sizeof(uint32_t); (offset & addressmask) != 0U; - offset <<= 1) { - if ((mmio_read_32(STM32MP_DDR_BASE + - (uint32_t)offset) != DDR_PATTERN) && - (offset != testoffset)) { - return (uint32_t)(STM32MP_DDR_BASE + offset); - } - } - - mmio_write_32(STM32MP_DDR_BASE + (uint32_t)testoffset, - DDR_PATTERN); - } - - return 0; -} - -/******************************************************************************* - * This function checks the DDR size. It has to be run with Data Cache off. - * This test is run before data have been put in DDR, and is only done for - * cold boot. The DDR data can then be overwritten, and it is not useful to - * restore its content. - * Returns DDR computed size. - ******************************************************************************/ -static uint32_t ddr_check_size(void) -{ - uint32_t offset = sizeof(uint32_t); - - mmio_write_32(STM32MP_DDR_BASE, DDR_PATTERN); - - while (offset < STM32MP_DDR_MAX_SIZE) { - mmio_write_32(STM32MP_DDR_BASE + offset, DDR_ANTIPATTERN); - dsb(); - - if (mmio_read_32(STM32MP_DDR_BASE) != DDR_PATTERN) { - break; - } - - offset <<= 1; - } - - INFO("Memory size = 0x%x (%d MB)\n", offset, offset / (1024U * 1024U)); - - return offset; -} - static int stm32mp1_ddr_setup(void) { struct ddr_info *priv = &ddr_priv_data; @@ -249,6 +114,17 @@ static int stm32mp1_ddr_setup(void) INFO("RAM: %s\n", config.info.name); for (idx = 0; idx < ARRAY_SIZE(param); idx++) { + /* Check present field to avoid warning for optional properties */ + if (param[idx].present != NULL) { + if (fdt_getprop(fdt, node, param[idx].name, NULL) == NULL) { + *(param[idx].present) = false; + VERBOSE("%s: %s[0x%x] = absent\n", __func__, + param[idx].name, param[idx].size); + continue; + } + /* Save presence of optional parameters */ + *(param[idx].present) = true; + } ret = fdt_read_uint32_array(fdt, node, param[idx].name, param[idx].size, (void *)((uintptr_t)&config + @@ -256,20 +132,11 @@ static int stm32mp1_ddr_setup(void) VERBOSE("%s: %s[0x%x] = %d\n", __func__, param[idx].name, param[idx].size, ret); - if ((ret != 0) && - ((ret != -FDT_ERR_NOTFOUND) || - (param[idx].present == NULL))) { + if (ret != 0) { ERROR("%s: Cannot read %s, error=%d\n", __func__, param[idx].name, ret); return -EINVAL; } - if (param[idx].present != NULL) { - /* save presence of optional parameters */ - *(param[idx].present) = true; - if (ret == -FDT_ERR_NOTFOUND) { - *(param[idx].present) = false; - } - } } config.self_refresh = false; @@ -297,7 +164,7 @@ static int stm32mp1_ddr_setup(void) } if (config.self_refresh) { - uret = ddr_test_rw_access(); + uret = stm32mp_ddr_test_rw_access(); if (uret != 0U) { ERROR("DDR rw test: Can't access memory @ 0x%x\n", uret); @@ -307,21 +174,21 @@ static int stm32mp1_ddr_setup(void) /* Restore area overwritten by training */ stm32_restore_ddr_training_area(); } else { - uret = ddr_test_data_bus(); + uret = stm32mp_ddr_test_data_bus(); if (uret != 0U) { ERROR("DDR data bus test: can't access memory @ 0x%x\n", uret); panic(); } - uret = ddr_test_addr_bus(); + uret = stm32mp_ddr_test_addr_bus(config.info.size); if (uret != 0U) { ERROR("DDR addr bus test: can't access memory @ 0x%x\n", uret); panic(); } - uret = ddr_check_size(); + uret = stm32mp_ddr_check_size(); if (uret < config.info.size) { ERROR("DDR size: 0x%x does not match DT config: 0x%x\n", uret, config.info.size); diff --git a/drivers/st/ddr/stm32mp_ddr_test.c b/drivers/st/ddr/stm32mp_ddr_test.c new file mode 100644 index 0000000000..45920b7f80 --- /dev/null +++ b/drivers/st/ddr/stm32mp_ddr_test.c @@ -0,0 +1,148 @@ +/* + * Copyright (C) 2021, STMicroelectronics - All Rights Reserved + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include + +#include + +#include + +#define DDR_PATTERN 0xAAAAAAAAU +#define DDR_ANTIPATTERN 0x55555555U + +/******************************************************************************* + * This function tests a simple read/write access to the DDR. + * Note that the previous content is restored after test. + * Returns 0 if success, and address value else. + ******************************************************************************/ +uint32_t stm32mp_ddr_test_rw_access(void) +{ + uint32_t saved_value = mmio_read_32(STM32MP_DDR_BASE); + + mmio_write_32(STM32MP_DDR_BASE, DDR_PATTERN); + + if (mmio_read_32(STM32MP_DDR_BASE) != DDR_PATTERN) { + return (uint32_t)STM32MP_DDR_BASE; + } + + mmio_write_32(STM32MP_DDR_BASE, saved_value); + + return 0; +} + +/******************************************************************************* + * This function tests the DDR data bus wiring. + * This is inspired from the Data Bus Test algorithm written by Michael Barr + * in "Programming Embedded Systems in C and C++" book. + * resources.oreilly.com/examples/9781565923546/blob/master/Chapter6/ + * File: memtest.c - This source code belongs to Public Domain. + * Returns 0 if success, and address value else. + ******************************************************************************/ +uint32_t stm32mp_ddr_test_data_bus(void) +{ + uint32_t pattern; + + for (pattern = 1U; pattern != 0U; pattern <<= 1) { + mmio_write_32(STM32MP_DDR_BASE, pattern); + + if (mmio_read_32(STM32MP_DDR_BASE) != pattern) { + return (uint32_t)STM32MP_DDR_BASE; + } + } + + return 0; +} + +/******************************************************************************* + * This function tests the DDR address bus wiring. + * This is inspired from the Data Bus Test algorithm written by Michael Barr + * in "Programming Embedded Systems in C and C++" book. + * resources.oreilly.com/examples/9781565923546/blob/master/Chapter6/ + * File: memtest.c - This source code belongs to Public Domain. + * size: size in bytes of the DDR memory device. + * Returns 0 if success, and address value else. + ******************************************************************************/ +uint32_t stm32mp_ddr_test_addr_bus(uint64_t size) +{ + uint64_t addressmask = size - 1U; + uint64_t offset; + uint64_t testoffset = 0; + + /* Write the default pattern at each of the power-of-two offsets. */ + for (offset = sizeof(uint32_t); (offset & addressmask) != 0U; + offset <<= 1) { + mmio_write_32(STM32MP_DDR_BASE + (uint32_t)offset, + DDR_PATTERN); + } + + /* Check for address bits stuck high. */ + mmio_write_32(STM32MP_DDR_BASE + (uint32_t)testoffset, + DDR_ANTIPATTERN); + + for (offset = sizeof(uint32_t); (offset & addressmask) != 0U; + offset <<= 1) { + if (mmio_read_32(STM32MP_DDR_BASE + (uint32_t)offset) != + DDR_PATTERN) { + return (uint32_t)(STM32MP_DDR_BASE + offset); + } + } + + mmio_write_32(STM32MP_DDR_BASE + (uint32_t)testoffset, DDR_PATTERN); + + /* Check for address bits stuck low or shorted. */ + for (testoffset = sizeof(uint32_t); (testoffset & addressmask) != 0U; + testoffset <<= 1) { + mmio_write_32(STM32MP_DDR_BASE + (uint32_t)testoffset, + DDR_ANTIPATTERN); + + if (mmio_read_32(STM32MP_DDR_BASE) != DDR_PATTERN) { + return STM32MP_DDR_BASE; + } + + for (offset = sizeof(uint32_t); (offset & addressmask) != 0U; + offset <<= 1) { + if ((mmio_read_32(STM32MP_DDR_BASE + + (uint32_t)offset) != DDR_PATTERN) && + (offset != testoffset)) { + return (uint32_t)(STM32MP_DDR_BASE + offset); + } + } + + mmio_write_32(STM32MP_DDR_BASE + (uint32_t)testoffset, + DDR_PATTERN); + } + + return 0; +} + +/******************************************************************************* + * This function checks the DDR size. It has to be run with Data Cache off. + * This test is run before data have been put in DDR, and is only done for + * cold boot. The DDR data can then be overwritten, and it is not useful to + * restore its content. + * Returns DDR computed size. + ******************************************************************************/ +uint32_t stm32mp_ddr_check_size(void) +{ + uint32_t offset = sizeof(uint32_t); + + mmio_write_32(STM32MP_DDR_BASE, DDR_PATTERN); + + while (offset < STM32MP_DDR_MAX_SIZE) { + mmio_write_32(STM32MP_DDR_BASE + offset, DDR_ANTIPATTERN); + dsb(); + + if (mmio_read_32(STM32MP_DDR_BASE) != DDR_PATTERN) { + break; + } + + offset <<= 1; + } + + INFO("Memory size = 0x%x (%d MB)\n", offset, offset / (1024U * 1024U)); + + return offset; +} diff --git a/drivers/st/fmc/stm32_fmc2_nand.c b/drivers/st/fmc/stm32_fmc2_nand.c index 503e259876..e9ab6dafd8 100644 --- a/drivers/st/fmc/stm32_fmc2_nand.c +++ b/drivers/st/fmc/stm32_fmc2_nand.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2020, STMicroelectronics - All Rights Reserved + * Copyright (c) 2019-2021, STMicroelectronics - All Rights Reserved * * SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */ @@ -201,9 +201,6 @@ static void stm32_fmc2_nand_setup_timing(void) if ((twait < NAND_TCS_MIN) && (tset_mem < (NAND_TCS_MIN - twait))) { tset_mem = NAND_TCS_MIN - twait; } - if ((twait < NAND_TALS_MIN) && (tset_mem < (NAND_TALS_MIN - twait))) { - tset_mem = NAND_TALS_MIN - twait; - } if ((twait > thiz) && ((twait - thiz) < NAND_TDS_MIN) && (tset_mem < (NAND_TDS_MIN - (twait - thiz)))) { tset_mem = NAND_TDS_MIN - (twait - thiz); @@ -245,12 +242,6 @@ static void stm32_fmc2_nand_setup_timing(void) if ((twait < NAND_TCS_MIN) && (tset_att < (NAND_TCS_MIN - twait))) { tset_att = NAND_TCS_MIN - twait; } - if ((twait < NAND_TCLS_MIN) && (tset_att < (NAND_TCLS_MIN - twait))) { - tset_att = NAND_TCLS_MIN - twait; - } - if ((twait < NAND_TALS_MIN) && (tset_att < (NAND_TALS_MIN - twait))) { - tset_att = NAND_TALS_MIN - twait; - } if ((thold_mem < NAND_TRHW_MIN) && (tset_att < (NAND_TRHW_MIN - thold_mem))) { tset_att = NAND_TRHW_MIN - thold_mem; diff --git a/drivers/st/gpio/stm32_gpio.c b/drivers/st/gpio/stm32_gpio.c index 75707e63a1..5c54762ecc 100644 --- a/drivers/st/gpio/stm32_gpio.c +++ b/drivers/st/gpio/stm32_gpio.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2020, STMicroelectronics - All Rights Reserved + * Copyright (c) 2016-2021, STMicroelectronics - All Rights Reserved * * SPDX-License-Identifier: BSD-3-Clause */ @@ -284,3 +284,10 @@ void set_gpio_secure_cfg(uint32_t bank, uint32_t pin, bool secure) clk_disable(clock); } + +void set_gpio_reset_cfg(uint32_t bank, uint32_t pin) +{ + set_gpio(bank, pin, GPIO_MODE_ANALOG, GPIO_SPEED_LOW, + GPIO_NO_PULL, GPIO_ALTERNATE_(0), DT_DISABLED); + set_gpio_secure_cfg(bank, pin, stm32_gpio_is_secure_at_reset(bank)); +} diff --git a/drivers/st/mmc/stm32_sdmmc2.c b/drivers/st/mmc/stm32_sdmmc2.c index 8c203a4c03..c516bdb3d4 100644 --- a/drivers/st/mmc/stm32_sdmmc2.c +++ b/drivers/st/mmc/stm32_sdmmc2.c @@ -186,9 +186,8 @@ static void stm32_sdmmc2_init(void) freq = MIN(sdmmc2_params.max_freq, freq); } - if (sdmmc2_params.vmmc_regu.id != -1) { - stm32mp_regulator_register(&sdmmc2_params.vmmc_regu); - stm32mp_regulator_disable(&sdmmc2_params.vmmc_regu); + if (sdmmc2_params.vmmc_regu != NULL) { + regulator_disable(sdmmc2_params.vmmc_regu); } mdelay(VCC_POWER_OFF_DELAY); @@ -197,8 +196,8 @@ static void stm32_sdmmc2_init(void) SDMMC_POWER_PWRCTRL_PWR_CYCLE | sdmmc2_params.dirpol); mdelay(POWER_CYCLE_DELAY); - if (sdmmc2_params.vmmc_regu.id != -1) { - stm32mp_regulator_enable(&sdmmc2_params.vmmc_regu); + if (sdmmc2_params.vmmc_regu != NULL) { + regulator_enable(sdmmc2_params.vmmc_regu); } mdelay(VCC_POWER_ON_DELAY); @@ -758,10 +757,7 @@ static int stm32_sdmmc2_dt_get_config(void) sdmmc2_params.max_freq = fdt32_to_cpu(*cuint); } - cuint = fdt_getprop(fdt, sdmmc_node, "vmmc-supply", NULL); - if (cuint != NULL) { - sdmmc2_params.vmmc_regu.id = fdt32_to_cpu(*cuint); - } + sdmmc2_params.vmmc_regu = regulator_get_by_supply_name(fdt, sdmmc_node, "vmmc"); return 0; } @@ -783,7 +779,7 @@ int stm32_sdmmc2_mmc_init(struct stm32_sdmmc2_params *params) memcpy(&sdmmc2_params, params, sizeof(struct stm32_sdmmc2_params)); - sdmmc2_params.vmmc_regu.id = -1; + sdmmc2_params.vmmc_regu = NULL; if (stm32_sdmmc2_dt_get_config() != 0) { ERROR("%s: DT error\n", __func__); diff --git a/drivers/st/pmic/stm32mp_pmic.c b/drivers/st/pmic/stm32mp_pmic.c index 4e505debdf..e8cadcda0a 100644 --- a/drivers/st/pmic/stm32mp_pmic.c +++ b/drivers/st/pmic/stm32mp_pmic.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2020, STMicroelectronics - All Rights Reserved + * Copyright (c) 2017-2021, STMicroelectronics - All Rights Reserved * * SPDX-License-Identifier: BSD-3-Clause */ @@ -13,30 +13,21 @@ #include #include +#include #include #include #include #include +#include #include -#define STPMIC1_LDO12356_OUTPUT_MASK (uint8_t)(GENMASK(6, 2)) -#define STPMIC1_LDO12356_OUTPUT_SHIFT 2 -#define STPMIC1_LDO3_MODE (uint8_t)(BIT(7)) -#define STPMIC1_LDO3_DDR_SEL 31U - -#define STPMIC1_BUCK_OUTPUT_SHIFT 2 -#define STPMIC1_BUCK3_1V8 (39U << STPMIC1_BUCK_OUTPUT_SHIFT) - -#define REGULATOR_MODE_STANDBY 8U - -#define STPMIC1_DEFAULT_START_UP_DELAY_MS 1 - -#define CMD_GET_MIN_VOLTAGE 0U -#define CMD_CONFIG_BOOT_ON 1U -#define CMD_CONFIG_LP 2U - static struct i2c_handle_s i2c_handle; static uint32_t pmic_i2c_addr; +#if defined(IMAGE_BL32) +static struct spinlock lock; +#endif + +static int register_pmic(void); static int dt_get_pmic_node(void *fdt) { @@ -84,235 +75,6 @@ static bool dt_pmic_is_secure(void) (i2c_handle.dt_status == DT_SECURE); } -static int dt_pmic_get_regulator_voltage(void *fdt, int node, - uint16_t *min_mv, uint16_t *max_mv) -{ - const fdt32_t *cuint; - - cuint = fdt_getprop(fdt, node, "regulator-min-microvolt", NULL); - if (cuint == NULL) { - return -FDT_ERR_NOTFOUND; - } - - if (min_mv != NULL) { - *min_mv = (uint16_t)(fdt32_to_cpu(*cuint) / 1000U); - } - - cuint = fdt_getprop(fdt, node, "regulator-max-microvolt", NULL); - if (cuint == NULL) { - return -FDT_ERR_NOTFOUND; - } - - if (max_mv != NULL) { - *max_mv = (uint16_t)(fdt32_to_cpu(*cuint) / 1000U); - } - - return 0; -} - -static int pmic_config_boot_on(void *fdt, int node, const char *regu_name) -{ - uint16_t voltage = 0U; - uint16_t voltage_min; - uint16_t voltage_max; - int status; - int pmic_voltage; - - if ((fdt_getprop(fdt, node, "regulator-boot-on", NULL) == NULL) && - (fdt_getprop(fdt, node, "regulator-always-on", NULL) == NULL)) { - return 0; - } - - if (fdt_getprop(fdt, node, "regulator-pull-down", NULL) != NULL) { - - status = stpmic1_regulator_pull_down_set(regu_name); - if (status < 0) { - return status; - } - } - - if (fdt_getprop(fdt, node, "st,mask-reset", NULL) != NULL) { - - status = stpmic1_regulator_mask_reset_set(regu_name); - if (status < 0) { - return status; - } - } - - if (dt_pmic_get_regulator_voltage(fdt, node, &voltage_min, - &voltage_max) < 0) { - return 0; - } - - pmic_voltage = stpmic1_regulator_voltage_get(regu_name); - if (pmic_voltage < 0) { - return pmic_voltage; - } - - if ((uint16_t)pmic_voltage < voltage_min) { - voltage = voltage_min; - } - - if ((uint16_t)pmic_voltage > voltage_max) { - voltage = voltage_max; - } - - /* Only re-program voltage if not in the range provided in DT. */ - if (voltage != 0U) { - status = stpmic1_regulator_voltage_set(regu_name, voltage); - if (status < 0) { - return status; - } - } - - if (!stpmic1_is_regulator_enabled(regu_name)) { - status = stpmic1_regulator_enable(regu_name); - if (status < 0) { - return status; - } - } - - return 0; -} - -#if defined(IMAGE_BL32) -static int pmic_config_lp(void *fdt, int node, const char *node_name, - const char *regu_name) -{ - int status; - const fdt32_t *cuint; - int regulator_state_node; - - status = stpmic1_powerctrl_on(); - if (status < 0) { - return status; - }; - - /* - * First, copy active configuration (Control register) to - * PWRCTRL Control register, even if regulator_state_node - * does not exist. - */ - status = stpmic1_lp_copy_reg(regu_name); - if (status < 0) { - return status; - } - - /* Then apply configs from regulator_state_node */ - regulator_state_node = fdt_subnode_offset(fdt, node, node_name); - if (regulator_state_node <= 0) { - return 0; - } - - if (fdt_getprop(fdt, regulator_state_node, "regulator-on-in-suspend", - NULL) != NULL) { - status = stpmic1_lp_reg_on_off(regu_name, 1); - if (status < 0) { - return status; - } - } - - if (fdt_getprop(fdt, regulator_state_node, "regulator-off-in-suspend", - NULL) != NULL) { - status = stpmic1_lp_reg_on_off(regu_name, 0); - if (status < 0) { - return status; - } - } - - cuint = fdt_getprop(fdt, regulator_state_node, - "regulator-suspend-microvolt", NULL); - if (cuint != NULL) { - uint16_t voltage = (uint16_t)(fdt32_to_cpu(*cuint) / 1000U); - - status = stpmic1_lp_set_voltage(regu_name, voltage); - if (status < 0) { - return status; - } - } - - cuint = fdt_getprop(fdt, regulator_state_node, "regulator-mode", NULL); - if (cuint != NULL) { - if (fdt32_to_cpu(*cuint) == REGULATOR_MODE_STANDBY) { - status = stpmic1_lp_set_mode(regu_name, 1); - if (status < 0) { - return status; - } - } - } - - return 0; -} -#endif - -static int pmic_operate(uint8_t command, const char *node_name, - uint16_t *voltage_mv) -{ - int pmic_node, regulators_node, subnode; - void *fdt; - int ret = -EIO; - - if (fdt_get_address(&fdt) == 0) { - return -ENOENT; - } - - pmic_node = dt_get_pmic_node(fdt); - if (pmic_node < 0) { - return -ENOENT; - } - - regulators_node = fdt_subnode_offset(fdt, pmic_node, "regulators"); - if (regulators_node < 0) { - return -ENOENT; - } - - fdt_for_each_subnode(subnode, fdt, regulators_node) { - const char *regu_name = fdt_get_name(fdt, subnode, NULL); - - switch (command) { - case CMD_GET_MIN_VOLTAGE: - assert(node_name != NULL); - assert(voltage_mv != NULL); - - if (strcmp(regu_name, node_name) != 0) { - continue; - } - - ret = dt_pmic_get_regulator_voltage(fdt, subnode, - voltage_mv, NULL); - if (ret < 0) { - return -ENXIO; - } - - return ret; - - case CMD_CONFIG_BOOT_ON: - ret = pmic_config_boot_on(fdt, subnode, regu_name); - if (ret < 0) { - return ret; - } - break; - -#if defined(IMAGE_BL32) - case CMD_CONFIG_LP: - assert(node_name != NULL); - - ret = pmic_config_lp(fdt, subnode, node_name, - regu_name); - if (ret < 0) { - return ret; - } - break; -#endif - - default: - return -EINVAL; - } - } - - return ret; -} - /* * Get PMIC and its I2C bus configuration from the device tree. * Return 0 on success, negative on error, 1 if no PMIC node is defined. @@ -360,66 +122,6 @@ static int dt_pmic_i2c_config(struct dt_node_info *i2c_info, return stm32_i2c_get_setup_from_fdt(i2c_node, init); } -int pmic_configure_boot_on_regulators(void) -{ - return pmic_operate(CMD_CONFIG_BOOT_ON, NULL, NULL); -} - -int pmic_set_lp_config(const char *node_name) -{ - return pmic_operate(CMD_CONFIG_LP, node_name, NULL); -} - -int dt_pmic_find_supply(const char **supply_name, const char *regu_name) -{ - int pmic_node, regulators_node, subnode; - void *fdt; - - if (fdt_get_address(&fdt) == 0) { - return -FDT_ERR_NOTFOUND; - } - - pmic_node = dt_get_pmic_node(fdt); - if (pmic_node < 0) { - return -FDT_ERR_NOTFOUND; - } - - regulators_node = fdt_subnode_offset(fdt, pmic_node, "regulators"); - if (regulators_node < 0) { - return -FDT_ERR_NOTFOUND; - } - - fdt_for_each_subnode(subnode, fdt, regulators_node) { - const char *name; - - name = fdt_getprop(fdt, subnode, "regulator-name", NULL); - if ((name != NULL) && - (strcmp(name, regu_name) == 0)) { - *supply_name = fdt_get_name(fdt, subnode, NULL); - return 0; - } - } - - return -FDT_ERR_NOTFOUND; -} - -int pmic_set_regulator_min_voltage(const char *regu_name) -{ - int rc = -ENOENT; - const char *supply_name; - - if (dt_pmic_find_supply(&supply_name, regu_name) == 0) { - uint16_t min_mv; - - rc = pmic_operate(CMD_GET_MIN_VOLTAGE, supply_name, &min_mv); - if (rc == 0) { - rc = stpmic1_regulator_voltage_set(supply_name, min_mv); - } - } - - return rc; -} - bool initialize_pmic_i2c(void) { int ret; @@ -483,62 +185,6 @@ static void register_pmic_shared_peripherals(void) } } -static int pmic_regulator_enable(struct stm32mp_regulator *regu) -{ - void *fdt; - const char *node_name; - - if (fdt_get_address(&fdt) == 0) { - return -ENOENT; - } - - node_name = fdt_get_name(fdt, fdt_node_offset_by_phandle(fdt, regu->id), - NULL); - - return stpmic1_regulator_enable(node_name); -} - -static int pmic_regulator_disable(struct stm32mp_regulator *regu) -{ - void *fdt; - const char *node_name; - - if (fdt_get_address(&fdt) == 0) { - return -ENOENT; - } - - node_name = fdt_get_name(fdt, fdt_node_offset_by_phandle(fdt, regu->id), - NULL); - - return stpmic1_regulator_disable(node_name); -} - -static const struct stm32mp_regulator_ops pmic_regu_ops = { - .enable = pmic_regulator_enable, - .disable = pmic_regulator_disable, -}; - -bool is_pmic_regulator(struct stm32mp_regulator *regu) -{ - void *fdt; - int parent_node; - - if (fdt_get_address(&fdt) == 0) { - return false; - } - - parent_node = fdt_parent_offset(fdt, - fdt_node_offset_by_phandle(fdt, - regu->id)); - return (fdt_node_check_compatible(fdt, parent_node, - "st,stpmic1-regulators") == 0); -} - -void bind_pmic_regulator(struct stm32mp_regulator *regu) -{ - regu->ops = &pmic_regu_ops; -} - void initialize_pmic(void) { if (!initialize_pmic_i2c()) { @@ -547,13 +193,15 @@ void initialize_pmic(void) } register_pmic_shared_peripherals(); -} -void configure_pmic(void) -{ - if (pmic_configure_boot_on_regulators() < 0) { + if (register_pmic() < 0) { panic(); - }; + } + + if (stpmic1_powerctrl_on() < 0) { + panic(); + } + } #if DEBUG @@ -567,65 +215,61 @@ void print_pmic_info_and_debug(void) } INFO("PMIC version = 0x%02lx\n", pmic_version); - stpmic1_dump_regulators(); +#if defined(IMAGE_BL32) +#if LOG_LEVEL >= LOG_LEVEL_VERBOSE + regulator_core_dump(); +#endif +#endif } #endif int pmic_ddr_power_init(enum ddr_type ddr_type) { - bool buck3_at_1v8 = false; - uint8_t read_val; int status; - uint16_t buck2_mv; - uint16_t ldo3_mv; + uint16_t buck3_min_mv; + struct rdev *buck2, *buck3, *ldo3, *vref; - if (pmic_operate(CMD_GET_MIN_VOLTAGE, "buck2", &buck2_mv) != 0) { - return -EPERM; + buck2 = regulator_get_by_name("buck2"); + if (buck2 == NULL) { + return -ENOENT; } - switch (ddr_type) { - case STM32MP_DDR3: - /* Set LDO3 to sync mode */ - status = stpmic1_register_read(LDO3_CONTROL_REG, &read_val); - if (status != 0) { - return status; - } + ldo3 = regulator_get_by_name("ldo3"); + if (ldo3 == NULL) { + return -ENOENT; + } - read_val &= ~STPMIC1_LDO3_MODE; - read_val &= ~STPMIC1_LDO12356_OUTPUT_MASK; - read_val |= STPMIC1_LDO3_DDR_SEL << - STPMIC1_LDO12356_OUTPUT_SHIFT; + vref = regulator_get_by_name("vref_ddr"); + if (vref == NULL) { + return -ENOENT; + } - status = stpmic1_register_write(LDO3_CONTROL_REG, read_val); + switch (ddr_type) { + case STM32MP_DDR3: + status = regulator_set_flag(ldo3, REGUL_SINK_SOURCE); if (status != 0) { return status; } - status = stpmic1_regulator_voltage_set("buck2", buck2_mv); + status = regulator_set_min_voltage(buck2); if (status != 0) { return status; } - status = stpmic1_regulator_enable("buck2"); + status = regulator_enable(buck2); if (status != 0) { return status; } - mdelay(STPMIC1_DEFAULT_START_UP_DELAY_MS); - - status = stpmic1_regulator_enable("vref_ddr"); + status = regulator_enable(vref); if (status != 0) { return status; } - mdelay(STPMIC1_DEFAULT_START_UP_DELAY_MS); - - status = stpmic1_regulator_enable("ldo3"); + status = regulator_enable(ldo3); if (status != 0) { return status; } - - mdelay(STPMIC1_DEFAULT_START_UP_DELAY_MS); break; case STM32MP_LPDDR2: @@ -635,70 +279,280 @@ int pmic_ddr_power_init(enum ddr_type ddr_type) * Set LDO3 to bypass mode if BUCK3 = 1.8V * Set LDO3 to normal mode if BUCK3 != 1.8V */ - status = stpmic1_register_read(BUCK3_CONTROL_REG, &read_val); - if (status != 0) { - return status; - } - - if ((read_val & STPMIC1_BUCK3_1V8) == STPMIC1_BUCK3_1V8) { - buck3_at_1v8 = true; + buck3 = regulator_get_by_name("buck3"); + if (buck3 == NULL) { + return -ENOENT; } - status = stpmic1_register_read(LDO3_CONTROL_REG, &read_val); - if (status != 0) { - return status; - } + regulator_get_range(buck3, &buck3_min_mv, NULL); - read_val &= ~STPMIC1_LDO3_MODE; - read_val &= ~STPMIC1_LDO12356_OUTPUT_MASK; - if (buck3_at_1v8) { - read_val |= STPMIC1_LDO3_MODE; + if (buck3_min_mv != 1800) { + status = regulator_set_min_voltage(ldo3); + if (status != 0) { + return status; + } + } else { + status = regulator_set_flag(ldo3, REGUL_ENABLE_BYPASS); + if (status != 0) { + return status; + } } - status = stpmic1_register_write(LDO3_CONTROL_REG, read_val); + status = regulator_set_min_voltage(buck2); if (status != 0) { return status; } - if (pmic_operate(CMD_GET_MIN_VOLTAGE, "ldo3", &ldo3_mv) != 0) { - return -EPERM; - } - - status = stpmic1_regulator_voltage_set("ldo3", ldo3_mv); + status = regulator_enable(ldo3); if (status != 0) { return status; } - status = stpmic1_regulator_voltage_set("buck2", buck2_mv); + status = regulator_enable(buck2); if (status != 0) { return status; } - status = stpmic1_regulator_enable("ldo3"); + status = regulator_enable(vref); if (status != 0) { return status; } + break; + + default: + break; + }; - mdelay(STPMIC1_DEFAULT_START_UP_DELAY_MS); + return 0; +} - status = stpmic1_regulator_enable("buck2"); - if (status != 0) { - return status; +void pmic_switch_off(void) +{ + stpmic1_switch_off(); + udelay(100); + + /* Shouldn't be reached */ + panic(); +} + +enum { + STPMIC1_BUCK1 = 0, + STPMIC1_BUCK2, + STPMIC1_BUCK3, + STPMIC1_BUCK4, + STPMIC1_LDO1, + STPMIC1_LDO2, + STPMIC1_LDO3, + STPMIC1_LDO4, + STPMIC1_LDO5, + STPMIC1_LDO6, + STPMIC1_VREF_DDR, + STPMIC1_BOOST, + STPMIC1_VBUS_OTG, + STPMIC1_SW_OUT, +}; + +static int pmic_set_state(const struct regul_description *desc, bool enable) +{ + VERBOSE("%s: set state to %u\n", desc->node_name, enable); + + if (enable == STATE_ENABLE) { + return stpmic1_regulator_enable(desc->node_name); + } else { + return stpmic1_regulator_disable(desc->node_name); + } +} + +static int pmic_get_state(const struct regul_description *desc) +{ + VERBOSE("%s: get state\n", desc->node_name); + + return stpmic1_is_regulator_enabled(desc->node_name); +} + +static int pmic_get_voltage(const struct regul_description *desc) +{ + VERBOSE("%s: get volt\n", desc->node_name); + + return stpmic1_regulator_voltage_get(desc->node_name); +} + +static int pmic_set_voltage(const struct regul_description *desc, uint16_t mv) +{ + VERBOSE("%s: get volt\n", desc->node_name); + + return stpmic1_regulator_voltage_set(desc->node_name, mv); +} + +static int pmic_list_voltages(const struct regul_description *desc, + const uint16_t **levels, size_t *count) +{ + VERBOSE("%s: list volt\n", desc->node_name); + + return stpmic1_regulator_levels_mv(desc->node_name, levels, count); +} + +static int pmic_set_flag(const struct regul_description *desc, uint16_t flag) +{ + VERBOSE("%s: set_flag 0x%x\n", desc->node_name, flag); + + switch (flag) { + case REGUL_OCP: + return stpmic1_regulator_icc_set(desc->node_name); + + case REGUL_ACTIVE_DISCHARGE: + return stpmic1_active_discharge_mode_set(desc->node_name); + + case REGUL_PULL_DOWN: + return stpmic1_regulator_pull_down_set(desc->node_name); + + case REGUL_MASK_RESET: + return stpmic1_regulator_mask_reset_set(desc->node_name); + + case REGUL_SINK_SOURCE: + return stpmic1_regulator_sink_mode_set(desc->node_name); + + case REGUL_ENABLE_BYPASS: + return stpmic1_regulator_bypass_mode_set(desc->node_name); + + default: + return -EINVAL; + } +} + +#if defined(IMAGE_BL32) +static int driver_suspend(const struct regul_description *desc, uint8_t state, uint16_t mv) +{ + int ret; + + VERBOSE("%s: suspend state:%d volt:%d\n", desc->node_name, (int)state, mv); + + ret = stpmic1_lp_copy_reg(desc->node_name); + if (ret != 0) { + return ret; + } + + if ((state & LP_STATE_OFF) != 0U) { + ret = stpmic1_lp_reg_on_off(desc->node_name, 0); + if (ret != 0) { + return ret; } + } - mdelay(STPMIC1_DEFAULT_START_UP_DELAY_MS); + if ((state & LP_STATE_ON) != 0U) { + ret = stpmic1_lp_reg_on_off(desc->node_name, 1); + if (ret != 0) { + return ret; + } + } - status = stpmic1_regulator_enable("vref_ddr"); - if (status != 0) { - return status; + if ((state & LP_STATE_SET_VOLT) != 0U) { + ret = stpmic1_lp_set_voltage(desc->node_name, mv); + if (ret != 0) { + return ret; } + } - mdelay(STPMIC1_DEFAULT_START_UP_DELAY_MS); - break; + return 0; +} - default: - break; - }; +static void driver_lock(const struct regul_description *desc) +{ + if (stm32mp_lock_available()) { + spin_lock(&lock); + } +} + +static void driver_unlock(const struct regul_description *desc) +{ + if (stm32mp_lock_available()) { + spin_unlock(&lock); + } +} +#endif + +struct regul_ops pmic_ops = { + .set_state = pmic_set_state, + .get_state = pmic_get_state, + .set_voltage = pmic_set_voltage, + .get_voltage = pmic_get_voltage, + .list_voltages = pmic_list_voltages, + .set_flag = pmic_set_flag, +#if defined(IMAGE_BL32) + .lock = driver_lock, + .unlock = driver_unlock, + .suspend = driver_suspend, +#endif +}; + +#define DEFINE_REGU(name) { \ + .node_name = name, \ + .ops = &pmic_ops, \ + .driver_data = NULL, \ + .enable_ramp_delay = 1000, \ +} + +static const struct regul_description pmic_regs[] = { + [STPMIC1_BUCK1] = DEFINE_REGU("buck1"), + [STPMIC1_BUCK2] = DEFINE_REGU("buck2"), + [STPMIC1_BUCK3] = DEFINE_REGU("buck3"), + [STPMIC1_BUCK4] = DEFINE_REGU("buck4"), + [STPMIC1_LDO1] = DEFINE_REGU("ldo1"), + [STPMIC1_LDO2] = DEFINE_REGU("ldo2"), + [STPMIC1_LDO3] = DEFINE_REGU("ldo3"), + [STPMIC1_LDO4] = DEFINE_REGU("ldo4"), + [STPMIC1_LDO5] = DEFINE_REGU("ldo5"), + [STPMIC1_LDO6] = DEFINE_REGU("ldo6"), + [STPMIC1_VREF_DDR] = DEFINE_REGU("vref_ddr"), + [STPMIC1_BOOST] = DEFINE_REGU("boost"), + [STPMIC1_VBUS_OTG] = DEFINE_REGU("pwr_sw1"), + [STPMIC1_SW_OUT] = DEFINE_REGU("pwr_sw2"), +}; + +#define NB_REG ARRAY_SIZE(pmic_regs) + +static int register_pmic(void) +{ + void *fdt; + int pmic_node, regulators_node, subnode; + + VERBOSE("Register pmic\n"); + + if (fdt_get_address(&fdt) == 0) { + return -FDT_ERR_NOTFOUND; + } + + pmic_node = dt_get_pmic_node(fdt); + if (pmic_node < 0) { + return pmic_node; + } + + regulators_node = fdt_subnode_offset(fdt, pmic_node, "regulators"); + if (regulators_node < 0) { + return -ENOENT; + } + + fdt_for_each_subnode(subnode, fdt, regulators_node) { + const char *reg_name = fdt_get_name(fdt, subnode, NULL); + const struct regul_description *desc; + unsigned int i; + int ret; + + for (i = 0; i < NB_REG; i++) { + desc = &pmic_regs[i]; + if (strcmp(desc->node_name, reg_name) == 0) { + break; + } + } + assert(i < NB_REG); + + ret = regulator_register(desc, subnode); + if (ret != 0) { + WARN("%s:%d failed to register %s\n", __func__, + __LINE__, reg_name); + return ret; + } + } return 0; } diff --git a/drivers/st/pmic/stpmic1.c b/drivers/st/pmic/stpmic1.c index a1db120dc1..c33ef47944 100644 --- a/drivers/st/pmic/stpmic1.c +++ b/drivers/st/pmic/stpmic1.c @@ -17,15 +17,23 @@ struct regul_struct { const uint16_t *voltage_table; uint8_t voltage_table_size; uint8_t control_reg; + uint8_t enable_mask; uint8_t low_power_reg; uint8_t pull_down_reg; uint8_t pull_down; uint8_t mask_reset_reg; uint8_t mask_reset; + uint8_t icc_reg; + uint8_t icc_mask; }; static struct i2c_handle_s *pmic_i2c_handle; static uint16_t pmic_i2c_addr; +/* + * Special mode corresponds to LDO3 in sink source mode or in bypass mode. + * LDO3 doesn't switch back from special to normal mode. + */ +static bool ldo3_special_mode; /* Voltage tables in mV */ static const uint16_t buck1_voltage_table[] = { @@ -346,8 +354,11 @@ static const uint16_t ldo3_voltage_table[] = { 3300, 3300, 3300, - 500, - 0xFFFF, /* VREFDDR */ +}; + +/* Special mode table is used for sink source OR bypass mode */ +static const uint16_t ldo3_special_mode_table[] = { + 0, }; static const uint16_t ldo5_voltage_table[] = { @@ -431,104 +442,135 @@ static const struct regul_struct regulators_table[] = { .voltage_table = buck1_voltage_table, .voltage_table_size = ARRAY_SIZE(buck1_voltage_table), .control_reg = BUCK1_CONTROL_REG, + .enable_mask = LDO_BUCK_ENABLE_MASK, .low_power_reg = BUCK1_PWRCTRL_REG, .pull_down_reg = BUCK_PULL_DOWN_REG, .pull_down = BUCK1_PULL_DOWN_SHIFT, .mask_reset_reg = MASK_RESET_BUCK_REG, .mask_reset = BUCK1_MASK_RESET, + .icc_reg = BUCK_ICC_TURNOFF_REG, + .icc_mask = BUCK1_ICC_SHIFT, }, { .dt_node_name = "buck2", .voltage_table = buck2_voltage_table, .voltage_table_size = ARRAY_SIZE(buck2_voltage_table), .control_reg = BUCK2_CONTROL_REG, + .enable_mask = LDO_BUCK_ENABLE_MASK, .low_power_reg = BUCK2_PWRCTRL_REG, .pull_down_reg = BUCK_PULL_DOWN_REG, .pull_down = BUCK2_PULL_DOWN_SHIFT, .mask_reset_reg = MASK_RESET_BUCK_REG, .mask_reset = BUCK2_MASK_RESET, + .icc_reg = BUCK_ICC_TURNOFF_REG, + .icc_mask = BUCK2_ICC_SHIFT, }, { .dt_node_name = "buck3", .voltage_table = buck3_voltage_table, .voltage_table_size = ARRAY_SIZE(buck3_voltage_table), .control_reg = BUCK3_CONTROL_REG, + .enable_mask = LDO_BUCK_ENABLE_MASK, .low_power_reg = BUCK3_PWRCTRL_REG, .pull_down_reg = BUCK_PULL_DOWN_REG, .pull_down = BUCK3_PULL_DOWN_SHIFT, .mask_reset_reg = MASK_RESET_BUCK_REG, .mask_reset = BUCK3_MASK_RESET, + .icc_reg = BUCK_ICC_TURNOFF_REG, + .icc_mask = BUCK3_ICC_SHIFT, }, { .dt_node_name = "buck4", .voltage_table = buck4_voltage_table, .voltage_table_size = ARRAY_SIZE(buck4_voltage_table), .control_reg = BUCK4_CONTROL_REG, + .enable_mask = LDO_BUCK_ENABLE_MASK, .low_power_reg = BUCK4_PWRCTRL_REG, .pull_down_reg = BUCK_PULL_DOWN_REG, .pull_down = BUCK4_PULL_DOWN_SHIFT, .mask_reset_reg = MASK_RESET_BUCK_REG, .mask_reset = BUCK4_MASK_RESET, + .icc_reg = BUCK_ICC_TURNOFF_REG, + .icc_mask = BUCK4_ICC_SHIFT, }, { .dt_node_name = "ldo1", .voltage_table = ldo1_voltage_table, .voltage_table_size = ARRAY_SIZE(ldo1_voltage_table), .control_reg = LDO1_CONTROL_REG, + .enable_mask = LDO_BUCK_ENABLE_MASK, .low_power_reg = LDO1_PWRCTRL_REG, .mask_reset_reg = MASK_RESET_LDO_REG, .mask_reset = LDO1_MASK_RESET, + .icc_reg = LDO_ICC_TURNOFF_REG, + .icc_mask = LDO1_ICC_SHIFT, }, { .dt_node_name = "ldo2", .voltage_table = ldo2_voltage_table, .voltage_table_size = ARRAY_SIZE(ldo2_voltage_table), .control_reg = LDO2_CONTROL_REG, + .enable_mask = LDO_BUCK_ENABLE_MASK, .low_power_reg = LDO2_PWRCTRL_REG, .mask_reset_reg = MASK_RESET_LDO_REG, .mask_reset = LDO2_MASK_RESET, + .icc_reg = LDO_ICC_TURNOFF_REG, + .icc_mask = LDO2_ICC_SHIFT, }, { .dt_node_name = "ldo3", .voltage_table = ldo3_voltage_table, .voltage_table_size = ARRAY_SIZE(ldo3_voltage_table), .control_reg = LDO3_CONTROL_REG, + .enable_mask = LDO_BUCK_ENABLE_MASK, .low_power_reg = LDO3_PWRCTRL_REG, .mask_reset_reg = MASK_RESET_LDO_REG, .mask_reset = LDO3_MASK_RESET, + .icc_reg = LDO_ICC_TURNOFF_REG, + .icc_mask = LDO3_ICC_SHIFT, }, { .dt_node_name = "ldo4", .voltage_table = ldo4_voltage_table, .voltage_table_size = ARRAY_SIZE(ldo4_voltage_table), .control_reg = LDO4_CONTROL_REG, + .enable_mask = LDO_BUCK_ENABLE_MASK, .low_power_reg = LDO4_PWRCTRL_REG, .mask_reset_reg = MASK_RESET_LDO_REG, .mask_reset = LDO4_MASK_RESET, + .icc_reg = LDO_ICC_TURNOFF_REG, + .icc_mask = LDO4_ICC_SHIFT, }, { .dt_node_name = "ldo5", .voltage_table = ldo5_voltage_table, .voltage_table_size = ARRAY_SIZE(ldo5_voltage_table), .control_reg = LDO5_CONTROL_REG, + .enable_mask = LDO_BUCK_ENABLE_MASK, .low_power_reg = LDO5_PWRCTRL_REG, .mask_reset_reg = MASK_RESET_LDO_REG, .mask_reset = LDO5_MASK_RESET, + .icc_reg = LDO_ICC_TURNOFF_REG, + .icc_mask = LDO5_ICC_SHIFT, }, { .dt_node_name = "ldo6", .voltage_table = ldo6_voltage_table, .voltage_table_size = ARRAY_SIZE(ldo6_voltage_table), .control_reg = LDO6_CONTROL_REG, + .enable_mask = LDO_BUCK_ENABLE_MASK, .low_power_reg = LDO6_PWRCTRL_REG, .mask_reset_reg = MASK_RESET_LDO_REG, .mask_reset = LDO6_MASK_RESET, + .icc_reg = LDO_ICC_TURNOFF_REG, + .icc_mask = LDO6_ICC_SHIFT, }, { .dt_node_name = "vref_ddr", .voltage_table = vref_ddr_voltage_table, .voltage_table_size = ARRAY_SIZE(vref_ddr_voltage_table), .control_reg = VREF_DDR_CONTROL_REG, + .enable_mask = LDO_BUCK_ENABLE_MASK, .low_power_reg = VREF_DDR_PWRCTRL_REG, .mask_reset_reg = MASK_RESET_LDO_REG, .mask_reset = VREF_DDR_MASK_RESET, @@ -538,21 +580,27 @@ static const struct regul_struct regulators_table[] = { .voltage_table = fixed_5v_voltage_table, .voltage_table_size = ARRAY_SIZE(fixed_5v_voltage_table), .control_reg = USB_CONTROL_REG, - .mask_reset = BOOST_ENABLED, + .enable_mask = BOOST_ENABLED, + .icc_reg = BUCK_ICC_TURNOFF_REG, + .icc_mask = BOOST_ICC_SHIFT, }, { .dt_node_name = "pwr_sw1", .voltage_table = fixed_5v_voltage_table, .voltage_table_size = ARRAY_SIZE(fixed_5v_voltage_table), .control_reg = USB_CONTROL_REG, - .mask_reset = USBSW_OTG_SWITCH_ENABLED, + .enable_mask = USBSW_OTG_SWITCH_ENABLED, + .icc_reg = BUCK_ICC_TURNOFF_REG, + .icc_mask = PWR_SW1_ICC_SHIFT, }, { .dt_node_name = "pwr_sw2", .voltage_table = fixed_5v_voltage_table, .voltage_table_size = ARRAY_SIZE(fixed_5v_voltage_table), .control_reg = USB_CONTROL_REG, - .mask_reset = SWIN_SWOUT_ENABLED, + .enable_mask = SWIN_SWOUT_ENABLED, + .icc_reg = BUCK_ICC_TURNOFF_REG, + .icc_mask = PWR_SW2_ICC_SHIFT, }, }; @@ -607,8 +655,8 @@ int stpmic1_regulator_enable(const char *name) { const struct regul_struct *regul = get_regulator_data(name); - return stpmic1_register_update(regul->control_reg, LDO_BUCK_ENABLE_MASK, - LDO_BUCK_ENABLE_MASK); + return stpmic1_register_update(regul->control_reg, regul->enable_mask, + regul->enable_mask); } int stpmic1_regulator_disable(const char *name) @@ -616,7 +664,7 @@ int stpmic1_regulator_disable(const char *name) const struct regul_struct *regul = get_regulator_data(name); return stpmic1_register_update(regul->control_reg, 0, - LDO_BUCK_ENABLE_MASK); + regul->enable_mask); } bool stpmic1_is_regulator_enabled(const char *name) @@ -628,7 +676,7 @@ bool stpmic1_is_regulator_enabled(const char *name) panic(); } - return (val & LDO_BUCK_ENABLE_MASK) == LDO_BUCK_ENABLE_MASK; + return (val & regul->enable_mask) == regul->enable_mask; } int stpmic1_regulator_voltage_set(const char *name, uint16_t millivolts) @@ -637,6 +685,16 @@ int stpmic1_regulator_voltage_set(const char *name, uint16_t millivolts) const struct regul_struct *regul = get_regulator_data(name); uint8_t mask; + if ((strncmp(name, "ldo3", 4) == 0) && ldo3_special_mode) { + /* + * when the LDO3 is in special mode, we do not change voltage, + * because by setting voltage, the LDO would leaves sink-source + * mode. There is obviously no reason to leave sink-source mode + * at runtime. + */ + return 0; + } + /* Voltage can be set for buck or ldo (except ldo4) regulators */ if (strncmp(name, "buck", 4) == 0) { mask = BUCK_VOLTAGE_MASK; @@ -670,12 +728,74 @@ int stpmic1_regulator_mask_reset_set(const char *name) { const struct regul_struct *regul = get_regulator_data(name); + if (regul->mask_reset_reg == 0U) { + return -EPERM; + } + return stpmic1_register_update(regul->mask_reset_reg, BIT(regul->mask_reset), LDO_BUCK_RESET_MASK << regul->mask_reset); } +int stpmic1_regulator_icc_set(const char *name) +{ + const struct regul_struct *regul = get_regulator_data(name); + + if (regul->mask_reset_reg == 0U) { + return -EPERM; + } + + return stpmic1_register_update(regul->icc_reg, + BIT(regul->icc_mask), + BIT(regul->icc_mask)); +} + +int stpmic1_regulator_sink_mode_set(const char *name) +{ + if (strncmp(name, "ldo3", 4) != 0) { + return -EPERM; + } + + ldo3_special_mode = true; + + /* disable bypass mode, enable sink mode */ + return stpmic1_register_update(LDO3_CONTROL_REG, + LDO3_DDR_SEL << LDO_BUCK_VOLTAGE_SHIFT, + LDO3_BYPASS | LDO_VOLTAGE_MASK); +} + +int stpmic1_regulator_bypass_mode_set(const char *name) +{ + if (strncmp(name, "ldo3", 4) != 0) { + return -EPERM; + } + + ldo3_special_mode = true; + + /* enable bypass mode, disable sink mode */ + return stpmic1_register_update(LDO3_CONTROL_REG, + LDO3_BYPASS, + LDO3_BYPASS | LDO_VOLTAGE_MASK); +} + +int stpmic1_active_discharge_mode_set(const char *name) +{ + if (strncmp(name, "pwr_sw1", 7) == 0) { + return stpmic1_register_update(USB_CONTROL_REG, + VBUS_OTG_DISCHARGE, + VBUS_OTG_DISCHARGE); + } + + if (strncmp(name, "pwr_sw2", 7) == 0) { + return stpmic1_register_update(USB_CONTROL_REG, + SW_OUT_DISCHARGE, + SW_OUT_DISCHARGE); + } + + return -EPERM; +} + /* Low-power functions */ int stpmic1_lp_copy_reg(const char *name) { @@ -732,6 +852,22 @@ int stpmic1_lp_set_voltage(const char *name, uint16_t millivolts) mask); } +int stpmic1_regulator_levels_mv(const char *name, const uint16_t **levels, + size_t *levels_count) +{ + const struct regul_struct *regul = get_regulator_data(name); + + if ((strncmp(name, "ldo3", 4) == 0) && ldo3_special_mode) { + *levels_count = ARRAY_SIZE(ldo3_special_mode_table); + *levels = ldo3_special_mode_table; + } else { + *levels_count = regul->voltage_table_size; + *levels = regul->voltage_table; + } + + return 0; +} + int stpmic1_regulator_voltage_get(const char *name) { const struct regul_struct *regul = get_regulator_data(name); @@ -739,6 +875,10 @@ int stpmic1_regulator_voltage_get(const char *name) uint8_t mask; int status; + if ((strncmp(name, "ldo3", 4) == 0) && ldo3_special_mode) { + return 0; + } + /* Voltage can be set for buck or ldo (except ldo4) regulators */ if (strncmp(name, "buck", 4) == 0) { mask = BUCK_VOLTAGE_MASK; diff --git a/drivers/st/regulator/regulator_fixed.c b/drivers/st/regulator/regulator_fixed.c new file mode 100644 index 0000000000..56593717f6 --- /dev/null +++ b/drivers/st/regulator/regulator_fixed.c @@ -0,0 +1,91 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright (c) 2020-2021, STMicroelectronics + */ + +#include +#include + +#include + +#include +#include +#include + +#ifndef PLAT_NB_FIXED_REGS +#error "Missing PLAT_NB_FIXED_REGS" +#endif + +#define FIXED_NAME_LEN 32U + +struct fixed_data { + char name[FIXED_NAME_LEN]; + uint16_t volt; + struct regul_description desc; +}; + +static struct fixed_data data[PLAT_NB_FIXED_REGS]; + +static int fixed_set_state(const struct regul_description *desc, bool state) +{ + return 0; +} + +static int fixed_get_state(const struct regul_description *desc) +{ + return 1; +} + +static struct regul_ops fixed_ops = { + .set_state = fixed_set_state, + .get_state = fixed_get_state, +}; + +int fixed_regulator_register(void) +{ + uint32_t count = 0; + void *fdt; + int node = 0; + + VERBOSE("fixed reg init!\n"); + + if (fdt_get_address(&fdt) == 0) { + return -FDT_ERR_NOTFOUND; + } + + do { + size_t len __unused; + int ret; + struct fixed_data *d = &data[count]; + const char *reg_name; + + node = fdt_node_offset_by_compatible(fdt, node, "regulator-fixed"); + if (node < 0) { + break; + } + + reg_name = fdt_get_name(fdt, node, NULL); + + VERBOSE("register fixed reg %s!\n", reg_name); + + len = snprintf(d->name, FIXED_NAME_LEN - 1, "%s", reg_name); + assert((len > 0) && (len < (FIXED_NAME_LEN - 1))); + + d->desc.node_name = d->name; + d->desc.driver_data = d; + d->desc.ops = &fixed_ops; + + ret = regulator_register(&d->desc, node); + if (ret != 0) { + WARN("%s:%d failed to register %s\n", __func__, + __LINE__, reg_name); + return ret; + } + + count++; + assert(count <= PLAT_NB_FIXED_REGS); + + } while (node > 0); + + return 0; +} diff --git a/drivers/st/regulator/stm32mp_dummy_regulator.c b/drivers/st/regulator/stm32mp_dummy_regulator.c deleted file mode 100644 index 1003aba054..0000000000 --- a/drivers/st/regulator/stm32mp_dummy_regulator.c +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (C) 2019, STMicroelectronics - All Rights Reserved - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -#include - -static int dummy_regulator_enable(struct stm32mp_regulator *regu) -{ - return 0; -} - -static int dummy_regulator_disable(struct stm32mp_regulator *regu) -{ - return 0; -} - -static const struct stm32mp_regulator_ops dummy_regu_ops = { - .enable = dummy_regulator_enable, - .disable = dummy_regulator_disable, -}; - -void bind_dummy_regulator(struct stm32mp_regulator *regu) -{ - regu->ops = &dummy_regu_ops; -} diff --git a/drivers/st/regulator/stm32mp_regulator.c b/drivers/st/regulator/stm32mp_regulator.c deleted file mode 100644 index f0e4a4ae5c..0000000000 --- a/drivers/st/regulator/stm32mp_regulator.c +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (C) 2019, STMicroelectronics - All Rights Reserved - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -#include - -#include - -#pragma weak plat_bind_regulator -int plat_bind_regulator(struct stm32mp_regulator *regu) -{ - return -1; -} - -int stm32mp_regulator_enable(struct stm32mp_regulator *regu) -{ - assert((regu->ops != NULL) && (regu->ops->enable != NULL)); - - return regu->ops->enable(regu); -} - -int stm32mp_regulator_disable(struct stm32mp_regulator *regu) -{ - assert((regu->ops != NULL) && (regu->ops->disable != NULL)); - - if (regu->always_on) { - return 0; - } - - return regu->ops->disable(regu); -} - -int stm32mp_regulator_register(struct stm32mp_regulator *regu) -{ - return plat_bind_regulator(regu); -} diff --git a/drivers/st/tamper/stm32_tamp.c b/drivers/st/tamper/stm32_tamp.c index c9a9e9aef8..5a4dde38cd 100644 --- a/drivers/st/tamper/stm32_tamp.c +++ b/drivers/st/tamper/stm32_tamp.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018-2020, STMicroelectronics - All Rights Reserved + * Copyright (c) 2018-2021, STMicroelectronics - All Rights Reserved * * SPDX-License-Identifier: BSD-3-Clause */ @@ -11,8 +11,10 @@ #include +#include #include #include +#include #include #include #include @@ -20,98 +22,190 @@ #define DT_TAMP_COMPAT "st,stm32-tamp" /* STM32 Registers */ -#define STM32_TAMP_CR1 0x00U -#define STM32_TAMP_CR2 0x04U -#define STM32_TAMP_FLTCR 0x0CU -#define STM32_TAMP_ATCR 0x10U -#define STM32_TAMP_ATSEEDR 0x14U -#define STM32_TAMP_ATOR 0x18U -#define STM32_TAMP_SMCR 0x20U -#define STM32_TAMP_IER 0x2CU -#define STM32_TAMP_SR 0x30U -#define STM32_TAMP_SCR 0x3CU -#define STM32_TAMP_COUNTR 0x40U -#define STM32_TAMP_OR 0x50U -#define STM32_TAMP_HWCFGR2 0x3ECU -#define STM32_TAMP_HWCFGR1 0x3F0U -#define STM32_TAMP_VERR 0x3F4U -#define STM32_TAMP_IPIDR 0x3F8U -#define STM32_TAMP_SIDR 0x3FCU - -/* STM32_TAMP_FLTCR bit fields */ -#define STM32_TAMP_FLTCR_TAMPFREQ GENMASK(2, 0) -#define STM32_TAMP_FLTCR_TAMPFLT GENMASK(4, 3) -#define STM32_TAMP_FLTCR_TAMPPRCH GENMASK(6, 5) -#define STM32_TAMP_FLTCR_TAMPPUDIS BIT(7) - -/* STM32_TAMP_ATCR bit fields */ -#define STM32_TAMP_ATCR_ATCKSEL GENMASK(18, 16) -#define STM32_TAMP_ATCR_ATPER GENMASK(26, 24) -#define STM32_TAMP_ATCR_ATOSHARE BIT(30) -#define STM32_TAMP_ATCR_FLTEN BIT(31) - -/* STM32_TAMP_ATOR bit fields */ -#define STM32_TAMP_PRNG GENMASK(7, 0) -#define STM32_TAMP_SEEDF BIT(14) -#define STM32_TAMP_INITS BIT(15) - -/* STM32_TAMP_IER bit fields */ -#define STM32_TAMP_IER_TAMPXIE_ALL GENMASK(7, 0) -#define STM32_TAMP_IER_ITAMPXIE_ALL GENMASK(31, 16) - -/* STM32_TAMP_SR bit fields */ -#define STM32_TAMP_SR_TAMPXF_MASK GENMASK(7, 0) -#define STM32_TAMP_SR_ITAMPXF_MASK GENMASK(31, 16) - -/* STM32_TAMP_SMCR but fields */ -#define STM32_TAMP_SMCR_DPROT BIT(31) - -/* STM32_TAMP_CFGR bit fields */ -#define STM32_TAMP_OR_OUT3RMP BIT(0) - -/* STM32_TAMP_HWCFGR2 bit fields */ -#define STM32_TAMP_HWCFGR2_TZ GENMASK(11, 8) -#define STM32_TAMP_HWCFGR2_OR GENMASK(7, 0) - -/* STM32_TAMP_HWCFGR1 bit fields */ -#define STM32_TAMP_HWCFGR1_BKPREG GENMASK(7, 0) -#define STM32_TAMP_HWCFGR1_TAMPER GENMASK(11, 8) -#define STM32_TAMP_HWCFGR1_ACTIVE GENMASK(15, 12) -#define STM32_TAMP_HWCFGR1_INTERN GENMASK(31, 16) - -/* STM32_TAMP_VERR bit fields */ -#define STM32_TAMP_VERR_MINREV GENMASK(3, 0) -#define STM32_TAMP_VERR_MAJREV GENMASK(7, 4) - -#define STM32_TAMP_MAX_INTERNAL 16U -#define STM32_TAMP_MAX_EXTERNAL 8U +#define _TAMP_CR1 0x00U +#define _TAMP_CR2 0x04U +#define _TAMP_FLTCR 0x0CU +#define _TAMP_ATCR1 0x10U +#define _TAMP_ATSEEDR 0x14U +#define _TAMP_ATOR 0x18U +#define _TAMP_SMCR 0x20U +#define _TAMP_IER 0x2CU +#define _TAMP_SR 0x30U +#define _TAMP_MISR 0x34U +#define _TAMP_SMISR 0x38U +#define _TAMP_SCR 0x3CU +#define _TAMP_COUNTR 0x40U +#define _TAMP_OR 0x50U +#define _TAMP_HWCFGR2 0x3ECU +#define _TAMP_HWCFGR1 0x3F0U +#define _TAMP_VERR 0x3F4U +#define _TAMP_IPIDR 0x3F8U +#define _TAMP_SIDR 0x3FCU + +/* _TAMP_CR1 bit filds */ +#define _TAMP_CR1_ITAMP(id) BIT((id) + 16U) +#define _TAMP_CR1_ETAMP(id) BIT((id)) + +/* _TAMP_CR2 bit filds */ +#define _TAMP_CR2_ETAMPTRG(id) BIT((id) + 24U) +#define _TAMP_CR2_ETAMPMSK_MAX_ID 3U +#define _TAMP_CR2_ETAMPMSK(id) BIT((id) + 16U) +#define _TAMP_CR2_ETAMPNOER(id) BIT((id)) + +/* _TAMP_FLTCR bit fields */ +#define _TAMP_FLTCR_TAMPFREQ GENMASK(2, 0) +#define _TAMP_FLTCR_TAMPFLT GENMASK(4, 3) +#define _TAMP_FLTCR_TAMPPRCH GENMASK(6, 5) +#define _TAMP_FLTCR_TAMPPUDIS BIT(7) + +/* _TAMP_ATCR bit fields */ +#define _TAMP_ATCR1_ATCKSEL GENMASK(18, 16) +#define _TAMP_ATCR1_ATPER GENMASK(26, 24) +#define _TAMP_ATCR1_COMMON_MASK GENMASK(31, 16) +#define _TAMP_ATCR1_ETAMPAM(id) BIT((id)) +#define _TAMP_ATCR1_ATOSEL_MASK(i) GENMASK(((i) + 1) * 2U + 7U, (i) * 2U + 8U) +#define _TAMP_ATCR1_ATOSEL(i, o) (((o) - 1U) << ((i) * 2U + 8U)) + +/* _TAMP_ATOR bit fields */ +#define _TAMP_PRNG GENMASK(7, 0) +#define _TAMP_SEEDF BIT(14) +#define _TAMP_INITS BIT(15) + +/* _TAMP_IER bit fields */ +#define _TAMP_IER_ITAMP(id) BIT((id) + 16U) +#define _TAMP_IER_ETAMP(id) BIT((id)) + +/* _TAMP_SR bit fields */ +#define _TAMP_SR_ETAMPXF_MASK GENMASK(7, 0) +#define _TAMP_SR_ITAMPXF_MASK GENMASK(31, 16) +#define _TAMP_SR_ITAMP(id) BIT((id) + 16U) +#define _TAMP_SR_ETAMP(id) BIT((id)) + +/* _TAMP_SCR bit fields */ +#define _TAMP_SCR_ITAMP(id) BIT((id) + 16U) +#define _TAMP_SCR_ETAMP(id) BIT((id)) + +/* _TAMP_SMCR bit fields */ +#define _TAMP_SMCR_BKPRWDPROT_MASK GENMASK(7, 0) +#define _TAMP_SMCR_BKPRWDPROT_SHIFT U(0) +#define _TAMP_SMCR_BKPWDPROT_MASK GENMASK(23, 16) +#define _TAMP_SMCR_BKPWDPROT_SHIFT U(16) +#define _TAMP_SMCR_DPROT BIT(31) + +/* _TAMP_OR bit fields */ +#define _TAMP_OR_OUT3RMP_PI8 0U +#define _TAMP_OR_OUT3RMP_PC13 BIT(0) + +/* _TAMP_HWCFGR2 bit fields */ +#define _TAMP_HWCFGR2_TZ GENMASK(11, 8) +#define _TAMP_HWCFGR2_OR GENMASK(7, 0) + +/* _TAMP_HWCFGR1 bit fields */ +#define _TAMP_HWCFGR1_BKPREG GENMASK(7, 0) +#define _TAMP_HWCFGR1_TAMPER GENMASK(11, 8) +#define _TAMP_HWCFGR1_ACTIVE GENMASK(15, 12) +#define _TAMP_HWCFGR1_INTERN GENMASK(31, 16) +#define _TAMP_HWCFGR1_ITAMP_MAX_ID 16U +#define _TAMP_HWCFGR1_ITAMP(id) BIT((id) + 16U) + +/* _TAMP_VERR bit fields */ +#define _TAMP_VERR_MINREV GENMASK(3, 0) +#define _TAMP_VERR_MAJREV GENMASK(7, 4) + +#define _TAMP_NB_MONOTONIC_COUNTER 0x1 + +/* + * Macro to manage bit manipulation when we work on local variable + * before writing only once to the real register + */ + +#define CLRBITS(v, bits) (v) &= ~(bits) +#define SETBITS(v, bits) (v) |= (bits) +#define CLRSETBITS(v, mask, bits) (v) = ((v) & ~(mask)) | (bits) + +struct stm32_tamp_int { + const uint32_t id; + uint32_t mode; + int (*func)(int id); +}; + +struct stm32_tamp_ext { + const uint32_t id; + uint32_t mode; + uint8_t out_pin; + int (*func)(int id); +}; struct stm32_tamp_instance { uintptr_t base; uint32_t clock; uint32_t hwconf1; uint32_t hwconf2; - uint16_t int_nbtamp; - uint8_t ext_nbtamp; - struct stm32_tamp_int *int_tamp; - struct stm32_tamp_ext *ext_tamp; + uint32_t secret_list_conf; + uint32_t privilege_conf; + uint32_t secure_conf; + uint32_t passive_conf; + uint32_t active_conf; + struct stm32_tamp_int int_tamp[PLAT_MAX_TAMP_INT]; + struct stm32_tamp_ext ext_tamp[PLAT_MAX_TAMP_EXT]; }; -static struct stm32_tamp_instance stm32_tamp; +/* 0 is the expected initial values for all fields but .id */ +static struct stm32_tamp_instance stm32_tamp = { + .int_tamp = { + { + .id = INT_TAMP1, + }, + { + .id = INT_TAMP2, + }, + { + .id = INT_TAMP3, + }, + { + .id = INT_TAMP4, + }, + { + .id = INT_TAMP5, + }, + { + .id = INT_TAMP8, + }, + }, + .ext_tamp = { + { + .id = EXT_TAMP1, + }, + { + .id = EXT_TAMP2, + }, + { + .id = EXT_TAMP3, + }, + } +}; -static void stm32_tamp_set_secured(unsigned long base) +static void stm32_tamp_set_secure(unsigned long base, uint32_t mode) { - mmio_clrbits_32(base + STM32_TAMP_SMCR, STM32_TAMP_SMCR_DPROT); + if (mode & TAMP_REGS_IT_SECURE) { + mmio_clrbits_32(base + _TAMP_SMCR, _TAMP_SMCR_DPROT); + } else { + mmio_setbits_32(base + _TAMP_SMCR, _TAMP_SMCR_DPROT); + } } -static void stm32_tamp_configure_or(unsigned long base, uint32_t out3) +static void stm32_tamp_set_privilege(unsigned long base __unused, uint32_t mode __unused) { - mmio_setbits_32(base + STM32_TAMP_OR, out3); } -static int stm32_tamp_seed_init(unsigned long base) +static void stm32_tamp_set_output_pin(unsigned long base, uint32_t out) { - /* Need RNG access */ + mmio_setbits_32(base + _TAMP_OR, out); +} + +static int stm32_tamp_set_seed(unsigned long base) +{ + /* Need RNG access. */ uint32_t timeout = 100; uint8_t idx; @@ -123,11 +217,10 @@ static int stm32_tamp_seed_init(unsigned long base) } VERBOSE("Seed init %u\n", rnd); - mmio_write_32(base + STM32_TAMP_ATSEEDR, rnd); + mmio_write_32(base + _TAMP_ATSEEDR, rnd); } - while (((mmio_read_32(base + STM32_TAMP_ATOR) & - STM32_TAMP_SEEDF) != 0U) && + while (((mmio_read_32(base + _TAMP_ATOR) & _TAMP_SEEDF) != 0U) && (timeout != 0U)) { timeout--; } @@ -139,129 +232,334 @@ static int stm32_tamp_seed_init(unsigned long base) return 0; } -static void stm32_tamp_reset_register(unsigned long base) +static bool is_int_tamp_id_valid(uint32_t id) { - /* Disable all internal tamper */ - mmio_write_32(base + STM32_TAMP_CR1, 0U); - - /* Disable all external tamper */ - mmio_write_32(base + STM32_TAMP_CR2, 0U); + if (id > _TAMP_HWCFGR1_ITAMP_MAX_ID) { + return false; + } - /* Clean configuration registers */ - mmio_write_32(base + STM32_TAMP_FLTCR, 0U); - mmio_write_32(base + STM32_TAMP_ATCR, 0U); - mmio_clrbits_32(base + STM32_TAMP_SMCR, STM32_TAMP_SMCR_DPROT); + return (stm32_tamp.hwconf1 & _TAMP_HWCFGR1_ITAMP(id)) + == _TAMP_HWCFGR1_ITAMP(id); +} - /* Clean Tamper IT */ - mmio_write_32(base + STM32_TAMP_IER, 0U); - mmio_write_32(base + STM32_TAMP_SCR, ~0U); +static bool is_ext_tamp_id_valid(uint32_t id) +{ + if (id > PLAT_MAX_TAMP_EXT) { + return false; + } - mmio_clrbits_32(base + STM32_TAMP_OR, STM32_TAMP_OR_OUT3RMP); + return true; } -void stm32_tamp_write_mcounter(void) +static int stm32_tamp_set_int_config(struct stm32_tamp_int *tamp_int, + uint32_t *cr1, uint32_t *cr3, uint32_t *ier) { - mmio_write_32(stm32_tamp.base + STM32_TAMP_COUNTR, 1U); + uint32_t id; + + if (tamp_int == NULL) { + return -EINVAL; + } + + id = tamp_int->id; + + if (!is_int_tamp_id_valid(id)) { + return -EINVAL; + } + + /* If etamp is disabled */ + if ((tamp_int->mode & TAMP_ENABLE) != TAMP_ENABLE) { + CLRBITS(*cr1, _TAMP_CR1_ITAMP(id)); + CLRBITS(*ier, _TAMP_IER_ITAMP(id)); + return 0; + } + + SETBITS(*cr1, _TAMP_CR1_ITAMP(id)); + SETBITS(*ier, _TAMP_IER_ITAMP(id)); + + return 0; } -void stm32_tamp_configure_internal(struct stm32_tamp_int *tamper_list, - uint16_t nb_tamper) +static int stm32_tamp_set_ext_config(struct stm32_tamp_ext *tamp_ext, + uint32_t *cr1, uint32_t *cr2, + uint32_t *atcr1, uint32_t *atcr2, uint32_t *ier) { - uint16_t i; + uint32_t id; - assert(nb_tamper < STM32_TAMP_MAX_INTERNAL); + if (tamp_ext == NULL) { + return -EINVAL; + } - for (i = 0; i < nb_tamper; i++) { - int id = tamper_list[i].id; - uint32_t u_id; + id = tamp_ext->id; - if (id == -1) { - continue; - } + /* Exit if not a valid TAMP_ID */ + if (!is_ext_tamp_id_valid(id)) { + return -EINVAL; + } + + /* If etamp is disabled */ + if ((tamp_ext->mode & TAMP_ENABLE) != TAMP_ENABLE) { + CLRBITS(*cr1, _TAMP_CR1_ETAMP(id)); + CLRBITS(*cr2, _TAMP_CR2_ETAMPMSK(id)); + CLRBITS(*cr2, _TAMP_CR2_ETAMPTRG(id)); + CLRBITS(*cr2, _TAMP_CR2_ETAMPNOER(id)); + CLRBITS(*ier, _TAMP_IER_ETAMP(id)); + return 0; + } + + SETBITS(*cr1, _TAMP_CR1_ETAMP(id)); + + if ((tamp_ext->mode & TAMP_TRIG_ON) == TAMP_TRIG_ON) { + SETBITS(*cr2, _TAMP_CR2_ETAMPTRG(id)); + } else { + CLRBITS(*cr2, _TAMP_CR2_ETAMPTRG(id)); + } + + if ((tamp_ext->mode & TAMP_ACTIVE) == TAMP_ACTIVE) { + SETBITS(*cr1, _TAMP_ATCR1_ETAMPAM(id)); + } else { + CLRBITS(*cr1, _TAMP_ATCR1_ETAMPAM(id)); + } + + if ((tamp_ext->mode & TAMP_NOERASE) == TAMP_NOERASE) { + SETBITS(*cr2, _TAMP_CR2_ETAMPNOER(id)); + } else { + CLRBITS(*cr2, _TAMP_CR2_ETAMPNOER(id)); + } - u_id = (uint32_t)id; + /* Configure output pin: + * For the case out_pin = 0, we select same output pin than the input one. + */ + if (tamp_ext->out_pin == TAMPOUTSEL_SAME_AS_INPUT) { + tamp_ext->out_pin = id + 1; + } + + if (tamp_ext->out_pin < PLAT_MAX_TAMP_EXT + 1U) { + CLRSETBITS(*atcr1, _TAMP_ATCR1_ATOSEL_MASK(id), + _TAMP_ATCR1_ATOSEL(id, tamp_ext->out_pin)); + } - if ((stm32_tamp.hwconf1 & BIT(u_id + 16U)) != 0U) { - mmio_setbits_32(stm32_tamp.base + STM32_TAMP_CR1, - BIT(u_id + 16U)); - mmio_setbits_32(stm32_tamp.base + STM32_TAMP_IER, - BIT(u_id + 16U)); + if (id < _TAMP_CR2_ETAMPMSK_MAX_ID) { + /* + * Only external TAMP 1, 2 and 3 can be masked + */ + if ((tamp_ext->mode & TAMP_EVT_MASK) == TAMP_EVT_MASK) { + /* + * ETAMP(id) event generates a trigger event. This ETAMP(id) is masked + * and internally cleared by hardware. The backup registers are not erased. + */ + CLRBITS(*ier, _TAMP_IER_ETAMP(id)); + CLRBITS(*cr2, _TAMP_CR2_ETAMPMSK(id)); + } else { + /* + * normal ETAMP interrupt: + * ETAMP(id) event generates a trigger event and TAMP(id)F must be cleared + * by software to * allow next tamper event detection. + */ + CLRBITS(*cr2, _TAMP_CR2_ETAMPMSK(id)); + CLRBITS(*ier, _TAMP_IER_ETAMP(id)); } + } else { + /* other than 1,2,3 external TAMP, we want its interruption */ + CLRBITS(*ier, _TAMP_IER_ETAMP(id)); } - stm32_tamp.int_tamp = tamper_list; - stm32_tamp.int_nbtamp = nb_tamper; + return 0; } -void stm32_tamp_configure_external(struct stm32_tamp_ext *ext_tamper_list, - uint8_t nb_tamper, uint32_t passive_conf, - uint32_t active_conf) +int stm32_tamp_set_secure_bkpregs(struct bkpregs_conf *bkpregs_conf) { - /* External configuration */ - uint8_t i, active_tamp = 0; + uint32_t first_z2; + uint32_t first_z3; - assert(nb_tamper < STM32_TAMP_MAX_EXTERNAL); + if (bkpregs_conf == NULL) { + return -EINVAL; + } - /* Enable external Tamp */ - for (i = 0; i < nb_tamper; i++) { - int id = ext_tamper_list[i].id; - uint32_t reg = 0, u_id; + first_z2 = bkpregs_conf->nb_zone1_regs; + first_z3 = bkpregs_conf->nb_zone1_regs + bkpregs_conf->nb_zone2_regs; - if (id == -1) { - continue; - } + if ((first_z2 > (stm32_tamp.hwconf1 & _TAMP_HWCFGR1_BKPREG)) || + (first_z3 > (stm32_tamp.hwconf1 & _TAMP_HWCFGR1_BKPREG))) { + return -ENODEV; + } + + mmio_clrsetbits_32(stm32_tamp.base + _TAMP_SMCR, + _TAMP_SMCR_BKPRWDPROT_MASK, + (first_z2 << _TAMP_SMCR_BKPRWDPROT_SHIFT) & + _TAMP_SMCR_BKPRWDPROT_MASK); - u_id = (uint32_t)id; + mmio_clrsetbits_32(stm32_tamp.base + _TAMP_SMCR, + _TAMP_SMCR_BKPWDPROT_MASK, + (first_z3 << _TAMP_SMCR_BKPWDPROT_SHIFT) & + _TAMP_SMCR_BKPWDPROT_MASK); + return 0; +} + +int stm32_tamp_set_config(void) +{ + int ret; + uint32_t i; + uint32_t cr1 = 0, cr2 = 0, cr3 = 0; + uint32_t atcr1 = 0, atcr2 = 0; + uint32_t fltcr = 0; + uint32_t ier = 0; + + /* Select access in secure or unsecure */ + stm32_tamp_set_secure(stm32_tamp.base, stm32_tamp.secure_conf); + + /* Select acces in privileged mode or unprivileged mode */ + stm32_tamp_set_privilege(stm32_tamp.base, stm32_tamp.privilege_conf); + + if (stm32_tamp.passive_conf != 0U) { + /* Filter mode register set */ + fltcr = stm32_tamp.passive_conf; + } - mmio_setbits_32(stm32_tamp.base + STM32_TAMP_CR1, - BIT(u_id)); + if (stm32_tamp.active_conf != 0U) { + /* Active mode configuration */ + CLRSETBITS(atcr1, _TAMP_ATCR1_COMMON_MASK, + (stm32_tamp.active_conf & _TAMP_ATCR1_COMMON_MASK)); + } - if (ext_tamper_list[i].mode == TAMP_TRIG_ON) { - reg |= BIT(u_id + 24U); + for (i = 0U; i < PLAT_MAX_TAMP_INT; i++) { + ret = stm32_tamp_set_int_config(&(stm32_tamp.int_tamp[i]), + &cr1, &cr3, &ier); + if (ret != 0) { + return ret; } + } - if (ext_tamper_list[i].mode == TAMP_ACTIVE) { - active_tamp |= BIT(u_id); + for (i = 0U; i < PLAT_MAX_TAMP_EXT; i++) { + ret = stm32_tamp_set_ext_config(&(stm32_tamp.ext_tamp[i]), + &cr1, &cr2, &atcr1, &atcr2, &ier); + if (ret != 0) { + return ret; } + } + + /* + * We apply configuration all in a row: + * As for active ext tamper "all the needed tampers must be enabled in the same write + * access". + */ + mmio_write_32(stm32_tamp.base + _TAMP_FLTCR, fltcr); + /* Active filter configuration applied only if not already done. */ + if (((mmio_read_32(stm32_tamp.base + _TAMP_ATOR) & _TAMP_INITS) != _TAMP_INITS)) { + mmio_write_32(stm32_tamp.base + _TAMP_ATCR1, atcr1); + } - if (ext_tamper_list[i].erase != 0U) { - reg |= BIT(u_id); + mmio_write_32(stm32_tamp.base + _TAMP_CR1, cr1); + mmio_write_32(stm32_tamp.base + _TAMP_CR2, cr2); + /* If active tamper we reinit the seed. */ + if (stm32_tamp.active_conf != 0U) { + if (stm32_tamp_set_seed(stm32_tamp.base) != 0) { + ERROR("Active tamper: SEED not initialized\n"); + return -EPERM; } + } - if (ext_tamper_list[i].evt_mask != 0U) { - reg |= BIT(u_id + 16U); - } else { - mmio_setbits_32(stm32_tamp.base + STM32_TAMP_IER, - BIT(u_id)); + /* Ack all pending interrupt */ + mmio_write_32(stm32_tamp.base + _TAMP_SCR, ~0U); + /* Enable interrupts. */ + mmio_write_32(stm32_tamp.base + _TAMP_IER, ier); + + return 0; +} + +int stm32_tamp_write_mcounter(int counter_idx) +{ + mmio_write_32(stm32_tamp.base + _TAMP_COUNTR, 1U); + + return 0; +} + +uint32_t stm32_tamp_read_mcounter(int counter_idx) +{ + return mmio_read_32(stm32_tamp.base + _TAMP_COUNTR); +} + +void stm32_tamp_configure_secret_list(uint32_t secret_list_conf) +{ + stm32_tamp.secret_list_conf = secret_list_conf; +} + +void stm32_tamp_configure_privilege_access(uint32_t privilege_conf) +{ + stm32_tamp.privilege_conf = privilege_conf; +} + +void stm32_tamp_configure_secure_access(uint32_t secure_conf) +{ + stm32_tamp.secure_conf = secure_conf; +} + +void stm32_tamp_configure_passive(uint32_t passive_conf) +{ + stm32_tamp.passive_conf = passive_conf; +} + +void stm32_tamp_configure_active(uint32_t active_conf) +{ + stm32_tamp.active_conf = active_conf; +} + +int stm32_tamp_configure_internal(enum stm32_tamp_int_id id, uint32_t mode, int (*callback)(int id)) +{ + uint32_t i; + uint32_t itamp_id = id; + struct stm32_tamp_int *tamp_int = NULL; + + /* Find internal Tamp struct*/ + for (i = 0U; i < PLAT_MAX_TAMP_INT; i++) { + if (stm32_tamp.int_tamp[i].id == itamp_id) { + tamp_int = &(stm32_tamp.int_tamp[i]); + break; } + } - mmio_setbits_32(stm32_tamp.base + STM32_TAMP_CR2, reg); + if (tamp_int == NULL) { + return -EINVAL; } - /* Filter mode register set */ - mmio_write_32(stm32_tamp.base + STM32_TAMP_FLTCR, passive_conf); + tamp_int->mode = mode; + tamp_int->func = callback; - /* Active mode configuration */ - if (active_tamp != 0U) { - mmio_write_32(stm32_tamp.base + STM32_TAMP_ATCR, - active_conf | active_tamp); - if (stm32_tamp_seed_init(stm32_tamp.base) != 0) { - ERROR("Active tamper: SEED not initialized\n"); - panic(); + return 0; +} + +int stm32_tamp_configure_external(enum stm32_tamp_ext_id id, uint32_t mode, + enum stm32_tamp_ext_out_id out_pin, int (*callback)(int id)) +{ + uint32_t i; + uint32_t etamp_id = id; + struct stm32_tamp_ext *tamp_ext = NULL; + + /* Find external Tamp struct */ + for (i = 0U; i < PLAT_MAX_TAMP_EXT; i++) { + if (stm32_tamp.ext_tamp[i].id == etamp_id) { + tamp_ext = &(stm32_tamp.ext_tamp[i]); + break; } } - stm32_tamp.ext_tamp = ext_tamper_list; - stm32_tamp.ext_nbtamp = nb_tamper; + if (tamp_ext == NULL) { + return -EINVAL; + } + + tamp_ext->mode = mode; + tamp_ext->out_pin = out_pin; + tamp_ext->func = callback; + + return 0; } void stm32_tamp_it_handler(void) { - uint32_t it = mmio_read_32(stm32_tamp.base + STM32_TAMP_SR); + uint32_t it = mmio_read_32(stm32_tamp.base + _TAMP_SR); + uint32_t int_it = it & _TAMP_SR_ITAMPXF_MASK; + uint32_t ext_it = it & _TAMP_SR_ETAMPXF_MASK; uint8_t tamp = 0; struct stm32_rtc_time tamp_ts; - struct stm32_tamp_int *int_list = stm32_tamp.int_tamp; - struct stm32_tamp_ext *ext_list = stm32_tamp.ext_tamp; if (stm32_rtc_is_timestamp_enable()) { stm32_rtc_get_timestamp(&tamp_ts); @@ -271,45 +569,53 @@ void stm32_tamp_it_handler(void) tamp_ts.min, tamp_ts.sec); } - /* Internal tamper interrupt */ - if ((it & STM32_TAMP_IER_ITAMPXIE_ALL) == 0U) { - goto tamp_ext; - } + while ((int_it != 0U) && (tamp < PLAT_MAX_TAMP_INT)) { + int ret = -1; + uint32_t int_id = stm32_tamp.int_tamp[tamp].id; - while ((it != 0U) && (tamp < stm32_tamp.int_nbtamp)) { - uint32_t int_id = (uint32_t)int_list[tamp].id; + if ((it & _TAMP_SR_ITAMP(int_id)) != 0U) { + if (stm32_tamp.int_tamp[tamp].func != NULL) { + ret = stm32_tamp.int_tamp[tamp].func(int_id); + } + + if (ret >= 0) { + mmio_setbits_32(stm32_tamp.base + _TAMP_SCR, + _TAMP_SR_ITAMP(int_id)); + ext_it &= ~_TAMP_SR_ITAMP(int_id); - if ((it & BIT(int_id + 16U)) != 0U) { - mmio_setbits_32(stm32_tamp.base + STM32_TAMP_SCR, BIT(int_id + 16U)); - it &= ~BIT(int_id + 16U); - if (int_list[tamp].func != NULL) { - int_list[tamp].func(int_id); + if (ret > 0) { + stm32mp_system_reset(); + } } } tamp++; } -tamp_ext: tamp = 0; /* External tamper interrupt */ - if ((it == 0U) || ((it & STM32_TAMP_IER_TAMPXIE_ALL) == 0U)) { - return; - } + while ((ext_it != 0U) && (tamp < PLAT_MAX_TAMP_EXT)) { + int ret = -1; + uint32_t ext_id = stm32_tamp.ext_tamp[tamp].id; - while ((it != 0U) && (tamp < stm32_tamp.ext_nbtamp)) { - uint32_t ext_id = (uint32_t)ext_list[tamp].id; - - if ((it & BIT(ext_id)) != 0U) { - if (ext_list[tamp].func != NULL) { - ext_list[tamp].func(ext_id); + if ((ext_it & _TAMP_SR_ETAMP(ext_id)) != 0U) { + if (stm32_tamp.ext_tamp[tamp].func != NULL) { + ret = stm32_tamp.ext_tamp[tamp].func(ext_id); } - mmio_setbits_32(stm32_tamp.base + STM32_TAMP_SCR, - BIT(ext_id)); - it &= ~BIT(ext_id); + if (ret >= 0) { + mmio_setbits_32(stm32_tamp.base + _TAMP_SCR, + _TAMP_SCR_ETAMP(ext_id)); + ext_it &= ~_TAMP_SR_ETAMP(ext_id); + + if (ret > 0) { + stm32mp_system_reset(); + } + } } tamp++; } + + gicv2_end_of_interrupt(STM32MP1_IRQ_TAMPSERRS); } int stm32_tamp_init(void) @@ -325,7 +631,7 @@ int stm32_tamp_init(void) node = dt_get_node(&dt_tamp, -1, DT_TAMP_COMPAT); if (node < 0) { - return -FDT_ERR_NOTFOUND; + return -EINVAL; } assert(dt_tamp.base != 0U); @@ -337,37 +643,34 @@ int stm32_tamp_init(void) /* Init Tamp clock */ clk_enable(stm32_tamp.clock); - /* Reset Tamp register without modifying backup registers conf */ - stm32_tamp_reset_register(stm32_tamp.base); - /* Check if TAMP is enabled */ if ((dt_tamp.status != DT_SECURE) && (dt_tamp.status != DT_SHARED)) { return 0; } - stm32_tamp.hwconf1 = mmio_read_32(stm32_tamp.base + STM32_TAMP_HWCFGR1); - stm32_tamp.hwconf2 = mmio_read_32(stm32_tamp.base + STM32_TAMP_HWCFGR2); + stm32_tamp.hwconf1 = mmio_read_32(stm32_tamp.base + _TAMP_HWCFGR1); + stm32_tamp.hwconf2 = mmio_read_32(stm32_tamp.base + _TAMP_HWCFGR2); - rev = mmio_read_32(stm32_tamp.base + STM32_TAMP_VERR); - VERBOSE("STM32 TAMPER V%u.%u\n", (rev & STM32_TAMP_VERR_MAJREV) >> 4, - rev & STM32_TAMP_VERR_MINREV); +#if LOG_LEVEL >= LOG_LEVEL_VERBOSE + rev = mmio_read_32(stm32_tamp.base + _TAMP_VERR); + VERBOSE("STM32 TAMPER V%u.%u\n", (rev & _TAMP_VERR_MAJREV) >> 4, + rev & _TAMP_VERR_MINREV); +#endif - if ((stm32_tamp.hwconf2 & STM32_TAMP_HWCFGR2_TZ) == 0U) { + if ((stm32_tamp.hwconf2 & _TAMP_HWCFGR2_TZ) == 0U) { ERROR("Tamper IP doesn't support trustzone"); return -EPERM; } - stm32_tamp_set_secured(stm32_tamp.base); - if (dt_set_pinctrl_config(node) != -FDT_ERR_NOTFOUND) { if (fdt_getprop(fdt, node, "st,out3-pc13", NULL) != NULL) { - stm32_tamp_configure_or(stm32_tamp.base, 1); + stm32_tamp_set_output_pin(stm32_tamp.base, _TAMP_OR_OUT3RMP_PC13); } } if (stm32_gic_enable_spi(node, NULL) < 0) { - panic(); + return -EPERM; } if (fdt_getprop(fdt, node, "wakeup-source", NULL) != NULL) { diff --git a/drivers/st/uart/aarch32/stm32_console.S b/drivers/st/uart/aarch32/stm32_console.S index 2cb04a88fc..5872157323 100644 --- a/drivers/st/uart/aarch32/stm32_console.S +++ b/drivers/st/uart/aarch32/stm32_console.S @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018-2020, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2018-2021, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ @@ -45,7 +45,12 @@ func console_stm32_core_init /* Check the input base address */ cmp r0, #0 beq core_init_fail -#if defined(IMAGE_BL2) +#if !defined(IMAGE_BL2) + /* Skip UART initialization if it is already enabled */ + ldr r3, [r0, #USART_CR1] + ands r3, r3, #USART_CR1_UE + bne 1f +#endif /* IMAGE_BL2 */ /* Check baud rate and uart clock for sanity */ cmp r1, #0 beq core_init_fail @@ -78,7 +83,7 @@ teack_loop: ldr r3, [r0, #USART_ISR] tst r3, #USART_ISR_TEACK beq teack_loop -#endif /* IMAGE_BL2 */ +1: mov r0, #1 bx lr core_init_fail: diff --git a/fdts/stm32mp15-ddr-512m-fw-config.dts b/fdts/stm32mp15-ddr-512m-fw-config.dts deleted file mode 100644 index 3d0722181a..0000000000 --- a/fdts/stm32mp15-ddr-512m-fw-config.dts +++ /dev/null @@ -1,63 +0,0 @@ -// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) -/* - * Copyright (c) 2020, STMicroelectronics - All Rights Reserved - */ - -#include - -#include -#include - -/dts-v1/; - -/ { - dtb-registry { - compatible = "fconf,dyn_cfg-dtb_registry"; - - hw-config { - load-address = <0x0 STM32MP_HW_CONFIG_BASE>; - max-size = ; - id = ; - }; - - nt_fw { - load-address = <0x0 STM32MP_BL33_BASE>; - max-size = ; - id = ; - }; - -#ifdef AARCH32_SP_OPTEE - tos_fw { - load-address = <0x0 0x2FFC0000>; - max-size = <0x0001F000>; - id = ; - }; -#else - tos_fw { - load-address = <0x0 STM32MP_BL32_BASE>; - max-size = ; - id = ; - }; - - tos_fw-config { - load-address = <0x0 STM32MP_BL32_DTB_BASE>; - max-size = ; - id = ; - }; -#endif - }; - - st-mem-firewall { - compatible = "st,mem-firewall"; -#ifdef AARCH32_SP_OPTEE - memory-ranges = < - 0xc0000000 0x1e000000 TZC_REGION_S_NONE TZC_REGION_NSEC_ALL_ACCESS_RDWR - 0xde000000 0x01e00000 TZC_REGION_S_RDWR 0 - 0xdfe00000 0x00200000 TZC_REGION_S_NONE - TZC_REGION_ACCESS_RDWR(STM32MP1_TZC_A7_ID)>; -#else - memory-ranges = < - 0xc0000000 0x20000000 TZC_REGION_S_NONE TZC_REGION_NSEC_ALL_ACCESS_RDWR>; -#endif - }; -}; diff --git a/fdts/stm32mp15-ddr.dtsi b/fdts/stm32mp15-ddr.dtsi index 734943c0ea..43424a0079 100644 --- a/fdts/stm32mp15-ddr.dtsi +++ b/fdts/stm32mp15-ddr.dtsi @@ -1,165 +1,129 @@ // SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause /* - * Copyright (C) 2018, STMicroelectronics - All Rights Reserved + * Copyright (C) 2018-2021, STMicroelectronics - All Rights Reserved */ -/ { - soc { - ddr: ddr@5a003000{ +&ddr { + st,mem-name = DDR_MEM_NAME; + st,mem-speed = ; + st,mem-size = ; - compatible = "st,stm32mp1-ddr"; + st,ctl-reg = < + DDR_MSTR + DDR_MRCTRL0 + DDR_MRCTRL1 + DDR_DERATEEN + DDR_DERATEINT + DDR_PWRCTL + DDR_PWRTMG + DDR_HWLPCTL + DDR_RFSHCTL0 + DDR_RFSHCTL3 + DDR_CRCPARCTL0 + DDR_ZQCTL0 + DDR_DFITMG0 + DDR_DFITMG1 + DDR_DFILPCFG0 + DDR_DFIUPD0 + DDR_DFIUPD1 + DDR_DFIUPD2 + DDR_DFIPHYMSTR + DDR_ODTMAP + DDR_DBG0 + DDR_DBG1 + DDR_DBGCMD + DDR_POISONCFG + DDR_PCCFG + >; - reg = <0x5A003000 0x550 - 0x5A004000 0x234>; + st,ctl-timing = < + DDR_RFSHTMG + DDR_DRAMTMG0 + DDR_DRAMTMG1 + DDR_DRAMTMG2 + DDR_DRAMTMG3 + DDR_DRAMTMG4 + DDR_DRAMTMG5 + DDR_DRAMTMG6 + DDR_DRAMTMG7 + DDR_DRAMTMG8 + DDR_DRAMTMG14 + DDR_ODTCFG + >; - clocks = <&rcc AXIDCG>, - <&rcc DDRC1>, -#if STM32MP_DDR_DUAL_AXI_PORT - <&rcc DDRC2>, -#endif - <&rcc DDRPHYC>, - <&rcc DDRCAPB>, - <&rcc DDRPHYCAPB>; - - clock-names = "axidcg", - "ddrc1", -#if STM32MP_DDR_DUAL_AXI_PORT - "ddrc2", -#endif - "ddrphyc", - "ddrcapb", - "ddrphycapb"; + st,ctl-map = < + DDR_ADDRMAP1 + DDR_ADDRMAP2 + DDR_ADDRMAP3 + DDR_ADDRMAP4 + DDR_ADDRMAP5 + DDR_ADDRMAP6 + DDR_ADDRMAP9 + DDR_ADDRMAP10 + DDR_ADDRMAP11 + >; - st,mem-name = DDR_MEM_NAME; - st,mem-speed = ; - st,mem-size = ; + st,ctl-perf = < + DDR_SCHED + DDR_SCHED1 + DDR_PERFHPR1 + DDR_PERFLPR1 + DDR_PERFWR1 + DDR_PCFGR_0 + DDR_PCFGW_0 + DDR_PCFGQOS0_0 + DDR_PCFGQOS1_0 + DDR_PCFGWQOS0_0 + DDR_PCFGWQOS1_0 + DDR_PCFGR_1 + DDR_PCFGW_1 + DDR_PCFGQOS0_1 + DDR_PCFGQOS1_1 + DDR_PCFGWQOS0_1 + DDR_PCFGWQOS1_1 + >; - st,ctl-reg = < - DDR_MSTR - DDR_MRCTRL0 - DDR_MRCTRL1 - DDR_DERATEEN - DDR_DERATEINT - DDR_PWRCTL - DDR_PWRTMG - DDR_HWLPCTL - DDR_RFSHCTL0 - DDR_RFSHCTL3 - DDR_CRCPARCTL0 - DDR_ZQCTL0 - DDR_DFITMG0 - DDR_DFITMG1 - DDR_DFILPCFG0 - DDR_DFIUPD0 - DDR_DFIUPD1 - DDR_DFIUPD2 - DDR_DFIPHYMSTR - DDR_ODTMAP - DDR_DBG0 - DDR_DBG1 - DDR_DBGCMD - DDR_POISONCFG - DDR_PCCFG - >; + st,phy-reg = < + DDR_PGCR + DDR_ACIOCR + DDR_DXCCR + DDR_DSGCR + DDR_DCR + DDR_ODTCR + DDR_ZQ0CR1 + DDR_DX0GCR + DDR_DX1GCR + DDR_DX2GCR + DDR_DX3GCR + >; - st,ctl-timing = < - DDR_RFSHTMG - DDR_DRAMTMG0 - DDR_DRAMTMG1 - DDR_DRAMTMG2 - DDR_DRAMTMG3 - DDR_DRAMTMG4 - DDR_DRAMTMG5 - DDR_DRAMTMG6 - DDR_DRAMTMG7 - DDR_DRAMTMG8 - DDR_DRAMTMG14 - DDR_ODTCFG - >; - - st,ctl-map = < - DDR_ADDRMAP1 - DDR_ADDRMAP2 - DDR_ADDRMAP3 - DDR_ADDRMAP4 - DDR_ADDRMAP5 - DDR_ADDRMAP6 - DDR_ADDRMAP9 - DDR_ADDRMAP10 - DDR_ADDRMAP11 - >; - - st,ctl-perf = < - DDR_SCHED - DDR_SCHED1 - DDR_PERFHPR1 - DDR_PERFLPR1 - DDR_PERFWR1 - DDR_PCFGR_0 - DDR_PCFGW_0 - DDR_PCFGQOS0_0 - DDR_PCFGQOS1_0 - DDR_PCFGWQOS0_0 - DDR_PCFGWQOS1_0 -#if STM32MP_DDR_DUAL_AXI_PORT - DDR_PCFGR_1 - DDR_PCFGW_1 - DDR_PCFGQOS0_1 - DDR_PCFGQOS1_1 - DDR_PCFGWQOS0_1 - DDR_PCFGWQOS1_1 -#endif - >; - - st,phy-reg = < - DDR_PGCR - DDR_ACIOCR - DDR_DXCCR - DDR_DSGCR - DDR_DCR - DDR_ODTCR - DDR_ZQ0CR1 - DDR_DX0GCR - DDR_DX1GCR -#if STM32MP_DDR_DUAL_AXI_PORT - DDR_DX2GCR - DDR_DX3GCR -#endif - >; - - st,phy-timing = < - DDR_PTR0 - DDR_PTR1 - DDR_PTR2 - DDR_DTPR0 - DDR_DTPR1 - DDR_DTPR2 - DDR_MR0 - DDR_MR1 - DDR_MR2 - DDR_MR3 - >; + st,phy-timing = < + DDR_PTR0 + DDR_PTR1 + DDR_PTR2 + DDR_DTPR0 + DDR_DTPR1 + DDR_DTPR2 + DDR_MR0 + DDR_MR1 + DDR_MR2 + DDR_MR3 + >; #ifdef DDR_PHY_CAL_SKIP - st,phy-cal = < - DDR_DX0DLLCR - DDR_DX0DQTR - DDR_DX0DQSTR - DDR_DX1DLLCR - DDR_DX1DQTR - DDR_DX1DQSTR -#if STM32MP_DDR_DUAL_AXI_PORT - DDR_DX2DLLCR - DDR_DX2DQTR - DDR_DX2DQSTR - DDR_DX3DLLCR - DDR_DX3DQTR - DDR_DX3DQSTR + st,phy-cal = < + DDR_DX0DLLCR + DDR_DX0DQTR + DDR_DX0DQSTR + DDR_DX1DLLCR + DDR_DX1DQTR + DDR_DX1DQSTR + DDR_DX2DLLCR + DDR_DX2DQTR + DDR_DX2DQSTR + DDR_DX3DLLCR + DDR_DX3DQTR + DDR_DX3DQSTR + >; #endif - >; -#endif - - status = "okay"; - }; - }; }; diff --git a/fdts/stm32mp15-ddr3-1x4Gb-1066-binG.dtsi b/fdts/stm32mp15-ddr3-1x4Gb-1066-binG.dtsi index 127053b86a..6ca6293d4c 100644 --- a/fdts/stm32mp15-ddr3-1x4Gb-1066-binG.dtsi +++ b/fdts/stm32mp15-ddr3-1x4Gb-1066-binG.dtsi @@ -15,7 +15,7 @@ * Save Date: 2020.02.20, save Time: 18:45:20 */ -#define DDR_MEM_NAME "DDR3-DDR3L 16bits 533000Khz" +#define DDR_MEM_NAME "DDR3-DDR3L 16bits 533000kHz" #define DDR_MEM_SPEED 533000 #define DDR_MEM_SIZE 0x20000000 @@ -61,13 +61,13 @@ #define DDR_DBGCMD 0x00000000 #define DDR_POISONCFG 0x00000000 #define DDR_PCCFG 0x00000010 -#define DDR_PCFGR_0 0x00000000 +#define DDR_PCFGR_0 0x00010000 #define DDR_PCFGW_0 0x00000000 #define DDR_PCFGQOS0_0 0x02100C03 #define DDR_PCFGQOS1_0 0x00800100 #define DDR_PCFGWQOS0_0 0x01100C03 #define DDR_PCFGWQOS1_0 0x01000200 -#define DDR_PCFGR_1 0x00000000 +#define DDR_PCFGR_1 0x00010000 #define DDR_PCFGW_1 0x00000000 #define DDR_PCFGQOS0_1 0x02100C03 #define DDR_PCFGQOS1_1 0x00800040 diff --git a/fdts/stm32mp15-ddr3-2x4Gb-1066-binG.dtsi b/fdts/stm32mp15-ddr3-2x4Gb-1066-binG.dtsi index 5ae861fee1..548f69a197 100644 --- a/fdts/stm32mp15-ddr3-2x4Gb-1066-binG.dtsi +++ b/fdts/stm32mp15-ddr3-2x4Gb-1066-binG.dtsi @@ -15,7 +15,7 @@ * Save Date: 2020.02.20, save Time: 18:49:33 */ -#define DDR_MEM_NAME "DDR3-DDR3L 32bits 533000Khz" +#define DDR_MEM_NAME "DDR3-DDR3L 32bits 533000kHz" #define DDR_MEM_SPEED 533000 #define DDR_MEM_SIZE 0x40000000 @@ -61,13 +61,13 @@ #define DDR_DBGCMD 0x00000000 #define DDR_POISONCFG 0x00000000 #define DDR_PCCFG 0x00000010 -#define DDR_PCFGR_0 0x00000000 +#define DDR_PCFGR_0 0x00010000 #define DDR_PCFGW_0 0x00000000 #define DDR_PCFGQOS0_0 0x02100C03 #define DDR_PCFGQOS1_0 0x00800100 #define DDR_PCFGWQOS0_0 0x01100C03 #define DDR_PCFGWQOS1_0 0x01000200 -#define DDR_PCFGR_1 0x00000000 +#define DDR_PCFGR_1 0x00010000 #define DDR_PCFGW_1 0x00000000 #define DDR_PCFGQOS0_1 0x02100C03 #define DDR_PCFGQOS1_1 0x00800040 diff --git a/fdts/stm32mp15-ddr-1g-fw-config.dts b/fdts/stm32mp15-fw-config.dts similarity index 60% rename from fdts/stm32mp15-ddr-1g-fw-config.dts rename to fdts/stm32mp15-fw-config.dts index c871463062..f5c4972061 100644 --- a/fdts/stm32mp15-ddr-1g-fw-config.dts +++ b/fdts/stm32mp15-fw-config.dts @@ -1,6 +1,6 @@ // SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) /* - * Copyright (c) 2020, STMicroelectronics - All Rights Reserved + * Copyright (c) 2020-2021, STMicroelectronics - All Rights Reserved */ #include @@ -8,6 +8,21 @@ #include #include +#ifndef DDR_SIZE +#error "DDR_SIZE is not defined" +#endif + +#define DDR_NS_BASE STM32MP_DDR_BASE +#ifdef AARCH32_SP_OPTEE +#define DDR_SHARE_SIZE 0x00200000 +#define DDR_SHARE_BASE (STM32MP_DDR_BASE + (DDR_SIZE - DDR_SHARE_SIZE)) +#define DDR_SEC_SIZE 0x01e00000 +#define DDR_SEC_BASE (DDR_SHARE_BASE - DDR_SEC_SIZE) +#define DDR_NS_SIZE (DDR_SEC_BASE - DDR_NS_BASE) +#else +#define DDR_NS_SIZE DDR_SIZE +#endif + /dts-v1/; / { @@ -51,13 +66,13 @@ compatible = "st,mem-firewall"; #ifdef AARCH32_SP_OPTEE memory-ranges = < - 0xc0000000 0x3e000000 TZC_REGION_S_NONE TZC_REGION_NSEC_ALL_ACCESS_RDWR - 0xfe000000 0x01e00000 TZC_REGION_S_RDWR 0 - 0xffe00000 0x00200000 TZC_REGION_S_NONE + DDR_NS_BASE DDR_NS_SIZE TZC_REGION_S_NONE TZC_REGION_NSEC_ALL_ACCESS_RDWR + DDR_SEC_BASE DDR_SEC_SIZE TZC_REGION_S_RDWR 0 + DDR_SHARE_BASE DDR_SHARE_SIZE TZC_REGION_S_NONE TZC_REGION_ACCESS_RDWR(STM32MP1_TZC_A7_ID)>; #else memory-ranges = < - 0xc0000000 0x40000000 TZC_REGION_S_NONE TZC_REGION_NSEC_ALL_ACCESS_RDWR>; + DDR_NS_BASE DDR_NS_SIZE TZC_REGION_S_NONE TZC_REGION_NSEC_ALL_ACCESS_RDWR>; #endif }; }; diff --git a/fdts/stm32mp151.dtsi b/fdts/stm32mp151.dtsi index 714d94710f..90b93387a6 100644 --- a/fdts/stm32mp151.dtsi +++ b/fdts/stm32mp151.dtsi @@ -382,6 +382,24 @@ secure-status = "disabled"; }; + ddr: ddr@5a003000{ + compatible = "st,stm32mp1-ddr"; + reg = <0x5A003000 0x550 0x5A004000 0x234>; + clocks = <&rcc AXIDCG>, + <&rcc DDRC1>, + <&rcc DDRC2>, + <&rcc DDRPHYC>, + <&rcc DDRCAPB>, + <&rcc DDRPHYCAPB>; + clock-names = "axidcg", + "ddrc1", + "ddrc2", + "ddrphyc", + "ddrcapb", + "ddrphycapb"; + status = "okay"; + }; + usbphyc: usbphyc@5a006000 { #address-cells = <1>; #size-cells = <0>; diff --git a/fdts/stm32mp157a-avenger96-fw-config.dts b/fdts/stm32mp157a-avenger96-fw-config.dts index 10f9402c4a..275406410e 100644 --- a/fdts/stm32mp157a-avenger96-fw-config.dts +++ b/fdts/stm32mp157a-avenger96-fw-config.dts @@ -3,4 +3,5 @@ * Copyright (c) 2020, STMicroelectronics - All Rights Reserved */ -#include "stm32mp15-ddr-1g-fw-config.dts" +#define DDR_SIZE 0x40000000 /* 1GB */ +#include "stm32mp15-fw-config.dts" diff --git a/fdts/stm32mp157a-dk1-fw-config.dts b/fdts/stm32mp157a-dk1-fw-config.dts index 256d0db935..d2be11aab2 100644 --- a/fdts/stm32mp157a-dk1-fw-config.dts +++ b/fdts/stm32mp157a-dk1-fw-config.dts @@ -3,4 +3,5 @@ * Copyright (c) 2020, STMicroelectronics - All Rights Reserved */ -#include "stm32mp15-ddr-512m-fw-config.dts" +#define DDR_SIZE 0x20000000 /* 512MB */ +#include "stm32mp15-fw-config.dts" diff --git a/fdts/stm32mp157a-ed1-fw-config.dts b/fdts/stm32mp157a-ed1-fw-config.dts index 10f9402c4a..275406410e 100644 --- a/fdts/stm32mp157a-ed1-fw-config.dts +++ b/fdts/stm32mp157a-ed1-fw-config.dts @@ -3,4 +3,5 @@ * Copyright (c) 2020, STMicroelectronics - All Rights Reserved */ -#include "stm32mp15-ddr-1g-fw-config.dts" +#define DDR_SIZE 0x40000000 /* 1GB */ +#include "stm32mp15-fw-config.dts" diff --git a/fdts/stm32mp157a-ev1-fw-config.dts b/fdts/stm32mp157a-ev1-fw-config.dts index 10f9402c4a..275406410e 100644 --- a/fdts/stm32mp157a-ev1-fw-config.dts +++ b/fdts/stm32mp157a-ev1-fw-config.dts @@ -3,4 +3,5 @@ * Copyright (c) 2020, STMicroelectronics - All Rights Reserved */ -#include "stm32mp15-ddr-1g-fw-config.dts" +#define DDR_SIZE 0x40000000 /* 1GB */ +#include "stm32mp15-fw-config.dts" diff --git a/fdts/stm32mp157c-dk2-fw-config.dts b/fdts/stm32mp157c-dk2-fw-config.dts index 256d0db935..d2be11aab2 100644 --- a/fdts/stm32mp157c-dk2-fw-config.dts +++ b/fdts/stm32mp157c-dk2-fw-config.dts @@ -3,4 +3,5 @@ * Copyright (c) 2020, STMicroelectronics - All Rights Reserved */ -#include "stm32mp15-ddr-512m-fw-config.dts" +#define DDR_SIZE 0x20000000 /* 512MB */ +#include "stm32mp15-fw-config.dts" diff --git a/fdts/stm32mp157c-ed1-fw-config.dts b/fdts/stm32mp157c-ed1-fw-config.dts index 10f9402c4a..275406410e 100644 --- a/fdts/stm32mp157c-ed1-fw-config.dts +++ b/fdts/stm32mp157c-ed1-fw-config.dts @@ -3,4 +3,5 @@ * Copyright (c) 2020, STMicroelectronics - All Rights Reserved */ -#include "stm32mp15-ddr-1g-fw-config.dts" +#define DDR_SIZE 0x40000000 /* 1GB */ +#include "stm32mp15-fw-config.dts" diff --git a/fdts/stm32mp157c-ev1-fw-config.dts b/fdts/stm32mp157c-ev1-fw-config.dts index 10f9402c4a..275406410e 100644 --- a/fdts/stm32mp157c-ev1-fw-config.dts +++ b/fdts/stm32mp157c-ev1-fw-config.dts @@ -3,4 +3,5 @@ * Copyright (c) 2020, STMicroelectronics - All Rights Reserved */ -#include "stm32mp15-ddr-1g-fw-config.dts" +#define DDR_SIZE 0x40000000 /* 1GB */ +#include "stm32mp15-fw-config.dts" diff --git a/fdts/stm32mp157d-dk1-fw-config.dts b/fdts/stm32mp157d-dk1-fw-config.dts index 256d0db935..d2be11aab2 100644 --- a/fdts/stm32mp157d-dk1-fw-config.dts +++ b/fdts/stm32mp157d-dk1-fw-config.dts @@ -3,4 +3,5 @@ * Copyright (c) 2020, STMicroelectronics - All Rights Reserved */ -#include "stm32mp15-ddr-512m-fw-config.dts" +#define DDR_SIZE 0x20000000 /* 512MB */ +#include "stm32mp15-fw-config.dts" diff --git a/fdts/stm32mp157d-ed1-fw-config.dts b/fdts/stm32mp157d-ed1-fw-config.dts index 10f9402c4a..275406410e 100644 --- a/fdts/stm32mp157d-ed1-fw-config.dts +++ b/fdts/stm32mp157d-ed1-fw-config.dts @@ -3,4 +3,5 @@ * Copyright (c) 2020, STMicroelectronics - All Rights Reserved */ -#include "stm32mp15-ddr-1g-fw-config.dts" +#define DDR_SIZE 0x40000000 /* 1GB */ +#include "stm32mp15-fw-config.dts" diff --git a/fdts/stm32mp157d-ev1-fw-config.dts b/fdts/stm32mp157d-ev1-fw-config.dts index 10f9402c4a..275406410e 100644 --- a/fdts/stm32mp157d-ev1-fw-config.dts +++ b/fdts/stm32mp157d-ev1-fw-config.dts @@ -3,4 +3,5 @@ * Copyright (c) 2020, STMicroelectronics - All Rights Reserved */ -#include "stm32mp15-ddr-1g-fw-config.dts" +#define DDR_SIZE 0x40000000 /* 1GB */ +#include "stm32mp15-fw-config.dts" diff --git a/fdts/stm32mp157f-dk2-fw-config.dts b/fdts/stm32mp157f-dk2-fw-config.dts index 256d0db935..d2be11aab2 100644 --- a/fdts/stm32mp157f-dk2-fw-config.dts +++ b/fdts/stm32mp157f-dk2-fw-config.dts @@ -3,4 +3,5 @@ * Copyright (c) 2020, STMicroelectronics - All Rights Reserved */ -#include "stm32mp15-ddr-512m-fw-config.dts" +#define DDR_SIZE 0x20000000 /* 512MB */ +#include "stm32mp15-fw-config.dts" diff --git a/fdts/stm32mp157f-ed1-fw-config.dts b/fdts/stm32mp157f-ed1-fw-config.dts index 10f9402c4a..275406410e 100644 --- a/fdts/stm32mp157f-ed1-fw-config.dts +++ b/fdts/stm32mp157f-ed1-fw-config.dts @@ -3,4 +3,5 @@ * Copyright (c) 2020, STMicroelectronics - All Rights Reserved */ -#include "stm32mp15-ddr-1g-fw-config.dts" +#define DDR_SIZE 0x40000000 /* 1GB */ +#include "stm32mp15-fw-config.dts" diff --git a/fdts/stm32mp157f-ev1-fw-config.dts b/fdts/stm32mp157f-ev1-fw-config.dts index 10f9402c4a..275406410e 100644 --- a/fdts/stm32mp157f-ev1-fw-config.dts +++ b/fdts/stm32mp157f-ev1-fw-config.dts @@ -3,4 +3,5 @@ * Copyright (c) 2020, STMicroelectronics - All Rights Reserved */ -#include "stm32mp15-ddr-1g-fw-config.dts" +#define DDR_SIZE 0x40000000 /* 1GB */ +#include "stm32mp15-fw-config.dts" diff --git a/fdts/stm32mp15xx-dkx.dtsi b/fdts/stm32mp15xx-dkx.dtsi index e5166706ee..fa1a4baaca 100644 --- a/fdts/stm32mp15xx-dkx.dtsi +++ b/fdts/stm32mp15xx-dkx.dtsi @@ -134,14 +134,15 @@ vtt_ddr: ldo3 { regulator-name = "vtt_ddr"; - regulator-min-microvolt = <500000>; - regulator-max-microvolt = <750000>; regulator-always-on; regulator-over-current-protection; + st,regulator-sink-source; }; vdd_usb: ldo4 { regulator-name = "vdd_usb"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; }; vdda: ldo5 { @@ -161,7 +162,6 @@ vref_ddr: vref_ddr { regulator-name = "vref_ddr"; regulator-always-on; - regulator-over-current-protection; }; bst_out: boost { @@ -254,7 +254,7 @@ CLK_CKPER_HSE CLK_FMC_ACLK CLK_QSPI_ACLK - CLK_ETH_DISABLED + CLK_ETH_PLL4P CLK_SDMMC12_PLL4P CLK_DSI_DSIPLL CLK_STGEN_HSE diff --git a/fdts/stm32mp15xx-edx.dtsi b/fdts/stm32mp15xx-edx.dtsi index 540f5b9d97..cccf3e3595 100644 --- a/fdts/stm32mp15xx-edx.dtsi +++ b/fdts/stm32mp15xx-edx.dtsi @@ -136,14 +136,15 @@ vtt_ddr: ldo3 { regulator-name = "vtt_ddr"; - regulator-min-microvolt = <500000>; - regulator-max-microvolt = <750000>; regulator-always-on; regulator-over-current-protection; + st,regulator-sink-source; }; vdd_usb: ldo4 { regulator-name = "vdd_usb"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; }; vdd_sd: ldo5 { @@ -162,7 +163,6 @@ vref_ddr: vref_ddr { regulator-name = "vref_ddr"; regulator-always-on; - regulator-over-current-protection; }; bst_out: boost { @@ -256,7 +256,7 @@ CLK_CKPER_HSE CLK_FMC_ACLK CLK_QSPI_ACLK - CLK_ETH_DISABLED + CLK_ETH_PLL4P CLK_SDMMC12_PLL4P CLK_DSI_DSIPLL CLK_STGEN_HSE diff --git a/include/arch/aarch32/el3_common_macros.S b/include/arch/aarch32/el3_common_macros.S index 6bbcde2e0a..ed4ca273e9 100644 --- a/include/arch/aarch32/el3_common_macros.S +++ b/include/arch/aarch32/el3_common_macros.S @@ -351,10 +351,21 @@ * includes the data and NOBITS sections. This is done to * safeguard against possible corruption of this memory by * dirty cache lines in a system cache as a result of use by - * an earlier boot loader stage. + * an earlier boot loader stage. If PIE is enabled however, + * RO sections including the GOT may be modified during + * pie fixup. Therefore, to be on the safe side, invalidate + * the entire image region if PIE is enabled. * ----------------------------------------------------------------- */ +#if ENABLE_PIE +#if SEPARATE_CODE_AND_RODATA + ldr r0, =__TEXT_START__ +#else + ldr r0, =__RO_START__ +#endif /* SEPARATE_CODE_AND_RODATA */ +#else ldr r0, =__RW_START__ +#endif /* ENABLE_PIE */ ldr r1, =__RW_END__ sub r1, r1, r0 bl inv_dcache_range diff --git a/include/arch/aarch64/el3_common_macros.S b/include/arch/aarch64/el3_common_macros.S index 6f4143c5f5..20adcac2fd 100644 --- a/include/arch/aarch64/el3_common_macros.S +++ b/include/arch/aarch64/el3_common_macros.S @@ -375,11 +375,24 @@ * includes the data and NOBITS sections. This is done to * safeguard against possible corruption of this memory by * dirty cache lines in a system cache as a result of use by - * an earlier boot loader stage. + * an earlier boot loader stage. If PIE is enabled however, + * RO sections including the GOT may be modified during + * pie fixup. Therefore, to be on the safe side, invalidate + * the entire image region if PIE is enabled. * ------------------------------------------------------------- */ +#if ENABLE_PIE +#if SEPARATE_CODE_AND_RODATA + adrp x0, __TEXT_START__ + add x0, x0, :lo12:__TEXT_START__ +#else + adrp x0, __RO_START__ + add x0, x0, :lo12:__RO_START__ +#endif /* SEPARATE_CODE_AND_RODATA */ +#else adrp x0, __RW_START__ add x0, x0, :lo12:__RW_START__ +#endif /* ENABLE_PIE */ adrp x1, __RW_END__ add x1, x1, :lo12:__RW_END__ sub x1, x1, x0 diff --git a/include/drivers/regulator.h b/include/drivers/regulator.h new file mode 100644 index 0000000000..392051f96e --- /dev/null +++ b/include/drivers/regulator.h @@ -0,0 +1,160 @@ +/* + * Copyright (c) 2017-2020, STMicroelectronics - All Rights Reserved + * + * SPDX-License-Identifier: BSD-3-Clause + */ +#ifndef REGULATOR_H +#define REGULATOR_H + +#include + +#ifndef PLAT_NB_RDEVS +#error "Missing PLAT_NB_RDEVS" +#endif + +#ifndef PLAT_NB_SUSPEND_MODES +#error "Missing PLAT_NB_SUSPEND_MODES" +#endif + +const char *plat_get_lp_mode_name(int mode); + +/* + * Consumer interface + */ + +/* regulator-always-on : regulator should never be disabled */ +#define REGUL_ALWAYS_ON BIT(0) +/* + * regulator-boot-on: + * It's expected that this regulator was left on by the bootloader. + * The core shouldn't prevent it from being turned off later. + * The regulator is needed to exit from suspend so it is turned on during suspend entry. + */ +#define REGUL_BOOT_ON BIT(1) +/* regulator-over-current-protection: Enable over current protection. */ +#define REGUL_OCP BIT(2) +/* regulator-active-discharge: enable active discharge. */ +#define REGUL_ACTIVE_DISCHARGE BIT(3) +/* regulator-pull-down: Enable pull down resistor when the regulator is disabled. */ +#define REGUL_PULL_DOWN BIT(4) +/* + * st,mask-reset: set mask reset for the regulator, meaning that the regulator + * setting is maintained during pmic reset. + */ +#define REGUL_MASK_RESET BIT(5) +/* st,regulator-sink-source: set the regulator in sink source mode */ +#define REGUL_SINK_SOURCE BIT(6) +/* st,regulator-bypass: set the regulator in bypass mode */ +#define REGUL_ENABLE_BYPASS BIT(7) + +struct rdev *regulator_get_by_name(const char *node_name); + +#if defined(IMAGE_BL32) +struct rdev *regulator_get_by_regulator_name(const char *reg_name); +#endif + +struct rdev *regulator_get_by_supply_name(const void *fdt, int node, const char *name); + +int regulator_enable(struct rdev *rdev); +int regulator_disable(struct rdev *rdev); +int regulator_is_enabled(const struct rdev *rdev); + +int regulator_set_voltage(struct rdev *rdev, uint16_t volt); +int regulator_set_min_voltage(struct rdev *rdev); +int regulator_get_voltage(const struct rdev *rdev); + +int regulator_list_voltages(const struct rdev *rdev, const uint16_t **levels, size_t *count); +void regulator_get_range(const struct rdev *rdev, uint16_t *min_mv, uint16_t *max_mv); +int regulator_set_flag(struct rdev *rdev, uint16_t flag); + +/* + * Driver Interface + */ + +/* set_state() arguments */ +#define STATE_DISABLE false +#define STATE_ENABLE true + +/* suspend() arguments */ +#define LP_STATE_OFF BIT(0) +#define LP_STATE_ON BIT(1) +#define LP_STATE_UNCHANGED BIT(2) +#define LP_STATE_SET_VOLT BIT(3) + +struct regul_description { + const char *node_name; + const struct regul_ops *ops; + const void *driver_data; + const char *supply_name; + const uint32_t enable_ramp_delay; +}; + +struct regul_ops { + int (*set_state)(const struct regul_description *desc, bool state); + int (*get_state)(const struct regul_description *desc); + int (*set_voltage)(const struct regul_description *desc, uint16_t mv); + int (*get_voltage)(const struct regul_description *desc); + int (*list_voltages)(const struct regul_description *desc, + const uint16_t **levels, size_t *count); + int (*set_flag)(const struct regul_description *desc, uint16_t flag); +#if defined(IMAGE_BL32) + void (*lock)(const struct regul_description *desc); + void (*unlock)(const struct regul_description *desc); + int (*suspend)(const struct regul_description *desc, uint8_t state, + uint16_t mv); +#endif +}; + +int regulator_register(const struct regul_description *desc, int node); + +/* + * Internal regulator structure + * The structure is internal to the core, and the content should not be used + * by a consumer nor a driver. + */ +struct rdev { + const struct regul_description *desc; + + int32_t phandle; + + uint16_t min_mv; + uint16_t max_mv; + + uint16_t flags; + + uint32_t enable_ramp_delay; +#if defined(IMAGE_BL32) + const char *reg_name; + + uint8_t use_count; + + int32_t supply_phandle; + struct rdev *supply_dev; + + uint8_t lp_state[PLAT_NB_SUSPEND_MODES]; + uint16_t lp_mv[PLAT_NB_SUSPEND_MODES]; +#endif +}; + +#if defined(IMAGE_BL32) + +/* Boot and init */ +int regulator_core_config(void); +int regulator_core_cleanup(void); + +/* Suspend resume operations */ +#define PLAT_BACKUP_REGULATOR_SIZE (sizeof(int8_t) * PLAT_NB_RDEVS) + +int regulator_core_suspend(int mode); +int regulator_core_resume(void); + +void regulator_core_backup_context(void *backup_area, size_t backup_size); +void regulator_core_restore_context(void *backup_area, size_t backup_size); + +#if LOG_LEVEL >= LOG_LEVEL_VERBOSE +void regulator_core_dump(void); +#endif + +#endif + +#endif /* REGULATOR_H */ diff --git a/include/drivers/st/regulator_fixed.h b/include/drivers/st/regulator_fixed.h new file mode 100644 index 0000000000..b03c6e38c6 --- /dev/null +++ b/include/drivers/st/regulator_fixed.h @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2020-2021, STMicroelectronics - All Rights Reserved + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef REGULATOR_FIXED_H +#define REGULATOR_FIXED_H + +int fixed_regulator_register(void); + +#endif /* REGULATOR_FIXED_H */ diff --git a/include/drivers/st/stm32_gpio.h b/include/drivers/st/stm32_gpio.h index e241f584f7..b072345159 100644 --- a/include/drivers/st/stm32_gpio.h +++ b/include/drivers/st/stm32_gpio.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2019, STMicroelectronics - All Rights Reserved + * Copyright (c) 2015-2021, STMicroelectronics - All Rights Reserved * * SPDX-License-Identifier: BSD-3-Clause */ @@ -52,6 +52,7 @@ int dt_set_pinctrl_config(int node); void set_gpio(uint32_t bank, uint32_t pin, uint32_t mode, uint32_t speed, uint32_t pull, uint32_t alternate, uint8_t status); void set_gpio_secure_cfg(uint32_t bank, uint32_t pin, bool secure); +void set_gpio_reset_cfg(uint32_t bank, uint32_t pin); #endif /*__ASSEMBLER__*/ #endif /* STM32_GPIO_H */ diff --git a/include/drivers/st/stm32_sdmmc2.h b/include/drivers/st/stm32_sdmmc2.h index 5b4bd0e167..af02b91ea5 100644 --- a/include/drivers/st/stm32_sdmmc2.h +++ b/include/drivers/st/stm32_sdmmc2.h @@ -10,7 +10,7 @@ #include #include -#include +#include struct stm32_sdmmc2_params { uintptr_t reg_base; @@ -25,7 +25,7 @@ struct stm32_sdmmc2_params { unsigned int reset_id; unsigned int max_freq; bool use_dma; - struct stm32mp_regulator vmmc_regu; + struct rdev *vmmc_regu; }; unsigned long long stm32_sdmmc2_mmc_get_device_size(void); diff --git a/include/drivers/st/stm32_tamp.h b/include/drivers/st/stm32_tamp.h index 424cbb205a..11dc96df69 100644 --- a/include/drivers/st/stm32_tamp.h +++ b/include/drivers/st/stm32_tamp.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014-2020, STMicroelectronics - All Rights Reserved + * Copyright (c) 2014-2021, STMicroelectronics - All Rights Reserved * * SPDX-License-Identifier: BSD-3-Clause */ @@ -9,22 +9,22 @@ /* Internal Tamper */ enum stm32_tamp_int_id { - ITAMP1 = 0, - ITAMP2, - ITAMP3, - ITAMP4, - ITAMP5, - ITAMP6, - ITAMP7, - ITAMP8, - ITAMP9, - ITAMP10, - ITAMP11, - ITAMP12, - ITAMP13, - ITAMP14, - ITAMP15, - ITAMP16 + INT_TAMP1 = 0, + INT_TAMP2, + INT_TAMP3, + INT_TAMP4, + INT_TAMP5, + INT_TAMP6, + INT_TAMP7, + INT_TAMP8, + INT_TAMP9, + INT_TAMP10, + INT_TAMP11, + INT_TAMP12, + INT_TAMP13, + INT_TAMP14, + INT_TAMP15, + INT_TAMP16 }; /* External Tamper */ @@ -39,95 +39,111 @@ enum stm32_tamp_ext_id { EXT_TAMP8 }; -enum stm32_tamp_state { - TAMP_DISABLE = 0, - TAMP_ENABLE +/* Out pin to compare for external Tamper */ +enum stm32_tamp_ext_out_id { + TAMPOUTSEL_SAME_AS_INPUT = 0, + TAMPOUTSEL1 = 1, + TAMPOUTSEL2, + TAMPOUTSEL3, + TAMPOUTSEL4, + TAMPOUTSEL5, + TAMPOUTSEL6, + TAMPOUTSEL7, + TAMPOUTSEL8, }; -#define TAMP_UNUSED {.id = -1} +/* Define number of backup registers in zone 1 and zone 2 (remaining are in + * zone 3) + * + * backup registers in zone 1 : read/write only in secure mode + * zone 2 : write only in secure mode, read in secure + * and non-secure mode + * zone 3 : read/write in secure and non-secure mode + * + * Protection zone 1 if nb_zone1_regs == 0 no backup register are in zone 1 + * else backup registers from TAMP_BKP0R to TAMP_BKPxR + * with x = nb_zone1_regs - 1 are in zone 1. + * Protection zone 2 if nb_zone2_regs == 0 no backup register are in zone 2 + * else backup registers from TAMP_BKPyR with y = nb_zone1_regs + * to TAMP_BKPzR with z = (nb_zone1_regs1 + nb_zone2_regs - 1) + * are in zone 2. + * Protection zone 3 backup registers from TAMP_BKPtR + * with t = nb_zone1_regs1 + nb_zone2_regs to last backup + * register are in zone 3. + */ +struct bkpregs_conf { + uint32_t nb_zone1_regs; + uint32_t nb_zone2_regs; +}; -/* define TAMPER modes */ +/* Define TAMPER modes */ +#define TAMP_DISABLE 0x0U +#define TAMP_ENABLE 0x1U #define TAMP_TRIG_OFF 0x0U -#define TAMP_TRIG_ON 0x1U -#define TAMP_ACTIVE 0x2U +#define TAMP_TRIG_ON 0x2U +#define TAMP_ACTIVE 0x4U #define TAMP_ERASE 0x0U -#define TAMP_NOERASE 0x1U +#define TAMP_NOERASE 0x8U #define TAMP_NO_EVT_MASK 0x0U -#define TAMP_EVT_MASK 0x1U - -/* define Passive FILTER mode */ -#define TAMP_FILTER_PRECHARGE 0x0U -#define TAMP_FILTER_PULL_UP_DISABLE 0x1U -#define TAMP_FILTER_DURATION_1_CYCLE 0x0U -#define TAMP_FILTER_DURATION_2_CYCLES 0x1U -#define TAMP_FILTER_DURATION_3_CYCLES 0x2U -#define TAMP_FILTER_DURATION_4_CYCLES 0x3U -#define TAMP_FILTER_COUNT_1 0x0U -#define TAMP_FILTER_COUNT_2 0x1U -#define TAMP_FILTER_COUNT_4 0x2U -#define TAMP_FILTER_COUNT_8 0x3U -#define TAMP_FILTER_SAMPLING_32768 0x0U -#define TAMP_FILTER_SAMPLING_16384 0x1U -#define TAMP_FILTER_SAMPLING_8192 0x2U -#define TAMP_FILTER_SAMPLING_4096 0x3U -#define TAMP_FILTER_SAMPLING_2048 0x4U -#define TAMP_FILTER_SAMPLING_1024 0x5U -#define TAMP_FILTER_SAMPLING_512 0x6U -#define TAMP_FILTER_SAMPLING_256 0x7U - -/* define active filter */ -#define TAMP_ACTIVE_FILTER_OFF 0x0U -#define TAMP_ACTIVE_FILTER_ON 0x1U -#define TAMP_ACTIVE_ATO_DEDICATED 0x0U -#define TAMP_ACTIVE_ATO_TAMPOUTSEL 0x1U -#define TAMP_ACTIVE_APER_1_OUTPUT 0x0U -#define TAMP_ACTIVE_APER_2_OUTPUTS 0x1U -#define TAMP_ACTIVE_APER_3_4_OUTPUTS 0x2U -#define TAMP_ACTIVE_APER_5_OUTPUTS 0x3U -#define TAMP_ACTIVE_CKSEL_DIV_0 0x0U -#define TAMP_ACTIVE_CKSEL_DIV_2 0x1U -#define TAMP_ACTIVE_CKSEL_DIV_4 0x2U -#define TAMP_ACTIVE_CKSEL_DIV_8 0x3U -#define TAMP_ACTIVE_CKSEL_DIV_16 0x4U -#define TAMP_ACTIVE_CKSEL_DIV_32 0x5U -#define TAMP_ACTIVE_CKSEL_DIV_64 0x6U -#define TAMP_ACTIVE_CKSEL_DIV_128 0x7U -#define TAMP_ACTIVE_ATOSEL_OUT1_(X) (0x0U << ((X) * 2)) -#define TAMP_ACTIVE_ATOSEL_OUT2_(X) (0x1U << ((X) * 2)) -#define TAMP_ACTIVE_ATOSEL_OUT3_(X) (0x2U << ((X) * 2)) -#define TAMP_ACTIVE_ATOSEL_OUT4_(X) (0x3U << ((X) * 2)) - -#define TAMP_EXT(tamp_id, trig, erase, mask) (((tamp_id) << 3) | ((trig) << 2)\ - | ((erase) << 1) | (mask)) - -#define TAMP_FLTCR(precharge, duration, count, sample) (((precharge) << 7) |\ - ((duration) << 5) |\ - ((count) << 3) |\ - (sample)) - -#define TAMP_ACT(filter, ato, aper, atcksel, atosel) (((filter) << 31) |\ - ((ato) << 30) |\ - ((aper) << 24) |\ - ((atcksel) << 16) |\ - (atosel) << 8) - -struct stm32_tamp_int { - int id; - void (*func)(int id); -}; - -struct stm32_tamp_ext { - int id; - uint8_t mode; - uint8_t erase; - uint8_t evt_mask; - void (*func)(int id); -}; +#define TAMP_EVT_MASK 0x10U + +/* Define Passive FILTER mode */ +#define TAMP_FILTER_TAMPPUDIS_OFFSET 7U +#define TAMP_FILTER_PRECHARGE (0x0U << TAMP_FILTER_TAMPPUDIS_OFFSET) +#define TAMP_FILTER_PULL_UP_DISABLE (0x1U << TAMP_FILTER_TAMPPUDIS_OFFSET) +#define TAMP_FILTER_TAMPPRCH_OFFSET 5U +#define TAMP_FILTER_DURATION_1_CYCLE (0x0U << TAMP_FILTER_TAMPPRCH_OFFSET) +#define TAMP_FILTER_DURATION_2_CYCLES (0x1U << TAMP_FILTER_TAMPPRCH_OFFSET) +#define TAMP_FILTER_DURATION_4_CYCLES (0x2U << TAMP_FILTER_TAMPPRCH_OFFSET) +#define TAMP_FILTER_DURATION_8_CYCLES (0x3U << TAMP_FILTER_TAMPPRCH_OFFSET) +#define TAMP_FILTER_TAMPFLT_OFFSET 3U +#define TAMP_FILTER_COUNT_1 (0x0U << TAMP_FILTER_TAMPFLT_OFFSET) +#define TAMP_FILTER_COUNT_2 (0x1U << TAMP_FILTER_TAMPFLT_OFFSET) +#define TAMP_FILTER_COUNT_4 (0x2U << TAMP_FILTER_TAMPFLT_OFFSET) +#define TAMP_FILTER_COUNT_8 (0x3U << TAMP_FILTER_TAMPFLT_OFFSET) +#define TAMP_FILTER_TAMPFREQ_OFFSET 0U +#define TAMP_FILTER_SAMPLING_32768 (0x0U << TAMP_FILTER_TAMPFREQ_OFFSET) +#define TAMP_FILTER_SAMPLING_16384 (0x1U << TAMP_FILTER_TAMPFREQ_OFFSET) +#define TAMP_FILTER_SAMPLING_8192 (0x2U << TAMP_FILTER_TAMPFREQ_OFFSET) +#define TAMP_FILTER_SAMPLING_4096 (0x3U << TAMP_FILTER_TAMPFREQ_OFFSET) +#define TAMP_FILTER_SAMPLING_2048 (0x4U << TAMP_FILTER_TAMPFREQ_OFFSET) +#define TAMP_FILTER_SAMPLING_1024 (0x5U << TAMP_FILTER_TAMPFREQ_OFFSET) +#define TAMP_FILTER_SAMPLING_512 (0x6U << TAMP_FILTER_TAMPFREQ_OFFSET) +#define TAMP_FILTER_SAMPLING_256 (0x7U << TAMP_FILTER_TAMPFREQ_OFFSET) + +/* Define active filter */ +#define TAMP_ACTIVE_FLTEN_OFFSET 31U +#define TAMP_ACTIVE_FILTER_OFF (0x0U << TAMP_ACTIVE_FLTEN_OFFSET) +#define TAMP_ACTIVE_FILTER_ON (0x1U << TAMP_ACTIVE_FLTEN_OFFSET) +#define TAMP_FILTER_ATOSHARE_OFFSET 30U +#define TAMP_FILTER_USE_DEDICATED_OUT (0x0U << TAMP_FILTER_ATOSHARE_OFFSET) +#define TAMP_FILTER_SELECT_OUT (0x1U << TAMP_FILTER_ATOSHARE_OFFSET) +#define TAMP_ACTIVE_ATPER_OFFSET 24U +#define TAMP_ACTIVE_ATPER_1_OUTPUT (0x0U << TAMP_ACTIVE_ATPER_OFFSET) +#define TAMP_ACTIVE_ATPER_2_OUTPUTS (0x1U << TAMP_ACTIVE_ATPER_OFFSET) +#define TAMP_ACTIVE_ATPER_3_4_OUTPUTS (0x2U << TAMP_ACTIVE_ATPER_OFFSET) +#define TAMP_ACTIVE_ATPER_5_OUTPUTS (0x3U << TAMP_ACTIVE_ATPER_OFFSET) +#define TAMP_ACTIVE_ATCKSEL_OFFSET 16U +#define TAMP_ACTIVE_CKSEL_DIV_0 (0x0U << TAMP_ACTIVE_ATCKSEL_OFFSET) +#define TAMP_ACTIVE_CKSEL_DIV_2 (0x1U << TAMP_ACTIVE_ATCKSEL_OFFSET) +#define TAMP_ACTIVE_CKSEL_DIV_4 (0x2U << TAMP_ACTIVE_ATCKSEL_OFFSET) +#define TAMP_ACTIVE_CKSEL_DIV_8 (0x3U << TAMP_ACTIVE_ATCKSEL_OFFSET) +#define TAMP_ACTIVE_CKSEL_DIV_16 (0x4U << TAMP_ACTIVE_ATCKSEL_OFFSET) +#define TAMP_ACTIVE_CKSEL_DIV_32 (0x5U << TAMP_ACTIVE_ATCKSEL_OFFSET) +#define TAMP_ACTIVE_CKSEL_DIV_64 (0x6U << TAMP_ACTIVE_ATCKSEL_OFFSET) +#define TAMP_ACTIVE_CKSEL_DIV_128 (0x7U << TAMP_ACTIVE_ATCKSEL_OFFSET) + +/* Define secure mode acces */ +/* Tamper configuration and interrupt can be written when the APB access is secure or nonsecure.*/ +#define TAMP_REGS_IT_UNSECURE 0U +/* Tamper configuration and interrupt can be written only when the APB access is secure.*/ +#define TAMP_REGS_IT_SECURE BIT(31) /* - * stm32_tamp_write_mcounter : Increase monotonic counter + * stm32_tamp_write_mcounter : Increase monotonic counter[counter_idx] */ -void stm32_tamp_write_mcounter(void); +int stm32_tamp_write_mcounter(int counter_idx); +uint32_t stm32_tamp_read_mcounter(int counter_idx); /* * stm32_tamp_it_handler : Interrupt handler @@ -135,24 +151,69 @@ void stm32_tamp_write_mcounter(void); void stm32_tamp_it_handler(void); /* - * stm32_tamp_configure_internal: Configure internal tamper - * tamper_list: List of tamper to enable - * nb_tamper: Number of tamper in list + * stm32_tamp_configure_secure_access: Configure which registers can be + * read/write from unsecure world + * secure_conf is a bit field from TAMP_.*_{UN,}SECURE define + */ +void stm32_tamp_configure_secure_access(uint32_t secure_conf); + +/* + * stm32_tamp_configure_privilege_access: Configure which registers can be + * read/write from unpriviliged world + * privilege_conf is a bit field from TAMP_.*_{UN,}PRIVILEGE define + */ +void stm32_tamp_configure_privilege_access(uint32_t privilege_conf); + +/* + * stm32_tamp_configure_passive: Configure passive mode + * passive_conf is a bit field from TAMP_FILTER_* define + */ +void stm32_tamp_configure_passive(uint32_t passive_conf); + +/* + * stm32_tamp_configure_ctive: Configure active mode + * passive_conf is a bit field from TAMP_ACTIVE_* define + */ +void stm32_tamp_configure_active(uint32_t active_conf); + +/* + * stm32_tamp_configure_internal: Configure one internal tamper + * id: internal tamper id + * mode: bitmask from TAMPER modes define + * callback: function to call when tamper is raised (can be NULL), + * called in interrupt context, + * if callback returns negative value, blocked secrets stay blocked + * (driver doesn't release this specific tamper). + * if callback returns 0 this specific tamp is ack (in case of no-erase + * tamper, blocked secret are unblocked) + * if callback returns positive value, this specific tamp is ack (in + * case of no-erase tamper, blocked secret are unblocked) and system is + * rebooted). + * + * return: -EINVAL if 'id' is not a valid internal tamp id, else 0 */ -void stm32_tamp_configure_internal(struct stm32_tamp_int *tamper_list, - uint16_t nb_tamper); +int stm32_tamp_configure_internal(enum stm32_tamp_int_id id, uint32_t mode, + int (*callback)(int id)); /* - * stm32_tamp_configure_external: Configure external tamper and associated - * configuration for filtering - * ext_tamp_list: List of external tamper to configure - * nb_tamper: Number of tamper in list - * passive_conf: Filter configuration - * active_conf: Configuration for active tamper + * stm32_tamp_configure_external: Configure one external tamper + * id: external tamper id + * mode: bitmask from TAMPER modes define + * pin_out; output pin connected to input pin (linekd with selected ext tamp id) + * callback: function to call when tamper is raised (can be NULL), + * called in interrupt context, + * if callback returns negative value, blocked secrets stay blocked + * (driver doesn't release this specific tamper). + * if callback returns 0 this specific tamp is ack (in case of no-erase + * tamper, blocked secret are unblocked) + * if callback returns positive value, this specific tamp is ack (in + * case of no-erase tamper, blocked secret are unblocked) and system is + * rebooted). + * + * return: -EINVAL if 'id' is not a valid external tamp id, else 0 */ -void stm32_tamp_configure_external(struct stm32_tamp_ext *ext_tamper_list, - uint8_t nb_tamper, uint32_t passive_conf, - uint32_t active_conf); +int stm32_tamp_configure_external(enum stm32_tamp_ext_id id, uint32_t mode, + enum stm32_tamp_ext_out_id out_pin, int (*callback)(int id)); /* * stm32_tamp_init: Initialize tamper from DT @@ -160,4 +221,32 @@ void stm32_tamp_configure_external(struct stm32_tamp_ext *ext_tamper_list, */ int stm32_tamp_init(void); +/* + * stm32_tamp_set_secure_bkprwregs : Configure backup registers zone. + * registers in zone 1 : read/write only in secure mode + * zone 2 : write only in secure mode, read in secure and non-secure mode + * zone 3 : read/write in secure and non-secure mode + * + * bkpregs_conf : a pointer to struct bkpregs_conf that define the number of registers in zone 1 + * and zone 2 (remaining backup registers will be in zone 3). + * + * return 0 if OK, -ENODEV if zone 1 and/or zone 2 definition are out of range. + */ +int stm32_tamp_set_secure_bkpregs(struct bkpregs_conf *bkpregs_conf); + +/* + * stm32_tamp_set_config: apply configuration + * default one if no previous call to any of : + * stm32_tamp_configure_passive() + * stm32_tamp_configure_active() + * stm32_tamp_configure_internal() + * stm32_tamp_configure_external() + * stm32_tamp_configure_secret_list() + * stm32_tamp_configure_secure_access() + * stm32_tamp_configure_privilige_access() + * + * return: < 0 if unable to apply configuration, else 0 + */ +int stm32_tamp_set_config(void); + #endif /* STM32_TAMP_H */ diff --git a/include/drivers/st/stm32mp1_ddr_regs.h b/include/drivers/st/stm32mp1_ddr_regs.h index e298fcf77b..1ccefc4fca 100644 --- a/include/drivers/st/stm32mp1_ddr_regs.h +++ b/include/drivers/st/stm32mp1_ddr_regs.h @@ -361,6 +361,7 @@ struct stm32mp1_ddrphy { #define DDRPHYC_PIR_DRAMRST BIT(5) #define DDRPHYC_PIR_DRAMINIT BIT(6) #define DDRPHYC_PIR_QSTRN BIT(7) +#define DDRPHYC_PIR_RVTRN BIT(8) #define DDRPHYC_PIR_ICPC BIT(16) #define DDRPHYC_PIR_ZCALBYP BIT(30) #define DDRPHYC_PIR_INITSTEPS_MASK GENMASK(31, 7) diff --git a/include/drivers/st/stm32mp1_rcc.h b/include/drivers/st/stm32mp1_rcc.h index 616051e772..ec6b485046 100644 --- a/include/drivers/st/stm32mp1_rcc.h +++ b/include/drivers/st/stm32mp1_rcc.h @@ -306,6 +306,8 @@ /* Fields of RCC_RDLSICR register */ #define RCC_RDLSICR_LSION BIT(0) #define RCC_RDLSICR_LSIRDY BIT(1) +#define RCC_RDLSICR_MRD_MASK GENMASK(20, 16) +#define RCC_RDLSICR_MRD_SHIFT 16 /* Used for all RCC_PLLCR registers */ #define RCC_PLLNCR_PLLON BIT(0) diff --git a/include/drivers/st/stm32mp_ddr_test.h b/include/drivers/st/stm32mp_ddr_test.h new file mode 100644 index 0000000000..fe4c8c08e0 --- /dev/null +++ b/include/drivers/st/stm32mp_ddr_test.h @@ -0,0 +1,15 @@ +/* + * Copyright (C) 2021, STMicroelectronics - All Rights Reserved + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef STM32MP_DDR_TEST_H +#define STM32MP_DDR_TEST_H + +uint32_t stm32mp_ddr_test_rw_access(void); +uint32_t stm32mp_ddr_test_data_bus(void); +uint32_t stm32mp_ddr_test_addr_bus(uint64_t size); +uint32_t stm32mp_ddr_check_size(void); + +#endif /* STM32MP_DDR_TEST_H */ diff --git a/include/drivers/st/stm32mp_dummy_regulator.h b/include/drivers/st/stm32mp_dummy_regulator.h deleted file mode 100644 index 6804192ba0..0000000000 --- a/include/drivers/st/stm32mp_dummy_regulator.h +++ /dev/null @@ -1,14 +0,0 @@ -/* - * Copyright (C) 2019, STMicroelectronics - All Rights Reserved - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -#ifndef STM32MP_DUMMY_REGULATOR_H -#define STM32MP_DUMMY_REGULATOR_H - -#include - -void bind_dummy_regulator(struct stm32mp_regulator *regu); - -#endif /* STM32MP_DUMMY_REGULATOR_H */ diff --git a/include/drivers/st/stm32mp_pmic.h b/include/drivers/st/stm32mp_pmic.h index 898a28b44c..dd91d5eebc 100644 --- a/include/drivers/st/stm32mp_pmic.h +++ b/include/drivers/st/stm32mp_pmic.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2020, STMicroelectronics - All Rights Reserved + * Copyright (c) 2017-2021, STMicroelectronics - All Rights Reserved * * SPDX-License-Identifier: BSD-3-Clause */ @@ -11,8 +11,6 @@ #include -#include - /* * dt_pmic_status - Check PMIC status from device tree * @@ -21,31 +19,6 @@ */ int dt_pmic_status(void); -/* - * dt_pmic_configure_boot_on_regulators - Configure boot-on and always-on - * regulators from device tree configuration - * - * Returns 0 on success, and negative values on errors - */ -int pmic_configure_boot_on_regulators(void); - -int pmic_set_lp_config(const char *node_name); - -/* - * dt_pmic_find_supply - Find the supply name related to a regulator name - * - * Returns 0 on success, and negative values on errors - */ -int dt_pmic_find_supply(const char **supply_name, const char *regu_name); - -/* - * pmic_set_regulator_min_voltage - Set target supply to its device tree - * "regulator-min-microvolt" value. - * - * Returns 0 on success, and negative values on errors - */ -int pmic_set_regulator_min_voltage(const char *regu_name); - /* * initialize_pmic_i2c - Initialize I2C for the PMIC control * @@ -60,13 +33,6 @@ bool initialize_pmic_i2c(void); */ void initialize_pmic(void); -/* - * configure_pmic - PMIC configuration function, called at platform init - * - * Panics on errors - */ -void configure_pmic(void); - #if DEBUG void print_pmic_info_and_debug(void); #else @@ -75,9 +41,6 @@ static inline void print_pmic_info_and_debug(void) } #endif -bool is_pmic_regulator(struct stm32mp_regulator *regu); -void bind_pmic_regulator(struct stm32mp_regulator *regu); - /* * pmic_ddr_power_init - Initialize regulators required for DDR * @@ -85,4 +48,11 @@ void bind_pmic_regulator(struct stm32mp_regulator *regu); */ int pmic_ddr_power_init(enum ddr_type ddr_type); +/* + * pmic_switch_off - switch off the platform with PMIC + * + * Panics on errors + */ +void pmic_switch_off(void); + #endif /* STM32MP_PMIC_H */ diff --git a/include/drivers/st/stm32mp_regulator.h b/include/drivers/st/stm32mp_regulator.h deleted file mode 100644 index 7a66b97ba7..0000000000 --- a/include/drivers/st/stm32mp_regulator.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (C) 2019, STMicroelectronics - All Rights Reserved - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -#ifndef STM32MP_REGULATOR_H -#define STM32MP_REGULATOR_H - -#include - -struct stm32mp_regulator; - -struct stm32mp_regulator_ops { - int (*enable)(struct stm32mp_regulator *regu); - int (*disable)(struct stm32mp_regulator *regu); -}; - -struct stm32mp_regulator { - const struct stm32mp_regulator_ops *ops; - int id; - bool always_on; -}; - -int stm32mp_regulator_enable(struct stm32mp_regulator *regu); -int stm32mp_regulator_disable(struct stm32mp_regulator *regu); -int stm32mp_regulator_register(struct stm32mp_regulator *regu); - -int plat_bind_regulator(struct stm32mp_regulator *regu); - -#endif /* STM32MP_REGULATOR_H */ diff --git a/include/drivers/st/stpmic1.h b/include/drivers/st/stpmic1.h index 5c8933d84d..4e19ba3e5c 100644 --- a/include/drivers/st/stpmic1.h +++ b/include/drivers/st/stpmic1.h @@ -103,6 +103,22 @@ #define BUCK4_PULL_DOWN_SHIFT 6 #define VREF_DDR_PULL_DOWN_SHIFT 4 +/* ICC register */ +#define BUCK1_ICC_SHIFT 0 +#define BUCK2_ICC_SHIFT 1 +#define BUCK3_ICC_SHIFT 2 +#define BUCK4_ICC_SHIFT 3 +#define PWR_SW1_ICC_SHIFT 4 +#define PWR_SW2_ICC_SHIFT 5 +#define BOOST_ICC_SHIFT 6 + +#define LDO1_ICC_SHIFT 0 +#define LDO2_ICC_SHIFT 1 +#define LDO3_ICC_SHIFT 2 +#define LDO4_ICC_SHIFT 3 +#define LDO5_ICC_SHIFT 4 +#define LDO6_ICC_SHIFT 5 + /* Buck Mask reset register */ #define BUCK1_MASK_RESET 0 #define BUCK2_MASK_RESET 1 @@ -118,6 +134,10 @@ #define LDO6_MASK_RESET 5 #define VREF_DDR_MASK_RESET 6 +/* LDO3 Special modes */ +#define LDO3_BYPASS BIT(7) +#define LDO3_DDR_SEL 31U + /* Main PMIC Control Register (MAIN_CONTROL_REG) */ #define ICC_EVENT_ENABLED BIT(4) #define PWRCTRL_POLARITY_HIGH BIT(3) @@ -145,6 +165,8 @@ /* USB Control Register */ #define BOOST_OVP_DISABLED BIT(7) #define VBUS_OTG_DETECTION_DISABLED BIT(6) +#define SW_OUT_DISCHARGE BIT(5) +#define VBUS_OTG_DISCHARGE BIT(4) #define OCP_LIMIT_HIGH BIT(3) #define SWIN_SWOUT_ENABLED BIT(2) #define USBSW_OTG_SWITCH_ENABLED BIT(1) @@ -159,9 +181,15 @@ int stpmic1_regulator_enable(const char *name); int stpmic1_regulator_disable(const char *name); bool stpmic1_is_regulator_enabled(const char *name); int stpmic1_regulator_voltage_set(const char *name, uint16_t millivolts); +int stpmic1_regulator_levels_mv(const char *name, const uint16_t **levels, + size_t *levels_count); int stpmic1_regulator_voltage_get(const char *name); int stpmic1_regulator_pull_down_set(const char *name); int stpmic1_regulator_mask_reset_set(const char *name); +int stpmic1_regulator_icc_set(const char *name); +int stpmic1_regulator_sink_mode_set(const char *name); +int stpmic1_regulator_bypass_mode_set(const char *name); +int stpmic1_active_discharge_mode_set(const char *name); int stpmic1_lp_copy_reg(const char *name); int stpmic1_lp_reg_on_off(const char *name, uint8_t enable); int stpmic1_lp_set_mode(const char *name, uint8_t hplp); diff --git a/include/dt-bindings/interrupt-controller/arm-gic.h b/include/dt-bindings/interrupt-controller/arm-gic.h index aa9158cb1b..881159c7fc 100644 --- a/include/dt-bindings/interrupt-controller/arm-gic.h +++ b/include/dt-bindings/interrupt-controller/arm-gic.h @@ -1,21 +1,26 @@ -/* SPDX-License-Identifier: GPL-2.0 or BSD-3-Clause */ /* + * Copyright (c) 2019-2021, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: MIT + * * This header provides constants for the ARM GIC. */ #ifndef _DT_BINDINGS_INTERRUPT_CONTROLLER_ARM_GIC_H #define _DT_BINDINGS_INTERRUPT_CONTROLLER_ARM_GIC_H +#include + /* interrupt specifier cell 0 */ #define GIC_SPI 0 #define GIC_PPI 1 -#define IRQ_TYPE_NONE 0 -#define IRQ_TYPE_EDGE_RISING 1 -#define IRQ_TYPE_EDGE_FALLING 2 -#define IRQ_TYPE_EDGE_BOTH (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING) -#define IRQ_TYPE_LEVEL_HIGH 4 -#define IRQ_TYPE_LEVEL_LOW 8 +/* + * Interrupt specifier cell 2. + * The flags in irq.h are valid, plus those below. + */ +#define GIC_CPU_MASK_RAW(x) ((x) << 8) +#define GIC_CPU_MASK_SIMPLE(num) GIC_CPU_MASK_RAW((1 << (num)) - 1) #endif diff --git a/include/dt-bindings/interrupt-controller/irq.h b/include/dt-bindings/interrupt-controller/irq.h new file mode 100644 index 0000000000..1ff6681e24 --- /dev/null +++ b/include/dt-bindings/interrupt-controller/irq.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2021, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: MIT + * + * This header provides constants for most IRQ bindings. + * + * Most IRQ bindings include a flags cell as part of the IRQ specifier. + * In most cases, the format of the flags cell uses the standard values + * defined in this header. + */ + +#ifndef _DT_BINDINGS_INTERRUPT_CONTROLLER_IRQ_H +#define _DT_BINDINGS_INTERRUPT_CONTROLLER_IRQ_H + +#define IRQ_TYPE_NONE 0 +#define IRQ_TYPE_EDGE_RISING 1 +#define IRQ_TYPE_EDGE_FALLING 2 +#define IRQ_TYPE_EDGE_BOTH (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING) +#define IRQ_TYPE_LEVEL_HIGH 4 +#define IRQ_TYPE_LEVEL_LOW 8 + +#endif diff --git a/lib/aarch32/misc_helpers.S b/lib/aarch32/misc_helpers.S index aea975c0ad..1cd8e236cf 100644 --- a/lib/aarch32/misc_helpers.S +++ b/lib/aarch32/misc_helpers.S @@ -301,9 +301,9 @@ func fixup_gdt_reloc cmp r4, r6 blo 2f - /* Skip adding offset if address is >= upper limit */ + /* Skip adding offset if address is > upper limit */ cmp r4, r7 - bhs 2f + bhi 2f add r4, r0, r4 str r4, [r3] diff --git a/licenses/LICENSE.MIT b/licenses/LICENSE.MIT new file mode 100644 index 0000000000..8aa26455d2 --- /dev/null +++ b/licenses/LICENSE.MIT @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) [year] [fullname] + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/plat/st/common/bl2_io_storage.c b/plat/st/common/bl2_io_storage.c index 23794db963..2ea9f627ec 100644 --- a/plat/st/common/bl2_io_storage.c +++ b/plat/st/common/bl2_io_storage.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2020, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2015-2021, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ @@ -11,6 +11,7 @@ #include #include +#include #include #include #include @@ -48,7 +49,7 @@ static uint32_t nand_bkp_offset; #if STM32MP_SDMMC || STM32MP_EMMC static uint32_t block_buffer[MMC_BLOCK_SIZE] __aligned(MMC_BLOCK_SIZE); -static const io_block_dev_spec_t mmc_block_dev_spec = { +static io_block_dev_spec_t mmc_block_dev_spec = { /* It's used as temp buffer in block driver */ .buffer = { .offset = (size_t)&block_buffer, @@ -412,6 +413,11 @@ int bl2_plat_handle_pre_image_load(unsigned int image_id) image_block_spec.length = entry->length; gpt_init_done = true; + } else { + bl_mem_params_node_t *bl_mem_params = get_bl_mem_params_node(image_id); + + mmc_block_dev_spec.buffer.offset = bl_mem_params->image_info.image_base; + mmc_block_dev_spec.buffer.length = bl_mem_params->image_info.image_max_size; } break; diff --git a/plat/st/common/include/stm32cubeprogrammer.h b/plat/st/common/include/stm32cubeprogrammer.h index 947ad43aea..db5dfbf4f4 100644 --- a/plat/st/common/include/stm32cubeprogrammer.h +++ b/plat/st/common/include/stm32cubeprogrammer.h @@ -31,9 +31,6 @@ #define NACK_BYTE 0x1FU #define ABORT 0x5FU -#define DEVICE_ID_BYTE1 0x05U -#define DEVICE_ID_BYTE2 0x00U - /* Functions provided by plat */ uint8_t usb_dfu_get_phase(uint8_t alt); diff --git a/plat/st/common/include/stm32mp_common.h b/plat/st/common/include/stm32mp_common.h index 022e22742a..40291c43ed 100644 --- a/plat/st/common/include/stm32mp_common.h +++ b/plat/st/common/include/stm32mp_common.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018-2020, STMicroelectronics - All Rights Reserved + * Copyright (C) 2018-2021, STMicroelectronics - All Rights Reserved * * SPDX-License-Identifier: BSD-3-Clause */ @@ -7,12 +7,12 @@ #ifndef STM32MP_COMMON_H #define STM32MP_COMMON_H -#include #include #include -void __dead2 stm32mp_plat_reset(int cpu); +#define JEDEC_ST_BKID U(0x0) +#define JEDEC_ST_MFID U(0x20) /* Functions to save and get boot context address given by ROM code */ void stm32mp_save_boot_ctx_address(uintptr_t address); @@ -24,10 +24,6 @@ bool stm32mp_is_single_core(void); bool stm32mp_is_closed_device(void); bool stm32mp_is_auth_supported(void); -const char *stm32mp_get_cpu_supply_name(void); -const char *stm32mp_get_vdd_supply_name(void); -const char *stm32mp_get_usb_phy_supply_name(void); - /* Return the base address of the DDR controller */ uintptr_t stm32mp_ddrctrl_base(void); @@ -88,12 +84,15 @@ uintptr_t get_uart_address(uint32_t instance_nb); uintptr_t stm32_get_gpio_bank_base(unsigned int bank); unsigned long stm32_get_gpio_bank_clock(unsigned int bank); uint32_t stm32_get_gpio_bank_offset(unsigned int bank); +bool stm32_gpio_is_secure_at_reset(unsigned int bank); /* Return node offset for target GPIO bank ID @bank or a FDT error code */ int stm32_get_gpio_bank_pinctrl_node(void *fdt, unsigned int bank); /* Get the chip revision */ -int stm32mp_get_chip_version(uint32_t *chip_version); +uint32_t stm32mp_get_chip_version(void); +/* Get the chip device ID */ +uint32_t stm32mp_get_chip_dev_id(void); /* Get SOC name */ #define STM32_SOC_NAME_SIZE 20 diff --git a/plat/st/common/include/stm32mp_dt.h b/plat/st/common/include/stm32mp_dt.h index 0ff30a3827..0414014c2f 100644 --- a/plat/st/common/include/stm32mp_dt.h +++ b/plat/st/common/include/stm32mp_dt.h @@ -44,9 +44,9 @@ int dt_get_max_opp_freqvolt(uint32_t *freq_khz, uint32_t *voltage_mv); int dt_get_all_opp_freqvolt(uint32_t *count, uint32_t *freq_khz_array, uint32_t *voltage_mv_array); uint32_t dt_get_pwr_vdd_voltage(void); -const char *dt_get_vdd_regulator_name(void); -const char *dt_get_cpu_regulator_name(void); -const char *dt_get_usb_phy_regulator_name(void); +struct rdev *dt_get_vdd_regulator(void); +struct rdev *dt_get_cpu_regulator(void); +struct rdev *dt_get_usb_phy_regulator(void); const char *dt_get_board_model(void); int fdt_get_gpio_bank_pin_count(unsigned int bank); diff --git a/plat/st/common/stm32cubeprogrammer_uart.c b/plat/st/common/stm32cubeprogrammer_uart.c index 3fd16aa39c..7a6e02463f 100644 --- a/plat/st/common/stm32cubeprogrammer_uart.c +++ b/plat/st/common/stm32cubeprogrammer_uart.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, STMicroelectronics - All Rights Reserved + * Copyright (c) 2020-2021, STMicroelectronics - All Rights Reserved * * SPDX-License-Identifier: BSD-3-Clause */ @@ -203,13 +203,20 @@ static int get_version_command(void) static int get_id_command(void) { - const uint8_t msg[3] = { - sizeof(msg) - 1, - DEVICE_ID_BYTE1, - DEVICE_ID_BYTE2 - }; + uint32_t id = stm32mp_get_chip_dev_id(); + int ret; + + ret = uart_write_8(2U); /* Length of command */ + if (ret != 0) { + return ret; + } + + ret = uart_write_8((id & 0xFF00) >> 8); /* device ID byte 1 */ + if (ret != 0) { + return ret; + } - return uart_write(msg, sizeof(msg)); + return uart_write_8(id & 0xFF); /* device ID byte 2 */ } static int uart_send_phase(uint32_t address) diff --git a/plat/st/common/stm32mp_common.c b/plat/st/common/stm32mp_common.c index 3f385ca317..04219677cc 100644 --- a/plat/st/common/stm32mp_common.c +++ b/plat/st/common/stm32mp_common.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2020, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2015-2021, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ @@ -13,10 +13,12 @@ #include #include #include +#include #include #include #include #include +#include #define HEADER_VERSION_MAJOR_MASK GENMASK(23, 16) @@ -32,12 +34,6 @@ unsigned int plat_get_syscnt_freq2(void) return read_cntfrq_el0(); } -#pragma weak stm32mp_plat_reset -void __dead2 stm32mp_plat_reset(int cpu) -{ - panic(); -} - static uintptr_t boot_ctx_address; static uint16_t boot_itf_selected; static uint32_t boot_action_saved; @@ -147,58 +143,6 @@ int stm32mp_check_header(boot_api_image_header_t *header, uintptr_t buffer) } #endif -/* Return CPU supply name */ -const char *stm32mp_get_cpu_supply_name(void) -{ - const char *regulator; - const char *supply = NULL; - - regulator = dt_get_cpu_regulator_name(); - if (regulator == NULL) { - return NULL; - } - - if (dt_pmic_status() > 0) { - if (dt_pmic_find_supply(&supply, regulator) != 0) { - return NULL; - } - } - - return supply; -} - -/* Return VDD supply name */ -const char *stm32mp_get_vdd_supply_name(void) -{ - const char *supply = NULL; - - if (dt_pmic_status() > 0) { - const char *regulator = dt_get_vdd_regulator_name(); - - if (regulator != NULL) { - dt_pmic_find_supply(&supply, regulator); - } - } - - return supply; -} - -/* Return USB phy supply name */ -const char *stm32mp_get_usb_phy_supply_name(void) -{ - const char *supply = NULL; - - if (dt_pmic_status() > 0) { - const char *regulator = dt_get_usb_phy_regulator_name(); - - if (regulator != NULL) { - dt_pmic_find_supply(&supply, regulator); - } - } - - return supply; -} - #if TRUSTED_BOARD_BOOT && STM32MP_USE_STM32IMAGE /* Save pointer to last loaded header */ static boot_api_image_header_t *latest_stm32_header; @@ -243,3 +187,35 @@ int stm32mp_unmap_ddr(void) return mmap_remove_dynamic_region(STM32MP_DDR_BASE, STM32MP_DDR_MAX_SIZE); } + +/***************************************************************************** + * plat_is_smccc_feature_available() - This function checks whether SMCCC + * feature is availabile for platform. + * @fid: SMCCC function id + * + * Return SMC_ARCH_CALL_SUCCESS if SMCCC feature is available and + * SMC_ARCH_CALL_NOT_SUPPORTED otherwise. + *****************************************************************************/ +int32_t plat_is_smccc_feature_available(u_register_t fid) +{ + switch (fid) { + case SMCCC_ARCH_SOC_ID: + return SMC_ARCH_CALL_SUCCESS; + default: + return SMC_ARCH_CALL_NOT_SUPPORTED; + } +} + +/* Get SOC version */ +int32_t plat_get_soc_version(void) +{ + uint32_t manfid = (JEDEC_ST_BKID << 24U) | (JEDEC_ST_MFID << 16U); + + return (int32_t)(manfid | (stm32mp_get_chip_dev_id() & 0xFFFFU)); +} + +/* Get SOC revision */ +int32_t plat_get_soc_revision(void) +{ + return (int32_t)stm32mp_get_chip_version(); +} diff --git a/plat/st/common/stm32mp_dt.c b/plat/st/common/stm32mp_dt.c index a3584cbc12..fd25c93fca 100644 --- a/plat/st/common/stm32mp_dt.c +++ b/plat/st/common/stm32mp_dt.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2020, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2017-2021, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ @@ -13,6 +13,7 @@ #include #include +#include #include #include @@ -71,21 +72,20 @@ bool fdt_check_node(int node) uint8_t fdt_get_status(int node) { uint8_t status = DT_DISABLED; - int len; const char *cchar; - cchar = fdt_getprop(fdt, node, "status", &len); + cchar = fdt_getprop(fdt, node, "status", NULL); if ((cchar == NULL) || - (strncmp(cchar, "okay", (size_t)len) == 0)) { + (strncmp(cchar, "okay", strlen("okay")) == 0)) { status |= DT_NON_SECURE; } - cchar = fdt_getprop(fdt, node, "secure-status", &len); + cchar = fdt_getprop(fdt, node, "secure-status", NULL); if (cchar == NULL) { if (status == DT_NON_SECURE) { status |= DT_SECURE; } - } else if (strncmp(cchar, "okay", (size_t)len) == 0) { + } else if (strncmp(cchar, "okay", strlen("okay")) == 0) { status |= DT_SECURE; } @@ -458,61 +458,23 @@ int dt_get_all_opp_freqvolt(uint32_t *count, uint32_t *freq_khz_array, ******************************************************************************/ uint32_t dt_get_pwr_vdd_voltage(void) { - int node; - const fdt32_t *cuint; + struct rdev *regul = dt_get_vdd_regulator(); + uint16_t min; - node = fdt_node_offset_by_compatible(fdt, -1, DT_PWR_COMPAT); - if (node < 0) { + if (regul == NULL) { return 0; } - cuint = fdt_getprop(fdt, node, "vdd-supply", NULL); - if (cuint == NULL) { - return 0; - } + regulator_get_range(regul, &min, NULL); - node = fdt_node_offset_by_phandle(fdt, fdt32_to_cpu(*cuint)); - if (node < 0) { - return 0; - } - - cuint = fdt_getprop(fdt, node, "regulator-min-microvolt", NULL); - if (cuint == NULL) { - return 0; - } - - return fdt32_to_cpu(*cuint); + return (uint32_t)min * 1000U; } /******************************************************************************* - * This function return the real regulator name from DT. + * This function retrieves VDD supply regulator from DT. + * Returns an rdev taken from supply node, NULL otherwise. ******************************************************************************/ -static const char *dt_get_regulator_name(int node, const char *regu_name) -{ - const fdt32_t *cuint; - - if ((node < 0) || (regu_name == NULL)) { - return NULL; - } - - cuint = fdt_getprop(fdt, node, regu_name, NULL); - if (cuint == NULL) { - return NULL; - } - - node = fdt_node_offset_by_phandle(fdt, fdt32_to_cpu(*cuint)); - if (node < 0) { - return NULL; - } - - return (const char *)fdt_getprop(fdt, node, "regulator-name", NULL); -} - -/******************************************************************************* - * This function retrieves VDD regulator name from DT. - * Returns string taken from supply node, NULL otherwise. - ******************************************************************************/ -const char *dt_get_vdd_regulator_name(void) +struct rdev *dt_get_vdd_regulator(void) { int node = fdt_node_offset_by_compatible(fdt, -1, DT_PWR_COMPAT); @@ -520,14 +482,14 @@ const char *dt_get_vdd_regulator_name(void) return NULL; } - return dt_get_regulator_name(node, "vdd-supply"); + return regulator_get_by_supply_name(fdt, node, "vdd"); } /******************************************************************************* - * This function retrieves CPU regulator name from DT. - * Returns string taken from supply node, NULL otherwise. + * This function retrieves CPU supply regulator from DT. + * Returns an rdev taken from supply node, NULL otherwise. ******************************************************************************/ -const char *dt_get_cpu_regulator_name(void) +struct rdev *dt_get_cpu_regulator(void) { int node = fdt_path_offset(fdt, "/cpus/cpu@0"); @@ -535,27 +497,27 @@ const char *dt_get_cpu_regulator_name(void) return NULL; } - return dt_get_regulator_name(node, "cpu-supply"); + return regulator_get_by_supply_name(fdt, node, "cpu"); } /******************************************************************************* * This function retrieves USB phy regulator name from DT. * Returns string taken from supply node, NULL otherwise. ******************************************************************************/ -const char *dt_get_usb_phy_regulator_name(void) +struct rdev *dt_get_usb_phy_regulator(void) { int node = fdt_node_offset_by_compatible(fdt, -1, DT_USBPHYC_COMPAT); int subnode; - const char *reg_name = NULL; if (node < 0) { return NULL; } fdt_for_each_subnode(subnode, fdt, node) { - reg_name = dt_get_regulator_name(subnode, "phy-supply"); - if (reg_name != NULL) { - return reg_name; + struct rdev *supply = regulator_get_by_supply_name(fdt, node, "phy"); + + if (supply != NULL) { + return supply; } } diff --git a/plat/st/common/stm32mp_trusted_boot.c b/plat/st/common/stm32mp_trusted_boot.c index 1ea30abf9b..6bc77e2440 100644 --- a/plat/st/common/stm32mp_trusted_boot.c +++ b/plat/st/common/stm32mp_trusted_boot.c @@ -85,7 +85,7 @@ int plat_get_rotpk_info(void *cookie, void **key_ptr, unsigned int *key_len, memcpy(&res, proot_pk, sizeof(uint32_t)); if ((res == 0U) || (res == 0xFFFFFFFFU)) { while (idx < ARRAY_SIZE(root_pk_hash)) { - memcpy(&rootpk, (proot_pk + idx), sizeof(uint32_t)); + memcpy(&rootpk, root_pk_hash + idx, sizeof(uint32_t)); if (res != rootpk) { return 0; } diff --git a/plat/st/stm32mp1/bl2_plat_setup.c b/plat/st/stm32mp1/bl2_plat_setup.c index 13ce3042a5..642138a1dd 100644 --- a/plat/st/stm32mp1/bl2_plat_setup.c +++ b/plat/st/stm32mp1/bl2_plat_setup.c @@ -17,6 +17,8 @@ #include #include #include +#include +#include #include #include #include @@ -189,10 +191,6 @@ void bl2_platform_setup(void) /* Clear the context in BKPSRAM */ stm32_clean_context(); - - if (dt_pmic_status() > 0) { - configure_pmic(); - } } /* Map DDR for binary load, now with cacheable attribute */ @@ -269,21 +267,21 @@ static void initialize_clock(void) if (dt_pmic_status() > 0) { int read_voltage; - const char *name; + struct rdev *regul; - name = stm32mp_get_cpu_supply_name(); - if (name == NULL) { + regul = dt_get_cpu_regulator(); + if (regul == NULL) { panic(); } - read_voltage = stpmic1_regulator_voltage_get(name); + read_voltage = regulator_get_voltage(regul); if (read_voltage < 0) { panic(); } if (voltage_mv != (uint32_t)read_voltage) { - if (stpmic1_regulator_voltage_set(name, - (uint16_t)voltage_mv) != 0) { + if (regulator_set_voltage(regul, + (uint16_t)voltage_mv) != 0) { panic(); } } @@ -380,10 +378,11 @@ void bl2_el3_plat_arch_setup(void) mmio_clrbits_32(rcc_base + RCC_BDCR, RCC_BDCR_VSWRST); } - /* Enable BKP Register protection */ - mmio_write_32(TAMP_SMCR, - TAMP_BKP_SEC_NUMBER << TAMP_BKP_SEC_WDPROT_SHIFT | - TAMP_BKP_SEC_NUMBER << TAMP_BKP_SEC_RWDPROT_SHIFT); + /* Set minimum reset pulse duration to 31ms for discrete power supplied boards */ + if (dt_pmic_status() <= 0) { + mmio_clrsetbits_32(rcc_base + RCC_RDLSICR, RCC_RDLSICR_MRD_MASK, + 31U << RCC_RDLSICR_MRD_SHIFT); + } generic_delay_timer_init(); @@ -411,6 +410,11 @@ void bl2_el3_plat_arch_setup(void) initialize_clock(); +#if STM32MP_USB_PROGRAMMER + /* Deconfigure all UART RX pins configured by ROM code */ + stm32mp1_deconfigure_uart_pins(); +#endif + result = dt_get_stdout_uart_info(&dt_uart_info); if ((result <= 0) || @@ -455,13 +459,11 @@ void bl2_el3_plat_arch_setup(void) stm32mp_print_boardinfo(); -#if TRUSTED_BOARD_BOOT if (boot_context->auth_status != BOOT_API_CTX_AUTH_NO) { NOTICE("Bootrom authentication %s\n", (boot_context->auth_status == BOOT_API_CTX_AUTH_FAILED) ? "failed" : "succeeded"); } -#endif skip_console_init: #if !TRUSTED_BOARD_BOOT @@ -506,7 +508,7 @@ skip_console_init: stm32mp1_syscfg_enable_io_compensation_finish(); if (dt_pmic_status() > 0) { - initialize_pmic(); + initialize_pmic_i2c(); print_pmic_info_and_debug(); } @@ -718,6 +720,19 @@ int bl2_plat_handle_post_image_load(unsigned int image_id) break; } +#if STM32MP_SDMMC || STM32MP_EMMC + /* + * Invalidate remaining data read from MMC but not flushed by load_image_flush(). + * We take the worst case which is 2 MMC blocks. + */ + if ((image_id != FW_CONFIG_ID) && + ((bl_mem_params->image_info.h.attr & IMAGE_ATTRIB_SKIP_LOADING) == 0U)) { + inv_dcache_range(bl_mem_params->image_info.image_base + + bl_mem_params->image_info.image_size, + 2U * MMC_BLOCK_SIZE); + } +#endif + return err; } diff --git a/plat/st/stm32mp1/include/stm32mp1_critic_power.h b/plat/st/stm32mp1/include/stm32mp1_critic_power.h index cd7099c444..7563406b4e 100644 --- a/plat/st/stm32mp1/include/stm32mp1_critic_power.h +++ b/plat/st/stm32mp1/include/stm32mp1_critic_power.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019-2020, STMicroelectronics - All Rights Reserved + * Copyright (C) 2019-2021, STMicroelectronics - All Rights Reserved * * SPDX-License-Identifier: BSD-3-Clause */ @@ -12,11 +12,11 @@ */ #if defined(IMAGE_BL32) #if STM32MP_SP_MIN_IN_DDR -extern void (*stm32_pwr_down_wfi)(bool is_cstop); +extern void (*stm32_pwr_down_wfi)(bool is_cstop, uint32_t mode); #else -extern void stm32_pwr_down_wfi(bool is_cstop); +extern void stm32_pwr_down_wfi(bool is_cstop, uint32_t mode); #endif #endif -extern void stm32_pwr_down_wfi_wrapper(bool is_cstop); +extern void stm32_pwr_down_wfi_wrapper(bool is_cstop, uint32_t mode); #endif /* STM32MP1_CRITIC_POWER_H */ diff --git a/plat/st/stm32mp1/include/stm32mp1_private.h b/plat/st/stm32mp1/include/stm32mp1_private.h index ebf9e52bc9..cbcd2c8bd5 100644 --- a/plat/st/stm32mp1/include/stm32mp1_private.h +++ b/plat/st/stm32mp1/include/stm32mp1_private.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2020, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2015-2021, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ @@ -40,6 +40,8 @@ void stm32mp1_syscfg_enable_io_compensation_start(void); void stm32mp1_syscfg_enable_io_compensation_finish(void); void stm32mp1_syscfg_disable_io_compensation(void); +void stm32mp1_deconfigure_uart_pins(void); + #if STM32MP_USE_STM32IMAGE uint32_t stm32mp_get_ddr_ns_size(void); #endif diff --git a/plat/st/stm32mp1/plat_bl2_mem_params_desc.c b/plat/st/stm32mp1/plat_bl2_mem_params_desc.c index d322da0090..6092db2b95 100644 --- a/plat/st/stm32mp1/plat_bl2_mem_params_desc.c +++ b/plat/st/stm32mp1/plat_bl2_mem_params_desc.c @@ -21,18 +21,18 @@ static bl_mem_params_node_t bl2_mem_params_descs[] = { /* Fill FW_CONFIG related information if it exists */ { - .image_id = FW_CONFIG_ID, - SET_STATIC_PARAM_HEAD(ep_info, PARAM_IMAGE_BINARY, - VERSION_2, entry_point_info_t, - SECURE | NON_EXECUTABLE), - SET_STATIC_PARAM_HEAD(image_info, PARAM_IMAGE_BINARY, - VERSION_2, image_info_t, - IMAGE_ATTRIB_PLAT_SETUP), - - .image_info.image_base = STM32MP_FW_CONFIG_BASE, - .image_info.image_max_size = STM32MP_FW_CONFIG_MAX_SIZE, - - .next_handoff_image_id = INVALID_IMAGE_ID, + .image_id = FW_CONFIG_ID, + SET_STATIC_PARAM_HEAD(ep_info, PARAM_IMAGE_BINARY, + VERSION_2, entry_point_info_t, + SECURE | NON_EXECUTABLE), + SET_STATIC_PARAM_HEAD(image_info, PARAM_IMAGE_BINARY, + VERSION_2, image_info_t, + IMAGE_ATTRIB_PLAT_SETUP), + + .image_info.image_base = STM32MP_FW_CONFIG_BASE, + .image_info.image_max_size = STM32MP_FW_CONFIG_MAX_SIZE, + + .next_handoff_image_id = INVALID_IMAGE_ID, }, /* Fill BL32 related information */ @@ -85,27 +85,28 @@ static bl_mem_params_node_t bl2_mem_params_descs[] = { /* Fill HW_CONFIG related information if it exists */ { - .image_id = HW_CONFIG_ID, - SET_STATIC_PARAM_HEAD(ep_info, PARAM_IMAGE_BINARY, - VERSION_2, entry_point_info_t, - NON_SECURE | NON_EXECUTABLE), - SET_STATIC_PARAM_HEAD(image_info, PARAM_IMAGE_BINARY, - VERSION_2, image_info_t, - IMAGE_ATTRIB_SKIP_LOADING), - - .next_handoff_image_id = INVALID_IMAGE_ID, + .image_id = HW_CONFIG_ID, + SET_STATIC_PARAM_HEAD(ep_info, PARAM_IMAGE_BINARY, + VERSION_2, entry_point_info_t, + NON_SECURE | NON_EXECUTABLE), + SET_STATIC_PARAM_HEAD(image_info, PARAM_IMAGE_BINARY, + VERSION_2, image_info_t, + IMAGE_ATTRIB_SKIP_LOADING), + + .next_handoff_image_id = INVALID_IMAGE_ID, }, + /* Fill TOS_FW_CONFIG related information if it exists */ { - .image_id = TOS_FW_CONFIG_ID, - SET_STATIC_PARAM_HEAD(ep_info, PARAM_IMAGE_BINARY, - VERSION_2, entry_point_info_t, - SECURE | NON_EXECUTABLE), - SET_STATIC_PARAM_HEAD(image_info, PARAM_IMAGE_BINARY, - VERSION_2, image_info_t, - IMAGE_ATTRIB_SKIP_LOADING), - - .next_handoff_image_id = INVALID_IMAGE_ID, + .image_id = TOS_FW_CONFIG_ID, + SET_STATIC_PARAM_HEAD(ep_info, PARAM_IMAGE_BINARY, + VERSION_2, entry_point_info_t, + SECURE | NON_EXECUTABLE), + SET_STATIC_PARAM_HEAD(image_info, PARAM_IMAGE_BINARY, + VERSION_2, image_info_t, + IMAGE_ATTRIB_SKIP_LOADING), + + .next_handoff_image_id = INVALID_IMAGE_ID, }, /* Fill BL33 related information */ diff --git a/plat/st/stm32mp1/platform.mk b/plat/st/stm32mp1/platform.mk index 067e1fff9f..55acd67422 100644 --- a/plat/st/stm32mp1/platform.mk +++ b/plat/st/stm32mp1/platform.mk @@ -15,7 +15,7 @@ USE_COHERENT_MEM := 0 STM32MP_USE_STM32IMAGE ?= 0 # Add specific ST version -ST_VERSION := r1.0 +ST_VERSION := r2.0 ifeq ($(STM32MP_USE_STM32IMAGE),1) ST_VERSION := ${ST_VERSION}-nofip endif @@ -107,8 +107,14 @@ BL32_DTSI := stm32mp15-bl32.dtsi FDT_SOURCES += $(addprefix ${BUILD_PLAT}/fdts/, $(patsubst %.dtb,%-bl32.dts,$(DTB_FILE_NAME))) endif endif + +$(eval DTC_V = $(shell $(DTC) -v | awk '{print $$NF}')) +$(eval DTC_VERSION = $(shell printf "%d" $(shell echo ${DTC_V} | cut -d- -f1 | sed "s/\./0/g"))) DTC_CPPFLAGS += ${INCLUDES} DTC_FLAGS += -Wno-unit_address_vs_reg +ifeq ($(shell test $(DTC_VERSION) -ge 10601; echo $$?),0) +DTC_FLAGS += -Wno-interrupt_provider +endif # Macros and rules to build TF binary STM32_TF_ELF_LDFLAGS := --hash-style=gnu --as-needed @@ -129,7 +135,7 @@ STM32IMAGE_SRC := ${STM32IMAGEPATH}/stm32image.c ifneq (${STM32MP_USE_STM32IMAGE},1) FIP_DEPS += dtbs -STM32MP_NT_FW_CONFIG := ${BL33_CFG} +STM32MP_HW_CONFIG := ${BL33_CFG} STM32MP_FW_CONFIG_NAME := $(patsubst %.dtb,%-fw-config.dtb,$(DTB_FILE_NAME)) STM32MP_FW_CONFIG := ${BUILD_PLAT}/fdts/$(STM32MP_FW_CONFIG_NAME) ifneq (${AARCH32_SP},none) @@ -137,8 +143,8 @@ FDT_SOURCES += $(addprefix fdts/, $(patsubst %.dtb,%.dts,$(STM32MP_FW_CONFIG_NA endif # Add the FW_CONFIG to FIP and specify the same to certtool $(eval $(call TOOL_ADD_PAYLOAD,${STM32MP_FW_CONFIG},--fw-config)) -# Add the NT_FW_CONFIG to FIP and specify the same to certtool -$(eval $(call TOOL_ADD_PAYLOAD,${STM32MP_NT_FW_CONFIG},--hw-config)) +# Add the HW_CONFIG to FIP and specify the same to certtool +$(eval $(call TOOL_ADD_PAYLOAD,${STM32MP_HW_CONFIG},--hw-config)) ifeq (${GENERATE_COT},1) $(eval $(call TOOL_ADD_PAYLOAD,${BUILD_PLAT}/tb_fw.crt,--tb-fw-cert)) endif @@ -212,6 +218,8 @@ PLAT_BL_COMMON_SOURCES := common/fdt_wrappers.c \ plat/st/common/stm32mp_common.c \ plat/st/stm32mp1/stm32mp1_private.c +PLAT_BL_COMMON_SOURCES += drivers/regulator/regulator_core.c + PLAT_BL_COMMON_SOURCES += drivers/st/uart/aarch32/stm32_console.S ifneq (${ENABLE_STACK_PROTECTOR},0) @@ -236,8 +244,6 @@ PLAT_BL_COMMON_SOURCES += drivers/arm/tzc/tzc400.c \ drivers/st/iwdg/stm32_iwdg.c \ drivers/st/pmic/stm32mp_pmic.c \ drivers/st/pmic/stpmic1.c \ - drivers/st/regulator/stm32mp_dummy_regulator.c \ - drivers/st/regulator/stm32mp_regulator.c \ drivers/st/reset/stm32mp1_reset.c \ plat/st/common/stm32mp_dt.c \ plat/st/common/stm32mp_shres_helpers.c \ @@ -363,7 +369,8 @@ BL2_SOURCES += drivers/st/usb_dwc2/usb_dwc2.c \ plat/st/stm32mp1/stm32mp1_usb.c endif -BL2_SOURCES += drivers/st/ddr/stm32mp1_ddr.c \ +BL2_SOURCES += drivers/st/ddr/stm32mp_ddr_test.c \ + drivers/st/ddr/stm32mp1_ddr.c \ drivers/st/ddr/stm32mp1_ram.c BL2_SOURCES += common/desc_image_load.c \ @@ -409,8 +416,6 @@ clean_stm32image: ${Q}${MAKE} --no-print-directory -C ${STM32IMAGEPATH} clean check_dtc_version: - $(eval DTC_V = $(shell $(DTC) -v | awk '{print $$NF}')) - $(eval DTC_VERSION = $(shell printf "%d" $(shell echo ${DTC_V} | cut -d- -f1 | sed "s/\./0/g"))) @if [ ${DTC_VERSION} -lt 10404 ]; then \ echo "dtc version too old (${DTC_V}), you need at least version 1.4.4"; \ false; \ diff --git a/plat/st/stm32mp1/services/bsec_svc.c b/plat/st/stm32mp1/services/bsec_svc.c index e3d845d2ec..633e63eb31 100644 --- a/plat/st/stm32mp1/services/bsec_svc.c +++ b/plat/st/stm32mp1/services/bsec_svc.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -87,16 +88,18 @@ static enum bsec_ssp_status bsec_check_ssp(uint32_t otp, uint32_t update) sizeof(boot_api_ssp_config_t)); #endif if (dt_pmic_status() > 0) { - const char *name; + struct rdev *regul; initialize_pmic(); - name = stm32mp_get_cpu_supply_name(); - if (name == NULL) { + regul = dt_get_cpu_regulator(); + if (regul == NULL) { return BSEC_SSP_ERROR; } - stpmic1_regulator_mask_reset_set(name); + if (regulator_set_flag(regul, REGUL_MASK_RESET) < 0) { + return BSEC_SSP_ERROR; + } } return BSEC_SSP_SET; diff --git a/plat/st/stm32mp1/sp_min/sp_min-stm32mp1.mk b/plat/st/stm32mp1/sp_min/sp_min-stm32mp1.mk index dd81d13a08..99575f5666 100644 --- a/plat/st/stm32mp1/sp_min/sp_min-stm32mp1.mk +++ b/plat/st/stm32mp1/sp_min/sp_min-stm32mp1.mk @@ -17,6 +17,7 @@ BL32_CFLAGS += -DSTM32MP_SHARED_RESOURCES BL32_SOURCES += drivers/st/clk/stm32mp1_calib.c \ drivers/st/etzpc/etzpc.c \ + drivers/st/regulator/regulator_fixed.c \ drivers/st/rng/stm32_rng.c \ drivers/st/rtc/stm32_rtc.c \ drivers/st/tamper/stm32_tamp.c \ diff --git a/plat/st/stm32mp1/sp_min/sp_min_setup.c b/plat/st/stm32mp1/sp_min/sp_min_setup.c index 0065be44fd..d408b76523 100644 --- a/plat/st/stm32mp1/sp_min/sp_min_setup.c +++ b/plat/st/stm32mp1/sp_min/sp_min_setup.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2020, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2015-2021, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ @@ -18,8 +18,10 @@ #include #include #include +#include #include #include +#include #include #include #include @@ -51,43 +53,26 @@ static entry_point_info_t bl33_image_ep_info; static console_t console; -static void stm32mp1_tamper_action(int id); - -static const char *tamper_name[PLAT_MAX_TAMP_INT] = { - "RTC power domain", - "Temperature monitoring", - "LSE monitoring", - "HSE monitoring", - "RTC calendar overflow", - "Monotonic counter" -}; +static struct dt_node_info dt_uart_info; -static struct stm32_tamp_int int_tamp[PLAT_MAX_TAMP_INT] = { - { - .id = ITAMP1, - .func = stm32mp1_tamper_action, - }, - { - .id = ITAMP2, - .func = stm32mp1_tamper_action, - }, - { - .id = ITAMP3, - .func = stm32mp1_tamper_action, - }, - { - .id = ITAMP4, - .func = stm32mp1_tamper_action, - }, - TAMP_UNUSED, - TAMP_UNUSED, +static const char * const tamper_name[] = { + [INT_TAMP1] = "RTC power domain", + [INT_TAMP2] = "Temperature monitoring", + [INT_TAMP3] = "LSE monitoring", + [INT_TAMP4] = "HSE monitoring", }; -static struct stm32_tamp_ext ext_tamp[PLAT_MAX_TAMP_EXT] = { - TAMP_UNUSED, - TAMP_UNUSED, - TAMP_UNUSED, -}; +static int stm32mp1_tamper_action(int id) +{ + const char *tamp_name = NULL; + + if ((id >= 0) && ((size_t)id < ARRAY_SIZE(tamper_name))) { + tamp_name = tamper_name[id]; + } + ERROR("Tamper %u (%s) occurs\n", id, tamp_name); + + return 1; /* ack TAMPER and reset system */ +} static void stm32_sgi1_it_handler(void) { @@ -114,12 +99,6 @@ static void stm32_sgi1_it_handler(void) stm32mp_wait_cpu_reset(); } -static void stm32mp1_tamper_action(int id) -{ - ERROR("Tamper %s occurs\n", tamper_name[id]); - stm32mp_system_reset(); -} - static void configure_wakeup_interrupt(void) { int irq_num = fdt_rcc_enable_it("wakeup"); @@ -141,14 +120,15 @@ static void initialize_pll1_settings(void) } if (dt_pmic_status() > 0) { - const char *name = stm32mp_get_cpu_supply_name(); + struct rdev *regul; int ret; - if (name == NULL) { + regul = dt_get_cpu_regulator(); + if (regul == NULL) { panic(); } - ret = stpmic1_regulator_voltage_get(name); + ret = regulator_get_voltage(regul); if (ret < 0) { panic(); } @@ -164,16 +144,18 @@ static void initialize_pll1_settings(void) static void disable_usb_phy_regulator(void) { if (dt_pmic_status() > 0) { - const char *name = stm32mp_get_usb_phy_supply_name(); + struct rdev *regul = dt_get_usb_phy_regulator(); int ret; - if (name == NULL) { + if (regul == NULL) { return; } - ret = stpmic1_regulator_disable(name); - if (ret < 0) { - WARN("USBPHYC phy-supply (%s) disable failed\n", name); + if (regulator_is_enabled(regul) == 1) { + ret = regulator_disable(regul); + if (ret < 0) { + WARN("USBPHYC phy-supply (%s) disable failed\n", regul->reg_name); + } } } } @@ -262,6 +244,7 @@ static uintptr_t get_saved_pc(void) entry_point_info_t *sp_min_plat_get_bl33_ep_info(void) { entry_point_info_t *next_image_info = &bl33_image_ep_info; + unsigned int console_flags; /* * PC is set to 0 when resetting after STANDBY @@ -276,6 +259,16 @@ entry_point_info_t *sp_min_plat_get_bl33_ep_info(void) panic(); } + console_flags = CONSOLE_FLAG_CRASH | CONSOLE_FLAG_TRANSLATE_CRLF; + if ((clk_is_enabled(dt_uart_info.clock)) && + (clk_get_rate(dt_uart_info.clock) != 0U)) { + console_flags |= CONSOLE_FLAG_BOOT; +#ifdef DEBUG + console_flags |= CONSOLE_FLAG_RUNTIME; +#endif + } + console_set_scope(&console, console_flags); + cpu_context = cm_get_context(NON_SECURE); next_image_info->spsr = read_ctx_reg(get_regs_ctx(cpu_context), @@ -291,6 +284,8 @@ entry_point_info_t *sp_min_plat_get_bl33_ep_info(void) next_image_info->pc = read_ctx_reg(get_regs_ctx(cpu_context), CTX_LR); } + + regulator_core_resume(); } return next_image_info; @@ -327,17 +322,12 @@ static void stm32mp1_etzpc_early_setup(void) etzpc_configure_tzma(STM32MP1_ETZPC_TZMA_SYSRAM, TZMA1_SECURE_RANGE); } -#if !STM32MP_USE_STM32IMAGE +#if STM32MP_SP_MIN_IN_DDR static void populate_ns_dt(u_register_t ns_dt_addr, uintptr_t sec_base, size_t sec_size) { void *external_fdt = (void *)ns_dt_addr; int ret; - if (sec_base < STM32MP_DDR_BASE) { - /* No need to reserve memory if secure monitor is not in DDR */ - return; - } - /* Map Base Non Secure DDR for Non secure DT update */ ret = mmap_add_dynamic_region(ns_dt_addr, ns_dt_addr, STM32MP_HW_CONFIG_MAX_SIZE, MT_NON_CACHEABLE | MT_EXECUTE_NEVER | MT_RW | MT_NS); @@ -377,7 +367,6 @@ out: ******************************************************************************/ static void setup_uart_console(void) { - struct dt_node_info dt_uart_info; unsigned int console_flags; int result; uint32_t boot_itf; @@ -419,10 +408,9 @@ void sp_min_early_platform_setup2(u_register_t arg0, u_register_t arg1, uintptr_t dt_addr = STM32MP_DTB_BASE; #else uintptr_t dt_addr = arg1; - uintptr_t sec_base = 0U; - size_t sec_size = 0U; #endif #if STM32MP_SP_MIN_IN_DDR + uintptr_t sec_base = 0U; uintptr_t bl2_code_base = 0U; uintptr_t bl2_code_end = 0U; uintptr_t bl2_end = 0U; @@ -511,36 +499,41 @@ void sp_min_early_platform_setup2(u_register_t arg0, u_register_t arg1, } } -#if !STM32MP_USE_STM32IMAGE +#if STM32MP_SP_MIN_IN_DDR if (bl_params->image_id == BL32_IMAGE_ID) { sec_base = bl_params->image_info->image_base; - sec_size = bl_params->image_info->image_max_size; } #endif bl_params = bl_params->next_params_info; } -#if !STM32MP_USE_STM32IMAGE +#if STM32MP_SP_MIN_IN_DDR if (arg2 != 0U) { /* This will expect the BL32 DT and BL32 are grouped */ if (dt_addr < sec_base) { - sec_size = sec_size + sec_base - dt_addr; sec_base = dt_addr; - } else { - sec_size = dt_addr - sec_base + STM32MP_BL32_DTB_SIZE; } - populate_ns_dt(arg2, sec_base, sec_size); + populate_ns_dt(arg2, sec_base, DDR_SEC_SIZE); } else { INFO("Non-secure device tree not found\n"); } #endif + generic_delay_timer_init(); + if (dt_pmic_status() > 0) { initialize_pmic(); } + fixed_regulator_register(); + + if (regulator_core_config() != 0) { + ERROR("Regulator core config error\n"); + panic(); + } + disable_usb_phy_regulator(); initialize_pll1_settings(); @@ -550,8 +543,6 @@ void sp_min_early_platform_setup2(u_register_t arg0, u_register_t arg1, static void init_sec_peripherals(void) { - uint32_t filter_conf = 0; - uint32_t active_conf = 0; int ret; /* Disable MCU subsystem protection */ @@ -571,9 +562,28 @@ static void init_sec_peripherals(void) /* Init tamper */ if (stm32_tamp_init() > 0) { - stm32_tamp_configure_internal(int_tamp, PLAT_MAX_TAMP_INT); - stm32_tamp_configure_external(ext_tamp, PLAT_MAX_TAMP_EXT, - filter_conf, active_conf); + struct bkpregs_conf bkpregs_conf = { + .nb_zone1_regs = TAMP_BKP_SEC_NUMBER, + .nb_zone2_regs = 0 /* no register in zone 2 */ + /* zone3 all remaining */ + }; + + /* Enable BKP Register protection */ + if (stm32_tamp_set_secure_bkpregs(&bkpregs_conf) < 0) { + panic(); + } + + stm32_tamp_configure_secure_access(TAMP_REGS_IT_SECURE); + + stm32_tamp_configure_internal(INT_TAMP1, TAMP_ENABLE, stm32mp1_tamper_action); + stm32_tamp_configure_internal(INT_TAMP2, TAMP_ENABLE, stm32mp1_tamper_action); + stm32_tamp_configure_internal(INT_TAMP3, TAMP_ENABLE, stm32mp1_tamper_action); + stm32_tamp_configure_internal(INT_TAMP4, TAMP_ENABLE, stm32mp1_tamper_action); + + ret = stm32_tamp_set_config(); + if (ret < 0) { + panic(); + } /* Enable timestamp for tamper */ stm32_rtc_set_tamper_timestamp(); @@ -593,8 +603,6 @@ void sp_min_platform_setup(void) ddr_save_sr_mode(); - generic_delay_timer_init(); - stm32_gic_init(); init_sec_peripherals(); @@ -608,6 +616,11 @@ void sp_min_platform_setup(void) stm32mp_lock_periph_registering(); stm32mp1_init_scmi_server(); + + /* Cold boot: clean-up regulators state */ + if (get_saved_pc() == 0U) { + regulator_core_cleanup(); + } } void sp_min_plat_arch_setup(void) diff --git a/plat/st/stm32mp1/stm32mp1_context.c b/plat/st/stm32mp1/stm32mp1_context.c index 027475ed40..1705c15258 100644 --- a/plat/st/stm32mp1/stm32mp1_context.c +++ b/plat/st/stm32mp1/stm32mp1_context.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2020, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2017-2021, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -92,6 +93,7 @@ struct backup_bl32_data_s { unsigned long long stgen; uint8_t clock_cfg[CLOCK_CONTEXT_SIZE]; uint8_t scmi_context[SCMI_CONTEXT_SIZE]; + uint8_t regul_context[PLAT_BACKUP_REGULATOR_SIZE]; }; static struct backup_bl32_data_s *get_bl32_backup_data(void) @@ -101,7 +103,7 @@ static struct backup_bl32_data_s *get_bl32_backup_data(void) } #if STM32MP_SP_MIN_IN_DDR -void (*stm32_pwr_down_wfi)(bool is_cstop); +void (*stm32_pwr_down_wfi)(bool is_cstop, uint32_t mode); #endif #endif @@ -227,6 +229,9 @@ int stm32_save_context(uint32_t zq0cr0_zdata, save_clock_pm_context(); + regulator_core_backup_context(backup_bl32_data->regul_context, + sizeof(backup_bl32_data->regul_context)); + clk_disable(BKPSRAM); return 0; @@ -279,6 +284,9 @@ int stm32_restore_context(void) &backup_bl32_data->rtc); stm32mp_stgen_restore_counter(backup_bl32_data->stgen, stdby_time_in_ms); + regulator_core_restore_context(backup_bl32_data->regul_context, + sizeof(backup_bl32_data->regul_context)); + clk_disable(BKPSRAM); stm32mp1_clock_resume(); @@ -317,7 +325,7 @@ void stm32_context_get_bl2_low_power_params(uintptr_t *bl2_code_base, } #if STM32MP_SP_MIN_IN_DDR - stm32_pwr_down_wfi = (void (*)(bool))backup_data->low_power_ep; + stm32_pwr_down_wfi = (void (*)(bool, uint32_t))backup_data->low_power_ep; #endif *bl2_code_base = (uintptr_t)backup_data->bl2_code_base; *bl2_code_end = (uintptr_t)backup_data->bl2_code_end; @@ -463,6 +471,8 @@ void stm32_save_ddr_training_area(void) PAGE_SIZE, MT_MEMORY | MT_RW | MT_NS); assert(ret == 0); + flush_dcache_range(STM32MP_DDR_BASE, TRAINING_AREA_SIZE); + memcpy(&backup_data->ddr_training_backup, (const uint32_t *)STM32MP_DDR_BASE, TRAINING_AREA_SIZE); diff --git a/plat/st/stm32mp1/stm32mp1_critic_power.c b/plat/st/stm32mp1/stm32mp1_critic_power.c index 583cf93fad..aad11fa508 100644 --- a/plat/st/stm32mp1/stm32mp1_critic_power.c +++ b/plat/st/stm32mp1/stm32mp1_critic_power.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019-2020, STMicroelectronics - All Rights Reserved + * Copyright (C) 2019-2021, STMicroelectronics - All Rights Reserved * * SPDX-License-Identifier: BSD-3-Clause */ @@ -10,19 +10,38 @@ #include #include #include +#include #include +#include +#include #include -static void cstop_critic_enter(void) +static void cstop_critic_enter(uint32_t mode) { + /* Switch to Software Self-Refresh mode */ + ddr_set_sr_mode(DDR_SSR_MODE); + /* * Set DDR in Self-refresh,. * This is also the procedure awaited when switching off power supply. */ if (ddr_standby_sr_entry() != 0) { ERROR("Unable to put DDR in SR\n"); - panic(); + if (mode != STM32_PM_SHUTDOWN) { + panic(); + } + } +} + +static void shutdown_critic_enter(void) +{ + if (dt_pmic_status() > 0) { + if (!initialize_pmic_i2c()) { + panic(); + } + + pmic_switch_off(); } } @@ -36,10 +55,18 @@ static void cstop_critic_exit(void) } } -void stm32_pwr_down_wfi_load(bool is_cstop) +void stm32_pwr_down_wfi_load(bool is_cstop, uint32_t mode) { + if (mode != STM32_PM_CSLEEP_RUN) { + dcsw_op_all(DC_OP_CISW); + } + if (is_cstop) { - cstop_critic_enter(); + cstop_critic_enter(mode); + } + + if (mode == STM32_PM_SHUTDOWN) { + shutdown_critic_enter(); } /* @@ -61,12 +88,20 @@ void stm32_pwr_down_wfi_load(bool is_cstop) extern void wfi_svc_int_enable(uintptr_t stack_addr); static uint32_t int_stack[STM32MP_INT_STACK_SIZE]; -void stm32_pwr_down_wfi(bool is_cstop) +void stm32_pwr_down_wfi(bool is_cstop, uint32_t mode) { uint32_t interrupt = GIC_SPURIOUS_INTERRUPT; + if (mode != STM32_PM_CSLEEP_RUN) { + dcsw_op_all(DC_OP_CISW); + } + if (is_cstop) { - cstop_critic_enter(); + cstop_critic_enter(mode); + } + + if (mode == STM32_PM_SHUTDOWN) { + shutdown_critic_enter(); } stm32mp1_calib_set_wakeup(false); diff --git a/plat/st/stm32mp1/stm32mp1_critic_power_wrapper.S b/plat/st/stm32mp1/stm32mp1_critic_power_wrapper.S index 2c4dd844d2..514def2fc4 100644 --- a/plat/st/stm32mp1/stm32mp1_critic_power_wrapper.S +++ b/plat/st/stm32mp1/stm32mp1_critic_power_wrapper.S @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019-2020, STMicroelectronics - All Rights Reserved + * Copyright (C) 2019-2021, STMicroelectronics - All Rights Reserved * * SPDX-License-Identifier: BSD-3-Clause */ @@ -21,6 +21,9 @@ func stm32_pwr_down_wfi_wrapper push {r4,r5,r6,lr} + # Save r0 and r1 in r2 and r3, as they are used in disable_mmu_secure + mov r2, r0 + mov r3, r1 # Save current sp in r4 mov r4, sp # Save current VBAR in r5 @@ -34,20 +37,21 @@ func stm32_pwr_down_wfi_wrapper stcopr r1, MVBAR # Set sp to BL2 STACK (as BL2 is not using it anymore) - ldr sp, =__STACKS_END__ + ldr sp, =__STACKS_END__ # Disable MMU as TLB are still stored in DDR, # and in few instructions DDR won't be readable - bl disable_mmu_secure + bl disable_mmu_secure # dsb is done in disable mmu # isb is done in disable mmu - # We didn't change R0 to keep it as first parameter - bl stm32_pwr_down_wfi_load + mov r0, r2 + mov r1, r3 + bl stm32_pwr_down_wfi_load # Restore stack - mov sp, r4 + mov sp, r4 # Restore VBAR stcopr r5, VBAR # Restore MVBAR diff --git a/plat/st/stm32mp1/stm32mp1_def.h b/plat/st/stm32mp1/stm32mp1_def.h index 326b227842..780d124d17 100644 --- a/plat/st/stm32mp1/stm32mp1_def.h +++ b/plat/st/stm32mp1/stm32mp1_def.h @@ -162,8 +162,8 @@ enum ddr_type { #define STM32MP_BL2_RO_SIZE U(0x00014000) /* 80 KB */ #define STM32MP_BL2_SIZE U(0x0001B000) /* 108 KB for BL2 */ #else -#define STM32MP_BL2_RO_SIZE U(0x00010000) /* 64 KB */ -#define STM32MP_BL2_SIZE U(0x00015000) /* 84 KB for BL2 */ +#define STM32MP_BL2_RO_SIZE U(0x00011000) /* 68 KB */ +#define STM32MP_BL2_SIZE U(0x00016000) /* 88 KB for BL2 */ #endif #define STM32MP_BL2_BASE (STM32MP_SEC_SYSRAM_BASE + \ @@ -182,7 +182,7 @@ enum ddr_type { #if STM32MP_SP_MIN_IN_DDR #define STM32MP_BL32_SIZE U(0x00025000) /* 148 KB for BL32 */ #else -#define STM32MP_BL32_SIZE U(0x0001A000) /* 100 KB for BL32 */ +#define STM32MP_BL32_SIZE U(0x0001B000) /* 108 KB for BL32 */ #endif #endif /* STM32MP_USE_STM32IMAGE */ #endif /* STM32MP_SSP */ @@ -265,10 +265,14 @@ enum ddr_type { STM32MP_BL2_DTB_SIZE) #define STM32MP_BL32_DTB_SIZE U(0x00005000) /* 20 KB for DTB */ +#if STM32MP_SP_MIN_IN_DDR +#define DDR_SEC_SIZE U(0x02000000) /* 32MB */ +#else #define STM32MP_BL32_DTB_BASE STM32MP_SYSRAM_BASE #define STM32MP_BL32_BASE (STM32MP_BL32_DTB_BASE + \ STM32MP_BL32_DTB_SIZE) +#endif #if defined(IMAGE_BL2) #define STM32MP_DTB_SIZE STM32MP_BL2_DTB_SIZE @@ -581,11 +585,8 @@ enum ddr_type { #define PLAT_MAX_TAMP_INT U(6) #define PLAT_MAX_TAMP_EXT U(3) #define TAMP_BASE U(0x5C00A000) -#define TAMP_SMCR (TAMP_BASE + U(0x20)) #define TAMP_BKP_REGISTER_BASE (TAMP_BASE + U(0x100)) #define TAMP_BKP_SEC_NUMBER U(10) -#define TAMP_BKP_SEC_WDPROT_SHIFT U(16) -#define TAMP_BKP_SEC_RWDPROT_SHIFT U(0) #if !(defined(__LINKER__) || defined(__ASSEMBLER__)) @@ -650,6 +651,16 @@ static inline uint32_t tamp_bkpr(uint32_t idx) #define PLAT_MAX_OPP_NB U(2) #define PLAT_MAX_PLLCFG_NB U(6) +/******************************************************************************* + * REGULATORS + ******************************************************************************/ +/* 3 PWR + 1 VREFBUF + 14 PMIC regulators + 1 FIXED */ +#define PLAT_NB_RDEVS U(19) +/* Number of low power modes defined in the device tree */ +#define PLAT_NB_SUSPEND_MODES 7 +/* 1 FIXED */ +#define PLAT_NB_FIXED_REGS U(1) + /******************************************************************************* * DEBUG ******************************************************************************/ diff --git a/plat/st/stm32mp1/stm32mp1_helper.S b/plat/st/stm32mp1/stm32mp1_helper.S index 315a67f2cf..da3ab1562b 100644 --- a/plat/st/stm32mp1/stm32mp1_helper.S +++ b/plat/st/stm32mp1/stm32mp1_helper.S @@ -251,12 +251,12 @@ func plat_crash_console_init str r2, [r1] 1: ldr r0, [r1] - ands r0, r2 + ands r2, r0, r2 beq 1b str r2, [r1, #4] /* RSTCLR register */ 2: ldr r0, [r1] - ands r0, r2 + ands r2, r0, r2 bne 2b /* Enable GPIOs for UART TX */ ldr r1, =(RCC_BASE + DEBUG_UART_TX_GPIO_BANK_CLK_REG) diff --git a/plat/st/stm32mp1/stm32mp1_low_power.c b/plat/st/stm32mp1/stm32mp1_low_power.c index ae6fd88c88..82e2de710c 100644 --- a/plat/st/stm32mp1/stm32mp1_low_power.c +++ b/plat/st/stm32mp1/stm32mp1_low_power.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2020, STMicroelectronics - All Rights Reserved + * Copyright (c) 2017-2021, STMicroelectronics - All Rights Reserved * * SPDX-License-Identifier: BSD-3-Clause */ @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -104,6 +105,11 @@ static struct spinlock lp_lock; static volatile int cpu0_state = STATE_NONE; static volatile int cpu1_state = STATE_NONE; +const char *plat_get_lp_mode_name(int mode) +{ + return config_pwr[mode].regul_suspend_node_name; +} + void stm32_apply_pmic_suspend_config(uint32_t mode) { const char *node_name; @@ -116,14 +122,6 @@ void stm32_apply_pmic_suspend_config(uint32_t mode) if (!initialize_pmic_i2c()) { panic(); } - - if (pmic_set_lp_config(node_name) < 0) { - panic(); - } - - if (pmic_configure_boot_on_regulators() < 0) { - panic(); - } } } @@ -147,11 +145,6 @@ static void enter_cstop(uint32_t mode, uint32_t nsec_addr) stm32mp1_syscfg_disable_io_compensation(); - /* Switch to Software Self-Refresh mode */ - ddr_set_sr_mode(DDR_SSR_MODE); - - dcsw_op_all(DC_OP_CISW); - stm32_clean_context(); if (mode == STM32_PM_CSTOP_ALLOW_STANDBY_DDR_SR) { @@ -170,6 +163,8 @@ static void enter_cstop(uint32_t mode, uint32_t nsec_addr) } } + regulator_core_suspend(mode); + /* Clear RCC interrupt before enabling it */ mmio_setbits_32(rcc_base + RCC_MP_CIFR, RCC_MP_CIFR_WKUPF); @@ -289,6 +284,8 @@ void stm32_exit_cstop(void) panic(); } + regulator_core_resume(); + stm32mp1_syscfg_enable_io_compensation_finish(); } @@ -348,7 +345,7 @@ static void stm32_auto_stop_cpu0(void) enter_cstop(STM32_PM_CSTOP_ALLOW_LP_STOP, 0); - stm32_pwr_down_wfi(true); + stm32_pwr_down_wfi(true, STM32_PM_CSTOP_ALLOW_LP_STOP); stm32_exit_cstop(); @@ -380,27 +377,6 @@ void stm32_auto_stop(void) } } -static void enter_shutdown(void) -{ - /* Set DDR in Self-refresh before shutting down the platform */ - if (ddr_standby_sr_entry() != 0) { - WARN("DDR can't be set in Self-refresh mode\n"); - } - - if (dt_pmic_status() > 0) { - if (!initialize_pmic_i2c()) { - panic(); - } - - stpmic1_switch_off(); - - udelay(100); - - /* Shouldn't be reached */ - panic(); - } -} - static void enter_csleep(void) { uintptr_t pwr_base = stm32mp_pwr_base(); @@ -410,14 +386,13 @@ static void enter_csleep(void) mmio_clrsetbits_32(pwr_base + PWR_CR1, PWR_CR1_MASK, config_pwr[STM32_PM_CSLEEP_RUN].pwr_cr1); - stm32_pwr_down_wfi(false); + stm32_pwr_down_wfi(false, STM32_PM_CSLEEP_RUN); } void stm32_enter_low_power(uint32_t mode, uint32_t nsec_addr) { switch (mode) { case STM32_PM_SHUTDOWN: - enter_shutdown(); break; case STM32_PM_CSLEEP_RUN: diff --git a/plat/st/stm32mp1/stm32mp1_pm.c b/plat/st/stm32mp1/stm32mp1_pm.c index 962a992243..e5f622a5be 100644 --- a/plat/st/stm32mp1/stm32mp1_pm.c +++ b/plat/st/stm32mp1/stm32mp1_pm.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2020, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2015-2021, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ @@ -169,7 +169,8 @@ static void __dead2 stm32_pwr_domain_pwr_down_wfi(const psci_power_state_t void (*warm_entrypoint)(void) = (void (*)(void))stm32_sec_entrypoint; - stm32_pwr_down_wfi(stm32_is_cstop_done()); + stm32_pwr_down_wfi(stm32_is_cstop_done(), + stm32mp1_get_lp_soc_mode(PSCI_MODE_SYSTEM_SUSPEND)); stm32_exit_cstop(); @@ -207,7 +208,7 @@ static void __dead2 stm32_system_off(void) stm32_enter_low_power(soc_mode, 0); - stm32_pwr_down_wfi(false); + stm32_pwr_down_wfi(true, soc_mode); /* This shouldn't be reached */ panic(); diff --git a/plat/st/stm32mp1/stm32mp1_private.c b/plat/st/stm32mp1/stm32mp1_private.c index 09afe1a6ea..0451efe72f 100644 --- a/plat/st/stm32mp1/stm32mp1_private.c +++ b/plat/st/stm32mp1/stm32mp1_private.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2020, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2015-2021, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ @@ -13,11 +13,9 @@ #include #include #include +#include #include -#include #include -#include -#include #include #include #include @@ -165,110 +163,6 @@ void __dead2 stm32mp_wait_cpu_reset(void) } } -/* - * tzc_source_ip contains the TZC transaction source IPs that need to be reset - * before a C-A7 subsystem is reset (i.e. independent reset): - * - C-A7 subsystem is reset separately later in the sequence, - * - C-M4 subsystem is not concerned here, - * - DAP is excluded for debug purpose, - * - IPs are stored with their ETZPC IDs (STM32MP1_ETZPC_MAX_ID if not - * applicable) because some of them need to be reset only if they are not - * configured in MCU isolation mode inside ETZPC device tree. - */ -struct tzc_source_ip { - uint32_t reset_id; - uint32_t clock_id; - uint32_t decprot_id; -}; - -#define _TZC_FIXED(res, clk) \ - { \ - .reset_id = (res), \ - .clock_id = (clk), \ - .decprot_id = STM32MP1_ETZPC_MAX_ID, \ - } - -#define _TZC_COND(res, clk, decprot) \ - { \ - .reset_id = (res), \ - .clock_id = (clk), \ - .decprot_id = (decprot), \ - } - -static const struct tzc_source_ip tzc_source_ip[] = { - _TZC_FIXED(LTDC_R, LTDC_PX), - _TZC_FIXED(GPU_R, GPU), - _TZC_FIXED(USBH_R, USBH), - _TZC_FIXED(SDMMC1_R, SDMMC1_K), - _TZC_FIXED(SDMMC2_R, SDMMC2_K), - _TZC_FIXED(MDMA_R, MDMA), - _TZC_COND(USBO_R, USBO_K, STM32MP1_ETZPC_OTG_ID), - _TZC_COND(SDMMC3_R, SDMMC3_K, STM32MP1_ETZPC_SDMMC3_ID), - _TZC_COND(ETHMAC_R, ETHMAC, STM32MP1_ETZPC_ETH_ID), - _TZC_COND(DMA1_R, DMA1, STM32MP1_ETZPC_DMA1_ID), - _TZC_COND(DMA2_R, DMA2, STM32MP1_ETZPC_DMA2_ID), -}; - -#define TIMEOUT_US_1MS U(1000) - -void __dead2 stm32mp_plat_reset(int cpu) -{ - uint32_t reg = RCC_MP_GRSTCSETR_MPUP0RST; - uint32_t id; - - /* Mask timer interrupts */ - stm32mp_mask_timer(); - - for (id = 0U; id < ARRAY_SIZE(tzc_source_ip); id++) { - if ((!clk_is_enabled(tzc_source_ip[id].clock_id)) || - ((tzc_source_ip[id].decprot_id != STM32MP1_ETZPC_MAX_ID) && - (etzpc_get_decprot(tzc_source_ip[id].decprot_id) == - ETZPC_DECPROT_MCU_ISOLATION))) { - continue; - } - - if (tzc_source_ip[id].reset_id != GPU_R) { - uint32_t reset = tzc_source_ip[id].reset_id; - int ret; - - ret = stm32mp_reset_assert(reset, TIMEOUT_US_1MS); - if (ret != 0) { - panic(); - } - ret = stm32mp_reset_deassert(reset, TIMEOUT_US_1MS); - if (ret != 0) { - panic(); - } - } else { - /* GPU reset automatically cleared by hardware */ - mmio_setbits_32(stm32mp_rcc_base() + RCC_AHB6RSTSETR, - RCC_AHB6RSTSETR_GPURST); - } - } - - if (!stm32mp_is_single_core()) { - unsigned int sec_cpu = (cpu == STM32MP_PRIMARY_CPU) ? - STM32MP_SECONDARY_CPU : STM32MP_PRIMARY_CPU; - - gicv2_raise_sgi(ARM_IRQ_SEC_SGI_1, sec_cpu); - reg |= RCC_MP_GRSTCSETR_MPUP1RST; - } - - do { - id = plat_ic_get_pending_interrupt_id(); - - if (id <= MAX_SPI_ID) { - gicv2_end_of_interrupt(id); - - plat_ic_disable_interrupt(id); - } - } while (id <= MAX_SPI_ID); - - mmio_write_32(stm32mp_rcc_base() + RCC_MP_GRSTCSETR, reg); - - stm32mp_wait_cpu_reset(); -} - uintptr_t stm32_get_gpio_bank_base(unsigned int bank) { if (bank == GPIO_BANK_Z) { @@ -291,6 +185,15 @@ uint32_t stm32_get_gpio_bank_offset(unsigned int bank) return bank * GPIO_BANK_OFFSET; } +bool stm32_gpio_is_secure_at_reset(unsigned int bank) +{ + if (bank == GPIO_BANK_Z) { + return true; + } + + return false; +} + #if STM32MP_UART_PROGRAMMER || defined(IMAGE_BL32) /* * UART Management @@ -317,6 +220,53 @@ uintptr_t get_uart_address(uint32_t instance_nb) } #endif +#if STM32MP_USB_PROGRAMMER +struct gpio_bank_pin_list { + uint32_t bank; + uint32_t pin; +}; + +static const struct gpio_bank_pin_list gpio_list[] = { + { /* USART2_RX: GPIOA3 */ + .bank = 0, + .pin = 3, + }, + { /* USART3_RX: GPIOB12 */ + .bank = 1, + .pin = 12, + }, + { /* UART4_RX: GPIOB2 */ + .bank = 1, + .pin = 2, + }, + { /* UART5_RX: GPIOB4 */ + .bank = 1, + .pin = 5, + }, + { /* USART6_RX: GPIOC7 */ + .bank = 2, + .pin = 7, + }, + { /* UART7_RX: GPIOF6 */ + .bank = 5, + .pin = 6, + }, + { /* UART8_RX: GPIOE0 */ + .bank = 4, + .pin = 0, + }, +}; + +void stm32mp1_deconfigure_uart_pins(void) +{ + size_t i; + + for (i = 0; i < ARRAY_SIZE(gpio_list); i++) { + set_gpio_reset_cfg(gpio_list[i].bank, gpio_list[i].pin); + } +} +#endif + unsigned long stm32_get_gpio_bank_clock(unsigned int bank) { if (bank == GPIO_BANK_Z) { @@ -403,25 +353,38 @@ int stm32_get_otp_value_from_idx(const uint32_t otp_idx, uint32_t *otp_val) return 0; } -int stm32mp_get_chip_version(uint32_t *chip_version) +uint32_t stm32mp_get_chip_version(void) { - return stm32mp1_dbgmcu_get_chip_version(chip_version); + uint32_t version = 0U; + + if (stm32mp1_dbgmcu_get_chip_version(&version) < 0) { + INFO("Cannot get CPU version, debug disabled\n"); + return 0U; + } + + return version; } -static uint32_t get_part_number(void) +uint32_t stm32mp_get_chip_dev_id(void) { - static uint32_t part_number; uint32_t dev_id; - if (part_number != 0U) { - return part_number; - } - if (stm32mp1_dbgmcu_get_chip_dev_id(&dev_id) < 0) { INFO("Use default chip ID, debug disabled\n"); dev_id = STM32MP1_CHIP_ID; } + return dev_id; +} + +static uint32_t get_part_number(void) +{ + static uint32_t part_number; + + if (part_number != 0U) { + return part_number; + } + if (stm32_get_otp_value(PART_NUMBER_OTP, &part_number) != 0) { panic(); } @@ -429,7 +392,7 @@ static uint32_t get_part_number(void) part_number = (part_number & PART_NUMBER_OTP_PART_MASK) >> PART_NUMBER_OTP_PART_SHIFT; - part_number |= dev_id << 16; + part_number |= stm32mp_get_chip_dev_id() << 16; return part_number; } @@ -477,8 +440,6 @@ bool stm32mp_supports_cpu_opp(uint32_t opp_id) void stm32mp_get_soc_name(char name[STM32_SOC_NAME_SIZE]) { char *cpu_s, *cpu_r, *pkg; - uint32_t chip_dev_id; - int ret; /* MPUs Part Numbers */ switch (get_part_number()) { @@ -543,12 +504,7 @@ void stm32mp_get_soc_name(char name[STM32_SOC_NAME_SIZE]) } /* REVISION */ - ret = stm32mp_get_chip_version(&chip_dev_id); - if (ret < 0) { - INFO("Cannot get CPU version, debug disabled\n"); - } - - switch (chip_dev_id) { + switch (stm32mp_get_chip_version()) { case STM32MP1_REV_B: cpu_r = "B"; break; @@ -732,29 +688,6 @@ enum etzpc_decprot_attributes stm32mp_etzpc_binding2decprot(uint32_t mode) } } -int plat_bind_regulator(struct stm32mp_regulator *regu) -{ - void *fdt; - int regu_node; - - if (fdt_get_address(&fdt) == 0) { - return false; - } - - if ((dt_pmic_status() > 0) && is_pmic_regulator(regu)) { - bind_pmic_regulator(regu); - } else { - bind_dummy_regulator(regu); - } - - regu_node = fdt_node_offset_by_phandle(fdt, regu->id); - if (fdt_getprop(fdt, regu_node, "regulator-always-on", NULL) != NULL) { - regu->always_on = true; - } - - return 0; -} - #if STM32MP_USE_STM32IMAGE /* Get the non-secure DDR size */ uint32_t stm32mp_get_ddr_ns_size(void) @@ -789,9 +722,14 @@ bool stm32mp1_addr_inside_backupsram(uintptr_t addr) bool stm32mp1_is_wakeup_from_standby(void) { + uint32_t rstsr = mmio_read_32(stm32mp_rcc_base() + RCC_MP_RSTSCLRR); uint32_t bkpr_core1_addr = tamp_bkpr(BOOT_API_CORE1_BRANCH_ADDRESS_TAMP_BCK_REG_IDX); uint32_t nsec_address; + if ((rstsr & RCC_MP_RSTSCLRR_PADRSTF) != 0U) { + return false; + } + if (stm32mp_get_boot_action() != BOOT_API_CTX_BOOT_ACTION_WAKEUP_STANDBY) { return false; } diff --git a/plat/st/stm32mp1/stm32mp1_ssp.c b/plat/st/stm32mp1/stm32mp1_ssp.c index bcbf374782..a60721691e 100644 --- a/plat/st/stm32mp1/stm32mp1_ssp.c +++ b/plat/st/stm32mp1/stm32mp1_ssp.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -803,24 +804,24 @@ static void ssp_start(boot_api_context_t *boot_context) * the required MPSYSRST. */ if (dt_pmic_status() > 0) { - const char *name; + struct rdev *regul; - name = stm32mp_get_cpu_supply_name(); - if (name == NULL) { - goto out; + regul = dt_get_cpu_regulator(); + if (regul == NULL) { + panic(); } - if (stpmic1_regulator_mask_reset_set(name) != 0) { - WARN("Failed to write %s reset mask\n", name); + if (regulator_set_flag(regul, REGUL_MASK_RESET) < 0) { + WARN("Failed to write cpu-supply reset mask\n"); } - name = stm32mp_get_vdd_supply_name(); - if (name == NULL) { + regul = dt_get_vdd_regulator(); + if (regul == NULL) { goto out; } - if (stpmic1_regulator_mask_reset_set(name) != 0) { - WARN("Failed to write %s reset mask\n", name); + if (regulator_set_flag(regul, REGUL_MASK_RESET) < 0) { + WARN("Failed to write vdd-supply reset mask\n"); } } else { static const char debug_msg[] = { @@ -1028,7 +1029,7 @@ skip_console_init: stm32_iwdg_refresh(); if (dt_pmic_status() > 0) { - initialize_pmic(); + initialize_pmic_i2c(); print_pmic_info_and_debug(); } diff --git a/plat/st/stm32mp1/stm32mp1_syscfg.c b/plat/st/stm32mp1/stm32mp1_syscfg.c index 2c5fa082fc..b471be2096 100644 --- a/plat/st/stm32mp1/stm32mp1_syscfg.c +++ b/plat/st/stm32mp1/stm32mp1_syscfg.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2020, STMicroelectronics - All Rights Reserved + * Copyright (c) 2019-2021, STMicroelectronics - All Rights Reserved * * SPDX-License-Identifier: BSD-3-Clause */ @@ -26,6 +26,9 @@ #define SYSCFG_CMPENSETR 0x24U #define SYSCFG_CMPENCLRR 0x28U +#define CMPCR_CMPENSETR_OFFSET 0x4U +#define CMPCR_CMPENCLRR_OFFSET 0x8U + /* * SYSCFG_BOOTR Register */ @@ -63,25 +66,61 @@ */ #define SYSCFG_CMPENSETR_MPU_EN BIT(0) -void stm32mp1_syscfg_init(void) +static void enable_io_comp_cell_finish(uintptr_t cmpcr_off) +{ + uint64_t start; + + start = timeout_init_us(SYSCFG_CMPCR_READY_TIMEOUT_US); + + while ((mmio_read_32(SYSCFG_BASE + cmpcr_off) & SYSCFG_CMPCR_READY) == 0U) { + if (timeout_elapsed(start)) { + /* Failure on IO compensation enable is not a issue: warn only. */ + WARN("IO compensation cell not ready\n"); + break; + } + } + + mmio_clrbits_32(SYSCFG_BASE + cmpcr_off, SYSCFG_CMPCR_SW_CTRL); +} + +static void disable_io_comp_cell(uintptr_t cmpcr_off) +{ + uint32_t value; + + if (((mmio_read_32(SYSCFG_BASE + cmpcr_off) & SYSCFG_CMPCR_READY) == 0U) || + ((mmio_read_32(SYSCFG_BASE + cmpcr_off + CMPCR_CMPENSETR_OFFSET) & + SYSCFG_CMPENSETR_MPU_EN) == 0U)) { + return; + } + + value = mmio_read_32(SYSCFG_BASE + cmpcr_off) >> SYSCFG_CMPCR_ANSRC_SHIFT; + + mmio_clrbits_32(SYSCFG_BASE + cmpcr_off, SYSCFG_CMPCR_RANSRC | SYSCFG_CMPCR_RAPSRC); + + value <<= SYSCFG_CMPCR_RANSRC_SHIFT; + value |= mmio_read_32(SYSCFG_BASE + cmpcr_off); + + mmio_write_32(SYSCFG_BASE + cmpcr_off, value | SYSCFG_CMPCR_SW_CTRL); + + mmio_setbits_32(SYSCFG_BASE + cmpcr_off + CMPCR_CMPENCLRR_OFFSET, SYSCFG_CMPENSETR_MPU_EN); +} + +static void enable_high_speed_mode_low_voltage(void) +{ + mmio_write_32(SYSCFG_BASE + SYSCFG_IOCTRLSETR, + SYSCFG_IOCTRLSETR_HSLVEN_TRACE | + SYSCFG_IOCTRLSETR_HSLVEN_QUADSPI | + SYSCFG_IOCTRLSETR_HSLVEN_ETH | + SYSCFG_IOCTRLSETR_HSLVEN_SDMMC | + SYSCFG_IOCTRLSETR_HSLVEN_SPI); +} + +static void stm32mp1_syscfg_set_hslv(void) { - uint32_t bootr; uint32_t otp_value; uint32_t vdd_voltage; bool product_below_2v5; - /* - * Interconnect update : select master using the port 1. - * LTDC = AXI_M9. - */ - mmio_write_32(SYSCFG_BASE + SYSCFG_ICNR, SYSCFG_ICNR_AXI_M9); - - /* Disable Pull-Down for boot pin connected to VDD */ - bootr = mmio_read_32(SYSCFG_BASE + SYSCFG_BOOTR) & - SYSCFG_BOOTR_BOOT_MASK; - mmio_clrsetbits_32(SYSCFG_BASE + SYSCFG_BOOTR, SYSCFG_BOOTR_BOOTPD_MASK, - bootr << SYSCFG_BOOTR_BOOTPD_SHIFT); - /* * High Speed Low Voltage Pad mode Enable for SPI, SDMMC, ETH, QSPI * and TRACE. Needed above ~50MHz and conditioned by AFMUX selection. @@ -110,12 +149,7 @@ void stm32mp1_syscfg_init(void) if (vdd_voltage == 0U) { WARN("VDD unknown\n"); } else if (vdd_voltage < 2700000U) { - mmio_write_32(SYSCFG_BASE + SYSCFG_IOCTRLSETR, - SYSCFG_IOCTRLSETR_HSLVEN_TRACE | - SYSCFG_IOCTRLSETR_HSLVEN_QUADSPI | - SYSCFG_IOCTRLSETR_HSLVEN_ETH | - SYSCFG_IOCTRLSETR_HSLVEN_SDMMC | - SYSCFG_IOCTRLSETR_HSLVEN_SPI); + enable_high_speed_mode_low_voltage(); if (!product_below_2v5) { INFO("Product_below_2v5=0: HSLVEN protected by HW\n"); @@ -128,6 +162,25 @@ void stm32mp1_syscfg_init(void) panic(); } } +} + +void stm32mp1_syscfg_init(void) +{ + uint32_t bootr; + + /* + * Interconnect update : select master using the port 1. + * LTDC = AXI_M9. + */ + mmio_write_32(SYSCFG_BASE + SYSCFG_ICNR, SYSCFG_ICNR_AXI_M9); + + /* Disable Pull-Down for boot pin connected to VDD */ + bootr = mmio_read_32(SYSCFG_BASE + SYSCFG_BOOTR) & + SYSCFG_BOOTR_BOOT_MASK; + mmio_clrsetbits_32(SYSCFG_BASE + SYSCFG_BOOTR, SYSCFG_BOOTR_BOOTPD_MASK, + bootr << SYSCFG_BOOTR_BOOTPD_SHIFT); + + stm32mp1_syscfg_set_hslv(); stm32mp1_syscfg_enable_io_compensation_start(); } @@ -141,35 +194,17 @@ void stm32mp1_syscfg_enable_io_compensation_start(void) */ stm32mp1_clk_force_enable(SYSCFG); - mmio_setbits_32(SYSCFG_BASE + SYSCFG_CMPENSETR, + mmio_setbits_32(SYSCFG_BASE + CMPCR_CMPENSETR_OFFSET + SYSCFG_CMPCR, SYSCFG_CMPENSETR_MPU_EN); } void stm32mp1_syscfg_enable_io_compensation_finish(void) { - uint64_t start; - - start = timeout_init_us(SYSCFG_CMPCR_READY_TIMEOUT_US); - - while ((mmio_read_32(SYSCFG_BASE + SYSCFG_CMPCR) & - SYSCFG_CMPCR_READY) == 0U) { - if (timeout_elapsed(start)) { - /* - * Failure on IO compensation enable is not a issue: - * warn only. - */ - WARN("IO compensation cell not ready\n"); - break; - } - } - - mmio_clrbits_32(SYSCFG_BASE + SYSCFG_CMPCR, SYSCFG_CMPCR_SW_CTRL); + enable_io_comp_cell_finish(SYSCFG_CMPCR); } void stm32mp1_syscfg_disable_io_compensation(void) { - uint32_t value; - stm32mp1_clk_force_enable(SYSCFG); /* @@ -178,18 +213,7 @@ void stm32mp1_syscfg_disable_io_compensation(void) * requested for other usages and always OFF in STANDBY. * Disable non-secure SYSCFG clock, we assume non-secure is suspended. */ - value = mmio_read_32(SYSCFG_BASE + SYSCFG_CMPCR) >> - SYSCFG_CMPCR_ANSRC_SHIFT; - - mmio_clrbits_32(SYSCFG_BASE + SYSCFG_CMPCR, - SYSCFG_CMPCR_RANSRC | SYSCFG_CMPCR_RAPSRC); - - value = mmio_read_32(SYSCFG_BASE + SYSCFG_CMPCR) | - (value << SYSCFG_CMPCR_RANSRC_SHIFT); - - mmio_write_32(SYSCFG_BASE + SYSCFG_CMPCR, value | SYSCFG_CMPCR_SW_CTRL); - - mmio_setbits_32(SYSCFG_BASE + SYSCFG_CMPENCLRR, SYSCFG_CMPENSETR_MPU_EN); + disable_io_comp_cell(SYSCFG_CMPCR); stm32mp1_clk_force_disable(SYSCFG); } diff --git a/plat/st/stm32mp1/stm32mp1_usb.c b/plat/st/stm32mp1/stm32mp1_usb.c index c63db4a2ff..a205b64d34 100644 --- a/plat/st/stm32mp1/stm32mp1_usb.c +++ b/plat/st/stm32mp1/stm32mp1_usb.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, STMicroelectronics - All Rights Reserved + * Copyright (c) 2020-2021, STMicroelectronics - All Rights Reserved * * SPDX-License-Identifier: BSD-3-Clause */ @@ -310,7 +310,7 @@ static uint8_t *stm32mp1_product_desc(uint16_t *length) char str_chip_version[5]; stm32mp_get_soc_name(name); - stm32mp_get_chip_version(&chip_version); + chip_version = stm32mp_get_chip_version(); int_to_str(STM32MP1_CHIP_ID, (uint8_t *)str_chip_id, 4); int_to_str(chip_version, (uint8_t *)str_chip_version, 5); -- 2.17.1