diff --git a/recipes-bsp/trusted-firmware-a/tf-a-stm32mp/0003-st-update-r1.2.0.patch b/recipes-bsp/trusted-firmware-a/tf-a-stm32mp/0003-st-update-r1.2.0.patch new file mode 100644 index 0000000..450dd44 --- /dev/null +++ b/recipes-bsp/trusted-firmware-a/tf-a-stm32mp/0003-st-update-r1.2.0.patch @@ -0,0 +1,7087 @@ +From 801e39ee5f7ecfc1cb4505d2fef5858c486571a5 Mon Sep 17 00:00:00 2001 +From: Romuald JEANNE +Date: Wed, 29 Jan 2020 14:25:17 +0100 +Subject: [PATCH] st update r1.2.0 + +Signed-off-by: Romuald JEANNE +--- + docs/devicetree/bindings/power/st,stpmic1.txt | 38 -- + docs/devicetree/bindings/soc/st,stm32-romem.txt | 43 ++ + drivers/mmc/mmc.c | 69 ++- + drivers/st/bsec/bsec.c | 129 ++++- + drivers/st/clk/stm32mp1_calib.c | 4 +- + drivers/st/clk/stm32mp1_clk.c | 680 ++++++++++++++++++++++-- + drivers/st/clk/stm32mp1_clkfunc.c | 19 +- + drivers/st/clk/stm32mp_clkfunc.c | 121 +---- + drivers/st/ddr/stm32mp1_ddr.c | 11 +- + drivers/st/ddr/stm32mp1_ddr_helpers.c | 26 +- + drivers/st/ddr/stm32mp1_ram.c | 18 +- + drivers/st/etzpc/etzpc.c | 6 +- + drivers/st/gpio/stm32_gpio.c | 6 +- + drivers/st/i2c/stm32_i2c.c | 165 +++--- + drivers/st/io/io_programmer_st_usb.c | 8 +- + drivers/st/io/io_stm32image.c | 4 +- + drivers/st/iwdg/stm32_iwdg.c | 6 +- + drivers/st/mmc/stm32_sdmmc2.c | 96 ++-- + drivers/st/nand/nand.c | 15 +- + drivers/st/pmic/stm32mp_pmic.c | 472 ++++++++++------ + drivers/st/pmic/stpmic1.c | 20 +- + drivers/st/qspi/io_qspi.c | 4 +- + drivers/st/regulator/stm32mp_dummy_regulator.c | 27 + + drivers/st/regulator/stm32mp_regulator.c | 38 ++ + drivers/st/reset/stm32mp1_reset.c | 3 +- + drivers/st/rng/stm32_rng.c | 3 +- + drivers/st/rtc/stm32_rtc.c | 42 +- + drivers/st/tamper/stm32_tamp.c | 4 +- + drivers/st/timer/stm32_timer.c | 3 +- + drivers/st/uart/io_programmer_uart.c | 5 +- + fdts/stm32mp15-ddr.dtsi | 2 +- + fdts/stm32mp157a-dk1.dts | 33 +- + fdts/stm32mp157c-ed1.dts | 33 +- + fdts/stm32mp157c-security.dtsi | 51 +- + fdts/stm32mp157c.dtsi | 17 + + include/drivers/mmc.h | 27 +- + include/drivers/st/bsec.h | 5 +- + include/drivers/st/stm32_i2c.h | 20 +- + include/drivers/st/stm32_sdmmc2.h | 2 + + include/drivers/st/stm32mp1_clk.h | 22 +- + include/drivers/st/stm32mp1_ddr_regs.h | 4 +- + include/drivers/st/stm32mp_clkfunc.h | 7 +- + include/drivers/st/stm32mp_dummy_regulator.h | 14 + + include/drivers/st/stm32mp_pmic.h | 17 +- + include/drivers/st/stm32mp_regulator.h | 31 ++ + include/drivers/st/stpmic1.h | 24 +- + lib/usb/usb_st_dfu.c | 2 +- + plat/st/common/bl2_io_storage.c | 112 +--- + plat/st/common/include/stm32mp_common.h | 11 +- + plat/st/common/include/stm32mp_dt.h | 7 + + plat/st/common/stm32mp_common.c | 8 +- + plat/st/common/stm32mp_dt.c | 272 ++++++++-- + plat/st/stm32mp1/bl2_plat_setup.c | 183 +++++-- + plat/st/stm32mp1/include/stm32mp1_context.h | 3 + + plat/st/stm32mp1/include/stm32mp1_dbgmcu.h | 10 +- + plat/st/stm32mp1/include/stm32mp1_smc.h | 143 ++++- + plat/st/stm32mp1/plat_image_load.c | 41 +- + plat/st/stm32mp1/platform.mk | 17 +- + plat/st/stm32mp1/services/bsec_svc.c | 20 +- + plat/st/stm32mp1/services/rcc_svc.c | 34 +- + plat/st/stm32mp1/services/rcc_svc.h | 4 +- + plat/st/stm32mp1/services/stm32mp1_svc_setup.c | 10 +- + plat/st/stm32mp1/sp_min/sp_min_setup.c | 26 + + plat/st/stm32mp1/stm32mp1_context.c | 91 +++- + plat/st/stm32mp1/stm32mp1_dbgmcu.c | 72 ++- + plat/st/stm32mp1/stm32mp1_def.h | 76 ++- + plat/st/stm32mp1/stm32mp1_helper_dbg.S | 10 +- + plat/st/stm32mp1/stm32mp1_low_power.c | 18 +- + plat/st/stm32mp1/stm32mp1_pm.c | 12 +- + plat/st/stm32mp1/stm32mp1_power_config.c | 9 +- + plat/st/stm32mp1/stm32mp1_private.c | 271 +++++++--- + plat/st/stm32mp1/stm32mp1_security.c | 22 +- + plat/st/stm32mp1/stm32mp1_syscfg.c | 33 +- + plat/st/stm32mp1/stm32mp1_usb_desc.c | 22 +- + tools/stm32image/stm32image.c | 18 +- + 75 files changed, 2854 insertions(+), 1097 deletions(-) + create mode 100644 drivers/st/regulator/stm32mp_dummy_regulator.c + create mode 100644 drivers/st/regulator/stm32mp_regulator.c + create mode 100644 include/drivers/st/stm32mp_dummy_regulator.h + create mode 100644 include/drivers/st/stm32mp_regulator.h + +diff --git a/docs/devicetree/bindings/power/st,stpmic1.txt b/docs/devicetree/bindings/power/st,stpmic1.txt +index 54b64e2..83307d2 100644 +--- a/docs/devicetree/bindings/power/st,stpmic1.txt ++++ b/docs/devicetree/bindings/power/st,stpmic1.txt +@@ -45,43 +45,6 @@ Required parent device properties: + IT_TWARN_R=30 + IT_TWARN_F=31 + +-Optional parent device properties: +-- st,main-control-register: +- -bit 1: Power cycling will be performed on turn OFF condition +- -bit 2: PWRCTRL is functional +- -bit 3: PWRCTRL active high +-- st,pads-pull-register: +- -bit 1: WAKEUP pull down is not active +- -bit 2: PWRCTRL pull up is active +- -bit 3: PWRCTRL pull down is active +- -bit 4: WAKEUP detector is disabled +-- st,vin-control-register: +- -bit 0: VINLOW monitoring is enabled +- -bit [1...3]: VINLOW rising threshold +- 000 VINOK_f + 50mV +- 001 VINOK_f + 100mV +- 010 VINOK_f + 150mV +- 011 VINOK_f + 200mV +- 100 VINOK_f + 250mV +- 101 VINOK_f + 300mV +- 110 VINOK_f + 350mV +- 111 VINOK_f + 400mV +- -bit [4...5]: VINLOW hyst +- 00 100mV +- 01 200mV +- 10 300mV +- 11 400mV +- -bit 6: SW_OUT detector is disabled +- -bit 7: SW_IN detector is enabled. +-- st,usb-control-register: +- -bit 3: SW_OUT current limit +- 0: 600mA +- 1: 1.1A +- -bit 4: VBUS_OTG discharge is enabled +- -bit 5: SW_OUT discharge is enabled +- -bit 6: VBUS_OTG detection is enabled +- -bit 7: BOOST_OVP is disabled +- + STPMIC1 consists in a varied group of sub-devices. + Each sub-device binding is be described in own documentation file. + +@@ -98,7 +61,6 @@ pmic: pmic@33 { + reg = <0x33>; + interrupt-parent = <&gpioa>; + interrupts = <0 2>; +- st,main-control-register=<0x0c>; + interrupt-controller; + #interrupt-cells = <2>; + +diff --git a/docs/devicetree/bindings/soc/st,stm32-romem.txt b/docs/devicetree/bindings/soc/st,stm32-romem.txt +index fbff52e..c430fb8 100644 +--- a/docs/devicetree/bindings/soc/st,stm32-romem.txt ++++ b/docs/devicetree/bindings/soc/st,stm32-romem.txt +@@ -16,6 +16,12 @@ Required properties: + Optional Data cells: + - Must be child nodes as described in nvmem.txt. + ++Optional-properties: ++- "st,non-secure-otp" specifies that the OTP can be accessed by non-secure ++ world through secure world services. Only useful for upper OTPs. This ++ property mandates 32-bit granularity of the related nvmem area, that is ++ offset and length are both multiple of 4. ++ + Example on stm32f4: + romem: nvmem@1fff7800 { + compatible = "st,stm32-romem"; +@@ -29,3 +35,40 @@ Example on stm32f4: + }; + ... + }; ++ ++Example on stm32mp1: ++ bsec: nvmem@5c005000 { ++ ... ++ mac_addr: mac_addr@e4 { ++ reg = <0xe4 0x8>; ++ st,non-secure-otp; ++ }; ++ ... ++ }; ++ ++The nvmem_layout node gathers all nvmem platform-dependent layout information, ++including OTP names and phandles, in order to allow easy accesses for data ++consumers, using pre-defined string in nvmem-cell-names property. ++ ++Required properties: ++- compatible: "st,stm32-nvmem-layout" ++- nvmem-cells and nvmem-cell-names, as described in nvmem.txt. ++ ++Example on stm32mp1: ++ nvmem_layout: nvmem_layout@0 { ++ compatible = "st,stm32-nvmem-layout"; ++ nvmem-cells = <&part_number_otp>, ++ ... ++ ; ++ nvmem-cell-names = "part_number_otp", ++ ... ++ ; ++ }; ++ ++ bsec: nvmem@5c005000 { ++ ... ++ part_number_otp: part_number_otp@4 { ++ reg = <0x4 0x1>; ++ }; ++ ... ++ }; +diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c +index 3f9657d..baaddfe 100644 +--- a/drivers/mmc/mmc.c ++++ b/drivers/mmc/mmc.c +@@ -24,6 +24,7 @@ + static const struct mmc_ops *ops; + static unsigned int mmc_ocr_value; + static struct mmc_csd_emmc mmc_csd; ++static struct sd_switch_status sd_switch_func_status; + static unsigned char mmc_ext_csd[512] __aligned(16); + static unsigned int mmc_flags; + static struct mmc_device_info *mmc_dev_info; +@@ -43,6 +44,11 @@ static bool is_cmd23_enabled(void) + return ((mmc_flags & MMC_FLAG_CMD23) != 0U); + } + ++static bool is_sd_cmd6_enabled(void) ++{ ++ return ((mmc_flags & MMC_FLAG_SD_CMD6) != 0U); ++} ++ + static int mmc_send_cmd(unsigned int idx, unsigned int arg, + unsigned int r_type, unsigned int *r_data) + { +@@ -326,6 +332,33 @@ static int mmc_fill_device_info(void) + return 0; + } + ++static int sd_switch(unsigned char mode, unsigned char group, ++ unsigned char func) ++{ ++ unsigned int group_shift = (group - 1U) * 4U; ++ unsigned int group_mask = GENMASK(group_shift + 3U, group_shift); ++ unsigned int arg; ++ int ret = 0; ++ ++ ret = ops->prepare(0, (uintptr_t)&sd_switch_func_status, ++ sizeof(sd_switch_func_status)); ++ if (ret != 0) { ++ return ret; ++ } ++ ++ /* MMC CMD6: SWITCH_FUNC */ ++ arg = (mode << 31) | GENMASK(23, 0); ++ arg &= ~group_mask; ++ arg |= func << group_shift; ++ ret = mmc_send_cmd(MMC_CMD(6), arg, MMC_RESPONSE_R1, NULL); ++ if (ret != 0) { ++ return ret; ++ } ++ ++ return ops->read(0, (uintptr_t)&sd_switch_func_status, ++ sizeof(sd_switch_func_status)); ++} ++ + static int sd_send_op_cond(void) + { + int n; +@@ -360,7 +393,7 @@ static int sd_send_op_cond(void) + return 0; + } + +- mdelay(1); ++ mdelay(10); + } + + ERROR("ACMD41 failed after %d retries\n", SEND_OP_COND_MAX_RETRIES); +@@ -493,7 +526,39 @@ static int mmc_enumerate(unsigned int clk, unsigned int bus_width) + return ret; + } + +- return mmc_fill_device_info(); ++ ret = mmc_fill_device_info(); ++ if (ret != 0) { ++ return ret; ++ } ++ ++ if (is_sd_cmd6_enabled() && ++ (mmc_dev_info->mmc_dev_type == MMC_IS_SD_HC)) { ++ /* Try to switch to High Speed Mode */ ++ ret = sd_switch(SD_SWITCH_FUNC_CHECK, 1U, 1U); ++ if (ret != 0) { ++ return ret; ++ } ++ ++ if ((sd_switch_func_status.support_g1 & BIT(9)) == 0U) { ++ /* High speed not supported, keep default speed */ ++ return 0; ++ } ++ ++ ret = sd_switch(SD_SWITCH_FUNC_SWITCH, 1U, 1U); ++ if (ret != 0) { ++ return ret; ++ } ++ ++ if ((sd_switch_func_status.sel_g2_g1 & 0x1U) == 0U) { ++ /* Cannot switch to high speed, keep default speed */ ++ return 0; ++ } ++ ++ mmc_dev_info->max_bus_freq = 50000000U; ++ ret = ops->set_ios(clk, bus_width); ++ } ++ ++ return ret; + } + + size_t mmc_read_blocks(int lba, uintptr_t buf, size_t size) +diff --git a/drivers/st/bsec/bsec.c b/drivers/st/bsec/bsec.c +index 3dad2c2..2193a67 100644 +--- a/drivers/st/bsec/bsec.c ++++ b/drivers/st/bsec/bsec.c +@@ -1,6 +1,6 @@ + /* +- * Copyright (c) 2017-2018, STMicroelectronics - All Rights Reserved +- * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. ++ * Copyright (c) 2017-2019, STMicroelectronics - All Rights Reserved ++ * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +@@ -11,9 +11,9 @@ + #include + #include + #include ++#include + #include + #include +-#include + + #define BSEC_IP_VERSION_1_0 0x10 + #define BSEC_COMPAT "st,stm32mp15-bsec" +@@ -82,33 +82,59 @@ static int bsec_dt_otp_nsec_access(void *fdt, int bsec_node) + + fdt_for_each_subnode(bsec_subnode, fdt, bsec_node) { + const fdt32_t *cuint; +- uint32_t reg; ++ uint32_t otp; + uint32_t i; + uint32_t size; +- uint8_t status; ++ uint32_t offset; ++ uint32_t length; + + cuint = fdt_getprop(fdt, bsec_subnode, "reg", NULL); + if (cuint == NULL) { + panic(); + } + +- reg = fdt32_to_cpu(*cuint) / sizeof(uint32_t); +- if (reg < STM32MP1_UPPER_OTP_START) { +- continue; ++ offset = fdt32_to_cpu(*cuint); ++ cuint++; ++ length = fdt32_to_cpu(*cuint); ++ ++ otp = offset / sizeof(uint32_t); ++ ++ if (otp < STM32MP1_UPPER_OTP_START) { ++ unsigned int otp_end = round_up(offset + length, ++ sizeof(uint32_t)) / ++ sizeof(uint32_t); ++ ++ if (otp_end > STM32MP1_UPPER_OTP_START) { ++ /* ++ * OTP crosses Lower/Upper boundary, consider ++ * only the upper part. ++ */ ++ otp = STM32MP1_UPPER_OTP_START; ++ length -= (STM32MP1_UPPER_OTP_START * ++ sizeof(uint32_t)) - offset; ++ offset = STM32MP1_UPPER_OTP_START * ++ sizeof(uint32_t); ++ ++ WARN("OTP crosses Lower/Upper boundary\n"); ++ } else { ++ continue; ++ } + } + +- status = fdt_get_status(bsec_subnode); +- if ((status & DT_NON_SECURE) == 0U) { ++ if ((fdt_getprop(fdt, bsec_subnode, ++ "st,non-secure-otp", NULL)) == NULL) { + continue; + } + +- size = fdt32_to_cpu(*(cuint + 1)) / sizeof(uint32_t); +- +- if ((fdt32_to_cpu(*(cuint + 1)) % sizeof(uint32_t)) != 0) { +- size++; ++ if (((offset % sizeof(uint32_t)) != 0) || ++ ((length % sizeof(uint32_t)) != 0)) { ++ ERROR("Unaligned non-secure OTP\n"); ++ panic(); + } + +- for (i = reg; i < (reg + size); i++) { ++ size = length / sizeof(uint32_t); ++ ++ for (i = otp; i < (otp + size); i++) { + enable_non_secure_access(i); + } + } +@@ -267,6 +293,79 @@ uint32_t bsec_get_config(struct bsec_config *cfg) + } + + /* ++ * bsec_find_otp_name_in_dt: get OTP ID and length in DT. ++ * name: sub-node name to look up. ++ * otp: pointer to read OTP number or NULL. ++ * otp_len: pointer to read OTP length in bits or NULL. ++ * return value: BSEC_OK if no error. ++ */ ++uint32_t bsec_find_otp_name_in_dt(const char *name, uint32_t *otp, ++ uint32_t *otp_len) ++{ ++ void *fdt; ++ int node; ++ int index, len; ++ const fdt32_t *cuint; ++ ++ if ((name == NULL) || (otp == NULL)) { ++ return BSEC_INVALID_PARAM; ++ } ++ ++ if (fdt_get_address(&fdt) == 0) { ++ panic(); ++ } ++ ++ node = dt_get_node_by_compatible(DT_NVMEM_LAYOUT_COMPAT); ++ if (node < 0) { ++ return BSEC_ERROR; ++ } ++ ++ index = fdt_stringlist_search(fdt, node, "nvmem-cell-names", name); ++ if (index < 0) { ++ return BSEC_ERROR; ++ } ++ ++ cuint = fdt_getprop(fdt, node, "nvmem-cells", &len); ++ if (cuint == NULL) { ++ return BSEC_ERROR; ++ } ++ ++ if ((index * (int)sizeof(uint32_t)) > len) { ++ return BSEC_ERROR; ++ } ++ ++ cuint += index; ++ ++ node = fdt_node_offset_by_phandle(fdt, fdt32_to_cpu(*cuint)); ++ if (node < 0) { ++ ERROR("Malformed nvmem_layout node: ignored\n"); ++ return BSEC_ERROR; ++ } ++ ++ cuint = fdt_getprop(fdt, node, "reg", &len); ++ if ((cuint == NULL) || (len != (2 * (int)sizeof(uint32_t)))) { ++ ERROR("Malformed nvmem_layout node: ignored\n"); ++ return BSEC_ERROR; ++ } ++ ++ if (fdt32_to_cpu(*cuint) % sizeof(uint32_t)) { ++ ERROR("Misaligned nvmem_layout element: ignored\n"); ++ return BSEC_ERROR; ++ } ++ ++ if (otp != NULL) { ++ *otp = fdt32_to_cpu(*cuint) / sizeof(uint32_t); ++ } ++ ++ if (otp_len != NULL) { ++ cuint++; ++ *otp_len = fdt32_to_cpu(*cuint) * CHAR_BIT; ++ } ++ ++ return BSEC_OK; ++} ++ ++/* + * bsec_shadow_register: copy SAFMEM OTP to BSEC data. + * otp: OTP number. + * return value: BSEC_OK if no error. +diff --git a/drivers/st/clk/stm32mp1_calib.c b/drivers/st/clk/stm32mp1_calib.c +index 030a84f..14d9d8d 100644 +--- a/drivers/st/clk/stm32mp1_calib.c ++++ b/drivers/st/clk/stm32mp1_calib.c +@@ -16,13 +16,11 @@ + #include + #include + #include ++#include + #include + #include + #include + #include +-#include +-#include +-#include + #include + #include + #include +diff --git a/drivers/st/clk/stm32mp1_clk.c b/drivers/st/clk/stm32mp1_clk.c +index 286234e..e5ffc11 100644 +--- a/drivers/st/clk/stm32mp1_clk.c ++++ b/drivers/st/clk/stm32mp1_clk.c +@@ -16,18 +16,14 @@ + #include + #include + #include ++#include + #include + #include + #include + #include +-#include +-#include +-#include + #include + #include +-#include + #include +-#include + #include + + #define MAX_HSI_HZ 64000000 +@@ -42,6 +38,19 @@ + #define HSIDIV_TIMEOUT TIMEOUT_200MS + #define OSCRDY_TIMEOUT TIMEOUT_1S + ++/* PLL settings computation related definitions */ ++#define POST_DIVM_MIN 8000000 ++#define POST_DIVM_MAX 16000000 ++#define DIVM_MIN 0 ++#define DIVM_MAX 63 ++#define DIVN_MIN 24 ++#define DIVN_MAX 99 ++#define DIVP_MIN 0 ++#define DIVP_MAX 127 ++#define FRAC_MAX 8192 ++#define VCO_MIN 800000000 ++#define VCO_MAX 1600000000 ++ + enum stm32mp1_parent_id { + /* Oscillators are defined in enum stm32mp_osc_id */ + +@@ -204,6 +213,14 @@ struct stm32mp1_clk_pll { + enum stm32mp_osc_id refclk[REFCLK_SIZE]; + }; + ++struct stm32mp1_pll_settings { ++ uint32_t valid_id; ++ uint32_t freq[PLAT_MAX_OPP_NB]; ++ uint32_t volt[PLAT_MAX_OPP_NB]; ++ uint32_t cfg[PLAT_MAX_OPP_NB][PLAT_MAX_PLLCFG_NB]; ++ uint32_t frac[PLAT_MAX_OPP_NB]; ++}; ++ + /* Clocks with selectable source and non set/clr register access */ + #define _CLK_SELEC(off, b, idx, s) \ + { \ +@@ -460,7 +477,6 @@ static const struct stm32mp1_clk_sel stm32mp1_clk_sel[_PARENT_SEL_NB] = { + }; + + /* Define characteristic of PLL according type */ +-#define DIVN_MIN 24 + static const struct stm32mp1_pll stm32mp1_pll[PLL_TYPE_NB] = { + [PLL_800] = { + .refclk_min = 4, +@@ -585,6 +601,8 @@ static unsigned long stm32mp1_osc[NB_OSC]; + static struct spinlock reg_lock; + 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 const struct stm32mp1_clk_gate *gate_ref(unsigned int idx) + { +@@ -1462,11 +1480,8 @@ static int stm32mp1_pll_stop(enum stm32mp1_pll_id pll_id) + return 0; + } + +-static void stm32mp1_pll_config_output(enum stm32mp1_pll_id pll_id, +- uint32_t *pllcfg) ++static uint32_t stm32mp1_pll_compute_pllxcfgr2(uint32_t *pllcfg) + { +- const struct stm32mp1_clk_pll *pll = pll_ref(pll_id); +- uintptr_t rcc_base = stm32mp_rcc_base(); + uint32_t value; + + value = (pllcfg[PLLCFG_P] << RCC_PLLNCFGR2_DIVP_SHIFT) & +@@ -1475,21 +1490,33 @@ static void stm32mp1_pll_config_output(enum stm32mp1_pll_id pll_id, + RCC_PLLNCFGR2_DIVQ_MASK; + value |= (pllcfg[PLLCFG_R] << RCC_PLLNCFGR2_DIVR_SHIFT) & + RCC_PLLNCFGR2_DIVR_MASK; +- mmio_write_32(rcc_base + pll->pllxcfgr2, value); ++ ++ return value; + } + +-static int stm32mp1_pll_config(enum stm32mp1_pll_id pll_id, +- uint32_t *pllcfg, uint32_t fracv) ++static void stm32mp1_pll_config_output(enum stm32mp1_pll_id pll_id, ++ uint32_t *pllcfg) + { + const struct stm32mp1_clk_pll *pll = pll_ref(pll_id); ++ uintptr_t rcc_base = stm32mp_rcc_base(); ++ uint32_t value; ++ ++ value = stm32mp1_pll_compute_pllxcfgr2(pllcfg); ++ ++ mmio_write_32(rcc_base + pll->pllxcfgr2, value); ++} ++ ++static int stm32mp1_pll_compute_pllxcfgr1(const struct stm32mp1_clk_pll *pll, ++ uint32_t *pllcfg, uint32_t *cfgr1) ++{ + uint32_t rcc_base = stm32mp_rcc_base(); + enum stm32mp1_plltype type = pll->plltype; + unsigned long refclk; + uint32_t ifrge = 0; +- uint32_t src, value; ++ uint32_t src; + + src = mmio_read_32(rcc_base + pll->rckxselr) & +- RCC_SELR_REFCLK_SRC_MASK; ++ RCC_SELR_REFCLK_SRC_MASK; + + refclk = stm32mp1_clk_get_fixed(pll->refclk[src]) / + (pllcfg[PLLCFG_M] + 1U); +@@ -1503,23 +1530,39 @@ static int stm32mp1_pll_config(enum stm32mp1_pll_id pll_id, + ifrge = 1U; + } + +- value = (pllcfg[PLLCFG_N] << RCC_PLLNCFGR1_DIVN_SHIFT) & +- RCC_PLLNCFGR1_DIVN_MASK; +- value |= (pllcfg[PLLCFG_M] << RCC_PLLNCFGR1_DIVM_SHIFT) & +- RCC_PLLNCFGR1_DIVM_MASK; +- value |= (ifrge << RCC_PLLNCFGR1_IFRGE_SHIFT) & +- RCC_PLLNCFGR1_IFRGE_MASK; ++ *cfgr1 = (pllcfg[PLLCFG_N] << RCC_PLLNCFGR1_DIVN_SHIFT) & ++ RCC_PLLNCFGR1_DIVN_MASK; ++ *cfgr1 |= (pllcfg[PLLCFG_M] << RCC_PLLNCFGR1_DIVM_SHIFT) & ++ RCC_PLLNCFGR1_DIVM_MASK; ++ *cfgr1 |= (ifrge << RCC_PLLNCFGR1_IFRGE_SHIFT) & ++ RCC_PLLNCFGR1_IFRGE_MASK; ++ ++ return 0; ++} ++ ++static int stm32mp1_pll_config(enum stm32mp1_pll_id pll_id, ++ uint32_t *pllcfg, uint32_t fracv) ++{ ++ const struct stm32mp1_clk_pll *pll = pll_ref(pll_id); ++ uint32_t rcc_base = stm32mp_rcc_base(); ++ uint32_t value; ++ int ret; ++ ++ ret = stm32mp1_pll_compute_pllxcfgr1(pll, pllcfg, &value); ++ if (ret != 0) { ++ return ret; ++ } ++ + mmio_write_32(rcc_base + pll->pllxcfgr1, value); + + /* Fractional configuration */ + value = 0; + mmio_write_32(rcc_base + pll->pllxfracr, value); + ++ /* Frac must be enabled only once its configuration is loaded */ + value = fracv << RCC_PLLNFRACR_FRACV_SHIFT; + mmio_write_32(rcc_base + pll->pllxfracr, value); +- +- value |= RCC_PLLNFRACR_FRACLE; +- mmio_write_32(rcc_base + pll->pllxfracr, value); ++ mmio_setbits_32(rcc_base + pll->pllxfracr, RCC_PLLNFRACR_FRACLE); + + stm32mp1_pll_config_output(pll_id, pllcfg); + +@@ -1684,17 +1727,24 @@ unsigned long stm32mp_clk_timer_get_rate(unsigned long id) + return parent_rate * (timpre + 1) * 2; + } + +-void stm32mp1_stgen_increment(unsigned long long offset_in_ms) ++unsigned long long stm32mp1_stgen_get_counter(void) ++{ ++ uintptr_t stgen = fdt_get_stgen_base(); ++ ++ return (((unsigned long long)mmio_read_32(stgen + CNTCVU_OFF) << 32) | ++ mmio_read_32(stgen + CNTCVL_OFF)); ++} ++ ++void stm32mp1_stgen_restore_counter(unsigned long long value, ++ unsigned long long offset_in_ms) + { + uintptr_t stgen; + unsigned long long cnt; + + stgen = fdt_get_stgen_base(); + +- cnt = ((unsigned long long)mmio_read_32(stgen + CNTCVU_OFF) << 32) | +- mmio_read_32(stgen + CNTCVL_OFF); +- +- cnt += (offset_in_ms * mmio_read_32(stgen + CNTFID_OFF)) / 1000U; ++ cnt = value + ((offset_in_ms * mmio_read_32(stgen + CNTFID_OFF)) / ++ 1000U); + + mmio_clrbits_32(stgen + CNTCR_OFF, CNTCR_EN); + mmio_write_32(stgen + CNTCVL_OFF, (uint32_t)cnt); +@@ -1753,6 +1803,187 @@ static void stm32mp1_pkcs_config(uint32_t pkcs) + mmio_clrsetbits_32(address, mask, value); + } + ++static bool clk_pll1_settings_are_valid(void) ++{ ++ return pll1_settings.valid_id == PLL1_SETTINGS_VALID_ID; ++} ++ ++int stm32mp1_round_opp_khz(uint32_t *freq_khz) ++{ ++ unsigned int i; ++ uint32_t round_opp = 0U; ++ ++ if (!clk_pll1_settings_are_valid()) { ++ /* ++ * No OPP table in DT, or an error occurred during PLL1 ++ * settings computation, system can only work on current ++ * operating point, so return current CPU frequency. ++ */ ++ *freq_khz = current_opp_khz; ++ ++ return 0; ++ } ++ ++ for (i = 0; i < PLAT_MAX_OPP_NB; i++) { ++ if ((pll1_settings.freq[i] <= *freq_khz) && ++ (pll1_settings.freq[i] > round_opp)) { ++ round_opp = pll1_settings.freq[i]; ++ } ++ } ++ ++ *freq_khz = round_opp; ++ ++ return 0; ++} ++ ++/* ++ * Check if PLL1 can be configured on the fly. ++ * @result (-1) => config on the fly is not possible. ++ * (0) => config on the fly is possible. ++ * (+1) => same parameters, no need to reconfigure. ++ * Return value is 0 if no error. ++ */ ++static int stm32mp1_is_pll_config_on_the_fly(enum stm32mp1_pll_id pll_id, ++ uint32_t *pllcfg, uint32_t fracv, ++ int *result) ++{ ++ const struct stm32mp1_clk_pll *pll = pll_ref(pll_id); ++ uintptr_t rcc_base = stm32mp_rcc_base(); ++ uint32_t fracr; ++ uint32_t value; ++ int ret; ++ ++ ret = stm32mp1_pll_compute_pllxcfgr1(pll, pllcfg, &value); ++ if (ret != 0) { ++ return ret; ++ } ++ ++ if (mmio_read_32(rcc_base + pll->pllxcfgr1) != value) { ++ /* Different DIVN/DIVM, can't config on the fly */ ++ *result = -1; ++ return 0; ++ } ++ ++ *result = true; ++ ++ fracr = fracv << RCC_PLLNFRACR_FRACV_SHIFT; ++ fracr |= RCC_PLLNFRACR_FRACLE; ++ value = stm32mp1_pll_compute_pllxcfgr2(pllcfg); ++ ++ if ((mmio_read_32(rcc_base + pll->pllxfracr) == fracr) && ++ (mmio_read_32(rcc_base + pll->pllxcfgr2) == value)) { ++ /* Same parameters, no need to config */ ++ *result = 1; ++ } else { ++ *result = 0; ++ } ++ ++ return 0; ++} ++ ++static int stm32mp1_pll1_config_from_opp_khz(uint32_t freq_khz) ++{ ++ unsigned int i; ++ int ret; ++ int config_on_the_fly = -1; ++ ++ for (i = 0; i < PLAT_MAX_OPP_NB; i++) { ++ if (pll1_settings.freq[i] == freq_khz) { ++ break; ++ } ++ } ++ ++ if (i == PLAT_MAX_OPP_NB) { ++ return -ENXIO; ++ } ++ ++ ret = stm32mp1_is_pll_config_on_the_fly(_PLL1, &pll1_settings.cfg[i][0], ++ pll1_settings.frac[i], ++ &config_on_the_fly); ++ if (ret != 0) { ++ return ret; ++ } ++ ++ if (config_on_the_fly == 1) { ++ /* No need to reconfigure, setup already OK */ ++ return 0; ++ } ++ ++ if (config_on_the_fly == -1) { ++ /* Switch to HSI and stop PLL1 before reconfiguration */ ++ ret = stm32mp1_set_clksrc(CLK_MPU_HSI); ++ if (ret != 0) { ++ return ret; ++ } ++ ++ ret = stm32mp1_pll_stop(_PLL1); ++ if (ret != 0) { ++ return ret; ++ } ++ } ++ ++ ret = stm32mp1_pll_config(_PLL1, &pll1_settings.cfg[i][0], ++ pll1_settings.frac[i]); ++ if (ret != 0) { ++ return ret; ++ } ++ ++ if (config_on_the_fly == -1) { ++ /* Start PLL1 and switch back to after reconfiguration */ ++ stm32mp1_pll_start(_PLL1); ++ ++ ret = stm32mp1_pll_output(_PLL1, ++ pll1_settings.cfg[i][PLLCFG_O]); ++ if (ret != 0) { ++ return ret; ++ } ++ ++ ret = stm32mp1_set_clksrc(CLK_MPU_PLL1P); ++ if (ret != 0) { ++ return ret; ++ } ++ } ++ ++ return 0; ++} ++ ++int stm32mp1_set_opp_khz(uint32_t freq_khz) ++{ ++ if (freq_khz == current_opp_khz) { ++ /* OPP already set, nothing to do */ ++ return 0; ++ } ++ ++ if (!clk_pll1_settings_are_valid()) { ++ /* ++ * No OPP table in DT or an error occurred during PLL1 ++ * settings computation, system can only work on current ++ * operating point so return error. ++ */ ++ return -EACCES; ++ } ++ ++ /* Check that PLL1 (without MPUDIV) is MPU clock source */ ++ if (((mmio_read_32(stm32mp_rcc_base() + RCC_MPCKSELR) & ++ RCC_SELR_SRC_MASK)) != RCC_MPCKSELR_PLL) { ++ return -EPERM; ++ } ++ ++ if (stm32mp1_pll1_config_from_opp_khz(freq_khz) != 0) { ++ /* Restore original value */ ++ if (stm32mp1_pll1_config_from_opp_khz(current_opp_khz) != 0) { ++ ERROR("No CPU operating point can be set\n"); ++ panic(); ++ } ++ ++ return -EIO; ++ } ++ ++ current_opp_khz = freq_khz; ++ ++ return 0; ++} ++ + #if defined(IMAGE_BL32) + void stm32mp1_clk_mpu_suspend(void) + { +@@ -1779,15 +2010,349 @@ void stm32mp1_clk_mpu_resume(void) + } + #endif + +-int stm32mp1_clk_init(void) ++static int clk_get_pll_settings_from_dt(int plloff, unsigned int *pllcfg, ++ uint32_t *fracv, uint32_t *csg, ++ bool *csg_set) ++{ ++ int ret; ++ ++ ret = fdt_read_uint32_array(plloff, "cfg", pllcfg, (uint32_t)PLLCFG_NB); ++ if (ret < 0) { ++ return -FDT_ERR_NOTFOUND; ++ } ++ ++ *fracv = fdt_read_uint32_default(plloff, "frac", 0); ++ ++ ret = fdt_read_uint32_array(plloff, "csg", csg, (uint32_t)PLLCSG_NB); ++ ++ *csg_set = (ret == 0); ++ ++ if (ret == -FDT_ERR_NOTFOUND) { ++ ret = 0; ++ } ++ ++ return ret; ++} ++ ++static int clk_compute_pll1_settings(unsigned long input_freq, ++ uint32_t freq_khz, ++ uint32_t *pllcfg, uint32_t *fracv) ++{ ++ unsigned long post_divm; ++ unsigned long long output_freq = freq_khz * 1000U; ++ unsigned long long freq; ++ unsigned long long vco; ++ int divm; ++ int divn; ++ int divp; ++ int frac; ++ int i; ++ unsigned int diff; ++ unsigned int best_diff = UINT_MAX; ++ ++ /* Following parameters have always the same value */ ++ pllcfg[PLLCFG_Q] = 0; ++ pllcfg[PLLCFG_R] = 0; ++ pllcfg[PLLCFG_O] = PQR(1, 0, 0); ++ ++ for (divm = DIVM_MAX; divm >= DIVM_MIN; divm--) { ++ post_divm = input_freq / (unsigned long)(divm + 1); ++ ++ if ((post_divm < POST_DIVM_MIN) || ++ (post_divm > POST_DIVM_MAX)) { ++ continue; ++ } ++ ++ for (divp = DIVP_MIN; divp <= DIVP_MAX; divp++) { ++ ++ freq = output_freq * (divm + 1) * (divp + 1); ++ ++ divn = (int)((freq / input_freq) - 1); ++ if ((divn < DIVN_MIN) || (divn > DIVN_MAX)) { ++ continue; ++ } ++ ++ frac = (int)(((freq * FRAC_MAX) / input_freq) - ++ ((divn + 1) * FRAC_MAX)); ++ ++ /* 2 loops to refine the fractional part */ ++ for (i = 2; i != 0; i--) { ++ if (frac > FRAC_MAX) { ++ break; ++ } ++ ++ vco = (post_divm * (divn + 1)) + ++ ((post_divm * (unsigned long long)frac) / ++ FRAC_MAX); ++ ++ if ((vco < (VCO_MIN / 2)) || ++ (vco > (VCO_MAX / 2))) { ++ frac++; ++ continue; ++ } ++ ++ freq = vco / (divp + 1); ++ if (output_freq < freq) { ++ diff = (unsigned int)(freq - ++ output_freq); ++ } else { ++ diff = (unsigned int)(output_freq - ++ freq); ++ } ++ ++ if (diff < best_diff) { ++ pllcfg[PLLCFG_M] = divm; ++ pllcfg[PLLCFG_N] = divn; ++ pllcfg[PLLCFG_P] = divp; ++ *fracv = frac; ++ ++ if (diff == 0) { ++ return 0; ++ } ++ ++ best_diff = diff; ++ } ++ ++ frac++; ++ } ++ } ++ } ++ ++ if (best_diff == UINT_MAX) { ++ return -1; ++ } ++ ++ return 0; ++} ++ ++static int clk_get_pll1_settings(uint32_t clksrc, uint32_t freq_khz, ++ uint32_t *pllcfg, uint32_t *fracv) ++{ ++ unsigned long input_freq; ++ unsigned int i; ++ ++ assert(pllcfg != NULL); ++ assert(fracv != NULL); ++ ++ for (i = 0; i < PLAT_MAX_OPP_NB; i++) { ++ if (pll1_settings.freq[i] == freq_khz) { ++ break; ++ } ++ } ++ ++ if (((i == PLAT_MAX_OPP_NB) && (pll1_settings.valid_id == 0U)) || ++ ((i < PLAT_MAX_OPP_NB) && ++ (pll1_settings.cfg[i][PLLCFG_O] == 0U))) { ++ /* ++ * Either PLL1 settings structure is completely empty, ++ * or this frequency is not yet filled: compute settings. ++ */ ++ switch (clksrc) { ++ case CLK_PLL12_HSI: ++ input_freq = stm32mp_clk_get_rate(CK_HSI); ++ break; ++ case CLK_PLL12_HSE: ++ input_freq = stm32mp_clk_get_rate(CK_HSE); ++ break; ++ default: ++ panic(); ++ } ++ ++ return clk_compute_pll1_settings(input_freq, freq_khz, pllcfg, ++ fracv); ++ } ++ ++ if ((i < PLAT_MAX_OPP_NB) && ++ (pll1_settings.cfg[i][PLLCFG_O] != 0U)) { ++ /* ++ * Index is in range and PLL1 settings line is filled, ++ * use content to answer to the request. ++ */ ++ memcpy(pllcfg, &pll1_settings.cfg[i][0], ++ sizeof(uint32_t) * PLAT_MAX_PLLCFG_NB); ++ *fracv = pll1_settings.frac[i]; ++ ++ return 0; ++ } ++ ++ return -1; ++} ++ ++int stm32mp1_clk_get_maxfreq_opp(uint32_t *freq_khz, ++ uint32_t *voltage_mv) ++{ ++ unsigned int i; ++ uint32_t freq = 0U; ++ uint32_t voltage = 0U; ++ ++ assert(freq_khz != NULL); ++ assert(voltage_mv != NULL); ++ ++ if (!clk_pll1_settings_are_valid()) { ++ return -1; ++ } ++ ++ for (i = 0; i < PLAT_MAX_OPP_NB; i++) { ++ if (pll1_settings.freq[i] > freq) { ++ freq = pll1_settings.freq[i]; ++ voltage = pll1_settings.volt[i]; ++ } ++ } ++ ++ if ((freq == 0U) || (voltage == 0U)) { ++ return -1; ++ } ++ ++ *freq_khz = freq; ++ *voltage_mv = voltage; ++ ++ return 0; ++} ++ ++static int clk_save_current_pll1_settings(uint32_t buck1_voltage) ++{ ++ const struct stm32mp1_clk_pll *pll = pll_ref(_PLL1); ++ uint32_t rcc_base = stm32mp_rcc_base(); ++ uint32_t freq; ++ unsigned int i; ++ ++ freq = udiv_round_nearest(stm32mp_clk_get_rate(CK_MPU), 1000L); ++ ++ for (i = 0; i < PLAT_MAX_OPP_NB; i++) { ++ if (pll1_settings.freq[i] == freq) { ++ break; ++ } ++ } ++ ++ if ((i == PLAT_MAX_OPP_NB) || ++ ((pll1_settings.volt[i] != buck1_voltage) && ++ (buck1_voltage != 0U))) { ++ return -1; ++ } ++ ++ pll1_settings.cfg[i][PLLCFG_M] = ++ (mmio_read_32(rcc_base + pll->pllxcfgr1) & ++ RCC_PLLNCFGR1_DIVM_MASK) >> RCC_PLLNCFGR1_DIVM_SHIFT; ++ ++ pll1_settings.cfg[i][PLLCFG_N] = ++ (mmio_read_32(rcc_base + pll->pllxcfgr1) & ++ RCC_PLLNCFGR1_DIVN_MASK) >> RCC_PLLNCFGR1_DIVN_SHIFT; ++ ++ pll1_settings.cfg[i][PLLCFG_P] = ++ (mmio_read_32(rcc_base + pll->pllxcfgr2) & ++ RCC_PLLNCFGR2_DIVP_MASK) >> RCC_PLLNCFGR2_DIVP_SHIFT; ++ ++ pll1_settings.cfg[i][PLLCFG_Q] = ++ (mmio_read_32(rcc_base + pll->pllxcfgr2) & ++ RCC_PLLNCFGR2_DIVQ_MASK) >> RCC_PLLNCFGR2_DIVQ_SHIFT; ++ ++ pll1_settings.cfg[i][PLLCFG_R] = ++ (mmio_read_32(rcc_base + pll->pllxcfgr2) & ++ RCC_PLLNCFGR2_DIVR_MASK) >> RCC_PLLNCFGR2_DIVR_SHIFT; ++ ++ pll1_settings.cfg[i][PLLCFG_O] = ++ mmio_read_32(rcc_base + pll->pllxcr) >> ++ RCC_PLLNCR_DIVEN_SHIFT; ++ ++ pll1_settings.frac[i] = ++ (mmio_read_32(rcc_base + pll->pllxfracr) & ++ RCC_PLLNFRACR_FRACV_MASK) >> RCC_PLLNFRACR_FRACV_SHIFT; ++ ++ return i; ++} ++ ++static uint32_t stm32mp1_clk_get_pll1_current_clksrc(void) + { ++ uint32_t value; ++ const struct stm32mp1_clk_pll *pll = pll_ref(_PLL1); + uint32_t rcc_base = stm32mp_rcc_base(); ++ ++ value = mmio_read_32(rcc_base + pll->rckxselr); ++ ++ switch (value & RCC_SELR_REFCLK_SRC_MASK) { ++ case 0: ++ return CLK_PLL12_HSI; ++ case 1: ++ return CLK_PLL12_HSE; ++ default: ++ panic(); ++ } ++} ++ ++int stm32mp1_clk_compute_all_pll1_settings(uint32_t buck1_voltage) ++{ ++ int i; ++ int ret; ++ int index; ++ uint32_t count = PLAT_MAX_OPP_NB; ++ uint32_t clksrc; ++ ++ ret = dt_get_all_opp_freqvolt(&count, pll1_settings.freq, ++ pll1_settings.volt); ++ switch (ret) { ++ case 0: ++ break; ++ case -FDT_ERR_NOTFOUND: ++ VERBOSE("Cannot find OPP table in DT, use default settings.\n"); ++ return 0; ++ default: ++ ERROR("Inconsistent OPP settings found in DT, ignored.\n"); ++ return 0; ++ } ++ ++ index = clk_save_current_pll1_settings(buck1_voltage); ++ ++ clksrc = stm32mp1_clk_get_pll1_current_clksrc(); ++ ++ for (i = 0; i < (int)count; i++) { ++ if (i == index) { ++ continue; ++ } ++ ++ ret = clk_get_pll1_settings(clksrc, pll1_settings.freq[i], ++ &pll1_settings.cfg[i][0], ++ &pll1_settings.frac[i]); ++ if (ret != 0) { ++ return ret; ++ } ++ } ++ ++ pll1_settings.valid_id = PLL1_SETTINGS_VALID_ID; ++ ++ return 0; ++} ++ ++void stm32mp1_clk_lp_save_opp_pll1_settings(uint8_t *data, size_t size) ++{ ++ if ((size != sizeof(pll1_settings)) || !clk_pll1_settings_are_valid()) { ++ panic(); ++ } ++ ++ memcpy(data, &pll1_settings, size); ++} ++ ++void stm32mp1_clk_lp_load_opp_pll1_settings(uint8_t *data, size_t size) ++{ ++ if (size != sizeof(pll1_settings)) { ++ panic(); ++ } ++ ++ memcpy(&pll1_settings, data, size); ++} ++ ++int stm32mp1_clk_init(uint32_t pll1_freq_khz) ++{ ++ uint32_t rcc_base = stm32mp_rcc_base(); ++ uint32_t pllfracv[_PLL_NB]; ++ uint32_t pllcsg[_PLL_NB][PLLCSG_NB]; + unsigned int clksrc[CLKSRC_NB]; + unsigned int clkdiv[CLKDIV_NB]; + unsigned int pllcfg[_PLL_NB][PLLCFG_NB]; + int plloff[_PLL_NB]; + int ret, len; + enum stm32mp1_pll_id i; ++ bool pllcsg_set[_PLL_NB]; ++ bool pllcfg_valid[_PLL_NB]; + bool lse_css = false; + bool pll3_preserve = false; + bool pll4_preserve = false; +@@ -1819,14 +2384,27 @@ int stm32mp1_clk_init(void) + snprintf(name, sizeof(name), "st,pll@%d", i); + plloff[i] = fdt_rcc_subnode_offset(name); + +- if (!fdt_check_node(plloff[i])) { ++ pllcfg_valid[i] = fdt_check_node(plloff[i]); ++ if (pllcfg_valid[i]) { ++ ret = clk_get_pll_settings_from_dt(plloff[i], pllcfg[i], ++ &pllfracv[i], pllcsg[i], ++ &pllcsg_set[i]); ++ if (ret != 0) { ++ return ret; ++ } ++ + continue; + } + +- ret = fdt_read_uint32_array(plloff[i], "cfg", +- pllcfg[i], (int)PLLCFG_NB); +- if (ret < 0) { +- return -FDT_ERR_NOTFOUND; ++ if ((i == _PLL1) && (pll1_freq_khz != 0U)) { ++ ret = clk_get_pll1_settings(clksrc[CLKSRC_PLL12], ++ pll1_freq_khz, ++ pllcfg[i], &pllfracv[i]); ++ if (ret != 0) { ++ return ret; ++ } ++ ++ pllcfg_valid[i] = true; + } + } + +@@ -1977,15 +2555,12 @@ int stm32mp1_clk_init(void) + + /* Configure and start PLLs */ + for (i = (enum stm32mp1_pll_id)0; i < _PLL_NB; i++) { +- uint32_t fracv; +- uint32_t csg[PLLCSG_NB]; +- + if (((i == _PLL3) && pll3_preserve) || + ((i == _PLL4) && pll4_preserve && !pll4_bootrom)) { + continue; + } + +- if (!fdt_check_node(plloff[i])) { ++ if (!pllcfg_valid[i]) { + continue; + } + +@@ -1995,25 +2570,20 @@ int stm32mp1_clk_init(void) + continue; + } + +- fracv = fdt_read_uint32_default(plloff[i], "frac", 0); +- +- ret = stm32mp1_pll_config(i, pllcfg[i], fracv); ++ ret = stm32mp1_pll_config(i, pllcfg[i], pllfracv[i]); + if (ret != 0) { + return ret; + } +- ret = fdt_read_uint32_array(plloff[i], "csg", csg, +- (uint32_t)PLLCSG_NB); +- if (ret == 0) { +- stm32mp1_pll_csg(i, csg); +- } else if (ret != -FDT_ERR_NOTFOUND) { +- return ret; ++ ++ if (pllcsg_set[i]) { ++ stm32mp1_pll_csg(i, pllcsg[i]); + } + + stm32mp1_pll_start(i); + } + /* Wait and start PLLs ouptut when ready */ + for (i = (enum stm32mp1_pll_id)0; i < _PLL_NB; i++) { +- if (!fdt_check_node(plloff[i])) { ++ if (!pllcfg_valid[i]) { + continue; + } + +@@ -2425,9 +2995,21 @@ static void sync_earlyboot_clocks_state(void) + + int stm32mp1_clk_probe(void) + { ++ unsigned long freq_khz; ++ ++ assert(PLLCFG_NB == PLAT_MAX_PLLCFG_NB); ++ + stm32mp1_osc_init(); + + sync_earlyboot_clocks_state(); + ++ /* Save current CPU operating point value */ ++ freq_khz = udiv_round_nearest(stm32mp_clk_get_rate(CK_MPU), 1000UL); ++ if (freq_khz > (unsigned long)UINT32_MAX) { ++ panic(); ++ } ++ ++ current_opp_khz = (uint32_t)freq_khz; ++ + return 0; + } +diff --git a/drivers/st/clk/stm32mp1_clkfunc.c b/drivers/st/clk/stm32mp1_clkfunc.c +index 99a7360..1777a24 100644 +--- a/drivers/st/clk/stm32mp1_clkfunc.c ++++ b/drivers/st/clk/stm32mp1_clkfunc.c +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 2017-2018, STMicroelectronics - All Rights Reserved ++ * Copyright (c) 2017-2019, STMicroelectronics - All Rights Reserved + * + * SPDX-License-Identifier: BSD-3-Clause + */ +@@ -10,8 +10,6 @@ + #include + #include + #include +-#include +-#include + #include + #include + +@@ -56,6 +54,10 @@ int fdt_osc_read_freq(const char *name, uint32_t *freq) + if (strncmp(cchar, name, (size_t)ret) == 0) { + const fdt32_t *cuint; + ++ if (fdt_get_status(subnode) == DT_DISABLED) { ++ goto exit; ++ } ++ + cuint = fdt_getprop(fdt, subnode, "clock-frequency", + &ret); + if (cuint == NULL) { +@@ -68,7 +70,8 @@ int fdt_osc_read_freq(const char *name, uint32_t *freq) + } + } + +- /* Oscillator not found, freq=0 */ ++exit: ++ /* Oscillator not found or disabled, freq=0 */ + *freq = 0; + return 0; + } +@@ -170,11 +173,11 @@ uint32_t fdt_osc_read_uint32_default(enum stm32mp_osc_id osc_id, + ******************************************************************************/ + int fdt_rcc_enable_it(const char *name) + { +- void *fdt; ++ int node = fdt_get_rcc_node(); + +- if (fdt_get_address(&fdt) == 0) { +- return -ENOENT; ++ if (node < 0) { ++ return -ENODEV; + } + +- return stm32_gic_enable_spi(fdt_get_rcc_node(fdt), name); ++ return stm32_gic_enable_spi(node, name); + } +diff --git a/drivers/st/clk/stm32mp_clkfunc.c b/drivers/st/clk/stm32mp_clkfunc.c +index 5c7e202..a8ae62e 100644 +--- a/drivers/st/clk/stm32mp_clkfunc.c ++++ b/drivers/st/clk/stm32mp_clkfunc.c +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 2017-2018, STMicroelectronics - All Rights Reserved ++ * Copyright (c) 2017-2019, STMicroelectronics - All Rights Reserved + * + * SPDX-License-Identifier: BSD-3-Clause + */ +@@ -9,8 +9,6 @@ + #include + #include + #include +-#include +-#include + + #define DT_STGEN_COMPAT "st,stm32-stgen" + #define DT_UART_COMPAT "st,stm32h7-uart" +@@ -18,37 +16,9 @@ + /******************************************************************************* + * This function returns the RCC node in the device tree. + ******************************************************************************/ +-int fdt_get_rcc_node(void *fdt) ++int fdt_get_rcc_node(void) + { +- return fdt_node_offset_by_compatible(fdt, -1, DT_RCC_CLK_COMPAT); +-} +- +-/******************************************************************************* +- * This function reads the rcc base address. +- * It reads the value indicated inside the device tree. +- * Returns address on success, and 0 on failure. +- ******************************************************************************/ +-uint32_t fdt_rcc_read_addr(void) +-{ +- int node; +- void *fdt; +- const fdt32_t *cuint; +- +- if (fdt_get_address(&fdt) == 0) { +- return 0; +- } +- +- node = fdt_get_rcc_node(fdt); +- if (node < 0) { +- return 0; +- } +- +- cuint = fdt_getprop(fdt, node, "reg", NULL); +- if (cuint == NULL) { +- return 0; +- } +- +- return fdt32_to_cpu(*cuint); ++ return dt_get_node_by_compatible(DT_RCC_CLK_COMPAT); + } + + /******************************************************************************* +@@ -62,13 +32,8 @@ int fdt_rcc_read_uint32_array(const char *prop_name, + uint32_t *array, uint32_t count) + { + int node; +- void *fdt; +- +- if (fdt_get_address(&fdt) == 0) { +- return -ENOENT; +- } + +- node = fdt_get_rcc_node(fdt); ++ node = fdt_get_rcc_node(); + if (node < 0) { + return -FDT_ERR_NOTFOUND; + } +@@ -85,13 +50,8 @@ int fdt_rcc_read_uint32_array(const char *prop_name, + uint32_t fdt_rcc_read_uint32_default(const char *prop_name, uint32_t dflt_value) + { + int node; +- void *fdt; +- +- if (fdt_get_address(&fdt) == 0) { +- return dflt_value; +- } + +- node = fdt_node_offset_by_compatible(fdt, -1, DT_RCC_CLK_COMPAT); ++ node = fdt_get_rcc_node(); + if (node < 0) { + return dflt_value; + } +@@ -113,7 +73,7 @@ int fdt_rcc_subnode_offset(const char *name) + return -ENOENT; + } + +- node = fdt_get_rcc_node(fdt); ++ node = fdt_get_rcc_node(); + if (node < 0) { + return -FDT_ERR_NOTFOUND; + } +@@ -142,7 +102,7 @@ const fdt32_t *fdt_rcc_read_prop(const char *prop_name, int *lenp) + return NULL; + } + +- node = fdt_get_rcc_node(fdt); ++ node = fdt_get_rcc_node(); + if (node < 0) { + return NULL; + } +@@ -164,13 +124,8 @@ const fdt32_t *fdt_rcc_read_prop(const char *prop_name, int *lenp) + bool fdt_get_rcc_secure_status(void) + { + int node; +- void *fdt; +- +- if (fdt_get_address(&fdt) == 0) { +- return false; +- } + +- node = fdt_get_rcc_node(fdt); ++ node = fdt_get_rcc_node(); + if (node < 0) { + return false; + } +@@ -185,25 +140,7 @@ bool fdt_get_rcc_secure_status(void) + ******************************************************************************/ + uintptr_t fdt_get_stgen_base(void) + { +- int node; +- const fdt32_t *cuint; +- void *fdt; +- +- if (fdt_get_address(&fdt) == 0) { +- return 0; +- } +- +- node = fdt_node_offset_by_compatible(fdt, -1, DT_STGEN_COMPAT); +- if (node < 0) { +- return 0; +- } +- +- cuint = fdt_getprop(fdt, node, "reg", NULL); +- if (cuint == NULL) { +- return 0; +- } +- +- return fdt32_to_cpu(*cuint); ++ return dt_get_peripheral_base(DT_STGEN_COMPAT); + } + + /******************************************************************************* +@@ -273,35 +210,31 @@ unsigned long fdt_get_uart_clock_freq(uintptr_t instance) + { + int node; + void *fdt; ++ unsigned long clk_id; + + if (fdt_get_address(&fdt) == 0) { + return 0; + } + + /* Check for UART nodes */ +- node = fdt_node_offset_by_compatible(fdt, -1, DT_UART_COMPAT); +- while (node != -FDT_ERR_NOTFOUND) { +- const fdt32_t *cuint; +- +- cuint = fdt_getprop(fdt, node, "reg", NULL); +- if (cuint == NULL) +- goto next; +- +- if ((uintptr_t)fdt32_to_cpu(*cuint) == instance) { +- unsigned long clk_id; +- +- cuint = fdt_getprop(fdt, node, "clocks", NULL); +- if (cuint == NULL) +- goto next; +- +- cuint++; +- clk_id = (unsigned long)(fdt32_to_cpu(*cuint)); ++ node = dt_match_instance_by_compatible(DT_UART_COMPAT, instance); ++ if (node < 0) { ++ return 0UL; ++ } + +- return stm32mp_clk_get_rate(clk_id); +- } +-next: +- node = fdt_node_offset_by_compatible(fdt, node, DT_UART_COMPAT); ++ clk_id = fdt_get_clock_id(node); ++ if (clk_id < 0) { ++ return 0UL; + } + +- return 0; ++ return stm32mp_clk_get_rate(clk_id); ++} ++ ++/******************************************************************************* ++ * This function checks if PLL1 hard-coded settings have been defined in DT. ++ * Returns true if PLL1 node is found and enabled, false if not. ++ ******************************************************************************/ ++bool fdt_is_pll1_predefined(void) ++{ ++ return fdt_check_node(fdt_rcc_subnode_offset(DT_PLL1_NODE_NAME)); + } +diff --git a/drivers/st/ddr/stm32mp1_ddr.c b/drivers/st/ddr/stm32mp1_ddr.c +index 00ebb22..1be2c23 100644 +--- a/drivers/st/ddr/stm32mp1_ddr.c ++++ b/drivers/st/ddr/stm32mp1_ddr.c +@@ -1,5 +1,5 @@ + /* +- * Copyright (C) 2018, STMicroelectronics - All Rights Reserved ++ * Copyright (C) 2018-2019, STMicroelectronics - All Rights Reserved + * + * SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause + */ +@@ -13,8 +13,6 @@ + #include + #include + #include +-#include +-#include + #include + + struct reg_desc { +@@ -652,7 +650,8 @@ static void stm32mp1_refresh_disable(struct stm32mp1_ddrctl *ctl) + /* Quasi-dynamic register update*/ + mmio_setbits_32((uintptr_t)&ctl->rfshctl3, + DDRCTRL_RFSHCTL3_DIS_AUTO_REFRESH); +- mmio_clrbits_32((uintptr_t)&ctl->pwrctl, DDRCTRL_PWRCTL_POWERDOWN_EN); ++ mmio_clrbits_32((uintptr_t)&ctl->pwrctl, DDRCTRL_PWRCTL_POWERDOWN_EN | ++ DDRCTRL_PWRCTL_SELFREF_EN); + mmio_clrbits_32((uintptr_t)&ctl->dfimisc, + DDRCTRL_DFIMISC_DFI_INIT_COMPLETE_EN); + stm32mp1_wait_sw_done_ack(ctl); +@@ -670,6 +669,10 @@ static void stm32mp1_refresh_restore(struct stm32mp1_ddrctl *ctl, + mmio_setbits_32((uintptr_t)&ctl->pwrctl, + DDRCTRL_PWRCTL_POWERDOWN_EN); + } ++ if ((pwrctl & DDRCTRL_PWRCTL_SELFREF_EN) != 0U) { ++ mmio_setbits_32((uintptr_t)&ctl->pwrctl, ++ DDRCTRL_PWRCTL_SELFREF_EN); ++ } + mmio_setbits_32((uintptr_t)&ctl->dfimisc, + DDRCTRL_DFIMISC_DFI_INIT_COMPLETE_EN); + stm32mp1_wait_sw_done_ack(ctl); +diff --git a/drivers/st/ddr/stm32mp1_ddr_helpers.c b/drivers/st/ddr/stm32mp1_ddr_helpers.c +index 63f254f..8f9d07b 100644 +--- a/drivers/st/ddr/stm32mp1_ddr_helpers.c ++++ b/drivers/st/ddr/stm32mp1_ddr_helpers.c +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 2017-2018, STMicroelectronics - All Rights Reserved ++ * Copyright (c) 2017-2019, STMicroelectronics - All Rights Reserved + * + * SPDX-License-Identifier: BSD-3-Clause + */ +@@ -10,7 +10,6 @@ + #include + #include + #include +-#include + + #define TIMEOUT_500US us2tick(500) + +@@ -127,6 +126,9 @@ static int ddr_sw_self_refresh_in(void) + DDRPHYC_ACIOCR_CSPDD_MASK, + DDRPHYC_ACIOCR_CSPDD_0); + ++ /* Disable command/address output driver */ ++ mmio_clrbits_32(ddrphyc_base + DDRPHYC_ACIOCR, DDRPHYC_ACIOCR_ACOE); ++ + mmio_setbits_32(ddrphyc_base + DDRPHYC_DXCCR, DDRPHYC_DXCCR_DXPDD); + + mmio_setbits_32(ddrphyc_base + DDRPHYC_DXCCR, DDRPHYC_DXCCR_DXPDR); +@@ -144,6 +146,12 @@ static int ddr_sw_self_refresh_in(void) + /* Disable PZQ cell (PUBL register) */ + mmio_setbits_32(ddrphyc_base + DDRPHYC_ZQ0CR0, DDRPHYC_ZQ0CRN_ZQPD); + ++ /* Set latch */ ++ mmio_clrbits_32(ddrphyc_base + DDRPHYC_DSGCR, DDRPHYC_DSGCR_CKOE); ++ ++ /* Additional delay to avoid early latch */ ++ udelay(10); ++ + /* Activate sw retention in PWRCTRL */ + pwr_regs_lock(); + mmio_setbits_32(pwr_base + PWR_CR3, PWR_CR3_DDRRETEN); +@@ -293,6 +301,9 @@ int ddr_sw_self_refresh_exit(void) + /* Enable pad drivers */ + mmio_clrbits_32(ddrphyc_base + DDRPHYC_ACIOCR, DDRPHYC_ACIOCR_ACPDD); + ++ /* Enable command/address output driver */ ++ mmio_setbits_32(ddrphyc_base + DDRPHYC_ACIOCR, DDRPHYC_ACIOCR_ACOE); ++ + mmio_clrbits_32(ddrphyc_base + DDRPHYC_ACIOCR, + DDRPHYC_ACIOCR_CKPDD_MASK); + +@@ -303,6 +314,9 @@ int ddr_sw_self_refresh_exit(void) + + mmio_clrbits_32(ddrphyc_base + DDRPHYC_DXCCR, DDRPHYC_DXCCR_DXPDR); + ++ /* Release latch */ ++ mmio_setbits_32(ddrphyc_base + DDRPHYC_DSGCR, DDRPHYC_DSGCR_CKOE); ++ + mmio_clrbits_32(ddrphyc_base + DDRPHYC_DSGCR, + DDRPHYC_DSGCR_ODTPDD_MASK); + +@@ -369,6 +383,10 @@ void ddr_sr_mode_ssr(void) + uintptr_t rcc_ddritfcr = stm32mp_rcc_base() + RCC_DDRITFCR; + uintptr_t ddrctrl_base = stm32mp_ddrctrl_base(); + ++ if (!stm32mp_ddr_supports_ssr_asr()) { ++ return; ++ } ++ + stm32mp1_clk_rcc_regs_lock(); + + mmio_setbits_32(rcc_ddritfcr, RCC_DDRITFCR_DDRC1LPEN); +@@ -421,6 +439,10 @@ void ddr_sr_mode_asr(void) + uintptr_t rcc_ddritfcr = stm32mp_rcc_base() + RCC_DDRITFCR; + uintptr_t ddrctrl_base = stm32mp_ddrctrl_base(); + ++ if (!stm32mp_ddr_supports_ssr_asr()) { ++ return; ++ } ++ + stm32mp1_clk_rcc_regs_lock(); + + mmio_setbits_32(rcc_ddritfcr, RCC_DDRITFCR_AXIDCGEN); +diff --git a/drivers/st/ddr/stm32mp1_ram.c b/drivers/st/ddr/stm32mp1_ram.c +index 773c9f7..ef35a06 100644 +--- a/drivers/st/ddr/stm32mp1_ram.c ++++ b/drivers/st/ddr/stm32mp1_ram.c +@@ -1,18 +1,15 @@ + /* +- * Copyright (C) 2018, STMicroelectronics - All Rights Reserved ++ * Copyright (C) 2018-2020, STMicroelectronics - All Rights Reserved + * + * SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause + */ + + #include +-#include + #include + #include + #include + #include + #include +-#include +-#include + + #define DDR_PATTERN 0xAAAAAAAAU + #define DDR_ANTIPATTERN 0x55555555U +@@ -220,9 +217,8 @@ static int stm32mp1_ddr_setup(void) + return -ENOENT; + } + +- node = fdt_node_offset_by_compatible(fdt, -1, DT_DDR_COMPAT); ++ node = dt_get_node_by_compatible(DT_DDR_COMPAT); + if (node < 0) { +- ERROR("%s: Cannot read DDR node in DT\n", __func__); + return -EINVAL; + } + +@@ -291,11 +287,6 @@ static int stm32mp1_ddr_setup(void) + VERBOSE("%s : ram size(%x, %x)\n", __func__, + (uint32_t)priv->info.base, (uint32_t)priv->info.size); + +-#ifndef DCACHE_OFF +- write_sctlr(read_sctlr() & ~SCTLR_C_BIT); +- dcsw_op_all(DC_OP_CISW); +-#endif +- + if (config.self_refresh) { + uret = ddr_test_rw_access(); + if (uret != 0U) { +@@ -329,9 +320,8 @@ static int stm32mp1_ddr_setup(void) + } + } + +-#ifndef DCACHE_OFF +- write_sctlr(read_sctlr() | SCTLR_C_BIT); +-#endif ++ /* Switch to Automatic Self-Refresh */ ++ ddr_sr_mode_asr(); + + return 0; + } +diff --git a/drivers/st/etzpc/etzpc.c b/drivers/st/etzpc/etzpc.c +index 06c3282..f2ddd75 100644 +--- a/drivers/st/etzpc/etzpc.c ++++ b/drivers/st/etzpc/etzpc.c +@@ -1,6 +1,6 @@ + /* +- * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved. +- * Copyright (c) 2017-2018, STMicroelectronics ++ * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved. ++ * Copyright (c) 2017-2019, STMicroelectronics - All Rights Reserved + * + * SPDX-License-Identifier: BSD-3-Clause + */ +@@ -15,8 +15,6 @@ + #include + #include + #include +-#include +-#include + #include + + /* Device Tree related definitions */ +diff --git a/drivers/st/gpio/stm32_gpio.c b/drivers/st/gpio/stm32_gpio.c +index fc0dce8..8c23c5b 100644 +--- a/drivers/st/gpio/stm32_gpio.c ++++ b/drivers/st/gpio/stm32_gpio.c +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 2016-2018, STMicroelectronics - All Rights Reserved ++ * Copyright (c) 2016-2019, STMicroelectronics - All Rights Reserved + * + * SPDX-License-Identifier: BSD-3-Clause + */ +@@ -14,8 +14,6 @@ + #include + #include + #include +-#include +-#include + + #define DT_GPIO_BANK_SHIFT 12 + #define DT_GPIO_BANK_MASK 0x1F000U +@@ -165,7 +163,7 @@ int dt_set_pinctrl_config(int node) + void *fdt; + + if (fdt_get_address(&fdt) == 0) { +- return -ENOENT; ++ return -FDT_ERR_NOTFOUND; + } + + if (status == DT_DISABLED) { +diff --git a/drivers/st/i2c/stm32_i2c.c b/drivers/st/i2c/stm32_i2c.c +index ce609ba..f57bf5a 100644 +--- a/drivers/st/i2c/stm32_i2c.c ++++ b/drivers/st/i2c/stm32_i2c.c +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 2016-2018, STMicroelectronics - All Rights Reserved ++ * Copyright (c) 2016-2019, STMicroelectronics - All Rights Reserved + * + * SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause + */ +@@ -15,7 +15,6 @@ + #include + #include + #include +-#include + #include + + /* STM32 I2C registers offsets */ +@@ -40,8 +39,6 @@ + /* + * struct i2c_spec_s - Private I2C timing specifications. + * @rate: I2C bus speed (Hz) +- * @rate_min: 80% of I2C bus speed (Hz) +- * @rate_max: 120% of I2C bus speed (Hz) + * @fall_max: Max fall time of both SDA and SCL signals (ns) + * @rise_max: Max rise time of both SDA and SCL signals (ns) + * @hddat_min: Min data hold time (ns) +@@ -52,8 +49,6 @@ + */ + struct i2c_spec_s { + uint32_t rate; +- uint32_t rate_min; +- uint32_t rate_max; + uint32_t fall_max; + uint32_t rise_max; + uint32_t hddat_min; +@@ -87,10 +82,9 @@ struct i2c_timing_s { + * [1] https://www.i2c-bus.org/specification/ + */ + static const struct i2c_spec_s i2c_specs[] = { +- [I2C_SPEED_STANDARD] = { ++ /* Standard - 100KHz */ ++ { + .rate = STANDARD_RATE, +- .rate_min = (STANDARD_RATE * 80) / 100, +- .rate_max = (STANDARD_RATE * 120) / 100, + .fall_max = 300, + .rise_max = 1000, + .hddat_min = 0, +@@ -99,10 +93,9 @@ static const struct i2c_spec_s i2c_specs[] = { + .l_min = 4700, + .h_min = 4000, + }, +- [I2C_SPEED_FAST] = { ++ /* Fast - 400KHz */ ++ { + .rate = FAST_RATE, +- .rate_min = (FAST_RATE * 80) / 100, +- .rate_max = (FAST_RATE * 120) / 100, + .fall_max = 300, + .rise_max = 300, + .hddat_min = 0, +@@ -111,10 +104,9 @@ static const struct i2c_spec_s i2c_specs[] = { + .l_min = 1300, + .h_min = 600, + }, +- [I2C_SPEED_FAST_PLUS] = { ++ /* FastPlus - 1MHz */ ++ { + .rate = FAST_PLUS_RATE, +- .rate_min = (FAST_PLUS_RATE * 80) / 100, +- .rate_max = (FAST_PLUS_RATE * 120) / 100, + .fall_max = 100, + .rise_max = 120, + .hddat_min = 0, +@@ -125,9 +117,6 @@ static const struct i2c_spec_s i2c_specs[] = { + }, + }; + +-static uint32_t saved_timing; +-static unsigned long saved_frequency; +- + static int i2c_request_memory_write(struct i2c_handle_s *hi2c, + uint16_t dev_addr, uint16_t mem_addr, + uint16_t mem_add_size, +@@ -162,6 +151,21 @@ static void notif_i2c_timeout(struct i2c_handle_s *hi2c) + hi2c->i2c_state = I2C_STATE_READY; + } + ++static const struct i2c_spec_s *get_specs(uint32_t rate) ++{ ++ int i; ++ ++ for (i = 0; i < ARRAY_SIZE(i2c_specs); i++) { ++ if (rate <= i2c_specs[i].rate) { ++ return &i2c_specs[i]; ++ } ++ } ++ ++ /* NOT REACHED */ ++ return NULL; ++} ++ ++#define RATE_MIN(rate) (((rate) / 100U) * 80U) + /* + * @brief Compute the I2C device timings. + * @param init: Ref to the initialization configuration structure +@@ -172,7 +176,7 @@ static void notif_i2c_timeout(struct i2c_handle_s *hi2c) + static int i2c_compute_timing(struct stm32_i2c_init_s *init, + uint32_t clock_src, uint32_t *timing) + { +- enum i2c_speed_e mode = init->speed_mode; ++ const struct i2c_spec_s *specs; + uint32_t speed_freq; + uint32_t i2cclk = udiv_round_nearest(I2C_NSEC_PER_SEC, clock_src); + uint32_t i2cbus; +@@ -196,24 +200,21 @@ static int i2c_compute_timing(struct stm32_i2c_init_s *init, + int s = -1; + struct i2c_timing_s solutions[I2C_TIMINGR_PRESC_MAX]; + +- switch (mode) { +- case I2C_SPEED_STANDARD ... I2C_SPEED_FAST_PLUS: +- break; +- default: +- ERROR("I2C speed out of bound {%d/%d}\n", +- mode, I2C_SPEED_FAST_PLUS); ++ specs = get_specs(init->bus_rate); ++ if (specs == NULL) { ++ ERROR("I2C speed out of bound {%d}\n", init->bus_rate); + return -EINVAL; + } + +- speed_freq = i2c_specs[mode].rate; ++ speed_freq = specs->rate; + i2cbus = udiv_round_nearest(I2C_NSEC_PER_SEC, speed_freq); + clk_error_prev = INT_MAX; + +- if ((init->rise_time > i2c_specs[mode].rise_max) || +- (init->fall_time > i2c_specs[mode].fall_max)) { ++ if ((init->rise_time > specs->rise_max) || ++ (init->fall_time > specs->fall_max)) { + ERROR(" I2C timings out of bound Rise{%d>%d}/Fall{%d>%d}\n", +- init->rise_time, i2c_specs[mode].rise_max, +- init->fall_time, i2c_specs[mode].fall_max); ++ init->rise_time, specs->rise_max, ++ init->fall_time, specs->fall_max); + return -EINVAL; + } + +@@ -230,13 +231,13 @@ static int i2c_compute_timing(struct stm32_i2c_init_s *init, + STM32_I2C_ANALOG_FILTER_DELAY_MAX : 0); + dnf_delay = init->digital_filter_coef * i2cclk; + +- sdadel_min = i2c_specs[mode].hddat_min + init->fall_time - ++ sdadel_min = specs->hddat_min + init->fall_time - + af_delay_min - ((init->digital_filter_coef + 3) * i2cclk); + +- sdadel_max = i2c_specs[mode].vddat_max - init->rise_time - ++ sdadel_max = specs->vddat_max - init->rise_time - + af_delay_max - ((init->digital_filter_coef + 4) * i2cclk); + +- scldel_min = init->rise_time + i2c_specs[mode].sudat_min; ++ scldel_min = init->rise_time + specs->sudat_min; + + if (sdadel_min < 0) { + sdadel_min_u = 0; +@@ -290,8 +291,8 @@ static int i2c_compute_timing(struct stm32_i2c_init_s *init, + } + + tsync = af_delay_min + dnf_delay + (2 * i2cclk); +- clk_max = I2C_NSEC_PER_SEC / i2c_specs[mode].rate_min; +- clk_min = I2C_NSEC_PER_SEC / i2c_specs[mode].rate_max; ++ clk_max = I2C_NSEC_PER_SEC / RATE_MIN(specs->rate); ++ clk_min = I2C_NSEC_PER_SEC / specs->rate; + + /* + * Among prescaler possibilities discovered above figures out SCL Low +@@ -313,7 +314,7 @@ static int i2c_compute_timing(struct stm32_i2c_init_s *init, + for (l = 0; l < I2C_TIMINGR_SCLL_MAX; l++) { + uint32_t tscl_l = ((l + 1) * prescaler) + tsync; + +- if ((tscl_l < i2c_specs[mode].l_min) || ++ if ((tscl_l < specs->l_min) || + (i2cclk >= + ((tscl_l - af_delay_min - dnf_delay) / 4))) { + continue; +@@ -326,7 +327,7 @@ static int i2c_compute_timing(struct stm32_i2c_init_s *init, + init->fall_time; + + if ((tscl >= clk_min) && (tscl <= clk_max) && +- (tscl_h >= i2c_specs[mode].h_min) && ++ (tscl_h >= specs->h_min) && + (i2cclk < tscl_h)) { + int clk_error = tscl - i2cbus; + +@@ -366,6 +367,19 @@ static int i2c_compute_timing(struct stm32_i2c_init_s *init, + return 0; + } + ++static uint32_t get_lower_rate(uint32_t rate) ++{ ++ int i; ++ ++ for (i = ARRAY_SIZE(i2c_specs) - 1; i >= 0; i--) { ++ if (rate > i2c_specs[i].rate) { ++ return i2c_specs[i].rate; ++ } ++ } ++ ++ return i2c_specs[0].rate; ++} ++ + /* + * @brief Setup the I2C device timings. + * @param hi2c: Pointer to a struct i2c_handle_s structure that contains +@@ -379,9 +393,9 @@ static int i2c_setup_timing(struct i2c_handle_s *hi2c, + uint32_t *timing) + { + int rc = 0; +- unsigned long clock_src; ++ uint32_t clock_src; + +- clock_src = stm32mp_clk_get_rate(hi2c->clock); ++ clock_src = (uint32_t)stm32mp_clk_get_rate(hi2c->clock); + if (clock_src == 0U) { + ERROR("I2C clock rate is 0\n"); + return -EINVAL; +@@ -391,8 +405,8 @@ static int i2c_setup_timing(struct i2c_handle_s *hi2c, + * If the timing has already been computed, and the frequency is the + * same as when it was computed, then use the saved timing. + */ +- if (clock_src == saved_frequency) { +- *timing = saved_timing; ++ if (clock_src == hi2c->saved_frequency) { ++ *timing = hi2c->saved_timing; + return 0; + } + +@@ -400,10 +414,10 @@ static int i2c_setup_timing(struct i2c_handle_s *hi2c, + rc = i2c_compute_timing(init, clock_src, timing); + if (rc != 0) { + ERROR("Failed to compute I2C timings\n"); +- if (init->speed_mode > I2C_SPEED_STANDARD) { +- init->speed_mode--; ++ if (init->bus_rate > STANDARD_RATE) { ++ init->bus_rate = get_lower_rate(init->bus_rate); + WARN("Downgrade I2C speed to %uHz)\n", +- i2c_specs[init->speed_mode].rate); ++ init->bus_rate); + } else { + break; + } +@@ -415,16 +429,16 @@ static int i2c_setup_timing(struct i2c_handle_s *hi2c, + return rc; + } + +- VERBOSE("I2C Speed Mode(%i), Freq(%i), Clk Source(%li)\n", +- init->speed_mode, i2c_specs[init->speed_mode].rate, clock_src); ++ VERBOSE("I2C Freq(%i), Clk Source(%i)\n", ++ init->bus_rate, clock_src); + VERBOSE("I2C Rise(%i) and Fall(%i) Time\n", + init->rise_time, init->fall_time); + VERBOSE("I2C Analog Filter(%s), DNF(%i)\n", + (init->analog_filter ? "On" : "Off"), + init->digital_filter_coef); + +- saved_timing = *timing; +- saved_frequency = clock_src; ++ hi2c->saved_timing = *timing; ++ hi2c->saved_frequency = clock_src; + + return 0; + } +@@ -469,49 +483,30 @@ static int i2c_config_analog_filter(struct i2c_handle_s *hi2c, + /* + * @brief Get I2C setup information from the device tree and set pinctrl + * configuration. +- * @param fdt: Pointer to the device tree + * @param node: I2C node offset + * @param init: Ref to the initialization configuration structure + * @retval 0 if OK, negative value else + */ +-int stm32_i2c_get_setup_from_fdt(void *fdt, int node, +- struct stm32_i2c_init_s *init) ++int stm32_i2c_get_setup_from_fdt(int node, struct stm32_i2c_init_s *init) + { +- const fdt32_t *cuint; +- +- cuint = fdt_getprop(fdt, node, "i2c-scl-rising-time-ns", NULL); +- if (cuint == NULL) { +- init->rise_time = STM32_I2C_RISE_TIME_DEFAULT; +- } else { +- init->rise_time = fdt32_to_cpu(*cuint); +- } +- +- cuint = fdt_getprop(fdt, node, "i2c-scl-falling-time-ns", NULL); +- if (cuint == NULL) { +- init->fall_time = STM32_I2C_FALL_TIME_DEFAULT; +- } else { +- init->fall_time = fdt32_to_cpu(*cuint); +- } +- +- cuint = fdt_getprop(fdt, node, "clock-frequency", NULL); +- if (cuint == NULL) { +- init->speed_mode = STM32_I2C_SPEED_DEFAULT; +- } else { +- switch (fdt32_to_cpu(*cuint)) { +- case STANDARD_RATE: +- init->speed_mode = I2C_SPEED_STANDARD; +- break; +- case FAST_RATE: +- init->speed_mode = I2C_SPEED_FAST; +- break; +- case FAST_PLUS_RATE: +- init->speed_mode = I2C_SPEED_FAST_PLUS; +- break; +- default: +- init->speed_mode = STM32_I2C_SPEED_DEFAULT; +- break; +- } ++ uint32_t read_val; ++ ++ init->rise_time = fdt_read_uint32_default(node, ++ "i2c-scl-rising-time-ns", ++ STM32_I2C_RISE_TIME_DEFAULT); ++ ++ init->fall_time = fdt_read_uint32_default(node, ++ "i2c-scl-falling-time-ns", ++ STM32_I2C_FALL_TIME_DEFAULT); ++ ++ read_val = fdt_read_uint32_default(node, "clock-frequency", ++ STANDARD_RATE); ++ if (read_val > FAST_PLUS_RATE) { ++ ERROR("Invalid bus speed (%i > %i)\n", read_val, ++ FAST_PLUS_RATE); ++ return -FDT_ERR_BADVALUE; + } ++ init->bus_rate = read_val; + + return dt_set_pinctrl_config(node); + } +diff --git a/drivers/st/io/io_programmer_st_usb.c b/drivers/st/io/io_programmer_st_usb.c +index a0871f6..878cfa3 100644 +--- a/drivers/st/io/io_programmer_st_usb.c ++++ b/drivers/st/io/io_programmer_st_usb.c +@@ -1,13 +1,12 @@ + /* +- * Copyright (c) 2017, STMicroelectronics - All Rights Reserved +- * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. ++ * Copyright (c) 2017-2019, STMicroelectronics - All Rights Reserved ++ * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + + #include + #include +-#include + #include + #include + #include +@@ -16,10 +15,7 @@ + #include + #include + #include +-#include +-#include + #include +-#include + #include + + static uint8_t first_usb_buffer[USB_DFU_MAX_XFER_SIZE + 1] __aligned(4); +diff --git a/drivers/st/io/io_stm32image.c b/drivers/st/io/io_stm32image.c +index fde6269..8d53a0d 100644 +--- a/drivers/st/io/io_stm32image.c ++++ b/drivers/st/io/io_stm32image.c +@@ -1,11 +1,10 @@ + /* +- * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. ++ * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + + #include +-#include + #include + #include + #include +@@ -13,7 +12,6 @@ + #include + #include + #include +-#include + #include + #include + #include +diff --git a/drivers/st/iwdg/stm32_iwdg.c b/drivers/st/iwdg/stm32_iwdg.c +index 1b5bfe3..ef23bfc 100644 +--- a/drivers/st/iwdg/stm32_iwdg.c ++++ b/drivers/st/iwdg/stm32_iwdg.c +@@ -1,6 +1,6 @@ + /* +- * Copyright (c) 2017-2018, STMicroelectronics - All Rights Reserved +- * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. ++ * Copyright (c) 2017-2019, STMicroelectronics - All Rights Reserved ++ * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +@@ -17,8 +17,6 @@ + #include + #include + #include +-#include +-#include + #include + #include + +diff --git a/drivers/st/mmc/stm32_sdmmc2.c b/drivers/st/mmc/stm32_sdmmc2.c +index aab0582..df9ba63 100644 +--- a/drivers/st/mmc/stm32_sdmmc2.c ++++ b/drivers/st/mmc/stm32_sdmmc2.c +@@ -17,8 +17,6 @@ + #include + #include + #include +-#include +-#include + #include + #include + #include +@@ -49,6 +47,7 @@ + + /* SDMMC power control register */ + #define SDMMC_POWER_PWRCTRL GENMASK(1, 0) ++#define SDMMC_POWER_PWRCTRL_PWR_CYCLE BIT(1) + #define SDMMC_POWER_DIRPOL BIT(4) + + /* SDMMC clock control register */ +@@ -115,6 +114,13 @@ + #define TIMEOUT_10_MS ms2tick(10) + #define TIMEOUT_1_S s2tick(1) + ++/* Power cycle delays in ms */ ++#define VCC_POWER_OFF_DELAY 2 ++#define VCC_POWER_ON_DELAY 2 ++#define POWER_CYCLE_DELAY 2 ++#define POWER_OFF_DELAY 2 ++#define POWER_ON_DELAY 1 ++ + #define DT_SDMMC2_COMPAT "st,stm32-sdmmc2" + + static void stm32_sdmmc2_init(void); +@@ -136,6 +142,8 @@ static const struct mmc_ops stm32_sdmmc2_ops = { + + static struct stm32_sdmmc2_params sdmmc2_params; + ++static bool next_cmd_is_acmd; ++ + #pragma weak plat_sdmmc2_use_dma + bool plat_sdmmc2_use_dma(unsigned int instance, unsigned int memory) + { +@@ -173,6 +181,26 @@ static void stm32_sdmmc2_init(void) + freq = MIN(sdmmc2_params.max_freq, STM32MP_MMC_INIT_FREQ); + } + ++ if (sdmmc2_params.vmmc_regu.id != -1) { ++ stm32mp_regulator_register(&sdmmc2_params.vmmc_regu); ++ stm32mp_regulator_disable(&sdmmc2_params.vmmc_regu); ++ } ++ ++ mdelay(VCC_POWER_OFF_DELAY); ++ ++ mmio_write_32(base + SDMMC_POWER, ++ 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); ++ } ++ ++ mdelay(VCC_POWER_ON_DELAY); ++ ++ mmio_write_32(base + SDMMC_POWER, sdmmc2_params.dirpol); ++ mdelay(POWER_OFF_DELAY); ++ + clock_div = div_round_up(sdmmc2_params.clk_rate, + freq * 2); + +@@ -183,7 +211,7 @@ static void stm32_sdmmc2_init(void) + mmio_write_32(base + SDMMC_POWER, + SDMMC_POWER_PWRCTRL | sdmmc2_params.dirpol); + +- mdelay(1); ++ mdelay(POWER_ON_DELAY); + } + + static int stm32_sdmmc2_stop_transfer(void) +@@ -241,6 +269,20 @@ static int stm32_sdmmc2_send_cmd_req(struct mmc_cmd *cmd) + case MMC_CMD(1): + arg_reg |= OCR_POWERUP; + break; ++ case MMC_CMD(6): ++ if ((sdmmc2_params.device_info->mmc_dev_type == MMC_IS_SD_HC) && ++ (!next_cmd_is_acmd)) { ++ cmd_reg |= SDMMC_CMDR_CMDTRANS; ++ if (sdmmc2_params.use_dma) { ++ flags_data |= SDMMC_STAR_DCRCFAIL | ++ SDMMC_STAR_DTIMEOUT | ++ SDMMC_STAR_DATAEND | ++ SDMMC_STAR_RXOVERR | ++ SDMMC_STAR_IDMATE | ++ SDMMC_STAR_DBCKEND; ++ } ++ } ++ break; + case MMC_CMD(8): + if (sdmmc2_params.device_info->mmc_dev_type == MMC_IS_EMMC) { + cmd_reg |= SDMMC_CMDR_CMDTRANS; +@@ -278,6 +320,8 @@ static int stm32_sdmmc2_send_cmd_req(struct mmc_cmd *cmd) + break; + } + ++ next_cmd_is_acmd = (cmd->cmd_idx == MMC_CMD(55)); ++ + if ((cmd->resp_type & MMC_RSP_BUSY) != 0U) { + mmio_write_32(base + SDMMC_DTIMER, UINT32_MAX); + } +@@ -636,6 +680,7 @@ static int stm32_sdmmc2_dt_get_config(void) + int sdmmc_node; + void *fdt = NULL; + const fdt32_t *cuint; ++ struct dt_node_info dt_info; + + if (fdt_get_address(&fdt) == 0) { + return -FDT_ERR_NOTFOUND; +@@ -645,27 +690,14 @@ static int stm32_sdmmc2_dt_get_config(void) + return -FDT_ERR_NOTFOUND; + } + +- sdmmc_node = fdt_node_offset_by_compatible(fdt, -1, DT_SDMMC2_COMPAT); +- +- while (sdmmc_node != -FDT_ERR_NOTFOUND) { +- cuint = fdt_getprop(fdt, sdmmc_node, "reg", NULL); +- if (cuint == NULL) { +- continue; +- } +- +- if (fdt32_to_cpu(*cuint) == sdmmc2_params.reg_base) { +- break; +- } +- +- sdmmc_node = fdt_node_offset_by_compatible(fdt, sdmmc_node, +- DT_SDMMC2_COMPAT); +- } +- ++ sdmmc_node = dt_match_instance_by_compatible(DT_SDMMC2_COMPAT, ++ sdmmc2_params.reg_base); + if (sdmmc_node == -FDT_ERR_NOTFOUND) { + return -FDT_ERR_NOTFOUND; + } + +- if (fdt_get_status(sdmmc_node) == DT_DISABLED) { ++ dt_fill_device_info(&dt_info, sdmmc_node); ++ if (dt_info.status == DT_DISABLED) { + return -FDT_ERR_NOTFOUND; + } + +@@ -673,21 +705,8 @@ static int stm32_sdmmc2_dt_get_config(void) + return -FDT_ERR_BADVALUE; + } + +- cuint = fdt_getprop(fdt, sdmmc_node, "clocks", NULL); +- if (cuint == NULL) { +- return -FDT_ERR_NOTFOUND; +- } +- +- cuint++; +- sdmmc2_params.clock_id = fdt32_to_cpu(*cuint); +- +- cuint = fdt_getprop(fdt, sdmmc_node, "resets", NULL); +- if (cuint == NULL) { +- return -FDT_ERR_NOTFOUND; +- } +- +- cuint++; +- sdmmc2_params.reset_id = fdt32_to_cpu(*cuint); ++ sdmmc2_params.clock_id = dt_info.clock; ++ sdmmc2_params.reset_id = dt_info.reset; + + if ((fdt_getprop(fdt, sdmmc_node, "st,use-ckin", NULL)) != NULL) { + sdmmc2_params.pin_ckin = SDMMC_CLKCR_SELCLKRX_0; +@@ -722,6 +741,11 @@ 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); ++ } ++ + return 0; + } + +@@ -740,6 +764,8 @@ 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; ++ + if (stm32_sdmmc2_dt_get_config() != 0) { + ERROR("%s: DT error\n", __func__); + return -ENOMEM; +diff --git a/drivers/st/nand/nand.c b/drivers/st/nand/nand.c +index 9198800..2bd076a 100644 +--- a/drivers/st/nand/nand.c ++++ b/drivers/st/nand/nand.c +@@ -23,7 +23,6 @@ + #include + #include + #include +-#include + #include + + /* Other internal NAND driver definitions */ +@@ -190,10 +189,10 @@ static void nand_calc_timing(NAND_HandleTypeDef *hNand) + * tHOLD_ATT > tWC - (tSETUP_ATT + tWAIT) + */ + thold_att = MAX(hclkp, FMC_TALH_MIN); +- thold_att = MAX(hclkp, FMC_TCH_MIN); +- thold_att = MAX(hclkp, FMC_TCLH_MIN); +- thold_att = MAX(hclkp, FMC_TCOH_MIN); +- thold_att = MAX(hclkp, FMC_TDH_MIN); ++ thold_att = MAX(thold_att, FMC_TCH_MIN); ++ thold_att = MAX(thold_att, FMC_TCLH_MIN); ++ thold_att = MAX(thold_att, FMC_TCOH_MIN); ++ thold_att = MAX(thold_att, FMC_TDH_MIN); + if ((FMC_TWB_MAX + FMC_TIO + FMC_TSYNC > tset_mem) && + (thold_att < FMC_TWB_MAX + FMC_TIO + FMC_TSYNC - tset_mem)) { + thold_att = FMC_TWB_MAX + FMC_TIO + FMC_TSYNC - tset_mem; +@@ -749,7 +748,7 @@ static Std_ReturnType Nand_ReadParameterPage(NAND_HandleTypeDef *hNand) + static Std_ReturnType Nand_DetectAndInit(NAND_HandleTypeDef *hNand) + { + NAND_IDTypeDef pNAND_ID; +- uint32_t nand_param_in_otp, result; ++ uint32_t nand_param_in_otp; + + assert(hNand); + +@@ -759,9 +758,7 @@ static Std_ReturnType Nand_DetectAndInit(NAND_HandleTypeDef *hNand) + Nand_ReadIDCode(hNand, &pNAND_ID); + + /* Check if NAND parameters are stored in OTP */ +- result = bsec_shadow_read_otp(&nand_param_in_otp, NAND_OTP); +- if (result != BSEC_OK) { +- ERROR("BSEC: NAND_OTP Error %i\n", result); ++ if (stm32_get_otp_value(NAND_OTP, &nand_param_in_otp) != 0) { + return STD_NOT_OK; + } + +diff --git a/drivers/st/pmic/stm32mp_pmic.c b/drivers/st/pmic/stm32mp_pmic.c +index c8d70db..5abd8e6 100644 +--- a/drivers/st/pmic/stm32mp_pmic.c ++++ b/drivers/st/pmic/stm32mp_pmic.c +@@ -1,16 +1,16 @@ + /* +- * Copyright (c) 2017-2018, STMicroelectronics - All Rights Reserved ++ * Copyright (c) 2017-2019, STMicroelectronics - All Rights Reserved + * + * SPDX-License-Identifier: BSD-3-Clause + */ + ++#include + #include + #include + #include + #include + #include + #include +-#include + #include + #include + #include +@@ -19,7 +19,6 @@ + #define STPMIC1_LDO12356_OUTPUT_SHIFT 2 + #define STPMIC1_LDO3_MODE (uint8_t)(BIT(7)) + #define STPMIC1_LDO3_DDR_SEL 31U +-#define STPMIC1_LDO3_1800000 (9U << STPMIC1_LDO12356_OUTPUT_SHIFT) + + #define STPMIC1_BUCK_OUTPUT_SHIFT 2 + #define STPMIC1_BUCK3_1V8 (39U << STPMIC1_BUCK_OUTPUT_SHIFT) +@@ -28,29 +27,43 @@ + + #define STPMIC1_DEFAULT_START_UP_DELAY_MS 1 + ++#define CMD_GET_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; + +-static int dt_get_pmic_node(void *fdt) ++static int dt_get_pmic_node(void) + { +- return fdt_node_offset_by_compatible(fdt, -1, "st,stpmic1"); ++ static int node = -FDT_ERR_BADOFFSET; ++ ++ if (node == -FDT_ERR_BADOFFSET) { ++ node = dt_get_node_by_compatible("st,stpmic1"); ++ } ++ ++ return node; + } + + int dt_pmic_status(void) + { ++ static int status = -FDT_ERR_BADVALUE; + int node; +- void *fdt; + +- if (fdt_get_address(&fdt) == 0) { +- return -ENOENT; ++ if (status != -FDT_ERR_BADVALUE) { ++ return status; + } + +- node = dt_get_pmic_node(fdt); ++ node = dt_get_pmic_node(); + if (node <= 0) { +- return -FDT_ERR_NOTFOUND; ++ status = -FDT_ERR_NOTFOUND; ++ ++ return status; + } + +- return fdt_get_status(node); ++ status = (int)fdt_get_status(node); ++ ++ return status; + } + + static bool dt_pmic_is_secure(void) +@@ -62,120 +75,126 @@ static bool dt_pmic_is_secure(void) + (i2c_handle.dt_status == DT_SECURE); + } + +-/* +- * 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. +- */ +-static int dt_pmic_i2c_config(struct dt_node_info *i2c_info, +- struct stm32_i2c_init_s *init) ++static int dt_pmic_get_regulator_voltage(void *fdt, int node, ++ uint16_t *voltage_mv) + { +- int pmic_node, i2c_node; +- void *fdt; + const fdt32_t *cuint; + +- if (fdt_get_address(&fdt) == 0) { +- return -ENOENT; +- } ++ cuint = fdt_getprop(fdt, node, "regulator-min-microvolt", NULL); ++ if (cuint != NULL) { ++ *voltage_mv = (uint16_t)(fdt32_to_cpu(*cuint) / 1000U); + +- pmic_node = dt_get_pmic_node(fdt); +- if (pmic_node < 0) { +- return 1; ++ return 0; + } + +- cuint = fdt_getprop(fdt, pmic_node, "reg", NULL); +- if (cuint == NULL) { +- return -FDT_ERR_NOTFOUND; +- } ++ return -FDT_ERR_NOTFOUND; ++} + +- pmic_i2c_addr = fdt32_to_cpu(*cuint) << 1; +- if (pmic_i2c_addr > UINT16_MAX) { +- return -EINVAL; +- } ++static int pmic_config_boot_on(void *fdt, int node, const char *regu_name) ++{ ++ uint16_t voltage; ++ int status; + +- i2c_node = fdt_parent_offset(fdt, pmic_node); +- if (i2c_node < 0) { +- return -FDT_ERR_NOTFOUND; ++ if ((fdt_getprop(fdt, node, "regulator-boot-on", NULL) == NULL) && ++ (fdt_getprop(fdt, node, "regulator-always-on", NULL) == NULL)) { ++ return 0; + } + +- dt_fill_device_info(i2c_info, i2c_node); +- if (i2c_info->base == 0U) { +- return -FDT_ERR_NOTFOUND; +- } ++ if (fdt_getprop(fdt, node, "regulator-pull-down", NULL) != NULL) { + +- return stm32_i2c_get_setup_from_fdt(fdt, i2c_node, init); +-} ++ status = stpmic1_regulator_pull_down_set(regu_name); ++ if (status < 0) { ++ return status; ++ } ++ } + +-int dt_pmic_configure_boot_on_regulators(void) +-{ +- int pmic_node, regulators_node, regulator_node; +- void *fdt; ++ if (fdt_getprop(fdt, node, "st,mask-reset", NULL) != NULL) { + +- if (fdt_get_address(&fdt) == 0) { +- return -ENOENT; ++ status = stpmic1_regulator_mask_reset_set(regu_name); ++ if (status < 0) { ++ return status; ++ } + } + +- pmic_node = dt_get_pmic_node(fdt); +- if (pmic_node < 0) { +- return -FDT_ERR_NOTFOUND; ++ if (dt_pmic_get_regulator_voltage(fdt, node, &voltage) < 0) { ++ return 0; + } + +- regulators_node = fdt_subnode_offset(fdt, pmic_node, "regulators"); ++ status = stpmic1_regulator_voltage_set(regu_name, voltage); ++ if (status < 0) { ++ return status; ++ } + +- fdt_for_each_subnode(regulator_node, fdt, regulators_node) { +- const fdt32_t *cuint; +- const char *node_name = fdt_get_name(fdt, regulator_node, NULL); +- uint16_t voltage; +- int status; +- +-#if defined(IMAGE_BL2) +- if ((fdt_getprop(fdt, regulator_node, "regulator-boot-on", +- NULL) == NULL) && +- (fdt_getprop(fdt, regulator_node, "regulator-always-on", +- NULL) == NULL)) { +-#else +- if (fdt_getprop(fdt, regulator_node, "regulator-boot-on", +- NULL) == NULL) { +-#endif +- continue; ++ if (!stpmic1_is_regulator_enabled(regu_name)) { ++ status = stpmic1_regulator_enable(regu_name); ++ if (status < 0) { ++ return status; + } ++ } + +- if (fdt_getprop(fdt, regulator_node, "regulator-pull-down", +- NULL) != NULL) { +- int status; ++ return 0; ++} + +- status = stpmic1_regulator_pull_down_set(node_name); +- if (status != 0) { +- return status; +- } +- } ++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; ++ }; + +- if (fdt_getprop(fdt, regulator_node, "st,mask-reset", +- NULL) != NULL) { +- int 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; ++ } + +- status = stpmic1_regulator_mask_reset_set(node_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; + } ++ } + +- cuint = fdt_getprop(fdt, regulator_node, +- "regulator-min-microvolt", NULL); +- if (cuint == NULL) { +- continue; ++ 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; + } ++ } + +- /* DT uses microvolts, whereas driver awaits millivolts */ +- voltage = (uint16_t)(fdt32_to_cpu(*cuint) / 1000U); ++ 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_regulator_voltage_set(node_name, voltage); +- if (status != 0) { ++ status = stpmic1_lp_set_voltage(regu_name, voltage); ++ if (status < 0) { + return status; + } ++ } + +- if (stpmic1_is_regulator_enabled(node_name) == 0U) { +- status = stpmic1_regulator_enable(node_name); +- if (status != 0) { ++ 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; + } + } +@@ -184,97 +203,124 @@ int dt_pmic_configure_boot_on_regulators(void) + return 0; + } + +-int dt_pmic_set_lp_config(const char *node_name) ++static int pmic_operate(uint8_t command, const char *node_name, ++ uint16_t *voltage_mv) + { +- int pmic_node, regulators_node, regulator_node; +- int status; ++ int pmic_node, regulators_node, subnode; + void *fdt; +- +- if (node_name == NULL) { +- return 0; +- } ++ int ret = -EIO; ++ const char *regu_name; + + if (fdt_get_address(&fdt) == 0) { + return -ENOENT; + } + +- pmic_node = dt_get_pmic_node(fdt); ++ pmic_node = dt_get_pmic_node(); + if (pmic_node < 0) { +- return -FDT_ERR_NOTFOUND; ++ return -ENOENT; + } + +- status = stpmic1_powerctrl_on(); +- if (status != 0) { +- return status; +- }; +- + regulators_node = fdt_subnode_offset(fdt, pmic_node, "regulators"); + +- fdt_for_each_subnode(regulator_node, fdt, regulators_node) { +- const fdt32_t *cuint; +- const char *reg_name; +- int regulator_state_node; ++ fdt_for_each_subnode(subnode, fdt, regulators_node) { ++ regu_name = fdt_get_name(fdt, subnode, NULL); + +- /* +- * First, copy active configuration (Control register) to +- * PWRCTRL Control register, even if regulator_state_node +- * does not exist. +- */ +- reg_name = fdt_get_name(fdt, regulator_node, NULL); +- status = stpmic1_lp_copy_reg(reg_name); +- if (status != 0) { +- return status; +- } ++ switch (command) { ++ case CMD_GET_VOLTAGE: ++ assert(node_name != NULL); ++ assert(voltage_mv != NULL); + +- /* Then apply configs from regulator_state_node */ +- regulator_state_node = fdt_subnode_offset(fdt, +- regulator_node, +- node_name); +- if (regulator_state_node <= 0) { +- continue; +- } ++ if (strcmp(regu_name, node_name) != 0) { ++ continue; ++ } + +- if (fdt_getprop(fdt, regulator_state_node, +- "regulator-on-in-suspend", NULL) != NULL) { +- status = stpmic1_lp_reg_on_off(reg_name, 1); +- if (status != 0) { +- return status; ++ ret = dt_pmic_get_regulator_voltage(fdt, subnode, ++ voltage_mv); ++ if (ret < 0) { ++ return -ENXIO; + } +- } + +- if (fdt_getprop(fdt, regulator_state_node, +- "regulator-off-in-suspend", NULL) != NULL) { +- status = stpmic1_lp_reg_on_off(reg_name, 0); +- if (status != 0) { +- return status; ++ return ret; ++ ++ case CMD_CONFIG_BOOT_ON: ++ ret = pmic_config_boot_on(fdt, subnode, regu_name); ++ if (ret < 0) { ++ return ret; + } +- } ++ break; + +- cuint = fdt_getprop(fdt, regulator_state_node, +- "regulator-suspend-microvolt", NULL); +- if (cuint != NULL) { +- uint16_t voltage = (uint16_t)(fdt32_to_cpu(*cuint) / +- 1000U); ++ case CMD_CONFIG_LP: ++ assert(node_name != NULL); + +- status = stpmic1_lp_set_voltage(reg_name, voltage); +- if (status != 0) { +- return status; ++ ret = pmic_config_lp(fdt, subnode, node_name, ++ regu_name); ++ if (ret < 0) { ++ return ret; + } ++ break; ++ ++ default: ++ return -EINVAL; + } ++ } + +- 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(reg_name, 1); +- if (status != 0) { +- return status; +- } +- } ++ 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. ++ */ ++static int dt_pmic_i2c_config(struct dt_node_info *i2c_info, ++ struct stm32_i2c_init_s *init) ++{ ++ static int i2c_node = -FDT_ERR_NOTFOUND; ++ int pmic_node; ++ void *fdt; ++ const fdt32_t *cuint; ++ ++ if (i2c_node == -FDT_ERR_NOTFOUND) { ++ if (fdt_get_address(&fdt) == 0) { ++ return -FDT_ERR_NOTFOUND; ++ } ++ ++ pmic_node = dt_get_pmic_node(); ++ if (pmic_node < 0) { ++ return 1; ++ } ++ ++ cuint = fdt_getprop(fdt, pmic_node, "reg", NULL); ++ if (cuint == NULL) { ++ return -FDT_ERR_NOTFOUND; ++ } ++ ++ pmic_i2c_addr = fdt32_to_cpu(*cuint) << 1; ++ if (pmic_i2c_addr > UINT16_MAX) { ++ return -FDT_ERR_BADVALUE; ++ } ++ ++ i2c_node = fdt_parent_offset(fdt, pmic_node); ++ if (i2c_node < 0) { ++ return -FDT_ERR_NOTFOUND; + } + } + +- return 0; ++ dt_fill_device_info(i2c_info, i2c_node); ++ if (i2c_info->base == 0U) { ++ return -FDT_ERR_NOTFOUND; ++ } ++ ++ 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); + } + + /* +@@ -371,43 +417,111 @@ static void register_secure_pmic(void) + stm32mp_register_secure_periph_iomem(i2c_handle.i2c_base_addr); + } + +-void initialize_pmic(void) ++static int pmic_regulator_enable(struct stm32mp_regulator *regu) + { +- unsigned long pmic_version; ++ 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()) { + VERBOSE("No PMIC\n"); + register_non_secure_pmic(); + return; + } + +- if (stpmic1_get_version(&pmic_version) != 0) { +- ERROR("Failed to access PMIC\n"); +- panic(); +- } +- +- INFO("PMIC version = 0x%02lx\n", pmic_version); +- stpmic1_dump_regulators(); +- + if (dt_pmic_is_secure()) { + register_secure_pmic(); + } else { + VERBOSE("PMIC is not secure-only hence assumed non secure\n"); + register_non_secure_pmic(); + } ++} + +-#if defined(IMAGE_BL2) +- if (dt_pmic_configure_boot_on_regulators() != 0) { ++void configure_pmic(void) ++{ ++ if (pmic_configure_boot_on_regulators() < 0) { + panic(); + }; +-#endif + } + ++#if DEBUG ++void print_pmic_info_and_debug(void) ++{ ++ unsigned long pmic_version; ++ ++ if (stpmic1_get_version(&pmic_version) != 0) { ++ ERROR("Failed to access PMIC\n"); ++ panic(); ++ } ++ ++ INFO("PMIC version = 0x%02lx\n", pmic_version); ++ stpmic1_dump_regulators(); ++} ++#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; ++ ++ if (pmic_operate(CMD_GET_VOLTAGE, "buck2", &buck2_mv) != 0) { ++ return -EPERM; ++ } + + switch (ddr_type) { + case STM32MP_DDR3: +@@ -427,7 +541,7 @@ int pmic_ddr_power_init(enum ddr_type ddr_type) + return status; + } + +- status = stpmic1_regulator_voltage_set("buck2", 1350); ++ status = stpmic1_regulator_voltage_set("buck2", buck2_mv); + if (status != 0) { + return status; + } +@@ -477,7 +591,6 @@ int pmic_ddr_power_init(enum ddr_type ddr_type) + + read_val &= ~STPMIC1_LDO3_MODE; + read_val &= ~STPMIC1_LDO12356_OUTPUT_MASK; +- read_val |= STPMIC1_LDO3_1800000; + if (buck3_at_1v8) { + read_val |= STPMIC1_LDO3_MODE; + } +@@ -487,7 +600,16 @@ int pmic_ddr_power_init(enum ddr_type ddr_type) + return status; + } + +- status = stpmic1_regulator_voltage_set("buck2", 1200); ++ if (pmic_operate(CMD_GET_VOLTAGE, "ldo3", &ldo3_mv) != 0) { ++ return -EPERM; ++ } ++ ++ status = stpmic1_regulator_voltage_set("ldo3", ldo3_mv); ++ if (status != 0) { ++ return status; ++ } ++ ++ status = stpmic1_regulator_voltage_set("buck2", buck2_mv); + if (status != 0) { + return status; + } +diff --git a/drivers/st/pmic/stpmic1.c b/drivers/st/pmic/stpmic1.c +index 2bd2b60..463ef60 100644 +--- a/drivers/st/pmic/stpmic1.c ++++ b/drivers/st/pmic/stpmic1.c +@@ -581,17 +581,19 @@ int stpmic1_regulator_enable(const char *name) + { + const struct regul_struct *regul = get_regulator_data(name); + +- return stpmic1_register_update(regul->control_reg, BIT(0), BIT(0)); ++ return stpmic1_register_update(regul->control_reg, LDO_BUCK_ENABLE_MASK, ++ LDO_BUCK_ENABLE_MASK); + } + + int stpmic1_regulator_disable(const char *name) + { + const struct regul_struct *regul = get_regulator_data(name); + +- return stpmic1_register_update(regul->control_reg, 0, BIT(0)); ++ return stpmic1_register_update(regul->control_reg, 0, ++ LDO_BUCK_ENABLE_MASK); + } + +-uint8_t stpmic1_is_regulator_enabled(const char *name) ++bool stpmic1_is_regulator_enabled(const char *name) + { + uint8_t val; + const struct regul_struct *regul = get_regulator_data(name); +@@ -600,7 +602,7 @@ uint8_t stpmic1_is_regulator_enabled(const char *name) + panic(); + } + +- return (val & 0x1U); ++ return (val & LDO_BUCK_ENABLE_MASK) == LDO_BUCK_ENABLE_MASK; + } + + int stpmic1_regulator_voltage_set(const char *name, uint16_t millivolts) +@@ -716,13 +718,15 @@ int stpmic1_regulator_voltage_get(const char *name) + return 0; + } + +- if (stpmic1_register_read(regul->control_reg, &value)) ++ if (stpmic1_register_read(regul->control_reg, &value)) { + return -1; ++ } + + value = (value & mask) >> LDO_BUCK_VOLTAGE_SHIFT; + +- if (value > regul->voltage_table_size) ++ if (value > regul->voltage_table_size) { + return -1; ++ } + + return (int)regul->voltage_table[value]; + } +@@ -803,11 +807,9 @@ void stpmic1_dump_regulators(void) + + int stpmic1_get_version(unsigned long *version) + { +- int rc; + uint8_t read_val; + +- rc = stpmic1_register_read(VERSION_STATUS_REG, &read_val); +- if (rc) { ++ if (stpmic1_register_read(VERSION_STATUS_REG, &read_val) != 0) { + return -1; + } + +diff --git a/drivers/st/qspi/io_qspi.c b/drivers/st/qspi/io_qspi.c +index b00b7d6..00a778c 100644 +--- a/drivers/st/qspi/io_qspi.c ++++ b/drivers/st/qspi/io_qspi.c +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved. ++ * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +@@ -13,8 +13,6 @@ + #include + #include + #include +-#include +-#include + #include + + #define QSPI_COMPAT "st,stm32f469-qspi" +diff --git a/drivers/st/regulator/stm32mp_dummy_regulator.c b/drivers/st/regulator/stm32mp_dummy_regulator.c +new file mode 100644 +index 0000000..23d6892 +--- /dev/null ++++ b/drivers/st/regulator/stm32mp_dummy_regulator.c +@@ -0,0 +1,27 @@ ++/* ++ * 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 +new file mode 100644 +index 0000000..f0e4a4a +--- /dev/null ++++ b/drivers/st/regulator/stm32mp_regulator.c +@@ -0,0 +1,38 @@ ++/* ++ * 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/reset/stm32mp1_reset.c b/drivers/st/reset/stm32mp1_reset.c +index 2e19ef0..45fb988 100644 +--- a/drivers/st/reset/stm32mp1_reset.c ++++ b/drivers/st/reset/stm32mp1_reset.c +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 2018, STMicroelectronics - All Rights Reserved ++ * Copyright (c) 2018-2019, STMicroelectronics - All Rights Reserved + * + * SPDX-License-Identifier: BSD-3-Clause + */ +@@ -10,7 +10,6 @@ + #include + #include + #include +-#include + #include + #include + +diff --git a/drivers/st/rng/stm32_rng.c b/drivers/st/rng/stm32_rng.c +index eec75b2..94d74b0 100644 +--- a/drivers/st/rng/stm32_rng.c ++++ b/drivers/st/rng/stm32_rng.c +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 2018, STMicroelectronics - All Rights Reserved ++ * Copyright (c) 2018-2019, STMicroelectronics - All Rights Reserved + * + * SPDX-License-Identifier: BSD-3-Clause + */ +@@ -13,7 +13,6 @@ + #include + #include + #include +-#include + #include + + #define DT_RNG_COMPAT "st,stm32-rng" +diff --git a/drivers/st/rtc/stm32_rtc.c b/drivers/st/rtc/stm32_rtc.c +index 017c46d..3f469d7 100644 +--- a/drivers/st/rtc/stm32_rtc.c ++++ b/drivers/st/rtc/stm32_rtc.c +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 2018, STMicroelectronics - All Rights Reserved ++ * Copyright (c) 2018-2019, STMicroelectronics - All Rights Reserved + * + * SPDX-License-Identifier: BSD-3-Clause + */ +@@ -12,7 +12,6 @@ + #include + #include + #include +-#include + + #define RTC_COMPAT "st,stm32mp1-rtc" + +@@ -251,20 +250,11 @@ static uint32_t stm32_rtc_get_second_fraction(struct stm32_rtc_calendar *cal) + * This function computes the fraction difference between two timestamps. + * Here again the returned value is in milliseconds. + ******************************************************************************/ +-static unsigned long long stm32_rtc_diff_frac(struct stm32_rtc_calendar *cur, +- struct stm32_rtc_calendar *ref) ++static signed long long stm32_rtc_diff_frac(struct stm32_rtc_calendar *cur, ++ struct stm32_rtc_calendar *ref) + { +- unsigned long long val_r; +- unsigned long long val_c; +- +- val_r = stm32_rtc_get_second_fraction(ref); +- val_c = stm32_rtc_get_second_fraction(cur); +- +- if (val_c >= val_r) { +- return val_c - val_r; +- } else { +- return 1000U - val_r + val_c; +- } ++ return (signed long long)stm32_rtc_get_second_fraction(cur) - ++ (signed long long)stm32_rtc_get_second_fraction(ref); + } + + /******************************************************************************* +@@ -272,10 +262,9 @@ static unsigned long long stm32_rtc_diff_frac(struct stm32_rtc_calendar *cur, + * It includes seconds, minutes and hours. + * Here again the returned value is in milliseconds. + ******************************************************************************/ +-static unsigned long long stm32_rtc_diff_time(struct stm32_rtc_time *current, +- struct stm32_rtc_time *ref) ++static signed long long stm32_rtc_diff_time(struct stm32_rtc_time *current, ++ struct stm32_rtc_time *ref) + { +- signed long long diff_in_s; + signed long long curr_s; + signed long long ref_s; + +@@ -287,12 +276,7 @@ static unsigned long long stm32_rtc_diff_time(struct stm32_rtc_time *current, + (((signed long long)ref->min + + (((signed long long)ref->hour * 60))) * 60); + +- diff_in_s = curr_s - ref_s; +- if (diff_in_s < 0) { +- diff_in_s += 24 * 60 * 60; +- } +- +- return (unsigned long long)diff_in_s * 1000U; ++ return (curr_s - ref_s) * 1000; + } + + /******************************************************************************* +@@ -310,8 +294,8 @@ static bool stm32_is_a_leap_year(uint32_t year) + * It includes days, months, years, with exceptions. + * Here again the returned value is in milliseconds. + ******************************************************************************/ +-static unsigned long long stm32_rtc_diff_date(struct stm32_rtc_time *current, +- struct stm32_rtc_time *ref) ++static signed long long stm32_rtc_diff_date(struct stm32_rtc_time *current, ++ struct stm32_rtc_time *ref) + { + uint32_t diff_in_days = 0; + uint32_t m; +@@ -385,7 +369,7 @@ static unsigned long long stm32_rtc_diff_date(struct stm32_rtc_time *current, + } + } + +- return (24ULL * 60U * 60U * 1000U) * (unsigned long long)diff_in_days; ++ return (24 * 60 * 60 * 1000) * (signed long long)diff_in_days; + } + + /******************************************************************************* +@@ -395,7 +379,7 @@ static unsigned long long stm32_rtc_diff_date(struct stm32_rtc_time *current, + unsigned long long stm32_rtc_diff_calendar(struct stm32_rtc_calendar *cur, + struct stm32_rtc_calendar *ref) + { +- unsigned long long diff_in_ms = 0; ++ signed long long diff_in_ms = 0; + struct stm32_rtc_time curr_t; + struct stm32_rtc_time ref_t; + +@@ -412,7 +396,7 @@ unsigned long long stm32_rtc_diff_calendar(struct stm32_rtc_calendar *cur, + + stm32mp_clk_disable(rtc_dev.clock); + +- return diff_in_ms; ++ return (unsigned long long)diff_in_ms; + } + + /******************************************************************************* +diff --git a/drivers/st/tamper/stm32_tamp.c b/drivers/st/tamper/stm32_tamp.c +index 0bfa177..b09f122 100644 +--- a/drivers/st/tamper/stm32_tamp.c ++++ b/drivers/st/tamper/stm32_tamp.c +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 2018, STMicroelectronics - All Rights Reserved ++ * Copyright (c) 2018-2019, STMicroelectronics - All Rights Reserved + * + * SPDX-License-Identifier: BSD-3-Clause + */ +@@ -12,8 +12,6 @@ + #include + #include + #include +-#include +-#include + + #define DT_TAMP_COMPAT "st,stm32-tamp" + /* STM32 Registers */ +diff --git a/drivers/st/timer/stm32_timer.c b/drivers/st/timer/stm32_timer.c +index 4c58000..f33821e 100644 +--- a/drivers/st/timer/stm32_timer.c ++++ b/drivers/st/timer/stm32_timer.c +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 2018, STMicroelectronics - All Rights Reserved ++ * Copyright (c) 2018-2019, STMicroelectronics - All Rights Reserved + * + * SPDX-License-Identifier: BSD-3-Clause + */ +@@ -12,7 +12,6 @@ + #include + #include + #include +-#include + + #define TIM_CR1 0x00U /* Control Register 1 */ + #define TIM_CR2 0x04U /* Control Register 2 */ +diff --git a/drivers/st/uart/io_programmer_uart.c b/drivers/st/uart/io_programmer_uart.c +index 34a7cbb..f56a552 100644 +--- a/drivers/st/uart/io_programmer_uart.c ++++ b/drivers/st/uart/io_programmer_uart.c +@@ -1,12 +1,11 @@ + /* +- * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved. ++ * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + + #include + #include +-#include + #include + #include + #include +@@ -16,8 +15,6 @@ + #include + #include + #include +-#include +-#include + #include + + /* USART bootloader protocol version V4.0*/ +diff --git a/fdts/stm32mp15-ddr.dtsi b/fdts/stm32mp15-ddr.dtsi +index 1a5c51c..4825691 100644 +--- a/fdts/stm32mp15-ddr.dtsi ++++ b/fdts/stm32mp15-ddr.dtsi +@@ -5,7 +5,7 @@ + + / { + soc { +- ddr: ddr@5A003000{ ++ ddr: ddr@5a003000{ + + compatible = "st,stm32mp1-ddr"; + +diff --git a/fdts/stm32mp157a-dk1.dts b/fdts/stm32mp157a-dk1.dts +index f081575..d852171 100644 +--- a/fdts/stm32mp157a-dk1.dts ++++ b/fdts/stm32mp157a-dk1.dts +@@ -34,6 +34,7 @@ + pinctrl-0 = <&i2c4_pins_a>; + i2c-scl-rising-time-ns = <185>; + i2c-scl-falling-time-ns = <20>; ++ clock-frequency = <400000>; + status = "okay"; + + pmic: stpmic@33 { +@@ -43,10 +44,7 @@ + interrupt-controller; + #interrupt-cells = <2>; + status = "okay"; +- +- st,main-control-register = <0x04>; +- st,vin-control-register = <0xc0>; +- st,usb-control-register = <0x20>; ++ wakeup-source; + + regulators { + compatible = "st,stpmic1-regulators"; +@@ -283,12 +281,6 @@ + CLK_LPTIM45_LSE + >; + +- /* VCO = 1300.0 MHz => P = 650 (CPU) */ +- pll1: st,pll@0 { +- cfg = < 2 80 0 0 0 PQR(1,0,0) >; +- frac = < 0x800 >; +- }; +- + /* VCO = 1066.0 MHz => P = 266 (AXI), Q = 533 (GPU), R = 533 (DDR) */ + pll2: st,pll@1 { + cfg = < 2 65 1 0 0 PQR(1,1,1) >; +@@ -311,8 +303,7 @@ + &bsec { + board_id: board_id@ec { + reg = <0xec 0x4>; +- status = "okay"; +- secure-status = "okay"; ++ st,non-secure-otp; + }; + }; + +@@ -332,6 +323,24 @@ + secure-status = "okay"; + }; + ++&nvmem_layout { ++ nvmem-cells = <&part_number_otp>, ++ <&monotonic_otp>, ++ <&nand_otp>, ++ <&uid_otp>, ++ <&package_otp>, ++ <&hw2_otp>, ++ <&board_id>; ++ ++ nvmem-cell-names = "part_number_otp", ++ "monotonic_otp", ++ "nand_otp", ++ "uid_otp", ++ "package_otp", ++ "hw2_otp", ++ "board_id"; ++}; ++ + &pwr { + system_suspend_supported_soc_modes = < + STM32_PM_CSLEEP_RUN +diff --git a/fdts/stm32mp157c-ed1.dts b/fdts/stm32mp157c-ed1.dts +index 61d5301..02c4233 100644 +--- a/fdts/stm32mp157c-ed1.dts ++++ b/fdts/stm32mp157c-ed1.dts +@@ -30,6 +30,7 @@ + pinctrl-0 = <&i2c4_pins_a>; + i2c-scl-rising-time-ns = <185>; + i2c-scl-falling-time-ns = <20>; ++ clock-frequency = <400000>; + status = "okay"; + + pmic: stpmic@33 { +@@ -39,10 +40,7 @@ + interrupt-controller; + #interrupt-cells = <2>; + status = "okay"; +- +- st,main-control-register = <0x04>; +- st,vin-control-register = <0xc0>; +- st,usb-control-register = <0x20>; ++ wakeup-source; + + regulators { + compatible = "st,stpmic1-regulators"; +@@ -288,12 +286,6 @@ + CLK_LPTIM45_LSE + >; + +- /* VCO = 1300.0 MHz => P = 650 (CPU) */ +- pll1: st,pll@0 { +- cfg = < 2 80 0 0 0 PQR(1,0,0) >; +- frac = < 0x800 >; +- }; +- + /* VCO = 1066.0 MHz => P = 266 (AXI), Q = 533 (GPU), R = 533 (DDR) */ + pll2: st,pll@1 { + cfg = < 2 65 1 0 0 PQR(1,1,1) >; +@@ -316,8 +308,7 @@ + &bsec { + board_id: board_id@ec { + reg = <0xec 0x4>; +- status = "okay"; +- secure-status = "okay"; ++ st,non-secure-otp; + }; + }; + +@@ -337,6 +328,24 @@ + secure-status = "okay"; + }; + ++&nvmem_layout { ++ nvmem-cells =<&part_number_otp>, ++ <&monotonic_otp>, ++ <&nand_otp>, ++ <&uid_otp>, ++ <&package_otp>, ++ <&hw2_otp>, ++ <&board_id>; ++ ++ nvmem-cell-names = "part_number_otp", ++ "monotonic_otp", ++ "nand_otp", ++ "uid_otp", ++ "package_otp", ++ "hw2_otp", ++ "board_id"; ++}; ++ + &pwr { + system_suspend_supported_soc_modes = < + STM32_PM_CSLEEP_RUN +diff --git a/fdts/stm32mp157c-security.dtsi b/fdts/stm32mp157c-security.dtsi +index 124ed53..b18c6c3 100644 +--- a/fdts/stm32mp157c-security.dtsi ++++ b/fdts/stm32mp157c-security.dtsi +@@ -1,5 +1,5 @@ + /* +- * Copyright : STMicroelectronics 2017 ++ * Copyright (c) 2017-2019, STMicroelectronics - All Rights Reserved + * + * SPDX-License-Identifier: GPL-2.0+ BSD-3-Clause + */ +@@ -8,7 +8,7 @@ + + / { + soc { +- iwdg1: watchdog@5C003000 { ++ iwdg1: watchdog@5c003000 { + compatible = "st,stm32mp1-iwdg"; + reg = <0x5C003000 0x400>; + clocks = <&rcc IWDG1>, <&rcc CK_LSI>; +@@ -18,7 +18,7 @@ + secure-status = "disabled"; + }; + +- etzpc: etzpc@5C007000 { ++ etzpc: etzpc@5c007000 { + compatible = "st,stm32-etzpc"; + reg = <0x5C007000 0x400>; + clocks = <&rcc TZPC>; +@@ -26,20 +26,53 @@ + secure-status = "okay"; + }; + +- stgen: stgen@5C008000 { ++ stgen: stgen@5c008000 { + compatible = "st,stm32-stgen"; + reg = <0x5C008000 0x1000>; + }; ++ ++ nvmem_layout: nvmem_layout@0 { ++ compatible = "st,stm32-nvmem-layout"; ++ ++ nvmem-cells = <&part_number_otp>, ++ <&monotonic_otp>, ++ <&nand_otp>, ++ <&uid_otp>, ++ <&package_otp>, ++ <&hw2_otp>; ++ ++ nvmem-cell-names = "part_number_otp", ++ "monotonic_otp", ++ "nand_otp", ++ "uid_otp", ++ "package_otp", ++ "hw2_otp"; ++ }; + }; + }; + + &bsec { +- mac_addr: mac_addr@e4 { +- reg = <0xe4 0x6>; ++ part_number_otp: part_number_otp@4 { ++ reg = <0x4 0x1>; ++ }; ++ monotonic_otp: monotonic_otp@10 { ++ reg = <0x10 0x4>; + }; +- /* Spare field to align on 32-bit OTP granularity */ +- spare_ns_ea: spare_ns_ea@ea { +- reg = <0xea 0x2>; ++ nand_otp: nand_otp@24 { ++ reg = <0x24 0x4>; ++ }; ++ uid_otp: uid_otp@34 { ++ reg = <0x34 0xc>; ++ }; ++ package_otp: package_otp@40 { ++ reg = <0x40 0x4>; ++ }; ++ hw2_otp: hw2_otp@48 { ++ reg = <0x48 0x4>; ++ }; ++ mac_addr: mac_addr@e4 { ++ reg = <0xe4 0x8>; ++ st,non-secure-otp; + }; + }; + +diff --git a/fdts/stm32mp157c.dtsi b/fdts/stm32mp157c.dtsi +index e649c3a..13125b1 100644 +--- a/fdts/stm32mp157c.dtsi ++++ b/fdts/stm32mp157c.dtsi +@@ -388,5 +388,22 @@ + compatible = "simple-bus", "syscon", "simple-mfd"; + reg = <0x5c00a000 0x400>; + }; ++ ++ cpu_opp_table: cpu0-opp-table { ++ compatible = "operating-points-v2"; ++ opp-shared; ++ ++ opp-650000000 { ++ opp-hz = /bits/ 64 <650000000>; ++ opp-microvolt = <1200000>; ++ opp-supported-hw = <0x1>; ++ }; ++ ++ opp-800000000 { ++ opp-hz = /bits/ 64 <800000000>; ++ opp-microvolt = <1350000>; ++ opp-supported-hw = <0x2>; ++ }; ++ }; + }; + }; +diff --git a/include/drivers/mmc.h b/include/drivers/mmc.h +index 38553b9..30580ea 100644 +--- a/include/drivers/mmc.h ++++ b/include/drivers/mmc.h +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. ++ * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +@@ -103,6 +103,7 @@ + #define MMC_STATE_SLP 10 + + #define MMC_FLAG_CMD23 (U(1) << 0) ++#define MMC_FLAG_SD_CMD6 (U(1) << 1) + + #define CMD8_CHECK_PATTERN U(0xAA) + #define VHS_2_7_3_6_V BIT(8) +@@ -110,6 +111,9 @@ + #define SD_SCR_BUS_WIDTH_1 BIT(8) + #define SD_SCR_BUS_WIDTH_4 BIT(10) + ++#define SD_SWITCH_FUNC_CHECK 0U ++#define SD_SWITCH_FUNC_SWITCH 1U ++ + struct mmc_cmd { + unsigned int cmd_idx; + unsigned int cmd_arg; +@@ -209,6 +213,27 @@ struct mmc_csd_sd_v2 { + unsigned int csd_structure: 2; + }; + ++struct sd_switch_status { ++ unsigned short max_current; ++ unsigned short support_g6; ++ unsigned short support_g5; ++ unsigned short support_g4; ++ unsigned short support_g3; ++ unsigned short support_g2; ++ unsigned short support_g1; ++ unsigned char sel_g6_g5; ++ unsigned char sel_g4_g3; ++ unsigned char sel_g2_g1; ++ unsigned char data_struct_ver; ++ unsigned short busy_g6; ++ unsigned short busy_g5; ++ unsigned short busy_g4; ++ unsigned short busy_g3; ++ unsigned short busy_g2; ++ unsigned short busy_g1; ++ unsigned short reserved[17]; ++}; ++ + enum mmc_device_type { + MMC_IS_EMMC, + MMC_IS_SD, +diff --git a/include/drivers/st/bsec.h b/include/drivers/st/bsec.h +index 71a68c2..25f29de 100644 +--- a/include/drivers/st/bsec.h ++++ b/include/drivers/st/bsec.h +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. ++ * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +@@ -172,6 +172,9 @@ uint32_t bsec_get_base(void); + uint32_t bsec_set_config(struct bsec_config *cfg); + uint32_t bsec_get_config(struct bsec_config *cfg); + ++uint32_t bsec_find_otp_name_in_dt(const char *name, uint32_t *otp, ++ uint32_t *otp_len); ++ + uint32_t bsec_shadow_register(uint32_t otp); + uint32_t bsec_read_otp(uint32_t *val, uint32_t otp); + uint32_t bsec_write_otp(uint32_t val, uint32_t otp); +diff --git a/include/drivers/st/stm32_i2c.h b/include/drivers/st/stm32_i2c.h +index 4d5e302..7e0d93f 100644 +--- a/include/drivers/st/stm32_i2c.h ++++ b/include/drivers/st/stm32_i2c.h +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 2016-2018, STMicroelectronics - All Rights Reserved ++ * Copyright (c) 2016-2019, STMicroelectronics - All Rights Reserved + * + * SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause + */ +@@ -125,12 +125,6 @@ + #define I2C_ICR_TIMOUTCF BIT(12) + #define I2C_ICR_ALERTCF BIT(13) + +-enum i2c_speed_e { +- I2C_SPEED_STANDARD, /* 100 kHz */ +- I2C_SPEED_FAST, /* 400 kHz */ +- I2C_SPEED_FAST_PLUS, /* 1 MHz */ +-}; +- + #define STANDARD_RATE 100000 + #define FAST_RATE 400000 + #define FAST_PLUS_RATE 1000000 +@@ -195,12 +189,7 @@ struct stm32_i2c_init_s { + * time in nanoseconds. + */ + +- enum i2c_speed_e speed_mode; /* +- * Specifies the I2C clock source +- * frequency mode. +- * This parameter can be a value of @ref +- * i2c_speed_mode_e. +- */ ++ uint32_t bus_rate; /* Specifies the I2C clock frequency */ + + int analog_filter; /* + * Specifies if the I2C analog noise +@@ -252,6 +241,8 @@ struct i2c_handle_s { + enum i2c_state_e i2c_state; /* Communication state */ + enum i2c_mode_e i2c_mode; /* Communication mode */ + uint32_t i2c_err; /* Error code */ ++ uint32_t saved_timing; /* Saved timing value */ ++ uint32_t saved_frequency; /* Saved frequency value */ + }; + + #define I2C_ADDRESSINGMODE_7BIT 0x00000001U +@@ -313,8 +304,7 @@ struct i2c_handle_s { + #define STM32_I2C_ANALOG_FILTER_DELAY_MAX 260 /* ns */ + #define STM32_I2C_DIGITAL_FILTER_MAX 16 + +-int stm32_i2c_get_setup_from_fdt(void *fdt, int node, +- struct stm32_i2c_init_s *init); ++int stm32_i2c_get_setup_from_fdt(int node, struct stm32_i2c_init_s *init); + int stm32_i2c_init(struct i2c_handle_s *hi2c, + struct stm32_i2c_init_s *init_data); + int stm32_i2c_mem_write(struct i2c_handle_s *hi2c, uint16_t dev_addr, +diff --git a/include/drivers/st/stm32_sdmmc2.h b/include/drivers/st/stm32_sdmmc2.h +index 7fa9c5d..c2bb7f6 100644 +--- a/include/drivers/st/stm32_sdmmc2.h ++++ b/include/drivers/st/stm32_sdmmc2.h +@@ -9,6 +9,7 @@ + + #include + #include ++#include + + struct stm32_sdmmc2_params { + uintptr_t reg_base; +@@ -23,6 +24,7 @@ struct stm32_sdmmc2_params { + unsigned int reset_id; + unsigned int max_freq; + bool use_dma; ++ struct stm32mp_regulator vmmc_regu; + }; + + unsigned long long stm32_sdmmc2_mmc_get_device_size(void); +diff --git a/include/drivers/st/stm32mp1_clk.h b/include/drivers/st/stm32mp1_clk.h +index 4f6930b..82f488b 100644 +--- a/include/drivers/st/stm32mp1_clk.h ++++ b/include/drivers/st/stm32mp1_clk.h +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 2018, STMicroelectronics - All Rights Reserved ++ * Copyright (c) 2018-2019, STMicroelectronics - All Rights Reserved + * + * SPDX-License-Identifier: BSD-3-Clause + */ +@@ -12,8 +12,16 @@ + + #include + ++#define PLL1_SETTINGS_VALID_ID U(0x504C4C31) /* "PLL1" */ ++ + int stm32mp1_clk_probe(void); +-int stm32mp1_clk_init(void); ++int stm32mp1_clk_init(uint32_t pll1_freq_mhz); ++ ++int stm32mp1_clk_compute_all_pll1_settings(uint32_t buck1_voltage); ++void stm32mp1_clk_lp_save_opp_pll1_settings(uint8_t *data, size_t size); ++void stm32mp1_clk_lp_load_opp_pll1_settings(uint8_t *data, size_t size); ++ ++int stm32mp1_clk_get_maxfreq_opp(uint32_t *freq_mhz, uint32_t *voltage_mv); + + bool stm32mp1_rcc_is_secure(void); + bool stm32mp1_rcc_is_mckprot(void); +@@ -47,15 +55,21 @@ unsigned int stm32mp1_clk_get_refcount(unsigned long id); + unsigned long stm32mp_clk_get_rate(unsigned long id); + unsigned long stm32mp_clk_timer_get_rate(unsigned long id); + +-void stm32mp1_stgen_increment(unsigned long long offset_in_ms); +- + bool stm32mp1_rtc_get_read_twice(void); + + /* SMP protection on RCC registers access */ + void stm32mp1_clk_rcc_regs_lock(void); + void stm32mp1_clk_rcc_regs_unlock(void); + ++void stm32mp1_stgen_restore_counter(unsigned long long value, ++ unsigned long long offset_in_ms); ++unsigned long long stm32mp1_stgen_get_counter(void); ++ + unsigned long stm32mp1_clk_rcc2id(unsigned int offset, unsigned int bit); ++ ++int stm32mp1_round_opp_khz(uint32_t *freq_khz); ++int stm32mp1_set_opp_khz(uint32_t freq_khz); ++ + #if defined(IMAGE_BL32) + void stm32mp1_clk_mpu_suspend(void); + void stm32mp1_clk_mpu_resume(void); +diff --git a/include/drivers/st/stm32mp1_ddr_regs.h b/include/drivers/st/stm32mp1_ddr_regs.h +index e928688..2361dcc 100644 +--- a/include/drivers/st/stm32mp1_ddr_regs.h ++++ b/include/drivers/st/stm32mp1_ddr_regs.h +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 2017-2018, STMicroelectronics - All Rights Reserved ++ * Copyright (c) 2017-2019, STMicroelectronics - All Rights Reserved + * + * SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause + */ +@@ -381,6 +381,7 @@ struct stm32mp1_ddrphy { + #define DDRPHYC_PTR0_TITMSRST_OFFSET 18 + #define DDRPHYC_PTR0_TITMSRST_MASK GENMASK(21, 18) + ++#define DDRPHYC_ACIOCR_ACOE BIT(1) + #define DDRPHYC_ACIOCR_ACPDD BIT(3) + #define DDRPHYC_ACIOCR_ACPDR BIT(4) + #define DDRPHYC_ACIOCR_CKPDD_MASK GENMASK(10, 8) +@@ -400,6 +401,7 @@ struct stm32mp1_ddrphy { + #define DDRPHYC_DSGCR_ODTPDD_MASK GENMASK(23, 20) + #define DDRPHYC_DSGCR_ODTPDD_0 BIT(20) + #define DDRPHYC_DSGCR_NL2PD BIT(24) ++#define DDRPHYC_DSGCR_CKOE BIT(28) + + #define DDRPHYC_ZQ0CRN_ZDATA_MASK GENMASK(27, 0) + #define DDRPHYC_ZQ0CRN_ZDATA_SHIFT 0 +diff --git a/include/drivers/st/stm32mp_clkfunc.h b/include/drivers/st/stm32mp_clkfunc.h +index c77c0b5..c0f8694 100644 +--- a/include/drivers/st/stm32mp_clkfunc.h ++++ b/include/drivers/st/stm32mp_clkfunc.h +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 2017-2018, STMicroelectronics - All Rights Reserved ++ * Copyright (c) 2017-2019, STMicroelectronics - All Rights Reserved + * + * SPDX-License-Identifier: BSD-3-Clause + */ +@@ -10,8 +10,7 @@ + #include + #include + +-int fdt_get_rcc_node(void *fdt); +-uint32_t fdt_rcc_read_addr(void); ++int fdt_get_rcc_node(void); + int fdt_rcc_read_uint32_array(const char *prop_name, + uint32_t *array, uint32_t count); + uint32_t fdt_rcc_read_uint32_default(const char *prop_name, +@@ -25,4 +24,6 @@ int fdt_get_clock_id(int node); + int fdt_get_clock_id_by_name(int node, const char *name); + unsigned long fdt_get_uart_clock_freq(uintptr_t instance); + ++bool fdt_is_pll1_predefined(void); ++ + #endif /* STM32MP_CLKFUNC_H */ +diff --git a/include/drivers/st/stm32mp_dummy_regulator.h b/include/drivers/st/stm32mp_dummy_regulator.h +new file mode 100644 +index 0000000..9fd83ac +--- /dev/null ++++ b/include/drivers/st/stm32mp_dummy_regulator.h +@@ -0,0 +1,14 @@ ++/* ++ * 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 39c80e4..1147d00 100644 +--- a/include/drivers/st/stm32mp_pmic.h ++++ b/include/drivers/st/stm32mp_pmic.h +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 2017-2018, STMicroelectronics - All Rights Reserved ++ * Copyright (c) 2017-2019, STMicroelectronics - All Rights Reserved + * + * SPDX-License-Identifier: BSD-3-Clause + */ +@@ -10,15 +10,26 @@ + #include + #include + #include ++#include + + int dt_pmic_status(void); +-int dt_pmic_configure_boot_on_regulators(void); +-int dt_pmic_set_lp_config(const char *node_name); ++int pmic_configure_boot_on_regulators(void); ++int pmic_set_lp_config(const char *node_name); + bool initialize_pmic_i2c(void); ++bool is_pmic_regulator(struct stm32mp_regulator *regu); ++void bind_pmic_regulator(struct stm32mp_regulator *regu); + void initialize_pmic(void); ++void configure_pmic(void); + #if STM32MP1_DEBUG_ENABLE + int pmic_keep_debug_unit(void); + #endif ++#if DEBUG ++void print_pmic_info_and_debug(void); ++#else ++static inline void print_pmic_info_and_debug(void) ++{ ++} ++#endif + int pmic_ddr_power_init(enum ddr_type ddr_type); + + #endif /* STM32MP_PMIC_H */ +diff --git a/include/drivers/st/stm32mp_regulator.h b/include/drivers/st/stm32mp_regulator.h +new file mode 100644 +index 0000000..7a66b97 +--- /dev/null ++++ b/include/drivers/st/stm32mp_regulator.h +@@ -0,0 +1,31 @@ ++/* ++ * 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 803a69e..50e1fa3 100644 +--- a/include/drivers/st/stpmic1.h ++++ b/include/drivers/st/stpmic1.h +@@ -86,15 +86,15 @@ + #define ITSOURCE4_REG 0xB3U + + /* Registers masks */ +-#define LDO_VOLTAGE_MASK 0x7CU +-#define BUCK_VOLTAGE_MASK 0xFCU ++#define LDO_VOLTAGE_MASK GENMASK(6, 2) ++#define BUCK_VOLTAGE_MASK GENMASK(7, 2) + #define LDO_BUCK_VOLTAGE_SHIFT 2 +-#define LDO_BUCK_ENABLE_MASK 0x01U +-#define LDO_BUCK_HPLP_ENABLE_MASK 0x02U ++#define LDO_BUCK_ENABLE_MASK BIT(0) ++#define LDO_BUCK_HPLP_ENABLE_MASK BIT(1) + #define LDO_BUCK_HPLP_SHIFT 1 +-#define LDO_BUCK_RANK_MASK 0x01U +-#define LDO_BUCK_RESET_MASK 0x01U +-#define LDO_BUCK_PULL_DOWN_MASK 0x03U ++#define LDO_BUCK_RANK_MASK BIT(0) ++#define LDO_BUCK_RESET_MASK BIT(0) ++#define LDO_BUCK_PULL_DOWN_MASK GENMASK(1, 0) + + /* Pull down register */ + #define BUCK1_PULL_DOWN_SHIFT 0 +@@ -135,12 +135,12 @@ + /* Main PMIC VINLOW Control Register (VIN_CONTROL_REGC DMSC) */ + #define SWIN_DETECTOR_ENABLED BIT(7) + #define SWOUT_DETECTOR_ENABLED BIT(6) +-#define VINLOW_HYST_MASK 0x3 ++#define VINLOW_HYST_MASK GENMASK(1, 0) + #define VINLOW_HYST_SHIFT 4 +-#define VINLOW_THRESHOLD_MASK 0x7 ++#define VINLOW_THRESHOLD_MASK GENMASK(2, 0) + #define VINLOW_THRESHOLD_SHIFT 1 +-#define VINLOW_ENABLED 0x01 +-#define VINLOW_CTRL_REG_MASK 0xFF ++#define VINLOW_ENABLED BIT(0) ++#define VINLOW_CTRL_REG_MASK GENMASK(7, 0) + + /* USB Control Register */ + #define BOOST_OVP_DISABLED BIT(7) +@@ -156,7 +156,7 @@ int stpmic1_register_write(uint8_t register_id, uint8_t value); + int stpmic1_register_update(uint8_t register_id, uint8_t value, uint8_t mask); + int stpmic1_regulator_enable(const char *name); + int stpmic1_regulator_disable(const char *name); +-uint8_t stpmic1_is_regulator_enabled(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_voltage_get(const char *name); + int stpmic1_regulator_pull_down_set(const char *name); +diff --git a/lib/usb/usb_st_dfu.c b/lib/usb/usb_st_dfu.c +index 2cf01f6..9a10f7b 100644 +--- a/lib/usb/usb_st_dfu.c ++++ b/lib/usb/usb_st_dfu.c +@@ -759,7 +759,7 @@ static uint8_t usb_dfu_setup(usb_handle_t *pdev, usb_setup_req_t *req) + break; + + case DFU_DETACH: +- INFO("Receive DFU detach\n"); ++ usb_dfu_detach(pdev, req); + break; + + default: +diff --git a/plat/st/common/bl2_io_storage.c b/plat/st/common/bl2_io_storage.c +index d483c18..93f8916 100644 +--- a/plat/st/common/bl2_io_storage.c ++++ b/plat/st/common/bl2_io_storage.c +@@ -89,7 +89,6 @@ static QSPI_HandleTypeDef qspi_dev_spec = { + #endif + + #if STM32MP_UART_PROGRAMMER +-/* uart*/ + static const io_dev_connector_t *uart_dev_con; + + static UART_HandleTypeDef uart_programmer = { +@@ -112,7 +111,6 @@ static const io_dev_connector_t *usb_dev_con; + #endif /*STM32MP_USB*/ + + #if STM32MP_FMC_NAND +-/* nand */ + static const io_dev_connector_t *nand_dev_con; + static NAND_HandleTypeDef nand_dev_spec; + #endif +@@ -305,102 +303,6 @@ static void print_boot_device(boot_api_context_t *boot_context) + } + } + +-#if STM32MP_SDMMC +-static void print_bootrom_sd_status(boot_api_context_t *boot_context) +-{ +- if (boot_context->sd_err_internal_timeout_cnt != 0U) { +- WARN("BootROM: %d timeout issues\n", +- boot_context->sd_err_internal_timeout_cnt); +- } +- +- if (boot_context->sd_err_dcrc_fail_cnt != 0U) { +- WARN("BootROM: %d DCRCFAIL error\n", +- boot_context->sd_err_dcrc_fail_cnt); +- } +- +- if (boot_context->sd_err_dtimeout_cnt != 0U) { +- WARN("BootROM: %d DTIMEOUT error\n", +- boot_context->sd_err_dtimeout_cnt); +- } +- +- if (boot_context->sd_err_ctimeout_cnt != 0U) { +- WARN("BootROM: %d CTIMEOUT error\n", +- boot_context->sd_err_ctimeout_cnt); +- } +- +- if (boot_context->sd_err_ccrc_fail_cnt != 0U) { +- WARN("BootROM: %d CCRCFAIL error count\n", +- boot_context->sd_err_ccrc_fail_cnt); +- } +- +- if (boot_context->sd_overall_retry_cnt != 0U) { +- WARN("BootROM: %d command retries\n", +- boot_context->sd_overall_retry_cnt); +- } +-} +-#endif +- +-#if STM32MP_EMMC +-static void print_bootrom_emmc_status(boot_api_context_t *boot_context) +-{ +- INFO("BootROM: %d (0x%x) bytes copied from eMMC\n", +- boot_context->emmc_nbbytes_rxcopied_tosysram_download_area, +- boot_context->emmc_nbbytes_rxcopied_tosysram_download_area); +- +- if (boot_context->emmc_error_status != +- BOOT_API_CTX_EMMC_ERROR_STATUS_NONE) { +- WARN("BootROM eMMC error:\n"); +- switch (boot_context->emmc_error_status) { +- case BOOT_API_CTX_EMMC_ERROR_STATUS_CMD_TIMEOUT: +- WARN(" CMD timeout\n"); +- break; +- case BOOT_API_CTX_EMMC_ERROR_STATUS_ACK_TIMEOUT: +- WARN(" ACK timeout\n"); +- break; +- case BOOT_API_CTX_EMMC_ERROR_STATUS_DATA_CRC_FAIL: +- WARN(" DATA CRC failed\n"); +- break; +- case BOOT_API_CTX_EMMC_ERROR_STATUS_NOT_ENOUGH_BOOT_DATA_RX: +- WARN(" Not enough data copied\n"); +- break; +- case BOOT_API_CTX_EMMC_ERROR_STATUS_HEADER_NOT_FOUND: +- WARN(" Header not found\n"); +- break; +- case BOOT_API_CTX_EMMC_ERROR_STATUS_HEADER_SIZE_ZERO: +- WARN(" Header size is zero\n"); +- break; +- case BOOT_API_CTX_EMMC_ERROR_STATUS_IMAGE_NOT_COMPLETE: +- WARN(" Image not complete\n"); +- break; +- default: +- WARN(" Error not listed\n"); +- break; +- } +- } +- +- switch (boot_context->emmc_xfer_status) { +- case BOOT_API_CTX_EMMC_XFER_STATUS_NOT_STARTED: +- WARN("BootROM: eMMC transfer status:\n"); +- WARN(" not started\n"); +- break; +- case BOOT_API_CTX_EMMC_XFER_STATUS_DATAEND_DETECTED: +- break; +- case BOOT_API_CTX_EMMC_XFER_STATUS_XFER_OVERALL_TIMEOUT_DETECTED: +- WARN("BootROM: eMMC transfer status:\n"); +- WARN(" timeout detected\n"); +- break; +- case BOOT_API_CTX_EMMC_XFER_STATUS_XFER_DATA_TIMEOUT: +- WARN("BootROM: eMMC transfer status:\n"); +- WARN(" data timeout detected\n"); +- break; +- default: +- WARN("BootROM: eMMC transfer status:\n"); +- WARN(" status not listed\n"); +- break; +- } +-} +-#endif +- + #if STM32MP_EMMC || STM32MP_SDMMC + static void boot_mmc(enum mmc_device_type mmc_dev_type, + uint16_t boot_interface_instance) +@@ -437,6 +339,10 @@ static void boot_mmc(enum mmc_device_type mmc_dev_type, + break; + } + ++ if (mmc_dev_type == MMC_IS_SD) { ++ params.flags = MMC_FLAG_SD_CMD6; ++ } ++ + params.device_info = &device_info; + if (stm32_sdmmc2_mmc_init(¶ms) != 0) { + ERROR("SDMMC%u init failed\n", boot_interface_instance); +@@ -641,7 +547,7 @@ static void flash_uart(uint16_t boot_interface_instance) + /* Open connections to devices */ + io_result = io_dev_open(uart_dev_con, (uintptr_t)&uart_programmer, + &image_dev_handle); +- assert(!io_result); ++ assert(io_result == 0); + } + #endif + +@@ -672,7 +578,13 @@ static void flash_usb(struct usb_ctx *usb_context) + usb_core_handle.dev_state = USBD_STATE_CONFIGURED; + + usb_core_handle.class_data = &usb_dfu_handle; ++ + usb_dfu_handle.dev_state = DFU_STATE_IDLE; ++ usb_dfu_handle.dev_status[1] = 0; ++ usb_dfu_handle.dev_status[2] = 0; ++ usb_dfu_handle.dev_status[3] = 0; ++ usb_dfu_handle.dev_status[4] = usb_dfu_handle.dev_state; ++ usb_dfu_handle.dev_status[5] = 0; + + /* Register the IO devices on this platform */ + io_result = register_io_dev_usb(&usb_dev_con); +@@ -711,13 +623,11 @@ void stm32mp_io_setup(void) + switch (boot_context->boot_interface_selected) { + #if STM32MP_SDMMC + case BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_SD: +- print_bootrom_sd_status(boot_context); + boot_mmc(MMC_IS_SD, boot_context->boot_interface_instance); + break; + #endif + #if STM32MP_EMMC + case BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_EMMC: +- print_bootrom_emmc_status(boot_context); + boot_mmc(MMC_IS_EMMC, boot_context->boot_interface_instance); + break; + #endif +diff --git a/plat/st/common/include/stm32mp_common.h b/plat/st/common/include/stm32mp_common.h +index dc2568b6..7e361d5 100644 +--- a/plat/st/common/include/stm32mp_common.h ++++ b/plat/st/common/include/stm32mp_common.h +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. ++ * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +@@ -15,7 +15,7 @@ void __dead2 stm32mp_plat_reset(int cpu); + void stm32mp_save_boot_ctx_address(uintptr_t address); + uintptr_t stm32mp_get_boot_ctx_address(void); + +-int stm32mp_is_single_core(void); ++bool stm32mp_is_single_core(void); + + uintptr_t stm32mp_ddrctrl_base(void); + uintptr_t stm32mp_ddrphyc_base(void); +@@ -24,6 +24,9 @@ uintptr_t stm32mp_rcc_base(void); + + int stm32_gic_enable_spi(int node, const char *name); + ++int stm32_get_otp_index(const char *otp_name, uint32_t *otp_idx, ++ uint32_t *otp_len); ++int stm32_get_otp_value(const char *otp_name, uint32_t *otp_val); + uint32_t stm32_read_otp_status(uint32_t *otp_value, uint32_t word); + uint8_t stm32_iwdg_get_instance(uintptr_t base); + uint32_t stm32_iwdg_get_otp_config(uintptr_t base); +@@ -35,6 +38,10 @@ uint32_t stm32_iwdg_shadow_update(uintptr_t base, uint32_t flags); + uintptr_t stm32_get_gpio_bank_base(unsigned int bank); + int stm32_get_gpio_bank_clock(unsigned int bank); + uint32_t stm32_get_gpio_bank_offset(unsigned int bank); ++ ++bool stm32mp_supports_cpu_opp(uint32_t opp_id); ++bool stm32mp_ddr_supports_ssr_asr(void); ++ + void stm32mp_print_cpuinfo(void); + void stm32mp_print_boardinfo(void); + +diff --git a/plat/st/common/include/stm32mp_dt.h b/plat/st/common/include/stm32mp_dt.h +index ee313d5..581236c 100644 +--- a/plat/st/common/include/stm32mp_dt.h ++++ b/plat/st/common/include/stm32mp_dt.h +@@ -41,10 +41,17 @@ int dt_set_stdout_pinctrl(void); + void dt_fill_device_info(struct dt_node_info *info, int node); + int dt_get_node(struct dt_node_info *info, int offset, const char *compat); + int dt_get_stdout_uart_info(struct dt_node_info *info); ++int dt_get_node_by_compatible(const char *compatible); ++int dt_match_instance_by_compatible(const char *compatible, uintptr_t address); ++uintptr_t dt_get_peripheral_base(const char *compatible); + uint32_t dt_get_ddr_size(void); + uintptr_t dt_get_ddrctrl_base(void); + uintptr_t dt_get_ddrphyc_base(void); ++uintptr_t dt_get_rcc_base(void); + uintptr_t dt_get_pwr_base(void); ++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); + uintptr_t dt_get_syscfg_base(void); + const char *dt_get_board_model(void); +diff --git a/plat/st/common/stm32mp_common.c b/plat/st/common/stm32mp_common.c +index 8efac68..ecc41fc 100644 +--- a/plat/st/common/stm32mp_common.c ++++ b/plat/st/common/stm32mp_common.c +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. ++ * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +@@ -51,9 +51,9 @@ uintptr_t stm32mp_get_boot_ctx_address(void) + */ + #pragma weak stm32mp_is_single_core + +-int stm32mp_is_single_core(void) ++bool stm32mp_is_single_core(void) + { +- return 0; ++ return false; + } + + uintptr_t stm32mp_ddrctrl_base(void) +@@ -100,7 +100,7 @@ uintptr_t stm32mp_rcc_base(void) + static uintptr_t rcc_base; + + if (rcc_base == 0) { +- rcc_base = fdt_rcc_read_addr(); ++ rcc_base = dt_get_rcc_base(); + + assert(rcc_base == RCC_BASE); + } +diff --git a/plat/st/common/stm32mp_dt.c b/plat/st/common/stm32mp_dt.c +index 2f9951b..203b50f 100644 +--- a/plat/st/common/stm32mp_dt.c ++++ b/plat/st/common/stm32mp_dt.c +@@ -337,6 +337,74 @@ int dt_get_stdout_uart_info(struct dt_node_info *info) + } + + /******************************************************************************* ++ * This function returns the node offset matching compatible string in the DT. ++ * It is only valid for single instance peripherals (DDR, RCC, PWR, STGEN, ++ * SYSCFG...). ++ * Returns value on success, and error value on failure. ++ ******************************************************************************/ ++int dt_get_node_by_compatible(const char *compatible) ++{ ++ int node = fdt_node_offset_by_compatible(fdt, -1, compatible); ++ ++ if (node < 0) { ++ INFO("Cannot find %s node in DT\n", compatible); ++ } ++ ++ return node; ++} ++ ++/******************************************************************************* ++ * This function returns the node offset matching compatible string in the DT, ++ * and also matching the reg property with the given address. ++ * Returns value on success, and error value on failure. ++ ******************************************************************************/ ++int dt_match_instance_by_compatible(const char *compatible, uintptr_t address) ++{ ++ int node; ++ ++ for (node = fdt_node_offset_by_compatible(fdt, -1, compatible); ++ node != -FDT_ERR_NOTFOUND; ++ node = fdt_node_offset_by_compatible(fdt, node, compatible)) { ++ const fdt32_t *cuint; ++ ++ cuint = fdt_getprop(fdt, node, "reg", NULL); ++ if (cuint == NULL) { ++ continue; ++ } ++ ++ if ((uintptr_t)fdt32_to_cpu(*cuint) == address) { ++ return node; ++ } ++ } ++ ++ return -FDT_ERR_NOTFOUND; ++} ++ ++/******************************************************************************* ++ * This function returns the peripheral base address information from the ++ * compatible string in the DT. It is only valid for single instance ++ * peripherals (RCC, PWR, STGEN, SYSCFG...). ++ * Returns value on success, and 0 on failure. ++ ******************************************************************************/ ++uintptr_t dt_get_peripheral_base(const char *compatible) ++{ ++ int node; ++ const fdt32_t *cuint; ++ ++ node = dt_get_node_by_compatible(compatible); ++ if (node < 0) { ++ return 0; ++ } ++ ++ cuint = fdt_getprop(fdt, node, "reg", NULL); ++ if (cuint == NULL) { ++ return 0; ++ } ++ ++ return fdt32_to_cpu(*cuint); ++} ++ ++/******************************************************************************* + * This function gets DDR size information from the DT. + * Returns value in bytes on success, and 0 on failure. + ******************************************************************************/ +@@ -344,9 +412,8 @@ uint32_t dt_get_ddr_size(void) + { + int node; + +- node = fdt_node_offset_by_compatible(fdt, -1, DT_DDR_COMPAT); ++ node = dt_get_node_by_compatible(DT_DDR_COMPAT); + if (node < 0) { +- INFO("%s: Cannot read DDR node in DT\n", __func__); + return 0; + } + +@@ -362,9 +429,8 @@ uintptr_t dt_get_ddrctrl_base(void) + int node; + uint32_t array[4]; + +- node = fdt_node_offset_by_compatible(fdt, -1, DT_DDR_COMPAT); ++ node = dt_get_node_by_compatible(DT_DDR_COMPAT); + if (node < 0) { +- INFO("%s: Cannot read DDR node in DT\n", __func__); + return 0; + } + +@@ -384,9 +450,8 @@ uintptr_t dt_get_ddrphyc_base(void) + int node; + uint32_t array[4]; + +- node = fdt_node_offset_by_compatible(fdt, -1, DT_DDR_COMPAT); ++ node = dt_get_node_by_compatible(DT_DDR_COMPAT); + if (node < 0) { +- INFO("%s: Cannot read DDR node in DT\n", __func__); + return 0; + } + +@@ -398,26 +463,186 @@ uintptr_t dt_get_ddrphyc_base(void) + } + + /******************************************************************************* ++ * This function gets RCC base address information from the DT. ++ * Returns value on success, and 0 on failure. ++ ******************************************************************************/ ++uintptr_t dt_get_rcc_base(void) ++{ ++ return dt_get_peripheral_base(DT_RCC_CLK_COMPAT); ++} ++ ++/******************************************************************************* + * This function gets PWR base address information from the DT. + * Returns value on success, and 0 on failure. + ******************************************************************************/ + uintptr_t dt_get_pwr_base(void) + { ++ return dt_get_peripheral_base(DT_PWR_COMPAT); ++} ++ ++/******************************************************************************* ++ * This function gets OPP table node from the DT. ++ * Returns node offset on success and a negative FDT error code on failure. ++ ******************************************************************************/ ++static int dt_get_opp_table_node(void) ++{ ++ return dt_get_node_by_compatible(DT_OPP_COMPAT); ++} ++ ++/******************************************************************************* ++ * This function gets OPP parameters (frequency in KHz and voltage in mV) from ++ * an OPP table subnode. Platform HW support capabilities are also checked. ++ * Returns 0 on success and a negative FDT error code on failure. ++ ******************************************************************************/ ++static int dt_get_opp_freqvolt_from_subnode(int subnode, uint32_t *freq_khz, ++ uint32_t *voltage_mv) ++{ ++ const fdt64_t *cuint64; ++ const fdt32_t *cuint32; ++ uint64_t read_freq_64; ++ uint32_t read_voltage_32; ++ ++ assert(freq_khz != NULL); ++ assert(voltage_mv != NULL); ++ ++ cuint32 = fdt_getprop(fdt, subnode, "opp-supported-hw", NULL); ++ if (cuint32 != NULL) { ++ if (!stm32mp_supports_cpu_opp(fdt32_to_cpu(*cuint32))) { ++ VERBOSE("Invalid opp-supported-hw 0x%x\n", ++ fdt32_to_cpu(*cuint32)); ++ return -FDT_ERR_BADVALUE; ++ } ++ } ++ ++ cuint64 = fdt_getprop(fdt, subnode, "opp-hz", NULL); ++ if (cuint64 == NULL) { ++ VERBOSE("Missing opp-hz\n"); ++ return -FDT_ERR_NOTFOUND; ++ } ++ ++ /* Frequency value expressed in KHz must fit on 32 bits */ ++ read_freq_64 = fdt64_to_cpu(*cuint64) / 1000ULL; ++ if (read_freq_64 > (uint64_t)UINT32_MAX) { ++ VERBOSE("Invalid opp-hz %llu\n", read_freq_64); ++ return -FDT_ERR_BADVALUE; ++ } ++ ++ cuint32 = fdt_getprop(fdt, subnode, "opp-microvolt", NULL); ++ if (cuint32 == NULL) { ++ VERBOSE("Missing opp-microvolt\n"); ++ return -FDT_ERR_NOTFOUND; ++ } ++ ++ /* Millivolt value must fit on 16 bits */ ++ read_voltage_32 = fdt32_to_cpu(*cuint32) / 1000U; ++ if (read_voltage_32 > (uint32_t)UINT16_MAX) { ++ VERBOSE("Invalid opp-microvolt %u\n", read_voltage_32); ++ return -FDT_ERR_BADVALUE; ++ } ++ ++ *freq_khz = (uint32_t)read_freq_64; ++ ++ *voltage_mv = read_voltage_32; ++ ++ return 0; ++} ++ ++/******************************************************************************* ++ * This function parses OPP table in DT and finds the parameters for the ++ * highest frequency supported by the HW platform. ++ * If found, the new frequency and voltage values override the original ones. ++ * Returns 0 on success and a negative FDT error code on failure. ++ ******************************************************************************/ ++int dt_get_max_opp_freqvolt(uint32_t *freq_khz, uint32_t *voltage_mv) ++{ + int node; +- const fdt32_t *cuint; ++ int subnode; ++ uint32_t freq = 0U; ++ uint32_t voltage = 0U; + +- node = fdt_node_offset_by_compatible(fdt, -1, DT_PWR_COMPAT); ++ assert(freq_khz != NULL); ++ assert(voltage_mv != NULL); ++ ++ node = dt_get_opp_table_node(); + if (node < 0) { +- INFO("%s: Cannot read PWR node in DT\n", __func__); +- return 0; ++ return node; + } + +- cuint = fdt_getprop(fdt, node, "reg", NULL); +- if (cuint == NULL) { +- return 0; ++ fdt_for_each_subnode(subnode, fdt, node) { ++ uint32_t read_freq; ++ uint32_t read_voltage; ++ ++ if (dt_get_opp_freqvolt_from_subnode(subnode, &read_freq, ++ &read_voltage) != 0) { ++ continue; ++ } ++ ++ if (read_freq > freq) { ++ freq = read_freq; ++ voltage = read_voltage; ++ } + } + +- return fdt32_to_cpu(*cuint); ++ if ((freq == 0U) || (voltage == 0U)) { ++ return -FDT_ERR_NOTFOUND; ++ } ++ ++ *freq_khz = freq; ++ *voltage_mv = voltage; ++ ++ return 0; ++} ++ ++/******************************************************************************* ++ * This function parses OPP table in DT and finds all parameters supported by ++ * the HW platform. ++ * If found, the corresponding frequency and voltage values are respectively ++ * stored in @*freq_khz_array and @*voltage_mv_array. ++ * Note that @*count has to be set by caller to the effective size allocated ++ * for both tables. Its value is then replaced by the number of filled elements. ++ * Returns 0 on success and a negative FDT error code on failure. ++ ******************************************************************************/ ++int dt_get_all_opp_freqvolt(uint32_t *count, uint32_t *freq_khz_array, ++ uint32_t *voltage_mv_array) ++{ ++ int node; ++ int subnode; ++ int idx = 0; ++ ++ assert(count != NULL); ++ assert(freq_khz_array != NULL); ++ assert(voltage_mv_array != NULL); ++ ++ node = dt_get_opp_table_node(); ++ if (node < 0) { ++ return node; ++ } ++ ++ fdt_for_each_subnode(subnode, fdt, node) { ++ uint32_t read_freq; ++ uint32_t read_voltage; ++ ++ if (dt_get_opp_freqvolt_from_subnode(subnode, &read_freq, ++ &read_voltage) != 0) { ++ continue; ++ } ++ ++ if (idx >= *count) { ++ return -FDT_ERR_NOSPACE; ++ } ++ ++ freq_khz_array[idx] = read_freq; ++ voltage_mv_array[idx] = read_voltage; ++ idx++; ++ } ++ ++ if (idx == 0U) { ++ return -FDT_ERR_NOTFOUND; ++ } ++ ++ *count = idx; ++ ++ return 0; + } + + /******************************************************************************* +@@ -429,9 +654,8 @@ uint32_t dt_get_pwr_vdd_voltage(void) + int node, pwr_regulators_node; + const fdt32_t *cuint; + +- node = fdt_node_offset_by_compatible(fdt, -1, DT_PWR_COMPAT); ++ node = dt_get_node_by_compatible(DT_PWR_COMPAT); + if (node < 0) { +- INFO("%s: Cannot read PWR node in DT\n", __func__); + return 0; + } + +@@ -465,21 +689,7 @@ uint32_t dt_get_pwr_vdd_voltage(void) + ******************************************************************************/ + uintptr_t dt_get_syscfg_base(void) + { +- int node; +- const fdt32_t *cuint; +- +- node = fdt_node_offset_by_compatible(fdt, -1, DT_SYSCFG_COMPAT); +- if (node < 0) { +- INFO("%s: Cannot read SYSCFG node in DT\n", __func__); +- return 0; +- } +- +- cuint = fdt_getprop(fdt, node, "reg", NULL); +- if (cuint == NULL) { +- return 0; +- } +- +- return fdt32_to_cpu(*cuint); ++ return dt_get_peripheral_base(DT_SYSCFG_COMPAT); + } + + /******************************************************************************* +diff --git a/plat/st/stm32mp1/bl2_plat_setup.c b/plat/st/stm32mp1/bl2_plat_setup.c +index 1a2e2d6..ef5a13d 100644 +--- a/plat/st/stm32mp1/bl2_plat_setup.c ++++ b/plat/st/stm32mp1/bl2_plat_setup.c +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved. ++ * Copyright (c) 2015-2020, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +@@ -23,6 +23,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -36,6 +37,7 @@ + #include + #include + #include ++#include + #include + #include + +@@ -146,19 +148,13 @@ void bl2_platform_setup(void) + { + int ret; + +- if (dt_pmic_status() > 0) { +- initialize_pmic(); +-#if STM32MP1_DEBUG_ENABLE +- /* Program PMIC to keep debug ON */ +- if ((stm32mp1_dbgmcu_boot_debug_info() == 1) && +- (stm32mp1_dbgmcu_is_debug_on() != 0)) { +- VERBOSE("Program PMIC to keep debug ON\n"); +- if (pmic_keep_debug_unit() != 0) { +- ERROR("PMIC not properly set for debug\n"); +- } +- } +-#endif +- } ++ /* ++ * Map DDR non cacheable during its initialisation to avoid ++ * speculative loads before accesses are fully setup. ++ */ ++ mmap_add_dynamic_region(STM32MP_DDR_BASE, STM32MP_DDR_BASE, ++ STM32MP_DDR_MAX_SIZE, ++ MT_NON_CACHEABLE | MT_RW | MT_NS); + + ret = stm32mp1_ddr_probe(); + if (ret < 0) { +@@ -166,15 +162,118 @@ void bl2_platform_setup(void) + panic(); + } + ++ mmap_remove_dynamic_region(STM32MP_DDR_BASE, STM32MP_DDR_MAX_SIZE); ++ + #ifdef AARCH32_SP_OPTEE + INFO("BL2 runs OP-TEE setup\n"); ++ ++ /* Map non secure DDR for BL33 load, now with cacheable attribute */ ++ mmap_add_dynamic_region(STM32MP_DDR_BASE, STM32MP_DDR_BASE, ++ dt_get_ddr_size() - STM32MP_DDR_S_SIZE - ++ STM32MP_DDR_SHMEM_SIZE, ++ MT_MEMORY | MT_RW | MT_NS); ++ ++ mmap_add_dynamic_region(STM32MP_DDR_BASE + dt_get_ddr_size() - ++ STM32MP_DDR_S_SIZE - STM32MP_DDR_SHMEM_SIZE, ++ STM32MP_DDR_BASE + dt_get_ddr_size() - ++ STM32MP_DDR_S_SIZE - STM32MP_DDR_SHMEM_SIZE, ++ STM32MP_DDR_S_SIZE, ++ MT_MEMORY | MT_RW | MT_SECURE); ++ + /* Initialize tzc400 after DDR initialization */ + stm32mp1_security_setup(); + #else + INFO("BL2 runs SP_MIN setup\n"); ++ ++ /* Map non secure DDR for BL33 load, now with cacheable attribute */ ++ mmap_add_dynamic_region(STM32MP_DDR_BASE, STM32MP_DDR_BASE, ++ dt_get_ddr_size(), ++ MT_MEMORY | MT_RW | MT_NS); + #endif + } + ++static void update_monotonic_counter(void) ++{ ++ uint32_t version; ++ uint32_t otp; ++ ++ CASSERT(STM32_TF_VERSION <= MAX_MONOTONIC_VALUE, ++ assert_stm32mp1_monotonic_counter_reach_max); ++ ++ /* Check if monotonic counter needs to be incremented */ ++ if (stm32_get_otp_index(MONOTONIC_OTP, &otp, NULL) != 0) { ++ panic(); ++ } ++ ++ if (stm32_get_otp_value(MONOTONIC_OTP, &version) != 0) { ++ panic(); ++ } ++ ++ if ((version + 1U) < BIT(STM32_TF_VERSION)) { ++ uint32_t result; ++ ++ /* Need to increment the monotonic counter */ ++ version = BIT(STM32_TF_VERSION) - 1U; ++ ++ result = bsec_program_otp(version, otp); ++ if (result != BSEC_OK) { ++ ERROR("BSEC: MONOTONIC_OTP program Error %i\n", ++ result); ++ panic(); ++ } ++ INFO("Monotonic counter has been incremented value 0x%x\n", ++ version); ++ } ++} ++ ++static void initialize_clock(bool wakeup_standby) ++{ ++ uint32_t voltage_mv = 0U; ++ uint32_t freq_khz = 0U; ++ int ret; ++ ++ if (wakeup_standby) { ++ stm32_get_pll1_settings_from_context(); ++ } ++ ++ /* ++ * If no pre-defined PLL1 settings in DT, find the highest frequency ++ * in the OPP table (in DT, compatible with plaform capabilities, or ++ * in structure restored in RAM), and set related VDDCORE voltage. ++ * If PLL1 settings found in DT, we consider VDDCORE voltage in DT is ++ * consistent with it. ++ */ ++ if (!fdt_is_pll1_predefined()) { ++ if (wakeup_standby) { ++ ret = stm32mp1_clk_get_maxfreq_opp(&freq_khz, ++ &voltage_mv); ++ } else { ++ ret = dt_get_max_opp_freqvolt(&freq_khz, &voltage_mv); ++ } ++ ++ if (ret != 0) { ++ panic(); ++ } ++ ++ if (dt_pmic_status() > 0) { ++ int read_voltage; ++ const char *name = "buck1"; ++ ++ read_voltage = stpmic1_regulator_voltage_get(name); ++ if (voltage_mv != (uint32_t)read_voltage) { ++ if (stpmic1_regulator_voltage_set(name, ++ (uint16_t)voltage_mv) != 0) { ++ panic(); ++ } ++ } ++ } ++ } ++ ++ if (stm32mp1_clk_init(freq_khz) < 0) { ++ panic(); ++ } ++} ++ + void bl2_el3_plat_arch_setup(void) + { + int32_t result; +@@ -189,6 +288,7 @@ void bl2_el3_plat_arch_setup(void) + tamp_bkpr(BOOT_API_CORE1_MAGIC_NUMBER_TAMP_BCK_REG_IDX); + uint32_t bkpr_core1_addr = + tamp_bkpr(BOOT_API_CORE1_BRANCH_ADDRESS_TAMP_BCK_REG_IDX); ++ bool wakeup_standby = false; + + mmap_add_region(BL_CODE_BASE, BL_CODE_BASE, + BL_CODE_END - BL_CODE_BASE, +@@ -201,14 +301,6 @@ void bl2_el3_plat_arch_setup(void) + #endif + + #ifdef AARCH32_SP_OPTEE +- /* OP-TEE image needs post load processing: keep RAM read/write */ +- mmap_add_region(STM32MP_DDR_BASE + dt_get_ddr_size() - +- STM32MP_DDR_S_SIZE, +- STM32MP_DDR_BASE + dt_get_ddr_size() - +- STM32MP_DDR_S_SIZE, +- STM32MP_DDR_S_SIZE, +- MT_MEMORY | MT_RW | MT_SECURE); +- + mmap_add_region(STM32MP_OPTEE_BASE, STM32MP_OPTEE_BASE, + STM32MP_OPTEE_SIZE, + MT_MEMORY | MT_RW | MT_SECURE); +@@ -216,19 +308,12 @@ void bl2_el3_plat_arch_setup(void) + /* Prevent corruption of preloaded BL32 */ + mmap_add_region(BL32_BASE, BL32_BASE, + BL32_LIMIT - BL32_BASE, +- MT_MEMORY | MT_RO | MT_SECURE); +- ++ MT_RO_DATA | MT_SECURE); + #endif +- /* Map non secure DDR for BL33 load and DDR training area restore */ +- mmap_add_region(STM32MP_DDR_BASE, +- STM32MP_DDR_BASE, +- STM32MP_DDR_MAX_SIZE, +- MT_MEMORY | MT_RW | MT_NS); +- + /* Prevent corruption of preloaded Device Tree */ + mmap_add_region(DTB_BASE, DTB_BASE, + DTB_LIMIT - DTB_BASE, +- MT_MEMORY | MT_RO | MT_SECURE); ++ MT_RO_DATA | MT_SECURE); + + configure_mmu(); + +@@ -301,6 +386,10 @@ void bl2_el3_plat_arch_setup(void) + mmio_write_32(bkpr_core1_magic, 0); + } + ++ if (mmio_read_32(bkpr_core1_addr) != 0U) { ++ wakeup_standby = true; ++ } ++ + generic_delay_timer_init(); + + #ifdef STM32MP_USB +@@ -325,10 +414,16 @@ void bl2_el3_plat_arch_setup(void) + panic(); + } + +- if (stm32mp1_clk_init() < 0) { +- panic(); ++ if (dt_pmic_status() > 0) { ++ initialize_pmic(); ++ ++ if (!wakeup_standby) { ++ configure_pmic(); ++ } + } + ++ initialize_clock(wakeup_standby); ++ + stm32mp1_syscfg_init(); + + result = dt_get_stdout_uart_info(&dt_uart_info); +@@ -418,6 +513,23 @@ skip_console_init: + + print_reset_reason(); + ++ if (dt_pmic_status() > 0) { ++ initialize_pmic(); ++ print_pmic_info_and_debug(); ++#if STM32MP1_DEBUG_ENABLE ++ /* Program PMIC to keep debug ON */ ++ if ((stm32mp1_dbgmcu_boot_debug_info() == 1) && ++ (stm32mp1_dbgmcu_is_debug_on())) { ++ VERBOSE("Program PMIC to keep debug ON\n"); ++ if (pmic_keep_debug_unit() != 0) { ++ ERROR("PMIC not properly set for debug\n"); ++ } ++ } ++#endif ++ } ++ ++ update_monotonic_counter(); ++ + stm32mp_io_setup(); + } + +@@ -438,11 +550,12 @@ static void set_mem_params_info(entry_point_info_t *ep_info, + unpaged->image_max_size = STM32MP_OPTEE_SIZE; + } else { + unpaged->image_base = STM32MP_DDR_BASE + dt_get_ddr_size() - +- STM32MP_DDR_S_SIZE; ++ STM32MP_DDR_S_SIZE - ++ STM32MP_DDR_SHMEM_SIZE; + unpaged->image_max_size = STM32MP_DDR_S_SIZE; + } + paged->image_base = STM32MP_DDR_BASE + dt_get_ddr_size() - +- STM32MP_DDR_S_SIZE; ++ STM32MP_DDR_S_SIZE - STM32MP_DDR_SHMEM_SIZE; + paged->image_max_size = STM32MP_DDR_S_SIZE; + } + #endif +diff --git a/plat/st/stm32mp1/include/stm32mp1_context.h b/plat/st/stm32mp1/include/stm32mp1_context.h +index 4cd6643..ba325c5 100644 +--- a/plat/st/stm32mp1/include/stm32mp1_context.h ++++ b/plat/st/stm32mp1/include/stm32mp1_context.h +@@ -15,8 +15,11 @@ + void stm32_clean_context(void); + int stm32_save_context(uint32_t zq0cr0_zdata); + int stm32_restore_context(void); ++unsigned long long stm32_get_stgen_from_context(void); + int stm32_restore_backup_reg(void); + uint32_t stm32_get_zdata_from_context(void); ++void stm32_get_pll1_settings_from_context(void); ++bool stm32_are_pll1_settings_valid_in_context(void); + int stm32_save_boot_interface(uint32_t interface, uint32_t instance); + int stm32_get_boot_interface(uint32_t *interface, uint32_t *instance); + void stm32_save_ddr_training_area(void); +diff --git a/plat/st/stm32mp1/include/stm32mp1_dbgmcu.h b/plat/st/stm32mp1/include/stm32mp1_dbgmcu.h +index fd97a16..c3cb0b3 100644 +--- a/plat/st/stm32mp1/include/stm32mp1_dbgmcu.h ++++ b/plat/st/stm32mp1/include/stm32mp1_dbgmcu.h +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. ++ * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +@@ -15,12 +15,12 @@ + #define VERBOSE_HEXDUMP8(buf, len) + #endif + +-uint32_t stm32mp1_dbgmcu_get_chip_version(void); +-uint32_t stm32mp1_dbgmcu_get_chip_dev_id(void); ++int stm32mp1_dbgmcu_get_chip_version(uint32_t *chip_version); ++int stm32mp1_dbgmcu_get_chip_dev_id(uint32_t *chip_dev_id); + int stm32mp1_dbgmcu_freeze_iwdg2(void); + int stm32mp1_dbgmcu_boot_debug_info(void); +-int stm32mp1_dbgmcu_clear_boot_info(void); +-uint32_t stm32mp1_dbgmcu_is_debug_on(void); ++void stm32mp1_dbgmcu_clear_boot_info(void); ++bool stm32mp1_dbgmcu_is_debug_on(void); + void stm32mp1_dbgmcu_hexdump8(uint8_t *buf, uint32_t len); + + #endif /* __PLAT_DBGMCU_H__ */ +diff --git a/plat/st/stm32mp1/include/stm32mp1_smc.h b/plat/st/stm32mp1/include/stm32mp1_smc.h +index 956493f..7014ff7 100644 +--- a/plat/st/stm32mp1/include/stm32mp1_smc.h ++++ b/plat/st/stm32mp1/include/stm32mp1_smc.h +@@ -1,68 +1,169 @@ + /* +- * Copyright (c) 2016-2018, STMicroelectronics - All Rights Reserved ++ * Copyright (c) 2016-2019, STMicroelectronics - All Rights Reserved + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +-#ifndef __STM32MP1_SMC_H__ +-#define __STM32MP1_SMC_H__ ++#ifndef STM32MP1_SMC_H ++#define STM32MP1_SMC_H + + #include + ++/* SMC service generic return codes */ ++#define STM32_SMC_OK 0x00000000U ++#define STM32_SMC_NOT_SUPPORTED 0xFFFFFFFFU ++#define STM32_SMC_FAILED 0xFFFFFFFEU ++#define STM32_SMC_INVALID_PARAMS 0xFFFFFFFDU ++ + /* +- * SMC function IDs for STM32 Service queries ++ * SMC function IDs for STM32 Service queries. + * STM32 SMC services use the space between 0x82000000 and 0x8200FFFF + * like this is defined in SMC calling Convention by ARM +- * for SiP (silicon Partner) ++ * for SiP (silicon Partner). + * https://developer.arm.com/docs/den0028/latest + */ + + /* Secure Service access from Non-secure */ ++ ++/* ++ * SMC function STM32_SMC_RCC. ++ * ++ * Argument a0: (input) SMCC ID. ++ * (output) Status return code. ++ * Argument a1: (input) Service ID (STM32_SMC_REG_xxx). ++ * Argument a2: (input) Register offset or physical address. ++ * (output) Register read value, if applicable. ++ * Argument a3: (input) Register target value if applicable. ++ */ + #define STM32_SMC_RCC 0x82001000 ++ ++/* ++ * SMC function STM32_SMC_PWR. ++ * ++ * Argument a0: (input) SMCC ID. ++ * (output) Status return code. ++ * Argument a1: (input) Service ID (STM32_SMC_REG_xxx). ++ * Argument a2: (input) Register offset or physical address. ++ * (output) Register read value, if applicable. ++ * Argument a3: (input) Register target value if applicable. ++ */ + #define STM32_SMC_PWR 0x82001001 ++ ++/* ++ * SMC functions STM32_SMC_RCC_CAL. ++ * ++ * Argument a0: (input) SMCC ID. ++ * (output) Status return code. ++ * Argument a1: (input) Clock ID (from DT clock bindings). ++ */ + #define STM32_SMC_RCC_CAL 0x82001002 ++ ++/* ++ * SMC functions STM32_SMC_BSEC. ++ * ++ * Argument a0: (input) SMCC ID. ++ * (output) Status return code. ++ * Argument a1: (input) Service ID (STM32_SMC_READ_xxx/_PROG_xxx/_WRITE_xxx). ++ * (output) OTP read value, if applicable. ++ * Argument a2: (input) OTP index. ++ * Argument a3: (input) OTP value if applicable. ++ */ + #define STM32_SMC_BSEC 0x82001003 + + /* Low Power services */ ++ ++/* ++ * SIP functions STM32_SMC_SR_MODE. ++ * ++ * Argument a0: (input) SMCC ID. ++ * (output) Status return code. ++ * Argument a1: (unused). ++ * Argument a2: (input) Target selfrefresh mode (STM32_SMC_SR_MODE_xxx). ++ */ + #define STM32_SMC_SR_MODE 0x82001004 ++ ++/* ++ * SIP function STM32_SMC_PD_DOMAIN. ++ * ++ * Argument a0: (input) SMCC ID. ++ * (output) Status return code. ++ * Argument a2: (index) ID of target power domain to be enabled/disabled. ++ * Argument a3: (input) 0 to disable, 1 to enable target domain. ++ */ + #define STM32_SMC_PD_DOMAIN 0x82001008 + ++/* ++ * SIP function STM32_SMC_RCC_OPP. ++ * ++ * Argument a0: (input) SMCC ID. ++ * (output) Status return code. ++ * Argument a1: (input) Service ID (STM32_SMC_RCC_OPP_xxx). ++ * (output) Rounded frequency, if applicable. ++ * Argument a2: (input) Requested frequency. ++ */ ++#define STM32_SMC_RCC_OPP 0x82001009 ++ + /* SMC function IDs for SiP Service queries */ ++ ++/* ++ * SIP function STM32_SIP_SVC_CALL_COUNT. ++ * ++ * Argument a0: (input) SMCC ID. ++ * (output) Dummy value 0. ++ */ + #define STM32_SIP_SVC_CALL_COUNT 0x8200ff00 ++ ++/* ++ * SIP function STM32_SIP_SVC_UID. ++ * ++ * Argument a0: (input) SMCC ID. ++ * (output) Lowest 32bit of the stm32mp1 SIP service UUID. ++ * Argument a1: (output) Next 32bit of the stm32mp1 SIP service UUID. ++ * Argument a2: (output) Next 32bit of the stm32mp1 SIP service UUID. ++ * Argument a3: (output) Last 32bit of the stm32mp1 SIP service UUID. ++ */ + #define STM32_SIP_SVC_UID 0x8200ff01 +-/* 0x8200ff02 is reserved */ +-#define STM32_SIP_SVC_VERSION 0x8200ff03 + +-/* STM32 SiP Service Calls version numbers */ +-#define STM32_SIP_SVC_VERSION_MAJOR 0x0 +-#define STM32_SIP_SVC_VERSION_MINOR 0x1 ++/* 0x8200ff02 is reserved */ + +-/* Number of STM32 SiP Calls implemented */ +-#define STM32_COMMON_SIP_NUM_CALLS 10 ++/* ++ * SIP function STM32_SIP_SVC_VERSION. ++ * ++ * Argument a0: (input) SMCC ID. ++ * (output) STM32 SIP service major. ++ * Argument a1: (output) STM32 SIP service minor. ++ */ ++#define STM32_SIP_SVC_VERSION 0x8200ff03 + +-/* Register access service use for RCC/RTC/PWR */ ++/* Service ID for STM32_SMC_RCC/_PWR */ + #define STM32_SMC_REG_READ 0x0 + #define STM32_SMC_REG_WRITE 0x1 + #define STM32_SMC_REG_SET 0x2 + #define STM32_SMC_REG_CLEAR 0x3 + +-/* Service for BSEC */ ++/* Service ID for STM32_SMC_BSEC */ + #define STM32_SMC_READ_SHADOW 0x01 + #define STM32_SMC_PROG_OTP 0x02 + #define STM32_SMC_WRITE_SHADOW 0x03 + #define STM32_SMC_READ_OTP 0x04 + #define STM32_SMC_READ_ALL 0x05 + #define STM32_SMC_WRITE_ALL 0x06 +- +-/* SMC error codes */ +-#define STM32_SMC_OK 0x00000000U +-#define STM32_SMC_NOT_SUPPORTED 0xFFFFFFFFU +-#define STM32_SMC_FAILED 0xFFFFFFFEU +-#define STM32_SMC_INVALID_PARAMS 0xFFFFFFFDU ++#define STM32_SMC_WRLOCK_OTP 0x07 + + /* DDR Self-Refresh modes */ + #define STM32_SMC_SR_MODE_SSR 0x0 + #define STM32_SMC_SR_MODE_ASR 0x1 + #define STM32_SMC_SR_MODE_HSR 0x2 + +-#endif /* __STM32MP1_SMC_H__ */ ++/* Service ID for STM32_SMC_RCC_OPP */ ++#define STM32_SMC_RCC_OPP_SET 0x0 ++#define STM32_SMC_RCC_OPP_ROUND 0x1 ++ ++/* STM32 SiP Service Calls version numbers */ ++#define STM32_SIP_SVC_VERSION_MAJOR 0x0 ++#define STM32_SIP_SVC_VERSION_MINOR 0x1 ++ ++/* Number of STM32 SiP Calls implemented */ ++#define STM32_COMMON_SIP_NUM_CALLS 11 ++ ++#endif /* STM32MP1_SMC_H */ +diff --git a/plat/st/stm32mp1/plat_image_load.c b/plat/st/stm32mp1/plat_image_load.c +index db53c37..a6ca9ce 100644 +--- a/plat/st/stm32mp1/plat_image_load.c ++++ b/plat/st/stm32mp1/plat_image_load.c +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved. ++ * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +@@ -7,7 +7,6 @@ + #include + #include + #include +-#include + #include + #include + #include +@@ -28,37 +27,7 @@ + ******************************************************************************/ + void plat_flush_next_bl_params(void) + { +- uint32_t version; +- + flush_bl_params_desc(); +- +- CASSERT(STM32_TF_VERSION <= MAX_MONOTONIC_VALUE, +- assert_stm32mp1_monotonic_counter_reach_max); +- +- /* Check if monotonic counter need to be incremented */ +- ; +- if (bsec_shadow_read_otp(&version, MONOTONIC_OTP) != BSEC_OK) { +- ERROR("BSEC: MONOTONIC_OTP Error\n"); +- panic(); +- } +- +- INFO("read version %i current version %i\n", version, STM32_TF_VERSION); +- +- if ((version + 1U) < BIT(STM32_TF_VERSION)) { +- uint32_t result; +- +- /* need to increment the monotonic counter */ +- version = BIT(STM32_TF_VERSION) - 1U; +- +- result = bsec_program_otp(version, MONOTONIC_OTP); +- if (result != BSEC_OK) { +- ERROR("BSEC: MONOTONIC_OTP program Error %i\n", +- result); +- panic(); +- } +- INFO("Monotonic counter has been incremented value 0x%x\n", +- version); +- } + } + + #ifdef AARCH32_SP_OPTEE +@@ -121,7 +90,13 @@ bl_load_info_t *plat_get_bl_image_load_info(void) + stm32mp_clk_disable(RTCAPB); + } + +- bl33->image_info.image_max_size = dt_get_ddr_size(); ++ /* Max size is non-secure DDR end address minus image_base */ ++ bl33->image_info.image_max_size = dt_get_ddr_size() - ++#ifdef AARCH32_SP_OPTEE ++ STM32MP_DDR_S_SIZE - ++ STM32MP_DDR_SHMEM_SIZE - ++#endif ++ bl33->image_info.image_base; + + return get_bl_load_info_from_mem_params_desc(); + } +diff --git a/plat/st/stm32mp1/platform.mk b/plat/st/stm32mp1/platform.mk +index 91bb1ca..31cc273 100644 +--- a/plat/st/stm32mp1/platform.mk ++++ b/plat/st/stm32mp1/platform.mk +@@ -1,5 +1,5 @@ + # +-# Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved. ++# Copyright (c) 2015-2020, ARM Limited and Contributors. All rights reserved. + # + # SPDX-License-Identifier: BSD-3-Clause + # +@@ -11,7 +11,7 @@ USE_COHERENT_MEM := 0 + MULTI_CONSOLE_API := 1 + + # Add specific ST version +-ST_VERSION := r1.5 ++ST_VERSION := r3.0 + VERSION_STRING := v${VERSION_MAJOR}.${VERSION_MINOR}-${ST_VERSION}(${BUILD_TYPE}):${BUILD_STRING} + + # Please don't increment this value without good understanding of +@@ -19,6 +19,11 @@ VERSION_STRING := v${VERSION_MAJOR}.${VERSION_MINOR}-${ST_VERSION}(${BUILD_TYPE + STM32_TF_VERSION ?= 0 + $(eval $(call add_define_val,STM32_TF_VERSION,${STM32_TF_VERSION})) + ++# Enable dynamic memory mapping ++PLAT_XLAT_TABLES_DYNAMIC := 1 ++$(eval $(call assert_boolean,PLAT_XLAT_TABLES_DYNAMIC)) ++$(eval $(call add_define,PLAT_XLAT_TABLES_DYNAMIC)) ++ + # Enable software PMIC programming in case of debug purpose + STM32MP1_DEBUG_ENABLE ?= 1 + $(eval $(call add_define_val,STM32MP1_DEBUG_ENABLE,${STM32MP1_DEBUG_ENABLE})) +@@ -134,6 +139,8 @@ PLAT_BL_COMMON_SOURCES += ${LIBFDT_SRCS} \ + 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 \ +@@ -219,7 +226,7 @@ STM32IMAGE ?= ${STM32IMAGEPATH}/stm32image${BIN_EXT} + .PHONY: ${STM32_TF_STM32} + .SUFFIXES: + +-all: check_dtc_version ${STM32_TF_STM32} stm32image ++all: check_dtc_version stm32image ${STM32_TF_STM32} + + ifeq ($(AARCH32_SP),sp_min) + # BL32 is built only if using SP_MIN +@@ -232,6 +239,8 @@ distclean realclean clean: clean_stm32image + stm32image: + ${Q}${MAKE} CPPFLAGS="" --no-print-directory -C ${STM32IMAGEPATH} + ++${STM32IMAGE}: stm32image ++ + clean_stm32image: + ${Q}${MAKE} --no-print-directory -C ${STM32IMAGEPATH} clean + +@@ -266,7 +275,7 @@ ${STM32_TF_BINARY}: ${STM32_TF_ELF} + @echo "Built $@ successfully" + @echo + +-${STM32_TF_STM32}: stm32image ${STM32_TF_BINARY} ++${STM32_TF_STM32}: ${STM32IMAGE} ${STM32_TF_BINARY} + @echo + @echo "Generated $@" + $(eval LOADADDR = $(shell cat ${STM32_TF_MAPFILE} | grep RAM | awk '{print $$2}')) +diff --git a/plat/st/stm32mp1/services/bsec_svc.c b/plat/st/stm32mp1/services/bsec_svc.c +index b13580d..85cf3c6 100644 +--- a/plat/st/stm32mp1/services/bsec_svc.c ++++ b/plat/st/stm32mp1/services/bsec_svc.c +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 2016-2018, STMicroelectronics - All Rights Reserved ++ * Copyright (c) 2016-2020, STMicroelectronics - All Rights Reserved + * + * SPDX-License-Identifier: BSD-3-Clause + */ +@@ -94,6 +94,7 @@ static enum bsec_ssp_status bsec_check_ssp(uint32_t otp, uint32_t update) + return BSEC_NO_SSP; + } + ++#if STM32MP_USB || STM32MP_UART_PROGRAMMER + static uint32_t bsec_read_all_bsec(struct otp_exchange *exchange) + { + uint32_t i; +@@ -382,6 +383,7 @@ static uint32_t bsec_write_all_bsec(struct otp_exchange *exchange, + + return BSEC_OK; + } ++#endif /* STM32MP_USB || STM32MP_UART_PROGRAMMER */ + + uint32_t bsec_main(uint32_t x1, uint32_t x2, uint32_t x3, + uint32_t *ret_otp_value) +@@ -391,14 +393,16 @@ uint32_t bsec_main(uint32_t x1, uint32_t x2, uint32_t x3, + + if ((x1 != STM32_SMC_READ_ALL) && (x1 != STM32_SMC_WRITE_ALL) && + (bsec_check_nsec_access_rights(x2) != BSEC_OK)) { +- return BSEC_ERROR; ++ return STM32_SMC_INVALID_PARAMS; + } + ++#if STM32MP_USB || STM32MP_UART_PROGRAMMER + if (((x1 == STM32_SMC_READ_ALL) || (x1 == STM32_SMC_WRITE_ALL)) && + (!ddr_is_nonsecured_area((uintptr_t)x2, + sizeof(struct otp_exchange)))) { +- return BSEC_ERROR; ++ return STM32_SMC_INVALID_PARAMS; + } ++#endif + + switch (x1) { + case STM32_SMC_READ_SHADOW: +@@ -443,6 +447,7 @@ uint32_t bsec_main(uint32_t x1, uint32_t x2, uint32_t x3, + + result = bsec_write_otp(tmp_data, x2); + break; ++#if STM32MP_USB || STM32MP_UART_PROGRAMMER + case STM32_SMC_READ_ALL: + result = bsec_read_all_bsec((struct otp_exchange *)x2); + break; +@@ -450,10 +455,13 @@ uint32_t bsec_main(uint32_t x1, uint32_t x2, uint32_t x3, + result = bsec_write_all_bsec((struct otp_exchange *)x2, + ret_otp_value); + break; +- default: +- result = BSEC_ERROR; ++#endif ++ case STM32_SMC_WRLOCK_OTP: ++ result = bsec_permanent_lock_otp(x2); + break; ++ default: ++ return STM32_SMC_INVALID_PARAMS; + } + +- return result; ++ return (result == BSEC_OK) ? STM32_SMC_OK : STM32_SMC_FAILED; + } +diff --git a/plat/st/stm32mp1/services/rcc_svc.c b/plat/st/stm32mp1/services/rcc_svc.c +index 6e8f9d0..3dc4ab0 100644 +--- a/plat/st/stm32mp1/services/rcc_svc.c ++++ b/plat/st/stm32mp1/services/rcc_svc.c +@@ -1,6 +1,5 @@ + /* +- * Copyright (c) 2017-2018, STMicroelectronics - All Rights Reserved +- * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. ++ * Copyright (c) 2017-2019, STMicroelectronics - All Rights Reserved + * + * SPDX-License-Identifier: BSD-3-Clause + */ +@@ -475,3 +474,34 @@ uint32_t rcc_cal_scv_handler(uint32_t x1) + + return ret; + } ++ ++uint32_t rcc_opp_scv_handler(uint32_t x1, uint32_t x2, uint32_t *res) ++{ ++ uint32_t cmd = x1; ++ uint32_t opp = x2 / 1000U; /* KHz */ ++ ++ switch (cmd) { ++ case STM32_SMC_RCC_OPP_SET: ++ if (stm32mp1_set_opp_khz(opp) != 0) { ++ return STM32_SMC_FAILED; ++ } ++ break; ++ ++ case STM32_SMC_RCC_OPP_ROUND: ++ if (stm32mp1_round_opp_khz(&opp) != 0) { ++ return STM32_SMC_FAILED; ++ } ++ ++ if (opp > (UINT32_MAX / 1000U)) { ++ return STM32_SMC_FAILED; ++ } ++ ++ *res = opp * 1000U; ++ break; ++ ++ default: ++ return STM32_SMC_INVALID_PARAMS; ++ } ++ ++ return STM32_SMC_OK; ++} +diff --git a/plat/st/stm32mp1/services/rcc_svc.h b/plat/st/stm32mp1/services/rcc_svc.h +index 75d4a3c..23c7582 100644 +--- a/plat/st/stm32mp1/services/rcc_svc.h ++++ b/plat/st/stm32mp1/services/rcc_svc.h +@@ -1,6 +1,5 @@ + /* +- * Copyright (c) 2017, STMicroelectronics - All Rights Reserved +- * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. ++ * Copyright (c) 2017-2019, STMicroelectronics - All Rights Reserved + * + * SPDX-License-Identifier: BSD-3-Clause + */ +@@ -10,5 +9,6 @@ + + uint32_t rcc_scv_handler(uint32_t x1, uint32_t x2, uint32_t x3); + uint32_t rcc_cal_scv_handler(uint32_t x1); ++uint32_t rcc_opp_scv_handler(uint32_t x1, uint32_t x2, uint32_t *res); + + #endif /* RCC_SVC_H */ +diff --git a/plat/st/stm32mp1/services/stm32mp1_svc_setup.c b/plat/st/stm32mp1/services/stm32mp1_svc_setup.c +index fff91c0..cabaf16 100644 +--- a/plat/st/stm32mp1/services/stm32mp1_svc_setup.c ++++ b/plat/st/stm32mp1/services/stm32mp1_svc_setup.c +@@ -1,6 +1,5 @@ + /* +- * Copyright (c) 2014-2018, STMicroelectronics - All Rights Reserved +- * Copyright (c) 2014, ARM Limited and Contributors. All rights reserved. ++ * Copyright (c) 2014-2020, STMicroelectronics - All Rights Reserved + * + * SPDX-License-Identifier: BSD-3-Clause + */ +@@ -74,6 +73,11 @@ static uintptr_t stm32mp1_svc_smc_handler(uint32_t smc_fid, u_register_t x1, + ret1 = rcc_cal_scv_handler(x1); + break; + ++ case STM32_SMC_RCC_OPP: ++ ret1 = rcc_opp_scv_handler(x1, x2, &ret2); ++ ret2_enabled = true; ++ break; ++ + case STM32_SMC_PWR: + ret1 = pwr_scv_handler(x1, x2, x3); + break; +@@ -88,7 +92,7 @@ static uintptr_t stm32mp1_svc_smc_handler(uint32_t smc_fid, u_register_t x1, + + default: + WARN("Unimplemented STM32MP1 Service Call: 0x%x\n", smc_fid); +- ret1 = SMC_UNK; ++ ret1 = STM32_SMC_NOT_SUPPORTED; + break; + } + +diff --git a/plat/st/stm32mp1/sp_min/sp_min_setup.c b/plat/st/stm32mp1/sp_min/sp_min_setup.c +index 8748b68..1d87080 100644 +--- a/plat/st/stm32mp1/sp_min/sp_min_setup.c ++++ b/plat/st/stm32mp1/sp_min/sp_min_setup.c +@@ -33,6 +33,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -97,6 +98,29 @@ static void configure_wakeup_interrupt(void) + plat_ic_set_interrupt_priority(irq_num, STM32MP1_IRQ_RCC_SEC_PRIO); + } + ++static void initialize_pll1_settings(void) ++{ ++ uint32_t vddcore_voltage = 0U; ++ int ret; ++ ++ if (stm32_are_pll1_settings_valid_in_context()) { ++ return; ++ } ++ ++ if (dt_pmic_status() > 0) { ++ ret = stpmic1_regulator_voltage_get("buck1"); ++ if (ret < 0) { ++ panic(); ++ } ++ ++ vddcore_voltage = (uint32_t)ret; ++ } ++ ++ if (stm32mp1_clk_compute_all_pll1_settings(vddcore_voltage) != 0) { ++ panic(); ++ } ++} ++ + /******************************************************************************* + * Interrupt handler for FIQ (secure IRQ) + ******************************************************************************/ +@@ -299,6 +323,8 @@ void sp_min_early_platform_setup2(u_register_t arg0, u_register_t arg1, + initialize_pmic(); + } + ++ initialize_pll1_settings(); ++ + stm32mp1_init_lp_states(); + } + +diff --git a/plat/st/stm32mp1/stm32mp1_context.c b/plat/st/stm32mp1/stm32mp1_context.c +index 8dc1146..362b672 100644 +--- a/plat/st/stm32mp1/stm32mp1_context.c ++++ b/plat/st/stm32mp1/stm32mp1_context.c +@@ -28,24 +28,46 @@ + #define TRAINING_AREA_SIZE 64 + + #ifdef AARCH32_SP_OPTEE +-/* OPTEE_MAILBOX_MAGIC relates to struct backup_data_s as defined */ +-#define OPTEE_MAILBOX_MAGIC_V1 0x01 +-#define OPTEE_MAILBOX_MAGIC ((OPTEE_MAILBOX_MAGIC_V1 << 16) + \ +- TRAINING_AREA_SIZE) ++/* ++ * OPTEE_MAILBOX_MAGIC relates to struct backup_data_s as defined ++ * ++ * OPTEE_MAILBOX_MAGIC_V1: ++ * Context provides magic, resume entry, zq0cr0 zdata and DDR training buffer. ++ * ++ * OPTEE_MAILBOX_MAGIC_V2: ++ * Context provides magic, resume entry, zq0cr0 zdata, DDR training buffer ++ * and PLL1 dual OPP settings structure (86 bytes). ++ */ ++#define OPTEE_MAILBOX_MAGIC_V1 (0x0001 << 16) ++#define OPTEE_MAILBOX_MAGIC_V2 (0x0002 << 16) ++#define OPTEE_MAILBOX_MAGIC (OPTEE_MAILBOX_MAGIC_V2 | \ ++ TRAINING_AREA_SIZE) ++ ++#if (PLAT_MAX_OPP_NB != 2) || (PLAT_MAX_PLLCFG_NB != 6) ++#error OPTEE_MAILBOX_MAGIC_V1 does not support expected PLL1 settings ++#endif + #endif + ++/* pll_settings structure size definitions (reference to clock driver) */ ++#define PLL1_SETTINGS_SIZE (((PLAT_MAX_OPP_NB * \ ++ (PLAT_MAX_PLLCFG_NB + 3)) + 1) * \ ++ sizeof(uint32_t)) ++ + struct backup_data_s { + #ifdef AARCH32_SP_OPTEE + uint32_t magic; + uint32_t core0_resume_hint; + uint32_t zq0cr0_zdata; + uint8_t ddr_training_backup[TRAINING_AREA_SIZE]; ++ uint8_t pll1_settings[PLL1_SETTINGS_SIZE]; + #else + smc_ctx_t saved_smc_context[PLATFORM_CORE_COUNT]; + cpu_context_t saved_cpu_context[PLATFORM_CORE_COUNT]; + uint32_t zq0cr0_zdata; + struct stm32_rtc_calendar rtc; + uint8_t ddr_training_backup[TRAINING_AREA_SIZE]; ++ uint8_t pll1_settings[PLL1_SETTINGS_SIZE]; ++ unsigned long long stgen; + #endif + }; + +@@ -106,6 +128,10 @@ int stm32_save_context(uint32_t zq0cr0_zdata) + backup_data->zq0cr0_zdata = zq0cr0_zdata; + + stm32_rtc_get_calendar(&backup_data->rtc); ++ backup_data->stgen = stm32mp1_stgen_get_counter(); ++ ++ stm32mp1_clk_lp_save_opp_pll1_settings(backup_data->pll1_settings, ++ sizeof(backup_data->pll1_settings)); + + stm32mp_clk_disable(BKPSRAM); + +@@ -137,16 +163,35 @@ int stm32_restore_context(void) + memcpy(cpu_context, backup_data->saved_cpu_context, + sizeof(cpu_context_t) * PLATFORM_CORE_COUNT); + +- /* update STGEN counter with standby mode length */ ++ /* Restore STGEN counter with standby mode length */ + stm32_rtc_get_calendar(¤t_calendar); + stdby_time_in_ms = stm32_rtc_diff_calendar(¤t_calendar, + &backup_data->rtc); +- stm32mp1_stgen_increment(stdby_time_in_ms); ++ stm32mp1_stgen_restore_counter(backup_data->stgen, stdby_time_in_ms); ++ ++ stm32mp1_clk_lp_load_opp_pll1_settings(backup_data->pll1_settings, ++ sizeof(backup_data->pll1_settings)); + + stm32mp_clk_disable(BKPSRAM); + + return 0; + } ++ ++unsigned long long stm32_get_stgen_from_context(void) ++{ ++ struct backup_data_s *backup_data; ++ unsigned long long stgen_cnt; ++ ++ stm32mp_clk_enable(BKPSRAM); ++ ++ backup_data = (struct backup_data_s *)STM32MP_BACKUP_RAM_BASE; ++ ++ stgen_cnt = backup_data->stgen; ++ ++ stm32mp_clk_disable(BKPSRAM); ++ ++ return stgen_cnt; ++} + #endif /*AARCH32_SP_OPTEE*/ + + uint32_t stm32_get_zdata_from_context(void) +@@ -166,6 +211,40 @@ uint32_t stm32_get_zdata_from_context(void) + return zdata; + } + ++void stm32_get_pll1_settings_from_context(void) ++{ ++ struct backup_data_s *backup_data; ++ uint8_t *data; ++ ++ stm32mp_clk_enable(BKPSRAM); ++ ++ backup_data = (struct backup_data_s *)STM32MP_BACKUP_RAM_BASE; ++ ++ data = (uint8_t *)backup_data->pll1_settings; ++ stm32mp1_clk_lp_load_opp_pll1_settings(data, ++ sizeof(backup_data->pll1_settings)); ++ ++ stm32mp_clk_disable(BKPSRAM); ++} ++ ++bool stm32_are_pll1_settings_valid_in_context(void) ++{ ++ struct backup_data_s *backup_data; ++ uint32_t *data; ++ bool is_valid; ++ ++ stm32mp_clk_enable(BKPSRAM); ++ ++ backup_data = (struct backup_data_s *)STM32MP_BACKUP_RAM_BASE; ++ data = (uint32_t *)backup_data->pll1_settings; ++ ++ is_valid = (data[0] == PLL1_SETTINGS_VALID_ID); ++ ++ stm32mp_clk_disable(BKPSRAM); ++ ++ return is_valid; ++} ++ + int stm32_save_boot_interface(uint32_t interface, uint32_t instance) + { + uint32_t bkpr_itf_idx = tamp_bkpr(TAMP_BOOT_ITF_BACKUP_REG_ID); +diff --git a/plat/st/stm32mp1/stm32mp1_dbgmcu.c b/plat/st/stm32mp1/stm32mp1_dbgmcu.c +index 716f7d8..39cf5d7 100644 +--- a/plat/st/stm32mp1/stm32mp1_dbgmcu.c ++++ b/plat/st/stm32mp1/stm32mp1_dbgmcu.c +@@ -1,9 +1,10 @@ + /* +- * Copyright (c) 2016-2018, STMicroelectronics - All Rights Reserved ++ * Copyright (c) 2016-2019, STMicroelectronics - All Rights Reserved + * + * SPDX-License-Identifier: BSD-3-Clause + */ + ++#include + #include + #include + #include +@@ -16,8 +17,12 @@ + #include + + #define DBGMCU_IDC 0x0U +-#define IDC_DEV_ID_MASK GENMASK(11, 0) + #define DBGMCU_APB4FZ1 0x2CU ++ ++#define DBGMCU_IDC_DEV_ID_MASK GENMASK(11, 0) ++#define DBGMCU_IDC_REV_ID_MASK GENMASK(31, 16) ++#define DBGMCU_IDC_REV_ID_SHIFT 16 ++ + #define DBGMCU_APB4FZ1_IWDG2 BIT(2) + + #define TAMP_DBG_BACKUP_REG_ID 20 +@@ -55,6 +60,10 @@ static int stm32mp1_dbgmcu_init(void) + } + + #if STM32MP1_DEBUG_ENABLE ++/* ++ * @brief Get debug mode information from backup registers. ++ * @retval 1 if debug mode is enabled, 0 otherwise. ++ */ + int stm32mp1_dbgmcu_boot_debug_info(void) + { + uint32_t backup_reg_dbg; +@@ -73,7 +82,11 @@ int stm32mp1_dbgmcu_boot_debug_info(void) + return 0; + } + +-int stm32mp1_dbgmcu_clear_boot_info(void) ++/* ++ * @brief Clear debug mode information in backup registers. ++ * @retval None. ++ */ ++void stm32mp1_dbgmcu_clear_boot_info(void) + { + stm32mp_clk_enable(RTCAPB); + +@@ -81,20 +94,28 @@ int stm32mp1_dbgmcu_clear_boot_info(void) + TAMP_DBG_DEBUG); + + stm32mp_clk_disable(RTCAPB); +- +- return 0; + } + +-uint32_t stm32mp1_dbgmcu_is_debug_on(void) ++/* ++ * @brief Get DBGMCU debug mode in BSEC registers. ++ * @retval True if debug mode enabled, false otherwise. ++ */ ++bool stm32mp1_dbgmcu_is_debug_on(void) + { + uint32_t dbg_conf; + + dbg_conf = bsec_read_debug_conf(); + +- return (dbg_conf & (BSEC_SPIDEN | BSEC_SPINDEN)); ++ return (dbg_conf & (BSEC_SPIDEN | BSEC_SPINDEN)) != 0U; + } + + #if LOG_LEVEL >= LOG_LEVEL_VERBOSE ++/* ++ * @brief Dump 8-bits buffer content in hexadecimal. ++ * @param buf: Pointer to the 8-bits buffer. ++ * @parma len: Length in bytes of the dump. ++ * @retval None. ++ */ + void stm32mp1_dbgmcu_hexdump8(uint8_t *buf, uint32_t len) + { + uint32_t i; +@@ -116,25 +137,48 @@ void stm32mp1_dbgmcu_hexdump8(uint8_t *buf, uint32_t len) + #endif + #endif + +-uint32_t stm32mp1_dbgmcu_get_chip_version(void) ++/* ++ * @brief Get silicon revision from DBGMCU registers. ++ * @param chip_version: pointer to the read value. ++ * @retval 0 on success, negative value on failure. ++ */ ++int stm32mp1_dbgmcu_get_chip_version(uint32_t *chip_version) + { +- if (stm32mp1_dbgmcu_init() == 0) { +- return (mmio_read_32(DBGMCU_BASE + DBGMCU_IDC) >> 16); ++ assert(chip_version != NULL); ++ ++ if (stm32mp1_dbgmcu_init() != 0) { ++ return -EPERM; + } + ++ *chip_version = (mmio_read_32(DBGMCU_BASE + DBGMCU_IDC) & ++ DBGMCU_IDC_REV_ID_MASK) >> DBGMCU_IDC_REV_ID_SHIFT; ++ + return 0; + } + +-uint32_t stm32mp1_dbgmcu_get_chip_dev_id(void) ++/* ++ * @brief Get device ID from DBGMCU registers. ++ * @param chip_version: pointer to the read value. ++ * @retval 0 on success, negative value on failure. ++ */ ++int stm32mp1_dbgmcu_get_chip_dev_id(uint32_t *chip_dev_id) + { +- if (stm32mp1_dbgmcu_init() == 0) { +- return (mmio_read_32(DBGMCU_BASE + DBGMCU_IDC) & +- IDC_DEV_ID_MASK); ++ assert(chip_dev_id != NULL); ++ ++ if (stm32mp1_dbgmcu_init() != 0) { ++ return -EPERM; + } + ++ *chip_dev_id = mmio_read_32(DBGMCU_BASE + DBGMCU_IDC) & ++ DBGMCU_IDC_DEV_ID_MASK; ++ + return 0; + } + ++/* ++ * @brief Freeze IWDG2 in debug mode. ++ * @retval None. ++ */ + int stm32mp1_dbgmcu_freeze_iwdg2(void) + { + if (stm32mp1_dbgmcu_init() == 0) { +diff --git a/plat/st/stm32mp1/stm32mp1_def.h b/plat/st/stm32mp1/stm32mp1_def.h +index 7d7d773..f130eab 100644 +--- a/plat/st/stm32mp1/stm32mp1_def.h ++++ b/plat/st/stm32mp1/stm32mp1_def.h +@@ -8,12 +8,17 @@ + #define STM32MP1_DEF_H + + #ifndef __ASSEMBLY__ ++#include + #include + #include + #include + #include + #include + #include ++#include ++#include ++#include ++#include + #include + #include + #include +@@ -29,6 +34,7 @@ + #include + #include + #include ++#include + #endif + #include + #include +@@ -45,9 +51,16 @@ + #define STM32MP153A_PART_NB U(0x05000025) + #define STM32MP151C_PART_NB U(0x0500002E) + #define STM32MP151A_PART_NB U(0x0500002F) ++#define STM32MP157F_PART_NB U(0x05000080) ++#define STM32MP157D_PART_NB U(0x05000081) ++#define STM32MP153F_PART_NB U(0x050000A4) ++#define STM32MP153D_PART_NB U(0x050000A5) ++#define STM32MP151F_PART_NB U(0x050000AE) ++#define STM32MP151D_PART_NB U(0x050000AF) + + #define STM32MP1_REV_A U(0x1000) + #define STM32MP1_REV_B U(0x2000) ++#define STM32MP1_REV_Z U(0x2001) + + /******************************************************************************* + * PACKAGE ID +@@ -85,7 +98,7 @@ + #define STM32MP_DDR_BASE U(0xC0000000) + #define STM32MP_DDR_MAX_SIZE U(0x40000000) /* Max 1GB */ + #ifdef AARCH32_SP_OPTEE +-#define STM32MP_DDR_S_SIZE U(0x02000000) /* 32 MB */ ++#define STM32MP_DDR_S_SIZE U(0x01E00000) /* 30 MB */ + #define STM32MP_DDR_SHMEM_SIZE U(0x00200000) /* 2 MB */ + #else + #define STM32MP_DDR_S_SIZE U(0) /* DDR is non secure */ +@@ -122,9 +135,9 @@ enum ddr_type { + STM32MP_OPTEE_BASE) + #else + #if STACK_PROTECTOR_ENABLED +-#define STM32MP_BL32_SIZE U(0x00011000) /* 68 Ko for BL32 */ ++#define STM32MP_BL32_SIZE U(0x00012000) /* 72 Ko for BL32 */ + #else +-#define STM32MP_BL32_SIZE U(0x00010000) /* 64 Ko for BL32 */ ++#define STM32MP_BL32_SIZE U(0x00011000) /* 68 Ko for BL32 */ + #endif + #endif + +@@ -134,30 +147,35 @@ enum ddr_type { + + #ifdef AARCH32_SP_OPTEE + #if STACK_PROTECTOR_ENABLED +-#define STM32MP_BL2_SIZE U(0x00019000) /* 100 Ko for BL2 */ ++#define STM32MP_BL2_SIZE U(0x0001A000) /* 104 Ko for BL2 */ + #else +-#define STM32MP_BL2_SIZE U(0x00017000) /* 92 Ko for BL2 */ ++#define STM32MP_BL2_SIZE U(0x00018000) /* 96 Ko for BL2 */ + #endif + #else + #if STACK_PROTECTOR_ENABLED +-#define STM32MP_BL2_SIZE U(0x00018000) /* 96 Ko for BL2 */ ++#define STM32MP_BL2_SIZE U(0x00019000) /* 100 Ko for BL2 */ + #else +-#define STM32MP_BL2_SIZE U(0x00016000) /* 88 Ko for BL2 */ ++#define STM32MP_BL2_SIZE U(0x00017000) /* 92 Ko for BL2 */ + #endif + #endif + + #define STM32MP_BL2_BASE (STM32MP_BL32_BASE - \ + STM32MP_BL2_SIZE) + +-/* BL2 and BL32/sp_min require 7 tables */ +-#define MAX_XLAT_TABLES U(7) /* 28 Ko for mapping */ ++#if defined(STM32MP_USB) ++/* BL2 and BL32/sp_min require 5 finer granularity tables */ ++ #define MAX_XLAT_TABLES U(5) /* 20 Ko for mapping */ ++#else ++/* BL2 and BL32/sp_min require 4 finer granularity tables */ ++ #define MAX_XLAT_TABLES U(4) /* 16 Ko for mapping */ ++#endif + + /* + * MAX_MMAP_REGIONS is usually: + * BL stm32mp1_mmap size + mmap regions in *_plat_arch_setup + */ + #if defined(IMAGE_BL2) +- #if (defined STM32MP_USB) ++ #if defined(STM32MP_USB) + #define MAX_MMAP_REGIONS 12 + #else + #define MAX_MMAP_REGIONS 11 +@@ -365,21 +383,16 @@ enum ddr_type { + + #define OTP_MAX_SIZE (STM32MP1_OTP_MAX_ID + 1U) + +-/* OTP offsets */ +-#define DATA0_OTP U(0) +-#define PART_NUMBER_OTP U(1) +-#define MONOTONIC_OTP U(4) +-#define NAND_OTP U(9) +-#define UID0_OTP U(13) +-#define UID1_OTP U(14) +-#define UID2_OTP U(15) +-#define PACKAGE_OTP U(16) +-#define HW2_OTP U(18) /* HW watchdog OTP */ ++/* OTP labels */ ++#define PART_NUMBER_OTP "part_number_otp" ++#define PACKAGE_OTP "package_otp" ++#define HW2_OTP "hw2_otp" ++#define NAND_OTP "nand_otp" ++#define MONOTONIC_OTP "monotonic_otp" ++#define UID_OTP "uid_otp" ++#define BOARD_ID_OTP "board_id" + + /* OTP mask */ +-/* DATA0 */ +-#define DATA0_OTP_SECURED BIT(6) +- + /* PART NUMBER */ + #define PART_SHIFT 0 + #define PART_MASK GENMASK_32(7, 0) +@@ -431,8 +444,12 @@ enum ddr_type { + #define NAND_ECC_BIT_NB_4_BITS 2 + #define NAND_ECC_BIT_NB_8_BITS 3 + ++/* MONOTONIC OTP */ + #define MAX_MONOTONIC_VALUE 32 + ++/* UID OTP */ ++#define UID_WORD_NB 3 ++ + /******************************************************************************* + * STM32MP1 FMC + ******************************************************************************/ +@@ -522,6 +539,14 @@ static inline uint32_t tamp_bkpr(uint32_t idx) + #define TIM_MAX_INSTANCE U(2) + + /******************************************************************************* ++ * STM32MP1 OPP ++ ******************************************************************************/ ++#define PLAT_OPP_ID1 U(1) ++#define PLAT_OPP_ID2 U(2) ++#define PLAT_MAX_OPP_NB U(2) ++#define PLAT_MAX_PLLCFG_NB U(6) ++ ++/******************************************************************************* + * DEBUG + ******************************************************************************/ + /*#define ICACHE_OFF*/ +@@ -531,9 +556,12 @@ static inline uint32_t tamp_bkpr(uint32_t idx) + /******************************************************************************* + * Device Tree defines + ******************************************************************************/ +-#define DT_BSEC_COMPAT "st,stm32mp15-bsec" ++#define DT_NVMEM_LAYOUT_COMPAT "st,stm32-nvmem-layout" ++#define DT_OPP_COMPAT "operating-points-v2" + #define DT_PWR_COMPAT "st,stm32mp1-pwr" + #define DT_RCC_CLK_COMPAT "st,stm32mp1-rcc" + #define DT_SYSCFG_COMPAT "st,stm32mp157-syscfg" + ++#define DT_PLL1_NODE_NAME "st,pll@0" ++ + #endif /* STM32MP1_DEF_H */ +diff --git a/plat/st/stm32mp1/stm32mp1_helper_dbg.S b/plat/st/stm32mp1/stm32mp1_helper_dbg.S +index 32a86fb..6e88e5b 100644 +--- a/plat/st/stm32mp1/stm32mp1_helper_dbg.S ++++ b/plat/st/stm32mp1/stm32mp1_helper_dbg.S +@@ -10,6 +10,9 @@ + * fixes the limitation. Anyway, this source code identifies the Soc revision + * and is only executed if it corresponds, so it can be kept on other + * revisions without any consequence. ++ * The revisions that need the workaround have ID values: ++ * - 0x2000X500 ++ * - 0x2001X500 + ****************************************************************************/ + + /***************************************************************************** +@@ -18,6 +21,8 @@ + * other pieces of software. + ****************************************************************************/ + ++#include ++ + #define BIT_(nr) ((1) << (nr)) + + #define BSEC_BASE 0x5C005000 +@@ -27,7 +32,7 @@ + + #define DBGMCU_BASE 0x50081000 + #define DBGMCU_IDC 0x00 +-#define DBGMCU_IDC_REV_ID_DEV_ID_MSK 0xFFFF0FFF ++#define DBGMCU_IDC_REV_ID_DEV_ID_MSK 0xFFFE0FFF + #define DBGMCU_IDC_REV_ID_DEV_ID_VALUE 0x20000500 + + #define RCC_BASE 0x50000000 +@@ -53,7 +58,7 @@ + .globl plat_dbg_attach_loop + + +-plat_dbg_attach_loop: ++func plat_dbg_attach_loop + /* + * This function is the first call of FSBL_ENTRYPOINT. + * Boot rom parameters are stored in r0..r3, so we mustn't use them +@@ -225,3 +230,4 @@ msb_incr: + bmi loop + func_exit: + bx lr ++endfunc plat_dbg_attach_loop +diff --git a/plat/st/stm32mp1/stm32mp1_low_power.c b/plat/st/stm32mp1/stm32mp1_low_power.c +index f8b35dd..48b7af6 100644 +--- a/plat/st/stm32mp1/stm32mp1_low_power.c ++++ b/plat/st/stm32mp1/stm32mp1_low_power.c +@@ -32,8 +32,7 @@ + #include + + static unsigned int gicc_pmr; +-static struct stm32_rtc_calendar sleep_time, current_calendar; +-static unsigned long long stdby_time_in_ms; ++static struct stm32_rtc_calendar sleep_time; + static bool enter_cstop_done; + static uint8_t int_stack[STM32MP_INT_STACK_SIZE]; + +@@ -101,11 +100,11 @@ void stm32_apply_pmic_suspend_config(uint32_t mode) + panic(); + } + +- if (dt_pmic_set_lp_config(node_name) != 0) { ++ if (pmic_set_lp_config(node_name) < 0) { + panic(); + } + +- if (dt_pmic_configure_boot_on_regulators() != 0) { ++ if (pmic_configure_boot_on_regulators() < 0) { + panic(); + } + } +@@ -131,6 +130,9 @@ static void enter_cstop(uint32_t mode, uint32_t nsec_addr) + + stm32mp1_syscfg_disable_io_compensation(); + ++ /* Switch to Software Self-Refresh */ ++ ddr_sr_mode_ssr(); ++ + dcsw_op_all(DC_OP_CISW); + + stm32_clean_context(); +@@ -225,6 +227,8 @@ void stm32_exit_cstop(void) + { + uintptr_t pwr_base = stm32mp_pwr_base(); + uintptr_t rcc_base = stm32mp_rcc_base(); ++ unsigned long long stdby_time_in_ms; ++ struct stm32_rtc_calendar current_calendar; + + if (!enter_cstop_done) { + return; +@@ -238,6 +242,9 @@ void stm32_exit_cstop(void) + panic(); + } + ++ /* Switch to Automatic Self-Refresh */ ++ ddr_sr_mode_asr(); ++ + plat_ic_set_priority_mask(gicc_pmr); + + /* Disable RCC Wake-up */ +@@ -259,7 +266,8 @@ void stm32_exit_cstop(void) + stdby_time_in_ms = stm32_rtc_diff_calendar(¤t_calendar, + &sleep_time); + +- stm32mp1_stgen_increment(stdby_time_in_ms); ++ stm32mp1_stgen_restore_counter(stm32_get_stgen_from_context(), ++ stdby_time_in_ms); + + stm32mp1_syscfg_enable_io_compensation(); + } +diff --git a/plat/st/stm32mp1/stm32mp1_pm.c b/plat/st/stm32mp1/stm32mp1_pm.c +index b95bc3d..e431199 100644 +--- a/plat/st/stm32mp1/stm32mp1_pm.c ++++ b/plat/st/stm32mp1/stm32mp1_pm.c +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. ++ * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +@@ -71,14 +71,8 @@ static int stm32_pwr_domain_on(u_register_t mpidr) + tamp_bkpr(BOOT_API_CORE1_BRANCH_ADDRESS_TAMP_BCK_REG_IDX); + uint32_t bkpr_core1_magic = + tamp_bkpr(BOOT_API_CORE1_MAGIC_NUMBER_TAMP_BCK_REG_IDX); +- int result; + +- result = stm32mp_is_single_core(); +- if (result < 0) { +- return PSCI_E_INTERN_FAIL; +- } +- +- if (result == 1) { ++ if (stm32mp_is_single_core()) { + return PSCI_E_INTERN_FAIL; + } + +@@ -203,7 +197,7 @@ static void __dead2 stm32_system_off(void) + { + uint32_t soc_mode = stm32mp1_get_lp_soc_mode(PSCI_MODE_SYSTEM_OFF); + +- if (stm32mp_is_single_core() == 0) { ++ if (!stm32mp_is_single_core()) { + /* Prepare Core 1 reset */ + mmio_setbits_32(stm32mp_rcc_base() + RCC_MP_GRSTCSETR, + RCC_MP_GRSTCSETR_MPUP1RST); +diff --git a/plat/st/stm32mp1/stm32mp1_power_config.c b/plat/st/stm32mp1/stm32mp1_power_config.c +index ec7ecb1..d5dd671 100644 +--- a/plat/st/stm32mp1/stm32mp1_power_config.c ++++ b/plat/st/stm32mp1/stm32mp1_power_config.c +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 2017-2018, STMicroelectronics - All Rights Reserved ++ * Copyright (c) 2017-2019, STMicroelectronics - All Rights Reserved + * + * SPDX-License-Identifier: BSD-3-Clause + */ +@@ -13,7 +13,6 @@ + #include + #include + +-#define DT_PWR_COMPAT "st,stm32mp1-pwr" + #define SYSTEM_SUSPEND_SUPPORTED_MODES "system_suspend_supported_soc_modes" + #define SYSTEM_OFF_MODE "system_off_soc_mode" + +@@ -21,9 +20,9 @@ static uint32_t deepest_system_suspend_mode; + static uint32_t system_off_mode; + static uint8_t stm32mp1_supported_soc_modes[STM32_PM_MAX_SOC_MODE]; + +-static int dt_get_pwr_node(void *fdt) ++static int dt_get_pwr_node(void) + { +- return fdt_node_offset_by_compatible(fdt, -1, DT_PWR_COMPAT); ++ return dt_get_node_by_compatible(DT_PWR_COMPAT); + } + + static void save_supported_mode(void *fdt, int pwr_node) +@@ -77,7 +76,7 @@ static int dt_fill_lp_state(uint32_t *lp_state_config, const char *lp_state) + return -ENOENT; + } + +- pwr_node = dt_get_pwr_node(fdt); ++ pwr_node = dt_get_pwr_node(); + if (pwr_node < 0) { + return -FDT_ERR_NOTFOUND; + } +diff --git a/plat/st/stm32mp1/stm32mp1_private.c b/plat/st/stm32mp1/stm32mp1_private.c +index aae537f..d399dc8 100644 +--- a/plat/st/stm32mp1/stm32mp1_private.c ++++ b/plat/st/stm32mp1/stm32mp1_private.c +@@ -15,6 +15,9 @@ + #include + #include + #include ++#include ++#include ++#include + #include + #include + +@@ -243,7 +246,7 @@ void __dead2 stm32mp_plat_reset(int cpu) + } + } + +- if (stm32mp_is_single_core() == 0) { ++ if (!stm32mp_is_single_core()) { + unsigned int sec_cpu = (cpu == STM32MP_PRIMARY_CPU) ? + STM32MP_SECONDARY_CPU : STM32MP_PRIMARY_CPU; + +@@ -266,38 +269,131 @@ void __dead2 stm32mp_plat_reset(int cpu) + stm32mp_wait_cpu_reset(); + } + +-static uint32_t get_part_number(void) ++int stm32_get_otp_index(const char *otp_name, uint32_t *otp_idx, ++ uint32_t *otp_len) + { +- uint32_t part_number = 0; ++ assert(otp_name != NULL); ++ assert(otp_idx != NULL); + +- if (bsec_shadow_read_otp(&part_number, PART_NUMBER_OTP) != BSEC_OK) { +- ERROR("BSEC: PART_NUMBER_OTP Error\n"); ++ if (bsec_find_otp_name_in_dt(otp_name, otp_idx, otp_len) != BSEC_OK) { ++ ERROR("BSEC: Get %s number Error\n", otp_name); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++int stm32_get_otp_value(const char *otp_name, uint32_t *otp_val) ++{ ++ uint32_t otp; ++ ++ assert(otp_name != NULL); ++ assert(otp_val != NULL); ++ ++ if (stm32_get_otp_index(otp_name, &otp, NULL) != 0) { ++ return -1; ++ } ++ ++#if defined(IMAGE_BL2) ++ if (bsec_shadow_read_otp(otp_val, otp) != BSEC_OK) { ++ ERROR("BSEC: %s Read Error\n", otp_name); ++ return -1; ++ } ++#elif defined(IMAGE_BL32) ++ if (bsec_read_otp(otp_val, otp) != BSEC_OK) { ++ ERROR("BSEC: %s Read Error\n", otp_name); ++ return -1; ++ } ++#endif ++ ++ return 0; ++} ++ ++static int get_part_number(uint32_t *part_nb) ++{ ++ uint32_t part_number; ++ uint32_t dev_id; ++ ++ assert(part_nb != NULL); ++ ++ if (stm32mp1_dbgmcu_get_chip_dev_id(&dev_id) < 0) { ++ return -1; ++ } ++ ++ if (stm32_get_otp_value(PART_NUMBER_OTP, &part_number) != 0) { + return -1; + } + + part_number = (part_number & PART_MASK) >> PART_SHIFT; + +- return (part_number | (stm32mp1_dbgmcu_get_chip_dev_id() << 16)); ++ *part_nb = part_number | (dev_id << 16); ++ ++ return 0; + } + +-static uint32_t get_cpu_package(void) ++static int get_cpu_package(uint32_t *cpu_package) + { +- uint32_t package = 0; ++ uint32_t package; ++ ++ assert(cpu_package != NULL); + +- if (bsec_shadow_read_otp(&package, PACKAGE_OTP) != BSEC_OK) { +- ERROR("BSEC: PART_NUMBER_OTP Error\n"); ++ if (stm32_get_otp_value(PACKAGE_OTP, &package) != 0) { + return -1; + } + +- return ((package & PKG_MASK) >> PKG_SHIFT); ++ *cpu_package = (package & PKG_MASK) >> PKG_SHIFT; ++ ++ return 0; ++} ++ ++bool stm32mp_supports_cpu_opp(uint32_t opp_id) ++{ ++ uint32_t part_number; ++ uint32_t id; ++ ++ if (get_part_number(&part_number) != 0) { ++ ERROR("Cannot get part number\n"); ++ panic(); ++ } ++ ++ switch (opp_id) { ++ case PLAT_OPP_ID1: ++ case PLAT_OPP_ID2: ++ id = opp_id; ++ break; ++ default: ++ return false; ++ } ++ ++ switch (part_number) { ++ case STM32MP157F_PART_NB: ++ case STM32MP157D_PART_NB: ++ case STM32MP153F_PART_NB: ++ case STM32MP153D_PART_NB: ++ case STM32MP151F_PART_NB: ++ case STM32MP151D_PART_NB: ++ return true; ++ default: ++ return id == PLAT_OPP_ID1; ++ } + } + + void stm32mp_print_cpuinfo(void) + { + const char *cpu_s, *cpu_r, *pkg; ++ uint32_t part_number; ++ uint32_t cpu_package; ++ uint32_t chip_dev_id; ++ int ret; + + /* MPUs Part Numbers */ +- switch (get_part_number()) { ++ ret = get_part_number(&part_number); ++ if (ret < 0) { ++ WARN("Cannot get part number\n"); ++ return; ++ } ++ ++ switch (part_number) { + case STM32MP157C_PART_NB: + cpu_s = "157C"; + break; +@@ -316,13 +412,37 @@ void stm32mp_print_cpuinfo(void) + case STM32MP151A_PART_NB: + cpu_s = "151A"; + break; ++ case STM32MP157F_PART_NB: ++ cpu_s = "157F"; ++ break; ++ case STM32MP157D_PART_NB: ++ cpu_s = "157D"; ++ break; ++ case STM32MP153F_PART_NB: ++ cpu_s = "153F"; ++ break; ++ case STM32MP153D_PART_NB: ++ cpu_s = "153D"; ++ break; ++ case STM32MP151F_PART_NB: ++ cpu_s = "151F"; ++ break; ++ case STM32MP151D_PART_NB: ++ cpu_s = "151D"; ++ break; + default: + cpu_s = "????"; + break; + } + + /* Package */ +- switch (get_cpu_package()) { ++ ret = get_cpu_package(&cpu_package); ++ if (ret < 0) { ++ WARN("Cannot get CPU package\n"); ++ return; ++ } ++ ++ switch (cpu_package) { + case PKG_AA_LBGA448: + pkg = "AA"; + break; +@@ -341,13 +461,22 @@ void stm32mp_print_cpuinfo(void) + } + + /* REVISION */ +- switch (stm32mp1_dbgmcu_get_chip_version()) { ++ ret = stm32mp1_dbgmcu_get_chip_version(&chip_dev_id); ++ if (ret < 0) { ++ WARN("Cannot get CPU version\n"); ++ return; ++ } ++ ++ switch (chip_dev_id) { + case STM32MP1_REV_A: + cpu_r = "A"; + break; + case STM32MP1_REV_B: + cpu_r = "B"; + break; ++ case STM32MP1_REV_Z: ++ cpu_r = "Z"; ++ break; + default: + cpu_r = "?"; + break; +@@ -359,35 +488,8 @@ void stm32mp_print_cpuinfo(void) + void stm32mp_print_boardinfo(void) + { + uint32_t board_id = 0; +- uint32_t board_otp; +- int bsec_node, bsec_board_id_node; +- void *fdt; +- const fdt32_t *cuint; + +- if (fdt_get_address(&fdt) == 0) { +- panic(); +- } +- +- bsec_node = fdt_node_offset_by_compatible(fdt, -1, DT_BSEC_COMPAT); +- if (bsec_node < 0) { +- return; +- } +- +- bsec_board_id_node = fdt_subnode_offset(fdt, bsec_node, "board_id"); +- if (bsec_board_id_node <= 0) { +- return; +- } +- +- cuint = fdt_getprop(fdt, bsec_board_id_node, "reg", NULL); +- if (cuint == NULL) { +- ERROR("board_id node without reg property\n"); +- panic(); +- } +- +- board_otp = fdt32_to_cpu(*cuint) / sizeof(uint32_t); +- +- if (bsec_shadow_read_otp(&board_id, board_otp) != BSEC_OK) { +- ERROR("BSEC: PART_NUMBER_OTP Error\n"); ++ if (stm32_get_otp_value(BOARD_ID_OTP, &board_id) != 0) { + return; + } + +@@ -404,22 +506,35 @@ void stm32mp_print_boardinfo(void) + } + } + +-/* +- * This function determines if one single core is presently running. This is +- * done by OTP read. +- * Returns 1 if yes, 0 if more that one core is running, -1 if error. +- */ +-int stm32mp_is_single_core(void) ++/* Return true when SoC provides a single Cortex-A7 core, and false otherwise */ ++bool stm32mp_is_single_core(void) + { +- uint32_t part_number = get_part_number(); ++ uint32_t part_number; + +- /* STM32MP151x is a single core */ +- if ((part_number == STM32MP151A_PART_NB) || +- (part_number == STM32MP151C_PART_NB)) { +- return 1; ++ if (get_part_number(&part_number) < 0) { ++ ERROR("Invalid part number, assume single core chip"); ++ return true; + } + +- return 0; ++ switch (part_number) { ++ case STM32MP151A_PART_NB: ++ case STM32MP151C_PART_NB: ++ case STM32MP151D_PART_NB: ++ case STM32MP151F_PART_NB: ++ return true; ++ ++ default: ++ return false; ++ } ++} ++ ++/* Return true if DDR supports Software/Automatic Self-Refresh */ ++bool stm32mp_ddr_supports_ssr_asr(void) ++{ ++ uintptr_t ddrctrl_base = stm32mp_ddrctrl_base(); ++ uint32_t mstr = mmio_read_32(ddrctrl_base + DDRCTRL_MSTR); ++ ++ return (mstr & DDRCTRL_MSTR_LPDDR2) != 0U; + } + + uint8_t stm32_iwdg_get_instance(uintptr_t base) +@@ -440,15 +555,9 @@ uint32_t stm32_iwdg_get_otp_config(uintptr_t base) + uint32_t iwdg_cfg = 0; + uint32_t otp_value; + +-#if defined(IMAGE_BL2) +- if (bsec_shadow_read_otp(&otp_value, HW2_OTP) != BSEC_OK) { ++ if (stm32_get_otp_value(HW2_OTP, &otp_value) != 0) { + panic(); + } +-#elif defined(IMAGE_BL32) +- if (bsec_read_otp(&otp_value, HW2_OTP) != BSEC_OK) { +- panic(); +- } +-#endif + + idx = stm32_iwdg_get_instance(base); + +@@ -471,31 +580,36 @@ uint32_t stm32_iwdg_get_otp_config(uintptr_t base) + uint32_t stm32_iwdg_shadow_update(uintptr_t base, uint32_t flags) + { + uint32_t idx; ++ uint32_t otp_value; + uint32_t otp; + uint32_t result; + +- if (bsec_shadow_read_otp(&otp, HW2_OTP) != BSEC_OK) { ++ if (stm32_get_otp_index(HW2_OTP, &otp, NULL) != 0) { ++ panic(); ++ } ++ ++ if (stm32_get_otp_value(HW2_OTP, &otp_value) != 0) { + panic(); + } + + idx = stm32_iwdg_get_instance(base); + + if ((flags & IWDG_DISABLE_ON_STOP) != 0) { +- otp |= BIT(idx + IWDG_FZ_STOP_POS); ++ otp_value |= BIT(idx + IWDG_FZ_STOP_POS); + } + + if ((flags & IWDG_DISABLE_ON_STANDBY) != 0) { +- otp |= BIT(idx + IWDG_FZ_STANDBY_POS); ++ otp_value |= BIT(idx + IWDG_FZ_STANDBY_POS); + } + +- result = bsec_write_otp(otp, HW2_OTP); ++ result = bsec_write_otp(otp_value, otp); + if (result != BSEC_OK) { + return result; + } + + /* Sticky lock OTP_IWDG (read and write) */ +- if ((bsec_set_sr_lock(HW2_OTP) != BSEC_OK) || +- (bsec_set_sw_lock(HW2_OTP) != BSEC_OK)) { ++ if ((bsec_set_sr_lock(otp) != BSEC_OK) || ++ (bsec_set_sw_lock(otp) != BSEC_OK)) { + return BSEC_LOCK_FAIL; + } + +@@ -524,3 +638,26 @@ enum etzpc_decprot_attributes stm32mp_etzpc_binding2decprot(uint32_t mode) + panic(); + } + } ++ ++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; ++} +diff --git a/plat/st/stm32mp1/stm32mp1_security.c b/plat/st/stm32mp1/stm32mp1_security.c +index d2da110..9ad9486 100644 +--- a/plat/st/stm32mp1/stm32mp1_security.c ++++ b/plat/st/stm32mp1/stm32mp1_security.c +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. ++ * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +@@ -24,6 +24,7 @@ static void init_tzc400(void) + unsigned long long region_base, region_top; + unsigned long long ddr_base = STM32MP_DDR_BASE; + unsigned long long ddr_size = (unsigned long long)dt_get_ddr_size(); ++ unsigned long long ddr_top = ddr_base + (ddr_size - 1U); + + tzc400_init(STM32MP1_TZC_BASE); + +@@ -35,7 +36,7 @@ static void init_tzc400(void) + * same configuration to all filters in the TZC. + */ + region_base = ddr_base; +- region_top = ddr_base + (ddr_size - STM32MP_DDR_S_SIZE - 1U); ++ region_top = ddr_top - STM32MP_DDR_S_SIZE - STM32MP_DDR_SHMEM_SIZE; + tzc400_configure_region(STM32MP1_FILTER_BIT_ALL, 1, + region_base, + region_top, +@@ -53,8 +54,8 @@ static void init_tzc400(void) + TZC_REGION_ACCESS_RDWR(STM32MP1_TZC_DAP_ID)); + + /* Region 2 set to cover all secure DRAM. */ +- region_base = ddr_base + (ddr_size - STM32MP_DDR_S_SIZE); +- region_top = ddr_base + (ddr_size - STM32MP_DDR_SHMEM_SIZE - 1U); ++ region_base = region_top + 1U; ++ region_top = ddr_top - STM32MP_DDR_SHMEM_SIZE; + tzc400_configure_region(STM32MP1_FILTER_BIT_ALL, 2, + region_base, + region_top, +@@ -62,8 +63,8 @@ static void init_tzc400(void) + 0); + + /* Region 3 set to cover non-secure shared memory DRAM. */ +- region_base = ddr_base + (ddr_size - STM32MP_DDR_SHMEM_SIZE); +- region_top = ddr_base + (ddr_size - 1U); ++ region_base = region_top + 1U; ++ region_top = ddr_top; + tzc400_configure_region(STM32MP1_FILTER_BIT_ALL, 3, + region_base, + region_top, +@@ -85,7 +86,7 @@ static void init_tzc400(void) + * same configuration to all filters in the TZC. + */ + region_base = ddr_base; +- region_top = ddr_base + (ddr_size - 1U); ++ region_top = ddr_top; + tzc400_configure_region(STM32MP1_FILTER_BIT_ALL, 1, + region_base, + region_top, +@@ -103,8 +104,11 @@ static void init_tzc400(void) + TZC_REGION_ACCESS_RDWR(STM32MP1_TZC_DAP_ID)); + #endif + +- /* Raise an exception if a NS device tries to access secure memory */ +- tzc400_set_action(TZC_ACTION_ERR); ++ /* ++ * Raise an interrupt (secure FIQ) if a NS device tries to access ++ * secure memory ++ */ ++ tzc400_set_action(TZC_ACTION_INT); + + tzc400_enable_filters(); + } +diff --git a/plat/st/stm32mp1/stm32mp1_syscfg.c b/plat/st/stm32mp1/stm32mp1_syscfg.c +index 3276870..47a16ac 100644 +--- a/plat/st/stm32mp1/stm32mp1_syscfg.c ++++ b/plat/st/stm32mp1/stm32mp1_syscfg.c +@@ -4,18 +4,18 @@ + * SPDX-License-Identifier: BSD-3-Clause + */ + +-#include + #include + #include + #include + #include ++#include + #include + #include + #include + #include + + /* +- * SYSCFG REGISTER OFFSET (base relative) ++ * SYSCFG register offsets (base relative) + */ + #define SYSCFG_BOOTR 0x00U + #define SYSCFG_IOCTRLSETR 0x18U +@@ -52,6 +52,8 @@ + #define SYSCFG_CMPCR_RAPSRC GENMASK(23, 20) + #define SYSCFG_CMPCR_ANSRC_SHIFT 24 + ++#define SYSCFG_CMPCR_READY_TIMEOUT_US 10000U ++ + /* + * SYSCFG_CMPENSETR Register + */ +@@ -60,9 +62,10 @@ + void stm32mp1_syscfg_init(void) + { + uint32_t bootr; +- uint32_t otp = 0; ++ uint32_t otp_value; + uint32_t vdd_voltage; + uintptr_t syscfg_base = dt_get_syscfg_base(); ++ bool product_below_2v5; + + /* + * Interconnect update : select master using the port 1. +@@ -96,11 +99,11 @@ void stm32mp1_syscfg_init(void) + * => TF-A enables the low power mode only if VDD < 2.7V (in DT) + * but this value needs to be consistent with board design. + */ +- if (bsec_read_otp(&otp, HW2_OTP) != BSEC_OK) { ++ if (stm32_get_otp_value(HW2_OTP, &otp_value) != 0) { + panic(); + } + +- otp = otp & HW2_OTP_PRODUCT_BELOW_2V5; ++ product_below_2v5 = (otp_value & HW2_OTP_PRODUCT_BELOW_2V5) != 0U; + + /* Get VDD supply */ + vdd_voltage = dt_get_pwr_vdd_voltage(); +@@ -117,11 +120,11 @@ void stm32mp1_syscfg_init(void) + SYSCFG_IOCTRLSETR_HSLVEN_SDMMC | + SYSCFG_IOCTRLSETR_HSLVEN_SPI); + +- if (otp == 0U) { ++ if (!product_below_2v5) { + INFO("Product_below_2v5=0: HSLVEN protected by HW\n"); + } + } else { +- if (otp != 0U) { ++ if (product_below_2v5) { + ERROR("Product_below_2v5=1: HSLVEN update is destructive, no update as VDD>2.7V\n"); + panic(); + } +@@ -137,6 +140,7 @@ void stm32mp1_syscfg_init(void) + void stm32mp1_syscfg_enable_io_compensation(void) + { + uintptr_t syscfg_base = dt_get_syscfg_base(); ++ uint64_t start; + + /* + * Activate automatic I/O compensation. +@@ -148,9 +152,18 @@ void stm32mp1_syscfg_enable_io_compensation(void) + mmio_setbits_32(syscfg_base + SYSCFG_CMPENSETR, + SYSCFG_CMPENSETR_MPU_EN); + ++ start = timeout_start(); ++ + while ((mmio_read_32(syscfg_base + SYSCFG_CMPCR) & + SYSCFG_CMPCR_READY) == 0U) { +- ; ++ if (timeout_elapsed(start, SYSCFG_CMPCR_READY_TIMEOUT_US)) { ++ /* ++ * 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); +@@ -180,9 +193,7 @@ void stm32mp1_syscfg_disable_io_compensation(void) + value = mmio_read_32(syscfg_base + SYSCFG_CMPCR) | + (value << SYSCFG_CMPCR_RANSRC_SHIFT); + +- mmio_write_32(syscfg_base + SYSCFG_CMPCR, value); +- +- mmio_setbits_32(syscfg_base + SYSCFG_CMPCR, SYSCFG_CMPCR_SW_CTRL); ++ mmio_write_32(syscfg_base + SYSCFG_CMPCR, value | SYSCFG_CMPCR_SW_CTRL); + + VERBOSE("[0x%x] SYSCFG.cmpcr = 0x%08x\n", + (uint32_t)syscfg_base + SYSCFG_CMPCR, +diff --git a/plat/st/stm32mp1/stm32mp1_usb_desc.c b/plat/st/stm32mp1/stm32mp1_usb_desc.c +index 410cfa1..25246e9 100644 +--- a/plat/st/stm32mp1/stm32mp1_usb_desc.c ++++ b/plat/st/stm32mp1/stm32mp1_usb_desc.c +@@ -1,12 +1,14 @@ + /* +- * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved. ++ * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + + #include + #include ++#include + #include ++#include + #include + #include + #include +@@ -148,10 +150,22 @@ static void update_serial_num_string(void) + { + /* serial number is set to 0*/ + uint8_t i; +- uint32_t deviceserial[3] = {0, 0, 0}; ++ uint32_t deviceserial[UID_WORD_NB] = {0U, 0U, 0U}; ++ uint32_t otp; ++ uint32_t len; + +- for (i = 0; i < 3; i++) { +- if (bsec_shadow_read_otp(&deviceserial[i], i + UID0_OTP) != ++ if (stm32_get_otp_index(UID_OTP, &otp, &len) != 0) { ++ ERROR("BSEC: Get UID_OTP number Error\n"); ++ return; ++ } ++ ++ if ((len / __WORD_BIT) != UID_WORD_NB) { ++ ERROR("BSEC: Get UID_OTP length Error\n"); ++ return; ++ } ++ ++ for (i = 0; i < UID_WORD_NB; i++) { ++ if (bsec_shadow_read_otp(&deviceserial[i], i + otp) != + BSEC_OK) { + ERROR("BSEC: UID%d Error\n", i); + return; +diff --git a/tools/stm32image/stm32image.c b/tools/stm32image/stm32image.c +index 41024e2..e80bf0b 100644 +--- a/tools/stm32image/stm32image.c ++++ b/tools/stm32image/stm32image.c +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 2017-2018, STMicroelectronics - All Rights Reserved ++ * Copyright (c) 2017-2020, STMicroelectronics - All Rights Reserved + * + * SPDX-License-Identifier: BSD-3-Clause + */ +@@ -45,8 +45,6 @@ struct stm32_header { + uint8_t binary_type; + }; + +-static struct stm32_header stm32image_header; +- + static void stm32image_default_header(struct stm32_header *ptr) + { + if (!ptr) { +@@ -56,8 +54,8 @@ static void stm32image_default_header(struct stm32_header *ptr) + ptr->magic_number = HEADER_MAGIC; + ptr->header_version[VER_MAJOR] = HEADER_VERSION_V1; + ptr->option_flags = HEADER_DEFAULT_OPTION; +- ptr->ecdsa_algorithm = 1; +- ptr->version_number = 0; ++ ptr->ecdsa_algorithm = __cpu_to_le32(1); ++ ptr->version_number = __cpu_to_le32(0); + ptr->binary_type = TF_BINARY_TYPE; + } + +@@ -115,7 +113,8 @@ static void stm32image_set_header(void *ptr, struct stat *sbuf, int ifd, + stm32hdr->image_entry_point = __cpu_to_le32(ep); + stm32hdr->image_length = __cpu_to_le32((uint32_t)sbuf->st_size - + sizeof(struct stm32_header)); +- stm32hdr->image_checksum = stm32image_checksum(ptr, sbuf->st_size); ++ stm32hdr->image_checksum = ++ __cpu_to_le32(stm32image_checksum(ptr, sbuf->st_size)); + stm32hdr->version_number = __cpu_to_le32(ver); + } + +@@ -126,6 +125,7 @@ static int stm32image_create_header_file(char *srcname, char *destname, + int src_fd, dest_fd; + struct stat sbuf; + unsigned char *ptr; ++ struct stm32_header stm32image_header; + + dest_fd = open(destname, O_RDWR | O_CREAT | O_TRUNC | O_APPEND, 0666); + if (dest_fd == -1) { +@@ -204,13 +204,13 @@ int main(int argc, char *argv[]) + dest = optarg; + break; + case 'l': +- loadaddr = strtol(optarg, NULL, 16); ++ loadaddr = strtol(optarg, NULL, 0); + break; + case 'e': +- entry = strtol(optarg, NULL, 16); ++ entry = strtol(optarg, NULL, 0); + break; + case 'v': +- version = strtol(optarg, NULL, 10); ++ version = strtol(optarg, NULL, 0); + break; + default: + fprintf(stderr, +-- +2.7.4 + diff --git a/recipes-bsp/trusted-firmware-a/tf-a-stm32mp_2.0.bb b/recipes-bsp/trusted-firmware-a/tf-a-stm32mp_2.0.bb index 6272e09..f237585 100644 --- a/recipes-bsp/trusted-firmware-a/tf-a-stm32mp_2.0.bb +++ b/recipes-bsp/trusted-firmware-a/tf-a-stm32mp_2.0.bb @@ -10,6 +10,7 @@ SRC_URI[sha256sum] = "7d699a1683bb7a5909de37b6eb91b6e38db32cd6fc5ae48a08eb0718d6 SRC_URI += " \ file://0001-st-update-r1.patch \ file://0002-st-update-r1.1.0.patch \ + file://0003-st-update-r1.2.0.patch \ " TF_VERSION = "2.0" @@ -30,7 +31,7 @@ include ${@oe.utils.ifelse(d.getVar('ST_ARCHIVER_ENABLE') == '1', 'tf-a-stm32mp- BBCLASSEXTEND = "devupstream:target" SRC_URI_class-devupstream = "git://github.com/STMicroelectronics/arm-trusted-firmware.git;protocol=https;name=tfa;branch=v2.0-stm32mp" -SRCREV_class-devupstream = "69cc28c5a1b877cf67def7f94dece087f3917b1c" +SRCREV_class-devupstream = "5148fa0d1272cdf714ba0d7f0c38e0f72fa27020" SRCREV_FORMAT_class-devupstream = "tfa" PV_class-devupstream = "${TF_VERSION}+github+${SRCPV}" # ---------------------------------