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