stm32mp1: add general SYSCFG management
authorYann Gautier <yann.gautier@st.com>
Mon, 20 May 2019 17:17:08 +0000 (19:17 +0200)
committerYann Gautier <yann.gautier@st.com>
Mon, 17 Jun 2019 12:03:51 +0000 (14:03 +0200)
The system configuration controller is mainly used to manage
the compensation cell and other IOs and system related settings.

The SYSCFG driver is in charge of configuring masters on the interconnect,
IO compensation, low voltage boards, or pull-ups for boot pins.
All other configurations should be handled in Linux drivers requiring it.

Device tree files are also updated to manage vdd-supply regulator.

Change-Id: I10fb513761a7d1f2b7afedca9c723ad9d1bccf42
Signed-off-by: Nicolas Le Bayon <nicolas.le.bayon@st.com>
Signed-off-by: Yann Gautier <yann.gautier@st.com>
drivers/st/clk/stm32mp1_clk.c
fdts/stm32mp157a-dk1.dts
fdts/stm32mp157c-ed1.dts
fdts/stm32mp157c.dtsi
plat/st/common/include/stm32mp_dt.h
plat/st/common/stm32mp_dt.c
plat/st/stm32mp1/bl2_plat_setup.c
plat/st/stm32mp1/include/stm32mp1_private.h
plat/st/stm32mp1/platform.mk
plat/st/stm32mp1/stm32mp1_def.h
plat/st/stm32mp1/stm32mp1_syscfg.c [new file with mode: 0644]

index cea1c46f3ebb720978dd69689f94aa9cbc25534b..76e6e6fdcf52520001cf1a45839f6a120d47a852 100644 (file)
@@ -323,6 +323,8 @@ static const struct stm32mp1_clk_gate stm32mp1_clk_gate[] = {
        _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),
index 68188be92b4449eded40c0a971e8723f127f9153..9016b0f5b0a679caa5afc421ff86129ca6239d0a 100644 (file)
        status = "okay";
 };
 
+&pwr {
+       pwr-regulators {
+               vdd-supply = <&vdd>;
+       };
+};
+
 &rng1 {
        status = "okay";
 };
index 820e4131e9460069de91752101595018a67ce046..7b16616b041263b019a35b97ef7b7200d673944e 100644 (file)
        status = "okay";
 };
 
+&pwr {
+       pwr-regulators {
+               vdd-supply = <&vdd>;
+       };
+};
+
 &rng1 {
        status = "okay";
 };
index 0ec7ecb783ef7fa09bd797d182a9ee75d74fdce7..1df76fa752e7fbaa33a8ae9b1bce24ef83fcbdb7 100644 (file)
@@ -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 <ludovic.barre@st.com> for STMicroelectronics.
  */
 #include <dt-bindings/interrupt-controller/arm-gic.h>
                        };
                };
 
+               syscfg: syscon@50020000 {
+                       compatible = "st,stm32mp157-syscfg", "syscon";
+                       reg = <0x50020000 0x400>;
+                       clocks = <&rcc SYSCFG>;
+               };
+
                rng1: rng@54003000 {
                        compatible = "st,stm32-rng";
                        reg = <0x54003000 0x400>;
index 3415b051d5b08c6d7e1b5d9b8770771099bc6cac..3e2c632cbb6b83c605b3e4c573d3a8b8dbada98b 100644 (file)
@@ -41,6 +41,8 @@ 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_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 */
index e64433bc822a9d7dbfbb4fbfc4e5df414b85c47e..8e828631bfa89f8fe5cb14b024501b8c342429a5 100644 (file)
@@ -358,6 +358,68 @@ uintptr_t dt_get_pwr_base(void)
        return fdt32_to_cpu(*cuint);
 }
 
+/*******************************************************************************
+ * 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
index b54486e843c7066e34c45f800d6d37b939594f17..27d298e8d5dfdd9054542cab18cfdfa93bfcc70a 100644 (file)
@@ -15,6 +15,7 @@
 #include <common/desc_image_load.h>
 #include <drivers/delay_timer.h>
 #include <drivers/generic_delay_timer.h>
+#include <drivers/st/bsec.h>
 #include <drivers/st/stm32_console.h>
 #include <drivers/st/stm32mp_pmic.h>
 #include <drivers/st/stm32mp_reset.h>
@@ -211,6 +212,10 @@ void bl2_el3_plat_arch_setup(void)
                ;
        }
 
+       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 @@ void bl2_el3_plat_arch_setup(void)
                panic();
        }
 
+       stm32mp1_syscfg_init();
+
        result = dt_get_stdout_uart_info(&dt_uart_info);
 
        if ((result <= 0) ||
index 49a2bdf415d0eb1c715ac2d698c44ad75908271f..e38fca012750be25268c6e09d606b1d1472a93e3 100644 (file)
@@ -17,4 +17,8 @@ void stm32mp1_security_setup(void);
 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 */
index ffe0cc643417967792f166ec55a188bab63dd7e4..a05f61988ce3a90f63efb534f85712cbbbd92169 100644 (file)
@@ -65,7 +65,8 @@ PLAT_BL_COMMON_SOURCES        +=      ${LIBFDT_SRCS}                                          \
                                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                                   \
index cff7ddbd631110a26a347b0d9fa077aadeb58f78..c6fb692eadcc574bb1d3c33476ed57137817bfa9 100644 (file)
@@ -239,11 +239,15 @@ enum ddr_type {
 
 /* 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 @@ static inline uint32_t tamp_bkpr(uint32_t idx)
  ******************************************************************************/
 #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 (file)
index 0000000..2fd06f3
--- /dev/null
@@ -0,0 +1,180 @@
+/*
+ * Copyright (c) 2019, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <common/debug.h>
+#include <drivers/st/bsec.h>
+#include <drivers/st/stpmic1.h>
+#include <lib/mmio.h>
+
+#include <stm32mp_dt.h>
+#include <stm32mp1_private.h>
+
+/*
+ * 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);
+}