diff --git a/drivers/st/clk/stm32mp1_clk.c b/drivers/st/clk/stm32mp1_clk.c index cea1c46..76e6e6f 100644 --- a/drivers/st/clk/stm32mp1_clk.c +++ b/drivers/st/clk/stm32mp1_clk.c @@ -323,6 +323,8 @@ _CLK_SC_FIXED(RCC_MP_APB2ENSETR, 2, TIM15_K, _PCLK2), _CLK_SC_SELEC(RCC_MP_APB2ENSETR, 13, USART6_K, _UART6_SEL), + _CLK_SC_FIXED(RCC_MP_APB3ENSETR, 11, SYSCFG, _UNKNOWN_ID), + _CLK_SC_SELEC(RCC_MP_APB4ENSETR, 8, DDRPERFM, _UNKNOWN_SEL), _CLK_SC_SELEC(RCC_MP_APB4ENSETR, 15, IWDG2, _UNKNOWN_SEL), _CLK_SC_SELEC(RCC_MP_APB4ENSETR, 16, USBPHY_K, _USBPHY_SEL), diff --git a/fdts/stm32mp157a-dk1.dts b/fdts/stm32mp157a-dk1.dts index 68188be..9016b0f 100644 --- a/fdts/stm32mp157a-dk1.dts +++ b/fdts/stm32mp157a-dk1.dts @@ -146,6 +146,12 @@ status = "okay"; }; +&pwr { + pwr-regulators { + vdd-supply = <&vdd>; + }; +}; + &rng1 { status = "okay"; }; diff --git a/fdts/stm32mp157c-ed1.dts b/fdts/stm32mp157c-ed1.dts index 820e413..7b16616 100644 --- a/fdts/stm32mp157c-ed1.dts +++ b/fdts/stm32mp157c-ed1.dts @@ -143,6 +143,12 @@ status = "okay"; }; +&pwr { + pwr-regulators { + vdd-supply = <&vdd>; + }; +}; + &rng1 { status = "okay"; }; diff --git a/fdts/stm32mp157c.dtsi b/fdts/stm32mp157c.dtsi index 0ec7ecb..1df76fa 100644 --- a/fdts/stm32mp157c.dtsi +++ b/fdts/stm32mp157c.dtsi @@ -1,6 +1,6 @@ // SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) /* - * Copyright (C) STMicroelectronics 2017 - All Rights Reserved + * Copyright (C) STMicroelectronics 2017-2019 - All Rights Reserved * Author: Ludovic Barre for STMicroelectronics. */ #include @@ -170,6 +170,12 @@ }; }; + syscfg: syscon@50020000 { + compatible = "st,stm32mp157-syscfg", "syscon"; + reg = <0x50020000 0x400>; + clocks = <&rcc SYSCFG>; + }; + rng1: rng@54003000 { compatible = "st,stm32-rng"; reg = <0x54003000 0x400>; diff --git a/plat/st/common/include/stm32mp_dt.h b/plat/st/common/include/stm32mp_dt.h index 3415b05..3e2c632 100644 --- a/plat/st/common/include/stm32mp_dt.h +++ b/plat/st/common/include/stm32mp_dt.h @@ -41,6 +41,8 @@ uintptr_t dt_get_ddrctrl_base(void); uintptr_t dt_get_ddrphyc_base(void); uintptr_t dt_get_pwr_base(void); +uint32_t dt_get_pwr_vdd_voltage(void); +uintptr_t dt_get_syscfg_base(void); const char *dt_get_board_model(void); #endif /* STM32MP_DT_H */ diff --git a/plat/st/common/stm32mp_dt.c b/plat/st/common/stm32mp_dt.c index e64433b..8e82863 100644 --- a/plat/st/common/stm32mp_dt.c +++ b/plat/st/common/stm32mp_dt.c @@ -359,6 +359,68 @@ } /******************************************************************************* + * This function gets PWR VDD regulator voltage information from the DT. + * Returns value in microvolts on success, and 0 on failure. + ******************************************************************************/ +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); + if (node < 0) { + INFO("%s: Cannot read PWR node in DT\n", __func__); + return 0; + } + + pwr_regulators_node = fdt_subnode_offset(fdt, node, "pwr-regulators"); + if (node < 0) { + INFO("%s: Cannot read pwr-regulators node in DT\n", __func__); + return 0; + } + + cuint = fdt_getprop(fdt, pwr_regulators_node, "vdd-supply", NULL); + if (cuint == NULL) { + return 0; + } + + node = fdt_node_offset_by_phandle(fdt, fdt32_to_cpu(*cuint)); + if (node < 0) { + return 0; + } + + cuint = fdt_getprop(fdt, node, "regulator-min-microvolt", NULL); + if (cuint == NULL) { + return 0; + } + + return fdt32_to_cpu(*cuint); +} + +/******************************************************************************* + * This function gets SYSCFG base address information from the DT. + * Returns value on success, and 0 on failure. + ******************************************************************************/ +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); +} + +/******************************************************************************* * This function retrieves board model from DT * Returns string taken from model node, NULL otherwise ******************************************************************************/ diff --git a/plat/st/stm32mp1/bl2_plat_setup.c b/plat/st/stm32mp1/bl2_plat_setup.c index b54486e..27d298e 100644 --- a/plat/st/stm32mp1/bl2_plat_setup.c +++ b/plat/st/stm32mp1/bl2_plat_setup.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -211,6 +212,10 @@ ; } + if (bsec_probe() != 0) { + panic(); + } + /* Reset backup domain on cold boot cases */ if ((mmio_read_32(rcc_base + RCC_BDCR) & RCC_BDCR_RTCSRC_MASK) == 0U) { mmio_setbits_32(rcc_base + RCC_BDCR, RCC_BDCR_VSWRST); @@ -236,6 +241,8 @@ panic(); } + stm32mp1_syscfg_init(); + result = dt_get_stdout_uart_info(&dt_uart_info); if ((result <= 0) || diff --git a/plat/st/stm32mp1/include/stm32mp1_private.h b/plat/st/stm32mp1/include/stm32mp1_private.h index 49a2bdf..e38fca0 100644 --- a/plat/st/stm32mp1/include/stm32mp1_private.h +++ b/plat/st/stm32mp1/include/stm32mp1_private.h @@ -17,4 +17,8 @@ void stm32mp1_gic_pcpu_init(void); void stm32mp1_gic_init(void); +void stm32mp1_syscfg_init(void); +void stm32mp1_syscfg_enable_io_compensation(void); +void stm32mp1_syscfg_disable_io_compensation(void); + #endif /* STM32MP1_PRIVATE_H */ diff --git a/plat/st/stm32mp1/platform.mk b/plat/st/stm32mp1/platform.mk index ffe0cc6..a05f619 100644 --- a/plat/st/stm32mp1/platform.mk +++ b/plat/st/stm32mp1/platform.mk @@ -65,7 +65,8 @@ plat/st/common/stm32mp_dt.c \ plat/st/stm32mp1/stm32mp1_context.c \ plat/st/stm32mp1/stm32mp1_helper.S \ - plat/st/stm32mp1/stm32mp1_security.c + plat/st/stm32mp1/stm32mp1_security.c \ + plat/st/stm32mp1/stm32mp1_syscfg.c BL2_SOURCES += drivers/io/io_block.c \ drivers/io/io_dummy.c \ diff --git a/plat/st/stm32mp1/stm32mp1_def.h b/plat/st/stm32mp1/stm32mp1_def.h index cff7ddb..c6fb692 100644 --- a/plat/st/stm32mp1/stm32mp1_def.h +++ b/plat/st/stm32mp1/stm32mp1_def.h @@ -239,11 +239,15 @@ /* OTP offsets */ #define DATA0_OTP U(0) +#define HW2_OTP U(18) /* OTP mask */ /* DATA0 */ #define DATA0_OTP_SECURED BIT(6) +/* HW2 OTP */ +#define HW2_OTP_PRODUCT_BELOW_2V5 BIT(13) + /******************************************************************************* * STM32MP1 TAMP ******************************************************************************/ @@ -277,5 +281,6 @@ ******************************************************************************/ #define DT_PWR_COMPAT "st,stm32mp1-pwr" #define DT_RCC_CLK_COMPAT "st,stm32mp1-rcc" +#define DT_SYSCFG_COMPAT "st,stm32mp157-syscfg" #endif /* STM32MP1_DEF_H */ diff --git a/plat/st/stm32mp1/stm32mp1_syscfg.c b/plat/st/stm32mp1/stm32mp1_syscfg.c new file mode 100644 index 0000000..2fd06f3 --- /dev/null +++ b/plat/st/stm32mp1/stm32mp1_syscfg.c @@ -0,0 +1,180 @@ +/* + * Copyright (c) 2019, STMicroelectronics - All Rights Reserved + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include + +#include +#include +#include +#include + +#include +#include + +/* + * SYSCFG REGISTER OFFSET (base relative) + */ +#define SYSCFG_BOOTR 0x00U +#define SYSCFG_IOCTRLSETR 0x18U +#define SYSCFG_ICNR 0x1CU +#define SYSCFG_CMPCR 0x20U +#define SYSCFG_CMPENSETR 0x24U + +/* + * SYSCFG_BOOTR Register + */ +#define SYSCFG_BOOTR_BOOT_MASK GENMASK(2, 0) +#define SYSCFG_BOOTR_BOOTPD_MASK GENMASK(6, 4) +#define SYSCFG_BOOTR_BOOTPD_SHIFT 4 +/* + * SYSCFG_IOCTRLSETR Register + */ +#define SYSCFG_IOCTRLSETR_HSLVEN_TRACE BIT(0) +#define SYSCFG_IOCTRLSETR_HSLVEN_QUADSPI BIT(1) +#define SYSCFG_IOCTRLSETR_HSLVEN_ETH BIT(2) +#define SYSCFG_IOCTRLSETR_HSLVEN_SDMMC BIT(3) +#define SYSCFG_IOCTRLSETR_HSLVEN_SPI BIT(4) + +/* + * SYSCFG_ICNR Register + */ +#define SYSCFG_ICNR_AXI_M9 BIT(9) + +/* + * SYSCFG_CMPCR Register + */ +#define SYSCFG_CMPCR_SW_CTRL BIT(1) +#define SYSCFG_CMPCR_READY BIT(8) +#define SYSCFG_CMPCR_RANSRC GENMASK(19, 16) +#define SYSCFG_CMPCR_RANSRC_SHIFT 16 +#define SYSCFG_CMPCR_RAPSRC GENMASK(23, 20) +#define SYSCFG_CMPCR_ANSRC_SHIFT 24 + +/* + * SYSCFG_CMPENSETR Register + */ +#define SYSCFG_CMPENSETR_MPU_EN BIT(0) + +void stm32mp1_syscfg_init(void) +{ + uint32_t bootr; + uint32_t otp = 0; + uint32_t vdd_voltage; + uintptr_t syscfg_base = dt_get_syscfg_base(); + + /* + * Interconnect update : select master using the port 1. + * LTDC = AXI_M9. + */ + mmio_write_32(syscfg_base + SYSCFG_ICNR, SYSCFG_ICNR_AXI_M9); + + /* Disable Pull-Down for boot pin connected to VDD */ + bootr = mmio_read_32(syscfg_base + SYSCFG_BOOTR) & + SYSCFG_BOOTR_BOOT_MASK; + mmio_clrsetbits_32(syscfg_base + SYSCFG_BOOTR, SYSCFG_BOOTR_BOOTPD_MASK, + bootr << SYSCFG_BOOTR_BOOTPD_SHIFT); + + /* + * High Speed Low Voltage Pad mode Enable for SPI, SDMMC, ETH, QSPI + * and TRACE. Needed above ~50MHz and conditioned by AFMUX selection. + * It could be disabled for low frequencies or if AFMUX is selected + * but the function is not used, typically for TRACE. + * If high speed low voltage pad mode is node enable, platform will + * over consume. + * + * WARNING: + * Enabling High Speed mode while VDD > 2.7V + * with the OTP product_below_2v5 (OTP 18, BIT 13) + * erroneously set to 1 can damage the SoC! + * => 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) { + panic(); + } + + otp = otp & HW2_OTP_PRODUCT_BELOW_2V5; + + /* Get VDD supply */ + vdd_voltage = dt_get_pwr_vdd_voltage(); + + /* Check if VDD is Low Voltage */ + if (vdd_voltage == 0U) { + WARN("VDD unknown"); + } else if (vdd_voltage < 2700000U) { + mmio_write_32(syscfg_base + SYSCFG_IOCTRLSETR, + SYSCFG_IOCTRLSETR_HSLVEN_TRACE | + SYSCFG_IOCTRLSETR_HSLVEN_QUADSPI | + SYSCFG_IOCTRLSETR_HSLVEN_ETH | + SYSCFG_IOCTRLSETR_HSLVEN_SDMMC | + SYSCFG_IOCTRLSETR_HSLVEN_SPI); + + if (otp == 0U) { + INFO("Product_below_2v5=0: HSLVEN protected by HW\n"); + } + } else { + if (otp != 0U) { + ERROR("Product_below_2v5=1:\n"); + ERROR("\tHSLVEN update is destructive,\n"); + ERROR("\tno update as VDD > 2.7V\n"); + panic(); + } + } + + stm32mp1_syscfg_enable_io_compensation(); +} + +void stm32mp1_syscfg_enable_io_compensation(void) +{ + uintptr_t syscfg_base = dt_get_syscfg_base(); + + /* + * Activate automatic I/O compensation. + * Warning: need to ensure CSI enabled and ready in clock driver. + * Enable non-secure clock, we assume non-secure is suspended. + */ + stm32mp1_clk_enable_non_secure(SYSCFG); + + mmio_setbits_32(syscfg_base + SYSCFG_CMPENSETR, + SYSCFG_CMPENSETR_MPU_EN); + + while ((mmio_read_32(syscfg_base + SYSCFG_CMPCR) & + SYSCFG_CMPCR_READY) == 0U) { + ; + } + + mmio_clrbits_32(syscfg_base + SYSCFG_CMPCR, SYSCFG_CMPCR_SW_CTRL); +} + +void stm32mp1_syscfg_disable_io_compensation(void) +{ + uintptr_t syscfg_base = dt_get_syscfg_base(); + uint32_t value; + + /* + * Deactivate automatic I/O compensation. + * Warning: CSI is disabled automatically in STOP if not + * requested for other usages and always OFF in STANDBY. + * Disable non-secure SYSCFG clock, we assume non-secure is suspended. + */ + value = mmio_read_32(syscfg_base + SYSCFG_CMPCR) >> + SYSCFG_CMPCR_ANSRC_SHIFT; + + mmio_clrbits_32(syscfg_base + SYSCFG_CMPCR, + SYSCFG_CMPCR_RANSRC | SYSCFG_CMPCR_RAPSRC); + + value = mmio_read_32(syscfg_base + SYSCFG_CMPCR) | + (value << SYSCFG_CMPCR_RANSRC_SHIFT); + + mmio_write_32(syscfg_base + SYSCFG_CMPCR, value); + + mmio_setbits_32(syscfg_base + SYSCFG_CMPCR, SYSCFG_CMPCR_SW_CTRL); + + mmio_clrbits_32(syscfg_base + SYSCFG_CMPENSETR, + SYSCFG_CMPENSETR_MPU_EN); + + stm32mp1_clk_disable_non_secure(SYSCFG); +}