4026 lines
114 KiB
Diff
4026 lines
114 KiB
Diff
From 120829073d96f24a5cc92626675a5d591b2fa726 Mon Sep 17 00:00:00 2001
|
|
From: Romuald JEANNE <romuald.jeanne@st.com>
|
|
Date: Mon, 20 Jan 2020 15:46:53 +0100
|
|
Subject: [PATCH] st updates r3
|
|
|
|
Signed-off-by: Romuald JEANNE <romuald.jeanne@st.com>
|
|
---
|
|
core/arch/arm/fdts/stm32mp15-ddr.dtsi | 4 +-
|
|
core/arch/arm/fdts/stm32mp157a-dk1.dts | 34 +-
|
|
core/arch/arm/fdts/stm32mp157c-ed1.dts | 51 +-
|
|
core/arch/arm/fdts/stm32mp157c-security.dtsi | 52 +-
|
|
core/arch/arm/fdts/stm32mp157c.dtsi | 38 ++
|
|
core/arch/arm/plat-stm32mp1/drivers/stm32mp1_clk.c | 669 ++++++++++++++++++++-
|
|
core/arch/arm/plat-stm32mp1/drivers/stm32mp1_clk.h | 9 +-
|
|
.../arm/plat-stm32mp1/drivers/stm32mp1_clkfunc.c | 58 +-
|
|
.../arch/arm/plat-stm32mp1/drivers/stm32mp1_ddrc.c | 20 +
|
|
.../arch/arm/plat-stm32mp1/drivers/stm32mp1_ddrc.h | 1 +
|
|
.../arch/arm/plat-stm32mp1/drivers/stm32mp1_pmic.c | 76 +--
|
|
.../arch/arm/plat-stm32mp1/drivers/stm32mp1_pmic.h | 7 +-
|
|
.../arm/plat-stm32mp1/drivers/stm32mp1_syscfg.c | 97 +++
|
|
core/arch/arm/plat-stm32mp1/drivers/sub.mk | 1 +
|
|
core/arch/arm/plat-stm32mp1/main.c | 162 ++++-
|
|
core/arch/arm/plat-stm32mp1/platform_config.h | 49 +-
|
|
core/arch/arm/plat-stm32mp1/pm/context.c | 45 +-
|
|
core/arch/arm/plat-stm32mp1/pm/low_power.c | 10 +-
|
|
core/arch/arm/plat-stm32mp1/pm/pm_helpers.S | 143 ++++-
|
|
core/arch/arm/plat-stm32mp1/pm/power_config.c | 4 +-
|
|
core/arch/arm/plat-stm32mp1/service/bsec_svc.c | 4 +
|
|
core/arch/arm/plat-stm32mp1/service/rcc_svc.c | 30 +-
|
|
core/arch/arm/plat-stm32mp1/service/rcc_svc.h | 3 +-
|
|
core/arch/arm/plat-stm32mp1/service/stm32mp1_smc.h | 16 +
|
|
.../arm/plat-stm32mp1/service/stm32mp1_svc_setup.c | 5 +-
|
|
core/arch/arm/plat-stm32mp1/stm32_util.h | 20 +-
|
|
core/arch/arm/plat-stm32mp1/stm32mp1_dt.c | 194 +++++-
|
|
core/arch/arm/plat-stm32mp1/stm32mp_dt.h | 10 +-
|
|
core/drivers/stm32_bsec.c | 188 +++++-
|
|
core/drivers/stm32_i2c.c | 232 ++++---
|
|
core/drivers/stm32_iwdg.c | 25 +-
|
|
core/drivers/stm32_rtc.c | 39 +-
|
|
core/drivers/stpmic1.c | 25 +-
|
|
core/include/drivers/stm32_bsec.h | 13 +
|
|
core/include/drivers/stm32_i2c.h | 24 +-
|
|
core/include/drivers/stm32_iwdg.h | 6 +-
|
|
core/include/drivers/stpmic1.h | 27 +-
|
|
37 files changed, 2030 insertions(+), 361 deletions(-)
|
|
create mode 100644 core/arch/arm/plat-stm32mp1/drivers/stm32mp1_syscfg.c
|
|
|
|
diff --git a/core/arch/arm/fdts/stm32mp15-ddr.dtsi b/core/arch/arm/fdts/stm32mp15-ddr.dtsi
|
|
index 1a5c51c..d3481e5 100644
|
|
--- a/core/arch/arm/fdts/stm32mp15-ddr.dtsi
|
|
+++ b/core/arch/arm/fdts/stm32mp15-ddr.dtsi
|
|
@@ -1,11 +1,11 @@
|
|
// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
|
|
/*
|
|
- * Copyright (C) 2018, STMicroelectronics - All Rights Reserved
|
|
+ * Copyright (C) 2018-2019, STMicroelectronics - All Rights Reserved
|
|
*/
|
|
|
|
/ {
|
|
soc {
|
|
- ddr: ddr@5A003000{
|
|
+ ddr: ddr@5a003000{
|
|
|
|
compatible = "st,stm32mp1-ddr";
|
|
|
|
diff --git a/core/arch/arm/fdts/stm32mp157a-dk1.dts b/core/arch/arm/fdts/stm32mp157a-dk1.dts
|
|
index 78cb849..b54b284 100644
|
|
--- a/core/arch/arm/fdts/stm32mp157a-dk1.dts
|
|
+++ b/core/arch/arm/fdts/stm32mp157a-dk1.dts
|
|
@@ -21,8 +21,7 @@
|
|
|
|
chosen {
|
|
stdout-path = "serial0:115200n8";
|
|
-};
|
|
-
|
|
+ };
|
|
};
|
|
|
|
&clk_hse {
|
|
@@ -34,6 +33,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 +43,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";
|
|
@@ -224,6 +221,13 @@
|
|
};
|
|
|
|
/* Security specific */
|
|
+&bsec {
|
|
+ board_id: board_id@ec {
|
|
+ reg = <0xec 0x4>;
|
|
+ st,non-secure-otp;
|
|
+ };
|
|
+};
|
|
+
|
|
&etzpc {
|
|
st,decprot = <
|
|
DECPROT(STM32MP1_ETZPC_USART1_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
|
|
@@ -240,6 +244,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/core/arch/arm/fdts/stm32mp157c-ed1.dts b/core/arch/arm/fdts/stm32mp157c-ed1.dts
|
|
index 81ae94c..ff9441e 100644
|
|
--- a/core/arch/arm/fdts/stm32mp157c-ed1.dts
|
|
+++ b/core/arch/arm/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";
|
|
@@ -229,6 +227,13 @@
|
|
};
|
|
|
|
/* Security specific */
|
|
+&bsec {
|
|
+ board_id: board_id@ec {
|
|
+ reg = <0xec 0x4>;
|
|
+ st,non-secure-otp;
|
|
+ };
|
|
+};
|
|
+
|
|
&etzpc {
|
|
st,decprot = <
|
|
DECPROT(STM32MP1_ETZPC_USART1_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
|
|
@@ -245,13 +250,31 @@
|
|
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
|
|
STM32_PM_CSTOP_ALLOW_LP_STOP
|
|
+ STM32_PM_CSTOP_ALLOW_LPLV_STOP
|
|
STM32_PM_CSTOP_ALLOW_STANDBY_DDR_SR
|
|
>;
|
|
-
|
|
system_off_soc_mode = <STM32_PM_CSTOP_ALLOW_STANDBY_DDR_OFF>;
|
|
};
|
|
|
|
@@ -267,6 +290,10 @@
|
|
regulator-on-in-suspend;
|
|
regulator-suspend-microvolt = <1200000>;
|
|
};
|
|
+ lplv-stop {
|
|
+ regulator-on-in-suspend;
|
|
+ regulator-suspend-microvolt = <900000>;
|
|
+ };
|
|
standby-ddr-sr {
|
|
regulator-off-in-suspend;
|
|
};
|
|
@@ -280,6 +307,10 @@
|
|
regulator-suspend-microvolt = <1350000>;
|
|
regulator-on-in-suspend;
|
|
};
|
|
+ lplv-stop {
|
|
+ regulator-suspend-microvolt = <1350000>;
|
|
+ regulator-on-in-suspend;
|
|
+ };
|
|
standby-ddr-sr {
|
|
regulator-suspend-microvolt = <1350000>;
|
|
regulator-on-in-suspend;
|
|
@@ -294,6 +325,10 @@
|
|
regulator-suspend-microvolt = <3300000>;
|
|
regulator-on-in-suspend;
|
|
};
|
|
+ lplv-stop {
|
|
+ regulator-suspend-microvolt = <3300000>;
|
|
+ regulator-on-in-suspend;
|
|
+ };
|
|
standby-ddr-sr {
|
|
regulator-suspend-microvolt = <3300000>;
|
|
regulator-on-in-suspend;
|
|
@@ -335,6 +370,9 @@
|
|
lp-stop {
|
|
regulator-off-in-suspend;
|
|
};
|
|
+ lplv-stop {
|
|
+ regulator-off-in-suspend;
|
|
+ };
|
|
standby-ddr-sr {
|
|
regulator-off-in-suspend;
|
|
};
|
|
@@ -374,6 +412,9 @@
|
|
lp-stop {
|
|
regulator-on-in-suspend;
|
|
};
|
|
+ lplv-stop {
|
|
+ regulator-on-in-suspend;
|
|
+ };
|
|
standby-ddr-sr {
|
|
regulator-on-in-suspend;
|
|
};
|
|
diff --git a/core/arch/arm/fdts/stm32mp157c-security.dtsi b/core/arch/arm/fdts/stm32mp157c-security.dtsi
|
|
index bff1043..5f5404f 100644
|
|
--- a/core/arch/arm/fdts/stm32mp157c-security.dtsi
|
|
+++ b/core/arch/arm/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: iwdg@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,23 +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>;
|
|
};
|
|
- /* Spare field to align on 32-bit OTP granularity */
|
|
- spare_ns_ea: spare_ns_ea@ea {
|
|
- reg = <0xea 0x2>;
|
|
+ monotonic_otp: monotonic_otp@10 {
|
|
+ reg = <0x10 0x4>;
|
|
};
|
|
- board_id: board_id@ec {
|
|
- reg = <0xec 0x4>;
|
|
+ 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/core/arch/arm/fdts/stm32mp157c.dtsi b/core/arch/arm/fdts/stm32mp157c.dtsi
|
|
index 06c2cf1..13125b1 100644
|
|
--- a/core/arch/arm/fdts/stm32mp157c.dtsi
|
|
+++ b/core/arch/arm/fdts/stm32mp157c.dtsi
|
|
@@ -290,6 +290,27 @@
|
|
status = "disabled";
|
|
};
|
|
|
|
+ usbphyc: usbphyc@5a006000 {
|
|
+ #address-cells = <1>;
|
|
+ #size-cells = <0>;
|
|
+ #clock-cells = <0>;
|
|
+ compatible = "st,stm32mp1-usbphyc";
|
|
+ reg = <0x5a006000 0x1000>;
|
|
+ clocks = <&rcc USBPHY_K>;
|
|
+ resets = <&rcc USBPHY_R>;
|
|
+ status = "disabled";
|
|
+
|
|
+ usbphyc_port0: usb-phy@0 {
|
|
+ #phy-cells = <0>;
|
|
+ reg = <0>;
|
|
+ };
|
|
+
|
|
+ usbphyc_port1: usb-phy@1 {
|
|
+ #phy-cells = <1>;
|
|
+ reg = <1>;
|
|
+ };
|
|
+ };
|
|
+
|
|
usart1: serial@5c000000 {
|
|
compatible = "st,stm32h7-uart";
|
|
reg = <0x5c000000 0x400>;
|
|
@@ -367,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/core/arch/arm/plat-stm32mp1/drivers/stm32mp1_clk.c b/core/arch/arm/plat-stm32mp1/drivers/stm32mp1_clk.c
|
|
index 69c3c74..5a02de1 100644
|
|
--- a/core/arch/arm/plat-stm32mp1/drivers/stm32mp1_clk.c
|
|
+++ b/core/arch/arm/plat-stm32mp1/drivers/stm32mp1_clk.c
|
|
@@ -1,6 +1,6 @@
|
|
// SPDX-License-Identifier: GPL-2.0+ BSD-3-Clause
|
|
/*
|
|
- * Copyright (C) 2017-2018, STMicroelectronics - All Rights Reserved
|
|
+ * Copyright (C) 2017-2019, STMicroelectronics - All Rights Reserved
|
|
*/
|
|
|
|
#include <assert.h>
|
|
@@ -33,6 +33,22 @@
|
|
#endif
|
|
|
|
#define CLKSRC_TIMEOUT_US 200000U
|
|
+#define PLLRDY_TIMEOUT_US 200000U
|
|
+
|
|
+/* 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
|
|
+
|
|
+#define PLL1_SETTINGS_VALID_ID 0x504C4C31 /* "PLL1" */
|
|
|
|
enum stm32mp1_parent_id {
|
|
/* Oscillators are defined in enum stm32mp_osc_id */
|
|
@@ -191,6 +207,15 @@ struct stm32mp1_clk_pll {
|
|
enum stm32mp_osc_id refclk[REFCLK_SIZE];
|
|
};
|
|
|
|
+/* Compact structure of 32bit cells, copied raw when suspending */
|
|
+struct __attribute__((__packed__)) 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 not set/clr register access */
|
|
#define _CLK_SELEC(off, b, idx, s) \
|
|
{ \
|
|
@@ -364,6 +389,7 @@ static const struct stm32mp1_clk_gate stm32mp1_clk_gate[] = {
|
|
_CLK_SELEC(RCC_DBGCFGR, 8, CK_DBG, _UNKNOWN_SEL),
|
|
_CLK_SC_FIXED(RCC_MP_APB1ENSETR, 6, TIM12_K, _PCLK1),
|
|
_CLK_SC_FIXED(RCC_MP_APB2ENSETR, 2, TIM15_K, _PCLK2),
|
|
+ _CLK_SC_FIXED(RCC_MP_APB3ENSETR, 11, SYSCFG, _UNKNOWN_ID),
|
|
_CLK_SC_SELEC(RCC_MP_AHB6ENSETR, 0, MDMA, _UNKNOWN_SEL),
|
|
_CLK_SC_SELEC(RCC_MP_AHB6ENSETR, 5, GPU, _UNKNOWN_SEL),
|
|
_CLK_SC_FIXED(RCC_MP_AHB6ENSETR, 10, ETHMAC, _ACLK),
|
|
@@ -447,6 +473,20 @@ static const struct stm32mp1_clk_sel stm32mp1_clk_sel[_PARENT_SEL_NB] = {
|
|
_CLK_PARENT(_USBO_SEL, RCC_USBCKSELR, 4, 0x1, usbo_parents),
|
|
};
|
|
|
|
+/* Define characteristics of PLL according type */
|
|
+static const struct stm32mp1_pll stm32mp1_pll[PLL_TYPE_NB] = {
|
|
+ [PLL_800] = {
|
|
+ .refclk_min = 4,
|
|
+ .refclk_max = 16,
|
|
+ .divn_max = 99,
|
|
+ },
|
|
+ [PLL_1600] = {
|
|
+ .refclk_min = 8,
|
|
+ .refclk_max = 16,
|
|
+ .divn_max = 199,
|
|
+ },
|
|
+};
|
|
+
|
|
/* PLLNCFGR2 register divider by output */
|
|
static const uint8_t pllncfgr2[_DIV_NB] = {
|
|
[_DIV_P] = RCC_PLLNCFGR2_DIVP_SHIFT,
|
|
@@ -491,7 +531,7 @@ static const uint8_t stm32mp1_axi_div[8] = {
|
|
1, 2, 3, 4, 4, 4, 4, 4
|
|
};
|
|
|
|
-#if TRACE_LEVEL >= TRACE_DEBUG
|
|
+#if TRACE_LEVEL >= TRACE_FLOW
|
|
static const char *const __maybe_unused stm32mp1_clk_parent_name[_PARENT_NB] = {
|
|
[_HSI] = "HSI",
|
|
[_HSE] = "HSE",
|
|
@@ -534,6 +574,8 @@ static const char *const __maybe_unused stm32mp1_clk_parent_name[_PARENT_NB] = {
|
|
static unsigned long stm32mp1_osc[NB_OSC];
|
|
static unsigned int gate_refcounts[NB_GATES];
|
|
static unsigned int 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)
|
|
{
|
|
@@ -606,6 +648,155 @@ static enum stm32mp1_parent_id stm32mp1_clk_get_fixed_parent(int i)
|
|
return (enum stm32mp1_parent_id)gate_ref(i)->fixed;
|
|
}
|
|
|
|
+static void pll_start(enum stm32mp1_pll_id pll_id)
|
|
+{
|
|
+ const struct stm32mp1_clk_pll *pll = pll_ref(pll_id);
|
|
+ uint32_t pllxcr = stm32_rcc_base() + pll->pllxcr;
|
|
+
|
|
+ mmio_clrsetbits_32(pllxcr,
|
|
+ RCC_PLLNCR_DIVPEN | RCC_PLLNCR_DIVQEN |
|
|
+ RCC_PLLNCR_DIVREN,
|
|
+ RCC_PLLNCR_PLLON);
|
|
+}
|
|
+
|
|
+static int pll_output(enum stm32mp1_pll_id pll_id, uint32_t output)
|
|
+{
|
|
+ const struct stm32mp1_clk_pll *pll = pll_ref(pll_id);
|
|
+ uint32_t pllxcr = stm32_rcc_base() + pll->pllxcr;
|
|
+ uint64_t start;
|
|
+
|
|
+ start = utimeout_init(PLLRDY_TIMEOUT_US);
|
|
+ /* Wait PLL lock */
|
|
+ while ((mmio_read_32(pllxcr) & RCC_PLLNCR_PLLRDY) == 0U) {
|
|
+ if (utimeout_elapsed(PLLRDY_TIMEOUT_US, start)) {
|
|
+ EMSG("PLL%d start failed @ 0x%"PRIx32": 0x%"PRIx32,
|
|
+ pll_id, pllxcr, mmio_read_32(pllxcr));
|
|
+ return -1;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /* Start the requested output */
|
|
+ mmio_setbits_32(pllxcr, output << RCC_PLLNCR_DIVEN_SHIFT);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int pll_stop(enum stm32mp1_pll_id pll_id)
|
|
+{
|
|
+ const struct stm32mp1_clk_pll *pll = pll_ref(pll_id);
|
|
+ uint32_t pllxcr = stm32_rcc_base() + pll->pllxcr;
|
|
+ uint64_t start;
|
|
+
|
|
+ /* Stop all output */
|
|
+ mmio_clrbits_32(pllxcr, RCC_PLLNCR_DIVPEN | RCC_PLLNCR_DIVQEN |
|
|
+ RCC_PLLNCR_DIVREN);
|
|
+
|
|
+ /* Stop PLL */
|
|
+ mmio_clrbits_32(pllxcr, RCC_PLLNCR_PLLON);
|
|
+
|
|
+ start = utimeout_init(PLLRDY_TIMEOUT_US);
|
|
+ /* Wait PLL stopped */
|
|
+ while ((mmio_read_32(pllxcr) & RCC_PLLNCR_PLLRDY) != 0U) {
|
|
+ if (utimeout_elapsed(PLLRDY_TIMEOUT_US, start)) {
|
|
+ EMSG("PLL%d stop failed @ 0x%"PRIx32": 0x%"PRIx32,
|
|
+ pll_id, pllxcr, mmio_read_32(pllxcr));
|
|
+
|
|
+ return -1;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static uint32_t pll_compute_pllxcfgr2(uint32_t *pllcfg)
|
|
+{
|
|
+ uint32_t value;
|
|
+
|
|
+ value = (pllcfg[PLLCFG_P] << RCC_PLLNCFGR2_DIVP_SHIFT) &
|
|
+ RCC_PLLNCFGR2_DIVP_MASK;
|
|
+ value |= (pllcfg[PLLCFG_Q] << RCC_PLLNCFGR2_DIVQ_SHIFT) &
|
|
+ RCC_PLLNCFGR2_DIVQ_MASK;
|
|
+ value |= (pllcfg[PLLCFG_R] << RCC_PLLNCFGR2_DIVR_SHIFT) &
|
|
+ RCC_PLLNCFGR2_DIVR_MASK;
|
|
+
|
|
+ return value;
|
|
+}
|
|
+
|
|
+static void 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 = stm32_rcc_base();
|
|
+ uint32_t value;
|
|
+
|
|
+ value = pll_compute_pllxcfgr2(pllcfg);
|
|
+
|
|
+ mmio_write_32(rcc_base + pll->pllxcfgr2, value);
|
|
+}
|
|
+
|
|
+static int pll_compute_pllxcfgr1(const struct stm32mp1_clk_pll *pll,
|
|
+ uint32_t *pllcfg, uint32_t *cfgr1)
|
|
+{
|
|
+ uint32_t rcc_base = stm32_rcc_base();
|
|
+ enum stm32mp1_plltype type = pll->plltype;
|
|
+ unsigned long refclk;
|
|
+ uint32_t ifrge = 0;
|
|
+ uint32_t src;
|
|
+
|
|
+ src = mmio_read_32(rcc_base + pll->rckxselr) &
|
|
+ RCC_SELR_REFCLK_SRC_MASK;
|
|
+
|
|
+ refclk = stm32mp1_clk_get_fixed(pll->refclk[src]) /
|
|
+ (pllcfg[PLLCFG_M] + 1U);
|
|
+
|
|
+ if ((refclk < (stm32mp1_pll[type].refclk_min * 1000000U)) ||
|
|
+ (refclk > (stm32mp1_pll[type].refclk_max * 1000000U))) {
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ if ((type == PLL_800) && (refclk >= 8000000U)) {
|
|
+ ifrge = 1U;
|
|
+ }
|
|
+
|
|
+ *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 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 = stm32_rcc_base();
|
|
+ uint32_t value;
|
|
+ int ret;
|
|
+
|
|
+ ret = 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 = mmio_read_32(rcc_base + pll->pllxfracr);
|
|
+ mmio_write_32(rcc_base + pll->pllxfracr, value | RCC_PLLNFRACR_FRACLE);
|
|
+
|
|
+ pll_config_output(pll_id, pllcfg);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
static int stm32mp1_set_clksrc(unsigned int clksrc)
|
|
{
|
|
uintptr_t address = stm32_rcc_base() + (clksrc >> 4);
|
|
@@ -617,7 +808,7 @@ static int stm32mp1_set_clksrc(unsigned int clksrc)
|
|
timeout_ref = utimeout_init(CLKSRC_TIMEOUT_US);
|
|
while ((mmio_read_32(address) & RCC_SELR_SRCRDY) == 0U) {
|
|
if (utimeout_elapsed(CLKSRC_TIMEOUT_US, timeout_ref)) {
|
|
- EMSG("CLKSRC %x start failed @ 0x%x: 0x%x\n",
|
|
+ EMSG("CLKSRC %x start failed @%"PRIxPTR": 0x%"PRIx32"\n",
|
|
clksrc, address, mmio_read_32(address));
|
|
return -1;
|
|
}
|
|
@@ -1085,6 +1276,274 @@ unsigned long stm32mp1_clk_get_rate(unsigned long id)
|
|
}
|
|
|
|
#ifdef CFG_DT
|
|
+static int clk_compute_pll1_settings(unsigned long input_freq, int idx)
|
|
+{
|
|
+ unsigned long post_divm;
|
|
+ unsigned long long output_freq = pll1_settings.freq[idx] * 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 */
|
|
+ pll1_settings.cfg[idx][PLLCFG_Q] = 0;
|
|
+ pll1_settings.cfg[idx][PLLCFG_R] = 0;
|
|
+ pll1_settings.cfg[idx][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) {
|
|
+ pll1_settings.cfg[idx][PLLCFG_M] = divm;
|
|
+ pll1_settings.cfg[idx][PLLCFG_N] = divn;
|
|
+ pll1_settings.cfg[idx][PLLCFG_P] = divp;
|
|
+ pll1_settings.frac[idx] = 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, int index)
|
|
+{
|
|
+ unsigned long input_freq;
|
|
+ unsigned int i;
|
|
+
|
|
+ for (i = 0; i < PLAT_MAX_OPP_NB; i++) {
|
|
+ if (pll1_settings.freq[i] == pll1_settings.freq[index]) {
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (((i == PLAT_MAX_OPP_NB) &&
|
|
+ !stm32mp1_clk_pll1_settings_are_valid()) ||
|
|
+ ((i < PLAT_MAX_OPP_NB) &&
|
|
+ (pll1_settings.cfg[i][PLLCFG_O] == 0U))) {
|
|
+ /*
|
|
+ * Either PLL1 settings structure is completely empty,
|
|
+ * or these settings are not yet computed: do it.
|
|
+ */
|
|
+ switch (clksrc) {
|
|
+ case CLK_PLL12_HSI:
|
|
+ input_freq = stm32mp1_clk_get_rate(CK_HSI);
|
|
+ break;
|
|
+ case CLK_PLL12_HSE:
|
|
+ input_freq = stm32mp1_clk_get_rate(CK_HSE);
|
|
+ break;
|
|
+ default:
|
|
+ panic();
|
|
+ }
|
|
+
|
|
+ return clk_compute_pll1_settings(input_freq, index);
|
|
+ }
|
|
+
|
|
+ if ((i < PLAT_MAX_OPP_NB) &&
|
|
+ (pll1_settings.cfg[i][PLLCFG_O] != 0U)) {
|
|
+ /*
|
|
+ * Index is in range and PLL1 settings are computed:
|
|
+ * use content to answer to the request.
|
|
+ */
|
|
+ memcpy(&pll1_settings.cfg[index][0], &pll1_settings.cfg[i][0],
|
|
+ sizeof(uint32_t) * PLAT_MAX_PLLCFG_NB);
|
|
+ pll1_settings.frac[index] = pll1_settings.frac[i];
|
|
+
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ return -1;
|
|
+}
|
|
+
|
|
+static int clk_save_current_pll1_settings(uint32_t buck1_voltage)
|
|
+{
|
|
+ const struct stm32mp1_clk_pll *pll = pll_ref(_PLL1);
|
|
+ uint32_t rcc_base = stm32_rcc_base();
|
|
+ uint32_t freq;
|
|
+ unsigned int i;
|
|
+
|
|
+ freq = UDIV_ROUND_NEAREST(stm32mp1_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 = stm32_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)
|
|
+{
|
|
+ unsigned int i;
|
|
+ int ret;
|
|
+ int index;
|
|
+ uint32_t count = PLAT_MAX_OPP_NB;
|
|
+ uint32_t clksrc;
|
|
+ void *fdt;
|
|
+
|
|
+ fdt = get_dt_blob();
|
|
+ if (fdt == NULL) {
|
|
+ panic();
|
|
+ }
|
|
+
|
|
+ ret = fdt_get_all_opp_freqvolt(fdt, &count, pll1_settings.freq,
|
|
+ pll1_settings.volt);
|
|
+ switch (ret) {
|
|
+ case 0:
|
|
+ break;
|
|
+ case -FDT_ERR_NOTFOUND:
|
|
+ DMSG("Cannot find all OPP info in DT: use default settings");
|
|
+ return 0;
|
|
+ default:
|
|
+ EMSG("Inconsistent OPP settings found in DT, ignored.");
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ index = clk_save_current_pll1_settings(buck1_voltage);
|
|
+
|
|
+ clksrc = stm32mp1_clk_get_pll1_current_clksrc();
|
|
+
|
|
+ for (i = 0; i < count; i++) {
|
|
+ if ((index >= 0) && (i == (unsigned int)index))
|
|
+ continue;
|
|
+
|
|
+ ret = clk_get_pll1_settings(clksrc, i);
|
|
+ if (ret)
|
|
+ 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)) ||
|
|
+ !stm32mp1_clk_pll1_settings_are_valid()) {
|
|
+ panic();
|
|
+ }
|
|
+
|
|
+ memcpy(data, &pll1_settings, size);
|
|
+}
|
|
+
|
|
+bool stm32mp1_clk_pll1_settings_are_valid(void)
|
|
+{
|
|
+ return pll1_settings.valid_id == PLL1_SETTINGS_VALID_ID;
|
|
+}
|
|
+
|
|
static void stm32mp1_osc_clk_init(const char *name,
|
|
enum stm32mp_osc_id index)
|
|
{
|
|
@@ -1113,6 +1572,21 @@ static void stm32mp1_osc_init(void)
|
|
DMSG("Osc %s frequency: %lu", name[i], stm32mp1_osc[i]);
|
|
}
|
|
}
|
|
+#else /* CFG_DT */
|
|
+int stm32mp1_clk_compute_all_pll1_settings(uint32_t buck1_voltage __unused)
|
|
+{
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+void stm32mp1_clk_lp_save_opp_pll1_settings(uint8_t *data __unused,
|
|
+ size_t size __unused)
|
|
+{
|
|
+}
|
|
+
|
|
+bool stm32mp1_clk_pll1_settings_are_valid(void)
|
|
+{
|
|
+ return false;
|
|
+}
|
|
#endif
|
|
|
|
/*
|
|
@@ -1508,16 +1982,187 @@ static void sync_earlyboot_clocks_state(void)
|
|
stm32mp_register_clock_parents_secure(BKPSRAM);
|
|
|
|
stm32mp_register_clock_parents_secure(RTCAPB);
|
|
-
|
|
-#if CFG_TEE_CORE_NB_CORE > 1
|
|
stm32mp1_clk_enable_secure(RTCAPB);
|
|
-#endif
|
|
|
|
/* The low power sequences mandates RNG1 and CRYP1 support */
|
|
stm32mp_register_clock_parents_secure(RNG1_K);
|
|
stm32mp_register_clock_parents_secure(CRYP1);
|
|
}
|
|
|
|
+/*
|
|
+ * 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 as those in place, no need to reconfig.
|
|
+ * Return value is 0 if no error.
|
|
+ */
|
|
+static int 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 = stm32_rcc_base();
|
|
+ uint32_t fracr;
|
|
+ uint32_t value;
|
|
+ int ret;
|
|
+
|
|
+ ret = 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;
|
|
+ }
|
|
+
|
|
+ fracr = fracv << RCC_PLLNFRACR_FRACV_SHIFT;
|
|
+ fracr |= RCC_PLLNFRACR_FRACLE;
|
|
+ value = 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;
|
|
+}
|
|
+
|
|
+/* Configure PLL1 from input frequency OPP parameters */
|
|
+static int 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 -1;
|
|
+ }
|
|
+
|
|
+ ret = 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 reconfig, 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 = pll_stop(_PLL1);
|
|
+ if (ret != 0) {
|
|
+ return ret;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ ret = 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 */
|
|
+ pll_start(_PLL1);
|
|
+
|
|
+ ret = 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 (!stm32mp1_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 -1;
|
|
+ }
|
|
+
|
|
+ /* Check that PLL1 (without MPUDIV) is MPU clock source */
|
|
+ if (((mmio_read_32(stm32_rcc_base() + RCC_MPCKSELR) &
|
|
+ RCC_SELR_SRC_MASK)) != RCC_MPCKSELR_PLL) {
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ if (pll1_config_from_opp_khz(freq_khz) != 0) {
|
|
+ /* Restore original value */
|
|
+ if (pll1_config_from_opp_khz(current_opp_khz) != 0) {
|
|
+ EMSG("No CPU operating point can be set");
|
|
+ panic();
|
|
+ }
|
|
+
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ current_opp_khz = freq_khz;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+int stm32mp1_round_opp_khz(uint32_t *freq_khz)
|
|
+{
|
|
+ unsigned int i;
|
|
+ uint32_t round_opp = 0U;
|
|
+
|
|
+ if (!stm32mp1_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;
|
|
+}
|
|
+
|
|
static void _clock_mpu_suspend(void)
|
|
{
|
|
uintptr_t mpckselr = stm32_rcc_base() + RCC_MPCKSELR;
|
|
@@ -1582,10 +2227,22 @@ void stm32mp_clock_suspend_resume(enum pm_op op)
|
|
|
|
static TEE_Result stm32mp1_clk_probe(void)
|
|
{
|
|
+ unsigned long freq_khz;
|
|
+
|
|
+ assert(PLLCFG_NB == PLAT_MAX_PLLCFG_NB);
|
|
+
|
|
init_clock_tree_from_dt();
|
|
|
|
sync_earlyboot_clocks_state();
|
|
|
|
+ /* Save current CPU operating point value */
|
|
+ freq_khz = UDIV_ROUND_NEAREST(stm32mp1_clk_get_rate(CK_MPU), 1000UL);
|
|
+ if (freq_khz > (unsigned long)UINT32_MAX) {
|
|
+ panic();
|
|
+ }
|
|
+
|
|
+ current_opp_khz = (uint32_t)freq_khz;
|
|
+
|
|
return TEE_SUCCESS;
|
|
}
|
|
/* Setup clock support before driver initialization */
|
|
diff --git a/core/arch/arm/plat-stm32mp1/drivers/stm32mp1_clk.h b/core/arch/arm/plat-stm32mp1/drivers/stm32mp1_clk.h
|
|
index 783d81d..26fda3d 100644
|
|
--- a/core/arch/arm/plat-stm32mp1/drivers/stm32mp1_clk.h
|
|
+++ b/core/arch/arm/plat-stm32mp1/drivers/stm32mp1_clk.h
|
|
@@ -1,6 +1,6 @@
|
|
/* SPDX-License-Identifier: BSD-3-Clause */
|
|
/*
|
|
- * Copyright (C) 2018, STMicroelectronics - All Rights Reserved
|
|
+ * Copyright (C) 2018-2019, STMicroelectronics - All Rights Reserved
|
|
*/
|
|
|
|
#ifndef __STM32MP1_CLK_H__
|
|
@@ -22,6 +22,10 @@ enum stm32mp_osc_id {
|
|
_UNKNOWN_OSC_ID = 0xFF
|
|
};
|
|
|
|
+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);
|
|
+bool stm32mp1_clk_pll1_settings_are_valid(void);
|
|
+
|
|
void __stm32mp1_clk_enable(unsigned long id, bool caller_is_secure);
|
|
void __stm32mp1_clk_disable(unsigned long id, bool caller_is_secure);
|
|
bool stm32mp1_clk_is_enabled(unsigned long id);
|
|
@@ -56,6 +60,9 @@ void stm32mp_register_clock_parents_secure(unsigned long id);
|
|
|
|
void stm32mp_update_earlyboot_clocks_state(void);
|
|
|
|
+int stm32mp1_set_opp_khz(uint32_t freq_khz);
|
|
+int stm32mp1_round_opp_khz(uint32_t *freq_khz);
|
|
+
|
|
void stm32mp1_clock_suspend(void);
|
|
void stm32mp1_clock_resume(void);
|
|
|
|
diff --git a/core/arch/arm/plat-stm32mp1/drivers/stm32mp1_clkfunc.c b/core/arch/arm/plat-stm32mp1/drivers/stm32mp1_clkfunc.c
|
|
index c83d561..ea57c9a 100644
|
|
--- a/core/arch/arm/plat-stm32mp1/drivers/stm32mp1_clkfunc.c
|
|
+++ b/core/arch/arm/plat-stm32mp1/drivers/stm32mp1_clkfunc.c
|
|
@@ -1,6 +1,6 @@
|
|
// SPDX-License-Identifier: BSD-3-Clause
|
|
/*
|
|
- * Copyright (c) 2017-2018, STMicroelectronics - All Rights Reserved
|
|
+ * Copyright (c) 2017-2019, STMicroelectronics - All Rights Reserved
|
|
*/
|
|
|
|
#include <dt-bindings/clock/stm32mp1-clksrc.h>
|
|
@@ -55,6 +55,11 @@ int fdt_osc_read_freq(void *fdt, const char *name, uint32_t *freq)
|
|
if (strncmp(cchar, name, (size_t)ret) == 0) {
|
|
const fdt32_t *cuint;
|
|
|
|
+ if (_fdt_get_status(fdt, subnode) ==
|
|
+ DT_STATUS_DISABLED) {
|
|
+ goto exit;
|
|
+ }
|
|
+
|
|
cuint = fdt_getprop(fdt, subnode, "clock-frequency",
|
|
&ret);
|
|
if (cuint == NULL) {
|
|
@@ -67,7 +72,8 @@ int fdt_osc_read_freq(void *fdt, const char *name, uint32_t *freq)
|
|
}
|
|
}
|
|
|
|
- /* Oscillator not found, freq=0 */
|
|
+exit:
|
|
+ /* Oscillator not found or disabled, freq=0 */
|
|
*freq = 0;
|
|
return 0;
|
|
}
|
|
@@ -196,7 +202,7 @@ uint32_t fdt_rcc_read_addr(void *fdt)
|
|
******************************************************************************/
|
|
int fdt_get_rcc_node(void *fdt)
|
|
{
|
|
- return fdt_node_offset_by_compatible(fdt, -1, DT_RCC_CLK_COMPAT);
|
|
+ return fdt_get_node_by_compatible(fdt, DT_RCC_CLK_COMPAT);
|
|
}
|
|
|
|
/*******************************************************************************
|
|
@@ -272,8 +278,6 @@ const fdt32_t *fdt_rcc_read_prop(void *fdt, const char *prop_name, int *lenp)
|
|
******************************************************************************/
|
|
uintptr_t get_stgen_base(void)
|
|
{
|
|
- int node;
|
|
- const fdt32_t *cuint;
|
|
void *fdt;
|
|
|
|
fdt = get_dt_blob();
|
|
@@ -281,17 +285,7 @@ uintptr_t get_stgen_base(void)
|
|
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 fdt_get_peripheral_base(fdt, DT_STGEN_COMPAT);
|
|
}
|
|
|
|
/*******************************************************************************
|
|
@@ -305,36 +299,22 @@ unsigned long get_uart_clock_freq(uint32_t instance)
|
|
{
|
|
int node;
|
|
void *fdt;
|
|
+ int clk_id;
|
|
|
|
fdt = get_dt_blob();
|
|
if (fdt == NULL) {
|
|
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 ((uint32_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 = fdt_match_instance_by_compatible(fdt, DT_UART_COMPAT, instance);
|
|
+ if (node < 0) {
|
|
+ return 0;
|
|
+ }
|
|
|
|
- return stm32mp1_clk_get_rate(clk_id);
|
|
- }
|
|
-next:
|
|
- node = fdt_node_offset_by_compatible(fdt, node, DT_UART_COMPAT);
|
|
+ clk_id = fdt_get_clock_id(fdt, node);
|
|
+ if (clk_id < 0) {
|
|
+ return 0;
|
|
}
|
|
|
|
- return 0;
|
|
+ return stm32mp1_clk_get_rate((unsigned long)clk_id);
|
|
}
|
|
diff --git a/core/arch/arm/plat-stm32mp1/drivers/stm32mp1_ddrc.c b/core/arch/arm/plat-stm32mp1/drivers/stm32mp1_ddrc.c
|
|
index 03ded28..8bb2635 100644
|
|
--- a/core/arch/arm/plat-stm32mp1/drivers/stm32mp1_ddrc.c
|
|
+++ b/core/arch/arm/plat-stm32mp1/drivers/stm32mp1_ddrc.c
|
|
@@ -102,6 +102,14 @@ static void do_sw_ack(void)
|
|
}
|
|
}
|
|
|
|
+static bool ddr_supports_ssr_asr(void)
|
|
+{
|
|
+ uintptr_t ddrctrl_base = get_ddrctrl_base();
|
|
+ uint32_t mstr = mmio_read_32(ddrctrl_base + DDRCTRL_MSTR);
|
|
+
|
|
+ return (mstr & DDRCTRL_MSTR_LPDDR2) != 0U;
|
|
+}
|
|
+
|
|
static int ddr_sw_self_refresh_in(void)
|
|
{
|
|
uint64_t to_ref;
|
|
@@ -177,6 +185,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(ddrphy_base + DDRPHYC_ACIOCR, DDRPHYC_ACIOCR_ACOE);
|
|
+
|
|
mmio_setbits_32(ddrphy_base + DDRPHYC_DXCCR, DDRPHYC_DXCCR_DXPDD);
|
|
|
|
mmio_setbits_32(ddrphy_base + DDRPHYC_DXCCR, DDRPHYC_DXCCR_DXPDR);
|
|
@@ -321,6 +332,9 @@ int ddr_sw_self_refresh_exit(void)
|
|
/* Enable pad drivers */
|
|
mmio_clrbits_32(ddrphy_base + DDRPHYC_ACIOCR, DDRPHYC_ACIOCR_ACPDD);
|
|
|
|
+ /* Enable command/address output driver */
|
|
+ mmio_setbits_32(ddrphy_base + DDRPHYC_ACIOCR, DDRPHYC_ACIOCR_ACOE);
|
|
+
|
|
mmio_clrbits_32(ddrphy_base + DDRPHYC_ACIOCR,
|
|
DDRPHYC_ACIOCR_CKPDD_MASK);
|
|
|
|
@@ -398,6 +412,9 @@ void ddr_sr_mode_ssr(void)
|
|
uintptr_t rcc_ddritfcr = stm32_rcc_base() + RCC_DDRITFCR;
|
|
uintptr_t ddrctrl_base = get_ddrctrl_base();
|
|
|
|
+ if (!ddr_supports_ssr_asr())
|
|
+ return;
|
|
+
|
|
mmio_setbits_32(rcc_ddritfcr, RCC_DDRITFCR_DDRC1LPEN);
|
|
|
|
mmio_setbits_32(rcc_ddritfcr, RCC_DDRITFCR_DDRC2LPEN);
|
|
@@ -446,6 +463,9 @@ void ddr_sr_mode_asr(void)
|
|
uintptr_t rcc_ddritfcr = stm32_rcc_base() + RCC_DDRITFCR;
|
|
uintptr_t ddrctrl_base = get_ddrctrl_base();
|
|
|
|
+ if (!ddr_supports_ssr_asr())
|
|
+ return;
|
|
+
|
|
mmio_setbits_32(rcc_ddritfcr, RCC_DDRITFCR_AXIDCGEN);
|
|
|
|
mmio_setbits_32(rcc_ddritfcr, RCC_DDRITFCR_DDRC1LPEN);
|
|
diff --git a/core/arch/arm/plat-stm32mp1/drivers/stm32mp1_ddrc.h b/core/arch/arm/plat-stm32mp1/drivers/stm32mp1_ddrc.h
|
|
index 59014b4..4afa313 100644
|
|
--- a/core/arch/arm/plat-stm32mp1/drivers/stm32mp1_ddrc.h
|
|
+++ b/core/arch/arm/plat-stm32mp1/drivers/stm32mp1_ddrc.h
|
|
@@ -162,6 +162,7 @@
|
|
#define DDRPHYC_PTR0_TITMSRST_OFFSET 18
|
|
#define DDRPHYC_PTR0_TITMSRST_MASK GENMASK_32(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_32(10, 8)
|
|
diff --git a/core/arch/arm/plat-stm32mp1/drivers/stm32mp1_pmic.c b/core/arch/arm/plat-stm32mp1/drivers/stm32mp1_pmic.c
|
|
index f2b7fe1..82225bd 100644
|
|
--- a/core/arch/arm/plat-stm32mp1/drivers/stm32mp1_pmic.c
|
|
+++ b/core/arch/arm/plat-stm32mp1/drivers/stm32mp1_pmic.c
|
|
@@ -1,6 +1,6 @@
|
|
// SPDX-License-Identifier: BSD-3-Clause
|
|
/*
|
|
- * Copyright (c) 2017-2018, STMicroelectronics - All Rights Reserved
|
|
+ * Copyright (c) 2017-2019, STMicroelectronics - All Rights Reserved
|
|
*/
|
|
|
|
#include <kernel/delay.h>
|
|
@@ -23,15 +23,6 @@
|
|
#include <trace.h>
|
|
#include <util.h>
|
|
|
|
-#define STPMIC1_LDO12356_OUTPUT_MASK (uint8_t)(GENMASK_32(6, 2))
|
|
-#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)
|
|
-
|
|
#define MODE_STANDBY 8U
|
|
|
|
#define STPMIC1_DEFAULT_START_UP_DELAY_MS 1
|
|
@@ -46,10 +37,28 @@ bool stm32mp_with_pmic(void)
|
|
|
|
static int dt_get_pmic_node(void *fdt)
|
|
{
|
|
- return fdt_node_offset_by_compatible(fdt, -1, "st,stpmic1");
|
|
+ static int node = -FDT_ERR_BADOFFSET;
|
|
+
|
|
+ if (node == -FDT_ERR_BADOFFSET) {
|
|
+ node = fdt_get_node_by_compatible(fdt, "st,stpmic1");
|
|
+ }
|
|
+
|
|
+ return node;
|
|
+}
|
|
+
|
|
+static int dt_get_regulators_node(void *fdt)
|
|
+{
|
|
+ int node;
|
|
+
|
|
+ node = dt_get_pmic_node(fdt);
|
|
+ if (node < 0) {
|
|
+ panic();
|
|
+ }
|
|
+
|
|
+ return fdt_subnode_offset(fdt, node, "regulators");
|
|
}
|
|
|
|
-static int dt_pmic_status(void)
|
|
+int stm32mp_dt_pmic_status(void)
|
|
{
|
|
void *fdt = get_dt_blob();
|
|
|
|
@@ -66,7 +75,7 @@ static int dt_pmic_status(void)
|
|
|
|
static bool dt_pmic_is_secure(void)
|
|
{
|
|
- int status = dt_pmic_status();
|
|
+ int status = stm32mp_dt_pmic_status();
|
|
|
|
return ((unsigned)status == DT_STATUS_OK_SEC) &&
|
|
(i2c_handle.dt_status == DT_STATUS_OK_SEC);
|
|
@@ -92,7 +101,7 @@ static size_t regu_bo_count;
|
|
|
|
static int save_boot_on_config(void)
|
|
{
|
|
- int pmic_node, regulators_node, regulator_node;
|
|
+ int regulators_node, subnode;
|
|
void *fdt;
|
|
|
|
assert(!regu_bo_config && !regu_bo_count);
|
|
@@ -102,42 +111,40 @@ static int save_boot_on_config(void)
|
|
panic();
|
|
}
|
|
|
|
- pmic_node = dt_get_pmic_node(fdt);
|
|
- if (pmic_node < 0) {
|
|
- panic();
|
|
- }
|
|
-
|
|
- regulators_node = fdt_subnode_offset(fdt, pmic_node, "regulators");
|
|
+ regulators_node = dt_get_regulators_node(fdt);
|
|
|
|
- fdt_for_each_subnode(regulator_node, fdt, regulators_node) {
|
|
+ fdt_for_each_subnode(subnode, fdt, regulators_node) {
|
|
const fdt32_t *cuint;
|
|
const char *name;
|
|
struct regu_bo_config regu_cfg;
|
|
uint16_t mv;
|
|
|
|
- if (fdt_getprop(fdt, regulator_node, "regulator-boot-on",
|
|
- NULL) == NULL) {
|
|
+ if ((fdt_getprop(fdt, subnode, "regulator-boot-on", NULL) ==
|
|
+ NULL) &&
|
|
+ (fdt_getprop(fdt, subnode, "regulator-always-on", NULL) ==
|
|
+ NULL)) {
|
|
continue;
|
|
}
|
|
|
|
memset(®u_cfg, 0, sizeof(regu_cfg));
|
|
- name = fdt_get_name(fdt, regulator_node, NULL);
|
|
+ name = fdt_get_name(fdt, subnode, NULL);
|
|
|
|
regu_cfg.flags |= REGU_BO_FLAG_ENABLE_REGU;
|
|
+ stpmic1_bo_enable_cfg(name, ®u_cfg.cfg);
|
|
|
|
- if (fdt_getprop(fdt, regulator_node, "regulator-pull-down",
|
|
+ if (fdt_getprop(fdt, subnode, "regulator-pull-down",
|
|
NULL) != NULL) {
|
|
stpmic1_bo_pull_down_cfg(name, ®u_cfg.cfg);
|
|
regu_cfg.flags |= REGU_BO_FLAG_PULL_DOWN;
|
|
}
|
|
|
|
- if (fdt_getprop(fdt, regulator_node, "st,mask-reset",
|
|
+ if (fdt_getprop(fdt, subnode, "st,mask-reset",
|
|
NULL) != NULL) {
|
|
stpmic1_bo_mask_reset_cfg(name, ®u_cfg.cfg);
|
|
regu_cfg.flags |= REGU_BO_FLAG_MASK_RESET;
|
|
}
|
|
|
|
- cuint = fdt_getprop(fdt, regulator_node,
|
|
+ cuint = fdt_getprop(fdt, subnode,
|
|
"regulator-min-microvolt", NULL);
|
|
if (cuint != NULL) {
|
|
/* DT uses microvolts, whereas driver awaits millivolts */
|
|
@@ -246,7 +253,7 @@ static unsigned int regu_lp_state2idx(const char *name)
|
|
|
|
static int save_low_power_config(const char *lp_state)
|
|
{
|
|
- int pmic_node, regulators_node, regulator_node;
|
|
+ int regulators_node, subnode;
|
|
void *fdt;
|
|
unsigned int state_idx = regu_lp_state2idx(lp_state);
|
|
struct regu_lp_state *state = ®u_lp_state[state_idx];
|
|
@@ -258,14 +265,9 @@ static int save_low_power_config(const char *lp_state)
|
|
panic();
|
|
}
|
|
|
|
- pmic_node = dt_get_pmic_node(fdt);
|
|
- if (pmic_node < 0) {
|
|
- return -FDT_ERR_NOTFOUND;
|
|
- }
|
|
-
|
|
- regulators_node = fdt_subnode_offset(fdt, pmic_node, "regulators");
|
|
+ regulators_node = dt_get_regulators_node(fdt);
|
|
|
|
- fdt_for_each_subnode(regulator_node, fdt, regulators_node) {
|
|
+ fdt_for_each_subnode(subnode, fdt, regulators_node) {
|
|
const fdt32_t *cuint;
|
|
const char *reg_name;
|
|
int regulator_state_node;
|
|
@@ -282,7 +284,7 @@ static int save_low_power_config(const char *lp_state)
|
|
|
|
memset(regu_cfg, 0, sizeof(*regu_cfg));
|
|
|
|
- reg_name = fdt_get_name(fdt, regulator_node, NULL);
|
|
+ reg_name = fdt_get_name(fdt, subnode, NULL);
|
|
|
|
if (stpmic1_lp_cfg(reg_name, ®u_cfg->cfg) != 0) {
|
|
EMSG("Invalid regu name %s", reg_name);
|
|
@@ -298,7 +300,7 @@ static int save_low_power_config(const char *lp_state)
|
|
|
|
/* Then apply configs from regulator_state_node */
|
|
regulator_state_node = fdt_subnode_offset(fdt,
|
|
- regulator_node,
|
|
+ subnode,
|
|
lp_state);
|
|
if (regulator_state_node <= 0) {
|
|
continue;
|
|
diff --git a/core/arch/arm/plat-stm32mp1/drivers/stm32mp1_pmic.h b/core/arch/arm/plat-stm32mp1/drivers/stm32mp1_pmic.h
|
|
index 01f15fd..4d26e70 100644
|
|
--- a/core/arch/arm/plat-stm32mp1/drivers/stm32mp1_pmic.h
|
|
+++ b/core/arch/arm/plat-stm32mp1/drivers/stm32mp1_pmic.h
|
|
@@ -1,6 +1,6 @@
|
|
/* SPDX-License-Identifier: BSD-3-Clause */
|
|
/*
|
|
- * Copyright (c) 2017-2018, STMicroelectronics - All Rights Reserved
|
|
+ * Copyright (c) 2017-2019, STMicroelectronics - All Rights Reserved
|
|
*/
|
|
|
|
#ifndef __STM32MP1_PMIC_H__
|
|
@@ -13,6 +13,7 @@ void stm32mp_pmic_apply_boot_on_config(void);
|
|
void stm32mp_pmic_apply_lp_config(const char *lp_state);
|
|
void stm32mp_get_pmic(void);
|
|
void stm32mp_put_pmic(void);
|
|
+int stm32mp_dt_pmic_status(void);
|
|
#else
|
|
static inline void stm32mp_pmic_apply_boot_on_config(void)
|
|
{
|
|
@@ -28,6 +29,10 @@ static inline void stm32mp_put_pmic(void)
|
|
{
|
|
panic();
|
|
}
|
|
+static inline int stm32mp_dt_pmic_status(void)
|
|
+{
|
|
+ return -1;
|
|
+}
|
|
#endif
|
|
|
|
#endif /*__STM32MP1_PMIC_H__*/
|
|
diff --git a/core/arch/arm/plat-stm32mp1/drivers/stm32mp1_syscfg.c b/core/arch/arm/plat-stm32mp1/drivers/stm32mp1_syscfg.c
|
|
new file mode 100644
|
|
index 0000000..ccc5352
|
|
--- /dev/null
|
|
+++ b/core/arch/arm/plat-stm32mp1/drivers/stm32mp1_syscfg.c
|
|
@@ -0,0 +1,97 @@
|
|
+// SPDX-License-Identifier: BSD-3-Clause
|
|
+/*
|
|
+ * Copyright (c) 2019, STMicroelectronics - All Rights Reserved
|
|
+ */
|
|
+
|
|
+#include <dt-bindings/clock/stm32mp1-clks.h>
|
|
+#include <kernel/delay.h>
|
|
+#include <stm32_util.h>
|
|
+#include <trace.h>
|
|
+#include <types_ext.h>
|
|
+
|
|
+/*
|
|
+ * SYSCFG register offsets (base relative)
|
|
+ */
|
|
+#define SYSCFG_CMPCR 0x20U
|
|
+#define SYSCFG_CMPENSETR 0x24U
|
|
+
|
|
+/*
|
|
+ * SYSCFG_CMPCR Register
|
|
+ */
|
|
+#define SYSCFG_CMPCR_SW_CTRL BIT(1)
|
|
+#define SYSCFG_CMPCR_READY BIT(8)
|
|
+#define SYSCFG_CMPCR_RANSRC GENMASK_32(19, 16)
|
|
+#define SYSCFG_CMPCR_RANSRC_SHIFT 16
|
|
+#define SYSCFG_CMPCR_RAPSRC GENMASK_32(23, 20)
|
|
+#define SYSCFG_CMPCR_ANSRC_SHIFT 24
|
|
+
|
|
+#define SYSCFG_CMPCR_READY_TIMEOUT_US 1000U
|
|
+
|
|
+/*
|
|
+ * SYSCFG_CMPENSETR Register
|
|
+ */
|
|
+#define SYSCFG_CMPENSETR_MPU_EN BIT(0)
|
|
+
|
|
+void stm32mp1_syscfg_enable_io_compensation(void)
|
|
+{
|
|
+ uintptr_t syscfg_base = stm32_get_syscfg_base();
|
|
+ uint64_t start;
|
|
+
|
|
+ /*
|
|
+ * 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);
|
|
+
|
|
+ start = utimeout_init(SYSCFG_CMPCR_READY_TIMEOUT_US);
|
|
+
|
|
+ while ((mmio_read_32(syscfg_base + SYSCFG_CMPCR) &
|
|
+ SYSCFG_CMPCR_READY) == 0U) {
|
|
+ if (utimeout_elapsed(SYSCFG_CMPCR_READY_TIMEOUT_US, start)) {
|
|
+ EMSG("IO compensation cell not ready");
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ mmio_clrbits_32(syscfg_base + SYSCFG_CMPCR, SYSCFG_CMPCR_SW_CTRL);
|
|
+
|
|
+ DMSG("[0x%"PRIxPTR"] SYSCFG.cmpcr = 0x%"PRIx32,
|
|
+ syscfg_base + SYSCFG_CMPCR,
|
|
+ mmio_read_32(syscfg_base + SYSCFG_CMPCR));
|
|
+}
|
|
+
|
|
+void stm32mp1_syscfg_disable_io_compensation(void)
|
|
+{
|
|
+ uintptr_t syscfg_base = stm32_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 | SYSCFG_CMPCR_SW_CTRL);
|
|
+
|
|
+ DMSG("[0x%"PRIxPTR"] SYSCFG.cmpcr = 0x%"PRIx32,
|
|
+ syscfg_base + SYSCFG_CMPCR,
|
|
+ mmio_read_32(syscfg_base + SYSCFG_CMPCR));
|
|
+
|
|
+ mmio_clrbits_32(syscfg_base + SYSCFG_CMPENSETR,
|
|
+ SYSCFG_CMPENSETR_MPU_EN);
|
|
+
|
|
+ stm32mp1_clk_disable_non_secure(SYSCFG);
|
|
+}
|
|
diff --git a/core/arch/arm/plat-stm32mp1/drivers/sub.mk b/core/arch/arm/plat-stm32mp1/drivers/sub.mk
|
|
index c668efa..0c5f3bc 100644
|
|
--- a/core/arch/arm/plat-stm32mp1/drivers/sub.mk
|
|
+++ b/core/arch/arm/plat-stm32mp1/drivers/sub.mk
|
|
@@ -6,3 +6,4 @@ srcs-$(CFG_STPMIC1) += stm32mp1_pmic.c
|
|
srcs-y += stm32mp1_clk.c
|
|
srcs-$(CFG_DT) += stm32mp1_clkfunc.c
|
|
srcs-y += stm32mp1_ddrc.c
|
|
+srcs-y += stm32mp1_syscfg.c
|
|
diff --git a/core/arch/arm/plat-stm32mp1/main.c b/core/arch/arm/plat-stm32mp1/main.c
|
|
index b501541..08deeea 100644
|
|
--- a/core/arch/arm/plat-stm32mp1/main.c
|
|
+++ b/core/arch/arm/plat-stm32mp1/main.c
|
|
@@ -1,6 +1,6 @@
|
|
// SPDX-License-Identifier: BSD-2-Clause
|
|
/*
|
|
- * Copyright (c) 2017-2018, STMicroelectronics
|
|
+ * Copyright (c) 2017-2019, STMicroelectronics
|
|
* Copyright (c) 2016-2018, Linaro Limited
|
|
*/
|
|
|
|
@@ -13,7 +13,9 @@
|
|
#include <drivers/stm32_iwdg.h>
|
|
#include <drivers/stm32_uart.h>
|
|
#include <drivers/stm32mp1_clk.h>
|
|
+#include <drivers/stm32mp1_pmic.h>
|
|
#include <drivers/stm32mp1_rcc.h>
|
|
+#include <drivers/stpmic1.h>
|
|
#include <dt-bindings/etzpc/stm32-etzpc.h>
|
|
#include <dt-bindings/clock/stm32mp1-clks.h>
|
|
#include <io.h>
|
|
@@ -47,6 +49,7 @@ register_phys_mem(MEM_AREA_IO_NSEC, RNG1_BASE, SMALL_PAGE_SIZE);
|
|
register_phys_mem(MEM_AREA_IO_NSEC, IWDG1_BASE, SMALL_PAGE_SIZE);
|
|
register_phys_mem(MEM_AREA_IO_NSEC, IWDG2_BASE, SMALL_PAGE_SIZE);
|
|
register_phys_mem(MEM_AREA_IO_NSEC, RTC_BASE, SMALL_PAGE_SIZE);
|
|
+register_phys_mem(MEM_AREA_IO_NSEC, SYSCFG_BASE, SMALL_PAGE_SIZE);
|
|
#ifdef CFG_WITH_NSEC_UARTS
|
|
register_phys_mem(MEM_AREA_IO_NSEC, USART1_BASE, SMALL_PAGE_SIZE);
|
|
register_phys_mem(MEM_AREA_IO_NSEC, USART2_BASE, SMALL_PAGE_SIZE);
|
|
@@ -237,6 +240,38 @@ static TEE_Result stm32_uart_console_probe(void)
|
|
return TEE_SUCCESS;
|
|
}
|
|
service_init_late(stm32_uart_console_probe);
|
|
+
|
|
+/* Compute PLL1 settings once PMIC init is completed */
|
|
+static TEE_Result initialize_pll1_settings(void)
|
|
+{
|
|
+ uint32_t vddcore_voltage = 0U;
|
|
+ int ret;
|
|
+
|
|
+ if (stm32mp1_clk_pll1_settings_are_valid()) {
|
|
+ return TEE_SUCCESS;
|
|
+ }
|
|
+
|
|
+ if (stm32mp_dt_pmic_status() > 0) {
|
|
+ stm32mp_get_pmic();
|
|
+
|
|
+ ret = stpmic1_regulator_voltage_get("buck1");
|
|
+ if (ret < 0) {
|
|
+ panic();
|
|
+ }
|
|
+
|
|
+ vddcore_voltage = (uint32_t)ret;
|
|
+
|
|
+ stm32mp_put_pmic();
|
|
+ }
|
|
+
|
|
+ if (stm32mp1_clk_compute_all_pll1_settings(vddcore_voltage) != 0) {
|
|
+ panic();
|
|
+ }
|
|
+
|
|
+ return TEE_SUCCESS;
|
|
+}
|
|
+driver_init_late(initialize_pll1_settings);
|
|
+
|
|
#endif
|
|
|
|
/*
|
|
@@ -360,15 +395,39 @@ bool sm_platform_handler(struct sm_ctx *ctx)
|
|
}
|
|
}
|
|
|
|
+static uintptr_t stm32_dbgmcu_base(void)
|
|
+{
|
|
+ static void *va;
|
|
+
|
|
+ if (!cpu_mmu_enabled())
|
|
+ return DBGMCU_BASE;
|
|
+
|
|
+ if (!va)
|
|
+ va = phys_to_virt(DBGMCU_BASE, MEM_AREA_IO_SEC);
|
|
+
|
|
+ return (uintptr_t)va;
|
|
+}
|
|
+
|
|
/* SoC versioning util */
|
|
-uint32_t stm32mp1_dbgmcu_get_chip_version(void)
|
|
+int stm32mp1_dbgmcu_get_chip_version(uint32_t *chip_version)
|
|
{
|
|
- uintptr_t base = DBGMCU_BASE;
|
|
+ assert(chip_version != NULL);
|
|
|
|
- if (cpu_mmu_enabled())
|
|
- base = (uintptr_t)phys_to_virt(DBGMCU_BASE, MEM_AREA_IO_SEC);
|
|
+ *chip_version = (read32(stm32_dbgmcu_base() + DBGMCU_IDC) &
|
|
+ DBGMCU_IDC_REV_ID_MASK) >> DBGMCU_IDC_REV_ID_SHIFT;
|
|
|
|
- return read32(base + DBGMCU_IDC) >> 16;
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/* SoC device ID util */
|
|
+int stm32mp1_dbgmcu_get_chip_dev_id(uint32_t *chip_dev_id)
|
|
+{
|
|
+ assert(chip_dev_id != NULL);
|
|
+
|
|
+ *chip_dev_id = read32(stm32_dbgmcu_base() + DBGMCU_IDC) &
|
|
+ DBGMCU_IDC_DEV_ID_MASK;
|
|
+
|
|
+ return 0;
|
|
}
|
|
|
|
static uintptr_t stm32_tamp_base(void)
|
|
@@ -420,6 +479,19 @@ uintptr_t stm32_get_stgen_base(void)
|
|
return va;
|
|
}
|
|
|
|
+uintptr_t stm32_get_syscfg_base(void)
|
|
+{
|
|
+ static uintptr_t va;
|
|
+
|
|
+ if (!cpu_mmu_enabled())
|
|
+ return SYSCFG_BASE;
|
|
+
|
|
+ if (!va)
|
|
+ va = (uintptr_t)phys_to_virt(SYSCFG_BASE, MEM_AREA_IO_NSEC);
|
|
+
|
|
+ return va;
|
|
+}
|
|
+
|
|
uintptr_t stm32_get_gpio_bank_base(unsigned int bank)
|
|
{
|
|
/* Non secure banks and mapped together, same for secure banks */
|
|
@@ -522,25 +594,93 @@ unsigned long stm32_get_iwdg_otp_config(uintptr_t pbase)
|
|
{
|
|
unsigned int idx;
|
|
unsigned long iwdg_cfg = 0;
|
|
+ uint32_t otp;
|
|
uint32_t otp_value;
|
|
|
|
idx = stm32mp_iwdg_iomem2instance(pbase);
|
|
|
|
- if (bsec_read_otp(&otp_value, HW2_OTP))
|
|
+ if (bsec_find_otp_name_in_nvmem_layout(HW2_OTP, &otp, NULL))
|
|
+ panic();
|
|
+
|
|
+ if (bsec_read_otp(&otp_value, otp))
|
|
panic();
|
|
|
|
if (otp_value & BIT(idx + HW2_OTP_IWDG_HW_ENABLE_SHIFT))
|
|
iwdg_cfg |= IWDG_HW_ENABLED;
|
|
|
|
- if (!(otp_value & BIT(idx + HW2_OTP_IWDG_FZ_STOP_SHIFT)))
|
|
- iwdg_cfg |= IWDG_ENABLE_ON_STOP;
|
|
+ if (otp_value & BIT(idx + HW2_OTP_IWDG_FZ_STOP_SHIFT))
|
|
+ iwdg_cfg |= IWDG_DISABLE_ON_STOP;
|
|
|
|
- if (!(otp_value & BIT(idx + HW2_OTP_IWDG_FZ_STANDBY_SHIFT)))
|
|
- iwdg_cfg |= IWDG_ENABLE_ON_STANDBY;
|
|
+ if (otp_value & BIT(idx + HW2_OTP_IWDG_FZ_STANDBY_SHIFT))
|
|
+ iwdg_cfg |= IWDG_DISABLE_ON_STANDBY;
|
|
|
|
return iwdg_cfg;
|
|
}
|
|
|
|
+static int get_part_number(uint32_t *part_nb)
|
|
+{
|
|
+ uint32_t part_number;
|
|
+ uint32_t dev_id;
|
|
+ uint32_t otp;
|
|
+ size_t bit_len;
|
|
+
|
|
+ assert(part_nb != NULL);
|
|
+
|
|
+ if (stm32mp1_dbgmcu_get_chip_dev_id(&dev_id) != 0) {
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ if (bsec_find_otp_name_in_nvmem_layout(PART_NUMBER_OTP, &otp,
|
|
+ &bit_len) != BSEC_OK) {
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ assert(bit_len == 8);
|
|
+
|
|
+ if (bsec_read_otp(&part_number, otp) != BSEC_OK) {
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ part_number = (part_number & PART_NUMBER_OTP_PART_MASK) >>
|
|
+ PART_NUMBER_OTP_PART_SHIFT;
|
|
+
|
|
+ *part_nb = part_number | (dev_id << 16);
|
|
+
|
|
+ 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) {
|
|
+ DMSG("Cannot get part number");
|
|
+ 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;
|
|
+ }
|
|
+}
|
|
+
|
|
uintptr_t stm32mp_get_etzpc_base(void)
|
|
{
|
|
return ETZPC_BASE;
|
|
diff --git a/core/arch/arm/plat-stm32mp1/platform_config.h b/core/arch/arm/plat-stm32mp1/platform_config.h
|
|
index e8d1660..d635efd 100644
|
|
--- a/core/arch/arm/plat-stm32mp1/platform_config.h
|
|
+++ b/core/arch/arm/plat-stm32mp1/platform_config.h
|
|
@@ -1,6 +1,6 @@
|
|
/* SPDX-License-Identifier: BSD-2-Clause */
|
|
/*
|
|
- * Copyright (c) 2017-2018, STMicroelectronics
|
|
+ * Copyright (c) 2017-2019, STMicroelectronics
|
|
*/
|
|
|
|
#ifndef PLATFORM_CONFIG_H
|
|
@@ -78,6 +78,7 @@
|
|
#define RTC_BASE 0x5c004000
|
|
#define SPI6_BASE 0x5c001000
|
|
#define STGEN_BASE 0x5C008000
|
|
+#define SYSCFG_BASE 0x50020000
|
|
#define TAMP_BASE 0x5c00a000
|
|
#define USART1_BASE 0x5c000000
|
|
#define USART2_BASE 0x4000e000
|
|
@@ -95,20 +96,15 @@
|
|
|
|
#define OTP_MAX_SIZE (STM32MP1_OTP_MAX_ID + 1U)
|
|
|
|
-#define DATA0_OTP 0
|
|
-#define PART_NUMBER_OTP 1
|
|
-#define MONOTONIC_OTP 4
|
|
-#define NAND_OTP 9
|
|
-#define UID0_OTP 13
|
|
-#define UID1_OTP 14
|
|
-#define UID2_OTP 15
|
|
-#define HW2_OTP 18
|
|
+#define HW2_OTP "hw2_otp"
|
|
+#define PART_NUMBER_OTP "part_number_otp"
|
|
|
|
-#define DATA0_OTP_SECURED BIT(6)
|
|
+#define HW2_OTP_IWDG_HW_ENABLE_SHIFT 3
|
|
+#define HW2_OTP_IWDG_FZ_STOP_SHIFT 5
|
|
+#define HW2_OTP_IWDG_FZ_STANDBY_SHIFT 7
|
|
|
|
-#define HW2_OTP_IWDG_HW_ENABLE_SHIFT 3
|
|
-#define HW2_OTP_IWDG_FZ_STOP_SHIFT 5
|
|
-#define HW2_OTP_IWDG_FZ_STANDBY_SHIFT 7
|
|
+#define PART_NUMBER_OTP_PART_MASK GENMASK_32(7, 0)
|
|
+#define PART_NUMBER_OTP_PART_SHIFT 0
|
|
|
|
/*
|
|
* GPIO banks: 11 non secure banks (A to K) and 1 secure bank (Z)
|
|
@@ -150,12 +146,35 @@
|
|
/* RCC platform resources */
|
|
#define RCC_WAKEUP_IT 177
|
|
|
|
-/* SoC revision */
|
|
+/* SoC part numbers and revisions */
|
|
+#define STM32MP157C_PART_NB 0x05000000
|
|
+#define STM32MP157A_PART_NB 0x05000001
|
|
+#define STM32MP153C_PART_NB 0x05000024
|
|
+#define STM32MP153A_PART_NB 0x05000025
|
|
+#define STM32MP151C_PART_NB 0x0500002E
|
|
+#define STM32MP151A_PART_NB 0x0500002F
|
|
+#define STM32MP157F_PART_NB 0x05000080
|
|
+#define STM32MP157D_PART_NB 0x05000081
|
|
+#define STM32MP153F_PART_NB 0x050000A4
|
|
+#define STM32MP153D_PART_NB 0x050000A5
|
|
+#define STM32MP151F_PART_NB 0x050000AE
|
|
+#define STM32MP151D_PART_NB 0x050000AF
|
|
+
|
|
#define STM32MP1_REV_A 0x00001000
|
|
#define STM32MP1_REV_B 0x00002000
|
|
+#define STM32MP1_REV_Z 0x00002001
|
|
+
|
|
+/* OPP */
|
|
+#define PLAT_OPP_ID1 1U
|
|
+#define PLAT_OPP_ID2 2U
|
|
+#define PLAT_MAX_OPP_NB 2U
|
|
+#define PLAT_MAX_PLLCFG_NB 6U
|
|
|
|
/* DBGMCU resources */
|
|
#define DBGMCU_IDC 0x0
|
|
+#define DBGMCU_IDC_DEV_ID_MASK GENMASK_32(11, 0)
|
|
+#define DBGMCU_IDC_REV_ID_MASK GENMASK_32(31, 16)
|
|
+#define DBGMCU_IDC_REV_ID_SHIFT 16
|
|
|
|
/* BKPSRAM layout */
|
|
#define BKPSRAM_SIZE SMALL_PAGE_SIZE
|
|
@@ -167,7 +186,7 @@
|
|
#define BKPSRAM_PM_MAILBOX_SIZE 0x100
|
|
#define BKPSRAM_PM_CONTEXT_OFFSET (BKPSRAM_PM_MAILBOX_OFFSET + \
|
|
BKPSRAM_PM_MAILBOX_SIZE)
|
|
-#define BKPSRAM_PM_CONTEXT_SIZE 0x700
|
|
+#define BKPSRAM_PM_CONTEXT_SIZE 0xF00
|
|
|
|
/* SYSRAM */
|
|
#define SYSRAM_SIZE 0x40000
|
|
diff --git a/core/arch/arm/plat-stm32mp1/pm/context.c b/core/arch/arm/plat-stm32mp1/pm/context.c
|
|
index 20e9e84..fcdad91 100644
|
|
--- a/core/arch/arm/plat-stm32mp1/pm/context.c
|
|
+++ b/core/arch/arm/plat-stm32mp1/pm/context.c
|
|
@@ -1,6 +1,6 @@
|
|
// SPDX-License-Identifier: BSD-3-Clause
|
|
/*
|
|
- * Copyright (c) 2018, STMicroelectronics - All Rights Reserved
|
|
+ * Copyright (c) 2018-2019, STMicroelectronics - All Rights Reserved
|
|
* Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
|
|
*/
|
|
|
|
@@ -32,7 +32,28 @@
|
|
|
|
#define TRAINING_AREA_SIZE 64
|
|
|
|
-#define STANDBY_CONTEXT_MAGIC (0x00010000 + TRAINING_AREA_SIZE)
|
|
+/*
|
|
+ * STANDBY_CONTEXT_MAGIC0:
|
|
+ * Context provides magic, resume entry, zq0cr0 zdata and DDR training buffer.
|
|
+ *
|
|
+ * STANDBY_CONTEXT_MAGIC1:
|
|
+ * Context provides magic, resume entry, zq0cr0 zdata, DDR training buffer
|
|
+ * and PLL1 dual OPP settings structure (86 bytes).
|
|
+ */
|
|
+#define STANDBY_CONTEXT_MAGIC0 (0x0001 << 16)
|
|
+#define STANDBY_CONTEXT_MAGIC1 (0x0002 << 16)
|
|
+
|
|
+#define STANDBY_CONTEXT_MAGIC (STANDBY_CONTEXT_MAGIC1 | \
|
|
+ TRAINING_AREA_SIZE)
|
|
+
|
|
+#if (PLAT_MAX_OPP_NB != 2) || (PLAT_MAX_PLLCFG_NB != 6)
|
|
+#error STANDBY_CONTEXT_MAGIC1 does not support expected PLL1 settings
|
|
+#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))
|
|
|
|
/*
|
|
* Context saved in TEE RAM during lower power sequence.
|
|
@@ -58,11 +79,12 @@ static struct pm_context plat_ctx;
|
|
* @zq0cr0_zdata: DDRPHY configuration to be restored.
|
|
* @ddr_training_backup: DDR area saved at suspend and backed up at resume
|
|
*/
|
|
-struct pm_mailbox {
|
|
+struct __attribute__((__packed__)) pm_mailbox {
|
|
uint32_t magic;
|
|
uint32_t core0_resume_ep;
|
|
uint32_t zq0cr0_zdata;
|
|
uint8_t ddr_training_backup[TRAINING_AREA_SIZE];
|
|
+ uint8_t pll1_settings[PLL1_SETTINGS_SIZE];
|
|
};
|
|
|
|
/*
|
|
@@ -323,6 +345,21 @@ static void save_ddr_training_area(void)
|
|
mobj_free(mobj);
|
|
}
|
|
|
|
+/*
|
|
+ * When returning from STANDBY, warm boot boot stage needs to access to PLL1
|
|
+ * settings. This avoids to re-compute them and optimizes performances. This
|
|
+ * structure must then be saved before going to STANDBY in the PM mailbox
|
|
+ * shared with the warm boot boot stage.
|
|
+ */
|
|
+static void save_pll1_settings(void)
|
|
+{
|
|
+ struct pm_mailbox *mailbox = get_pm_mailbox();
|
|
+ size_t size = sizeof(mailbox->pll1_settings);
|
|
+ uint8_t *data = &mailbox->pll1_settings[0];
|
|
+
|
|
+ stm32mp1_clk_lp_save_opp_pll1_settings(data, size);
|
|
+}
|
|
+
|
|
static void load_earlyboot_pm_mailbox(void)
|
|
{
|
|
struct pm_mailbox *mailbox = get_pm_mailbox();
|
|
@@ -337,6 +374,8 @@ static void load_earlyboot_pm_mailbox(void)
|
|
mailbox->zq0cr0_zdata = get_ddrphy_calibration();
|
|
|
|
save_ddr_training_area();
|
|
+
|
|
+ save_pll1_settings();
|
|
}
|
|
|
|
#ifdef CFG_STM32_RNG
|
|
diff --git a/core/arch/arm/plat-stm32mp1/pm/low_power.c b/core/arch/arm/plat-stm32mp1/pm/low_power.c
|
|
index 48bddb7..450b68a 100644
|
|
--- a/core/arch/arm/plat-stm32mp1/pm/low_power.c
|
|
+++ b/core/arch/arm/plat-stm32mp1/pm/low_power.c
|
|
@@ -170,6 +170,10 @@ int stm32_enter_cstop(uint32_t mode)
|
|
uintptr_t rcc_base = stm32_rcc_base();
|
|
int rc;
|
|
|
|
+ stm32mp1_syscfg_disable_io_compensation();
|
|
+
|
|
+ ddr_sr_mode_ssr();
|
|
+
|
|
stm32_apply_pmic_suspend_config(mode);
|
|
|
|
if (stm32mp_with_pmic() && (mode == STM32_PM_CSTOP_ALLOW_LP_STOP)) {
|
|
@@ -233,6 +237,8 @@ void stm32_exit_cstop(void)
|
|
ddr_in_selfrefresh = false;
|
|
}
|
|
|
|
+ ddr_sr_mode_asr();
|
|
+
|
|
restore_rcc_it_priority(gicd_rcc_wakeup, gicc_pmr);
|
|
|
|
/* Disable STOP request */
|
|
@@ -247,6 +253,8 @@ void stm32_exit_cstop(void)
|
|
|
|
/* Disable retention and backup RAM content after stop */
|
|
mmio_clrbits_32(pwr_base + PWR_CR2_OFF, PWR_CR2_BREN | PWR_CR2_RREN);
|
|
+
|
|
+ stm32mp1_syscfg_enable_io_compensation();
|
|
}
|
|
|
|
/*
|
|
@@ -412,7 +420,7 @@ void __noreturn stm32_cores_reset(void)
|
|
}
|
|
KEEP_PAGER(stm32_cores_reset);
|
|
|
|
-static void reset_other_core(void)
|
|
+static void __maybe_unused reset_other_core(void)
|
|
{
|
|
uintptr_t rcc_base = stm32_rcc_base();
|
|
uint32_t reset_mask;
|
|
diff --git a/core/arch/arm/plat-stm32mp1/pm/pm_helpers.S b/core/arch/arm/plat-stm32mp1/pm/pm_helpers.S
|
|
index d9ed746..cd8e48c 100644
|
|
--- a/core/arch/arm/plat-stm32mp1/pm/pm_helpers.S
|
|
+++ b/core/arch/arm/plat-stm32mp1/pm/pm_helpers.S
|
|
@@ -64,6 +64,36 @@
|
|
#define CRYP_SR_IFNF BIT(1)
|
|
#define CRYP_SR_IFEM BIT(0)
|
|
|
|
+/*
|
|
+ * Enable TRACE_SYSRAM_RESTORE to get some UART console traces
|
|
+ * at resume time.
|
|
+ */
|
|
+#if defined(TRACE_SYSRAM_RESTORE)
|
|
+
|
|
+#define UART_BASE UART4_BASE
|
|
+#define UART_ISR_OFF 0x1c
|
|
+#define UART_TDR_OFF 0x28
|
|
+#define USART_ISR_TXE_TXFNF (1<< 7)
|
|
+
|
|
+ .macro PRINT_CHAR _reg0, _reg1, _char
|
|
+ /* Trace only at resume when MMU is OFF */
|
|
+ read_sctlr \_reg0
|
|
+ ands \_reg0, #SCTLR_M
|
|
+ 101:
|
|
+ bne 102f
|
|
+ mov_imm \_reg0, UART4_BASE
|
|
+ ldr \_reg1, [\_reg0, #UART_ISR_OFF]
|
|
+ ands \_reg1, #USART_ISR_TXE_TXFNF
|
|
+ beq 101b
|
|
+ mov_imm \_reg1, (\_char)
|
|
+ str \_reg1, [\_reg0, #UART_TDR_OFF]
|
|
+ 102:
|
|
+ .endm
|
|
+#else
|
|
+ .macro PRINT_CHAR _reg0, _reg1, _char
|
|
+ .endm
|
|
+#endif
|
|
+
|
|
/* Bound of the binary image loaded in retained memory */
|
|
.global stm32mp_bkpsram_image_end
|
|
|
|
@@ -80,6 +110,9 @@
|
|
FUNC stm32mp_bkpsram_resume , :
|
|
UNWIND( .fnstart)
|
|
UNWIND( .cantunwind)
|
|
+
|
|
+ PRINT_CHAR r0, r1, '0'
|
|
+
|
|
/*
|
|
* Almost all sequences here expect PM context structure base address
|
|
* from CPU register r11.
|
|
@@ -105,6 +138,11 @@ UNWIND( .cantunwind)
|
|
cmp r0, #0
|
|
bne _failed
|
|
|
|
+ PRINT_CHAR r0, r1, 'T'
|
|
+ PRINT_CHAR r0, r1, 'a'
|
|
+ PRINT_CHAR r0, r1, 'g'
|
|
+ PRINT_CHAR r0, r1, '\n'
|
|
+
|
|
/* Compare the generated and reference tags */
|
|
add r8, r11, #PM_CTX_CCM_TAG
|
|
add r9, r11, #PM_CTX_CCM_REF_TAG
|
|
@@ -123,11 +161,18 @@ UNWIND( .cantunwind)
|
|
bne _failed
|
|
bl _save_resume_time
|
|
|
|
+ PRINT_CHAR r1, r2, 'O'
|
|
+ PRINT_CHAR r1, r2, 'k'
|
|
+ PRINT_CHAR r1, r2, '\n'
|
|
+
|
|
/* Resume into the restored TEE RAM */
|
|
ldr r1, [r11, #PM_CTX_RESUME_PA]
|
|
bx r1
|
|
|
|
_failed:
|
|
+ PRINT_CHAR r0, r12, 'F'
|
|
+ PRINT_CHAR r0, r12, '\n'
|
|
+
|
|
/* Clear context including key and reference tag */
|
|
mov r0, #0xa5
|
|
mov_imm r12, BKPSRAM_PM_CONTEXT_SIZE
|
|
@@ -279,16 +324,23 @@ _ccm_arm_8ms_timeout:
|
|
moveq r0, #1
|
|
ldr r1, [r1, #CNTCVL_OFFSET]
|
|
adds r0, r0, r1
|
|
- bcs _ccm_failed
|
|
+ bcs _ccm_failed_on_timeout
|
|
bx lr
|
|
|
|
_ccm_fail_on_timeout:
|
|
+
|
|
ldr r1, [r11, #PM_CTX_STGEN_BASE]
|
|
ldr r1, [r1, #CNTCVL_OFFSET]
|
|
cmp r1, r0
|
|
- bge _ccm_failed
|
|
+ bge _ccm_failed_on_timeout
|
|
bx lr
|
|
|
|
+_ccm_failed_on_timeout:
|
|
+ PRINT_CHAR r0, r1, 'T'
|
|
+ PRINT_CHAR r0, r1, 'o'
|
|
+ PRINT_CHAR r0, r1, '\n'
|
|
+ b _ccm_failed
|
|
+
|
|
/*
|
|
* Macro WAIT_FLAG_TIMEOUT compares timeout threshold (r0) with
|
|
* current time and branches the CCM failure entry on timeout.
|
|
@@ -346,8 +398,12 @@ stm32mp_ccm_teeram:
|
|
mov r7, r2
|
|
mov r6, r3
|
|
|
|
+ PRINT_CHAR r0, r1, '1'
|
|
+
|
|
bl _setup_cryp1
|
|
|
|
+ PRINT_CHAR r0, r1, '2'
|
|
+
|
|
mov_imm r0, (CRYP_CR_ALGOMODE(ALGOMODE_AES_CCM) | \
|
|
CRYP_CR_DATATYPE_8BIT | CRYP_CR_FFLUSH | \
|
|
CRYP_CR_KEYSIZE_256BIT)
|
|
@@ -355,6 +411,8 @@ stm32mp_ccm_teeram:
|
|
orrne r0, r0, #CRYP_CR_ALGODIR_DECRYPT
|
|
str r0, [r10, #CRYP_CR]
|
|
|
|
+ PRINT_CHAR r0, r1, '3'
|
|
+
|
|
/* Check data alignment (addresses and size) */
|
|
ands r0, r7, #0x0F
|
|
bne _ccm_failed
|
|
@@ -363,6 +421,8 @@ stm32mp_ccm_teeram:
|
|
ands r0, r9, #0x03
|
|
bne _ccm_failed
|
|
|
|
+ PRINT_CHAR r0, r1, '4'
|
|
+
|
|
ldr r0, [r11, #PM_CTX_CCM_KEY]
|
|
str r0, [r10, #CRYP_KEYR_BASE]
|
|
ldr r0, [r11, #(PM_CTX_CCM_KEY + 4)]
|
|
@@ -404,6 +464,8 @@ stm32mp_ccm_teeram:
|
|
ldr r0, [r11, #(PM_CTX_CCM_B0 + 12)]
|
|
str r0, [r10, #CRYP_DIN]
|
|
|
|
+ PRINT_CHAR r0, r1, '5'
|
|
+
|
|
WAIT_FLAG_TIMEOUT CRYP_CR, CRYP_CR_CRYPEN, 0
|
|
|
|
/* Setup CRYP for the CCM Payload phase */
|
|
@@ -414,7 +476,11 @@ stm32mp_ccm_teeram:
|
|
str r0, [r10, #CRYP_CR]
|
|
ldr r0, [r10, #CRYP_CR]
|
|
|
|
+ PRINT_CHAR r0, r1, '\n'
|
|
+
|
|
_next_block:
|
|
+ PRINT_CHAR r0, r1, 'b'
|
|
+
|
|
WAIT_FLAG_TIMEOUT CRYP_SR, CRYP_SR_IFEM, CRYP_SR_IFEM
|
|
|
|
/* Feed input data, r8 stores the current source buffer */
|
|
@@ -451,6 +517,9 @@ _next_block:
|
|
subs r7, r7, #16
|
|
bne _next_block;
|
|
|
|
+ PRINT_CHAR r0, r1, '\n'
|
|
+ PRINT_CHAR r0, r1, '6'
|
|
+
|
|
WAIT_FLAG_TIMEOUT CRYP_SR, CRYP_SR_BUSY, 0
|
|
|
|
/*
|
|
@@ -461,6 +530,8 @@ _next_block:
|
|
cmp r0, #(CRYP_SR_IFEM | CRYP_SR_IFNF)
|
|
bne _ccm_failed
|
|
|
|
+ PRINT_CHAR r0, r1, '7'
|
|
+
|
|
/* Setup CRYP1 for the CCM Final Phase */
|
|
ldr r0, [r10, #CRYP_CR]
|
|
bic r0, r0, #CRYP_CR_CRYPEN
|
|
@@ -483,6 +554,8 @@ _next_block:
|
|
ldr r0, [r11, #(PM_CTX_CCM_CTR0 + 12)]
|
|
str r0, [r10, #CRYP_DIN]
|
|
|
|
+ PRINT_CHAR r0, r1, '8'
|
|
+
|
|
WAIT_FLAG_TIMEOUT CRYP_SR, CRYP_SR_OFNE, CRYP_SR_OFNE
|
|
|
|
/* Store generated tag in the PM_CTX structure */
|
|
@@ -503,12 +576,18 @@ _next_block:
|
|
ands r0, r0, #CRYP_SR_OFNE
|
|
bne _ccm_failed
|
|
|
|
+ PRINT_CHAR r0, r1, '9'
|
|
+
|
|
/* Successful return */
|
|
bl _reset_cryp1
|
|
mov r0, #0
|
|
bx r12
|
|
|
|
_ccm_failed:
|
|
+
|
|
+ PRINT_CHAR r0, r1, 'K'
|
|
+ PRINT_CHAR r0, r1, 'O'
|
|
+
|
|
bl _reset_cryp1
|
|
mov r0, #1
|
|
bx r12
|
|
@@ -577,24 +656,50 @@ FUNC stm32mp_sysram_resume, :
|
|
UNWIND( .fnstart)
|
|
UNWIND( .cantunwind)
|
|
/* Invalidate the data cache */
|
|
- mov r0, #0 @ ; write the cache size selection register to be
|
|
- write_csselr r0 @ ; sure we address the data cache
|
|
- isb @ ; isb to sync the change to the cachesizeid reg
|
|
-
|
|
- mov r0, #0 @ ; set way number to 0
|
|
-_inv_nextway:
|
|
- mov r1, #0 @ ; set line number (=index) to 0
|
|
-_inv_nextline:
|
|
- orr r2, r0, r1 @ ; construct way/index value
|
|
- write_dcisw r2 @ ; inval data or unified cache line by set/way
|
|
- add r1, r1, #1 << LINE_FIELD_OFFSET @ ; increment the index
|
|
- cmp r1, #1 << LINE_FIELD_OVERFLOW @ ; overflow out of set field?
|
|
- bne _inv_nextline
|
|
- add r0, r0, #1 << WAY_FIELD_OFFSET @ ; increment the way number
|
|
- cmp r0, #0 @ ; overflow out of way field?
|
|
- bne _inv_nextway
|
|
|
|
- dsb
|
|
+ read_clidr r2
|
|
+ ubfx r3, r2, #CLIDR_LOC_SHIFT, #CLIDR_FIELD_WIDTH
|
|
+ lsl r3, r3, #CSSELR_LEVEL_SHIFT
|
|
+ mov r1, #0
|
|
+
|
|
+loop1:
|
|
+ add r10, r1, r1, LSR #1 // Work out 3x current cache level
|
|
+ mov r12, r2, LSR r10 // extract cache type bits from clidr
|
|
+ and r12, r12, #7 // mask the bits for current cache only
|
|
+ cmp r12, #2 // see what cache we have at this level
|
|
+ blo level_done // no cache or only instruction cache at this level
|
|
+
|
|
+ write_csselr r1 // select current cache level in csselr
|
|
+ isb // isb to sych the new cssr&csidr
|
|
+ read_ccsidr r12 // read the new ccsidr
|
|
+ and r10, r12, #7 // extract the length of the cache lines
|
|
+ add r10, r10, #4 // add 4 (r10 = line length offset)
|
|
+ ubfx r4, r12, #3, #10 // r4 = maximum way number (right aligned)
|
|
+ clz r5, r4 // r5 = the bit position of the way size increment
|
|
+ mov r9, r4 // r9 working copy of the aligned max way number
|
|
+
|
|
+loop2:
|
|
+ ubfx r7, r12, #13, #15 // r7 = max set number (right aligned)
|
|
+
|
|
+loop3:
|
|
+ orr r0, r1, r9, LSL r5 // factor in the way number and cache level into r0
|
|
+ orr r0, r0, r7, LSL r10 // factor in the set number
|
|
+
|
|
+ write_dcisw r0
|
|
+
|
|
+ subs r7, r7, #1 // decrement the set number
|
|
+ bhs loop3
|
|
+ subs r9, r9, #1 // decrement the way number
|
|
+ bhs loop2
|
|
+level_done:
|
|
+ add r1, r1, #2 // increment the cache number
|
|
+ cmp r3, r1
|
|
+ dsb sy // ensure completion of previous cache maintenance instruction
|
|
+ bhi loop1
|
|
+
|
|
+ mov r6, #0
|
|
+ write_csselr r6 //select cache level 0 in csselr
|
|
+ dsb sy
|
|
isb
|
|
|
|
/* Resume sequence executes in Monitor mode */
|
|
diff --git a/core/arch/arm/plat-stm32mp1/pm/power_config.c b/core/arch/arm/plat-stm32mp1/pm/power_config.c
|
|
index 7845ede..ef26608 100644
|
|
--- a/core/arch/arm/plat-stm32mp1/pm/power_config.c
|
|
+++ b/core/arch/arm/plat-stm32mp1/pm/power_config.c
|
|
@@ -1,6 +1,6 @@
|
|
// SPDX-License-Identifier: BSD-3-Clause
|
|
/*
|
|
- * Copyright (c) 2017-2018, STMicroelectronics - All Rights Reserved
|
|
+ * Copyright (c) 2017-2019, STMicroelectronics - All Rights Reserved
|
|
*/
|
|
|
|
#include <assert.h>
|
|
@@ -57,7 +57,7 @@ bool need_to_backup_cpu_context(unsigned int soc_mode)
|
|
#ifdef CFG_DT
|
|
static int dt_get_pwr_node(void *fdt)
|
|
{
|
|
- return fdt_node_offset_by_compatible(fdt, -1, DT_PWR_COMPAT);
|
|
+ return fdt_get_node_by_compatible(fdt, DT_PWR_COMPAT);
|
|
}
|
|
#endif
|
|
|
|
diff --git a/core/arch/arm/plat-stm32mp1/service/bsec_svc.c b/core/arch/arm/plat-stm32mp1/service/bsec_svc.c
|
|
index 1ce7195..f345978 100644
|
|
--- a/core/arch/arm/plat-stm32mp1/service/bsec_svc.c
|
|
+++ b/core/arch/arm/plat-stm32mp1/service/bsec_svc.c
|
|
@@ -48,6 +48,10 @@ uint32_t bsec_main(uint32_t x1, uint32_t x2, uint32_t x3, uint32_t *out)
|
|
result = bsec_write_otp(tmp, x2);
|
|
FMSG("read @%" PRIx32 " = %" PRIx32, x2, *out);
|
|
break;
|
|
+ case STM32_SIP_BSEC_WRLOCK_OTP:
|
|
+ FMSG("permanent write lock @%" PRIx32, x2);
|
|
+ result = bsec_permanent_lock_otp(x2);
|
|
+ break;
|
|
default:
|
|
EMSG("Invalid %" PRIx32, x1);
|
|
result = BSEC_ERROR;
|
|
diff --git a/core/arch/arm/plat-stm32mp1/service/rcc_svc.c b/core/arch/arm/plat-stm32mp1/service/rcc_svc.c
|
|
index 7bdaea8..3e7b4d3 100644
|
|
--- a/core/arch/arm/plat-stm32mp1/service/rcc_svc.c
|
|
+++ b/core/arch/arm/plat-stm32mp1/service/rcc_svc.c
|
|
@@ -1,6 +1,6 @@
|
|
// SPDX-License-Identifier: BSD-3-Clause
|
|
/*
|
|
- * Copyright (c) 2017-2018, STMicroelectronics
|
|
+ * Copyright (c) 2017-2019, STMicroelectronics
|
|
*/
|
|
|
|
#include <drivers/stm32mp1_clk.h>
|
|
@@ -438,3 +438,31 @@ uint32_t rcc_scv_handler(uint32_t x1, uint32_t x2, uint32_t x3)
|
|
|
|
return STM32_SIP_OK;
|
|
}
|
|
+
|
|
+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_SIP_RCC_OPP_SET:
|
|
+ if (stm32mp1_set_opp_khz(opp) != 0) {
|
|
+ return STM32_SIP_FAILED;
|
|
+ }
|
|
+ break;
|
|
+
|
|
+ case STM32_SIP_RCC_OPP_ROUND:
|
|
+ if(stm32mp1_round_opp_khz(&opp) != 0) {
|
|
+ return STM32_SIP_FAILED;
|
|
+ }
|
|
+
|
|
+ if (MUL_OVERFLOW(opp, 1000, res))
|
|
+ return STM32_SIP_FAILED;
|
|
+ break;
|
|
+
|
|
+ default:
|
|
+ return STM32_SIP_INVALID_PARAMS;
|
|
+ }
|
|
+
|
|
+ return STM32_SIP_OK;
|
|
+}
|
|
diff --git a/core/arch/arm/plat-stm32mp1/service/rcc_svc.h b/core/arch/arm/plat-stm32mp1/service/rcc_svc.h
|
|
index f198ebd..aaa1f75 100644
|
|
--- a/core/arch/arm/plat-stm32mp1/service/rcc_svc.h
|
|
+++ b/core/arch/arm/plat-stm32mp1/service/rcc_svc.h
|
|
@@ -1,11 +1,12 @@
|
|
/* SPDX-License-Identifier: BSD-2-Clause */
|
|
/*
|
|
- * Copyright (c) 2017-2018, STMicroelectronics
|
|
+ * Copyright (c) 2017-2019, STMicroelectronics
|
|
*/
|
|
|
|
#ifndef __RCC_SVC_H__
|
|
#define __RCC_SVC_H__
|
|
|
|
uint32_t rcc_scv_handler(uint32_t x1, uint32_t x2, uint32_t x3);
|
|
+uint32_t rcc_opp_scv_handler(uint32_t x1, uint32_t x2, uint32_t *res);
|
|
|
|
#endif /*__RCC_SVC_H__*/
|
|
diff --git a/core/arch/arm/plat-stm32mp1/service/stm32mp1_smc.h b/core/arch/arm/plat-stm32mp1/service/stm32mp1_smc.h
|
|
index 2db7b10..3482c34 100644
|
|
--- a/core/arch/arm/plat-stm32mp1/service/stm32mp1_smc.h
|
|
+++ b/core/arch/arm/plat-stm32mp1/service/stm32mp1_smc.h
|
|
@@ -110,6 +110,7 @@
|
|
#define STM32_SIP_BSEC_PROG_OTP 0x2
|
|
#define STM32_SIP_BSEC_WRITE_SHADOW 0x3
|
|
#define STM32_SIP_BSEC_READ_OTP 0x4
|
|
+#define STM32_SIP_BSEC_WRLOCK_OTP 0x5
|
|
|
|
/*
|
|
* SIP functions STM32_SIP_FUNC_SR_MODE
|
|
@@ -182,6 +183,21 @@
|
|
#define STM32_SIP_PD_MAX_PM_DOMAIN 0x3
|
|
|
|
/*
|
|
+ * SIP function STM32_SIP_FUNC_RCC_OPP.
|
|
+ *
|
|
+ * Argument a0: (input) SMCC ID.
|
|
+ * (output) Status return code.
|
|
+ * Argument a1: (input) Service ID (STM32_SIP_RCC_OPP_xxx).
|
|
+ * (output) Rounded frequency, if applicable.
|
|
+ * Argument a2: (input) Requested frequency.
|
|
+ */
|
|
+#define STM32_SIP_FUNC_RCC_OPP 0x1009
|
|
+
|
|
+/* Service ID for STM32_SIP_FUNC_RCC_OPP */
|
|
+#define STM32_SIP_RCC_OPP_SET 0x0
|
|
+#define STM32_SIP_RCC_OPP_ROUND 0x1
|
|
+
|
|
+/*
|
|
* OEM Functions
|
|
*/
|
|
#define STM32_OEM_SVC_VERSION_MAJOR 0x0
|
|
diff --git a/core/arch/arm/plat-stm32mp1/service/stm32mp1_svc_setup.c b/core/arch/arm/plat-stm32mp1/service/stm32mp1_svc_setup.c
|
|
index 3c7958c..a88577a 100644
|
|
--- a/core/arch/arm/plat-stm32mp1/service/stm32mp1_svc_setup.c
|
|
+++ b/core/arch/arm/plat-stm32mp1/service/stm32mp1_svc_setup.c
|
|
@@ -1,6 +1,6 @@
|
|
// SPDX-License-Identifier: BSD-3-Clause
|
|
/*
|
|
- * Copyright (c) 2017-2018, STMicroelectronics
|
|
+ * Copyright (c) 2017-2019, STMicroelectronics
|
|
*/
|
|
|
|
#include <arm.h>
|
|
@@ -70,6 +70,9 @@ bool stm32_sip_service(struct sm_ctx __unused *ctx,
|
|
case STM32_SIP_FUNC_RCC:
|
|
*a0 = rcc_scv_handler(*a1, *a2, *a3);
|
|
break;
|
|
+ case STM32_SIP_FUNC_RCC_OPP:
|
|
+ *a0 = rcc_opp_scv_handler(*a1, *a2, a1);
|
|
+ break;
|
|
#endif
|
|
#ifdef CFG_STM32_CLOCKSRC_CALIB
|
|
case STM32_SIP_RCC_CAL:
|
|
diff --git a/core/arch/arm/plat-stm32mp1/stm32_util.h b/core/arch/arm/plat-stm32mp1/stm32_util.h
|
|
index 347499b..a2818c0 100644
|
|
--- a/core/arch/arm/plat-stm32mp1/stm32_util.h
|
|
+++ b/core/arch/arm/plat-stm32mp1/stm32_util.h
|
|
@@ -1,6 +1,6 @@
|
|
/* SPDX-License-Identifier: BSD-3-Clause */
|
|
/*
|
|
- * Copyright (c) 2017-2018, STMicroelectronics
|
|
+ * Copyright (c) 2017-2019, STMicroelectronics
|
|
*/
|
|
|
|
#ifndef __STM32_UTIL_H__
|
|
@@ -15,8 +15,12 @@
|
|
#include <stdint.h>
|
|
#include <stdbool.h>
|
|
|
|
-/* SoC versioning */
|
|
-uint32_t stm32mp1_dbgmcu_get_chip_version(void);
|
|
+/* SoC versioning and device ID */
|
|
+int stm32mp1_dbgmcu_get_chip_version(uint32_t *chip_version);
|
|
+int stm32mp1_dbgmcu_get_chip_dev_id(uint32_t *chip_dev_id);
|
|
+
|
|
+/* OPP service */
|
|
+bool stm32mp_supports_cpu_opp(uint32_t opp_id);
|
|
|
|
/* SiP & OEM platform services */
|
|
bool stm32_sip_service(struct sm_ctx *ctx,
|
|
@@ -28,6 +32,9 @@ bool stm32_oem_service(struct sm_ctx *ctx,
|
|
/* Platform util for the STGEN driver */
|
|
uintptr_t stm32_get_stgen_base(void);
|
|
|
|
+/* Platform util for the SYSCFG driver */
|
|
+uintptr_t stm32_get_syscfg_base(void);
|
|
+
|
|
/* Platform util for the GIC */
|
|
uintptr_t get_gicc_base(void);
|
|
uintptr_t get_gicd_base(void);
|
|
@@ -120,6 +127,13 @@ void stm32mp_platform_reset(int cpu);
|
|
int stm32mp_start_clock_calib(unsigned int clock_id);
|
|
|
|
/*
|
|
+ * SYSCFG IO compensation.
|
|
+ * These functions assume non-secure world is suspended.
|
|
+ */
|
|
+void stm32mp1_syscfg_enable_io_compensation(void);
|
|
+void stm32mp1_syscfg_disable_io_compensation(void);
|
|
+
|
|
+/*
|
|
* Shared reference counter: increments by 2 on secure increment
|
|
* request, decrements by 2 on secure decrement request. Bit #0
|
|
* is set to 1 on non-secure increment request and reset to 0 on
|
|
diff --git a/core/arch/arm/plat-stm32mp1/stm32mp1_dt.c b/core/arch/arm/plat-stm32mp1/stm32mp1_dt.c
|
|
index 9ce6ba8..7413ebb 100644
|
|
--- a/core/arch/arm/plat-stm32mp1/stm32mp1_dt.c
|
|
+++ b/core/arch/arm/plat-stm32mp1/stm32mp1_dt.c
|
|
@@ -1,6 +1,6 @@
|
|
// SPDX-License-Identifier: BSD-3-Clause
|
|
/*
|
|
- * Copyright (c) 2018, STMicroelectronics - All Rights Reserved
|
|
+ * Copyright (c) 2018-2019, STMicroelectronics - All Rights Reserved
|
|
* Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
|
|
*/
|
|
|
|
@@ -230,6 +230,74 @@ int fdt_get_stdout_node_offset(void *fdt)
|
|
}
|
|
|
|
/*******************************************************************************
|
|
+ * This function returns the offset of the first matching compatible node
|
|
+ * in the DT. It should be used only for single instanced peripherals.
|
|
+ * Returns node on success and a negative FDT error code on failure.
|
|
+ ******************************************************************************/
|
|
+int fdt_get_node_by_compatible(void *fdt, const char *compatible)
|
|
+{
|
|
+ int node = fdt_node_offset_by_compatible(fdt, -1, compatible);
|
|
+
|
|
+ if (node < 0) {
|
|
+ DMSG("Cannot find %s node in DT", 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 node on success and a negative FDT error code on failure.
|
|
+ ******************************************************************************/
|
|
+int fdt_match_instance_by_compatible(void *fdt, 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
|
|
+ * first matching compatible string in the DT. It should be used only for
|
|
+ * single instanced peripherals.
|
|
+ * Returns non null base address on success, and 0 on failure.
|
|
+ ******************************************************************************/
|
|
+uintptr_t fdt_get_peripheral_base(void *fdt, const char *compatible)
|
|
+{
|
|
+ int node;
|
|
+ const fdt32_t *cuint;
|
|
+
|
|
+ node = fdt_get_node_by_compatible(fdt, 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 if success, and STM32MP1_DDR_SIZE_DFLT else.
|
|
******************************************************************************/
|
|
@@ -237,9 +305,8 @@ uint32_t fdt_get_ddr_size(void *fdt)
|
|
{
|
|
int node;
|
|
|
|
- node = fdt_node_offset_by_compatible(fdt, -1, DT_DDR_COMPAT);
|
|
+ node = fdt_get_node_by_compatible(fdt, DT_DDR_COMPAT);
|
|
if (node < 0) {
|
|
- IMSG("%s: Cannot read DDR node in DT\n", __func__);
|
|
return STM32MP1_DDR_SIZE_DFLT;
|
|
}
|
|
|
|
@@ -248,6 +315,127 @@ uint32_t fdt_get_ddr_size(void *fdt)
|
|
}
|
|
|
|
/*******************************************************************************
|
|
+ * This function gets OPP table node from the DT.
|
|
+ * Returns node offset on success and a negative FDT error code on failure.
|
|
+ ******************************************************************************/
|
|
+static int fdt_get_opp_table_node(void *fdt)
|
|
+{
|
|
+ return fdt_get_node_by_compatible(fdt, 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 fdt_get_opp_freqvolt_from_subnode(void *fdt, 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))) {
|
|
+ DMSG("Invalid opp-supported-hw 0x%"PRIx32,
|
|
+ fdt32_to_cpu(*cuint32));
|
|
+ return -FDT_ERR_BADVALUE;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ cuint64 = fdt_getprop(fdt, subnode, "opp-hz", NULL);
|
|
+ if (cuint64 == NULL) {
|
|
+ DMSG("Missing opp-hz");
|
|
+ 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) {
|
|
+ DMSG("Invalid opp-hz %"PRIu64, read_freq_64);
|
|
+ return -FDT_ERR_BADVALUE;
|
|
+ }
|
|
+
|
|
+ cuint32 = fdt_getprop(fdt, subnode, "opp-microvolt", NULL);
|
|
+ if (cuint32 == NULL) {
|
|
+ DMSG("Missing opp-microvolt");
|
|
+ return -FDT_ERR_NOTFOUND;
|
|
+ }
|
|
+
|
|
+ /* Millivolt value must fit on 16 bits */
|
|
+ read_voltage_32 = fdt32_to_cpu(*cuint32) / 1000U;
|
|
+ if (read_voltage_32 > UINT16_MAX) {
|
|
+ DMSG("Invalid opp-microvolt %"PRIu32, 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 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 fdt_get_all_opp_freqvolt(void *fdt, uint32_t *count,
|
|
+ uint32_t *freq_khz_array,
|
|
+ uint32_t *voltage_mv_array)
|
|
+{
|
|
+ int node;
|
|
+ int subnode;
|
|
+ uint32_t idx = 0U;
|
|
+
|
|
+ assert(count != NULL);
|
|
+ assert(freq_khz_array != NULL);
|
|
+ assert(voltage_mv_array != NULL);
|
|
+
|
|
+ node = fdt_get_opp_table_node(fdt);
|
|
+ if (node < 0) {
|
|
+ return node;
|
|
+ }
|
|
+
|
|
+ fdt_for_each_subnode(subnode, fdt, node) {
|
|
+ uint32_t read_freq;
|
|
+ uint32_t read_voltage;
|
|
+
|
|
+ if (fdt_get_opp_freqvolt_from_subnode(fdt, 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;
|
|
+}
|
|
+
|
|
+/*******************************************************************************
|
|
* This function retrieves board model from DT.
|
|
* Returns string taken from model node, NULL otherwise
|
|
******************************************************************************/
|
|
diff --git a/core/arch/arm/plat-stm32mp1/stm32mp_dt.h b/core/arch/arm/plat-stm32mp1/stm32mp_dt.h
|
|
index ec8aa4d..3229f2e 100644
|
|
--- a/core/arch/arm/plat-stm32mp1/stm32mp_dt.h
|
|
+++ b/core/arch/arm/plat-stm32mp1/stm32mp_dt.h
|
|
@@ -1,6 +1,6 @@
|
|
/* SPDX-License-Identifier: BSD-3-Clause */
|
|
/*
|
|
- * Copyright (c) 2018, STMicroelectronics - All Rights Reserved
|
|
+ * Copyright (c) 2018-2019, STMicroelectronics - All Rights Reserved
|
|
* Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
|
|
*/
|
|
|
|
@@ -11,6 +11,7 @@
|
|
#include <stdint.h>
|
|
|
|
#define DT_DDR_COMPAT "st,stm32mp1-ddr"
|
|
+#define DT_OPP_COMPAT "operating-points-v2"
|
|
|
|
struct dt_node_info {
|
|
uint32_t base;
|
|
@@ -28,7 +29,14 @@ void fdt_fill_device_info(void *fdt, struct dt_node_info *info, int node);
|
|
int fdt_get_node(void *fdt, struct dt_node_info *info, int offset,
|
|
const char *compat);
|
|
int fdt_get_stdout_node_offset(void *fdt);
|
|
+int fdt_get_node_by_compatible(void *fdt, const char *compatible);
|
|
+int fdt_match_instance_by_compatible(void *fdt, const char *compatible,
|
|
+ uintptr_t address);
|
|
+uintptr_t fdt_get_peripheral_base(void *fdt, const char *compatible);
|
|
uint32_t fdt_get_ddr_size(void *fdt);
|
|
+int fdt_get_all_opp_freqvolt(void *fdt, uint32_t *count,
|
|
+ uint32_t *freq_khz_array,
|
|
+ uint32_t *voltage_mv_array);
|
|
const char *fdt_get_board_model(void *fdt);
|
|
|
|
int fdt_get_clock_id(void *fdt, int node);
|
|
diff --git a/core/drivers/stm32_bsec.c b/core/drivers/stm32_bsec.c
|
|
index 7fcefdb..0e4c76b 100644
|
|
--- a/core/drivers/stm32_bsec.c
|
|
+++ b/core/drivers/stm32_bsec.c
|
|
@@ -19,9 +19,12 @@
|
|
|
|
#ifdef CFG_DT
|
|
#include <libfdt.h>
|
|
+#include <string.h>
|
|
#endif
|
|
|
|
-#define BSEC_COMPAT "st,stm32mp15-bsec"
|
|
+#define BSEC_COMPAT "st,stm32mp15-bsec"
|
|
+#define DT_NVMEM_LAYOUT_COMPAT "st,stm32-nvmem-layout"
|
|
+
|
|
#define BITS_PER_WORD (CHAR_BIT * sizeof(uint32_t))
|
|
#define OTP_ACCESS_SIZE (ROUNDUP(OTP_MAX_SIZE, BITS_PER_WORD) / BITS_PER_WORD)
|
|
|
|
@@ -76,35 +79,151 @@ 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) {
|
|
+ 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 = ROUNDUP(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);
|
|
+
|
|
+ IMSG("OTP crosses Lower/Upper boundary");
|
|
+ } else {
|
|
+ continue;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if ((fdt_getprop(fdt, bsec_subnode,
|
|
+ "st,non-secure-otp", NULL)) == NULL) {
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ if (((offset % sizeof(uint32_t)) != 0) ||
|
|
+ ((length % sizeof(uint32_t)) != 0)) {
|
|
+ EMSG("Unaligned non-secure OTP\n");
|
|
+ panic();
|
|
+ }
|
|
+
|
|
+ size = length / sizeof(uint32_t);
|
|
+
|
|
+ for (i = otp; i < (otp + size); i++) {
|
|
+ enable_non_secure_access(i);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+struct nvmem_layout {
|
|
+ char *name;
|
|
+ uint32_t number;
|
|
+ size_t bit_len;
|
|
+};
|
|
+
|
|
+static struct nvmem_layout *nvmem_layout;
|
|
+static size_t nvmem_layout_count;
|
|
+
|
|
+static int save_dt_nvmem_layout(void *fdt)
|
|
+{
|
|
+ const fdt32_t *cells;
|
|
+ int i;
|
|
+ int cell_nb;
|
|
+ int nvmem_node;
|
|
+
|
|
+ nvmem_node = fdt_get_node_by_compatible(fdt, DT_NVMEM_LAYOUT_COMPAT);
|
|
+ if (nvmem_node < 0) {
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ cells = fdt_getprop(fdt, nvmem_node, "nvmem-cells", &cell_nb);
|
|
+ if (cells == NULL) {
|
|
+ cell_nb = 0;
|
|
+ }
|
|
+
|
|
+ cell_nb /= sizeof(uint32_t);
|
|
+
|
|
+ i = fdt_stringlist_count(fdt, nvmem_node, "nvmem-cell-names");
|
|
+ if (i < 0) {
|
|
+ i = 0;
|
|
+ }
|
|
+
|
|
+ if (cell_nb != i) {
|
|
+ EMSG("Inconsistent NVMEM layout");
|
|
+ panic();
|
|
+ }
|
|
+
|
|
+ nvmem_layout = calloc(cell_nb, sizeof(*nvmem_layout));
|
|
+ if (nvmem_layout == NULL) {
|
|
+ panic();
|
|
+ }
|
|
+
|
|
+ nvmem_layout_count = (size_t)cell_nb;
|
|
+
|
|
+ for (i = 0; i < cell_nb; i++) {
|
|
+ const fdt32_t *cuint;
|
|
+ const char *string;
|
|
+ int len;
|
|
+ int node;
|
|
+
|
|
+ node = fdt_node_offset_by_phandle(fdt,
|
|
+ fdt32_to_cpu(*(cells + i)));
|
|
+ if (node < 0) {
|
|
+ EMSG("Malformed nvmem_layout node: ignored");
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ cuint = fdt_getprop(fdt, node, "reg", &len);
|
|
+ if ((cuint == NULL) || (len != (2 * (int)sizeof(uint32_t)))) {
|
|
+ EMSG("Malformed nvmem_layout node: ignored");
|
|
continue;
|
|
}
|
|
|
|
- status = _fdt_get_status(fdt, bsec_subnode);
|
|
- if ((status & DT_STATUS_OK_NSEC) == 0U) {
|
|
+ if (fdt32_to_cpu(*cuint) % sizeof(uint32_t)) {
|
|
+ EMSG("Misaligned nvmem_layout element: ignored");
|
|
continue;
|
|
}
|
|
|
|
- size = fdt32_to_cpu(*(cuint + 1)) / sizeof(uint32_t);
|
|
+ nvmem_layout[i].number = fdt32_to_cpu(*cuint) /
|
|
+ sizeof(uint32_t);
|
|
+ nvmem_layout[i].bit_len = fdt32_to_cpu(*(cuint + 1)) * CHAR_BIT;
|
|
|
|
- if ((fdt32_to_cpu(*(cuint + 1)) % sizeof(uint32_t)) != 0) {
|
|
- size++;
|
|
+ string = fdt_stringlist_get(fdt, nvmem_node, "nvmem-cell-names",
|
|
+ i, &len);
|
|
+ if ((string == NULL) || (len == 0)) {
|
|
+ continue;
|
|
}
|
|
|
|
- for (i = reg; i < (reg + size); i++) {
|
|
- enable_non_secure_access(i);
|
|
+ nvmem_layout[i].name = calloc(1, len + 1);
|
|
+ if (nvmem_layout[i].name == NULL) {
|
|
+ panic();
|
|
}
|
|
+
|
|
+ memcpy(nvmem_layout[i].name, string, len);
|
|
}
|
|
|
|
return 0;
|
|
@@ -158,6 +277,44 @@ static uint32_t bsec_check_error(uint32_t otp, bool check_disturbed)
|
|
return BSEC_OK;
|
|
}
|
|
|
|
+#ifdef CFG_DT
|
|
+/*
|
|
+ * bsec_find_otp_name_in_nvmem_layout: find and get OTP location from its name.
|
|
+ * name: sub-node name to look up.
|
|
+ * otp: pointer to read OTP number or NULL.
|
|
+ * otp_bit_len: pointer to read OTP length in bits or NULL.
|
|
+ * return value: BSEC_OK if no error.
|
|
+ */
|
|
+uint32_t bsec_find_otp_name_in_nvmem_layout(const char *name, uint32_t *otp,
|
|
+ uint32_t *otp_bit_len)
|
|
+{
|
|
+ size_t i;
|
|
+
|
|
+ if (name == NULL) {
|
|
+ return BSEC_INVALID_PARAM;
|
|
+ }
|
|
+
|
|
+ for (i = 0; i < nvmem_layout_count; i++) {
|
|
+ if (!nvmem_layout[i].name ||
|
|
+ strcmp(name, nvmem_layout[i].name)) {
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ if (otp != NULL) {
|
|
+ *otp = nvmem_layout[i].number;
|
|
+ }
|
|
+
|
|
+ if (otp_bit_len != NULL) {
|
|
+ *otp_bit_len = nvmem_layout[i].bit_len;
|
|
+ }
|
|
+
|
|
+ return BSEC_OK;
|
|
+ }
|
|
+
|
|
+ return BSEC_ERROR;
|
|
+}
|
|
+#endif
|
|
+
|
|
/*
|
|
* bsec_shadow_register: copy SAFMEM OTP to BSEC data.
|
|
* otp: OTP number.
|
|
@@ -209,11 +366,8 @@ uint32_t bsec_shadow_register(uint32_t otp)
|
|
*/
|
|
uint32_t bsec_read_otp(uint32_t *val, uint32_t otp)
|
|
{
|
|
- uint32_t exc;
|
|
-
|
|
- if (otp > stm32mp_get_otp_max()) {
|
|
+ if (otp > stm32mp_get_otp_max())
|
|
return BSEC_INVALID_PARAM;
|
|
- }
|
|
|
|
*val = read32(bsec_get_base() + BSEC_OTP_DATA_OFF +
|
|
(otp * sizeof(uint32_t)));
|
|
@@ -747,6 +901,8 @@ static TEE_Result initialize_bsec(void)
|
|
|
|
bsec_dt_otp_nsec_access(fdt, node);
|
|
|
|
+ save_dt_nvmem_layout(fdt);
|
|
+
|
|
return TEE_SUCCESS;
|
|
}
|
|
driver_init(initialize_bsec);
|
|
diff --git a/core/drivers/stm32_i2c.c b/core/drivers/stm32_i2c.c
|
|
index 8ba7178..a68ef96 100644
|
|
--- a/core/drivers/stm32_i2c.c
|
|
+++ b/core/drivers/stm32_i2c.c
|
|
@@ -1,6 +1,6 @@
|
|
// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
|
|
/*
|
|
- * Copyright (c) 2016-2018, STMicroelectronics - All Rights Reserved
|
|
+ * Copyright (c) 2016-2019, STMicroelectronics - All Rights Reserved
|
|
*/
|
|
|
|
#include <arm32.h>
|
|
@@ -14,6 +14,7 @@
|
|
#include <stdbool.h>
|
|
#include <stdlib.h>
|
|
#include <stm32_util.h>
|
|
+#include <stm32mp_dt.h>
|
|
|
|
/* STM32 I2C registers offsets */
|
|
#define I2C_CR1 0x00U
|
|
@@ -32,13 +33,14 @@
|
|
|
|
#define MAX_NBYTE_SIZE 255U
|
|
|
|
-#define I2C_NSEC_PER_SEC 1000000000L
|
|
+#define I2C_NSEC_PER_SEC 1000000000UL
|
|
+
|
|
+/* Effective rate cannot be lower than 80% target rate */
|
|
+#define RATE_MIN(rate) (((rate) * 80U) / 100U)
|
|
|
|
/*
|
|
* 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)
|
|
@@ -49,8 +51,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;
|
|
@@ -83,11 +83,11 @@ struct i2c_timing_s {
|
|
*
|
|
* [1] https://www.nxp.com/docs/en/user-guide/UM10204.pdf
|
|
*/
|
|
+/* This table must be sorted in increasing value for field @rate */
|
|
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,
|
|
@@ -96,10 +96,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,
|
|
@@ -108,10 +107,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,
|
|
@@ -184,6 +182,19 @@ 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)
|
|
+{
|
|
+ size_t i;
|
|
+
|
|
+ for (i = 0; i < ARRAY_SIZE(i2c_specs); i++) {
|
|
+ if (rate <= i2c_specs[i].rate) {
|
|
+ return &i2c_specs[i];
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
static void save_cfg(struct i2c_handle_s *hi2c, struct i2c_cfg *cfg)
|
|
{
|
|
uintptr_t base = get_base(hi2c);
|
|
@@ -222,11 +233,11 @@ static void restore_cfg(struct i2c_handle_s *hi2c, struct i2c_cfg *cfg)
|
|
|
|
static void __maybe_unused dump_cfg(struct i2c_cfg *cfg __maybe_unused)
|
|
{
|
|
- DMSG("CR1: %x", (unsigned)cfg->cr1);
|
|
- DMSG("CR2: %x", (unsigned)cfg->cr2);
|
|
- DMSG("OAR1: %x", (unsigned)cfg->oar1);
|
|
- DMSG("OAR2: %x", (unsigned)cfg->oar2);
|
|
- DMSG("TIM: %x", (unsigned)cfg->timingr);
|
|
+ DMSG("CR1: %"PRIx32, cfg->cr1);
|
|
+ DMSG("CR2: %"PRIx32, cfg->cr2);
|
|
+ DMSG("OAR1: %"PRIx32, cfg->oar1);
|
|
+ DMSG("OAR2: %"PRIx32, cfg->oar2);
|
|
+ DMSG("TIM: %"PRIx32, cfg->timingr);
|
|
}
|
|
|
|
static void __maybe_unused dump_i2c(struct i2c_handle_s *hi2c)
|
|
@@ -235,11 +246,11 @@ static void __maybe_unused dump_i2c(struct i2c_handle_s *hi2c)
|
|
|
|
stm32_clock_enable(hi2c->clock);
|
|
|
|
- DMSG("CR1: %x", (unsigned)mmio_read_32(base + I2C_CR1));
|
|
- DMSG("CR2: %x", (unsigned)mmio_read_32(base + I2C_CR2));
|
|
- DMSG("OAR1: %x", (unsigned)mmio_read_32(base + I2C_OAR1));
|
|
- DMSG("OAR2: %x", (unsigned)mmio_read_32(base + I2C_OAR2));
|
|
- DMSG("TIM: %x", (unsigned)mmio_read_32(base + I2C_TIMINGR));
|
|
+ DMSG("CR1: %"PRIx32, mmio_read_32(base + I2C_CR1));
|
|
+ DMSG("CR2: %"PRIx32, mmio_read_32(base + I2C_CR2));
|
|
+ DMSG("OAR1: %"PRIx32, mmio_read_32(base + I2C_OAR1));
|
|
+ DMSG("OAR2: %"PRIx32, mmio_read_32(base + I2C_OAR2));
|
|
+ DMSG("TIM: %"PRIx32, mmio_read_32(base + I2C_TIMINGR));
|
|
|
|
stm32_clock_disable(hi2c->clock);
|
|
}
|
|
@@ -254,7 +265,7 @@ static void __maybe_unused dump_i2c(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;
|
|
@@ -277,31 +288,26 @@ 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:
|
|
- case I2C_SPEED_FAST:
|
|
- case I2C_SPEED_FAST_PLUS:
|
|
- break;
|
|
- default:
|
|
- EMSG("I2C speed out of bound {%d/%d}\n",
|
|
- mode, I2C_SPEED_FAST_PLUS);
|
|
+ specs = get_specs(init->bus_rate);
|
|
+ if (specs == NULL) {
|
|
+ EMSG("I2C speed out of bound: %"PRId32"Hz", init->bus_rate);
|
|
return -1;
|
|
}
|
|
|
|
- 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)) {
|
|
- EMSG(" 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);
|
|
+ if ((init->rise_time > specs->rise_max) ||
|
|
+ (init->fall_time > specs->fall_max)) {
|
|
+ EMSG(" I2C timings out of bound Rise{%"PRId32">%"PRId32"}/Fall{%"PRId32">%"PRId32"}",
|
|
+ init->rise_time, specs->rise_max,
|
|
+ init->fall_time, specs->fall_max);
|
|
return -1;
|
|
}
|
|
|
|
if (init->digital_filter_coef > STM32_I2C_DIGITAL_FILTER_MAX) {
|
|
- EMSG("DNF out of bound %d/%d\n",
|
|
+ EMSG("DNF out of bound %"PRId8"/%d",
|
|
init->digital_filter_coef, STM32_I2C_DIGITAL_FILTER_MAX);
|
|
return -1;
|
|
}
|
|
@@ -313,19 +319,19 @@ 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;
|
|
delay = af_delay_min - ((init->digital_filter_coef + 3) * i2cclk);
|
|
if (SUB_OVERFLOW(sdadel_min, delay ,&sdadel_min))
|
|
sdadel_min = 0;
|
|
|
|
- sdadel_max = i2c_specs[mode].vddat_max - init->rise_time;
|
|
+ sdadel_max = specs->vddat_max - init->rise_time;
|
|
delay = af_delay_max - ((init->digital_filter_coef + 4) * i2cclk);
|
|
if (SUB_OVERFLOW(sdadel_max, delay ,&sdadel_max))
|
|
sdadel_max = 0;
|
|
|
|
- scldel_min = init->rise_time + i2c_specs[mode].sudat_min;
|
|
+ scldel_min = init->rise_time + specs->sudat_min;
|
|
|
|
- DMSG("I2C SDADEL(min/max): %u/%u, SCLDEL(Min): %u\n",
|
|
+ DMSG("I2C SDADEL(min/max): %u/%u, SCLDEL(Min): %u",
|
|
sdadel_min, sdadel_max, scldel_min);
|
|
|
|
memset(&solutions, 0, sizeof(solutions));
|
|
@@ -360,13 +366,13 @@ static int i2c_compute_timing(struct stm32_i2c_init_s *init,
|
|
}
|
|
|
|
if (p_prev == I2C_TIMINGR_PRESC_MAX) {
|
|
- EMSG(" I2C no Prescaler solution\n");
|
|
+ EMSG(" I2C no Prescaler solution");
|
|
return -1;
|
|
}
|
|
|
|
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
|
|
@@ -388,7 +394,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;
|
|
@@ -401,7 +407,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;
|
|
|
|
@@ -421,7 +427,7 @@ static int i2c_compute_timing(struct stm32_i2c_init_s *init,
|
|
}
|
|
|
|
if (s < 0) {
|
|
- EMSG(" I2C no solution at all\n");
|
|
+ EMSG(" I2C no solution at all");
|
|
return -1;
|
|
}
|
|
|
|
@@ -432,15 +438,47 @@ static int i2c_compute_timing(struct stm32_i2c_init_s *init,
|
|
I2C_SET_TIMINGR_SCLH(solutions[s].sclh) |
|
|
I2C_SET_TIMINGR_SCLL(solutions[s].scll);
|
|
|
|
- DMSG("I2C TIMINGR (PRESC/SCLDEL/SDADEL): %i/%i/%i\n",
|
|
+ DMSG("I2C TIMINGR (PRESC/SCLDEL/SDADEL): %i/%"PRIu8"/%"PRIu8"",
|
|
s, solutions[s].scldel, solutions[s].sdadel);
|
|
- DMSG("I2C TIMINGR (SCLH/SCLL): %i/%i\n",
|
|
+ DMSG("I2C TIMINGR (SCLH/SCLL): %"PRIu8"/%"PRIu8"",
|
|
solutions[s].sclh, solutions[s].scll);
|
|
- DMSG("I2C TIMINGR: 0x%x\n", *timing);
|
|
+ DMSG("I2C TIMINGR: 0x%"PRIx32"", *timing);
|
|
|
|
return 0;
|
|
}
|
|
|
|
+
|
|
+/* i2c_specs[] must be sorted by increasing rate */
|
|
+static bool __maybe_unused i2c_specs_is_consistent(void)
|
|
+{
|
|
+ size_t i;
|
|
+
|
|
+ COMPILE_TIME_ASSERT(ARRAY_SIZE(i2c_specs));
|
|
+
|
|
+ for (i = 1; i < ARRAY_SIZE(i2c_specs); i++)
|
|
+ if (i2c_specs[i - 1].rate >= i2c_specs[i].rate)
|
|
+ return false;
|
|
+
|
|
+ return true;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * @brief From requested rate, get the closest I2C rate without exceeding it,
|
|
+ * within I2C specification values defined in @i2c_specs.
|
|
+ * @param rate: The requested rate.
|
|
+ * @retval Found rate, else the lowest value supported by platform.
|
|
+ */
|
|
+static uint32_t get_lower_rate(uint32_t rate)
|
|
+{
|
|
+ int i;
|
|
+
|
|
+ for (i = (int)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
|
|
@@ -456,20 +494,31 @@ static int i2c_setup_timing(struct i2c_handle_s *hi2c,
|
|
int rc = 0;
|
|
uint32_t clock_src;
|
|
|
|
- clock_src = stm32_clock_get_rate(hi2c->clock);
|
|
+ assert(i2c_specs_is_consistent());
|
|
+
|
|
+ clock_src = (uint32_t)stm32_clock_get_rate(hi2c->clock);
|
|
if (clock_src == 0U) {
|
|
- EMSG("I2C clock rate is 0\n");
|
|
+ EMSG("I2C clock rate is 0");
|
|
return -1;
|
|
}
|
|
|
|
+ /*
|
|
+ * 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 == hi2c->saved_frequency) {
|
|
+ *timing = hi2c->saved_timing;
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
do {
|
|
rc = i2c_compute_timing(init, clock_src, timing);
|
|
if (rc != 0) {
|
|
- EMSG("Failed to compute I2C timings\n");
|
|
- if (init->speed_mode > I2C_SPEED_STANDARD) {
|
|
- init->speed_mode--;
|
|
- IMSG("Downgrade I2C speed to %uHz)\n",
|
|
- i2c_specs[init->speed_mode].rate);
|
|
+ EMSG("Failed to compute I2C timings");
|
|
+ if (init->bus_rate > STANDARD_RATE) {
|
|
+ init->bus_rate = get_lower_rate(init->bus_rate);
|
|
+ IMSG("Downgrade I2C speed to %"PRIu32"Hz)",
|
|
+ init->bus_rate);
|
|
} else {
|
|
break;
|
|
}
|
|
@@ -477,17 +526,20 @@ static int i2c_setup_timing(struct i2c_handle_s *hi2c,
|
|
} while (rc != 0);
|
|
|
|
if (rc != 0) {
|
|
- EMSG("Impossible to compute I2C timings\n");
|
|
+ EMSG("Impossible to compute I2C timings");
|
|
return rc;
|
|
}
|
|
|
|
- DMSG("I2C Speed Mode(%i), Freq(%i), Clk Source(%i)\n",
|
|
- init->speed_mode, i2c_specs[init->speed_mode].rate, clock_src);
|
|
- DMSG("I2C Rise(%i) and Fall(%i) Time\n",
|
|
+ DMSG("I2C Freq(%"PRIu32"Hz), Clk Source(%"PRId32")",
|
|
+ init->bus_rate, clock_src);
|
|
+ DMSG("I2C Rise(%"PRId32") and Fall(%"PRId32") Time",
|
|
init->rise_time, init->fall_time);
|
|
- DMSG("I2C Analog Filter(%s), DNF(%i)\n",
|
|
+ DMSG("I2C Analog Filter(%s), DNF(%"PRId8")",
|
|
(init->analog_filter ? "On" : "Off"), init->digital_filter_coef);
|
|
|
|
+ hi2c->saved_timing = *timing;
|
|
+ hi2c->saved_frequency = clock_src;
|
|
+
|
|
return 0;
|
|
}
|
|
|
|
@@ -543,43 +595,27 @@ int stm32_i2c_get_setup_from_fdt(void *fdt, int node,
|
|
struct stm32_pinctrl **pinctrl,
|
|
size_t *pinctrl_count)
|
|
{
|
|
- const fdt32_t *cuint;
|
|
+ uint32_t read_val;
|
|
int count;
|
|
|
|
- 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);
|
|
- }
|
|
+ init->rise_time = fdt_read_uint32_default(fdt, node,
|
|
+ "i2c-scl-rising-time-ns",
|
|
+ STM32_I2C_RISE_TIME_DEFAULT);
|
|
|
|
- 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);
|
|
- }
|
|
+ init->fall_time = fdt_read_uint32_default(fdt, node,
|
|
+ "i2c-scl-falling-time-ns",
|
|
+ STM32_I2C_FALL_TIME_DEFAULT);
|
|
|
|
- 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;
|
|
- }
|
|
+ read_val = fdt_read_uint32_default(fdt, node, "clock-frequency",
|
|
+ STANDARD_RATE);
|
|
+ if (read_val > FAST_PLUS_RATE) {
|
|
+ EMSG("Invalid bus speed (%"PRIu32" > %i)",
|
|
+ read_val, FAST_PLUS_RATE);
|
|
+ return -FDT_ERR_BADVALUE;
|
|
}
|
|
|
|
+ init->bus_rate = read_val;
|
|
+
|
|
count = stm32_pinctrl_fdt_get_pinctrl(fdt, node, NULL, 0);
|
|
if (count <= 0) {
|
|
*pinctrl = NULL;
|
|
@@ -691,7 +727,7 @@ int stm32_i2c_init(struct i2c_handle_s *hi2c,
|
|
I2C_ANALOGFILTER_ENABLE :
|
|
I2C_ANALOGFILTER_DISABLE);
|
|
if (rc != 0) {
|
|
- EMSG("Cannot initialize I2C analog filter (%d)\n", rc);
|
|
+ EMSG("Cannot initialize I2C analog filter (%d)", rc);
|
|
stm32_clock_disable(hi2c->clock);
|
|
return rc;
|
|
}
|
|
diff --git a/core/drivers/stm32_iwdg.c b/core/drivers/stm32_iwdg.c
|
|
index f1cdc1a..f042808 100644
|
|
--- a/core/drivers/stm32_iwdg.c
|
|
+++ b/core/drivers/stm32_iwdg.c
|
|
@@ -1,6 +1,6 @@
|
|
// SPDX-License-Identifier: BSD-3-Clause
|
|
/*
|
|
- * Copyright (c) 2017-2018, STMicroelectronics - All Rights Reserved
|
|
+ * Copyright (c) 2017-2019, STMicroelectronics - All Rights Reserved
|
|
* Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
|
|
*/
|
|
|
|
@@ -202,13 +202,14 @@ static int stm32_iwdg_conf_etimeout(void *fdt, int node,
|
|
void stm32_iwdg_refresh(uint32_t instance)
|
|
{
|
|
struct stm32_iwdg_instance *iwdg = get_iwdg(instance);
|
|
- uintptr_t iwdg_base = get_base(iwdg);
|
|
|
|
- assert(iwdg);
|
|
+ if (iwdg == NULL) {
|
|
+ return;
|
|
+ }
|
|
|
|
stm32_clock_enable(iwdg->clock);
|
|
|
|
- write32(IWDG_KR_RELOAD_KEY, iwdg_base + IWDG_KR_OFFSET);
|
|
+ write32(IWDG_KR_RELOAD_KEY, get_base(iwdg) + IWDG_KR_OFFSET);
|
|
|
|
stm32_clock_disable(iwdg->clock);
|
|
}
|
|
@@ -246,14 +247,14 @@ static TEE_Result iwdg_init(void)
|
|
iwdg.vbase = (uintptr_t)phys_to_virt(iwdg.pbase, memtype);
|
|
|
|
/* DT can specify low power cases */
|
|
- if (fdt_getprop(fdt, node, "stm32,enable-on-stop", NULL) !=
|
|
+ if (fdt_getprop(fdt, node, "stm32,enable-on-stop", NULL) ==
|
|
NULL) {
|
|
- iwdg.flags |= IWDG_ENABLE_ON_STOP;
|
|
+ iwdg.flags |= IWDG_DISABLE_ON_STOP;
|
|
}
|
|
|
|
- if (fdt_getprop(fdt, node, "stm32,enable-on-standby", NULL) !=
|
|
+ if (fdt_getprop(fdt, node, "stm32,enable-on-standby", NULL) ==
|
|
NULL) {
|
|
- iwdg.flags |= IWDG_ENABLE_ON_STANDBY;
|
|
+ iwdg.flags |= IWDG_DISABLE_ON_STANDBY;
|
|
}
|
|
|
|
hw_init = stm32_get_iwdg_otp_config(iwdg.pbase);
|
|
@@ -265,12 +266,12 @@ static TEE_Result iwdg_init(void)
|
|
iwdg.flags |= IWDG_HW_ENABLED;
|
|
}
|
|
|
|
- if ((hw_init & IWDG_ENABLE_ON_STOP) != 0) {
|
|
- iwdg.flags |= IWDG_ENABLE_ON_STOP;
|
|
+ if ((hw_init & IWDG_DISABLE_ON_STOP) != 0) {
|
|
+ iwdg.flags |= IWDG_DISABLE_ON_STOP;
|
|
}
|
|
|
|
- if ((hw_init & IWDG_ENABLE_ON_STANDBY) != 0) {
|
|
- iwdg.flags |= IWDG_ENABLE_ON_STANDBY;
|
|
+ if ((hw_init & IWDG_DISABLE_ON_STANDBY) != 0) {
|
|
+ iwdg.flags |= IWDG_DISABLE_ON_STANDBY;
|
|
}
|
|
|
|
if (dt_info.status == DT_STATUS_DISABLED) {
|
|
diff --git a/core/drivers/stm32_rtc.c b/core/drivers/stm32_rtc.c
|
|
index 709fafa..9834120 100644
|
|
--- a/core/drivers/stm32_rtc.c
|
|
+++ b/core/drivers/stm32_rtc.c
|
|
@@ -233,20 +233,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);
|
|
}
|
|
|
|
/*******************************************************************************
|
|
@@ -254,10 +245,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;
|
|
|
|
@@ -269,12 +259,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) * 1000U;
|
|
}
|
|
|
|
/*******************************************************************************
|
|
@@ -292,8 +277,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;
|
|
@@ -367,7 +352,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;
|
|
}
|
|
|
|
/*******************************************************************************
|
|
@@ -377,7 +362,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;
|
|
|
|
@@ -394,7 +379,7 @@ unsigned long long stm32_rtc_diff_calendar(struct stm32_rtc_calendar *cur,
|
|
|
|
stm32_clock_disable(rtc_dev.clock);
|
|
|
|
- return diff_in_ms;
|
|
+ return (unsigned long long)diff_in_ms;
|
|
}
|
|
|
|
/*******************************************************************************
|
|
diff --git a/core/drivers/stpmic1.c b/core/drivers/stpmic1.c
|
|
index 3831d40..d80edbc 100644
|
|
--- a/core/drivers/stpmic1.c
|
|
+++ b/core/drivers/stpmic1.c
|
|
@@ -1,6 +1,6 @@
|
|
// SPDX-License-Identifier: BSD-3-Clause
|
|
/*
|
|
- * Copyright (c) 2016-2018, STMicroelectronics - All Rights Reserved
|
|
+ * Copyright (c) 2016-2019, STMicroelectronics - All Rights Reserved
|
|
*/
|
|
|
|
#include <drivers/stpmic1.h>
|
|
@@ -347,6 +347,7 @@ static const uint16_t ldo3_voltage_table[] = {
|
|
3300,
|
|
3300,
|
|
3300,
|
|
+ 500, /* VOUT2/2 (Sink/source mode) */
|
|
0xFFFF, /* VREFDDR */
|
|
};
|
|
|
|
@@ -582,17 +583,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);
|
|
@@ -601,7 +604,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)
|
|
@@ -635,9 +638,19 @@ int stpmic1_regulator_mask_reset_set(const char *name)
|
|
regul->mask_reset);
|
|
}
|
|
|
|
+int stpmic1_bo_enable_cfg(const char *name, struct stpmic1_bo_cfg *cfg)
|
|
+{
|
|
+ const struct regul_struct *regul = get_regulator_data(name);
|
|
+
|
|
+ cfg->ctrl_reg = regul->control_reg;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
int stpmic1_bo_enable_unpg(struct stpmic1_bo_cfg *cfg)
|
|
{
|
|
- return stpmic1_register_update(cfg->ctrl_reg, BIT(0), BIT(0));
|
|
+ return stpmic1_register_update(cfg->ctrl_reg, LDO_BUCK_ENABLE_MASK,
|
|
+ LDO_BUCK_ENABLE_MASK);
|
|
}
|
|
|
|
/* Returns 1 if no configuration are expected applied at runtime, 0 otherwise */
|
|
diff --git a/core/include/drivers/stm32_bsec.h b/core/include/drivers/stm32_bsec.h
|
|
index bd33a7b..ee3c918 100644
|
|
--- a/core/include/drivers/stm32_bsec.h
|
|
+++ b/core/include/drivers/stm32_bsec.h
|
|
@@ -112,6 +112,19 @@
|
|
#define FREQ_30_45_MHZ 0x2
|
|
#define FREQ_45_67_MHZ 0x3
|
|
|
|
+#ifdef CFG_DT
|
|
+uint32_t bsec_find_otp_name_in_nvmem_layout(const char *name, uint32_t *otp,
|
|
+ uint32_t *otp_bit_len);
|
|
+#else
|
|
+static inline uint32_t bsec_find_otp_name_in_nvmem_layout(
|
|
+ const char *name __unused,
|
|
+ uint32_t *otp __unused,
|
|
+ uint32_t *otp_bit_len __unused)
|
|
+{
|
|
+ return BSEC_ERROR;
|
|
+}
|
|
+#endif
|
|
+
|
|
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/core/include/drivers/stm32_i2c.h b/core/include/drivers/stm32_i2c.h
|
|
index 3c6e326..83a5b52 100644
|
|
--- a/core/include/drivers/stm32_i2c.h
|
|
+++ b/core/include/drivers/stm32_i2c.h
|
|
@@ -1,6 +1,6 @@
|
|
/* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */
|
|
/*
|
|
- * Copyright (c) 2016-2018, STMicroelectronics - All Rights Reserved
|
|
+ * Copyright (c) 2016-2019, STMicroelectronics - All Rights Reserved
|
|
*/
|
|
|
|
#ifndef __STM32_I2C_H
|
|
@@ -134,15 +134,9 @@
|
|
#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
|
|
+#define STANDARD_RATE 100000
|
|
+#define FAST_RATE 400000
|
|
+#define FAST_PLUS_RATE 1000000
|
|
|
|
struct stm32_i2c_init_s {
|
|
uint32_t own_address1; /*
|
|
@@ -204,12 +198,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
|
|
@@ -273,6 +262,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 */
|
|
struct stm32_pinctrl *pinctrl; /* PINCTRLs configuration for the I2C PINs */
|
|
size_t pinctrl_count; /* Number of PINCTRLs elements */
|
|
struct i2c_cfg sec_cfg; /* Context for secure usage */
|
|
@@ -335,7 +326,6 @@ struct i2c_handle_s {
|
|
/* STM32 specific defines */
|
|
#define STM32_I2C_RISE_TIME_DEFAULT 25 /* ns */
|
|
#define STM32_I2C_FALL_TIME_DEFAULT 10 /* ns */
|
|
-#define STM32_I2C_SPEED_DEFAULT I2C_SPEED_STANDARD
|
|
#define STM32_I2C_ANALOG_FILTER_DELAY_MIN 50 /* ns */
|
|
#define STM32_I2C_ANALOG_FILTER_DELAY_MAX 260 /* ns */
|
|
#define STM32_I2C_DIGITAL_FILTER_MAX 16
|
|
diff --git a/core/include/drivers/stm32_iwdg.h b/core/include/drivers/stm32_iwdg.h
|
|
index b649dee..7dbfbbf 100644
|
|
--- a/core/include/drivers/stm32_iwdg.h
|
|
+++ b/core/include/drivers/stm32_iwdg.h
|
|
@@ -1,6 +1,6 @@
|
|
/* SPDX-License-Identifier: BSD-3-Clause */
|
|
/*
|
|
- * Copyright (c) 2018, STMicroelectronics - All Rights Reserved
|
|
+ * Copyright (c) 2018-2019, STMicroelectronics - All Rights Reserved
|
|
*/
|
|
|
|
#ifndef __STM32_IWDG_H__
|
|
@@ -9,8 +9,8 @@
|
|
#include <stdint.h>
|
|
|
|
#define IWDG_HW_ENABLED BIT(0)
|
|
-#define IWDG_ENABLE_ON_STOP BIT(1)
|
|
-#define IWDG_ENABLE_ON_STANDBY BIT(2)
|
|
+#define IWDG_DISABLE_ON_STOP BIT(1)
|
|
+#define IWDG_DISABLE_ON_STANDBY BIT(2)
|
|
|
|
void stm32_iwdg_refresh(uint32_t instance);
|
|
|
|
diff --git a/core/include/drivers/stpmic1.h b/core/include/drivers/stpmic1.h
|
|
index 3073662..7be6931 100644
|
|
--- a/core/include/drivers/stpmic1.h
|
|
+++ b/core/include/drivers/stpmic1.h
|
|
@@ -1,6 +1,6 @@
|
|
/* SPDX-License-Identifier: BSD-3-Clause */
|
|
/*
|
|
- * Copyright (c) 2016-2018, STMicroelectronics - All Rights Reserved
|
|
+ * Copyright (c) 2016-2019, STMicroelectronics - All Rights Reserved
|
|
*/
|
|
|
|
#ifndef __STPMIC1_H__
|
|
@@ -85,15 +85,15 @@
|
|
#define ITSOURCE4_REG 0xB3U
|
|
|
|
/* Registers masks */
|
|
-#define LDO_VOLTAGE_MASK 0x7CU
|
|
-#define BUCK_VOLTAGE_MASK 0xFCU
|
|
+#define LDO_VOLTAGE_MASK GENMASK_32(6, 2)
|
|
+#define BUCK_VOLTAGE_MASK GENMASK_32(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_32(1, 0)
|
|
|
|
/* Pull down register */
|
|
#define BUCK1_PULL_DOWN_SHIFT 0
|
|
@@ -134,12 +134,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_32(5, 4)
|
|
#define VINLOW_HYST_SHIFT 4
|
|
-#define VINLOW_THRESHOLD_MASK 0x7
|
|
+#define VINLOW_THRESHOLD_MASK GENMASK_32(3, 1)
|
|
#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_32(7, 0)
|
|
|
|
/* USB Control Register */
|
|
#define BOOST_OVP_DISABLED BIT(7)
|
|
@@ -157,7 +157,7 @@ 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);
|
|
@@ -199,6 +199,7 @@ struct stpmic1_lp_cfg {
|
|
uint8_t mask;
|
|
};
|
|
|
|
+int stpmic1_bo_enable_cfg(const char *name, struct stpmic1_bo_cfg *cfg);
|
|
int stpmic1_bo_enable_unpg(struct stpmic1_bo_cfg *cfg);
|
|
int stpmic1_bo_voltage_cfg(const char *name, uint16_t millivolts,
|
|
struct stpmic1_bo_cfg *cfg);
|
|
--
|
|
2.7.4
|
|
|