From 09948ae7f4f34cd1911f6dc83804abf4e6f6065f Mon Sep 17 00:00:00 2001 From: Christophe Priouzeau Date: Tue, 5 Feb 2019 11:22:25 +0100 Subject: [PATCH] Add optee os for stm32mp machine Signed-off-by: Christophe Priouzeau --- recipes-security/optee/optee-os-stm32mp.inc | 135 + .../optee/optee-os-stm32mp_3.3.0.bb | 40 + .../optee/optee-os/0001-st-updates-r1.patch | 23389 ++++++++++++++++ .../optee/optee-os/README.HOW_TO.txt | 147 + 4 files changed, 23711 insertions(+) create mode 100644 recipes-security/optee/optee-os-stm32mp.inc create mode 100644 recipes-security/optee/optee-os-stm32mp_3.3.0.bb create mode 100644 recipes-security/optee/optee-os/0001-st-updates-r1.patch create mode 100644 recipes-security/optee/optee-os/README.HOW_TO.txt diff --git a/recipes-security/optee/optee-os-stm32mp.inc b/recipes-security/optee/optee-os-stm32mp.inc new file mode 100644 index 0000000..85d7d6c --- /dev/null +++ b/recipes-security/optee/optee-os-stm32mp.inc @@ -0,0 +1,135 @@ +FILESEXTRAPATHS_prepend := "${THISDIR}/optee-os:" + +PACKAGE_ARCH = "${MACHINE_ARCH}" + +B = "${WORKDIR}/build" +# Configure build dir for externalsrc class usage through devtool +EXTERNALSRC_BUILD_pn-${PN} = "${WORKDIR}/build" + +DEPENDS += "dtc-native python-pycrypto-native" + +inherit deploy pythonnative + +OPTEEMACHINE ?= "${MACHINE}" +OPTEEOUTPUTMACHINE ?= "${MACHINE}" + +EXTRA_OEMAKE = "PLATFORM=${OPTEEMACHINE} \ + CROSS_COMPILE_core=${HOST_PREFIX} \ + CROSS_COMPILE_ta_arm64=${HOST_PREFIX} \ + ${@bb.utils.contains('TUNE_FEATURES', 'aarch64', 'CFG_ARM64_core=y ta-targets=ta_arm64', 'CFG_ARM32_core=y CROSS_COMPILE_ta_arm32=${HOST_PREFIX}', d)} \ + NOWERROR=1 \ + LDFLAGS= \ + LIBGCC_LOCATE_CFLAGS=--sysroot=${STAGING_DIR_HOST} \ + " + +EXTRA_OEMAKE += "CFG_TEE_CORE_LOG_LEVEL=2" +EXTRA_OEMAKE += "CFG_TEE_CORE_DEBUG=n" +EXTRA_OEMAKE += "comp-cflagscore='--sysroot=${STAGING_DIR_TARGET}'" + +OPTEE_ARCH_armv7a = "arm32" +OPTEE_ARCH_armv7ve = "arm32" +OPTEE_ARCH_aarch64 = "arm64" + +do_compile() { + unset -v CFLAGS CPPFLAGS LDFLAGS LDADD + if [ -n "${OPTEE_CONF}" ]; then + for conf in ${OPTEE_CONF}; do + oe_runmake -C ${S} O=${B}/${conf} CFG_SECURE_DT=${conf} + done + else + oe_runmake -C ${S} O=${B}/out + fi +} + +do_install() { + #install TA devkit + install -d ${D}${includedir}/optee/export-user_ta/ + + if [ -n "${OPTEE_CONF}" ]; then + for conf in ${OPTEE_CONF}; do + for f in ${B}/${conf}/export-ta_${OPTEE_ARCH}/* ; do + cp -aRf $f ${D}${includedir}/optee/export-user_ta/ + done + done + fi +} + +# Configure optee binaries +OPTEE_BOOTCHAIN = "optee" +OPTEE_HEADER = "tee-header_v2" +OPTEE_PAGEABLE = "tee-pageable_v2" +OPTEE_PAGER = "tee-pager_v2" +OPTEE_SUFFIX = "stm32" + +do_deploy() { + install -d ${DEPLOYDIR} + if [ -n "${OPTEE_CONF}" ]; then + for conf in ${OPTEE_CONF}; do + install -m 644 ${B}/${conf}/core/${OPTEE_HEADER}.${OPTEE_SUFFIX} ${DEPLOYDIR}/${OPTEE_HEADER}-${conf}-${OPTEE_BOOTCHAIN}.${OPTEE_SUFFIX} + install -m 644 ${B}/${conf}/core/${OPTEE_PAGER}.${OPTEE_SUFFIX} ${DEPLOYDIR}/${OPTEE_PAGER}-${conf}-${OPTEE_BOOTCHAIN}.${OPTEE_SUFFIX} + install -m 644 ${B}/${conf}/core/${OPTEE_PAGEABLE}.${OPTEE_SUFFIX} ${DEPLOYDIR}/${OPTEE_PAGEABLE}-${conf}-${OPTEE_BOOTCHAIN}.${OPTEE_SUFFIX} + done + else + install -m 644 ${B}/core/${OPTEE_HEADER}.${OPTEE_SUFFIX} ${DEPLOYDIR}/${OPTEE_HEADER}-${OPTEE_BOOTCHAIN}.${OPTEE_SUFFIX} + install -m 644 ${B}/core/${OPTEE_PAGER}.${OPTEE_SUFFIX} ${DEPLOYDIR}/${OPTEE_PAGER}-${OPTEE_BOOTCHAIN}.${OPTEE_SUFFIX} + install -m 644 ${B}/core/${OPTEE_PAGEABLE}.${OPTEE_SUFFIX} ${DEPLOYDIR}/${OPTEE_PAGEABLE}-${OPTEE_BOOTCHAIN}.${OPTEE_SUFFIX} + fi +} +addtask deploy before do_build after do_compile + +FILES_${PN} = "${nonarch_base_libdir}/firmware/" +FILES_${PN}-dev = "/usr/include/optee" + +INSANE_SKIP_${PN}-dev = "staticdev" + +INHIBIT_PACKAGE_STRIP = "1" + +# ---------------------------------------- +# ARCHIVER +# +inherit archiver +ARCHIVER_MODE[src] = "${@'original' if d.getVar('ST_ARCHIVER_ENABLE') == '1' else ''}" +SRC_URI += "file://README.HOW_TO.txt" + +inherit archiver_stm32mp_clean + +archiver_create_makefile_for_sdk() { + mkdir -p ${ARCHIVER_OUTDIR} + + #remove default variable + echo "LDFLAGS=" > ${ARCHIVER_OUTDIR}/Makefile.sdk + echo "CFLAGS=" >> ${ARCHIVER_OUTDIR}/Makefile.sdk + echo "CPPFLAGS=" >> ${ARCHIVER_OUTDIR}/Makefile.sdk + echo "" >> ${ARCHIVER_OUTDIR}/Makefile.sdk + + echo "LOCAL_PATH=\$(PWD)" >> ${ARCHIVER_OUTDIR}/Makefile.sdk + echo "" >> ${ARCHIVER_OUTDIR}/Makefile.sdk + + #set default CONFIGURATION with configured OPTEE_CONF + if [ -n "${OPTEE_CONF}" ]; then + echo "PLATFORM ?= ${MACHINE}" >> ${ARCHIVER_OUTDIR}/Makefile.sdk + echo "CFG_SECURE_DT ?= ${OPTEE_CONF}" >> ${ARCHIVER_OUTDIR}/Makefile.sdk + fi + + echo -n "EXTRA_OEMAKE=" >> ${ARCHIVER_OUTDIR}/Makefile.sdk + echo "${EXTRA_OEMAKE}" | sed "s|LIBGCC_LOCATE_CFLAGS=[^ ]* |LIBGCC_LOCATE_CFLAGS=\$(OECORE_NATIVE_SYSROOTK) |;s|comp-cflagscore='[^']*'|comp-cflagscore='\$(KCFLAGS)'|" >> ${ARCHIVER_OUTDIR}/Makefile.sdk + + echo "" >> ${ARCHIVER_OUTDIR}/Makefile.sdk + echo "all:" >> ${ARCHIVER_OUTDIR}/Makefile.sdk + echo " if test -n \"\$(CFG_SECURE_DT)\" ; then \\" >> ${ARCHIVER_OUTDIR}/Makefile.sdk + echo " for dt in \$(CFG_SECURE_DT) ; do \\" >> ${ARCHIVER_OUTDIR}/Makefile.sdk + echo " \$(MAKE) \$(EXTRA_OEMAKE) -C \$(LOCAL_PATH) PREFIX=\$(SDKTARGETSYSROOT) O=\$(LOCAL_PATH)/../build/\$\$dt CFG_SECURE_DT=\$\$dt ; \\" >> ${ARCHIVER_OUTDIR}/Makefile.sdk + # Copy binary files with explicit name + echo " cp ../build/\$\$dt/core/${OPTEE_HEADER}.${OPTEE_SUFFIX} ../build/${OPTEE_HEADER}-\$\$dt-${OPTEE_BOOTCHAIN}.${OPTEE_SUFFIX} ; \\" >> ${ARCHIVER_OUTDIR}/Makefile.sdk + echo " cp ../build/\$\$dt/core/${OPTEE_PAGER}.${OPTEE_SUFFIX} ../build/${OPTEE_PAGER}-\$\$dt-${OPTEE_BOOTCHAIN}.${OPTEE_SUFFIX} ; \\" >> ${ARCHIVER_OUTDIR}/Makefile.sdk + echo " cp ../build/\$\$dt/core/${OPTEE_PAGEABLE}.${OPTEE_SUFFIX} ../build/${OPTEE_PAGEABLE}-\$\$dt-${OPTEE_BOOTCHAIN}.${OPTEE_SUFFIX} ; \\" >> ${ARCHIVER_OUTDIR}/Makefile.sdk + echo " done ; \\" >> ${ARCHIVER_OUTDIR}/Makefile.sdk + echo " else \\" >> ${ARCHIVER_OUTDIR}/Makefile.sdk + echo " \$(MAKE) \$(EXTRA_OEMAKE) -C \$(LOCAL_PATH) PREFIX=\$(SDKTARGETSYSROOT) O=\$(LOCAL_PATH)/../build/ ; \\" >> ${ARCHIVER_OUTDIR}/Makefile.sdk + # Copy binary files with explicit name + echo " cp ../build/core/${OPTEE_HEADER}.${OPTEE_SUFFIX} ../build/${OPTEE_HEADER}-${OPTEE_BOOTCHAIN}.${OPTEE_SUFFIX} ; \\" >> ${ARCHIVER_OUTDIR}/Makefile.sdk + echo " cp ../build/core/${OPTEE_PAGER}.${OPTEE_SUFFIX} ../build/${OPTEE_PAGER}-${OPTEE_BOOTCHAIN}.${OPTEE_SUFFIX} ; \\" >> ${ARCHIVER_OUTDIR}/Makefile.sdk + echo " cp ../build/core/${OPTEE_PAGEABLE}.${OPTEE_SUFFIX} ../build/${OPTEE_PAGEABLE}-${OPTEE_BOOTCHAIN}.${OPTEE_SUFFIX} ; \\" >> ${ARCHIVER_OUTDIR}/Makefile.sdk + echo " fi" >> ${ARCHIVER_OUTDIR}/Makefile.sdk +} +do_ar_original[prefuncs] += "archiver_create_makefile_for_sdk" diff --git a/recipes-security/optee/optee-os-stm32mp_3.3.0.bb b/recipes-security/optee/optee-os-stm32mp_3.3.0.bb new file mode 100644 index 0000000..5a34e67 --- /dev/null +++ b/recipes-security/optee/optee-os-stm32mp_3.3.0.bb @@ -0,0 +1,40 @@ +SUMMARY = "OPTEE TA development kit for stm32mp" +LICENSE = "BSD" +LIC_FILES_CHKSUM = "file://LICENSE;md5=69663ab153298557a59c67a60a743e5b" + +COMPATIBLE_MACHINE = "(stm32mpcommon)" + +SRC_URI = "https://github.com/OP-TEE/optee_os/archive/${PV}.tar.gz" +SRC_URI[md5sum] = "7cb56c333066fd576460358fc97da85f" +SRC_URI[sha256sum] = "7b62e9fe650e197473eb2f4dc35c09d1e6395eb48dc1c16cc139d401b359ac6f" + +SRC_URI += " \ + file://0001-st-updates-r1.patch \ + " + +require optee-os-stm32mp.inc + +PV = "3.3.0" + +S = "${WORKDIR}/optee_os-${PV}" + +PROVIDES += "optee-os" + +do_configure_prepend(){ + chmod 755 ${S}/scripts/bin_to_c.py +} + +# --------------------------------- +# Configure devupstream class usage +# --------------------------------- +BBCLASSEXTEND = "devupstream:target" + +SRC_URI_class-devupstream = "git://github.com/STMicroelectronics/optee_os.git;protocol=https;branch=3.3.0-stm32mp" +SRCREV_class-devupstream = "5f5cc70dfd04419be2ba66b87f41584b6136118c" + +# --------------------------------- +# Configure default preference to manage dynamic selection between tarball and github +# --------------------------------- +STM32MP_SOURCE_SELECTION ?= "tarball" + +DEFAULT_PREFERENCE = "${@bb.utils.contains('STM32MP_SOURCE_SELECTION', 'github', '-1', '1', d)}" diff --git a/recipes-security/optee/optee-os/0001-st-updates-r1.patch b/recipes-security/optee/optee-os/0001-st-updates-r1.patch new file mode 100644 index 0000000..4a95e32 --- /dev/null +++ b/recipes-security/optee/optee-os/0001-st-updates-r1.patch @@ -0,0 +1,23389 @@ +From da84a97b7083d65144ed658e0f0def1232b7852c Mon Sep 17 00:00:00 2001 +From: christophe montaud +Date: Wed, 30 Jan 2019 10:41:28 +0100 +Subject: [PATCH] st updates r1 + +--- + core/arch/arm/fdts/stm32mp15-ddr.dtsi | 153 ++ + .../arm/fdts/stm32mp15-ddr3-1x4Gb-1066-binG.dtsi | 121 ++ + .../arm/fdts/stm32mp15-ddr3-2x4Gb-1066-binG.dtsi | 122 ++ + core/arch/arm/fdts/stm32mp157-pinctrl.dtsi | 350 +++++ + core/arch/arm/fdts/stm32mp157a-dk1.dts | 380 +++++ + core/arch/arm/fdts/stm32mp157c-dk2.dts | 16 + + core/arch/arm/fdts/stm32mp157c-ed1.dts | 381 +++++ + core/arch/arm/fdts/stm32mp157c-ev1.dts | 67 + + core/arch/arm/fdts/stm32mp157c-security.dtsi | 71 + + core/arch/arm/fdts/stm32mp157c.dtsi | 371 +++++ + core/arch/arm/fdts/stm32mp157caa-pinctrl.dtsi | 90 ++ + core/arch/arm/fdts/stm32mp157cab-pinctrl.dtsi | 62 + + core/arch/arm/fdts/stm32mp157cac-pinctrl.dtsi | 78 + + core/arch/arm/fdts/stm32mp157cad-pinctrl.dtsi | 62 + + core/arch/arm/include/arm32.h | 14 +- + core/arch/arm/include/kernel/delay.h | 8 + + core/arch/arm/include/mm/core_mmu.h | 3 + + core/arch/arm/include/sm/pm.h | 4 + + core/arch/arm/kernel/delay.c | 40 +- + core/arch/arm/kernel/generic_boot.c | 36 +- + core/arch/arm/mm/core_mmu.c | 3 + + core/arch/arm/mm/mobj.c | 3 +- + core/arch/arm/plat-stm32mp1/boot_api.h | 2 + + core/arch/arm/plat-stm32mp1/conf.mk | 81 +- + core/arch/arm/plat-stm32mp1/drivers/stm32_reset.c | 60 + + core/arch/arm/plat-stm32mp1/drivers/stm32_reset.h | 15 + + .../arm/plat-stm32mp1/drivers/stm32mp1_calib.c | 457 ++++++ + core/arch/arm/plat-stm32mp1/drivers/stm32mp1_clk.c | 1527 ++++++++++++++++++ + core/arch/arm/plat-stm32mp1/drivers/stm32mp1_clk.h | 62 + + .../arm/plat-stm32mp1/drivers/stm32mp1_clkfunc.c | 340 ++++ + .../arm/plat-stm32mp1/drivers/stm32mp1_clkfunc.h | 33 + + .../arch/arm/plat-stm32mp1/drivers/stm32mp1_ddrc.c | 513 ++++++ + .../arch/arm/plat-stm32mp1/drivers/stm32mp1_ddrc.h | 205 +++ + .../arch/arm/plat-stm32mp1/drivers/stm32mp1_pmic.c | 614 ++++++++ + .../arch/arm/plat-stm32mp1/drivers/stm32mp1_pmic.h | 33 + + core/arch/arm/plat-stm32mp1/drivers/stm32mp1_pwr.c | 21 + + core/arch/arm/plat-stm32mp1/drivers/stm32mp1_pwr.h | 48 + + core/arch/arm/plat-stm32mp1/drivers/stm32mp1_rcc.c | 51 + + core/arch/arm/plat-stm32mp1/drivers/stm32mp1_rcc.h | 539 +++++++ + core/arch/arm/plat-stm32mp1/drivers/sub.mk | 8 + + core/arch/arm/plat-stm32mp1/link.mk | 6 +- + core/arch/arm/plat-stm32mp1/main.c | 578 ++++++- + core/arch/arm/plat-stm32mp1/platform_config.h | 183 ++- + core/arch/arm/plat-stm32mp1/pm/context.c | 510 ++++++ + core/arch/arm/plat-stm32mp1/pm/context.h | 100 ++ + .../arm/plat-stm32mp1/pm/context_asm_defines.c | 28 + + core/arch/arm/plat-stm32mp1/pm/low_power.c | 431 ++++++ + core/arch/arm/plat-stm32mp1/pm/pm_helpers.S | 635 ++++++++ + core/arch/arm/plat-stm32mp1/pm/power.h | 26 + + core/arch/arm/plat-stm32mp1/pm/power_config.c | 212 +++ + core/arch/arm/plat-stm32mp1/pm/psci.c | 427 +++++ + core/arch/arm/plat-stm32mp1/pm/sub.mk | 7 + + core/arch/arm/plat-stm32mp1/reset.S | 28 +- + core/arch/arm/plat-stm32mp1/scripts/stm32image.py | 19 +- + core/arch/arm/plat-stm32mp1/service/bsec_svc.c | 65 + + core/arch/arm/plat-stm32mp1/service/bsec_svc.h | 14 + + .../arch/arm/plat-stm32mp1/service/low_power_svc.c | 153 ++ + .../arch/arm/plat-stm32mp1/service/low_power_svc.h | 22 + + core/arch/arm/plat-stm32mp1/service/pwr_svc.c | 117 ++ + core/arch/arm/plat-stm32mp1/service/pwr_svc.h | 11 + + core/arch/arm/plat-stm32mp1/service/rcc_svc.c | 440 ++++++ + core/arch/arm/plat-stm32mp1/service/rcc_svc.h | 11 + + core/arch/arm/plat-stm32mp1/service/stm32mp1_smc.h | 211 +++ + .../arm/plat-stm32mp1/service/stm32mp1_svc_setup.c | 129 ++ + core/arch/arm/plat-stm32mp1/service/sub.mk | 7 + + core/arch/arm/plat-stm32mp1/shared_resources.c | 1007 ++++++++++++ + core/arch/arm/plat-stm32mp1/stm32_util.h | 287 ++++ + core/arch/arm/plat-stm32mp1/stm32mp1_dt.c | 338 ++++ + core/arch/arm/plat-stm32mp1/stm32mp_dt.h | 39 + + core/arch/arm/plat-stm32mp1/stm32mp_pm.h | 49 + + core/arch/arm/plat-stm32mp1/sub.mk | 6 + + core/arch/arm/sm/pm_a32.S | 83 +- + core/arch/arm/tee/entry_std.c | 2 +- + core/drivers/gic.c | 210 ++- + core/drivers/stm32_bsec.c | 824 ++++++++++ + core/drivers/stm32_etzpc.c | 337 ++++ + core/drivers/stm32_gpio.c | 417 +++++ + core/drivers/stm32_i2c.c | 1629 ++++++++++++++++++++ + core/drivers/stm32_iwdg.c | 308 ++++ + core/drivers/stm32_rng.c | 200 +++ + core/drivers/stm32_rtc.c | 503 ++++++ + core/drivers/stm32_timer.c | 272 ++++ + core/drivers/stm32_uart.c | 142 +- + core/drivers/stpmic1.c | 954 ++++++++++++ + core/drivers/sub.mk | 9 + + core/include/drivers/gic.h | 29 + + core/include/drivers/stm32_bsec.h | 143 ++ + core/include/drivers/stm32_etzpc.h | 75 + + core/include/drivers/stm32_gpio.h | 107 ++ + core/include/drivers/stm32_i2c.h | 377 +++++ + core/include/drivers/stm32_iwdg.h | 17 + + core/include/drivers/stm32_rng.h | 14 + + core/include/drivers/stm32_rtc.h | 73 + + core/include/drivers/stm32_timer.h | 25 + + core/include/drivers/stm32_uart.h | 10 +- + core/include/drivers/stpmic1.h | 228 +++ + core/include/dt-bindings/clock/stm32mp1-clks.h | 252 +++ + core/include/dt-bindings/clock/stm32mp1-clksrc.h | 284 ++++ + core/include/dt-bindings/etzpc/stm32-etzpc.h | 108 ++ + .../dt-bindings/interrupt-controller/arm-gic.h | 21 + + core/include/dt-bindings/pinctrl/stm32-pinfunc.h | 41 + + core/include/dt-bindings/power/stm32mp1-power.h | 19 + + core/include/dt-bindings/reset/stm32mp1-resets.h | 108 ++ + core/include/kernel/interrupt.h | 15 + + core/kernel/console.c | 9 +- + core/kernel/interrupt.c | 10 + + core/lib/libfdt/fdt_ro.c | 154 +- + core/lib/libfdt/fdt_rw.c | 11 +- + core/lib/libfdt/fdt_wip.c | 29 +- + core/lib/libfdt/include/fdt.h | 8 + + core/lib/libfdt/include/libfdt.h | 247 ++- + core/secure_dt.mk | 107 ++ + core/sub.mk | 7 + + lib/libutils/ext/include/util.h | 7 + + mk/config.mk | 23 +- + scripts/bin_to_c.py | 58 + + 116 files changed, 21451 insertions(+), 195 deletions(-) + create mode 100644 core/arch/arm/fdts/stm32mp15-ddr.dtsi + create mode 100644 core/arch/arm/fdts/stm32mp15-ddr3-1x4Gb-1066-binG.dtsi + create mode 100644 core/arch/arm/fdts/stm32mp15-ddr3-2x4Gb-1066-binG.dtsi + create mode 100644 core/arch/arm/fdts/stm32mp157-pinctrl.dtsi + create mode 100644 core/arch/arm/fdts/stm32mp157a-dk1.dts + create mode 100644 core/arch/arm/fdts/stm32mp157c-dk2.dts + create mode 100644 core/arch/arm/fdts/stm32mp157c-ed1.dts + create mode 100644 core/arch/arm/fdts/stm32mp157c-ev1.dts + create mode 100644 core/arch/arm/fdts/stm32mp157c-security.dtsi + create mode 100644 core/arch/arm/fdts/stm32mp157c.dtsi + create mode 100644 core/arch/arm/fdts/stm32mp157caa-pinctrl.dtsi + create mode 100644 core/arch/arm/fdts/stm32mp157cab-pinctrl.dtsi + create mode 100644 core/arch/arm/fdts/stm32mp157cac-pinctrl.dtsi + create mode 100644 core/arch/arm/fdts/stm32mp157cad-pinctrl.dtsi + create mode 100644 core/arch/arm/plat-stm32mp1/drivers/stm32_reset.c + create mode 100644 core/arch/arm/plat-stm32mp1/drivers/stm32_reset.h + create mode 100644 core/arch/arm/plat-stm32mp1/drivers/stm32mp1_calib.c + create mode 100644 core/arch/arm/plat-stm32mp1/drivers/stm32mp1_clk.c + create mode 100644 core/arch/arm/plat-stm32mp1/drivers/stm32mp1_clk.h + create mode 100644 core/arch/arm/plat-stm32mp1/drivers/stm32mp1_clkfunc.c + create mode 100644 core/arch/arm/plat-stm32mp1/drivers/stm32mp1_clkfunc.h + create mode 100644 core/arch/arm/plat-stm32mp1/drivers/stm32mp1_ddrc.c + create mode 100644 core/arch/arm/plat-stm32mp1/drivers/stm32mp1_ddrc.h + create mode 100644 core/arch/arm/plat-stm32mp1/drivers/stm32mp1_pmic.c + create mode 100644 core/arch/arm/plat-stm32mp1/drivers/stm32mp1_pmic.h + create mode 100644 core/arch/arm/plat-stm32mp1/drivers/stm32mp1_pwr.c + create mode 100644 core/arch/arm/plat-stm32mp1/drivers/stm32mp1_pwr.h + create mode 100644 core/arch/arm/plat-stm32mp1/drivers/stm32mp1_rcc.c + create mode 100644 core/arch/arm/plat-stm32mp1/drivers/stm32mp1_rcc.h + create mode 100644 core/arch/arm/plat-stm32mp1/drivers/sub.mk + create mode 100644 core/arch/arm/plat-stm32mp1/pm/context.c + create mode 100644 core/arch/arm/plat-stm32mp1/pm/context.h + create mode 100644 core/arch/arm/plat-stm32mp1/pm/context_asm_defines.c + create mode 100644 core/arch/arm/plat-stm32mp1/pm/low_power.c + create mode 100644 core/arch/arm/plat-stm32mp1/pm/pm_helpers.S + create mode 100644 core/arch/arm/plat-stm32mp1/pm/power.h + create mode 100644 core/arch/arm/plat-stm32mp1/pm/power_config.c + create mode 100644 core/arch/arm/plat-stm32mp1/pm/psci.c + create mode 100644 core/arch/arm/plat-stm32mp1/pm/sub.mk + create mode 100644 core/arch/arm/plat-stm32mp1/service/bsec_svc.c + create mode 100644 core/arch/arm/plat-stm32mp1/service/bsec_svc.h + create mode 100644 core/arch/arm/plat-stm32mp1/service/low_power_svc.c + create mode 100644 core/arch/arm/plat-stm32mp1/service/low_power_svc.h + create mode 100644 core/arch/arm/plat-stm32mp1/service/pwr_svc.c + create mode 100644 core/arch/arm/plat-stm32mp1/service/pwr_svc.h + create mode 100644 core/arch/arm/plat-stm32mp1/service/rcc_svc.c + create mode 100644 core/arch/arm/plat-stm32mp1/service/rcc_svc.h + create mode 100644 core/arch/arm/plat-stm32mp1/service/stm32mp1_smc.h + create mode 100644 core/arch/arm/plat-stm32mp1/service/stm32mp1_svc_setup.c + create mode 100644 core/arch/arm/plat-stm32mp1/service/sub.mk + create mode 100644 core/arch/arm/plat-stm32mp1/shared_resources.c + create mode 100644 core/arch/arm/plat-stm32mp1/stm32_util.h + create mode 100644 core/arch/arm/plat-stm32mp1/stm32mp1_dt.c + create mode 100644 core/arch/arm/plat-stm32mp1/stm32mp_dt.h + create mode 100644 core/arch/arm/plat-stm32mp1/stm32mp_pm.h + create mode 100644 core/drivers/stm32_bsec.c + create mode 100644 core/drivers/stm32_etzpc.c + create mode 100644 core/drivers/stm32_gpio.c + create mode 100644 core/drivers/stm32_i2c.c + create mode 100644 core/drivers/stm32_iwdg.c + create mode 100644 core/drivers/stm32_rng.c + create mode 100644 core/drivers/stm32_rtc.c + create mode 100644 core/drivers/stm32_timer.c + create mode 100644 core/drivers/stpmic1.c + create mode 100644 core/include/drivers/stm32_bsec.h + create mode 100644 core/include/drivers/stm32_etzpc.h + create mode 100644 core/include/drivers/stm32_gpio.h + create mode 100644 core/include/drivers/stm32_i2c.h + create mode 100644 core/include/drivers/stm32_iwdg.h + create mode 100644 core/include/drivers/stm32_rng.h + create mode 100644 core/include/drivers/stm32_rtc.h + create mode 100644 core/include/drivers/stm32_timer.h + create mode 100644 core/include/drivers/stpmic1.h + create mode 100644 core/include/dt-bindings/clock/stm32mp1-clks.h + create mode 100644 core/include/dt-bindings/clock/stm32mp1-clksrc.h + create mode 100644 core/include/dt-bindings/etzpc/stm32-etzpc.h + create mode 100644 core/include/dt-bindings/interrupt-controller/arm-gic.h + create mode 100644 core/include/dt-bindings/pinctrl/stm32-pinfunc.h + create mode 100644 core/include/dt-bindings/power/stm32mp1-power.h + create mode 100644 core/include/dt-bindings/reset/stm32mp1-resets.h + create mode 100644 core/secure_dt.mk + create mode 100755 scripts/bin_to_c.py + +diff --git a/core/arch/arm/fdts/stm32mp15-ddr.dtsi b/core/arch/arm/fdts/stm32mp15-ddr.dtsi +new file mode 100644 +index 0000000..1a5c51c +--- /dev/null ++++ b/core/arch/arm/fdts/stm32mp15-ddr.dtsi +@@ -0,0 +1,153 @@ ++// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause ++/* ++ * Copyright (C) 2018, STMicroelectronics - All Rights Reserved ++ */ ++ ++/ { ++ soc { ++ ddr: ddr@5A003000{ ++ ++ compatible = "st,stm32mp1-ddr"; ++ ++ reg = <0x5A003000 0x550 ++ 0x5A004000 0x234>; ++ ++ clocks = <&rcc AXIDCG>, ++ <&rcc DDRC1>, ++ <&rcc DDRC2>, ++ <&rcc DDRPHYC>, ++ <&rcc DDRCAPB>, ++ <&rcc DDRPHYCAPB>; ++ ++ clock-names = "axidcg", ++ "ddrc1", ++ "ddrc2", ++ "ddrphyc", ++ "ddrcapb", ++ "ddrphycapb"; ++ ++ st,mem-name = DDR_MEM_NAME; ++ st,mem-speed = ; ++ st,mem-size = ; ++ ++ st,ctl-reg = < ++ DDR_MSTR ++ DDR_MRCTRL0 ++ DDR_MRCTRL1 ++ DDR_DERATEEN ++ DDR_DERATEINT ++ DDR_PWRCTL ++ DDR_PWRTMG ++ DDR_HWLPCTL ++ DDR_RFSHCTL0 ++ DDR_RFSHCTL3 ++ DDR_CRCPARCTL0 ++ DDR_ZQCTL0 ++ DDR_DFITMG0 ++ DDR_DFITMG1 ++ DDR_DFILPCFG0 ++ DDR_DFIUPD0 ++ DDR_DFIUPD1 ++ DDR_DFIUPD2 ++ DDR_DFIPHYMSTR ++ DDR_ODTMAP ++ DDR_DBG0 ++ DDR_DBG1 ++ DDR_DBGCMD ++ DDR_POISONCFG ++ DDR_PCCFG ++ >; ++ ++ st,ctl-timing = < ++ DDR_RFSHTMG ++ DDR_DRAMTMG0 ++ DDR_DRAMTMG1 ++ DDR_DRAMTMG2 ++ DDR_DRAMTMG3 ++ DDR_DRAMTMG4 ++ DDR_DRAMTMG5 ++ DDR_DRAMTMG6 ++ DDR_DRAMTMG7 ++ DDR_DRAMTMG8 ++ DDR_DRAMTMG14 ++ DDR_ODTCFG ++ >; ++ ++ st,ctl-map = < ++ DDR_ADDRMAP1 ++ DDR_ADDRMAP2 ++ DDR_ADDRMAP3 ++ DDR_ADDRMAP4 ++ DDR_ADDRMAP5 ++ DDR_ADDRMAP6 ++ DDR_ADDRMAP9 ++ DDR_ADDRMAP10 ++ DDR_ADDRMAP11 ++ >; ++ ++ st,ctl-perf = < ++ DDR_SCHED ++ DDR_SCHED1 ++ DDR_PERFHPR1 ++ DDR_PERFLPR1 ++ DDR_PERFWR1 ++ DDR_PCFGR_0 ++ DDR_PCFGW_0 ++ DDR_PCFGQOS0_0 ++ DDR_PCFGQOS1_0 ++ DDR_PCFGWQOS0_0 ++ DDR_PCFGWQOS1_0 ++ DDR_PCFGR_1 ++ DDR_PCFGW_1 ++ DDR_PCFGQOS0_1 ++ DDR_PCFGQOS1_1 ++ DDR_PCFGWQOS0_1 ++ DDR_PCFGWQOS1_1 ++ >; ++ ++ st,phy-reg = < ++ DDR_PGCR ++ DDR_ACIOCR ++ DDR_DXCCR ++ DDR_DSGCR ++ DDR_DCR ++ DDR_ODTCR ++ DDR_ZQ0CR1 ++ DDR_DX0GCR ++ DDR_DX1GCR ++ DDR_DX2GCR ++ DDR_DX3GCR ++ >; ++ ++ st,phy-timing = < ++ DDR_PTR0 ++ DDR_PTR1 ++ DDR_PTR2 ++ DDR_DTPR0 ++ DDR_DTPR1 ++ DDR_DTPR2 ++ DDR_MR0 ++ DDR_MR1 ++ DDR_MR2 ++ DDR_MR3 ++ >; ++ ++ st,phy-cal = < ++ DDR_DX0DLLCR ++ DDR_DX0DQTR ++ DDR_DX0DQSTR ++ DDR_DX1DLLCR ++ DDR_DX1DQTR ++ DDR_DX1DQSTR ++ DDR_DX2DLLCR ++ DDR_DX2DQTR ++ DDR_DX2DQSTR ++ DDR_DX3DLLCR ++ DDR_DX3DQTR ++ DDR_DX3DQSTR ++ >; ++ ++ status = "okay"; ++ }; ++ }; ++}; +diff --git a/core/arch/arm/fdts/stm32mp15-ddr3-1x4Gb-1066-binG.dtsi b/core/arch/arm/fdts/stm32mp15-ddr3-1x4Gb-1066-binG.dtsi +new file mode 100644 +index 0000000..16b8cf6 +--- /dev/null ++++ b/core/arch/arm/fdts/stm32mp15-ddr3-1x4Gb-1066-binG.dtsi +@@ -0,0 +1,121 @@ ++// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause ++/* ++ * Copyright (C) 2018, STMicroelectronics - All Rights Reserved ++ */ ++/* STM32MP157C DK1/DK2 BOARD configuration ++ * 1x DDR3L 4Gb, 16-bit, 533MHz. ++ * Reference used NT5CC256M16DP-DI from NANYA ++ * ++ * DDR type / Platform DDR3/3L ++ * freq 533MHz ++ * width 16 ++ * datasheet 0 = MT41J256M16-187 / DDR3-1066 bin G ++ * DDR density 4 ++ * timing mode optimized ++ * Scheduling/QoS options : type = 2 ++ * address mapping : RBC ++ * Tc > + 85C : N ++ */ ++ ++#define DDR_MEM_NAME "DDR3-1066/888 bin G 1x4Gb 533MHz v1.41" ++#define DDR_MEM_SPEED 533000 ++#define DDR_MEM_SIZE 0x20000000 ++ ++#define DDR_MSTR 0x00041401 ++#define DDR_MRCTRL0 0x00000010 ++#define DDR_MRCTRL1 0x00000000 ++#define DDR_DERATEEN 0x00000000 ++#define DDR_DERATEINT 0x00800000 ++#define DDR_PWRCTL 0x00000000 ++#define DDR_PWRTMG 0x00400010 ++#define DDR_HWLPCTL 0x00000000 ++#define DDR_RFSHCTL0 0x00210000 ++#define DDR_RFSHCTL3 0x00000000 ++#define DDR_RFSHTMG 0x0081008B ++#define DDR_CRCPARCTL0 0x00000000 ++#define DDR_DRAMTMG0 0x121B2414 ++#define DDR_DRAMTMG1 0x000A041C ++#define DDR_DRAMTMG2 0x0608090F ++#define DDR_DRAMTMG3 0x0050400C ++#define DDR_DRAMTMG4 0x08040608 ++#define DDR_DRAMTMG5 0x06060403 ++#define DDR_DRAMTMG6 0x02020002 ++#define DDR_DRAMTMG7 0x00000202 ++#define DDR_DRAMTMG8 0x00001005 ++#define DDR_DRAMTMG14 0x000000A0 ++#define DDR_ZQCTL0 0xC2000040 ++#define DDR_DFITMG0 0x02060105 ++#define DDR_DFITMG1 0x00000202 ++#define DDR_DFILPCFG0 0x07000000 ++#define DDR_DFIUPD0 0xC0400003 ++#define DDR_DFIUPD1 0x00000000 ++#define DDR_DFIUPD2 0x00000000 ++#define DDR_DFIPHYMSTR 0x00000000 ++#define DDR_ADDRMAP1 0x00070707 ++#define DDR_ADDRMAP2 0x00000000 ++#define DDR_ADDRMAP3 0x1F000000 ++#define DDR_ADDRMAP4 0x00001F1F ++#define DDR_ADDRMAP5 0x06060606 ++#define DDR_ADDRMAP6 0x0F060606 ++#define DDR_ADDRMAP9 0x00000000 ++#define DDR_ADDRMAP10 0x00000000 ++#define DDR_ADDRMAP11 0x00000000 ++#define DDR_ODTCFG 0x06000600 ++#define DDR_ODTMAP 0x00000001 ++#define DDR_SCHED 0x00000C01 ++#define DDR_SCHED1 0x00000000 ++#define DDR_PERFHPR1 0x01000001 ++#define DDR_PERFLPR1 0x08000200 ++#define DDR_PERFWR1 0x08000400 ++#define DDR_DBG0 0x00000000 ++#define DDR_DBG1 0x00000000 ++#define DDR_DBGCMD 0x00000000 ++#define DDR_POISONCFG 0x00000000 ++#define DDR_PCCFG 0x00000010 ++#define DDR_PCFGR_0 0x00010000 ++#define DDR_PCFGW_0 0x00000000 ++#define DDR_PCFGQOS0_0 0x02100C03 ++#define DDR_PCFGQOS1_0 0x00800100 ++#define DDR_PCFGWQOS0_0 0x01100C03 ++#define DDR_PCFGWQOS1_0 0x01000200 ++#define DDR_PCFGR_1 0x00010000 ++#define DDR_PCFGW_1 0x00000000 ++#define DDR_PCFGQOS0_1 0x02100C03 ++#define DDR_PCFGQOS1_1 0x00800040 ++#define DDR_PCFGWQOS0_1 0x01100C03 ++#define DDR_PCFGWQOS1_1 0x01000200 ++#define DDR_PGCR 0x01442E02 ++#define DDR_PTR0 0x0022AA5B ++#define DDR_PTR1 0x04841104 ++#define DDR_PTR2 0x042DA068 ++#define DDR_ACIOCR 0x10400812 ++#define DDR_DXCCR 0x00000C40 ++#define DDR_DSGCR 0xF200001F ++#define DDR_DCR 0x0000000B ++#define DDR_DTPR0 0x38D488D0 ++#define DDR_DTPR1 0x098B00D8 ++#define DDR_DTPR2 0x10023600 ++#define DDR_MR0 0x00000840 ++#define DDR_MR1 0x00000000 ++#define DDR_MR2 0x00000208 ++#define DDR_MR3 0x00000000 ++#define DDR_ODTCR 0x00010000 ++#define DDR_ZQ0CR1 0x00000038 ++#define DDR_DX0GCR 0x0000CE81 ++#define DDR_DX0DLLCR 0x40000000 ++#define DDR_DX0DQTR 0xFFFFFFFF ++#define DDR_DX0DQSTR 0x3DB02000 ++#define DDR_DX1GCR 0x0000CE81 ++#define DDR_DX1DLLCR 0x40000000 ++#define DDR_DX1DQTR 0xFFFFFFFF ++#define DDR_DX1DQSTR 0x3DB02000 ++#define DDR_DX2GCR 0x0000CE81 ++#define DDR_DX2DLLCR 0x40000000 ++#define DDR_DX2DQTR 0xFFFFFFFF ++#define DDR_DX2DQSTR 0x3DB02000 ++#define DDR_DX3GCR 0x0000CE81 ++#define DDR_DX3DLLCR 0x40000000 ++#define DDR_DX3DQTR 0xFFFFFFFF ++#define DDR_DX3DQSTR 0x3DB02000 ++ ++#include "stm32mp15-ddr.dtsi" +diff --git a/core/arch/arm/fdts/stm32mp15-ddr3-2x4Gb-1066-binG.dtsi b/core/arch/arm/fdts/stm32mp15-ddr3-2x4Gb-1066-binG.dtsi +new file mode 100644 +index 0000000..82e7104 +--- /dev/null ++++ b/core/arch/arm/fdts/stm32mp15-ddr3-2x4Gb-1066-binG.dtsi +@@ -0,0 +1,122 @@ ++// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause ++/* ++ * Copyright (C) 2018, STMicroelectronics - All Rights Reserved ++ */ ++ ++/* STM32MP157C ED1 BOARD configuration ++ * 2x DDR3L 4Gb each, 16-bit, 533MHz, Single Die Package in flyby topology. ++ * Reference used NT5CC256M16DP-DI from NANYA ++ * ++ * DDR type / Platform DDR3/3L ++ * freq 533MHz ++ * width 32 ++ * datasheet 0 = MT41J256M16-187 / DDR3-1066 bin G ++ * DDR density 8 ++ * timing mode optimized ++ * Scheduling/QoS options : type = 2 ++ * address mapping : RBC ++ * Tc > + 85C : N ++ */ ++ ++#define DDR_MEM_NAME "DDR3-1066/888 bin G 2x4Gb 533MHz v1.41" ++#define DDR_MEM_SPEED 533000 ++#define DDR_MEM_SIZE 0x40000000 ++ ++#define DDR_MSTR 0x00040401 ++#define DDR_MRCTRL0 0x00000010 ++#define DDR_MRCTRL1 0x00000000 ++#define DDR_DERATEEN 0x00000000 ++#define DDR_DERATEINT 0x00800000 ++#define DDR_PWRCTL 0x00000000 ++#define DDR_PWRTMG 0x00400010 ++#define DDR_HWLPCTL 0x00000000 ++#define DDR_RFSHCTL0 0x00210000 ++#define DDR_RFSHCTL3 0x00000000 ++#define DDR_RFSHTMG 0x0081008B ++#define DDR_CRCPARCTL0 0x00000000 ++#define DDR_DRAMTMG0 0x121B2414 ++#define DDR_DRAMTMG1 0x000A041C ++#define DDR_DRAMTMG2 0x0608090F ++#define DDR_DRAMTMG3 0x0050400C ++#define DDR_DRAMTMG4 0x08040608 ++#define DDR_DRAMTMG5 0x06060403 ++#define DDR_DRAMTMG6 0x02020002 ++#define DDR_DRAMTMG7 0x00000202 ++#define DDR_DRAMTMG8 0x00001005 ++#define DDR_DRAMTMG14 0x000000A0 ++#define DDR_ZQCTL0 0xC2000040 ++#define DDR_DFITMG0 0x02060105 ++#define DDR_DFITMG1 0x00000202 ++#define DDR_DFILPCFG0 0x07000000 ++#define DDR_DFIUPD0 0xC0400003 ++#define DDR_DFIUPD1 0x00000000 ++#define DDR_DFIUPD2 0x00000000 ++#define DDR_DFIPHYMSTR 0x00000000 ++#define DDR_ADDRMAP1 0x00080808 ++#define DDR_ADDRMAP2 0x00000000 ++#define DDR_ADDRMAP3 0x00000000 ++#define DDR_ADDRMAP4 0x00001F1F ++#define DDR_ADDRMAP5 0x07070707 ++#define DDR_ADDRMAP6 0x0F070707 ++#define DDR_ADDRMAP9 0x00000000 ++#define DDR_ADDRMAP10 0x00000000 ++#define DDR_ADDRMAP11 0x00000000 ++#define DDR_ODTCFG 0x06000600 ++#define DDR_ODTMAP 0x00000001 ++#define DDR_SCHED 0x00000C01 ++#define DDR_SCHED1 0x00000000 ++#define DDR_PERFHPR1 0x01000001 ++#define DDR_PERFLPR1 0x08000200 ++#define DDR_PERFWR1 0x08000400 ++#define DDR_DBG0 0x00000000 ++#define DDR_DBG1 0x00000000 ++#define DDR_DBGCMD 0x00000000 ++#define DDR_POISONCFG 0x00000000 ++#define DDR_PCCFG 0x00000010 ++#define DDR_PCFGR_0 0x00010000 ++#define DDR_PCFGW_0 0x00000000 ++#define DDR_PCFGQOS0_0 0x02100C03 ++#define DDR_PCFGQOS1_0 0x00800100 ++#define DDR_PCFGWQOS0_0 0x01100C03 ++#define DDR_PCFGWQOS1_0 0x01000200 ++#define DDR_PCFGR_1 0x00010000 ++#define DDR_PCFGW_1 0x00000000 ++#define DDR_PCFGQOS0_1 0x02100C03 ++#define DDR_PCFGQOS1_1 0x00800040 ++#define DDR_PCFGWQOS0_1 0x01100C03 ++#define DDR_PCFGWQOS1_1 0x01000200 ++#define DDR_PGCR 0x01442E02 ++#define DDR_PTR0 0x0022AA5B ++#define DDR_PTR1 0x04841104 ++#define DDR_PTR2 0x042DA068 ++#define DDR_ACIOCR 0x10400812 ++#define DDR_DXCCR 0x00000C40 ++#define DDR_DSGCR 0xF200001F ++#define DDR_DCR 0x0000000B ++#define DDR_DTPR0 0x38D488D0 ++#define DDR_DTPR1 0x098B00D8 ++#define DDR_DTPR2 0x10023600 ++#define DDR_MR0 0x00000840 ++#define DDR_MR1 0x00000000 ++#define DDR_MR2 0x00000208 ++#define DDR_MR3 0x00000000 ++#define DDR_ODTCR 0x00010000 ++#define DDR_ZQ0CR1 0x00000038 ++#define DDR_DX0GCR 0x0000CE81 ++#define DDR_DX0DLLCR 0x40000000 ++#define DDR_DX0DQTR 0xFFFFFFFF ++#define DDR_DX0DQSTR 0x3DB02000 ++#define DDR_DX1GCR 0x0000CE81 ++#define DDR_DX1DLLCR 0x40000000 ++#define DDR_DX1DQTR 0xFFFFFFFF ++#define DDR_DX1DQSTR 0x3DB02000 ++#define DDR_DX2GCR 0x0000CE81 ++#define DDR_DX2DLLCR 0x40000000 ++#define DDR_DX2DQTR 0xFFFFFFFF ++#define DDR_DX2DQSTR 0x3DB02000 ++#define DDR_DX3GCR 0x0000CE81 ++#define DDR_DX3DLLCR 0x40000000 ++#define DDR_DX3DQTR 0xFFFFFFFF ++#define DDR_DX3DQSTR 0x3DB02000 ++ ++#include "stm32mp15-ddr.dtsi" +diff --git a/core/arch/arm/fdts/stm32mp157-pinctrl.dtsi b/core/arch/arm/fdts/stm32mp157-pinctrl.dtsi +new file mode 100644 +index 0000000..8037e4f +--- /dev/null ++++ b/core/arch/arm/fdts/stm32mp157-pinctrl.dtsi +@@ -0,0 +1,350 @@ ++// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) ++/* ++ * Copyright (C) STMicroelectronics 2017 - All Rights Reserved ++ * Author: Ludovic Barre for STMicroelectronics. ++ */ ++#include ++ ++/ { ++ soc { ++ pinctrl: pin-controller@50002000 { ++ #address-cells = <1>; ++ #size-cells = <1>; ++ compatible = "st,stm32mp157-pinctrl"; ++ ranges = <0 0x50002000 0xa400>; ++ pins-are-numbered; ++ ++ gpioa: gpio@50002000 { ++ gpio-controller; ++ #gpio-cells = <2>; ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ reg = <0x0 0x400>; ++ clocks = <&rcc GPIOA>; ++ st,bank-name = "GPIOA"; ++ status = "disabled"; ++ }; ++ ++ gpiob: gpio@50003000 { ++ gpio-controller; ++ #gpio-cells = <2>; ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ reg = <0x1000 0x400>; ++ clocks = <&rcc GPIOB>; ++ st,bank-name = "GPIOB"; ++ status = "disabled"; ++ }; ++ ++ gpioc: gpio@50004000 { ++ gpio-controller; ++ #gpio-cells = <2>; ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ reg = <0x2000 0x400>; ++ clocks = <&rcc GPIOC>; ++ st,bank-name = "GPIOC"; ++ status = "disabled"; ++ }; ++ ++ gpiod: gpio@50005000 { ++ gpio-controller; ++ #gpio-cells = <2>; ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ reg = <0x3000 0x400>; ++ clocks = <&rcc GPIOD>; ++ st,bank-name = "GPIOD"; ++ status = "disabled"; ++ }; ++ ++ gpioe: gpio@50006000 { ++ gpio-controller; ++ #gpio-cells = <2>; ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ reg = <0x4000 0x400>; ++ clocks = <&rcc GPIOE>; ++ st,bank-name = "GPIOE"; ++ status = "disabled"; ++ }; ++ ++ gpiof: gpio@50007000 { ++ gpio-controller; ++ #gpio-cells = <2>; ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ reg = <0x5000 0x400>; ++ clocks = <&rcc GPIOF>; ++ st,bank-name = "GPIOF"; ++ status = "disabled"; ++ }; ++ ++ gpiog: gpio@50008000 { ++ gpio-controller; ++ #gpio-cells = <2>; ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ reg = <0x6000 0x400>; ++ clocks = <&rcc GPIOG>; ++ st,bank-name = "GPIOG"; ++ status = "disabled"; ++ }; ++ ++ gpioh: gpio@50009000 { ++ gpio-controller; ++ #gpio-cells = <2>; ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ reg = <0x7000 0x400>; ++ clocks = <&rcc GPIOH>; ++ st,bank-name = "GPIOH"; ++ status = "disabled"; ++ }; ++ ++ gpioi: gpio@5000a000 { ++ gpio-controller; ++ #gpio-cells = <2>; ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ reg = <0x8000 0x400>; ++ clocks = <&rcc GPIOI>; ++ st,bank-name = "GPIOI"; ++ status = "disabled"; ++ }; ++ ++ gpioj: gpio@5000b000 { ++ gpio-controller; ++ #gpio-cells = <2>; ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ reg = <0x9000 0x400>; ++ clocks = <&rcc GPIOJ>; ++ st,bank-name = "GPIOJ"; ++ status = "disabled"; ++ }; ++ ++ gpiok: gpio@5000c000 { ++ gpio-controller; ++ #gpio-cells = <2>; ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ reg = <0xa000 0x400>; ++ clocks = <&rcc GPIOK>; ++ st,bank-name = "GPIOK"; ++ status = "disabled"; ++ }; ++ ++ qspi_bk1_pins_a: qspi-bk1-0 { ++ pins1 { ++ pinmux = , /* QSPI_BK1_IO0 */ ++ , /* QSPI_BK1_IO1 */ ++ , /* QSPI_BK1_IO2 */ ++ ; /* QSPI_BK1_IO3 */ ++ bias-disable; ++ drive-push-pull; ++ slew-rate = <1>; ++ }; ++ pins2 { ++ pinmux = ; /* QSPI_BK1_NCS */ ++ bias-pull-up; ++ drive-push-pull; ++ slew-rate = <1>; ++ }; ++ }; ++ ++ qspi_bk2_pins_a: qspi-bk2-0 { ++ pins1 { ++ pinmux = , /* QSPI_BK2_IO0 */ ++ , /* QSPI_BK2_IO1 */ ++ , /* QSPI_BK2_IO2 */ ++ ; /* QSPI_BK2_IO3 */ ++ bias-disable; ++ drive-push-pull; ++ slew-rate = <1>; ++ }; ++ pins2 { ++ pinmux = ; /* QSPI_BK2_NCS */ ++ bias-pull-up; ++ drive-push-pull; ++ slew-rate = <1>; ++ }; ++ }; ++ ++ qspi_clk_pins_a: qspi-clk-0 { ++ pins { ++ pinmux = ; /* QSPI_CLK */ ++ bias-disable; ++ drive-push-pull; ++ slew-rate = <3>; ++ }; ++ }; ++ ++ sdmmc1_b4_pins_a: sdmmc1-b4-0 { ++ pins1 { ++ pinmux = , /* SDMMC1_D0 */ ++ , /* SDMMC1_D1 */ ++ , /* SDMMC1_D2 */ ++ , /* SDMMC1_D3 */ ++ ; /* SDMMC1_CMD */ ++ slew-rate = <1>; ++ drive-push-pull; ++ bias-disable; ++ }; ++ pins2 { ++ pinmux = ; /* SDMMC1_CK */ ++ slew-rate = <2>; ++ drive-push-pull; ++ bias-disable; ++ }; ++ }; ++ ++ sdmmc1_dir_pins_a: sdmmc1-dir-0 { ++ pins1 { ++ pinmux = , /* SDMMC1_D0DIR */ ++ , /* SDMMC1_D123DIR */ ++ ; /* SDMMC1_CDIR */ ++ slew-rate = <1>; ++ drive-push-pull; ++ bias-pull-up; ++ }; ++ pins2{ ++ pinmux = ; /* SDMMC1_CKIN */ ++ bias-pull-up; ++ }; ++ }; ++ ++ sdmmc1_dir_pins_b: sdmmc1-dir-1 { ++ pins1 { ++ pinmux = , /* SDMMC1_D0DIR */ ++ , /* SDMMC1_D123DIR */ ++ ; /* SDMMC1_CDIR */ ++ slew-rate = <3>; ++ drive-push-pull; ++ bias-pull-up; ++ }; ++ pins2 { ++ pinmux = ; /* SDMMC1_CKIN */ ++ bias-pull-up; ++ }; ++ }; ++ ++ sdmmc2_b4_pins_a: sdmmc2-b4-0 { ++ pins1 { ++ pinmux = , /* SDMMC2_D0 */ ++ , /* SDMMC2_D1 */ ++ , /* SDMMC2_D2 */ ++ , /* SDMMC2_D3 */ ++ ; /* SDMMC2_CMD */ ++ slew-rate = <1>; ++ drive-push-pull; ++ bias-pull-up; ++ }; ++ pins2 { ++ pinmux = ; /* SDMMC2_CK */ ++ slew-rate = <2>; ++ drive-push-pull; ++ bias-pull-up; ++ }; ++ }; ++ ++ sdmmc2_d47_pins_a: sdmmc2-d47-0 { ++ pins { ++ pinmux = , /* SDMMC2_D4 */ ++ , /* SDMMC2_D5 */ ++ , /* SDMMC2_D6 */ ++ ; /* SDMMC2_D7 */ ++ slew-rate = <1>; ++ drive-push-pull; ++ bias-pull-up; ++ }; ++ }; ++ ++ uart4_pins_a: uart4-0 { ++ pins1 { ++ pinmux = ; /* UART4_TX */ ++ bias-disable; ++ drive-push-pull; ++ slew-rate = <0>; ++ }; ++ pins2 { ++ pinmux = ; /* UART4_RX */ ++ bias-disable; ++ }; ++ }; ++ ++ uart7_pins_a: uart7-0 { ++ pins1 { ++ pinmux = ; /* USART7_TX */ ++ bias-disable; ++ drive-push-pull; ++ slew-rate = <0>; ++ }; ++ pins2 { ++ pinmux = ; /* USART7_RX */ ++ bias-disable; ++ }; ++ }; ++ ++ usart3_pins_a: usart3-0 { ++ pins1 { ++ pinmux = , /* USART3_TX */ ++ ; /* USART3_RTS */ ++ bias-disable; ++ drive-push-pull; ++ slew-rate = <0>; ++ }; ++ pins2 { ++ pinmux = , /* USART3_RX */ ++ ; /* USART3_CTS_NSS */ ++ bias-disable; ++ }; ++ }; ++ ++ usart3_pins_b: usart3-1 { ++ pins1 { ++ pinmux = , /* USART3_TX */ ++ ; /* USART3_RTS */ ++ bias-disable; ++ drive-push-pull; ++ slew-rate = <0>; ++ }; ++ pins2 { ++ pinmux = , /* USART3_RX */ ++ ; /* USART3_CTS_NSS */ ++ bias-disable; ++ }; ++ }; ++ }; ++ ++ pinctrl_z: pin-controller-z@54004000 { ++ #address-cells = <1>; ++ #size-cells = <1>; ++ compatible = "st,stm32mp157-z-pinctrl"; ++ ranges = <0 0x54004000 0x400>; ++ pins-are-numbered; ++ ++ gpioz: gpio@54004000 { ++ gpio-controller; ++ #gpio-cells = <2>; ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ reg = <0 0x400>; ++ clocks = <&rcc GPIOZ>; ++ st,bank-name = "GPIOZ"; ++ st,bank-ioport = <11>; ++ status = "disabled"; ++ }; ++ ++ i2c4_pins_a: i2c4-0 { ++ pins { ++ pinmux = , /* I2C4_SCL */ ++ ; /* I2C4_SDA */ ++ bias-disable; ++ drive-open-drain; ++ slew-rate = <0>; ++ }; ++ }; ++ }; ++ }; ++}; +diff --git a/core/arch/arm/fdts/stm32mp157a-dk1.dts b/core/arch/arm/fdts/stm32mp157a-dk1.dts +new file mode 100644 +index 0000000..e42bdcd +--- /dev/null ++++ b/core/arch/arm/fdts/stm32mp157a-dk1.dts +@@ -0,0 +1,380 @@ ++// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) ++/* ++ * Copyright (C) STMicroelectronics 2018-2019 - All Rights Reserved ++ * Author: Alexandre Torgue . ++ */ ++ ++/dts-v1/; ++ ++#include "stm32mp157c.dtsi" ++#include "stm32mp157cac-pinctrl.dtsi" ++ ++/ { ++ model = "STMicroelectronics STM32MP157A-DK1 Discovery Board"; ++ compatible = "st,stm32mp157a-dk1", "st,stm32mp157"; ++ ++ aliases { ++ serial0 = &uart4; ++ serial1 = &usart3; ++ serial2 = &uart7; ++ }; ++ ++ chosen { ++ stdout-path = "serial0:115200n8"; ++}; ++ ++}; ++ ++&clk_hse { ++ st,digbypass; ++}; ++ ++&i2c4 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&i2c4_pins_a>; ++ i2c-scl-rising-time-ns = <185>; ++ i2c-scl-falling-time-ns = <20>; ++ status = "okay"; ++ ++ pmic: stpmic@33 { ++ compatible = "st,stpmic1"; ++ reg = <0x33>; ++ interrupts-extended = <&exti_pwr 55 IRQ_TYPE_EDGE_FALLING>; ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ status = "okay"; ++ ++ st,main-control-register = <0x04>; ++ st,vin-control-register = <0xc0>; ++ st,usb-control-register = <0x20>; ++ ++ regulators { ++ compatible = "st,stpmic1-regulators"; ++ ++ ldo1-supply = <&v3v3>; ++ ldo3-supply = <&vdd_ddr>; ++ ldo6-supply = <&v3v3>; ++ ++ vddcore: buck1 { ++ regulator-name = "vddcore"; ++ regulator-min-microvolt = <1200000>; ++ regulator-max-microvolt = <1350000>; ++ regulator-always-on; ++ regulator-initial-mode = <0>; ++ regulator-over-current-protection; ++ }; ++ ++ vdd_ddr: buck2 { ++ regulator-name = "vdd_ddr"; ++ regulator-min-microvolt = <1350000>; ++ regulator-max-microvolt = <1350000>; ++ regulator-always-on; ++ regulator-initial-mode = <0>; ++ regulator-over-current-protection; ++ }; ++ ++ vdd: buck3 { ++ regulator-name = "vdd"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ regulator-always-on; ++ st,mask-reset; ++ regulator-initial-mode = <0>; ++ regulator-over-current-protection; ++ }; ++ ++ v3v3: buck4 { ++ regulator-name = "v3v3"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ regulator-always-on; ++ regulator-over-current-protection; ++ regulator-initial-mode = <0>; ++ }; ++ ++ v1v8_audio: ldo1 { ++ regulator-name = "v1v8_audio"; ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <1800000>; ++ regulator-always-on; ++ }; ++ ++ v3v3_hdmi: ldo2 { ++ regulator-name = "v3v3_hdmi"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ regulator-always-on; ++ }; ++ ++ vtt_ddr: ldo3 { ++ regulator-name = "vtt_ddr"; ++ regulator-min-microvolt = <500000>; ++ regulator-max-microvolt = <750000>; ++ regulator-always-on; ++ regulator-over-current-protection; ++ }; ++ ++ vdd_usb: ldo4 { ++ regulator-name = "vdd_usb"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ }; ++ ++ vdda: ldo5 { ++ regulator-name = "vdda"; ++ regulator-min-microvolt = <2900000>; ++ regulator-max-microvolt = <2900000>; ++ regulator-boot-on; ++ }; ++ ++ v1v2_hdmi: ldo6 { ++ regulator-name = "v1v2_hdmi"; ++ regulator-min-microvolt = <1200000>; ++ regulator-max-microvolt = <1200000>; ++ regulator-always-on; ++ }; ++ ++ vref_ddr: vref_ddr { ++ regulator-name = "vref_ddr"; ++ regulator-always-on; ++ regulator-over-current-protection; ++ }; ++ }; ++ }; ++}; ++ ++&iwdg2 { ++ timeout-sec = <32>; ++ status = "okay"; ++}; ++ ++&pwr { ++ pwr-supply = <&vdd>; ++}; ++ ++/* RNG1 is used by non secure at run time and by secure (low power sequences) */ ++&rng1 { ++ status = "okay"; ++ secure-status = "okay"; ++}; ++ ++&rtc { ++ status = "okay"; ++}; ++ ++&sdmmc1 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&sdmmc1_b4_pins_a>; ++ broken-cd; ++ st,neg-edge; ++ bus-width = <4>; ++ vmmc-supply = <&v3v3>; ++ status = "okay"; ++}; ++ ++&uart4 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&uart4_pins_a>; ++ status = "okay"; ++}; ++ ++&uart7 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&uart7_pins_a>; ++ status = "disabled"; ++}; ++ ++&usart3 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&usart3_pins_b>; ++ status = "disabled"; ++}; ++ ++ ++/* ATF Specific */ ++#include ++#include ++#include "stm32mp15-ddr3-1x4Gb-1066-binG.dtsi" ++#include "stm32mp157c-security.dtsi" ++ ++/ { ++ aliases { ++ gpio0 = &gpioa; ++ gpio1 = &gpiob; ++ gpio2 = &gpioc; ++ gpio3 = &gpiod; ++ gpio4 = &gpioe; ++ gpio5 = &gpiof; ++ gpio6 = &gpiog; ++ gpio7 = &gpioh; ++ gpio8 = &gpioi; ++ gpio25 = &gpioz; ++ i2c3 = &i2c4; ++ }; ++}; ++ ++/* CLOCK presence */ ++&rcc { ++ secure-status = "okay"; ++ st,hsi-cal; ++ st,csi-cal; ++ st,cal-sec = <60>; ++}; ++ ++/* Security specific */ ++&etzpc { ++ st,decprot = < ++ DECPROT(STM32MP1_ETZPC_USART1_ID, DECPROT_NS_RW, DECPROT_UNLOCK) ++ DECPROT(STM32MP1_ETZPC_SPI6_ID, DECPROT_NS_RW, DECPROT_UNLOCK) ++ DECPROT(STM32MP1_ETZPC_I2C4_ID, DECPROT_NS_RW, DECPROT_UNLOCK) ++ DECPROT(STM32MP1_ETZPC_I2C6_ID, DECPROT_NS_RW, DECPROT_UNLOCK) ++ DECPROT(STM32MP1_ETZPC_RNG1_ID, DECPROT_NS_RW, DECPROT_UNLOCK) ++ DECPROT(STM32MP1_ETZPC_HASH1_ID, DECPROT_NS_RW, DECPROT_UNLOCK) ++ DECPROT(STM32MP1_ETZPC_CRYP1_ID, DECPROT_NS_RW, DECPROT_UNLOCK) ++ >; ++}; ++ ++&iwdg2 { ++ secure-status = "okay"; ++}; ++ ++&pwr { ++ system_suspend_supported_soc_modes = < ++ STM32_PM_CSLEEP_RUN ++ STM32_PM_CSTOP_ALLOW_LP_STOP ++ STM32_PM_CSTOP_ALLOW_STANDBY_DDR_SR ++ >; ++ ++ system_off_soc_mode = ; ++}; ++ ++&timers15 { ++ secure-status = "okay"; ++ st,hsi-cal-input = <7>; ++ st,csi_cal-input = <8>; ++}; ++ ++/* Low-power states of regulators */ ++&vddcore { ++ lp-stop { ++ regulator-on-in-suspend; ++ regulator-suspend-microvolt = <1200000>; ++ }; ++ standby-ddr-sr { ++ regulator-off-in-suspend; ++ }; ++ standby-ddr-off { ++ regulator-off-in-suspend; ++ }; ++}; ++ ++&vdd_ddr { ++ lp-stop { ++ regulator-suspend-microvolt = <1350000>; ++ regulator-on-in-suspend; ++ }; ++ standby-ddr-sr { ++ regulator-suspend-microvolt = <1350000>; ++ regulator-on-in-suspend; ++ }; ++ standby-ddr-off { ++ regulator-off-in-suspend; ++ }; ++}; ++ ++&vdd { ++ lp-stop { ++ regulator-suspend-microvolt = <3300000>; ++ regulator-on-in-suspend; ++ }; ++ standby-ddr-sr { ++ regulator-suspend-microvolt = <3300000>; ++ regulator-on-in-suspend; ++ }; ++ standby-ddr-off { ++ regulator-suspend-microvolt = <3300000>; ++ regulator-on-in-suspend; ++ }; ++}; ++ ++&v3v3 { ++ lp-stop { ++ regulator-suspend-microvolt = <3300000>; ++ regulator-on-in-suspend; ++ }; ++ standby-ddr-sr { ++ regulator-off-in-suspend; ++ }; ++ standby-ddr-off { ++ regulator-off-in-suspend; ++ }; ++}; ++ ++&v1v8_audio { ++ standby-ddr-sr { ++ regulator-off-in-suspend; ++ }; ++ standby-ddr-off { ++ regulator-off-in-suspend; ++ }; ++}; ++ ++&v3v3_hdmi { ++ standby-ddr-sr { ++ regulator-off-in-suspend; ++ }; ++ standby-ddr-off { ++ regulator-off-in-suspend; ++ }; ++}; ++ ++&vtt_ddr { ++ lp-stop { ++ regulator-off-in-suspend; ++ }; ++ standby-ddr-sr { ++ regulator-off-in-suspend; ++ }; ++ standby-ddr-off { ++ regulator-off-in-suspend; ++ }; ++}; ++ ++&vdd_usb { ++ standby-ddr-sr { ++ regulator-off-in-suspend; ++ }; ++ standby-ddr-off { ++ regulator-off-in-suspend; ++ }; ++}; ++ ++&vdda { ++ standby-ddr-sr { ++ regulator-off-in-suspend; ++ }; ++ standby-ddr-off { ++ regulator-off-in-suspend; ++ }; ++}; ++ ++&v1v2_hdmi { ++ standby-ddr-sr { ++ regulator-off-in-suspend; ++ }; ++ standby-ddr-off { ++ regulator-off-in-suspend; ++ }; ++}; ++ ++&vref_ddr { ++ lp-stop { ++ regulator-on-in-suspend; ++ }; ++ standby-ddr-sr { ++ regulator-on-in-suspend; ++ }; ++ standby-ddr-off { ++ regulator-off-in-suspend; ++ }; ++}; +diff --git a/core/arch/arm/fdts/stm32mp157c-dk2.dts b/core/arch/arm/fdts/stm32mp157c-dk2.dts +new file mode 100644 +index 0000000..fdcf4c8 +--- /dev/null ++++ b/core/arch/arm/fdts/stm32mp157c-dk2.dts +@@ -0,0 +1,16 @@ ++// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) ++/* ++ * Copyright (C) STMicroelectronics 2018 - All Rights Reserved ++ * Author: Alexandre Torgue . ++ */ ++ ++/dts-v1/; ++ ++#include "stm32mp157a-dk1.dts" ++ ++/ { ++ model = "STMicroelectronics STM32MP157C-DK2 Discovery Board"; ++ compatible = "st,stm32mp157c-dk2", "st,stm32mp157"; ++ ++}; ++ +diff --git a/core/arch/arm/fdts/stm32mp157c-ed1.dts b/core/arch/arm/fdts/stm32mp157c-ed1.dts +new file mode 100644 +index 0000000..8462d23 +--- /dev/null ++++ b/core/arch/arm/fdts/stm32mp157c-ed1.dts +@@ -0,0 +1,381 @@ ++// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) ++/* ++ * Copyright (C) STMicroelectronics 2017-2019 - All Rights Reserved ++ * Author: Ludovic Barre for STMicroelectronics. ++ */ ++/dts-v1/; ++ ++#include "stm32mp157c.dtsi" ++#include "stm32mp157caa-pinctrl.dtsi" ++ ++/ { ++ model = "STMicroelectronics STM32MP157C eval daughter"; ++ compatible = "st,stm32mp157c-ed1", "st,stm32mp157"; ++ ++ chosen { ++ stdout-path = "serial0:115200n8"; ++ }; ++ ++ aliases { ++ serial0 = &uart4; ++ }; ++}; ++ ++&clk_hse { ++ st,digbypass; ++}; ++ ++&i2c4 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&i2c4_pins_a>; ++ i2c-scl-rising-time-ns = <185>; ++ i2c-scl-falling-time-ns = <20>; ++ status = "okay"; ++ ++ pmic: stpmic@33 { ++ compatible = "st,stpmic1"; ++ reg = <0x33>; ++ interrupts-extended = <&exti_pwr 55 IRQ_TYPE_EDGE_FALLING>; ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ status = "okay"; ++ ++ st,main-control-register = <0x04>; ++ st,vin-control-register = <0xc0>; ++ st,usb-control-register = <0x20>; ++ ++ regulators { ++ compatible = "st,stpmic1-regulators"; ++ ++ ldo1-supply = <&v3v3>; ++ ldo2-supply = <&v3v3>; ++ ldo3-supply = <&vdd_ddr>; ++ ldo5-supply = <&v3v3>; ++ ldo6-supply = <&v3v3>; ++ ++ vddcore: buck1 { ++ regulator-name = "vddcore"; ++ regulator-min-microvolt = <1200000>; ++ regulator-max-microvolt = <1350000>; ++ regulator-always-on; ++ regulator-initial-mode = <0>; ++ regulator-over-current-protection; ++ }; ++ ++ vdd_ddr: buck2 { ++ regulator-name = "vdd_ddr"; ++ regulator-min-microvolt = <1350000>; ++ regulator-max-microvolt = <1350000>; ++ regulator-always-on; ++ regulator-initial-mode = <0>; ++ regulator-over-current-protection; ++ }; ++ ++ vdd: buck3 { ++ regulator-name = "vdd"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ regulator-always-on; ++ st,mask-reset; ++ regulator-initial-mode = <0>; ++ regulator-over-current-protection; ++ }; ++ ++ v3v3: buck4 { ++ regulator-name = "v3v3"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ regulator-always-on; ++ regulator-over-current-protection; ++ regulator-initial-mode = <0>; ++ }; ++ ++ vdda: ldo1 { ++ regulator-name = "vdda"; ++ regulator-min-microvolt = <2900000>; ++ regulator-max-microvolt = <2900000>; ++ }; ++ ++ v2v8: ldo2 { ++ regulator-name = "v2v8"; ++ regulator-min-microvolt = <2800000>; ++ regulator-max-microvolt = <2800000>; ++ }; ++ ++ vtt_ddr: ldo3 { ++ regulator-name = "vtt_ddr"; ++ regulator-min-microvolt = <500000>; ++ regulator-max-microvolt = <750000>; ++ regulator-always-on; ++ regulator-over-current-protection; ++ }; ++ ++ vdd_usb: ldo4 { ++ regulator-name = "vdd_usb"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ }; ++ ++ vdd_sd: ldo5 { ++ regulator-name = "vdd_sd"; ++ regulator-min-microvolt = <2900000>; ++ regulator-max-microvolt = <2900000>; ++ regulator-boot-on; ++ }; ++ ++ v1v8: ldo6 { ++ regulator-name = "v1v8"; ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <1800000>; ++ }; ++ ++ vref_ddr: vref_ddr { ++ regulator-name = "vref_ddr"; ++ regulator-always-on; ++ regulator-over-current-protection; ++ }; ++ }; ++ }; ++}; ++ ++&iwdg2 { ++ timeout-sec = <32>; ++ status = "okay"; ++}; ++ ++&pwr { ++ pwr-supply = <&vdd>; ++}; ++ ++/* RNG1 is used by non secure at run time and by secure (low power sequences) */ ++&rng1 { ++ status = "okay"; ++ secure-status = "okay"; ++}; ++ ++&rtc { ++ status = "okay"; ++}; ++ ++&sdmmc1 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&sdmmc1_b4_pins_a &sdmmc1_dir_pins_a>; ++ broken-cd; ++ st,sig-dir; ++ st,neg-edge; ++ st,use-ckin; ++ bus-width = <4>; ++ vmmc-supply = <&vdd_sd>; ++ sd-uhs-sdr12; ++ sd-uhs-sdr25; ++ sd-uhs-sdr50; ++ sd-uhs-ddr50; ++ sd-uhs-sdr104; ++ status = "okay"; ++}; ++ ++&sdmmc2 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&sdmmc2_b4_pins_a &sdmmc2_d47_pins_a>; ++ non-removable; ++ no-sd; ++ no-sdio; ++ st,neg-edge; ++ bus-width = <8>; ++ vmmc-supply = <&v3v3>; ++ vqmmc-supply = <&v3v3>; ++ mmc-ddr-3_3v; ++ status = "okay"; ++}; ++ ++&uart4 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&uart4_pins_a>; ++ status = "okay"; ++}; ++ ++/* ATF Specific */ ++#include ++#include ++#include "stm32mp15-ddr3-2x4Gb-1066-binG.dtsi" ++#include "stm32mp157c-security.dtsi" ++ ++/ { ++ aliases { ++ gpio0 = &gpioa; ++ gpio1 = &gpiob; ++ gpio2 = &gpioc; ++ gpio3 = &gpiod; ++ gpio4 = &gpioe; ++ gpio5 = &gpiof; ++ gpio6 = &gpiog; ++ gpio7 = &gpioh; ++ gpio8 = &gpioi; ++ gpio9 = &gpioj; ++ gpio10 = &gpiok; ++ gpio25 = &gpioz; ++ i2c3 = &i2c4; ++ }; ++}; ++ ++/* CLOCK presence */ ++&rcc { ++ secure-status = "okay"; ++ st,hsi-cal; ++ st,csi-cal; ++ st,cal-sec = <60>; ++}; ++ ++/* Security specific */ ++&etzpc { ++ st,decprot = < ++ DECPROT(STM32MP1_ETZPC_USART1_ID, DECPROT_NS_RW, DECPROT_UNLOCK) ++ DECPROT(STM32MP1_ETZPC_SPI6_ID, DECPROT_NS_RW, DECPROT_UNLOCK) ++ DECPROT(STM32MP1_ETZPC_I2C4_ID, DECPROT_NS_RW, DECPROT_UNLOCK) ++ DECPROT(STM32MP1_ETZPC_I2C6_ID, DECPROT_NS_RW, DECPROT_UNLOCK) ++ DECPROT(STM32MP1_ETZPC_RNG1_ID, DECPROT_NS_RW, DECPROT_UNLOCK) ++ DECPROT(STM32MP1_ETZPC_HASH1_ID, DECPROT_NS_RW, DECPROT_UNLOCK) ++ DECPROT(STM32MP1_ETZPC_CRYP1_ID, DECPROT_NS_RW, DECPROT_UNLOCK) ++ >; ++}; ++ ++&iwdg2 { ++ secure-status = "okay"; ++}; ++ ++&pwr { ++ system_suspend_supported_soc_modes = < ++ STM32_PM_CSLEEP_RUN ++ STM32_PM_CSTOP_ALLOW_LP_STOP ++ STM32_PM_CSTOP_ALLOW_STANDBY_DDR_SR ++ >; ++ ++ system_off_soc_mode = ; ++}; ++ ++&timers15 { ++ secure-status = "okay"; ++ st,hsi-cal-input = <7>; ++ st,csi_cal-input = <8>; ++}; ++ ++/* Low-power states of regulators */ ++&vddcore { ++ lp-stop { ++ regulator-on-in-suspend; ++ regulator-suspend-microvolt = <1200000>; ++ }; ++ standby-ddr-sr { ++ regulator-off-in-suspend; ++ }; ++ standby-ddr-off { ++ regulator-off-in-suspend; ++ }; ++}; ++ ++&vdd_ddr { ++ lp-stop { ++ regulator-suspend-microvolt = <1350000>; ++ regulator-on-in-suspend; ++ }; ++ standby-ddr-sr { ++ regulator-suspend-microvolt = <1350000>; ++ regulator-on-in-suspend; ++ }; ++ standby-ddr-off { ++ regulator-off-in-suspend; ++ }; ++}; ++ ++&vdd { ++ lp-stop { ++ regulator-suspend-microvolt = <3300000>; ++ regulator-on-in-suspend; ++ }; ++ standby-ddr-sr { ++ regulator-suspend-microvolt = <3300000>; ++ regulator-on-in-suspend; ++ }; ++ standby-ddr-off { ++ regulator-suspend-microvolt = <3300000>; ++ regulator-on-in-suspend; ++ }; ++}; ++ ++&v3v3 { ++ standby-ddr-sr { ++ regulator-off-in-suspend; ++ }; ++ standby-ddr-off { ++ regulator-off-in-suspend; ++ }; ++}; ++ ++&vdda { ++ standby-ddr-sr { ++ regulator-off-in-suspend; ++ }; ++ standby-ddr-off { ++ regulator-off-in-suspend; ++ }; ++}; ++ ++&v2v8 { ++ standby-ddr-sr { ++ regulator-off-in-suspend; ++ }; ++ standby-ddr-off { ++ regulator-off-in-suspend; ++ }; ++}; ++ ++&vtt_ddr { ++ lp-stop { ++ regulator-off-in-suspend; ++ }; ++ standby-ddr-sr { ++ regulator-off-in-suspend; ++ }; ++ standby-ddr-off { ++ regulator-off-in-suspend; ++ }; ++}; ++ ++&vdd_usb { ++ standby-ddr-sr { ++ regulator-off-in-suspend; ++ }; ++ standby-ddr-off { ++ regulator-off-in-suspend; ++ }; ++}; ++ ++&vdd_sd { ++ standby-ddr-sr { ++ regulator-off-in-suspend; ++ }; ++ standby-ddr-off { ++ regulator-off-in-suspend; ++ }; ++}; ++ ++&v1v8 { ++ standby-ddr-sr { ++ regulator-off-in-suspend; ++ }; ++ standby-ddr-off { ++ regulator-off-in-suspend; ++ }; ++}; ++ ++&vref_ddr { ++ lp-stop { ++ regulator-on-in-suspend; ++ }; ++ standby-ddr-sr { ++ regulator-on-in-suspend; ++ }; ++ standby-ddr-off { ++ regulator-off-in-suspend; ++ }; ++}; +diff --git a/core/arch/arm/fdts/stm32mp157c-ev1.dts b/core/arch/arm/fdts/stm32mp157c-ev1.dts +new file mode 100644 +index 0000000..cfde8ed +--- /dev/null ++++ b/core/arch/arm/fdts/stm32mp157c-ev1.dts +@@ -0,0 +1,67 @@ ++// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) ++/* ++ * Copyright (C) STMicroelectronics 2017 - All Rights Reserved ++ * Author: Ludovic Barre for STMicroelectronics. ++ */ ++/dts-v1/; ++ ++#include "stm32mp157c-ed1.dts" ++ ++/ { ++ model = "STMicroelectronics STM32MP157C eval daughter on eval mother"; ++ compatible = "st,stm32mp157c-ev1", "st,stm32mp157c-ed1", "st,stm32mp157"; ++ ++ chosen { ++ stdout-path = "serial0:115200n8"; ++ }; ++ ++ aliases { ++ serial1 = &usart3; ++ }; ++}; ++ ++&fmc { ++ status = "okay"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ nand: nand@0 { ++ reg = <0>; ++ nand-on-flash-bbt; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ }; ++}; ++ ++&qspi { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&qspi_clk_pins_a &qspi_bk1_pins_a &qspi_bk2_pins_a>; ++ reg = <0x58003000 0x1000>, <0x70000000 0x4000000>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "okay"; ++ ++ flash0: mx66l51235l@0 { ++ compatible = "jedec,spi-nor"; ++ reg = <0>; ++ spi-rx-bus-width = <4>; ++ spi-max-frequency = <108000000>; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ }; ++ ++ flash1: mx66l51235l@1 { ++ compatible = "jedec,spi-nor"; ++ reg = <1>; ++ spi-rx-bus-width = <4>; ++ spi-max-frequency = <108000000>; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ }; ++}; ++ ++&usart3 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&usart3_pins_a>; ++ status = "disabled"; ++}; +diff --git a/core/arch/arm/fdts/stm32mp157c-security.dtsi b/core/arch/arm/fdts/stm32mp157c-security.dtsi +new file mode 100644 +index 0000000..bff1043 +--- /dev/null ++++ b/core/arch/arm/fdts/stm32mp157c-security.dtsi +@@ -0,0 +1,71 @@ ++/* ++ * Copyright : STMicroelectronics 2017 ++ * ++ * SPDX-License-Identifier: GPL-2.0+ BSD-3-Clause ++ */ ++ ++#include ++ ++/ { ++ soc { ++ iwdg1: iwdg@5C003000 { ++ compatible = "st,stm32mp1-iwdg"; ++ reg = <0x5C003000 0x400>; ++ clocks = <&rcc IWDG1>, <&rcc CK_LSI>; ++ clock-names = "pclk", "lsi"; ++ interrupts = ; ++ status = "disabled"; ++ secure-status = "disabled"; ++ }; ++ ++ etzpc: etzpc@5C007000 { ++ compatible = "st,stm32-etzpc"; ++ reg = <0x5C007000 0x400>; ++ clocks = <&rcc TZPC>; ++ status = "disabled"; ++ secure-status = "okay"; ++ }; ++ ++ stgen: stgen@5C008000 { ++ compatible = "st,stm32-stgen"; ++ reg = <0x5C008000 0x1000>; ++ }; ++ }; ++}; ++ ++&bsec { ++ mac_addr: mac_addr@e4 { ++ reg = <0xe4 0x6>; ++ }; ++ /* Spare field to align on 32-bit OTP granularity */ ++ spare_ns_ea: spare_ns_ea@ea { ++ reg = <0xea 0x2>; ++ }; ++ board_id: board_id@ec { ++ reg = <0xec 0x4>; ++ }; ++}; ++ ++&iwdg2 { ++ secure-interrupts = ; ++}; ++ ++&rcc { ++ secure-interrupts = ; ++ interrupt-names = "wakeup"; ++}; ++ ++&sdmmc1 { ++ compatible = "st,stm32-sdmmc2"; ++}; ++ ++&sdmmc2 { ++ compatible = "st,stm32-sdmmc2"; ++}; ++ ++&tamp { ++ compatible = "st,stm32-tamp"; ++ clocks = <&rcc RTCAPB>; ++ interrupts = ; ++ secure-status= "disabled"; ++}; +diff --git a/core/arch/arm/fdts/stm32mp157c.dtsi b/core/arch/arm/fdts/stm32mp157c.dtsi +new file mode 100644 +index 0000000..06c2cf1 +--- /dev/null ++++ b/core/arch/arm/fdts/stm32mp157c.dtsi +@@ -0,0 +1,371 @@ ++// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) ++/* ++ * Copyright (C) STMicroelectronics 2017-2019 - All Rights Reserved ++ * Author: Ludovic Barre for STMicroelectronics. ++ */ ++#include ++#include ++#include ++ ++/ { ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ++ intc: interrupt-controller@a0021000 { ++ compatible = "arm,cortex-a7-gic"; ++ #interrupt-cells = <3>; ++ interrupt-controller; ++ reg = <0xa0021000 0x1000>, ++ <0xa0022000 0x2000>; ++ }; ++ ++ clocks { ++ clk_hse: clk-hse { ++ #clock-cells = <0>; ++ compatible = "fixed-clock"; ++ clock-frequency = <24000000>; ++ }; ++ ++ clk_hsi: clk-hsi { ++ #clock-cells = <0>; ++ compatible = "fixed-clock"; ++ clock-frequency = <64000000>; ++ }; ++ ++ clk_lse: clk-lse { ++ #clock-cells = <0>; ++ compatible = "fixed-clock"; ++ clock-frequency = <32768>; ++ }; ++ ++ clk_lsi: clk-lsi { ++ #clock-cells = <0>; ++ compatible = "fixed-clock"; ++ clock-frequency = <32000>; ++ }; ++ ++ clk_csi: clk-csi { ++ #clock-cells = <0>; ++ compatible = "fixed-clock"; ++ clock-frequency = <4000000>; ++ }; ++ ++ clk_i2s_ckin: i2s_ckin { ++ #clock-cells = <0>; ++ compatible = "fixed-clock"; ++ clock-frequency = <0>; ++ }; ++ ++ clk_dsi_phy: ck_dsi_phy { ++ #clock-cells = <0>; ++ compatible = "fixed-clock"; ++ clock-frequency = <0>; ++ }; ++ }; ++ ++ soc { ++ compatible = "simple-bus"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ interrupt-parent = <&intc>; ++ ranges; ++ ++ timers12: timer@40006000 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ compatible = "st,stm32-timers"; ++ reg = <0x40006000 0x400>; ++ clocks = <&rcc TIM12_K>; ++ clock-names = "int"; ++ status = "disabled"; ++ }; ++ ++ usart2: serial@4000e000 { ++ compatible = "st,stm32h7-uart"; ++ reg = <0x4000e000 0x400>; ++ clocks = <&rcc USART2_K>; ++ resets = <&rcc USART2_R>; ++ status = "disabled"; ++ }; ++ ++ usart3: serial@4000f000 { ++ compatible = "st,stm32h7-uart"; ++ reg = <0x4000f000 0x400>; ++ clocks = <&rcc USART3_K>; ++ resets = <&rcc USART3_R>; ++ status = "disabled"; ++ }; ++ ++ uart4: serial@40010000 { ++ compatible = "st,stm32h7-uart"; ++ reg = <0x40010000 0x400>; ++ clocks = <&rcc UART4_K>; ++ resets = <&rcc UART4_R>; ++ status = "disabled"; ++ }; ++ ++ uart5: serial@40011000 { ++ compatible = "st,stm32h7-uart"; ++ reg = <0x40011000 0x400>; ++ clocks = <&rcc UART5_K>; ++ resets = <&rcc UART5_R>; ++ status = "disabled"; ++ }; ++ ++ ++ uart7: serial@40018000 { ++ compatible = "st,stm32h7-uart"; ++ reg = <0x40018000 0x400>; ++ clocks = <&rcc UART7_K>; ++ resets = <&rcc UART7_R>; ++ status = "disabled"; ++ }; ++ ++ uart8: serial@40019000 { ++ compatible = "st,stm32h7-uart"; ++ reg = <0x40019000 0x400>; ++ clocks = <&rcc UART8_K>; ++ resets = <&rcc UART8_R>; ++ status = "disabled"; ++ }; ++ ++ usart6: serial@44003000 { ++ compatible = "st,stm32h7-uart"; ++ reg = <0x44003000 0x400>; ++ clocks = <&rcc USART6_K>; ++ resets = <&rcc USART6_R>; ++ status = "disabled"; ++ }; ++ ++ timers15: timer@44006000 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ compatible = "st,stm32-timers"; ++ reg = <0x44006000 0x400>; ++ clocks = <&rcc TIM15_K>; ++ clock-names = "int"; ++ status = "disabled"; ++ }; ++ ++ sdmmc3: sdmmc@48004000 { ++ compatible = "arm,pl18x", "arm,primecell"; ++ arm,primecell-periphid = <0x00253180>; ++ reg = <0x48004000 0x400>, <0x48005000 0x400>; ++ clocks = <&rcc SDMMC3_K>; ++ clock-names = "apb_pclk"; ++ resets = <&rcc SDMMC3_R>; ++ cap-sd-highspeed; ++ cap-mmc-highspeed; ++ max-frequency = <120000000>; ++ status = "disabled"; ++ }; ++ ++ usbotg_hs: usb-otg@49000000 { ++ compatible = "st,stm32mp1-hsotg", "snps,dwc2"; ++ reg = <0x49000000 0x10000>; ++ clocks = <&rcc USBO_K>; ++ clock-names = "otg"; ++ resets = <&rcc USBO_R>; ++ reset-names = "dwc2"; ++ status = "disabled"; ++ }; ++ ++ rcc: rcc@50000000 { ++ compatible = "st,stm32mp1-rcc", "syscon"; ++ reg = <0x50000000 0x1000>; ++ #clock-cells = <1>; ++ #reset-cells = <1>; ++ interrupts = ; ++ }; ++ ++ pwr: pwr@50001000 { ++ compatible = "st,stm32mp1-pwr", "syscon", "simple-mfd"; ++ reg = <0x50001000 0x400>; ++ }; ++ ++ exti: interrupt-controller@5000d000 { ++ compatible = "st,stm32mp1-exti", "syscon"; ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ reg = <0x5000d000 0x400>; ++ ++ /* exti_pwr is an extra interrupt controller used for ++ * EXTI 55 to 60. It's mapped on pwr interrupt ++ * controller. ++ */ ++ exti_pwr: exti-pwr { ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ interrupt-parent = <&pwr>; ++ st,irq-number = <6>; ++ }; ++ }; ++ ++ syscfg: syscon@50020000 { ++ compatible = "st,stm32mp157-syscfg", "syscon"; ++ reg = <0x50020000 0x400>; ++ clocks = <&rcc SYSCFG>; ++ }; ++ ++ cryp1: cryp@54001000 { ++ compatible = "st,stm32mp1-cryp"; ++ reg = <0x54001000 0x400>; ++ interrupts = ; ++ clocks = <&rcc CRYP1>; ++ resets = <&rcc CRYP1_R>; ++ status = "disabled"; ++ }; ++ ++ hash1: hash@54002000 { ++ compatible = "st,stm32f756-hash"; ++ reg = <0x54002000 0x400>; ++ interrupts = ; ++ clocks = <&rcc HASH1>; ++ resets = <&rcc HASH1_R>; ++ status = "disabled"; ++ }; ++ ++ rng1: rng@54003000 { ++ compatible = "st,stm32-rng"; ++ reg = <0x54003000 0x400>; ++ clocks = <&rcc RNG1_K>; ++ resets = <&rcc RNG1_R>; ++ status = "disabled"; ++ }; ++ ++ fmc: nand-controller@58002000 { ++ compatible = "st,stm32mp15-fmc2"; ++ reg = <0x58002000 0x1000>, ++ <0x80000000 0x1000>, ++ <0x88010000 0x1000>, ++ <0x88020000 0x1000>, ++ <0x81000000 0x1000>, ++ <0x89010000 0x1000>, ++ <0x89020000 0x1000>; ++ clocks = <&rcc FMC_K>; ++ resets = <&rcc FMC_R>; ++ status = "disabled"; ++ }; ++ ++ qspi: qspi@58003000 { ++ compatible = "st,stm32f469-qspi"; ++ reg = <0x58003000 0x1000>, <0x70000000 0x10000000>; ++ reg-names = "qspi", "qspi_mm"; ++ clocks = <&rcc QSPI_K>; ++ resets = <&rcc QSPI_R>; ++ status = "disabled"; ++ }; ++ ++ sdmmc1: sdmmc@58005000 { ++ compatible = "arm,pl18x", "arm,primecell"; ++ arm,primecell-periphid = <0x00253180>; ++ reg = <0x58005000 0x1000>, <0x58006000 0x1000>; ++ clocks = <&rcc SDMMC1_K>; ++ clock-names = "apb_pclk"; ++ resets = <&rcc SDMMC1_R>; ++ cap-sd-highspeed; ++ cap-mmc-highspeed; ++ max-frequency = <120000000>; ++ status = "disabled"; ++ }; ++ ++ sdmmc2: sdmmc@58007000 { ++ compatible = "arm,pl18x", "arm,primecell"; ++ arm,primecell-periphid = <0x00253180>; ++ reg = <0x58007000 0x1000>, <0x58008000 0x1000>; ++ clocks = <&rcc SDMMC2_K>; ++ clock-names = "apb_pclk"; ++ resets = <&rcc SDMMC2_R>; ++ cap-sd-highspeed; ++ cap-mmc-highspeed; ++ max-frequency = <120000000>; ++ status = "disabled"; ++ }; ++ ++ iwdg2: watchdog@5a002000 { ++ compatible = "st,stm32mp1-iwdg"; ++ reg = <0x5a002000 0x400>; ++ clocks = <&rcc IWDG2>, <&rcc CK_LSI>; ++ clock-names = "pclk", "lsi"; ++ status = "disabled"; ++ }; ++ ++ usart1: serial@5c000000 { ++ compatible = "st,stm32h7-uart"; ++ reg = <0x5c000000 0x400>; ++ interrupt-names = "event", "wakeup"; ++ interrupts-extended = <&intc GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH>, ++ <&exti 26 1>; ++ clocks = <&rcc USART1_K>; ++ resets = <&rcc USART1_R>; ++ status = "disabled"; ++ }; ++ ++ spi6: spi@5c001000 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ compatible = "st,stm32h7-spi"; ++ reg = <0x5c001000 0x400>; ++ interrupts = ; ++ clocks = <&rcc SPI6_K>; ++ resets = <&rcc SPI6_R>; ++ status = "disabled"; ++ }; ++ ++ i2c4: i2c@5c002000 { ++ compatible = "st,stm32f7-i2c"; ++ reg = <0x5c002000 0x400>; ++ interrupt-names = "event", "error", "wakeup"; ++ interrupts-extended = <&intc GIC_SPI 95 IRQ_TYPE_LEVEL_HIGH>, ++ <&intc GIC_SPI 96 IRQ_TYPE_LEVEL_HIGH>, ++ <&exti 24 1>; ++ clocks = <&rcc I2C4_K>; ++ resets = <&rcc I2C4_R>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "disabled"; ++ }; ++ ++ rtc: rtc@5c004000 { ++ compatible = "st,stm32mp1-rtc"; ++ reg = <0x5c004000 0x400>; ++ clocks = <&rcc RTCAPB>, <&rcc RTC>; ++ clock-names = "pclk", "rtc_ck"; ++ interrupts-extended = <&intc GIC_SPI 3 IRQ_TYPE_LEVEL_HIGH>, ++ <&exti 19 1>; ++ status = "disabled"; ++ }; ++ ++ bsec: nvmem@5c005000 { ++ compatible = "st,stm32mp15-bsec"; ++ reg = <0x5c005000 0x400>; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ts_cal1: calib@5c { ++ reg = <0x5c 0x2>; ++ }; ++ ts_cal2: calib@5e { ++ reg = <0x5e 0x2>; ++ }; ++ }; ++ ++ i2c6: i2c@5c009000 { ++ compatible = "st,stm32f7-i2c"; ++ reg = <0x5c009000 0x400>; ++ interrupt-names = "event", "error", "wakeup"; ++ interrupts-extended = <&intc GIC_SPI 135 IRQ_TYPE_LEVEL_HIGH>, ++ <&intc GIC_SPI 136 IRQ_TYPE_LEVEL_HIGH>, ++ <&exti 54 1>; ++ clocks = <&rcc I2C6_K>; ++ resets = <&rcc I2C6_R>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "disabled"; ++ }; ++ ++ tamp: tamp@5c00a000 { ++ compatible = "simple-bus", "syscon", "simple-mfd"; ++ reg = <0x5c00a000 0x400>; ++ }; ++ }; ++}; +diff --git a/core/arch/arm/fdts/stm32mp157caa-pinctrl.dtsi b/core/arch/arm/fdts/stm32mp157caa-pinctrl.dtsi +new file mode 100644 +index 0000000..9b9cd08 +--- /dev/null ++++ b/core/arch/arm/fdts/stm32mp157caa-pinctrl.dtsi +@@ -0,0 +1,90 @@ ++// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) ++/* ++ * Copyright (C) STMicroelectronics 2018 - All Rights Reserved ++ * Author: Alexandre Torgue ++ */ ++ ++#include "stm32mp157-pinctrl.dtsi" ++/ { ++ soc { ++ pinctrl: pin-controller@50002000 { ++ st,package = ; ++ ++ gpioa: gpio@50002000 { ++ status = "okay"; ++ ngpios = <16>; ++ gpio-ranges = <&pinctrl 0 0 16>; ++ }; ++ ++ gpiob: gpio@50003000 { ++ status = "okay"; ++ ngpios = <16>; ++ gpio-ranges = <&pinctrl 0 16 16>; ++ }; ++ ++ gpioc: gpio@50004000 { ++ status = "okay"; ++ ngpios = <16>; ++ gpio-ranges = <&pinctrl 0 32 16>; ++ }; ++ ++ gpiod: gpio@50005000 { ++ status = "okay"; ++ ngpios = <16>; ++ gpio-ranges = <&pinctrl 0 48 16>; ++ }; ++ ++ gpioe: gpio@50006000 { ++ status = "okay"; ++ ngpios = <16>; ++ gpio-ranges = <&pinctrl 0 64 16>; ++ }; ++ ++ gpiof: gpio@50007000 { ++ status = "okay"; ++ ngpios = <16>; ++ gpio-ranges = <&pinctrl 0 80 16>; ++ }; ++ ++ gpiog: gpio@50008000 { ++ status = "okay"; ++ ngpios = <16>; ++ gpio-ranges = <&pinctrl 0 96 16>; ++ }; ++ ++ gpioh: gpio@50009000 { ++ status = "okay"; ++ ngpios = <16>; ++ gpio-ranges = <&pinctrl 0 112 16>; ++ }; ++ ++ gpioi: gpio@5000a000 { ++ status = "okay"; ++ ngpios = <16>; ++ gpio-ranges = <&pinctrl 0 128 16>; ++ }; ++ ++ gpioj: gpio@5000b000 { ++ status = "okay"; ++ ngpios = <16>; ++ gpio-ranges = <&pinctrl 0 144 16>; ++ }; ++ ++ gpiok: gpio@5000c000 { ++ status = "okay"; ++ ngpios = <8>; ++ gpio-ranges = <&pinctrl 0 160 8>; ++ }; ++ }; ++ ++ pinctrl_z: pin-controller-z@54004000 { ++ st,package = ; ++ ++ gpioz: gpio@54004000 { ++ status = "okay"; ++ ngpios = <8>; ++ gpio-ranges = <&pinctrl_z 0 400 8>; ++ }; ++ }; ++ }; ++}; +diff --git a/core/arch/arm/fdts/stm32mp157cab-pinctrl.dtsi b/core/arch/arm/fdts/stm32mp157cab-pinctrl.dtsi +new file mode 100644 +index 0000000..c570cf9 +--- /dev/null ++++ b/core/arch/arm/fdts/stm32mp157cab-pinctrl.dtsi +@@ -0,0 +1,62 @@ ++// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) ++/* ++ * Copyright (C) STMicroelectronics 2018 - All Rights Reserved ++ * Author: Alexandre Torgue ++ */ ++ ++#include "stm32mp157-pinctrl.dtsi" ++/ { ++ soc { ++ pinctrl: pin-controller@50002000 { ++ st,package = ; ++ ++ gpioa: gpio@50002000 { ++ status = "okay"; ++ ngpios = <16>; ++ gpio-ranges = <&pinctrl 0 0 16>; ++ }; ++ ++ gpiob: gpio@50003000 { ++ status = "okay"; ++ ngpios = <16>; ++ gpio-ranges = <&pinctrl 0 16 16>; ++ }; ++ ++ gpioc: gpio@50004000 { ++ status = "okay"; ++ ngpios = <16>; ++ gpio-ranges = <&pinctrl 0 32 16>; ++ }; ++ ++ gpiod: gpio@50005000 { ++ status = "okay"; ++ ngpios = <16>; ++ gpio-ranges = <&pinctrl 0 48 16>; ++ }; ++ ++ gpioe: gpio@50006000 { ++ status = "okay"; ++ ngpios = <16>; ++ gpio-ranges = <&pinctrl 0 64 16>; ++ }; ++ ++ gpiof: gpio@50007000 { ++ status = "okay"; ++ ngpios = <6>; ++ gpio-ranges = <&pinctrl 6 86 6>; ++ }; ++ ++ gpiog: gpio@50008000 { ++ status = "okay"; ++ ngpios = <10>; ++ gpio-ranges = <&pinctrl 6 102 10>; ++ }; ++ ++ gpioh: gpio@50009000 { ++ status = "okay"; ++ ngpios = <2>; ++ gpio-ranges = <&pinctrl 0 112 2>; ++ }; ++ }; ++ }; ++}; +diff --git a/core/arch/arm/fdts/stm32mp157cac-pinctrl.dtsi b/core/arch/arm/fdts/stm32mp157cac-pinctrl.dtsi +new file mode 100644 +index 0000000..777f991 +--- /dev/null ++++ b/core/arch/arm/fdts/stm32mp157cac-pinctrl.dtsi +@@ -0,0 +1,78 @@ ++// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) ++/* ++ * Copyright (C) STMicroelectronics 2018 - All Rights Reserved ++ * Author: Alexandre Torgue ++ */ ++ ++#include "stm32mp157-pinctrl.dtsi" ++/ { ++ soc { ++ pinctrl: pin-controller@50002000 { ++ st,package = ; ++ ++ gpioa: gpio@50002000 { ++ status = "okay"; ++ ngpios = <16>; ++ gpio-ranges = <&pinctrl 0 0 16>; ++ }; ++ ++ gpiob: gpio@50003000 { ++ status = "okay"; ++ ngpios = <16>; ++ gpio-ranges = <&pinctrl 0 16 16>; ++ }; ++ ++ gpioc: gpio@50004000 { ++ status = "okay"; ++ ngpios = <16>; ++ gpio-ranges = <&pinctrl 0 32 16>; ++ }; ++ ++ gpiod: gpio@50005000 { ++ status = "okay"; ++ ngpios = <16>; ++ gpio-ranges = <&pinctrl 0 48 16>; ++ }; ++ ++ gpioe: gpio@50006000 { ++ status = "okay"; ++ ngpios = <16>; ++ gpio-ranges = <&pinctrl 0 64 16>; ++ }; ++ ++ gpiof: gpio@50007000 { ++ status = "okay"; ++ ngpios = <16>; ++ gpio-ranges = <&pinctrl 0 80 16>; ++ }; ++ ++ gpiog: gpio@50008000 { ++ status = "okay"; ++ ngpios = <16>; ++ gpio-ranges = <&pinctrl 0 96 16>; ++ }; ++ ++ gpioh: gpio@50009000 { ++ status = "okay"; ++ ngpios = <16>; ++ gpio-ranges = <&pinctrl 0 112 16>; ++ }; ++ ++ gpioi: gpio@5000a000 { ++ status = "okay"; ++ ngpios = <12>; ++ gpio-ranges = <&pinctrl 0 128 12>; ++ }; ++ }; ++ ++ pinctrl_z: pin-controller-z@54004000 { ++ st,package = ; ++ ++ gpioz: gpio@54004000 { ++ status = "okay"; ++ ngpios = <8>; ++ gpio-ranges = <&pinctrl_z 0 400 8>; ++ }; ++ }; ++ }; ++}; +diff --git a/core/arch/arm/fdts/stm32mp157cad-pinctrl.dtsi b/core/arch/arm/fdts/stm32mp157cad-pinctrl.dtsi +new file mode 100644 +index 0000000..c4c303a +--- /dev/null ++++ b/core/arch/arm/fdts/stm32mp157cad-pinctrl.dtsi +@@ -0,0 +1,62 @@ ++// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) ++/* ++ * Copyright (C) STMicroelectronics 2018 - All Rights Reserved ++ * Author: Alexandre Torgue ++ */ ++ ++#include "stm32mp157-pinctrl.dtsi" ++/ { ++ soc { ++ pinctrl: pin-controller@50002000 { ++ st,package = ; ++ ++ gpioa: gpio@50002000 { ++ status = "okay"; ++ ngpios = <16>; ++ gpio-ranges = <&pinctrl 0 0 16>; ++ }; ++ ++ gpiob: gpio@50003000 { ++ status = "okay"; ++ ngpios = <16>; ++ gpio-ranges = <&pinctrl 0 16 16>; ++ }; ++ ++ gpioc: gpio@50004000 { ++ status = "okay"; ++ ngpios = <16>; ++ gpio-ranges = <&pinctrl 0 32 16>; ++ }; ++ ++ gpiod: gpio@50005000 { ++ status = "okay"; ++ ngpios = <16>; ++ gpio-ranges = <&pinctrl 0 48 16>; ++ }; ++ ++ gpioe: gpio@50006000 { ++ status = "okay"; ++ ngpios = <16>; ++ gpio-ranges = <&pinctrl 0 64 16>; ++ }; ++ ++ gpiof: gpio@50007000 { ++ status = "okay"; ++ ngpios = <6>; ++ gpio-ranges = <&pinctrl 6 86 6>; ++ }; ++ ++ gpiog: gpio@50008000 { ++ status = "okay"; ++ ngpios = <10>; ++ gpio-ranges = <&pinctrl 6 102 10>; ++ }; ++ ++ gpioh: gpio@50009000 { ++ status = "okay"; ++ ngpios = <2>; ++ gpio-ranges = <&pinctrl 0 112 2>; ++ }; ++ }; ++ }; ++}; +diff --git a/core/arch/arm/include/arm32.h b/core/arch/arm/include/arm32.h +index e7c3b2d..0dbd889 100644 +--- a/core/arch/arm/include/arm32.h ++++ b/core/arch/arm/include/arm32.h +@@ -1,12 +1,13 @@ + /* SPDX-License-Identifier: BSD-2-Clause */ + /* +- * Copyright (c) 2016, Linaro Limited ++ * Copyright (c) 2016-2018, Linaro Limited + * Copyright (c) 2014, STMicroelectronics International N.V. + */ + + #ifndef ARM32_H + #define ARM32_H + ++#include + #include + #include + #include +@@ -159,6 +160,17 @@ + #define IDPFR1_GENTIMER_SHIFT 16 + #define IDPFR1_GENTIMER_MASK (0xF << IDPFR1_GENTIMER_SHIFT) + ++/* Generic timer registers and fields */ ++#define CNTCR_OFFSET 0x000 ++#define CNTSR_OFFSET 0x004 ++#define CNTCVL_OFFSET 0x008 ++#define CNTCVU_OFFSET 0x00C ++#define CNTFID_OFFSET 0x020 ++ ++#define CNTCR_EN BIT(0) ++#define CNTCR_HDBG BIT(1) ++#define CNTCR_FCREQ(x) ((x) << 8) ++ + #ifndef ASM + #include + #ifdef CFG_ARM_GICV3 +diff --git a/core/arch/arm/include/kernel/delay.h b/core/arch/arm/include/kernel/delay.h +index 72ac873..2c47f0a 100644 +--- a/core/arch/arm/include/kernel/delay.h ++++ b/core/arch/arm/include/kernel/delay.h +@@ -1,5 +1,6 @@ + /* SPDX-License-Identifier: BSD-2-Clause */ + /* ++ * Copyright (c) 2018, Linaro Limited + * Copyright (C) 2017, Fuzhou Rockchip Electronics Co., Ltd. + * All rights reserved. + * +@@ -29,7 +30,14 @@ + #ifndef __KERNEL_DELAY_H + #define __KERNEL_DELAY_H + ++#include ++#include ++ + void udelay(uint32_t us); + void mdelay(uint32_t ms); + ++uint64_t utimeout_init(uint32_t us); ++bool utimeout_elapsed(uint32_t us, uint64_t ref); ++unsigned int utimeout_elapsed_us(uint32_t us, uint64_t reference); ++ + #endif +diff --git a/core/arch/arm/include/mm/core_mmu.h b/core/arch/arm/include/mm/core_mmu.h +index 64994d3..cec3a42 100644 +--- a/core/arch/arm/include/mm/core_mmu.h ++++ b/core/arch/arm/include/mm/core_mmu.h +@@ -101,6 +101,7 @@ + * MEM_AREA_NSEC_SHM: NonSecure shared RAM between NSec and TEE. + * MEM_AREA_RAM_NSEC: NonSecure RAM storing data + * MEM_AREA_RAM_SEC: Secure RAM storing some secrets ++ * MEM_AREA_ROM_SEC: Secure read only memory storing some secrets + * MEM_AREA_IO_NSEC: NonSecure HW mapped registers + * MEM_AREA_IO_SEC: Secure HW mapped registers + * MEM_AREA_RES_VASPACE: Reserved virtual memory space +@@ -121,6 +122,7 @@ enum teecore_memtypes { + MEM_AREA_NSEC_SHM, + MEM_AREA_RAM_NSEC, + MEM_AREA_RAM_SEC, ++ MEM_AREA_ROM_SEC, + MEM_AREA_IO_NSEC, + MEM_AREA_IO_SEC, + MEM_AREA_RES_VASPACE, +@@ -146,6 +148,7 @@ static inline const char *teecore_memtype_name(enum teecore_memtypes type) + [MEM_AREA_NSEC_SHM] = "NSEC_SHM", + [MEM_AREA_RAM_NSEC] = "RAM_NSEC", + [MEM_AREA_RAM_SEC] = "RAM_SEC", ++ [MEM_AREA_ROM_SEC] = "ROM_SEC", + [MEM_AREA_IO_NSEC] = "IO_NSEC", + [MEM_AREA_IO_SEC] = "IO_SEC", + [MEM_AREA_RES_VASPACE] = "RES_VASPACE", +diff --git a/core/arch/arm/include/sm/pm.h b/core/arch/arm/include/sm/pm.h +index 939f966..90f031a 100644 +--- a/core/arch/arm/include/sm/pm.h ++++ b/core/arch/arm/include/sm/pm.h +@@ -34,7 +34,11 @@ + struct sm_pm_ctx { + uint32_t sp; + paddr_t cpu_resume_addr; ++#ifdef CFG_WITH_LPAE ++ uint32_t suspend_regs[18]; ++#else + uint32_t suspend_regs[16]; ++#endif + }; + + /* suspend/resume core functions */ +diff --git a/core/arch/arm/kernel/delay.c b/core/arch/arm/kernel/delay.c +index 2321b78..ae62187 100644 +--- a/core/arch/arm/kernel/delay.c ++++ b/core/arch/arm/kernel/delay.c +@@ -1,5 +1,6 @@ + // SPDX-License-Identifier: BSD-2-Clause + /* ++ * Copyright (c) 2018, Linaro Limited + * Copyright (C) 2017, Fuzhou Rockchip Electronics Co., Ltd. + * All rights reserved. + * +@@ -29,12 +30,15 @@ + #include + #include + ++#define US2CNT(m) (((uint64_t)m * (uint64_t)read_cntfrq()) / 1000000ULL) ++#define CNT2US(m) ((uint32_t)(((uint64_t)m * 1000000ULL) / read_cntfrq())) ++ + void udelay(uint32_t us) + { + uint64_t start, target; + + start = read_cntpct(); +- target = ((uint64_t)read_cntfrq() * us) / 1000000ULL; ++ target = US2CNT(us); + + while (read_cntpct() - start <= target) + ; +@@ -44,3 +48,37 @@ void mdelay(uint32_t ms) + { + udelay(1000 * ms); + } ++ ++uint64_t utimeout_init(uint32_t us) ++{ ++ return read_cntpct() + US2CNT(us); ++} ++ ++bool utimeout_elapsed(uint32_t us, uint64_t reference) ++{ ++ uint64_t origin = reference - US2CNT(us); ++ uint64_t now = read_cntpct(); ++ ++ if (origin < reference) ++ return now < origin || now > reference; ++ ++ return now < origin && now > reference; ++} ++ ++unsigned int utimeout_elapsed_us(uint32_t us, uint64_t reference) ++{ ++ uint64_t origin = reference - US2CNT(us); ++ uint64_t now = read_cntpct(); ++ ++ if (origin < reference) { ++ if (now < origin || now > reference) ++ return CNT2US(now - reference); ++ ++ return 0; ++ } ++ ++ if (now < origin && now > reference) ++ return CNT2US(now - reference); ++ ++ return 0; ++} +diff --git a/core/arch/arm/kernel/generic_boot.c b/core/arch/arm/kernel/generic_boot.c +index e5f0f3d..612eab4 100644 +--- a/core/arch/arm/kernel/generic_boot.c ++++ b/core/arch/arm/kernel/generic_boot.c +@@ -73,6 +73,9 @@ uint32_t sem_cpu_sync[CFG_TEE_CORE_NB_CORE]; + KEEP_PAGER(sem_cpu_sync); + #endif + ++#ifdef CFG_STATIC_SECURE_DT ++extern uint8_t static_secure_dtb[]; ++#endif + #ifdef CFG_DT + static void *dt_blob_addr; + #endif +@@ -471,7 +474,7 @@ static void init_runtime(unsigned long pageable_part __unused) + } + #endif + +-#ifdef CFG_DT ++#if defined(CFG_DT) && !defined(CFG_STATIC_SECURE_DT) + void *get_dt_blob(void) + { + assert(cpu_mmu_enabled()); +@@ -836,23 +839,42 @@ static void update_fdt(void) + panic(); + } + } ++#endif /*CFG_DT && !CFG_STATIC_SECURE_DT*/ + +-#else +-static void init_fdt(unsigned long phys_fdt __unused) ++#if defined(CFG_DT) && defined(CFG_STATIC_SECURE_DT) ++void *get_dt_blob(void) + { ++ assert(cpu_mmu_enabled()); ++ ++ if (!dt_blob_addr) { ++ if (fdt_check_header((void *)&static_secure_dtb[0])) ++ panic("Invalid static DTB"); ++ ++ dt_blob_addr = (void *)&static_secure_dtb[0]; ++ } ++ ++ return dt_blob_addr; + } ++#endif + +-static void update_fdt(void) ++#ifndef CFG_DT ++void *get_dt_blob(void) + { ++ return NULL; + } ++#endif + ++#if !defined(CFG_DT) || defined(CFG_STATIC_SECURE_DT) + static void reset_dt_references(void) + { + } + +-void *get_dt_blob(void) ++static void init_fdt(unsigned long phys_fdt __unused) ++{ ++} ++ ++static void update_fdt(void) + { +- return NULL; + } + + static struct core_mmu_phys_mem *get_memory(void *fdt __unused, +@@ -861,7 +883,7 @@ static struct core_mmu_phys_mem *get_memory(void *fdt __unused, + return NULL; + } + +-#endif /*!CFG_DT*/ ++#endif /*!CFG_DT || CFG_STATIC_SECURE_DT*/ + + static void discover_nsec_memory(void) + { +diff --git a/core/arch/arm/mm/core_mmu.c b/core/arch/arm/mm/core_mmu.c +index f69069e..3337ca6 100644 +--- a/core/arch/arm/mm/core_mmu.c ++++ b/core/arch/arm/mm/core_mmu.c +@@ -627,6 +627,8 @@ uint32_t core_mmu_type_to_attr(enum teecore_memtypes t) + return attr | TEE_MATTR_PRW | cached; + case MEM_AREA_RAM_SEC: + return attr | TEE_MATTR_SECURE | TEE_MATTR_PRW | cached; ++ case MEM_AREA_ROM_SEC: ++ return attr | TEE_MATTR_SECURE | TEE_MATTR_PR | cached; + case MEM_AREA_RES_VASPACE: + case MEM_AREA_SHM_VASPACE: + return 0; +@@ -1014,6 +1016,7 @@ void core_init_mmu_map(void) + case MEM_AREA_IO_SEC: + case MEM_AREA_IO_NSEC: + case MEM_AREA_RAM_SEC: ++ case MEM_AREA_ROM_SEC: + case MEM_AREA_RAM_NSEC: + case MEM_AREA_RES_VASPACE: + case MEM_AREA_SHM_VASPACE: +diff --git a/core/arch/arm/mm/mobj.c b/core/arch/arm/mm/mobj.c +index b2bdf6b..789a88d 100644 +--- a/core/arch/arm/mm/mobj.c ++++ b/core/arch/arm/mm/mobj.c +@@ -52,6 +52,7 @@ static void *mobj_phys_get_va(struct mobj *mobj, size_t offset) + + return (void *)(moph->va + offset); + } ++KEEP_PAGER(mobj_phys_get_va); + + static TEE_Result mobj_phys_get_pa(struct mobj *mobj, size_t offs, + size_t granule, paddr_t *pa) +@@ -230,7 +231,7 @@ static void *mobj_mm_get_va(struct mobj *mobj, size_t offs) + return mobj_get_va(to_mobj_mm(mobj)->parent_mobj, + mobj_mm_offs(mobj, offs)); + } +- ++KEEP_PAGER(mobj_mm_get_va); + + static TEE_Result mobj_mm_get_pa(struct mobj *mobj, size_t offs, + size_t granule, paddr_t *pa) +diff --git a/core/arch/arm/plat-stm32mp1/boot_api.h b/core/arch/arm/plat-stm32mp1/boot_api.h +index 62e38b5..a7daffd 100644 +--- a/core/arch/arm/plat-stm32mp1/boot_api.h ++++ b/core/arch/arm/plat-stm32mp1/boot_api.h +@@ -14,7 +14,9 @@ + #define BCKR_CORE1_MAGIC_NUMBER 4 + + /* Value for BCKR_CORE1_MAGIC_NUMBER entry */ ++#define BOOT_API_A7_CORE0_MAGIC_NUMBER 0xca7face0 + #define BOOT_API_A7_CORE1_MAGIC_NUMBER 0xca7face1 ++#define BOOT_API_A7_RESET_MAGIC_NUMBER 0xca7dead0 + + /* Backup register #5: physical address of core1 entry at boot up */ + #define BCKR_CORE1_BRANCH_ADDRESS 5 +diff --git a/core/arch/arm/plat-stm32mp1/conf.mk b/core/arch/arm/plat-stm32mp1/conf.mk +index fb0ca5a..0940ce3 100644 +--- a/core/arch/arm/plat-stm32mp1/conf.mk ++++ b/core/arch/arm/plat-stm32mp1/conf.mk +@@ -1,9 +1,16 @@ + PLATFORM_FLAVOR ?= stm32mp157c ++STM32_BOARD ?= ev1 + ++# 1GB and 512MB DDR target do not locate secure DDR at the same place. ++# ++flavorlist-1G = stm32mp157c-ev1 stm32mp157c-ed1 ++flavorlist-512M = stm32mp157a-dk1 stm32mp157c-dk2 ++ ++# Generic stm32mp1 configuration directives ++# + include core/arch/arm/cpu/cortex-a7.mk + ta-targets = ta_arm32 + +-$(call force,CFG_TEE_CORE_NB_CORE,2) + $(call force,CFG_ARM32_core,y) + $(call force,CFG_BOOT_SECONDARY_REQUEST,y) + $(call force,CFG_GENERIC_BOOT,y) +@@ -11,23 +18,85 @@ $(call force,CFG_GIC,y) + $(call force,CFG_INIT_CNTVOFF,y) + $(call force,CFG_PM_STUBS,y) + $(call force,CFG_PSCI_ARM32,y) ++$(call force,CFG_PM_ARM32,y) + $(call force,CFG_SECONDARY_INIT_CNTFRQ,y) + $(call force,CFG_SECURE_TIME_SOURCE_CNTPCT,y) + $(call force,CFG_WITH_SOFTWARE_PRNG,y) ++$(call force,CFG_SM_PLATFORM_HANDLER,y) ++ ++ifneq ($(CFG_SECURE_DT),) ++$(call force,CFG_DT,y) ++$(call force,CFG_STATIC_SECURE_DT,y) ++endif ++ ++CFG_TEE_CORE_NB_CORE ?= 2 ++ ++ifneq (,$(filter $(CFG_SECURE_DT),$(flavorlist-512M))) ++CFG_TZDRAM_START ?= 0xde000000 ++CFG_SHMEM_START ?= 0xdfe00000 ++endif + + CFG_TZSRAM_START ?= 0x2ffc0000 + CFG_TZSRAM_SIZE ?= 0x00040000 + CFG_TZDRAM_START ?= 0xfe000000 + CFG_TZDRAM_SIZE ?= 0x01e00000 +-CFG_SHMEM_SIZE ?= 0x00200000 + CFG_SHMEM_START ?= 0xffe00000 ++CFG_SHMEM_SIZE ?= 0x00200000 + +-CFG_WITH_PAGER ?= y +-CFG_WITH_LPAE ?= y +-CFG_WITH_STACK_CANARIES ?= y ++CFG_CORE_HEAP_SIZE ?= 49152 ++CFG_WITH_PAGER ?= y ++CFG_WITH_LPAE ?= y ++CFG_WITH_STACK_CANARIES ?= y ++CFG_MMAP_REGIONS ?= 23 + ++ifneq ($(CFG_DT),y) ++# Some drivers mandate DT support ++$(call force,CFG_STPMIC1,n) ++$(call force,CFG_STM32_I2C,n) ++$(call force,CFG_STM32_IWDG,n) ++$(call force,CFG_STM32_RNG,n) ++$(call force,CFG_STM32_TIMER,n) ++$(call force,CFG_STM32_CLOCKSRC_CALIB,n) ++endif ++ ++$(call force,CFG_STM32_BSEC,y) ++$(call force,CFG_STM32_CRYP,y) ++$(call force,CFG_STM32_ETZPC,y) ++CFG_STM32_GPIO ?= y ++CFG_STM32_I2C ?= y ++CFG_STM32_IWDG ?= y + CFG_STM32_UART ?= y ++CFG_STM32_RNG ?= y ++$(call force,CFG_STM32_RTC,y) ++CFG_STM32_TIMER ?= y ++ ++CFG_STPMIC1 ?= y ++ ++$(call force,CFG_STM32_BSEC_SIP,y) ++$(call force,CFG_STM32_RCC_SIP,y) ++CFG_STM32_PWR_SIP ?= y ++CFG_STM32_POWER_SERVICES ?= y ++CFG_STM32_CLOCKSRC_CALIB ?= y ++ ++ifeq ($(CFG_STPMIC1),y) ++$(call force,CFG_STM32_I2C,y) ++$(call force,CFG_STM32_GPIO,y) ++endif ++ ++ifeq ($(CFG_STM32_CLOCKSRC_CALIB),y) ++$(call force,CFG_STM32_TIMER,y) ++endif ++ ++# Get a static mapping for the non secure low DDR (save 4kB of unpaged memory) ++CFG_STM32MP_MAP_NSEC_LOW_DDR ?= y + +-# Default enable the test facitilites ++# Default enable some test facitilites + CFG_TEE_CORE_EMBED_INTERNAL_TESTS ?= y + CFG_WITH_STATS ?= y ++CFG_UNWIND ?= n ++# Non secure UART and GPIO/pinctrl for the output console ++CFG_WITH_NSEC_GPIOS ?= y ++CFG_WITH_NSEC_UARTS ?= y ++CFG_FORCE_CONSOLE_ON_SUSPEND ?= n ++# UART instance used for early console (0 disables early console) ++CFG_STM32_EARLY_CONSOLE_UART ?= 4 +diff --git a/core/arch/arm/plat-stm32mp1/drivers/stm32_reset.c b/core/arch/arm/plat-stm32mp1/drivers/stm32_reset.c +new file mode 100644 +index 0000000..b406167 +--- /dev/null ++++ b/core/arch/arm/plat-stm32mp1/drivers/stm32_reset.c +@@ -0,0 +1,60 @@ ++// SPDX-License-Identifier: BSD-3-Clause ++/* ++ * Copyright (c) 2018, STMicroelectronics - All Rights Reserved ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define RST_CLR_OFFSET 4U ++#define RESET_TIMEOUT_US 1000 ++ ++static size_t id2reg_offset(unsigned int reset_id) ++{ ++ return ((reset_id & GENMASK_32(31, 5)) >> 5) * sizeof(uint32_t); ++} ++ ++static uint8_t id2reg_bit_pos(unsigned int reset_id) ++{ ++ return (uint8_t)(reset_id & GENMASK_32(4,0)); ++} ++ ++void stm32_reset_assert(unsigned int reset_id) ++{ ++ size_t offset = id2reg_offset(reset_id); ++ uint32_t bitmsk = BIT(id2reg_bit_pos(reset_id)); ++ uint64_t timeout_ref; ++ uintptr_t rcc_base = stm32_rcc_base(); ++ ++ write32(bitmsk, rcc_base + offset); ++ ++ timeout_ref = utimeout_init(RESET_TIMEOUT_US); ++ ++ while (!(read32(rcc_base + offset) & bitmsk)) { ++ if (utimeout_elapsed(RESET_TIMEOUT_US, timeout_ref)) { ++ panic("Reset timeout"); ++ } ++ } ++} ++ ++void stm32_reset_deassert(unsigned int reset_id) ++{ ++ size_t offset = id2reg_offset(reset_id) + RST_CLR_OFFSET; ++ uint32_t bitmsk = BIT(id2reg_bit_pos(reset_id)); ++ uint64_t timeout_ref; ++ uintptr_t rcc_base = stm32_rcc_base(); ++ ++ write32(bitmsk, rcc_base + offset); ++ ++ timeout_ref = utimeout_init(RESET_TIMEOUT_US); ++ ++ while (read32(rcc_base + offset) & bitmsk) { ++ if (utimeout_elapsed(RESET_TIMEOUT_US, timeout_ref)) { ++ panic("Reset timeout"); ++ } ++ } ++} +diff --git a/core/arch/arm/plat-stm32mp1/drivers/stm32_reset.h b/core/arch/arm/plat-stm32mp1/drivers/stm32_reset.h +new file mode 100644 +index 0000000..577ba9b +--- /dev/null ++++ b/core/arch/arm/plat-stm32mp1/drivers/stm32_reset.h +@@ -0,0 +1,15 @@ ++/* ++ * Copyright (c) 2018, STMicroelectronics - All Rights Reserved ++ * ++ * SPDX-License-Identifier: BSD-3-Clause ++ */ ++ ++#ifndef __STM32_RESET_H__ ++#define __STM32_RESET_H__ ++ ++#include ++ ++void stm32_reset_assert(uint32_t reset_id); ++void stm32_reset_deassert(uint32_t reset_id); ++ ++#endif /* __STM32MP1_RESET_H__ */ +diff --git a/core/arch/arm/plat-stm32mp1/drivers/stm32mp1_calib.c b/core/arch/arm/plat-stm32mp1/drivers/stm32mp1_calib.c +new file mode 100644 +index 0000000..583bf94 +--- /dev/null ++++ b/core/arch/arm/plat-stm32mp1/drivers/stm32mp1_calib.c +@@ -0,0 +1,457 @@ ++// SPDX-License-Identifier: BSD-3-Clause ++/* ++ * Copyright (c) 2018, STMicroelectronics ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define CAL_MAX_RETRY 20U ++ ++/* List of forbiden values for HSI and CSI */ ++static uint16_t fbv_hsi[] = { ++ 512, 480, 448, 416, 384, 352, 320, 288, ++ 256, 224, 192, 160, 128, 96, 64, 32, 0, ++}; ++static uint16_t fbv_csi[] = { ++ 256, 240, 224, 208, 192, 176, 160, 144, ++ 128, 112, 96, 80, 64, 48, 32, 16, 0, ++}; ++ ++struct stm32mp1_trim_boundary_t { ++ unsigned int x1; /* Max boundary trim value around forbidden value */ ++ unsigned int x2; /* Min boundary trim value around forbidden value */ ++}; ++ ++struct stm32mp1_clk_cal { ++ uint16_t *fbv; ++ unsigned int cal_ref; ++ int trim_max; ++ int trim_min; ++ unsigned int boundary_max; ++ unsigned long ref_freq; ++ unsigned int freq_margin; ++ unsigned long (*get_freq)(void); ++ void (*set_trim)(unsigned int cal); ++ unsigned int (*get_trim)(void); ++ struct stm32mp1_trim_boundary_t boundary[16]; ++}; ++ ++static void hsi_set_trim(unsigned int cal); ++static unsigned int hsi_get_trimed_cal(void); ++static void csi_set_trim(unsigned int cal); ++static unsigned int csi_get_trimed_cal(void); ++ ++static struct stm32mp1_clk_cal *hsi_calib; ++static struct stm32mp1_clk_cal *csi_calib; ++ ++static const struct stm32mp1_clk_cal hsi_calib_config = { ++ .fbv = fbv_hsi, ++ .trim_max = 63, ++ .trim_min = -64, ++ .ref_freq = 0, ++ .freq_margin = 1, ++ .set_trim = hsi_set_trim, ++ .get_trim = hsi_get_trimed_cal, ++}; ++ ++static const struct stm32mp1_clk_cal csi_calib_config = { ++ .fbv = fbv_csi, ++ .trim_max = 15, ++ .trim_min = -16, ++ .ref_freq = 0, ++ .freq_margin = 2, ++ .set_trim = csi_set_trim, ++ .get_trim = csi_get_trimed_cal, ++}; ++ ++static void hsi_set_trim(unsigned int cal) ++{ ++ int clk_trim = (int)cal - (int)hsi_calib->cal_ref; ++ uint32_t trim = ((uint32_t)clk_trim << RCC_HSICFGR_HSITRIM_SHIFT) & ++ RCC_HSICFGR_HSITRIM_MASK; ++ ++ mmio_clrsetbits_32(stm32_rcc_base() + RCC_HSICFGR, ++ RCC_HSICFGR_HSITRIM_MASK, trim); ++} ++KEEP_PAGER(hsi_set_trim); ++ ++static unsigned int hsi_get_trimed_cal(void) ++{ ++ uint32_t utrim = (mmio_read_32(stm32_rcc_base() + RCC_HSICFGR) & ++ RCC_HSICFGR_HSITRIM_MASK) >> ++ RCC_HSICFGR_HSITRIM_SHIFT; ++ int trim = (int)utrim - hsi_calib->trim_max; ++ ++ if (trim + (int)hsi_calib->cal_ref < 0) ++ return 0; ++ ++ return hsi_calib->cal_ref + trim; ++} ++KEEP_PAGER(hsi_get_trimed_cal); ++ ++static void csi_set_trim(unsigned int cal) ++{ ++ int clk_trim = (int)cal - (int)csi_calib->cal_ref + ++ csi_calib->trim_max + 1; ++ uint32_t trim = ((uint32_t)clk_trim << RCC_CSICFGR_CSITRIM_SHIFT) & ++ RCC_CSICFGR_CSITRIM_MASK; ++ ++ mmio_clrsetbits_32(stm32_rcc_base() + RCC_CSICFGR, ++ RCC_CSICFGR_CSITRIM_MASK, trim); ++} ++KEEP_PAGER(csi_set_trim); ++ ++static unsigned int csi_get_trimed_cal(void) ++{ ++ uint32_t trim = (mmio_read_32(stm32_rcc_base() + RCC_CSICFGR) & ++ RCC_CSICFGR_CSITRIM_MASK) >> ++ RCC_CSICFGR_CSITRIM_SHIFT; ++ ++ return (int)trim - csi_calib->trim_max + (int)csi_calib->cal_ref - 1; ++} ++KEEP_PAGER(csi_get_trimed_cal); ++ ++static unsigned int trim_increase(struct stm32mp1_clk_cal *clk_cal, ++ unsigned int cal) ++{ ++ struct stm32mp1_trim_boundary_t *boundary; ++ unsigned int new_cal; ++ int i; ++ ++ /* By default: last calibration value */ ++ new_cal = cal; ++ ++ /* Start from Lowest cal value */ ++ for (i = (int)clk_cal->boundary_max - 1; i >= 0; i--) { ++ boundary = &clk_cal->boundary[i]; ++ ++ if (cal < boundary->x2) { ++ new_cal = boundary->x2; ++ break; ++ } ++ ++ if ((cal >= boundary->x2) && (cal < boundary->x1)) { ++ new_cal = cal + 1; ++ break; ++ } ++ } ++ ++ return new_cal; ++} ++ ++static unsigned int trim_decrease(struct stm32mp1_clk_cal *clk_cal, ++ unsigned int cal) ++{ ++ struct stm32mp1_trim_boundary_t *boundary; ++ unsigned int new_cal; ++ unsigned int i; ++ ++ /* By default: last calibration value */ ++ new_cal = cal; ++ ++ /* Start from Highest cal value */ ++ for (i = 0; i < clk_cal->boundary_max; i++) { ++ boundary = &clk_cal->boundary[i]; ++ ++ if (cal > boundary->x1) { ++ new_cal = boundary->x1; ++ break; ++ } ++ ++ if ((cal > boundary->x2) && (cal <= boundary->x1)) { ++ new_cal = cal - 1; ++ break; ++ } ++ } ++ ++ return new_cal; ++} ++ ++static void rcc_calibration(struct stm32mp1_clk_cal *clk_cal) ++{ ++ unsigned long margin = (clk_cal->ref_freq * clk_cal->freq_margin) / 100; ++ unsigned long min = clk_cal->ref_freq - margin; ++ unsigned long max = clk_cal->ref_freq + margin; ++ unsigned long freq = clk_cal->get_freq(); ++ int cal = clk_cal->get_trim(); ++ unsigned int nb_retries; ++ ++ for (nb_retries = 0; nb_retries < CAL_MAX_RETRY; nb_retries++) { ++ if ((freq >= min) && (freq <= max)) { ++ break; ++ } ++ ++ if (freq < min) { ++ cal = trim_increase(clk_cal, cal); ++ } else { ++ cal = trim_decrease(clk_cal, cal); ++ } ++ ++ clk_cal->set_trim(cal); ++ ++ freq = clk_cal->get_freq(); ++ } ++ ++ if ((freq < min) || (freq > max)) { ++ DMSG("Calibration failed"); ++ panic("Calibration"); ++ } ++} ++ ++static void save_trim(struct stm32mp1_clk_cal *clk_cal, ++ unsigned int i, unsigned int x1, unsigned int x2) ++{ ++ clk_cal->boundary[i].x1 = x1; ++ clk_cal->boundary[i].x2 = x2; ++} ++ ++static int trim_find_prev_boundary(struct stm32mp1_clk_cal *clk_cal, ++ unsigned int x1) ++{ ++ unsigned int x = x1; ++ unsigned long freq; ++ ++ clk_cal->set_trim(x1 + 1); ++ freq = clk_cal->get_freq(); ++ ++ while (x >= (clk_cal->cal_ref + clk_cal->trim_min)) { ++ x--; ++ clk_cal->set_trim(x); ++ ++ if (clk_cal->get_freq() <= freq) { ++ break; ++ } ++ }; ++ ++ return x; ++} ++ ++static void trim_table_init(struct stm32mp1_clk_cal *clk_cal) ++{ ++ uint16_t *trim_fbv = clk_cal->fbv; ++ unsigned int min; ++ unsigned int max; ++ int boundary = 0; ++ int i = 0; ++ ++ max = clk_cal->cal_ref + clk_cal->trim_max; ++ min = clk_cal->cal_ref + clk_cal->trim_min; ++ ++ while (trim_fbv[i]) { ++ unsigned int x; ++ unsigned int x1 = trim_fbv[i]; ++ unsigned int x2 = trim_fbv[i + 1]; ++ ++ if ((max <= x2) || (min >= x1)) { ++ i++; ++ if (boundary != 0) { ++ goto out; ++ } ++ continue; ++ } ++ ++ /* Take forbiden value + 1 */ ++ x2 = x2 + 1; ++ if (x2 < min) { ++ x2 = min; ++ } ++ ++ if (boundary == 0) { ++ /* Save first boundary */ ++ save_trim(clk_cal, boundary, max, x2); ++ boundary++; ++ i++; ++ continue; ++ } ++ ++ x = trim_find_prev_boundary(clk_cal, x1); ++ /* Save boundary values */ ++ save_trim(clk_cal, boundary, x - 1, x2); ++ boundary++; ++ i++; ++ }; ++out: ++ clk_cal->boundary_max = boundary; ++} ++ ++/* Timer countdown/delay argument for the target calibration periodicity */ ++static uint32_t timer_val; ++ ++#define CNTP_CTL_ENABLE BIT(0) ++#define CNTP_CTL_IMASK BIT(1) ++#define CNTP_CTL_ISTATUS BIT(2) ++ ++static void arm_timer(void) ++{ ++ if (!timer_val) ++ return; ++ ++ write_cntp_ctl(read_cntp_ctl() & ~(CNTP_CTL_ENABLE | CNTP_CTL_IMASK)); ++ write_cntp_tval(timer_val); ++ write_cntp_ctl(read_cntp_ctl() | CNTP_CTL_ENABLE); ++} ++ ++static void arm_timer_with_period(uint32_t period_sec) ++{ ++ timer_val = period_sec * read_cntfrq(); ++ ++ arm_timer(); ++} ++ ++static void calib_period(void) ++{ ++ (void)stm32mp_start_clock_calib(CK_HSI); ++ (void)stm32mp_start_clock_calib(CK_CSI); ++ ++ arm_timer(); ++} ++ ++static enum itr_return arm_cntp_it_handler(struct itr_handler *handler __unused) ++{ ++ if (timer_val) ++ calib_period(); ++ ++ return ITRR_HANDLED; ++} ++static struct itr_handler arm_cntp_handler = { ++ .it = GIC_SPI_SEC_PHY_TIMER, ++ .handler = arm_cntp_it_handler, ++}; ++KEEP_PAGER(arm_cntp_handler); ++ ++static void timer_pm(enum pm_op op, void *handle __unused) ++{ ++ if (op != PM_OP_RESUME || !timer_val) ++ return; ++ ++ calib_period(); ++} ++KEEP_PAGER(timer_pm); ++ ++static TEE_Result init_arm_cntp_timer(void) ++{ ++ itr_add(&arm_cntp_handler); ++ itr_enable(arm_cntp_handler.it); ++ ++ stm32mp_register_pm_cb(timer_pm, NULL); ++ ++ return TEE_SUCCESS; ++} ++driver_init(init_arm_cntp_timer); ++ ++static void init_periodic_calibration(void *fdt, int node) ++{ ++ uint32_t period = fdt_read_uint32_default(fdt, node, "st,cal-sec", 0); ++ ++ DMSG("Calib period %us", period); ++ arm_timer_with_period(period); ++} ++ ++int stm32mp_start_clock_calib(unsigned int clock_id) ++{ ++ struct stm32mp1_clk_cal *clk_calib; ++ ++ switch (clock_id) { ++ case CK_HSI: ++ clk_calib = hsi_calib; ++ break; ++ case CK_CSI: ++ clk_calib = csi_calib; ++ break; ++ default: ++ DMSG("Cannot calibrate clock %u", clock_id); ++ return 1; ++ } ++ ++ if (clk_calib->ref_freq == 0U) ++ return 1; ++ ++ DMSG("%s", clock_id == CK_HSI ? "HSI" : "CSI"); ++ rcc_calibration(clk_calib); ++ ++ return 0; ++} ++ ++static void init_hsi_calibration(void *fdt, int node) ++{ ++ if (!fdt_getprop(fdt, node, "st,hsi-cal", NULL)) ++ return; ++ ++ hsi_calib = calloc(1, sizeof(*hsi_calib)); ++ assert(hsi_calib); ++ memcpy(hsi_calib, &hsi_calib_config, sizeof(*hsi_calib)); ++ ++ stm32_timer_freq_func(&hsi_calib->get_freq, HSI_CAL); ++ assert(hsi_calib->get_freq); ++ ++ hsi_calib->ref_freq = stm32mp1_clk_get_rate(CK_HSI); ++ ++ hsi_calib->cal_ref = (mmio_read_32(stm32_rcc_base() + RCC_HSICFGR) & ++ RCC_HSICFGR_HSICAL_MASK) >> ++ RCC_HSICFGR_HSICAL_SHIFT; ++ ++ trim_table_init(hsi_calib); ++ ++ hsi_calib->set_trim(hsi_calib->cal_ref); ++ ++ stm32mp_start_clock_calib(CK_HSI); ++} ++ ++static void init_csi_calibration(void *fdt, int node) ++{ ++ if (!fdt_getprop(fdt, node, "st,csi-cal", NULL)) ++ return; ++ ++ csi_calib = calloc(1, sizeof(*csi_calib)); ++ assert(csi_calib); ++ memcpy(csi_calib, &csi_calib_config, sizeof(*csi_calib)); ++ ++ stm32_timer_freq_func(&csi_calib->get_freq, CSI_CAL); ++ assert(csi_calib->get_freq); ++ ++ csi_calib->ref_freq = stm32mp1_clk_get_rate(CK_CSI); ++ ++ csi_calib->cal_ref = (mmio_read_32(stm32_rcc_base() + RCC_CSICFGR) & ++ RCC_CSICFGR_CSICAL_MASK) >> ++ RCC_CSICFGR_CSICAL_SHIFT; ++ ++ trim_table_init(csi_calib); ++ ++ csi_calib->set_trim(csi_calib->cal_ref); ++ ++ stm32mp_start_clock_calib(CK_CSI); ++} ++ ++static TEE_Result init_stm32mp1_calib(void) ++{ ++ void *fdt; ++ int rcc_node = -1; ++ ++ fdt = get_dt_blob(); ++ if (fdt) ++ rcc_node = fdt_get_rcc_node(fdt); ++ if (rcc_node < 0) ++ panic(); ++ ++ init_hsi_calibration(fdt, rcc_node); ++ init_csi_calibration(fdt, rcc_node); ++ init_periodic_calibration(fdt, rcc_node); ++ ++ return TEE_SUCCESS; ++} ++driver_init(init_stm32mp1_calib); +diff --git a/core/arch/arm/plat-stm32mp1/drivers/stm32mp1_clk.c b/core/arch/arm/plat-stm32mp1/drivers/stm32mp1_clk.c +new file mode 100644 +index 0000000..acf5d60 +--- /dev/null ++++ b/core/arch/arm/plat-stm32mp1/drivers/stm32mp1_clk.c +@@ -0,0 +1,1527 @@ ++// SPDX-License-Identifier: GPL-2.0+ BSD-3-Clause ++/* ++ * Copyright (C) 2017-2018, STMicroelectronics - All Rights Reserved ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#ifdef CFG_DT ++#include ++#include ++#endif ++ ++enum stm32mp1_parent_id { ++/* Oscillators are defined in enum stm32mp_osc_id */ ++ ++/* Other parent source */ ++ _HSI_KER = NB_OSC, ++ _HSE_KER, ++ _HSE_KER_DIV2, ++ _CSI_KER, ++ _PLL1_P, ++ _PLL1_Q, ++ _PLL1_R, ++ _PLL2_P, ++ _PLL2_Q, ++ _PLL2_R, ++ _PLL3_P, ++ _PLL3_Q, ++ _PLL3_R, ++ _PLL4_P, ++ _PLL4_Q, ++ _PLL4_R, ++ _ACLK, ++ _PCLK1, ++ _PCLK2, ++ _PCLK3, ++ _PCLK4, ++ _PCLK5, ++ _HCLK6, ++ _HCLK2, ++ _CK_PER, ++ _CK_MPU, ++ _CK_MCU, ++ _PARENT_NB, ++ _UNKNOWN_ID = 0xff, ++}; ++ ++/* Lists only the parent clock we are interested in */ ++enum stm32mp1_parent_sel { ++ _STGEN_SEL, ++ _I2C46_SEL, ++ _SPI6_SEL, ++ _USART1_SEL, ++ _RNG1_SEL, ++ _UART6_SEL, ++ _UART24_SEL, ++ _UART35_SEL, ++ _UART78_SEL, ++ _ASS_SEL, ++ _MSS_SEL, ++ _USBPHY_SEL, ++ _USBO_SEL, ++ _PARENT_SEL_NB, ++ _UNKNOWN_SEL = 0xff, ++}; ++ ++enum stm32mp1_pll_id { ++ _PLL1, ++ _PLL2, ++ _PLL3, ++ _PLL4, ++ _PLL_NB ++}; ++ ++enum stm32mp1_div_id { ++ _DIV_P, ++ _DIV_Q, ++ _DIV_R, ++ _DIV_NB, ++}; ++ ++enum stm32mp1_clksrc_id { ++ CLKSRC_MPU, ++ CLKSRC_AXI, ++ CLKSRC_MCU, ++ CLKSRC_PLL12, ++ CLKSRC_PLL3, ++ CLKSRC_PLL4, ++ CLKSRC_RTC, ++ CLKSRC_MCO1, ++ CLKSRC_MCO2, ++ CLKSRC_NB ++}; ++ ++enum stm32mp1_clkdiv_id { ++ CLKDIV_MPU, ++ CLKDIV_AXI, ++ CLKDIV_MCU, ++ CLKDIV_APB1, ++ CLKDIV_APB2, ++ CLKDIV_APB3, ++ CLKDIV_APB4, ++ CLKDIV_APB5, ++ CLKDIV_RTC, ++ CLKDIV_MCO1, ++ CLKDIV_MCO2, ++ CLKDIV_NB ++}; ++ ++enum stm32mp1_pllcfg { ++ PLLCFG_M, ++ PLLCFG_N, ++ PLLCFG_P, ++ PLLCFG_Q, ++ PLLCFG_R, ++ PLLCFG_O, ++ PLLCFG_NB ++}; ++ ++enum stm32mp1_pllcsg { ++ PLLCSG_MOD_PER, ++ PLLCSG_INC_STEP, ++ PLLCSG_SSCG_MODE, ++ PLLCSG_NB ++}; ++ ++enum stm32mp1_plltype { ++ PLL_800, ++ PLL_1600, ++ PLL_TYPE_NB ++}; ++ ++struct stm32mp1_pll { ++ uint8_t refclk_min; ++ uint8_t refclk_max; ++ uint8_t divn_max; ++}; ++ ++struct stm32mp1_clk_gate { ++ uint16_t offset; ++ uint8_t bit; ++ uint8_t index; ++ uint8_t set_clr; ++ uint8_t sel; /* Relates to enum stm32mp1_parent_sel */ ++ uint8_t fixed; /* Relates to enum stm32mp1_parent_id */ ++}; ++ ++struct stm32mp1_clk_sel { ++ uint16_t offset; ++ uint8_t src; ++ uint8_t msk; ++ uint8_t nb_parent; ++ const uint8_t *parent; ++}; ++ ++#define REFCLK_SIZE 4 ++struct stm32mp1_clk_pll { ++ enum stm32mp1_plltype plltype; ++ uint16_t rckxselr; ++ uint16_t pllxcfgr1; ++ uint16_t pllxcfgr2; ++ uint16_t pllxfracr; ++ uint16_t pllxcr; ++ uint16_t pllxcsgr; ++ enum stm32mp_osc_id refclk[REFCLK_SIZE]; ++}; ++ ++/* Clocks with selectable source and not set/clr register access */ ++#define _CLK_SELEC(off, b, idx, s) \ ++ { \ ++ .offset = (off), \ ++ .bit = (b), \ ++ .index = (idx), \ ++ .set_clr = 0, \ ++ .sel = (s), \ ++ .fixed = _UNKNOWN_ID, \ ++ } ++ ++/* Clocks with fixed source and not set/clr register access */ ++#define _CLK_FIXED(off, b, idx, f) \ ++ { \ ++ .offset = (off), \ ++ .bit = (b), \ ++ .index = (idx), \ ++ .set_clr = 0, \ ++ .sel = _UNKNOWN_SEL, \ ++ .fixed = (f), \ ++ } ++ ++/* Clocks with selectable source and set/clr register access */ ++#define _CLK_SC_SELEC(off, b, idx, s) \ ++ { \ ++ .offset = (off), \ ++ .bit = (b), \ ++ .index = (idx), \ ++ .set_clr = 1, \ ++ .sel = (s), \ ++ .fixed = _UNKNOWN_ID, \ ++ } ++ ++/* Clocks with fixed source and set/clr register access */ ++#define _CLK_SC_FIXED(off, b, idx, f) \ ++ { \ ++ .offset = (off), \ ++ .bit = (b), \ ++ .index = (idx), \ ++ .set_clr = 1, \ ++ .sel = _UNKNOWN_SEL, \ ++ .fixed = (f), \ ++ } ++ ++/* ++ * Clocks with selectable source and set/clr register access ++ * and enable bit position defined by a label (argument b) ++ */ ++#define _CLK_SC2_SELEC(off, b, idx, s) \ ++ { \ ++ .offset = (off), \ ++ .index = (idx), \ ++ .bit = off ## _ ## b ## _POS, \ ++ .set_clr = 1, \ ++ .sel = (s), \ ++ .fixed = _UNKNOWN_ID, \ ++ } ++#define _CLK_SC2_FIXED(off, b, idx, f) \ ++ { \ ++ .offset = (off), \ ++ .index = (idx), \ ++ .bit = off ## _ ## b ## _POS, \ ++ .set_clr = 1, \ ++ .sel = _UNKNOWN_SEL, \ ++ .fixed = (f), \ ++ } ++ ++#define _CLK_PARENT(idx, off, s, m, p) \ ++ [(idx)] = { \ ++ .offset = (off), \ ++ .src = (s), \ ++ .msk = (m), \ ++ .parent = (p), \ ++ .nb_parent = ARRAY_SIZE(p) \ ++ } ++ ++#define _CLK_PLL(idx, type, off1, off2, off3, \ ++ off4, off5, off6, \ ++ p1, p2, p3, p4) \ ++ [(idx)] = { \ ++ .plltype = (type), \ ++ .rckxselr = (off1), \ ++ .pllxcfgr1 = (off2), \ ++ .pllxcfgr2 = (off3), \ ++ .pllxfracr = (off4), \ ++ .pllxcr = (off5), \ ++ .pllxcsgr = (off6), \ ++ .refclk[0] = (p1), \ ++ .refclk[1] = (p2), \ ++ .refclk[2] = (p3), \ ++ .refclk[3] = (p4), \ ++ } ++ ++static const uint8_t stm32mp1_clks[][2] = { ++ { CK_PER, _CK_PER }, ++ { CK_MPU, _CK_MPU }, ++ { CK_AXI, _ACLK }, ++ { CK_MCU, _CK_MCU }, ++ { CK_HSE, _HSE }, ++ { CK_CSI, _CSI }, ++ { CK_LSI, _LSI }, ++ { CK_LSE, _LSE }, ++ { CK_HSI, _HSI }, ++ { CK_HSE_DIV2, _HSE_KER_DIV2 }, ++}; ++ ++#define NB_GATES ARRAY_SIZE(stm32mp1_clk_gate) ++ ++static const struct stm32mp1_clk_gate stm32mp1_clk_gate[] = { ++ _CLK_FIXED(RCC_DDRITFCR, 0, DDRC1, _ACLK), ++ _CLK_FIXED(RCC_DDRITFCR, 1, DDRC1LP, _ACLK), ++ _CLK_FIXED(RCC_DDRITFCR, 2, DDRC2, _ACLK), ++ _CLK_FIXED(RCC_DDRITFCR, 3, DDRC2LP, _ACLK), ++ _CLK_FIXED(RCC_DDRITFCR, 4, DDRPHYC, _PLL2_R), ++ _CLK_FIXED(RCC_DDRITFCR, 5, DDRPHYCLP, _PLL2_R), ++ _CLK_FIXED(RCC_DDRITFCR, 6, DDRCAPB, _PCLK4), ++ _CLK_FIXED(RCC_DDRITFCR, 7, DDRCAPBLP, _PCLK4), ++ _CLK_FIXED(RCC_DDRITFCR, 8, AXIDCG, _ACLK), ++ _CLK_FIXED(RCC_DDRITFCR, 9, DDRPHYCAPB, _PCLK4), ++ _CLK_FIXED(RCC_DDRITFCR, 10, DDRPHYCAPBLP, _PCLK4), ++ ++ _CLK_SC2_SELEC(RCC_MP_APB5ENSETR, SPI6EN, SPI6_K, _SPI6_SEL), ++ _CLK_SC2_SELEC(RCC_MP_APB5ENSETR, I2C4EN, I2C4_K, _I2C46_SEL), ++ _CLK_SC2_SELEC(RCC_MP_APB5ENSETR, I2C6EN, I2C6_K, _I2C46_SEL), ++ _CLK_SC2_SELEC(RCC_MP_APB5ENSETR, USART1EN, USART1_K, _USART1_SEL), ++ _CLK_SC2_FIXED(RCC_MP_APB5ENSETR, RTCAPBEN, RTCAPB, _PCLK5), ++ _CLK_SC2_FIXED(RCC_MP_APB5ENSETR, TZC1EN, TZC1, _PCLK5), ++ _CLK_SC2_FIXED(RCC_MP_APB5ENSETR, TZC2EN, TZC2, _PCLK5), ++ _CLK_SC2_FIXED(RCC_MP_APB5ENSETR, TZPCEN, TZPC, _PCLK5), ++ _CLK_SC2_FIXED(RCC_MP_APB5ENSETR, IWDG1APBEN, IWDG1, _PCLK5), ++ _CLK_SC2_FIXED(RCC_MP_APB5ENSETR, BSECEN, BSEC, _PCLK5), ++ _CLK_SC2_SELEC(RCC_MP_APB5ENSETR, STGENEN, STGEN_K, _STGEN_SEL), ++ ++ _CLK_SC2_FIXED(RCC_MP_AHB5ENSETR, GPIOZEN, GPIOZ, _PCLK5), ++ _CLK_SC2_FIXED(RCC_MP_AHB5ENSETR, CRYP1EN, CRYP1, _PCLK5), ++ _CLK_SC2_FIXED(RCC_MP_AHB5ENSETR, HASH1EN, HASH1, _PCLK5), ++ _CLK_SC2_SELEC(RCC_MP_AHB5ENSETR, RNG1EN, RNG1_K, _RNG1_SEL), ++ _CLK_SC2_FIXED(RCC_MP_AHB5ENSETR, BKPSRAMEN, BKPSRAM, _PCLK5), ++ ++ /* Non-secure clocks */ ++#ifdef CFG_WITH_NSEC_GPIOS ++ _CLK_SC_FIXED(RCC_MP_AHB4ENSETR, 0, GPIOA, _UNKNOWN_ID), ++ _CLK_SC_FIXED(RCC_MP_AHB4ENSETR, 1, GPIOB, _UNKNOWN_ID), ++ _CLK_SC_FIXED(RCC_MP_AHB4ENSETR, 2, GPIOC, _UNKNOWN_ID), ++ _CLK_SC_FIXED(RCC_MP_AHB4ENSETR, 3, GPIOD, _UNKNOWN_ID), ++ _CLK_SC_FIXED(RCC_MP_AHB4ENSETR, 4, GPIOE, _UNKNOWN_ID), ++ _CLK_SC_FIXED(RCC_MP_AHB4ENSETR, 5, GPIOF, _UNKNOWN_ID), ++ _CLK_SC_FIXED(RCC_MP_AHB4ENSETR, 6, GPIOG, _UNKNOWN_ID), ++ _CLK_SC_FIXED(RCC_MP_AHB4ENSETR, 7, GPIOH, _UNKNOWN_ID), ++ _CLK_SC_FIXED(RCC_MP_AHB4ENSETR, 8, GPIOI, _UNKNOWN_ID), ++ _CLK_SC_FIXED(RCC_MP_AHB4ENSETR, 9, GPIOJ, _UNKNOWN_ID), ++ _CLK_SC_FIXED(RCC_MP_AHB4ENSETR, 10, GPIOK, _UNKNOWN_ID), ++#endif ++#ifdef CFG_WITH_NSEC_UARTS ++ _CLK_SC_SELEC(RCC_MP_APB1ENSETR, 14, USART2_K, _UART24_SEL), ++ _CLK_SC_SELEC(RCC_MP_APB1ENSETR, 15, USART3_K, _UART35_SEL), ++ _CLK_SC_SELEC(RCC_MP_APB1ENSETR, 16, UART4_K, _UART24_SEL), ++ _CLK_SC_SELEC(RCC_MP_APB1ENSETR, 17, UART5_K, _UART35_SEL), ++ _CLK_SC_SELEC(RCC_MP_APB1ENSETR, 18, UART7_K, _UART78_SEL), ++ _CLK_SC_SELEC(RCC_MP_APB1ENSETR, 19, UART8_K, _UART78_SEL), ++ _CLK_SC_SELEC(RCC_MP_APB2ENSETR, 13, USART6_K, _UART6_SEL), ++#endif ++ _CLK_SC_SELEC(RCC_MP_APB4ENSETR, 8, DDRPERFM, _UNKNOWN_SEL), ++ _CLK_SC_SELEC(RCC_MP_APB4ENSETR, 15, IWDG2, _UNKNOWN_SEL), ++ _CLK_SC_SELEC(RCC_MP_APB4ENSETR, 16, USBPHY_K, _USBPHY_SEL), ++ _CLK_SC_SELEC(RCC_MP_AHB2ENSETR, 8, USBO_K, _USBO_SEL), ++ _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), ++}; ++KEEP_PAGER(stm32mp1_clk_gate); ++ ++/* Parents for secure aware clocks in the xxxSELR value ordering */ ++static const uint8_t stgen_parents[] = { ++ _HSI_KER, _HSE_KER ++}; ++ ++static const uint8_t i2c46_parents[] = { ++ _PCLK5, _PLL3_Q, _HSI_KER, _CSI_KER ++}; ++ ++static const uint8_t spi6_parents[] = { ++ _PCLK5, _PLL4_Q, _HSI_KER, _CSI_KER, _HSE_KER, _PLL3_Q ++}; ++ ++static const uint8_t usart1_parents[] = { ++ _PCLK5, _PLL3_Q, _HSI_KER, _CSI_KER, _PLL4_Q, _HSE_KER ++}; ++ ++static const uint8_t rng1_parents[] = { ++ _CSI, _PLL4_R, _LSE, _LSI ++}; ++ ++/* Parents for (some) non-secure clocks */ ++static const uint8_t uart6_parents[] = { ++ _PCLK2, _PLL4_Q, _HSI_KER, _CSI_KER, _HSE_KER ++}; ++ ++static const uint8_t uart234578_parents[] = { ++ _PCLK1, _PLL4_Q, _HSI_KER, _CSI_KER, _HSE_KER ++}; ++ ++static const uint8_t ass_parents[] = { ++ _HSI, _HSE, _PLL2 ++}; ++ ++static const uint8_t mss_parents[] = { ++ _HSI, _HSE, _CSI, _PLL3 ++}; ++ ++static const uint8_t usbphy_parents[] = { ++ _HSE_KER, _PLL4_R, _HSE_KER_DIV2 ++}; ++ ++static const uint8_t usbo_parents[] = { ++ _PLL4_R, _USB_PHY_48 ++}; ++ ++static const struct stm32mp1_clk_sel stm32mp1_clk_sel[_PARENT_SEL_NB] = { ++ /* Secure aware clocks */ ++ _CLK_PARENT(_STGEN_SEL, RCC_STGENCKSELR, 0, 0x3, stgen_parents), ++ _CLK_PARENT(_I2C46_SEL, RCC_I2C46CKSELR, 0, 0x7, i2c46_parents), ++ _CLK_PARENT(_SPI6_SEL, RCC_SPI6CKSELR, 0, 0x7, spi6_parents), ++ _CLK_PARENT(_USART1_SEL, RCC_UART1CKSELR, 0, 0x7, usart1_parents), ++ _CLK_PARENT(_RNG1_SEL, RCC_RNG1CKSELR, 0, 0x3, rng1_parents), ++ /* Always non-secure clocks (maybe used in some way in secure world) */ ++ _CLK_PARENT(_UART6_SEL, RCC_UART6CKSELR, 0, 0x7, uart6_parents), ++ _CLK_PARENT(_UART24_SEL, RCC_UART24CKSELR, 0, 0x7, uart234578_parents), ++ _CLK_PARENT(_UART35_SEL, RCC_UART35CKSELR, 0, 0x7, uart234578_parents), ++ _CLK_PARENT(_UART78_SEL, RCC_UART78CKSELR, 0, 0x7, uart234578_parents), ++ _CLK_PARENT(_ASS_SEL, RCC_ASSCKSELR, 0, 0x3, ass_parents), ++ _CLK_PARENT(_MSS_SEL, RCC_MSSCKSELR, 0, 0x3, mss_parents), ++ _CLK_PARENT(_USBPHY_SEL, RCC_USBCKSELR, 0, 0x3, usbphy_parents), ++ _CLK_PARENT(_USBO_SEL, RCC_USBCKSELR, 4, 0x1, usbo_parents), ++}; ++ ++/* PLLNCFGR2 register divider by output */ ++static const uint8_t pllncfgr2[_DIV_NB] = { ++ [_DIV_P] = RCC_PLLNCFGR2_DIVP_SHIFT, ++ [_DIV_Q] = RCC_PLLNCFGR2_DIVQ_SHIFT, ++ [_DIV_R] = RCC_PLLNCFGR2_DIVR_SHIFT, ++}; ++ ++static const struct stm32mp1_clk_pll stm32mp1_clk_pll[_PLL_NB] = { ++ _CLK_PLL(_PLL1, PLL_1600, ++ RCC_RCK12SELR, RCC_PLL1CFGR1, RCC_PLL1CFGR2, ++ RCC_PLL1FRACR, RCC_PLL1CR, RCC_PLL1CSGR, ++ _HSI, _HSE, _UNKNOWN_OSC_ID, _UNKNOWN_OSC_ID), ++ _CLK_PLL(_PLL2, PLL_1600, ++ RCC_RCK12SELR, RCC_PLL2CFGR1, RCC_PLL2CFGR2, ++ RCC_PLL2FRACR, RCC_PLL2CR, RCC_PLL2CSGR, ++ _HSI, _HSE, _UNKNOWN_OSC_ID, _UNKNOWN_OSC_ID), ++ _CLK_PLL(_PLL3, PLL_800, ++ RCC_RCK3SELR, RCC_PLL3CFGR1, RCC_PLL3CFGR2, ++ RCC_PLL3FRACR, RCC_PLL3CR, RCC_PLL3CSGR, ++ _HSI, _HSE, _CSI, _UNKNOWN_OSC_ID), ++ _CLK_PLL(_PLL4, PLL_800, ++ RCC_RCK4SELR, RCC_PLL4CFGR1, RCC_PLL4CFGR2, ++ RCC_PLL4FRACR, RCC_PLL4CR, RCC_PLL4CSGR, ++ _HSI, _HSE, _CSI, _I2S_CKIN), ++}; ++ ++/* Prescaler table lookups for clock computation */ ++/* div = /1 /2 /4 /8 / 16 /64 /128 /512 */ ++static const uint8_t stm32mp1_mcu_div[16] = { ++ 0, 1, 2, 3, 4, 6, 7, 8, 9, 9, 9, 9, 9, 9, 9, 9 ++}; ++ ++/* div = /1 /2 /4 /8 /16 : same divider for PMU and APBX */ ++#define stm32mp1_mpu_div stm32mp1_mpu_apbx_div ++#define stm32mp1_apbx_div stm32mp1_mpu_apbx_div ++static const uint8_t stm32mp1_mpu_apbx_div[8] = { ++ 0, 1, 2, 3, 4, 4, 4, 4 ++}; ++ ++/* div = /1 /2 /3 /4 */ ++static const uint8_t stm32mp1_axi_div[8] = { ++ 1, 2, 3, 4, 4, 4, 4, 4 ++}; ++ ++#if TRACE_LEVEL >= TRACE_DEBUG ++static const char *const __maybe_unused stm32mp1_clk_parent_name[_PARENT_NB] = { ++ [_HSI] = "HSI", ++ [_HSE] = "HSE", ++ [_CSI] = "CSI", ++ [_LSI] = "LSI", ++ [_LSE] = "LSE", ++ [_I2S_CKIN] = "I2S_CKIN", ++ [_HSI_KER] = "HSI_KER", ++ [_HSE_KER] = "HSE_KER", ++ [_HSE_KER_DIV2] = "HSE_KER_DIV2", ++ [_CSI_KER] = "CSI_KER", ++ [_PLL1_P] = "PLL1_P", ++ [_PLL1_Q] = "PLL1_Q", ++ [_PLL1_R] = "PLL1_R", ++ [_PLL2_P] = "PLL2_P", ++ [_PLL2_Q] = "PLL2_Q", ++ [_PLL2_R] = "PLL2_R", ++ [_PLL3_P] = "PLL3_P", ++ [_PLL3_Q] = "PLL3_Q", ++ [_PLL3_R] = "PLL3_R", ++ [_PLL4_P] = "PLL4_P", ++ [_PLL4_Q] = "PLL4_Q", ++ [_PLL4_R] = "PLL4_R", ++ [_ACLK] = "ACLK", ++ [_PCLK1] = "PCLK1", ++ [_PCLK2] = "PCLK2", ++ [_PCLK3] = "PCLK3", ++ [_PCLK4] = "PCLK4", ++ [_PCLK5] = "PCLK5", ++ [_HCLK6] = "KCLK6", ++ [_HCLK2] = "HCLK2", ++ [_CK_PER] = "CK_PER", ++ [_CK_MPU] = "CK_MPU", ++ [_CK_MCU] = "CK_MCU", ++ [_USB_PHY_48] = "USB_PHY_48", ++}; ++#endif ++ ++/* RCC clock device driver private */ ++static unsigned long stm32mp1_osc[NB_OSC]; ++static unsigned int gate_refcounts[NB_GATES]; ++static unsigned int refcount_lock; ++ ++static const struct stm32mp1_clk_gate *gate_ref(unsigned int idx) ++{ ++ return &stm32mp1_clk_gate[idx]; ++} ++ ++static const struct stm32mp1_clk_sel *clk_sel_ref(unsigned int idx) ++{ ++ return &stm32mp1_clk_sel[idx]; ++} ++ ++static const struct stm32mp1_clk_pll *pll_ref(unsigned int idx) ++{ ++ return &stm32mp1_clk_pll[idx]; ++} ++ ++static unsigned int get_id_from_rcc_bit(unsigned int offset, unsigned int bit) ++{ ++ unsigned int idx; ++ ++ for (idx = 0; idx < NB_GATES; idx++) { ++ const struct stm32mp1_clk_gate *gate = gate_ref(idx); ++ ++ if ((offset == gate->offset) && (bit == gate->bit)) { ++ return gate->index; ++ } ++ ++ if ((gate->set_clr != 0U) && ++ (offset == (gate->offset + RCC_MP_ENCLRR_OFFSET)) && ++ (bit == gate->bit)) { ++ return gate->index; ++ } ++ } ++ ++ /* Currently only supported gated clocks */ ++ return ~0U; ++} ++ ++static unsigned long stm32mp1_clk_get_fixed(enum stm32mp_osc_id idx) ++{ ++ if (idx >= NB_OSC) { ++ DMSG("clk id %d not found", idx); ++ return 0; ++ } ++ ++ return stm32mp1_osc[idx]; ++} ++ ++static int stm32mp1_clk_get_gated_id(unsigned long id) ++{ ++ unsigned int i; ++ ++ for (i = 0; i < NB_GATES; i++) { ++ if (gate_ref(i)->index == id) { ++ return i; ++ } ++ } ++ ++ DMSG("clk id %lu not found", id); ++ return -1; ++} ++ ++static enum stm32mp1_parent_sel stm32mp1_clk_get_sel(int i) ++{ ++ return (enum stm32mp1_parent_sel)(gate_ref(i)->sel); ++} ++ ++static enum stm32mp1_parent_id stm32mp1_clk_get_fixed_parent(int i) ++{ ++ return (enum stm32mp1_parent_id)gate_ref(i)->fixed; ++} ++ ++static int stm32mp1_clk_get_parent(unsigned long id) ++{ ++ const struct stm32mp1_clk_sel *sel; ++ unsigned int j; ++ uint32_t p_sel; ++ int i; ++ enum stm32mp1_parent_id p; ++ enum stm32mp1_parent_sel s; ++ uintptr_t rcc_base = stm32_rcc_base(); ++ ++ for (j = 0U; j < ARRAY_SIZE(stm32mp1_clks); j++) { ++ if (stm32mp1_clks[j][0] == id) { ++ return (int)stm32mp1_clks[j][1]; ++ } ++ } ++ ++ i = stm32mp1_clk_get_gated_id(id); ++ if (i < 0) { ++ panic(); ++ } ++ ++ p = stm32mp1_clk_get_fixed_parent(i); ++ if (p < _PARENT_NB) { ++ return (int)p; ++ } ++ ++ s = stm32mp1_clk_get_sel(i); ++ if (s == _UNKNOWN_SEL) { ++ return -1; ++ } ++ if (s >= _PARENT_SEL_NB) { ++ panic(); ++ } ++ ++ sel = clk_sel_ref(s); ++ p_sel = (mmio_read_32(rcc_base + sel->offset) >> sel->src) & sel->msk; ++ if (p_sel < sel->nb_parent) { ++ return (int)sel->parent[p_sel]; ++ } ++ ++ DMSG("No parent selected for clk %lu", id); ++ return -1; ++} ++ ++static unsigned long stm32mp1_pll_get_fref(const struct stm32mp1_clk_pll *pll) ++{ ++ uint32_t selr = mmio_read_32(stm32_rcc_base() + pll->rckxselr); ++ uint32_t src = selr & RCC_SELR_REFCLK_SRC_MASK; ++ ++ return stm32mp1_clk_get_fixed(pll->refclk[src]); ++} ++ ++/* ++ * pll_get_fvco() : return the VCO or (VCO / 2) frequency for the requested PLL ++ * - PLL1 & PLL2 => return VCO / 2 with Fpll_y_ck = FVCO / 2 * (DIVy + 1) ++ * - PLL3 & PLL4 => return VCO with Fpll_y_ck = FVCO / (DIVy + 1) ++ * => in all cases Fpll_y_ck = pll_get_fvco() / (DIVy + 1) ++ */ ++static unsigned long stm32mp1_pll_get_fvco(const struct stm32mp1_clk_pll *pll) ++{ ++ unsigned long refclk, fvco; ++ uint32_t cfgr1, fracr, divm, divn; ++ ++ cfgr1 = mmio_read_32(stm32_rcc_base() + pll->pllxcfgr1); ++ fracr = mmio_read_32(stm32_rcc_base() + pll->pllxfracr); ++ ++ divm = (cfgr1 & (RCC_PLLNCFGR1_DIVM_MASK)) >> RCC_PLLNCFGR1_DIVM_SHIFT; ++ divn = cfgr1 & RCC_PLLNCFGR1_DIVN_MASK; ++ ++ refclk = stm32mp1_pll_get_fref(pll); ++ ++ /* ++ * With FRACV : ++ * Fvco = Fck_ref * ((DIVN + 1) + FRACV / 2^13) / (DIVM + 1) ++ * Without FRACV ++ * Fvco = Fck_ref * ((DIVN + 1) / (DIVM + 1) ++ */ ++ if ((fracr & RCC_PLLNFRACR_FRACLE) != 0U) { ++ unsigned long long numerator; ++ unsigned long long denominator; ++ uint32_t fracv = (fracr & RCC_PLLNFRACR_FRACV_MASK) >> ++ RCC_PLLNFRACR_FRACV_SHIFT; ++ ++ numerator = (((unsigned long long)divn + 1U) << 13) + fracv; ++ numerator = refclk * numerator; ++ denominator = ((unsigned long long)divm + 1U) << 13; ++ fvco = (unsigned long)(numerator / denominator); ++ } else { ++ fvco = (unsigned long)(refclk * (divn + 1U) / (divm + 1U)); ++ } ++ ++ return fvco; ++} ++ ++static unsigned long stm32mp1_read_pll_freq(enum stm32mp1_pll_id pll_id, ++ enum stm32mp1_div_id div_id) ++{ ++ const struct stm32mp1_clk_pll *pll = pll_ref(pll_id); ++ unsigned long dfout; ++ uint32_t cfgr2, divy; ++ ++ if (div_id >= _DIV_NB) { ++ return 0; ++ } ++ ++ cfgr2 = mmio_read_32(stm32_rcc_base() + pll->pllxcfgr2); ++ divy = (cfgr2 >> pllncfgr2[div_id]) & RCC_PLLNCFGR2_DIVX_MASK; ++ ++ dfout = stm32mp1_pll_get_fvco(pll) / (divy + 1U); ++ ++ return dfout; ++} ++ ++static unsigned long get_clock_rate(int p) ++{ ++ uint32_t reg, clkdiv; ++ unsigned long clock = 0; ++ uintptr_t rcc_base = stm32_rcc_base(); ++ ++ switch (p) { ++ case _CK_MPU: ++ /* MPU sub system */ ++ reg = mmio_read_32(rcc_base + RCC_MPCKSELR); ++ switch (reg & RCC_SELR_SRC_MASK) { ++ case RCC_MPCKSELR_HSI: ++ clock = stm32mp1_clk_get_fixed(_HSI); ++ break; ++ case RCC_MPCKSELR_HSE: ++ clock = stm32mp1_clk_get_fixed(_HSE); ++ break; ++ case RCC_MPCKSELR_PLL: ++ clock = stm32mp1_read_pll_freq(_PLL1, _DIV_P); ++ break; ++ case RCC_MPCKSELR_PLL_MPUDIV: ++ clock = stm32mp1_read_pll_freq(_PLL1, _DIV_P); ++ ++ reg = mmio_read_32(rcc_base + RCC_MPCKDIVR); ++ clkdiv = reg & RCC_MPUDIV_MASK; ++ if (clkdiv != 0U) { ++ clock /= stm32mp1_mpu_div[clkdiv]; ++ } ++ break; ++ default: ++ break; ++ } ++ break; ++ /* AXI sub system */ ++ case _ACLK: ++ case _HCLK2: ++ case _HCLK6: ++ case _PCLK4: ++ case _PCLK5: ++ reg = mmio_read_32(rcc_base + RCC_ASSCKSELR); ++ switch (reg & RCC_SELR_SRC_MASK) { ++ case RCC_ASSCKSELR_HSI: ++ clock = stm32mp1_clk_get_fixed(_HSI); ++ break; ++ case RCC_ASSCKSELR_HSE: ++ clock = stm32mp1_clk_get_fixed(_HSE); ++ break; ++ case RCC_ASSCKSELR_PLL: ++ clock = stm32mp1_read_pll_freq(_PLL2, _DIV_P); ++ break; ++ default: ++ break; ++ } ++ ++ /* System clock divider */ ++ reg = mmio_read_32(rcc_base + RCC_AXIDIVR); ++ clock /= stm32mp1_axi_div[reg & RCC_AXIDIV_MASK]; ++ ++ switch (p) { ++ case _PCLK4: ++ reg = mmio_read_32(rcc_base + RCC_APB4DIVR); ++ clock >>= stm32mp1_apbx_div[reg & RCC_APBXDIV_MASK]; ++ break; ++ case _PCLK5: ++ reg = mmio_read_32(rcc_base + RCC_APB5DIVR); ++ clock >>= stm32mp1_apbx_div[reg & RCC_APBXDIV_MASK]; ++ break; ++ default: ++ break; ++ } ++ break; ++ /* MCU sub system */ ++ case _CK_MCU: ++ case _PCLK1: ++ case _PCLK2: ++ case _PCLK3: ++ reg = mmio_read_32(rcc_base + RCC_MSSCKSELR); ++ switch (reg & RCC_SELR_SRC_MASK) { ++ case RCC_MSSCKSELR_HSI: ++ clock = stm32mp1_clk_get_fixed(_HSI); ++ break; ++ case RCC_MSSCKSELR_HSE: ++ clock = stm32mp1_clk_get_fixed(_HSE); ++ break; ++ case RCC_MSSCKSELR_CSI: ++ clock = stm32mp1_clk_get_fixed(_CSI); ++ break; ++ case RCC_MSSCKSELR_PLL: ++ clock = stm32mp1_read_pll_freq(_PLL3, _DIV_P); ++ break; ++ default: ++ break; ++ } ++ ++ /* MCU clock divider */ ++ reg = mmio_read_32(rcc_base + RCC_MCUDIVR); ++ clock >>= stm32mp1_mcu_div[reg & RCC_MCUDIV_MASK]; ++ ++ switch (p) { ++ case _PCLK1: ++ reg = mmio_read_32(rcc_base + RCC_APB1DIVR); ++ clock >>= stm32mp1_apbx_div[reg & RCC_APBXDIV_MASK]; ++ break; ++ case _PCLK2: ++ reg = mmio_read_32(rcc_base + RCC_APB2DIVR); ++ clock >>= stm32mp1_apbx_div[reg & RCC_APBXDIV_MASK]; ++ break; ++ case _PCLK3: ++ reg = mmio_read_32(rcc_base + RCC_APB3DIVR); ++ clock >>= stm32mp1_apbx_div[reg & RCC_APBXDIV_MASK]; ++ break; ++ case _CK_MCU: ++ default: ++ break; ++ } ++ break; ++ case _CK_PER: ++ reg = mmio_read_32(rcc_base + RCC_CPERCKSELR); ++ switch (reg & RCC_SELR_SRC_MASK) { ++ case RCC_CPERCKSELR_HSI: ++ clock = stm32mp1_clk_get_fixed(_HSI); ++ break; ++ case RCC_CPERCKSELR_HSE: ++ clock = stm32mp1_clk_get_fixed(_HSE); ++ break; ++ case RCC_CPERCKSELR_CSI: ++ clock = stm32mp1_clk_get_fixed(_CSI); ++ break; ++ default: ++ break; ++ } ++ break; ++ case _HSI: ++ case _HSI_KER: ++ clock = stm32mp1_clk_get_fixed(_HSI); ++ break; ++ case _CSI: ++ case _CSI_KER: ++ clock = stm32mp1_clk_get_fixed(_CSI); ++ break; ++ case _HSE: ++ case _HSE_KER: ++ clock = stm32mp1_clk_get_fixed(_HSE); ++ break; ++ case _HSE_KER_DIV2: ++ clock = stm32mp1_clk_get_fixed(_HSE) >> 1; ++ break; ++ case _LSI: ++ clock = stm32mp1_clk_get_fixed(_LSI); ++ break; ++ case _LSE: ++ clock = stm32mp1_clk_get_fixed(_LSE); ++ break; ++ /* PLL */ ++ case _PLL1_P: ++ clock = stm32mp1_read_pll_freq(_PLL1, _DIV_P); ++ break; ++ case _PLL1_Q: ++ clock = stm32mp1_read_pll_freq(_PLL1, _DIV_Q); ++ break; ++ case _PLL1_R: ++ clock = stm32mp1_read_pll_freq(_PLL1, _DIV_R); ++ break; ++ case _PLL2_P: ++ clock = stm32mp1_read_pll_freq(_PLL2, _DIV_P); ++ break; ++ case _PLL2_Q: ++ clock = stm32mp1_read_pll_freq(_PLL2, _DIV_Q); ++ break; ++ case _PLL2_R: ++ clock = stm32mp1_read_pll_freq(_PLL2, _DIV_R); ++ break; ++ case _PLL3_P: ++ clock = stm32mp1_read_pll_freq(_PLL3, _DIV_P); ++ break; ++ case _PLL3_Q: ++ clock = stm32mp1_read_pll_freq(_PLL3, _DIV_Q); ++ break; ++ case _PLL3_R: ++ clock = stm32mp1_read_pll_freq(_PLL3, _DIV_R); ++ break; ++ case _PLL4_P: ++ clock = stm32mp1_read_pll_freq(_PLL4, _DIV_P); ++ break; ++ case _PLL4_Q: ++ clock = stm32mp1_read_pll_freq(_PLL4, _DIV_Q); ++ break; ++ case _PLL4_R: ++ clock = stm32mp1_read_pll_freq(_PLL4, _DIV_R); ++ break; ++ /* Other */ ++ case _USB_PHY_48: ++ clock = stm32mp1_clk_get_fixed(_USB_PHY_48); ++ break; ++ default: ++ break; ++ } ++ ++ return clock; ++} ++ ++static void __clk_enable(struct stm32mp1_clk_gate const *gate) ++{ ++ uintptr_t base = stm32_rcc_base(); ++ uint32_t bit = BIT(gate->bit); ++ ++ if (gate->set_clr != 0U) { ++ mmio_write_32(base + gate->offset, bit); ++ } else { ++ io_mask32_stm32shregs(base + gate->offset, bit, bit); ++ } ++ ++ FMSG("Clock %u has been enabled", gate->index); ++} ++ ++static void __clk_disable(struct stm32mp1_clk_gate const *gate) ++{ ++ uintptr_t base = stm32_rcc_base(); ++ uint32_t bit = BIT(gate->bit); ++ ++ if (gate->set_clr != 0U) { ++ mmio_write_32(base + gate->offset + RCC_MP_ENCLRR_OFFSET, bit); ++ } else { ++ io_mask32_stm32shregs(base + gate->offset, 0, bit); ++ } ++ ++ FMSG("Clock %u has been disabled", gate->index); ++} ++ ++static bool __clk_is_enabled(struct stm32mp1_clk_gate const *gate) ++{ ++ uintptr_t base = stm32_rcc_base(); ++ ++ return mmio_read_32(base + gate->offset) & BIT(gate->bit); ++} ++ ++bool stm32mp1_clk_is_enabled(unsigned long id) ++{ ++ int i = stm32mp1_clk_get_gated_id(id); ++ ++ if (i < 0) { ++ return false; ++ } ++ ++ return __clk_is_enabled(gate_ref(i)); ++} ++ ++unsigned int stm32mp1_clk_get_refcount(unsigned long id) ++{ ++ int i = stm32mp1_clk_get_gated_id(id); ++ ++ return gate_refcounts[i]; ++} ++ ++void __stm32mp1_clk_enable(unsigned long id, bool secure) ++{ ++ int i = stm32mp1_clk_get_gated_id(id); ++ uint32_t exceptions; ++ ++ if (i < 0) { ++ DMSG("Invalid clock %lu: %d", id, i); ++ panic(); ++ } ++ ++ exceptions = may_spin_lock(&refcount_lock); ++ ++ if (incr_shrefcnt(&gate_refcounts[i], secure) != 0) { ++ __clk_enable(gate_ref(i)); ++ } ++ ++ may_spin_unlock(&refcount_lock, exceptions); ++} ++ ++void __stm32mp1_clk_disable(unsigned long id, bool secure) ++{ ++ int i = stm32mp1_clk_get_gated_id(id); ++ uint32_t exceptions; ++ ++ if (i < 0) { ++ DMSG("Invalid clock %lu: %d", id, i); ++ panic(); ++ } ++ ++ exceptions = may_spin_lock(&refcount_lock); ++ ++ if (decr_shrefcnt(&gate_refcounts[i], secure) != 0) { ++ __clk_disable(gate_ref(i)); ++ } ++ ++ may_spin_unlock(&refcount_lock, exceptions); ++} ++ ++static long get_timer_rate(long parent_rate, unsigned int apb_bus) ++{ ++ uint32_t timgxpre; ++ uint32_t apbxdiv; ++ uintptr_t rcc_base = stm32_rcc_base(); ++ ++ switch (apb_bus) { ++ case 1: ++ apbxdiv = mmio_read_32(rcc_base + RCC_APB1DIVR) & ++ RCC_APBXDIV_MASK; ++ timgxpre = mmio_read_32(rcc_base + RCC_TIMG1PRER) & ++ RCC_TIMGXPRER_TIMGXPRE; ++ break; ++ case 2: ++ apbxdiv = mmio_read_32(rcc_base + RCC_APB2DIVR) & ++ RCC_APBXDIV_MASK; ++ timgxpre = mmio_read_32(rcc_base + RCC_TIMG2PRER) & ++ RCC_TIMGXPRER_TIMGXPRE; ++ break; ++ default: ++ panic(); ++ break; ++ } ++ ++ if (apbxdiv == 0) { ++ return parent_rate; ++ } ++ ++ return parent_rate * (timgxpre + 1) * 2; ++} ++ ++unsigned long stm32mp1_clk_get_rate(unsigned long id) ++{ ++ int p; ++ unsigned long rate; ++ ++ p = stm32mp1_clk_get_parent(id); ++ if (p < 0) { ++ return 0; ++ } ++ ++ rate = get_clock_rate(p); ++ ++ if ((id >= TIM2_K) && (id <= TIM14_K)) { ++ rate = get_timer_rate(rate, 1); ++ } ++ if ((id >= TIM1_K) && (id <= TIM17_K)) { ++ rate = get_timer_rate(rate, 2); ++ } ++ ++ return rate; ++} ++ ++#ifdef CFG_DT ++static void stm32mp1_osc_clk_init(const char *name, ++ enum stm32mp_osc_id index) ++{ ++ uint32_t frequency; ++ void *fdt; ++ ++ fdt = get_dt_blob(); ++ if (fdt == NULL) { ++ panic(); ++ } ++ ++ stm32mp1_osc[index] = 0; ++ ++ if (fdt_osc_read_freq(fdt, name, &frequency) == 0) { ++ stm32mp1_osc[index] = frequency; ++ } ++} ++ ++static void stm32mp1_osc_init(void) ++{ ++ enum stm32mp_osc_id i; ++ char **name __maybe_unused = (char **)&stm32mp_osc_node_label[0]; ++ ++ for (i = (enum stm32mp_osc_id)0 ; i < NB_OSC; i++) { ++ stm32mp1_osc_clk_init(stm32mp_osc_node_label[i], i); ++ DMSG("Osc %s frequency: %lu", name[i], stm32mp1_osc[i]); ++ } ++} ++#else ++static void stm32mp1_osc_init(void) ++{ ++} ++#endif ++ ++/* ++ * Lookup platform clock from enable bit location in RCC registers. ++ * Return a valid clock ID on success, return ~0 on error. ++ */ ++unsigned long stm32mp1_clk_rcc2id(size_t offset, size_t bit) ++{ ++ return get_id_from_rcc_bit(offset, bit); ++} ++ ++/* ++ * Get the parent ID of the target parent clock, for tagging as secure ++ * shared clock dependencies. ++ */ ++static int get_parent_id_parent(unsigned int parent_id) ++{ ++ enum stm32mp1_parent_sel s = _UNKNOWN_SEL; ++ enum stm32mp1_pll_id pll_id; ++ uint32_t p_sel; ++ ++ switch (parent_id) { ++ case _ACLK: ++ case _PCLK4: ++ case _PCLK5: ++ s = _ASS_SEL; ++ break; ++ case _PLL1_P: ++ case _PLL1_Q: ++ case _PLL1_R: ++ pll_id = _PLL1; ++ break; ++ case _PLL2_P: ++ case _PLL2_Q: ++ case _PLL2_R: ++ pll_id = _PLL2; ++ break; ++ case _PLL3_P: ++ case _PLL3_Q: ++ case _PLL3_R: ++ pll_id = _PLL3; ++ break; ++ case _PLL4_P: ++ case _PLL4_Q: ++ case _PLL4_R: ++ pll_id = _PLL4; ++ break; ++ case _PCLK1: ++ case _PCLK2: ++ case _HCLK2: ++ case _HCLK6: ++ case _CK_PER: ++ case _CK_MPU: ++ case _CK_MCU: ++ case _USB_PHY_48: ++ /* We do not expected to access these */ ++ panic(); ++ break; ++ default: ++ /* Other parents have no parent */ ++ return -1; ++ } ++ ++ if (s != _UNKNOWN_SEL) { ++ const struct stm32mp1_clk_sel *sel = clk_sel_ref(s); ++ uintptr_t rcc_base = stm32_rcc_base(); ++ ++ p_sel = (mmio_read_32(rcc_base + sel->offset) >> sel->src) & ++ sel->msk; ++ ++ if (p_sel < sel->nb_parent) { ++ return (int)sel->parent[p_sel]; ++ } ++ } else { ++ const struct stm32mp1_clk_pll *pll = pll_ref(pll_id); ++ ++ p_sel = mmio_read_32(stm32_rcc_base() + pll->rckxselr) & ++ RCC_SELR_REFCLK_SRC_MASK; ++ ++ if (pll->refclk[p_sel] != _UNKNOWN_OSC_ID) { ++ return (int)pll->refclk[p_sel]; ++ } ++ } ++ ++ FMSG("No parent selected for %s", stm32mp1_clk_parent_name[parent_id]); ++ return -1; ++} ++ ++static void secure_parent_clocks(unsigned long parent_id) ++{ ++ int grandparent_id; ++ ++ switch (parent_id) { ++ /* Secure only the parents for these clocks */ ++ case _ACLK: ++ case _HCLK2: ++ case _HCLK6: ++ case _PCLK4: ++ case _PCLK5: ++ break; ++ /* PLLs */ ++ case _PLL1_P: ++ stm32mp_register_secure_periph(STM32MP1_SHRES_PLL1_P); ++ break; ++ case _PLL1_Q: ++ stm32mp_register_secure_periph(STM32MP1_SHRES_PLL1_Q); ++ break; ++ case _PLL1_R: ++ stm32mp_register_secure_periph(STM32MP1_SHRES_PLL1_R); ++ break; ++ ++ case _PLL2_P: ++ stm32mp_register_secure_periph(STM32MP1_SHRES_PLL2_P); ++ break; ++ case _PLL2_Q: ++ stm32mp_register_secure_periph(STM32MP1_SHRES_PLL2_Q); ++ break; ++ case _PLL2_R: ++ stm32mp_register_secure_periph(STM32MP1_SHRES_PLL2_R); ++ break; ++ ++ case _PLL3_P: ++ stm32mp_register_secure_periph(STM32MP1_SHRES_PLL3_P); ++ break; ++ case _PLL3_Q: ++ stm32mp_register_secure_periph(STM32MP1_SHRES_PLL3_Q); ++ break; ++ case _PLL3_R: ++ stm32mp_register_secure_periph(STM32MP1_SHRES_PLL3_R); ++ break; ++ ++ /* Source clocks */ ++ case _HSI: ++ case _HSI_KER: ++ stm32mp_register_secure_periph(STM32MP1_SHRES_HSI); ++ break; ++ case _LSI: ++ stm32mp_register_secure_periph(STM32MP1_SHRES_LSI); ++ break; ++ case _CSI: ++ case _CSI_KER: ++ stm32mp_register_secure_periph(STM32MP1_SHRES_CSI); ++ break; ++ case _HSE: ++ case _HSE_KER: ++ case _HSE_KER_DIV2: ++ stm32mp_register_secure_periph(STM32MP1_SHRES_HSE); ++ break; ++ case _LSE: ++ stm32mp_register_secure_periph(STM32MP1_SHRES_LSE); ++ break; ++ ++ default: ++ panic(); ++ } ++ ++ grandparent_id = get_parent_id_parent(parent_id); ++ if (grandparent_id >= 0) { ++ secure_parent_clocks(grandparent_id); ++ } ++} ++ ++void stm32mp_register_clock_parents_secure(unsigned long clock_id) ++{ ++ int parent_id; ++ ++ switch (clock_id) { ++ case PLL1: ++ parent_id = get_parent_id_parent(_PLL1_P); ++ break; ++ case PLL2: ++ parent_id = get_parent_id_parent(_PLL2_P); ++ break; ++ case PLL3: ++ parent_id = get_parent_id_parent(_PLL3_P); ++ break; ++ case PLL4: ++ EMSG("PLL4 cannot be secure"); ++ panic(); ++ default: ++ /* Others are expected gateable clock */ ++ parent_id = stm32mp1_clk_get_parent(clock_id); ++ break; ++ } ++ ++ if (parent_id < 0) { ++ DMSG("No parent for clock %lu", clock_id); ++ panic(); ++ } ++ ++ secure_parent_clocks(parent_id); ++} ++ ++#ifdef CFG_DT ++/* ++ * Check that the device tree does not provide clock tree configuration ++ * information. Such configuration would not be applied since the early boot ++ * loader is in charge of configuring the clock tree and enabling the PLLs. ++ */ ++static void init_clock_tree_from_dt(void) ++{ ++ void *fdt; ++ uintptr_t rcc_base = stm32_rcc_base(); ++ int node = -1; ++ unsigned int i; ++ int len; ++ int ignored = 0; ++ ++ fdt = get_dt_blob(); ++ if (fdt != NULL) { ++ node = fdt_get_rcc_node(fdt); ++ } ++ ++ if ((fdt == NULL) || (node < 0)) { ++ panic("RCC DT"); ++ } ++ ++ if ((_fdt_get_status(fdt, node) & DT_STATUS_OK_SEC) == 0) { ++ panic("RCC disabled"); ++ } ++ ++ assert(virt_to_phys((void *)stm32_rcc_base()) == ++ fdt_rcc_read_addr(fdt)); ++ ++ /* Expect booting from a secure setup */ ++ if ((mmio_read_32(rcc_base + RCC_TZCR) & RCC_TZCR_TZEN) == 0) { ++ panic("RCC TZC[TZEN]"); ++ } ++ ++ /* Get oscillator frequency to handle freq get/set operations */ ++ stm32mp1_osc_init(); ++ ++ node = fdt_get_rcc_node(fdt); ++ assert(node >= 0); ++ ++ /* ++ * OP-TEE core is not in charge of the clock tree configuration. ++ * This is expected from an earlier boot stage. Modifying the clock ++ * tree here may jeopardize the already configured clock tree. ++ * The sequence below ignores such DT directives with a friendly ++ * debug trace. ++ */ ++ if (fdt_getprop(fdt, node, "st,clksrc", &len)) { ++ DMSG("Ignore source clocks configuration from DT"); ++ ignored++; ++ } ++ if (fdt_getprop(fdt, node, "st,clkdiv", &len)) { ++ DMSG("Ignore clock divisors configuration from DT"); ++ ignored++; ++ } ++ if (fdt_getprop(fdt, node, "st,pkcs", &len)) { ++ DMSG("Ignore peripheral clocks tree configuration from DT"); ++ ignored++; ++ } ++ for (i = (enum stm32mp1_pll_id)0; i < _PLL_NB; i++) { ++ char name[12]; ++ ++ snprintf(name, sizeof(name), "st,pll@%d", i); ++ node = fdt_rcc_subnode_offset(fdt, name); ++ ++ if (node <= 0) { ++ continue; ++ } ++ ++ if (fdt_getprop(fdt, node, "cfg", &len) || ++ fdt_getprop(fdt, node, "frac", &len)) { ++ DMSG("Ignore PLL%u configurations from DT", i); ++ ignored++; ++ } ++ } ++ ++ if (ignored != 0) { ++ IMSG("DT clock tree configurations were ignored"); ++ } ++} ++#else ++static void init_clock_tree_from_dt(void) ++{ ++ uintptr_t rcc_base = stm32_rcc_base(); ++ ++ /* Expect booting from a secure setup */ ++ if ((mmio_read_32(rcc_base + RCC_TZCR) & RCC_TZCR_TZEN) == 0) { ++ panic("RCC TZC[TZEN]"); ++ } ++} ++#endif /*CFG_DT*/ ++ ++/* Sync secure clock refcount after all drivers probe/inits, */ ++void stm32mp_update_earlyboot_clocks_state(void) ++{ ++ unsigned int idx; ++ ++ for (idx = 0; idx < NB_GATES; idx++) { ++ unsigned long clock_id = gate_ref(idx)->index; ++ ++ /* ++ * Drop non-secure refcount set on shareable clocks that are ++ * not shared. Secure clock should not hold a non-secure ++ * refcount. Non-secure clock cannot hold any refcount. ++ */ ++ if (__clk_is_enabled(gate_ref(idx)) && ++ stm32mp_clock_is_shareable(clock_id) && ++ !stm32mp_clock_is_shared(clock_id)) { ++ stm32mp1_clk_disable_non_secure(clock_id); ++ } ++ ++ /* ++ * Disable secure clocks enabled from early boot but not explicitly ++ * enabled from the secure world. ++ */ ++ if (__clk_is_enabled(gate_ref(idx)) && ++ !stm32mp_clock_is_non_secure(clock_id) && ++ !gate_refcounts[idx]) { ++ __clk_disable(gate_ref(idx)); ++ } ++ } ++ ++ /* Dump clocks state */ ++ for (idx = 0; idx < NB_GATES; idx++) { ++ unsigned long __maybe_unused clock_id = gate_ref(idx)->index; ++ int __maybe_unused p = stm32mp1_clk_get_parent(clock_id); ++ ++ FMSG("stm32mp clock %3lu is %sabled (refcnt %d) (parent %d %s)", ++ clock_id, ++ __clk_is_enabled(gate_ref(idx)) ? "en" : "dis", ++ gate_refcounts[idx], ++ p, p < 0 ? "n.a" : stm32mp1_clk_parent_name[p]); ++ } ++} ++ ++/* Set a non-secure refcount on shareable clock that were enabled from boot */ ++static void sync_earlyboot_clocks_state(void) ++{ ++ unsigned int idx; ++ ++ for (idx = 0; idx < NB_GATES; idx++) { ++ assert(!gate_refcounts[idx]); ++ } ++ ++ /* ++ * Set a non-secure refcount for shareable clocks enabled from boot. ++ * It will be dropped after core inits for secure-only clocks. ++ */ ++ for (idx = 0; idx < NB_GATES; idx++) { ++ struct stm32mp1_clk_gate const *gate = gate_ref(idx); ++ ++ if (__clk_is_enabled(gate) && ++ stm32mp_clock_is_shareable(gate->index)) { ++ gate_refcounts[idx] = SHREFCNT_NONSECURE_FLAG; ++ } ++ } ++ ++ /* ++ * Register secure clock parents and init a refcount for ++ * secure only resources that are not registered from a driver probe. ++ * - DDR controller and phy clocks. ++ * - TZC400, ETZPC and STGEN clocks. ++ * - RTCAPB clocks on multi-core ++ */ ++ stm32mp_register_clock_parents_secure(DDRC1); ++ stm32mp1_clk_enable_secure(DDRC1); ++ stm32mp_register_clock_parents_secure(DDRC1LP); ++ stm32mp1_clk_enable_secure(DDRC1LP); ++ stm32mp_register_clock_parents_secure(DDRC2); ++ stm32mp1_clk_enable_secure(DDRC2); ++ stm32mp_register_clock_parents_secure(DDRC2LP); ++ stm32mp1_clk_enable_secure(DDRC2LP); ++ stm32mp_register_clock_parents_secure(DDRPHYC); ++ stm32mp1_clk_enable_secure(DDRPHYC); ++ stm32mp_register_clock_parents_secure(DDRPHYCLP); ++ stm32mp1_clk_enable_secure(DDRPHYCLP); ++ stm32mp_register_clock_parents_secure(DDRCAPB); ++ stm32mp1_clk_enable_secure(DDRCAPB); ++ stm32mp_register_clock_parents_secure(AXIDCG); ++ stm32mp1_clk_enable_secure(AXIDCG); ++ stm32mp_register_clock_parents_secure(DDRPHYCAPB); ++ stm32mp1_clk_enable_secure(DDRPHYCAPB); ++ stm32mp_register_clock_parents_secure(DDRPHYCAPBLP); ++ stm32mp1_clk_enable_secure(DDRPHYCAPBLP); ++ ++ stm32mp_register_clock_parents_secure(TZPC); ++ stm32mp1_clk_enable_secure(TZPC); ++ stm32mp_register_clock_parents_secure(TZC1); ++ stm32mp1_clk_enable_secure(TZC1); ++ stm32mp_register_clock_parents_secure(TZC2); ++ stm32mp1_clk_enable_secure(TZC2); ++ stm32mp_register_clock_parents_secure(STGEN_K); ++ stm32mp1_clk_enable_secure(STGEN_K); ++ ++ stm32mp_register_clock_parents_secure(BSEC); ++ stm32mp1_clk_enable_secure(BSEC); ++ ++ 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); ++} ++ ++static void _clock_resume(void) ++{ ++ unsigned int idx; ++ ++ /* Sync secure and shared clocks physical state on functional state */ ++ for (idx = 0; idx < NB_GATES; idx++) { ++ struct stm32mp1_clk_gate const *gate = gate_ref(idx); ++ ++ if (stm32mp_clock_is_non_secure(gate->index)) { ++ continue; ++ } ++ ++ if (gate_refcounts[idx]) { ++ DMSG("Force clock %d enable", gate->index); ++ __clk_enable(gate); ++ } else { ++ DMSG("Force clock %d disable", gate->index); ++ __clk_disable(gate); ++ } ++ } ++} ++ ++void stm32mp_clock_suspend_resume(enum pm_op op) ++{ ++ switch (op) { ++ case PM_OP_SUSPEND: ++ /* Nothing to do */ ++ break; ++ case PM_OP_RESUME: ++ _clock_resume(); ++ break; ++ default: ++ panic(); ++ } ++} ++ ++static TEE_Result stm32mp1_clk_probe(void) ++{ ++ init_clock_tree_from_dt(); ++ ++ sync_earlyboot_clocks_state(); ++ ++ return TEE_SUCCESS; ++} ++/* Setup clock support before driver initialization */ ++service_init(stm32mp1_clk_probe); ++ +diff --git a/core/arch/arm/plat-stm32mp1/drivers/stm32mp1_clk.h b/core/arch/arm/plat-stm32mp1/drivers/stm32mp1_clk.h +new file mode 100644 +index 0000000..783d81d +--- /dev/null ++++ b/core/arch/arm/plat-stm32mp1/drivers/stm32mp1_clk.h +@@ -0,0 +1,62 @@ ++/* SPDX-License-Identifier: BSD-3-Clause */ ++/* ++ * Copyright (C) 2018, STMicroelectronics - All Rights Reserved ++ */ ++ ++#ifndef __STM32MP1_CLK_H__ ++#define __STM32MP1_CLK_H__ ++ ++#include ++#include ++#include ++ ++enum stm32mp_osc_id { ++ _HSI, ++ _HSE, ++ _CSI, ++ _LSI, ++ _LSE, ++ _I2S_CKIN, ++ _USB_PHY_48, ++ NB_OSC, ++ _UNKNOWN_OSC_ID = 0xFF ++}; ++ ++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); ++ ++static inline void stm32mp1_clk_enable_non_secure(unsigned long id) ++{ ++ __stm32mp1_clk_enable(id, false); ++} ++ ++static inline void stm32mp1_clk_enable_secure(unsigned long id) ++{ ++ __stm32mp1_clk_enable(id, true); ++} ++ ++static inline void stm32mp1_clk_disable_non_secure(unsigned long id) ++{ ++ __stm32mp1_clk_disable(id, false); ++} ++ ++static inline void stm32mp1_clk_disable_secure(unsigned long id) ++{ ++ __stm32mp1_clk_disable(id, true); ++} ++ ++unsigned int stm32mp1_clk_get_refcount(unsigned long id); ++ ++unsigned long stm32mp1_clk_get_rate(unsigned long id); ++ ++unsigned long stm32mp1_clk_rcc2id(size_t offset, size_t bit); ++ ++void stm32mp_register_clock_parents_secure(unsigned long id); ++ ++void stm32mp_update_earlyboot_clocks_state(void); ++ ++void stm32mp1_clock_suspend(void); ++void stm32mp1_clock_resume(void); ++ ++#endif /* __STM32MP1_CLK_H__ */ +diff --git a/core/arch/arm/plat-stm32mp1/drivers/stm32mp1_clkfunc.c b/core/arch/arm/plat-stm32mp1/drivers/stm32mp1_clkfunc.c +new file mode 100644 +index 0000000..c83d561 +--- /dev/null ++++ b/core/arch/arm/plat-stm32mp1/drivers/stm32mp1_clkfunc.c +@@ -0,0 +1,340 @@ ++// SPDX-License-Identifier: BSD-3-Clause ++/* ++ * Copyright (c) 2017-2018, STMicroelectronics - All Rights Reserved ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define DT_RCC_NODE_NAME "rcc@50000000" ++#define DT_RCC_CLK_COMPAT "st,stm32mp1-rcc" ++#define DT_RCC_COMPAT "syscon" ++#define DT_STGEN_COMPAT "st,stm32-stgen" ++#define DT_UART_COMPAT "st,stm32h7-uart" ++ ++const char *stm32mp_osc_node_label[NB_OSC] = { ++ [_LSI] = "clk-lsi", ++ [_LSE] = "clk-lse", ++ [_HSI] = "clk-hsi", ++ [_HSE] = "clk-hse", ++ [_CSI] = "clk-csi", ++ [_I2S_CKIN] = "i2s_ckin", ++ [_USB_PHY_48] = "ck_usbo_48m" ++}; ++ ++/******************************************************************************* ++ * This function reads the frequency of an oscillator from its name. ++ * It reads the value indicated inside the device tree. ++ * Returns 0 on success, and a negative FDT/ERRNO error code on failure. ++ * On success, value is stored in the second parameter. ++ ******************************************************************************/ ++int fdt_osc_read_freq(void *fdt, const char *name, uint32_t *freq) ++{ ++ int node, subnode; ++ ++ node = fdt_path_offset(fdt, "/clocks"); ++ if (node < 0) { ++ return -FDT_ERR_NOTFOUND; ++ } ++ ++ fdt_for_each_subnode(subnode, fdt, node) { ++ const char *cchar; ++ int ret; ++ ++ cchar = fdt_get_name(fdt, subnode, &ret); ++ if (cchar == NULL) { ++ return ret; ++ } ++ ++ if (strncmp(cchar, name, (size_t)ret) == 0) { ++ const fdt32_t *cuint; ++ ++ cuint = fdt_getprop(fdt, subnode, "clock-frequency", ++ &ret); ++ if (cuint == NULL) { ++ return ret; ++ } ++ ++ *freq = fdt32_to_cpu(*cuint); ++ ++ return 0; ++ } ++ } ++ ++ /* Oscillator not found, freq=0 */ ++ *freq = 0; ++ return 0; ++} ++ ++/******************************************************************************* ++ * This function checks the presence of an oscillator property from its id. ++ * The search is done inside the device tree. ++ * Returns true/false regarding search result. ++ ******************************************************************************/ ++bool fdt_osc_read_bool(void *fdt, enum stm32mp_osc_id osc_id, ++ const char *prop_name) ++{ ++ int node, subnode; ++ ++ if (osc_id >= NB_OSC) { ++ return false; ++ } ++ ++ node = fdt_path_offset(fdt, "/clocks"); ++ if (node < 0) { ++ return false; ++ } ++ ++ fdt_for_each_subnode(subnode, fdt, node) { ++ const char *cchar; ++ int ret; ++ ++ cchar = fdt_get_name(fdt, subnode, &ret); ++ if (cchar == NULL) { ++ return false; ++ } ++ ++ if (strncmp(cchar, stm32mp_osc_node_label[osc_id], ++ (size_t)ret) != 0) { ++ continue; ++ } ++ ++ if (fdt_getprop(fdt, subnode, prop_name, NULL) != NULL) { ++ return true; ++ } ++ } ++ ++ return false; ++} ++ ++/******************************************************************************* ++ * This function reads a value of a oscillator property from its id. ++ * Returns value on success, and a default value if property not found. ++ * Default value is passed as parameter. ++ ******************************************************************************/ ++uint32_t fdt_osc_read_uint32_default(void *fdt, enum stm32mp_osc_id osc_id, ++ const char *prop_name, uint32_t dflt_value) ++{ ++ int node, subnode; ++ ++ if (osc_id >= NB_OSC) { ++ return dflt_value; ++ } ++ ++ node = fdt_path_offset(fdt, "/clocks"); ++ if (node < 0) { ++ return dflt_value; ++ } ++ ++ fdt_for_each_subnode(subnode, fdt, node) { ++ const char *cchar; ++ int ret; ++ ++ cchar = fdt_get_name(fdt, subnode, &ret); ++ if (cchar == NULL) { ++ return dflt_value; ++ } ++ ++ if (strncmp(cchar, stm32mp_osc_node_label[osc_id], ++ (size_t)ret) != 0) { ++ continue; ++ } ++ ++ return fdt_read_uint32_default(fdt, subnode, prop_name, ++ dflt_value); ++ } ++ ++ return dflt_value; ++} ++ ++/******************************************************************************* ++ * This function reads the rcc base address. ++ * It reads the value indicated inside the device tree. ++ * Returns address on success, and 0 on failure. ++ ******************************************************************************/ ++uint32_t fdt_rcc_read_addr(void *fdt) ++{ ++ int node, subnode; ++ ++ node = fdt_path_offset(fdt, "/soc"); ++ if (node < 0) { ++ return 0; ++ } ++ ++ fdt_for_each_subnode(subnode, fdt, node) { ++ const char *cchar; ++ int ret; ++ ++ cchar = fdt_get_name(fdt, subnode, &ret); ++ if (cchar == NULL) { ++ return 0; ++ } ++ ++ if (strncmp(cchar, DT_RCC_NODE_NAME, (size_t)ret) == 0) { ++ const fdt32_t *cuint; ++ ++ cuint = fdt_getprop(fdt, subnode, "reg", NULL); ++ if (cuint == NULL) { ++ return 0; ++ } ++ ++ return fdt32_to_cpu(*cuint); ++ } ++ } ++ ++ return 0; ++} ++ ++/******************************************************************************* ++ * This function returns the RCC node in the device tree. ++ ******************************************************************************/ ++int fdt_get_rcc_node(void *fdt) ++{ ++ return fdt_node_offset_by_compatible(fdt, -1, DT_RCC_CLK_COMPAT); ++} ++ ++/******************************************************************************* ++ * This function reads a series of parameters in rcc-clk section. ++ * It reads the values indicated inside the device tree, from property name. ++ * The number of parameters is also indicated as entry parameter. ++ * Returns 0 on success, and a negative FDT/ERRNO error code on failure. ++ * On success, values are stored at the second parameter address. ++ ******************************************************************************/ ++int fdt_rcc_read_uint32_array(void *fdt, const char *prop_name, ++ uint32_t *array, uint32_t count) ++{ ++ int node = fdt_get_rcc_node(fdt); ++ ++ if (node < 0) { ++ return -FDT_ERR_NOTFOUND; ++ } ++ ++ return fdt_read_uint32_array(fdt, node, prop_name, array, count); ++} ++ ++/******************************************************************************* ++ * This function gets the subnode offset in rcc-clk section from its name. ++ * It reads the values indicated inside the device tree. ++ * Returns offset on success, and a negative FDT/ERRNO error code on failure. ++ ******************************************************************************/ ++int fdt_rcc_subnode_offset(void *fdt, const char *name) ++{ ++ int node, subnode; ++ ++ node = fdt_get_rcc_node(fdt); ++ if (node < 0) { ++ return -FDT_ERR_NOTFOUND; ++ } ++ ++ subnode = fdt_subnode_offset(fdt, node, name); ++ if (subnode <= 0) { ++ return -FDT_ERR_NOTFOUND; ++ } ++ ++ return subnode; ++} ++ ++/******************************************************************************* ++ * This function gets the pointer to a rcc-clk property from its name. ++ * It reads the values indicated inside the device tree. ++ * Length of the property is stored in the second parameter. ++ * Returns pointer on success, and NULL value on failure. ++ ******************************************************************************/ ++const fdt32_t *fdt_rcc_read_prop(void *fdt, const char *prop_name, int *lenp) ++{ ++ const fdt32_t *cuint; ++ int node, len; ++ ++ node = fdt_get_rcc_node(fdt); ++ if (node < 0) { ++ return NULL; ++ } ++ ++ cuint = fdt_getprop(fdt, node, prop_name, &len); ++ if (cuint == NULL) { ++ return NULL; ++ } ++ ++ *lenp = len; ++ return cuint; ++} ++ ++/******************************************************************************* ++ * This function reads the stgen base address. ++ * It reads the value indicated inside the device tree. ++ * Returns address on success, and NULL value on failure. ++ ******************************************************************************/ ++uintptr_t get_stgen_base(void) ++{ ++ int node; ++ const fdt32_t *cuint; ++ void *fdt; ++ ++ fdt = get_dt_blob(); ++ if (fdt == NULL) { ++ 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); ++} ++ ++/******************************************************************************* ++ * This function gets the frequency of the specified uart instance. ++ * From this instance, all the uarts nodes in DT are parsed, and the register ++ * base is compared to the instance. If match between these two values, then ++ * the clock source is read from the DT and we deduce the frequency. ++ * Returns clock frequency on success, 0 value on failure. ++ ******************************************************************************/ ++unsigned long get_uart_clock_freq(uint32_t instance) ++{ ++ int node; ++ void *fdt; ++ ++ 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)); ++ ++ return stm32mp1_clk_get_rate(clk_id); ++ } ++next: ++ node = fdt_node_offset_by_compatible(fdt, node, DT_UART_COMPAT); ++ } ++ ++ return 0; ++} +diff --git a/core/arch/arm/plat-stm32mp1/drivers/stm32mp1_clkfunc.h b/core/arch/arm/plat-stm32mp1/drivers/stm32mp1_clkfunc.h +new file mode 100644 +index 0000000..cbb489b +--- /dev/null ++++ b/core/arch/arm/plat-stm32mp1/drivers/stm32mp1_clkfunc.h +@@ -0,0 +1,33 @@ ++/* SPDX-License-Identifier: BSD-3-Clause */ ++/* ++ * Copyright (c) 2017-2018, STMicroelectronics - All Rights Reserved ++ */ ++ ++#ifndef __STM32MP1_CLKFUNC_H__ ++#define __STM32MP1_CLKFUNC_H__ ++ ++#include ++#include ++ ++extern const char *stm32mp_osc_node_label[NB_OSC]; ++ ++int fdt_osc_read_freq(void *fdt, const char *name, uint32_t *freq); ++bool fdt_osc_read_bool(void *fdt, enum stm32mp_osc_id osc_id, ++ const char *prop_name); ++uint32_t fdt_osc_read_uint32_default(void *fdt, enum stm32mp_osc_id osc_id, ++ const char *prop_name, ++ uint32_t dflt_value); ++ ++int fdt_get_rcc_node(void *fdt); ++uint32_t fdt_rcc_read_addr(void *fdt); ++int fdt_rcc_read_uint32_array(void *fdt, const char *prop_name, ++ uint32_t *array, uint32_t count); ++int fdt_rcc_subnode_offset(void *fdt, const char *name); ++const fdt32_t *fdt_rcc_read_prop(void *fdt, const char *prop_name, int *lenp); ++bool fdt_get_rcc_secure_status(void *fdt); ++ ++uintptr_t get_stgen_base(void); ++ ++unsigned long get_uart_clock_freq(uint32_t instance); ++ ++#endif /* __STM32MP1_CLKFUNC_H__ */ +diff --git a/core/arch/arm/plat-stm32mp1/drivers/stm32mp1_ddrc.c b/core/arch/arm/plat-stm32mp1/drivers/stm32mp1_ddrc.c +new file mode 100644 +index 0000000..03ded28 +--- /dev/null ++++ b/core/arch/arm/plat-stm32mp1/drivers/stm32mp1_ddrc.c +@@ -0,0 +1,513 @@ ++// SPDX-License-Identifier: BSD-3-Clause ++/* ++ * Copyright (c) 2017, STMicroelectronics - All Rights Reserved ++ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define TIMEOUT_500US (500 * 1000) ++ ++static uintptr_t get_ddrctrl_base(void) ++{ ++ static void *va; ++ ++ if (!cpu_mmu_enabled()) { ++ return DDRCTRL_BASE; ++ } ++ ++ if (!va) { ++ va = phys_to_virt(DDRCTRL_BASE, MEM_AREA_IO_SEC); ++ } ++ ++ return (uintptr_t)va; ++} ++ ++static uintptr_t get_ddrphy_base(void) ++{ ++ static void *va; ++ ++ if (!cpu_mmu_enabled()) { ++ return DDRPHYC_BASE; ++ } ++ ++ if (!va) { ++ va = phys_to_virt(DDRPHYC_BASE, MEM_AREA_IO_SEC); ++ } ++ ++ return (uintptr_t)va; ++} ++ ++static void ddr_disable_clock(void) ++{ ++ uintptr_t rcc_base = stm32_rcc_base(); ++ ++ /* Disable all clocks */ ++ mmio_clrbits_32(rcc_base + RCC_DDRITFCR, ++ RCC_DDRITFCR_DDRC1EN | ++ RCC_DDRITFCR_DDRC2EN | ++ RCC_DDRITFCR_DDRPHYCAPBEN | ++ RCC_DDRITFCR_DDRCAPBEN); ++} ++ ++static void ddr_enable_clock(void) ++{ ++ uintptr_t rcc_base = stm32_rcc_base(); ++ ++ /* Enable all clocks */ ++ mmio_setbits_32(rcc_base + RCC_DDRITFCR, ++ RCC_DDRITFCR_DDRC1EN | ++ RCC_DDRITFCR_DDRC2EN | ++ RCC_DDRITFCR_DDRPHYCEN | ++ RCC_DDRITFCR_DDRPHYCAPBEN | ++ RCC_DDRITFCR_DDRCAPBEN); ++} ++ ++static void do_sw_handshake(void) ++{ ++ uintptr_t ddrctrl_base = get_ddrctrl_base(); ++ ++ mmio_clrbits_32(ddrctrl_base + DDRCTRL_SWCTL, DDRCTRL_SWCTL_SW_DONE); ++} ++ ++static void do_sw_ack(void) ++{ ++ uint64_t to_ref; ++ uintptr_t ddrctrl_base = get_ddrctrl_base(); ++ ++ mmio_setbits_32(ddrctrl_base + DDRCTRL_SWCTL, DDRCTRL_SWCTL_SW_DONE); ++ ++ to_ref = utimeout_init(TIMEOUT_500US); ++ while ((mmio_read_32(ddrctrl_base + DDRCTRL_SWSTAT) & ++ DDRCTRL_SWSTAT_SW_DONE_ACK) == 0U) { ++ if (utimeout_elapsed(TIMEOUT_500US, to_ref)) { ++ panic(); ++ } ++ } ++} ++ ++static int ddr_sw_self_refresh_in(void) ++{ ++ uint64_t to_ref; ++ uint32_t operating_mode; ++ uint32_t selref_type; ++ uint8_t op_mode_changed = 0; ++ uintptr_t pwr_base = stm32_pwr_base(); ++ uintptr_t rcc_base = stm32_rcc_base(); ++ uintptr_t ddrctrl_base = get_ddrctrl_base(); ++ uintptr_t ddrphy_base = get_ddrphy_base(); ++ ++ mmio_clrbits_32(rcc_base + RCC_DDRITFCR, RCC_DDRITFCR_AXIDCGEN); ++ ++ /* Blocks AXI ports from taking anymore transactions */ ++ mmio_clrbits_32(ddrctrl_base + DDRCTRL_PCTRL_0, ++ DDRCTRL_PCTRL_N_PORT_EN); ++ mmio_clrbits_32(ddrctrl_base + DDRCTRL_PCTRL_1, ++ DDRCTRL_PCTRL_N_PORT_EN); ++ ++ /* ++ * Waits unit all AXI ports are idle ++ * Poll PSTAT.rd_port_busy_n = 0 ++ * Poll PSTAT.wr_port_busy_n = 0 ++ */ ++ to_ref = utimeout_init(TIMEOUT_500US); ++ while (mmio_read_32(ddrctrl_base + DDRCTRL_PSTAT)) { ++ if (utimeout_elapsed(TIMEOUT_500US, to_ref)) { ++ goto pstat_failed; ++ } ++ } ++ ++ /* SW Self-Refresh entry */ ++ mmio_setbits_32(ddrctrl_base + DDRCTRL_PWRCTL, ++ DDRCTRL_PWRCTL_SELFREF_SW); ++ ++ /* ++ * Wait operating mode change in self-refresh mode ++ * with STAT.operating_mode[1:0]==11. ++ * Ensure transition to self-refresh was due to software ++ * by checking also that STAT.selfref_type[1:0]=2. ++ */ ++ to_ref = utimeout_init(TIMEOUT_500US); ++ while (!utimeout_elapsed(TIMEOUT_500US, to_ref)) { ++ uint32_t stat = mmio_read_32(ddrctrl_base + DDRCTRL_STAT); ++ ++ operating_mode = stat & DDRCTRL_STAT_OPERATING_MODE_MASK; ++ selref_type = stat & DDRCTRL_STAT_SELFREF_TYPE_MASK; ++ ++ if ((operating_mode == DDRCTRL_STAT_OPERATING_MODE_SR) && ++ (selref_type == DDRCTRL_STAT_SELFREF_TYPE_SR)) { ++ op_mode_changed = 1; ++ break; ++ } ++ } ++ ++ if (op_mode_changed == 0U) ++ goto selfref_sw_failed; ++ ++ /* IOs powering down (PUBL registers) */ ++ mmio_setbits_32(ddrphy_base + DDRPHYC_ACIOCR, DDRPHYC_ACIOCR_ACPDD); ++ ++ mmio_setbits_32(ddrphy_base + DDRPHYC_ACIOCR, DDRPHYC_ACIOCR_ACPDR); ++ ++ mmio_clrsetbits_32(ddrphy_base + DDRPHYC_ACIOCR, ++ DDRPHYC_ACIOCR_CKPDD_MASK, ++ DDRPHYC_ACIOCR_CKPDD_0); ++ ++ mmio_clrsetbits_32(ddrphy_base + DDRPHYC_ACIOCR, ++ DDRPHYC_ACIOCR_CKPDR_MASK, ++ DDRPHYC_ACIOCR_CKPDR_0); ++ ++ mmio_clrsetbits_32(ddrphy_base + DDRPHYC_ACIOCR, ++ DDRPHYC_ACIOCR_CSPDD_MASK, ++ DDRPHYC_ACIOCR_CSPDD_0); ++ ++ mmio_setbits_32(ddrphy_base + DDRPHYC_DXCCR, DDRPHYC_DXCCR_DXPDD); ++ ++ mmio_setbits_32(ddrphy_base + DDRPHYC_DXCCR, DDRPHYC_DXCCR_DXPDR); ++ ++ mmio_clrsetbits_32(ddrphy_base + DDRPHYC_DSGCR, ++ DDRPHYC_DSGCR_ODTPDD_MASK, ++ DDRPHYC_DSGCR_ODTPDD_0); ++ ++ mmio_setbits_32(ddrphy_base + DDRPHYC_DSGCR, DDRPHYC_DSGCR_NL2PD); ++ ++ mmio_clrsetbits_32(ddrphy_base + DDRPHYC_DSGCR, ++ DDRPHYC_DSGCR_CKEPDD_MASK, ++ DDRPHYC_DSGCR_CKEPDD_0); ++ ++ /* Disable PZQ cell (PUBL register) */ ++ mmio_setbits_32(ddrphy_base + DDRPHYC_ZQ0CR0, DDRPHYC_ZQ0CRN_ZQPD); ++ ++ /* Activate sw retention in PWRCTRL */ ++ mmio_setbits_32(pwr_base + PWR_CR3_OFF, PWR_CR3_DDRRETEN); ++ ++ /* Switch controller clocks (uMCTL2/PUBL) to DLL ref clock */ ++ mmio_setbits_32(rcc_base + RCC_DDRITFCR, RCC_DDRITFCR_GSKPCTRL); ++ ++ /* Disable all DLLs: GLITCH window */ ++ mmio_setbits_32(ddrphy_base + DDRPHYC_ACDLLCR, ++ DDRPHYC_ACDLLCR_DLLDIS); ++ ++ mmio_setbits_32(ddrphy_base + DDRPHYC_DX0DLLCR, ++ DDRPHYC_DXNDLLCR_DLLDIS); ++ ++ mmio_setbits_32(ddrphy_base + DDRPHYC_DX1DLLCR, ++ DDRPHYC_DXNDLLCR_DLLDIS); ++ ++ mmio_setbits_32(ddrphy_base + DDRPHYC_DX2DLLCR, ++ DDRPHYC_DXNDLLCR_DLLDIS); ++ ++ mmio_setbits_32(ddrphy_base + DDRPHYC_DX3DLLCR, ++ DDRPHYC_DXNDLLCR_DLLDIS); ++ ++ /* Switch controller clocks (uMCTL2/PUBL) to DLL output clock */ ++ mmio_clrbits_32(rcc_base + RCC_DDRITFCR, RCC_DDRITFCR_GSKPCTRL); ++ ++ /* Disable all clocks */ ++ ddr_disable_clock(); ++ ++ return 0; ++ ++selfref_sw_failed: ++ /* This bit should be cleared to restore DDR in its previous state */ ++ mmio_clrbits_32(ddrctrl_base + DDRCTRL_PWRCTL, ++ DDRCTRL_PWRCTL_SELFREF_SW); ++ ++pstat_failed: ++ mmio_setbits_32(ddrctrl_base + DDRCTRL_PCTRL_0, ++ DDRCTRL_PCTRL_N_PORT_EN); ++ mmio_setbits_32(ddrctrl_base + DDRCTRL_PCTRL_1, ++ DDRCTRL_PCTRL_N_PORT_EN); ++ ++ return -1; ++} ++ ++int ddr_sw_self_refresh_exit(void) ++{ ++ uint64_t to_ref; ++ uintptr_t rcc_base = stm32_rcc_base(); ++ uintptr_t pwr_base = stm32_pwr_base(); ++ uintptr_t ddrctrl_base = get_ddrctrl_base(); ++ uintptr_t ddrphy_base = get_ddrphy_base(); ++ ++ /* Enable all clocks */ ++ ddr_enable_clock(); ++ ++ do_sw_handshake(); ++ ++ /* Mask dfi_init_complete_en */ ++ mmio_clrbits_32(ddrctrl_base + DDRCTRL_DFIMISC, ++ DDRCTRL_DFIMISC_DFI_INIT_COMPLETE_EN); ++ ++ do_sw_ack(); ++ ++ /* Switch controller clocks (uMCTL2/PUBL) to DLL ref clock */ ++ mmio_setbits_32(rcc_base + RCC_DDRITFCR, RCC_DDRITFCR_GSKPCTRL); ++ ++ /* Enable all DLLs: GLITCH window */ ++ mmio_clrbits_32(ddrphy_base + DDRPHYC_ACDLLCR, ++ DDRPHYC_ACDLLCR_DLLDIS); ++ ++ mmio_clrbits_32(ddrphy_base + DDRPHYC_DX0DLLCR, ++ DDRPHYC_DXNDLLCR_DLLDIS); ++ ++ mmio_clrbits_32(ddrphy_base + DDRPHYC_DX1DLLCR, ++ DDRPHYC_DXNDLLCR_DLLDIS); ++ ++ mmio_clrbits_32(ddrphy_base + DDRPHYC_DX2DLLCR, ++ DDRPHYC_DXNDLLCR_DLLDIS); ++ ++ mmio_clrbits_32(ddrphy_base + DDRPHYC_DX3DLLCR, ++ DDRPHYC_DXNDLLCR_DLLDIS); ++ ++ /* Additional delay to avoid early DLL clock switch */ ++ udelay(10); ++ ++ /* Switch controller clocks (uMCTL2/PUBL) to DLL ref clock */ ++ mmio_clrbits_32(rcc_base + RCC_DDRITFCR, RCC_DDRITFCR_GSKPCTRL); ++ mmio_clrbits_32(ddrphy_base + DDRPHYC_ACDLLCR, DDRPHYC_ACDLLCR_DLLSRST); ++ ++ udelay(10); ++ ++ mmio_setbits_32(ddrphy_base + DDRPHYC_ACDLLCR, ++ DDRPHYC_ACDLLCR_DLLSRST); ++ ++ /* PHY partial init: (DLL lock and ITM reset) */ ++ mmio_write_32(ddrphy_base + DDRPHYC_PIR, ++ DDRPHYC_PIR_DLLSRST | DDRPHYC_PIR_DLLLOCK | ++ DDRPHYC_PIR_ITMSRST | DDRPHYC_PIR_INIT); ++ ++ /* Need to wait at least 10 clock cycles before accessing PGSR */ ++ udelay(1); ++ ++ to_ref = utimeout_init(TIMEOUT_500US); ++ while ((mmio_read_32(ddrphy_base + DDRPHYC_PGSR) & ++ DDRPHYC_PGSR_IDONE) == 0U) { ++ if (utimeout_elapsed(TIMEOUT_500US, to_ref)) { ++ return -1; ++ } ++ } ++ ++ do_sw_handshake(); ++ ++ /* Unmask dfi_init_complete_en to uMCTL2 */ ++ mmio_setbits_32(ddrctrl_base + DDRCTRL_DFIMISC, ++ DDRCTRL_DFIMISC_DFI_INIT_COMPLETE_EN); ++ ++ do_sw_ack(); ++ ++ /* Deactivate sw retention in PWR */ ++ mmio_clrbits_32(pwr_base + PWR_CR3_OFF, PWR_CR3_DDRRETEN); ++ ++ /* Enable PZQ cell (PUBL register) */ ++ mmio_clrbits_32(ddrphy_base + DDRPHYC_ZQ0CR0, DDRPHYC_ZQ0CRN_ZQPD); ++ ++ /* Enable pad drivers */ ++ mmio_clrbits_32(ddrphy_base + DDRPHYC_ACIOCR, DDRPHYC_ACIOCR_ACPDD); ++ ++ mmio_clrbits_32(ddrphy_base + DDRPHYC_ACIOCR, ++ DDRPHYC_ACIOCR_CKPDD_MASK); ++ ++ mmio_clrbits_32(ddrphy_base + DDRPHYC_ACIOCR, ++ DDRPHYC_ACIOCR_CSPDD_MASK); ++ ++ mmio_clrbits_32(ddrphy_base + DDRPHYC_DXCCR, DDRPHYC_DXCCR_DXPDD); ++ ++ mmio_clrbits_32(ddrphy_base + DDRPHYC_DXCCR, DDRPHYC_DXCCR_DXPDR); ++ ++ mmio_clrbits_32(ddrphy_base + DDRPHYC_DSGCR, DDRPHYC_DSGCR_ODTPDD_MASK); ++ ++ mmio_clrbits_32(ddrphy_base + DDRPHYC_DSGCR, DDRPHYC_DSGCR_NL2PD); ++ ++ mmio_clrbits_32(ddrphy_base + DDRPHYC_DSGCR, DDRPHYC_DSGCR_CKEPDD_MASK); ++ ++ /* Remove selfrefresh */ ++ mmio_clrbits_32(ddrctrl_base + DDRCTRL_PWRCTL, ++ DDRCTRL_PWRCTL_SELFREF_SW); ++ ++ /* Wait operating_mode == normal */ ++ to_ref = utimeout_init(TIMEOUT_500US); ++ ++ while ((mmio_read_32(ddrctrl_base + DDRCTRL_STAT) & ++ DDRCTRL_STAT_OPERATING_MODE_MASK) != ++ DDRCTRL_STAT_OPERATING_MODE_NORMAL) { ++ if (utimeout_elapsed(TIMEOUT_500US, to_ref)) { ++ return -1; ++ } ++ } ++ ++ /* AXI ports are no longer blocked from taking transactions */ ++ mmio_setbits_32(ddrctrl_base + DDRCTRL_PCTRL_0, ++ DDRCTRL_PCTRL_N_PORT_EN); ++ mmio_setbits_32(ddrctrl_base + DDRCTRL_PCTRL_1, ++ DDRCTRL_PCTRL_N_PORT_EN); ++ ++ mmio_setbits_32(rcc_base + RCC_DDRITFCR, RCC_DDRITFCR_AXIDCGEN); ++ ++ return 0; ++} ++ ++uint32_t get_ddrphy_calibration(void) ++{ ++ uintptr_t ddrphy_base = get_ddrphy_base(); ++ uint32_t zcal = mmio_read_32(ddrphy_base + DDRPHYC_ZQ0CR0); ++ ++ return (zcal & DDRPHYC_ZQ0CRN_ZDATA_MASK) >> DDRPHYC_ZQ0CRN_ZDATA_SHIFT; ++} ++ ++int ddr_standby_sr_entry(uint32_t *zq0cr0_zdata) ++{ ++ uintptr_t pwr_base = stm32_pwr_base(); ++ uintptr_t ddrphy_base = get_ddrphy_base(); ++ ++ /* Save IOs calibration values */ ++ if (zq0cr0_zdata != NULL) { ++ *zq0cr0_zdata = mmio_read_32(ddrphy_base + DDRPHYC_ZQ0CR0) & ++ DDRPHYC_ZQ0CRN_ZDATA_MASK; ++ } ++ ++ /* Put DDR in Self-Refresh */ ++ if (ddr_sw_self_refresh_in() != 0) { ++ return -1; ++ } ++ ++ /* Enable I/O retention mode in standby */ ++ mmio_setbits_32(pwr_base + PWR_CR3_OFF, PWR_CR3_DDRSREN); ++ ++ return 0; ++} ++ ++void ddr_sr_mode_ssr(void) ++{ ++ uintptr_t rcc_ddritfcr = stm32_rcc_base() + RCC_DDRITFCR; ++ uintptr_t ddrctrl_base = get_ddrctrl_base(); ++ ++ mmio_setbits_32(rcc_ddritfcr, RCC_DDRITFCR_DDRC1LPEN); ++ ++ mmio_setbits_32(rcc_ddritfcr, RCC_DDRITFCR_DDRC2LPEN); ++ ++ mmio_setbits_32(rcc_ddritfcr, RCC_DDRITFCR_DDRC1EN); ++ ++ mmio_setbits_32(rcc_ddritfcr, RCC_DDRITFCR_DDRC2EN); ++ ++ mmio_setbits_32(rcc_ddritfcr, RCC_DDRITFCR_DDRCAPBLPEN); ++ ++ mmio_setbits_32(rcc_ddritfcr, RCC_DDRITFCR_DDRPHYCAPBLPEN); ++ ++ mmio_setbits_32(rcc_ddritfcr, RCC_DDRITFCR_DDRCAPBEN); ++ ++ mmio_setbits_32(rcc_ddritfcr, RCC_DDRITFCR_DDRPHYCAPBEN); ++ ++ mmio_setbits_32(rcc_ddritfcr, RCC_DDRITFCR_DDRPHYCEN); ++ ++ mmio_clrbits_32(rcc_ddritfcr, RCC_DDRITFCR_AXIDCGEN); ++ ++ mmio_clrbits_32(rcc_ddritfcr, RCC_DDRITFCR_DDRCKMOD_MASK); ++ ++ /* Disable HW LP interface of uMCTL2 */ ++ mmio_clrbits_32(ddrctrl_base + DDRCTRL_HWLPCTL, ++ DDRCTRL_HWLPCTL_HW_LP_EN); ++ ++ /* Configure Automatic LP modes of uMCTL2 */ ++ mmio_clrsetbits_32(ddrctrl_base + DDRCTRL_PWRTMG, ++ DDRCTRL_PWRTMG_SELFREF_TO_X32_MASK, ++ DDRCTRL_PWRTMG_SELFREF_TO_X32_0); ++ ++ /* ++ * Disable Clock disable with LP modes ++ * (used in RUN mode for LPDDR2 with specific timing). ++ */ ++ mmio_clrbits_32(ddrctrl_base + DDRCTRL_PWRCTL, ++ DDRCTRL_PWRCTL_EN_DFI_DRAM_CLK_DISABLE); ++ ++ /* Disable automatic Self-Refresh mode */ ++ mmio_clrbits_32(ddrctrl_base + DDRCTRL_PWRCTL, ++ DDRCTRL_PWRCTL_SELFREF_EN); ++} ++ ++void ddr_sr_mode_asr(void) ++{ ++ uintptr_t rcc_ddritfcr = stm32_rcc_base() + RCC_DDRITFCR; ++ uintptr_t ddrctrl_base = get_ddrctrl_base(); ++ ++ mmio_setbits_32(rcc_ddritfcr, RCC_DDRITFCR_AXIDCGEN); ++ ++ mmio_setbits_32(rcc_ddritfcr, RCC_DDRITFCR_DDRC1LPEN); ++ ++ mmio_setbits_32(rcc_ddritfcr, RCC_DDRITFCR_DDRC2LPEN); ++ ++ mmio_setbits_32(rcc_ddritfcr, RCC_DDRITFCR_DDRPHYCLPEN); ++ ++ mmio_clrsetbits_32(rcc_ddritfcr, RCC_DDRITFCR_DDRCKMOD_MASK, ++ RCC_DDRITFCR_DDRCKMOD_ASR1); ++ ++ /* Enable HW LP interface of uMCTL2 */ ++ mmio_setbits_32(ddrctrl_base + DDRCTRL_HWLPCTL, ++ DDRCTRL_HWLPCTL_HW_LP_EN); ++ ++ /* Configure Automatic LP modes of uMCTL2 */ ++ mmio_clrsetbits_32(ddrctrl_base + DDRCTRL_PWRTMG, ++ DDRCTRL_PWRTMG_SELFREF_TO_X32_MASK, ++ DDRCTRL_PWRTMG_SELFREF_TO_X32_0); ++ ++ /* ++ * Enable Clock disable with LP modes ++ * (used in RUN mode for LPDDR2 with specific timing). ++ */ ++ mmio_setbits_32(ddrctrl_base + DDRCTRL_PWRCTL, ++ DDRCTRL_PWRCTL_EN_DFI_DRAM_CLK_DISABLE); ++ ++ /* Enable automatic Self-Refresh for ASR mode */ ++ mmio_setbits_32(ddrctrl_base + DDRCTRL_PWRCTL, ++ DDRCTRL_PWRCTL_SELFREF_EN); ++} ++ ++void ddr_sr_mode_hsr(void) ++{ ++ uintptr_t rcc_ddritfcr = stm32_rcc_base() + RCC_DDRITFCR; ++ uintptr_t ddrctrl_base = get_ddrctrl_base(); ++ ++ mmio_setbits_32(rcc_ddritfcr, RCC_DDRITFCR_AXIDCGEN); ++ ++ mmio_clrbits_32(rcc_ddritfcr, RCC_DDRITFCR_DDRC1LPEN); ++ ++ mmio_clrbits_32(rcc_ddritfcr, RCC_DDRITFCR_DDRC2LPEN); ++ ++ mmio_setbits_32(rcc_ddritfcr, RCC_DDRITFCR_DDRPHYCLPEN); ++ ++ mmio_clrsetbits_32(rcc_ddritfcr, RCC_DDRITFCR_DDRCKMOD_MASK, ++ RCC_DDRITFCR_DDRCKMOD_HSR1); ++ ++ /* Enable HW LP interface of uMCTL2 */ ++ mmio_setbits_32(ddrctrl_base + DDRCTRL_HWLPCTL, ++ DDRCTRL_HWLPCTL_HW_LP_EN); ++ ++ /* Configure Automatic LP modes of uMCTL2 */ ++ mmio_clrsetbits_32(ddrctrl_base + DDRCTRL_PWRTMG, ++ DDRCTRL_PWRTMG_SELFREF_TO_X32_MASK, ++ DDRCTRL_PWRTMG_SELFREF_TO_X32_0); ++ ++ /* ++ * Enable Clock disable with LP modes ++ * (used in RUN mode for LPDDR2 with specific timing). ++ */ ++ mmio_setbits_32(ddrctrl_base + DDRCTRL_PWRCTL, ++ DDRCTRL_PWRCTL_EN_DFI_DRAM_CLK_DISABLE); ++} ++ +diff --git a/core/arch/arm/plat-stm32mp1/drivers/stm32mp1_ddrc.h b/core/arch/arm/plat-stm32mp1/drivers/stm32mp1_ddrc.h +new file mode 100644 +index 0000000..59014b4 +--- /dev/null ++++ b/core/arch/arm/plat-stm32mp1/drivers/stm32mp1_ddrc.h +@@ -0,0 +1,205 @@ ++/* SPDX-License-Identifier: BSD-3-Clause */ ++/* ++ * Copyright (c) 2017-2018, STMicroelectronics - All Rights Reserved ++ */ ++ ++#ifndef __STM32MP1_DDRC_H__ ++#define __STM32MP1_DDRC_H__ ++ ++#include ++ ++/* DDR Controller */ ++/* DDR Controller registers offsets */ ++#define DDRCTRL_MSTR 0x000 ++#define DDRCTRL_STAT 0x004 ++#define DDRCTRL_MRCTRL0 0x010 ++#define DDRCTRL_MRSTAT 0x018 ++#define DDRCTRL_PWRCTL 0x030 ++#define DDRCTRL_PWRTMG 0x034 ++#define DDRCTRL_HWLPCTL 0x038 ++#define DDRCTRL_RFSHCTL3 0x060 ++#define DDRCTRL_RFSHTMG 0x064 ++#define DDRCTRL_INIT0 0x0D0 ++#define DDRCTRL_DFIMISC 0x1B0 ++#define DDRCTRL_DBG1 0x304 ++#define DDRCTRL_DBGCAM 0x308 ++#define DDRCTRL_DBGCMD 0x30C ++#define DDRCTRL_DBGSTAT 0x310 ++#define DDRCTRL_SWCTL 0x320 ++#define DDRCTRL_SWSTAT 0x324 ++#define DDRCTRL_PSTAT 0x3FC ++#define DDRCTRL_PCTRL_0 0x490 ++#define DDRCTRL_PCTRL_1 0x540 ++ ++/* DDR Controller Register fields */ ++#define DDRCTRL_MSTR_DDR3 BIT(0) ++#define DDRCTRL_MSTR_LPDDR2 BIT(2) ++#define DDRCTRL_MSTR_LPDDR3 BIT(3) ++#define DDRCTRL_MSTR_DATA_BUS_WIDTH_MASK GENMASK_32(13, 12) ++#define DDRCTRL_MSTR_DATA_BUS_WIDTH_FULL 0 ++#define DDRCTRL_MSTR_DATA_BUS_WIDTH_HALF BIT(12) ++#define DDRCTRL_MSTR_DATA_BUS_WIDTH_QUARTER BIT(13) ++#define DDRCTRL_MSTR_DLL_OFF_MODE BIT(15) ++ ++#define DDRCTRL_STAT_OPERATING_MODE_MASK GENMASK_32(2, 0) ++#define DDRCTRL_STAT_OPERATING_MODE_NORMAL BIT(0) ++#define DDRCTRL_STAT_OPERATING_MODE_SR (BIT(0) | BIT(1)) ++#define DDRCTRL_STAT_SELFREF_TYPE_MASK GENMASK_32(5, 4) ++#define DDRCTRL_STAT_SELFREF_TYPE_ASR (BIT(4) | BIT(5)) ++#define DDRCTRL_STAT_SELFREF_TYPE_SR BIT(5) ++ ++#define DDRCTRL_MRCTRL0_MR_TYPE_WRITE 0 ++/* only one rank supported */ ++#define DDRCTRL_MRCTRL0_MR_RANK_SHIFT 4 ++#define DDRCTRL_MRCTRL0_MR_RANK_ALL \ ++ BIT(DDRCTRL_MRCTRL0_MR_RANK_SHIFT) ++#define DDRCTRL_MRCTRL0_MR_ADDR_SHIFT 12 ++#define DDRCTRL_MRCTRL0_MR_ADDR_MASK GENMASK_32(15, 12) ++#define DDRCTRL_MRCTRL0_MR_WR BIT(31) ++ ++#define DDRCTRL_MRSTAT_MR_WR_BUSY BIT(0) ++ ++#define DDRCTRL_PWRCTL_SELFREF_EN BIT(0) ++#define DDRCTRL_PWRCTL_POWERDOWN_EN BIT(1) ++#define DDRCTRL_PWRCTL_EN_DFI_DRAM_CLK_DISABLE BIT(3) ++#define DDRCTRL_PWRCTL_SELFREF_SW BIT(5) ++ ++#define DDRCTRL_PWRTMG_SELFREF_TO_X32_MASK GENMASK_32(19, 12) ++#define DDRCTRL_PWRTMG_SELFREF_TO_X32_0 BIT(16) ++ ++#define DDRCTRL_RFSHCTL3_DIS_AUTO_REFRESH BIT(0) ++ ++#define DDRCTRL_HWLPCTL_HW_LP_EN BIT(0) ++ ++#define DDRCTRL_RFSHTMG_T_RFC_NOM_X1_X32_MASK GENMASK_32(27, 16) ++#define DDRCTRL_RFSHTMG_T_RFC_NOM_X1_X32_SHIFT 16 ++ ++#define DDRCTRL_INIT0_SKIP_DRAM_INIT_MASK GENMASK_32(31, 30) ++#define DDRCTRL_INIT0_SKIP_DRAM_INIT_NORMAL BIT(30) ++ ++#define DDRCTRL_DFIMISC_DFI_INIT_COMPLETE_EN BIT(0) ++ ++#define DDRCTRL_DBG1_DIS_HIF BIT(1) ++ ++#define DDRCTRL_DBGCAM_WR_DATA_PIPELINE_EMPTY BIT(29) ++#define DDRCTRL_DBGCAM_RD_DATA_PIPELINE_EMPTY BIT(28) ++#define DDRCTRL_DBGCAM_DBG_WR_Q_EMPTY BIT(26) ++#define DDRCTRL_DBGCAM_DBG_LPR_Q_DEPTH GENMASK_32(12, 8) ++#define DDRCTRL_DBGCAM_DBG_HPR_Q_DEPTH GENMASK_32(4, 0) ++ ++#define DDRCTRL_DBGCAM_DATA_PIPELINE_EMPTY \ ++ (DDRCTRL_DBGCAM_WR_DATA_PIPELINE_EMPTY | \ ++ DDRCTRL_DBGCAM_RD_DATA_PIPELINE_EMPTY) ++ ++#define DDRCTRL_DBGCAM_DBG_Q_DEPTH \ ++ (DDRCTRL_DBGCAM_DBG_WR_Q_EMPTY | \ ++ DDRCTRL_DBGCAM_DBG_LPR_Q_DEPTH | \ ++ DDRCTRL_DBGCAM_DBG_HPR_Q_DEPTH) ++ ++#define DDRCTRL_DBGCMD_RANK0_REFRESH BIT(0) ++ ++#define DDRCTRL_DBGSTAT_RANK0_REFRESH_BUSY BIT(0) ++ ++#define DDRCTRL_SWCTL_SW_DONE BIT(0) ++ ++#define DDRCTRL_SWSTAT_SW_DONE_ACK BIT(0) ++ ++#define DDRCTRL_PCTRL_N_PORT_EN BIT(0) ++ ++/* DDR PHY registers offsets */ ++#define DDRPHYC_PIR 0x004 ++#define DDRPHYC_PGCR 0x008 ++#define DDRPHYC_PGSR 0x00C ++#define DDRPHYC_DLLGCR 0x010 ++#define DDRPHYC_ACDLLCR 0x014 ++#define DDRPHYC_PTR0 0x018 ++#define DDRPHYC_ACIOCR 0x024 ++#define DDRPHYC_DXCCR 0x028 ++#define DDRPHYC_DSGCR 0x02C ++#define DDRPHYC_ZQ0CR0 0x180 ++#define DDRPHYC_DX0GCR 0x1C0 ++#define DDRPHYC_DX0DLLCR 0x1CC ++#define DDRPHYC_DX1GCR 0x200 ++#define DDRPHYC_DX1DLLCR 0x20C ++#define DDRPHYC_DX2GCR 0x240 ++#define DDRPHYC_DX2DLLCR 0x24C ++#define DDRPHYC_DX3GCR 0x280 ++#define DDRPHYC_DX3DLLCR 0x28C ++ ++/* DDR PHY Register fields */ ++#define DDRPHYC_PIR_INIT BIT(0) ++#define DDRPHYC_PIR_DLLSRST BIT(1) ++#define DDRPHYC_PIR_DLLLOCK BIT(2) ++#define DDRPHYC_PIR_ZCAL BIT(3) ++#define DDRPHYC_PIR_ITMSRST BIT(4) ++#define DDRPHYC_PIR_DRAMRST BIT(5) ++#define DDRPHYC_PIR_DRAMINIT BIT(6) ++#define DDRPHYC_PIR_QSTRN BIT(7) ++#define DDRPHYC_PIR_ICPC BIT(16) ++#define DDRPHYC_PIR_ZCALBYP BIT(30) ++#define DDRPHYC_PIR_INITSTEPS_MASK GENMASK(31, 7) ++ ++#define DDRPHYC_PGCR_DFTCMP BIT(2) ++#define DDRPHYC_PGCR_PDDISDX BIT(24) ++#define DDRPHYC_PGCR_RFSHDT_MASK GENMASK_32(28, 25) ++ ++#define DDRPHYC_PGSR_IDONE BIT(0) ++#define DDRPHYC_PGSR_DTERR BIT(5) ++#define DDRPHYC_PGSR_DTIERR BIT(6) ++#define DDRPHYC_PGSR_DFTERR BIT(7) ++#define DDRPHYC_PGSR_RVERR BIT(8) ++#define DDRPHYC_PGSR_RVEIRR BIT(9) ++ ++#define DDRPHYC_DLLGCR_BPS200 BIT(23) ++ ++#define DDRPHYC_ACDLLCR_DLLSRST BIT(30) ++#define DDRPHYC_ACDLLCR_DLLDIS BIT(31) ++ ++#define DDRPHYC_PTR0_TDLLSRST_OFFSET 0 ++#define DDRPHYC_PTR0_TDLLSRST_MASK GENMASK_32(5, 0) ++#define DDRPHYC_PTR0_TDLLLOCK_OFFSET 6 ++#define DDRPHYC_PTR0_TDLLLOCK_MASK GENMASK_32(17, 6) ++#define DDRPHYC_PTR0_TITMSRST_OFFSET 18 ++#define DDRPHYC_PTR0_TITMSRST_MASK GENMASK_32(21, 18) ++ ++#define DDRPHYC_ACIOCR_ACPDD BIT(3) ++#define DDRPHYC_ACIOCR_ACPDR BIT(4) ++#define DDRPHYC_ACIOCR_CKPDD_MASK GENMASK_32(10, 8) ++#define DDRPHYC_ACIOCR_CKPDD_0 BIT(8) ++#define DDRPHYC_ACIOCR_CKPDR_MASK GENMASK_32(13, 11) ++#define DDRPHYC_ACIOCR_CKPDR_0 BIT(11) ++#define DDRPHYC_ACIOCR_CSPDD_MASK GENMASK_32(21, 18) ++#define DDRPHYC_ACIOCR_CSPDD_0 BIT(18) ++#define DDRPHYC_ACIOCR_RSTPDD BIT(27) ++#define DDRPHYC_ACIOCR_RSTPDR BIT(28) ++ ++#define DDRPHYC_DXCCR_DXPDD BIT(2) ++#define DDRPHYC_DXCCR_DXPDR BIT(3) ++ ++#define DDRPHYC_DSGCR_CKEPDD_MASK GENMASK_32(19, 16) ++#define DDRPHYC_DSGCR_CKEPDD_0 BIT(16) ++#define DDRPHYC_DSGCR_ODTPDD_MASK GENMASK_32(23, 20) ++#define DDRPHYC_DSGCR_ODTPDD_0 BIT(20) ++#define DDRPHYC_DSGCR_NL2PD BIT(24) ++ ++#define DDRPHYC_ZQ0CRN_ZDATA_MASK GENMASK_32(27, 0) ++#define DDRPHYC_ZQ0CRN_ZDATA_SHIFT 0 ++#define DDRPHYC_ZQ0CRN_ZDEN BIT(28) ++#define DDRPHYC_ZQ0CRN_ZQPD BIT(31) ++ ++#define DDRPHYC_DXNGCR_DXEN BIT(0) ++ ++#define DDRPHYC_DXNDLLCR_DLLSRST BIT(30) ++#define DDRPHYC_DXNDLLCR_DLLDIS BIT(31) ++#define DDRPHYC_DXNDLLCR_SDPHASE_MASK GENMASK(17, 14) ++#define DDRPHYC_DXNDLLCR_SDPHASE_SHIFT 14 ++ ++uint32_t get_ddrphy_calibration(void); ++ ++int ddr_sw_self_refresh_exit(void); ++int ddr_standby_sr_entry(uint32_t *zq0cr0_zdata); ++void ddr_sr_mode_ssr(void); ++void ddr_sr_mode_asr(void); ++void ddr_sr_mode_hsr(void); ++ ++#endif /*__STM32MP1_DDRC_H__*/ +diff --git a/core/arch/arm/plat-stm32mp1/drivers/stm32mp1_pmic.c b/core/arch/arm/plat-stm32mp1/drivers/stm32mp1_pmic.c +new file mode 100644 +index 0000000..ed38575 +--- /dev/null ++++ b/core/arch/arm/plat-stm32mp1/drivers/stm32mp1_pmic.c +@@ -0,0 +1,614 @@ ++// SPDX-License-Identifier: BSD-3-Clause ++/* ++ * Copyright (c) 2017-2018, STMicroelectronics - All Rights Reserved ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#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 ++ ++static struct i2c_handle_s i2c_handle; ++static uint32_t pmic_i2c_addr; ++ ++bool stm32mp_with_pmic(void) ++{ ++ return (i2c_handle.dt_status & DT_STATUS_OK_SEC) != 0; ++} ++ ++static int dt_get_pmic_node(void *fdt) ++{ ++ return fdt_node_offset_by_compatible(fdt, -1, "st,stpmic1"); ++} ++ ++static int dt_pmic_status(void) ++{ ++ void *fdt = get_dt_blob(); ++ ++ if (fdt) { ++ int node = dt_get_pmic_node(fdt); ++ ++ if (node > 0) { ++ return _fdt_get_status(fdt, node); ++ } ++ } ++ ++ return -1; ++} ++ ++static bool dt_pmic_is_secure(void) ++{ ++ int status = dt_pmic_status(); ++ ++ return ((unsigned)status == DT_STATUS_OK_SEC) && ++ (i2c_handle.dt_status == DT_STATUS_OK_SEC); ++} ++ ++/* ++ * @idx: Private identifier provided by the target PMIC driver ++ * @flags: Operations expected when entering a low power sequence ++ * @voltage: Target voltage to apply during low power sequences ++ */ ++struct regu_bo_config { ++ uint8_t flags; ++ struct stpmic1_bo_cfg cfg; ++}; ++ ++#define REGU_BO_FLAG_ENABLE_REGU BIT(0) ++#define REGU_BO_FLAG_SET_VOLTAGE BIT(1) ++#define REGU_BO_FLAG_PULL_DOWN BIT(2) ++#define REGU_BO_FLAG_MASK_RESET BIT(3) ++ ++static struct regu_bo_config *regu_bo_config; ++static size_t regu_bo_count; ++ ++static int save_boot_on_config(void) ++{ ++ int pmic_node, regulators_node, regulator_node; ++ void *fdt; ++ ++ assert(!regu_bo_config && !regu_bo_count); ++ ++ fdt = get_dt_blob(); ++ if (fdt == NULL) { ++ panic(); ++ } ++ ++ pmic_node = dt_get_pmic_node(fdt); ++ if (pmic_node < 0) { ++ panic(); ++ } ++ ++ regulators_node = fdt_subnode_offset(fdt, pmic_node, "regulators"); ++ ++ fdt_for_each_subnode(regulator_node, 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) { ++ continue; ++ } ++ ++ memset(®u_cfg, 0, sizeof(regu_cfg)); ++ name = fdt_get_name(fdt, regulator_node, NULL); ++ ++ regu_cfg.flags |= REGU_BO_FLAG_ENABLE_REGU; ++ ++ if (fdt_getprop(fdt, regulator_node, "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", ++ 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, ++ "regulator-min-microvolt", NULL); ++ if (cuint != NULL) { ++ /* DT uses microvolts, whereas driver awaits millivolts */ ++ mv = (uint16_t)(fdt32_to_cpu(*cuint) / 1000U); ++ ++ if (!stpmic1_bo_voltage_cfg(name, mv, ®u_cfg.cfg)) { ++ regu_cfg.flags |= REGU_BO_FLAG_SET_VOLTAGE; ++ } ++ } ++ ++ /* Save config in the Boot On configuration list */ ++ regu_bo_count++; ++ regu_bo_config = realloc(regu_bo_config, ++ regu_bo_count * sizeof(regu_cfg)); ++ if (regu_bo_config == NULL) { ++ panic(); ++ } ++ ++ memcpy(®u_bo_config[regu_bo_count - 1], ®u_cfg, ++ sizeof(regu_cfg)); ++ } ++ ++ return 0; ++} ++ ++void stm32mp_pmic_apply_boot_on_config(void) ++{ ++ size_t i; ++ ++ for (i = 0; i < regu_bo_count; i++) { ++ struct regu_bo_config *regu_cfg = ®u_bo_config[i]; ++ ++ if (regu_cfg->flags & REGU_BO_FLAG_SET_VOLTAGE) { ++ if (stpmic1_bo_voltage_unpg(®u_cfg->cfg)) { ++ panic(); ++ } ++ } ++ ++ if (regu_cfg->flags & REGU_BO_FLAG_ENABLE_REGU) { ++ if (stpmic1_bo_enable_unpg(®u_cfg->cfg)) { ++ panic(); ++ } ++ } ++ ++ if (regu_cfg->flags & REGU_BO_FLAG_PULL_DOWN) { ++ if (stpmic1_bo_pull_down_unpg(®u_cfg->cfg)) { ++ panic(); ++ } ++ } ++ ++ if (regu_cfg->flags & REGU_BO_FLAG_MASK_RESET) { ++ if (stpmic1_bo_mask_reset_unpg(®u_cfg->cfg)) { ++ panic(); ++ } ++ } ++ } ++} ++ ++/* ++ * @idx: Private identifier provided by the target PMIC driver ++ * @flags: Operations expected when entering a low power sequence ++ * @voltage: Target voltage to apply during low power sequences ++ */ ++struct regu_lp_config { ++ uint8_t flags; ++ struct stpmic1_lp_cfg cfg; ++}; ++ ++#define REGU_LP_FLAG_LOAD_PWRCTRL BIT(0) ++#define REGU_LP_FLAG_ON_IN_SUSPEND BIT(1) ++#define REGU_LP_FLAG_OFF_IN_SUSPEND BIT(2) ++#define REGU_LP_FLAG_SET_VOLTAGE BIT(3) ++#define REGU_LP_FLAG_MODE_STANDBY BIT(4) ++ ++struct regu_lp_state { ++ const char *name; ++ size_t cfg_count; ++ struct regu_lp_config *cfg; ++}; ++ ++#define REGU_LP_STATE_DISK 0 ++#define REGU_LP_STATE_STANDBY 1 ++#define REGU_LP_STATE_MEM 2 ++#define REGU_LP_STATE_COUNT 3 ++ ++static struct regu_lp_state regu_lp_state[REGU_LP_STATE_COUNT] = { ++ [REGU_LP_STATE_DISK] = { .name = "standby-ddr-off", }, ++ [REGU_LP_STATE_STANDBY] = { .name = "standby-ddr-sr", }, ++ [REGU_LP_STATE_MEM] = { .name = "lp-stop", }, ++}; ++ ++static unsigned int regu_lp_state2idx(const char *name) ++{ ++ unsigned int i; ++ ++ for (i = 0; i < ARRAY_SIZE(regu_lp_state); i++) { ++ struct regu_lp_state *state = ®u_lp_state[i]; ++ ++ if (!strncmp(name, state->name, strlen(state->name))) { ++ return i; ++ } ++ } ++ ++ panic(); ++} ++ ++static int save_low_power_config(const char *lp_state) ++{ ++ int pmic_node, regulators_node, regulator_node; ++ void *fdt; ++ unsigned int state_idx = regu_lp_state2idx(lp_state); ++ struct regu_lp_state *state = ®u_lp_state[state_idx]; ++ ++ assert(!state->cfg && !state->cfg_count); ++ ++ fdt = get_dt_blob(); ++ if (fdt == NULL) { ++ 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"); ++ ++ fdt_for_each_subnode(regulator_node, fdt, regulators_node) { ++ const fdt32_t *cuint; ++ const char *reg_name; ++ int regulator_state_node; ++ struct regu_lp_config *regu_cfg; ++ ++ state->cfg_count++; ++ state->cfg = realloc(state->cfg, ++ state->cfg_count * sizeof(*state->cfg)); ++ if (state->cfg == NULL) { ++ panic(); ++ } ++ ++ regu_cfg = &state->cfg[state->cfg_count - 1]; ++ ++ memset(regu_cfg, 0, sizeof(*regu_cfg)); ++ ++ reg_name = fdt_get_name(fdt, regulator_node, NULL); ++ ++ if (stpmic1_lp_cfg(reg_name, ®u_cfg->cfg) != 0) { ++ EMSG("Invalid regu name %s", reg_name); ++ return -1; ++ } ++ ++ /* ++ * Always copy active configuration (Control register) to ++ * PWRCTRL Control register, even if regulator_state_node ++ * does not exist. ++ */ ++ regu_cfg->flags |= REGU_LP_FLAG_LOAD_PWRCTRL; ++ ++ /* Then apply configs from regulator_state_node */ ++ regulator_state_node = fdt_subnode_offset(fdt, ++ regulator_node, ++ lp_state); ++ if (regulator_state_node <= 0) { ++ continue; ++ } ++ ++ if (fdt_getprop(fdt, regulator_state_node, ++ "regulator-on-in-suspend", NULL) != NULL) { ++ regu_cfg->flags |= REGU_LP_FLAG_ON_IN_SUSPEND; ++ } ++ ++ if (fdt_getprop(fdt, regulator_state_node, ++ "regulator-off-in-suspend", NULL) != NULL) { ++ regu_cfg->flags |= REGU_LP_FLAG_OFF_IN_SUSPEND; ++ } ++ ++ cuint = fdt_getprop(fdt, regulator_state_node, ++ "regulator-suspend-microvolt", NULL); ++ if (cuint != NULL) { ++ uint32_t mv = fdt32_to_cpu(*cuint) / 1000U; ++ ++ if (stpmic1_lp_voltage_cfg(reg_name, mv, ++ ®u_cfg->cfg) == 0) { ++ regu_cfg->flags |= REGU_LP_FLAG_SET_VOLTAGE; ++ } ++ } ++ ++ cuint = fdt_getprop(fdt, regulator_state_node, ++ "regulator-mode", NULL); ++ if (cuint != NULL) { ++ if (fdt32_to_cpu(*cuint) == MODE_STANDBY) { ++ regu_cfg->flags |= REGU_LP_FLAG_MODE_STANDBY; ++ } ++ } ++ } ++ ++ return 0; ++} ++ ++/* ++ * int stm32mp_pmic_set_lp_config(char *lp_state) ++ * ++ * Load the low power configuration stored in regu_lp_state[]. ++ */ ++void stm32mp_pmic_apply_lp_config(const char *lp_state) ++{ ++ unsigned int state_idx = regu_lp_state2idx(lp_state); ++ struct regu_lp_state *state = ®u_lp_state[state_idx]; ++ size_t i; ++ ++ if (stpmic1_powerctrl_on() != 0) { ++ panic(); ++ } ++ ++ for (i = 0; i < state->cfg_count; i++) { ++ struct stpmic1_lp_cfg *cfg = &state->cfg[i].cfg; ++ ++ if ((state->cfg[i].flags & REGU_LP_FLAG_LOAD_PWRCTRL) != 0) { ++ if (stpmic1_lp_load_unpg(cfg) != 0) { ++ panic(); ++ } ++ } ++ ++ if ((state->cfg[i].flags & REGU_LP_FLAG_ON_IN_SUSPEND) != 0) { ++ if (stpmic1_lp_on_off_unpg(cfg, 1) != 0) { ++ panic(); ++ } ++ } ++ ++ if ((state->cfg[i].flags & REGU_LP_FLAG_OFF_IN_SUSPEND) != 0) { ++ if (stpmic1_lp_on_off_unpg(cfg, 0) != 0) { ++ panic(); ++ } ++ } ++ ++ if ((state->cfg[i].flags & REGU_LP_FLAG_SET_VOLTAGE) != 0) { ++ if (stpmic1_lp_voltage_unpg(cfg) != 0) { ++ panic(); ++ } ++ } ++ ++ if ((state->cfg[i].flags & REGU_LP_FLAG_MODE_STANDBY) != 0) { ++ if (stpmic1_lp_mode_unpg(cfg, 1) != 0) { ++ panic(); ++ } ++ } ++ } ++} ++ ++static int save_power_configurations(void) ++{ ++ unsigned int i; ++ ++ if (save_boot_on_config() != 0) { ++ return -1; ++ } ++ ++ for (i = 0; i < ARRAY_SIZE(regu_lp_state); i++) { ++ if (save_low_power_config(regu_lp_state[i].name) != 0) { ++ return -1; ++ } ++ } ++ ++ return 0; ++} ++ ++/* ++ * Get PMIC and its I2C bus configuration from the device tree. ++ * Return 0 on success, negative on error, 1 if no PMIC node is defined. ++ */ ++static int dt_pmic_i2c_config(struct dt_node_info *i2c_info, ++ struct stm32_pinctrl **pinctrl, ++ size_t *pinctrl_count, ++ struct stm32_i2c_init_s *init) ++{ ++ int pmic_node; ++ int i2c_node; ++ void *fdt; ++ const fdt32_t *cuint; ++ ++ fdt = get_dt_blob(); ++ if (!fdt) { ++ return -1; ++ } ++ ++ pmic_node = dt_get_pmic_node(fdt); ++ if (pmic_node < 0) { ++ return 1; ++ } ++ ++ cuint = fdt_getprop(fdt, pmic_node, "reg", NULL); ++ if (cuint == NULL) { ++ return -FDT_ERR_NOTFOUND; ++ } ++ ++ pmic_i2c_addr = fdt32_to_cpu(*cuint) << 1; ++ if (pmic_i2c_addr > UINT16_MAX) { ++ return -1; ++ } ++ ++ i2c_node = fdt_parent_offset(fdt, pmic_node); ++ if (i2c_node < 0) { ++ return -FDT_ERR_NOTFOUND; ++ } ++ ++ fdt_fill_device_info(fdt, i2c_info, i2c_node); ++ if (i2c_info->base == 0U) { ++ return -FDT_ERR_NOTFOUND; ++ } ++ ++ return stm32_i2c_get_setup_from_fdt(fdt, i2c_node, init, ++ pinctrl, pinctrl_count); ++} ++ ++/* ++ * PMIC and resource initialization ++ */ ++ ++/* Return true if PMIC is available, false if not found, panics on errors */ ++static bool initialize_pmic_i2c(void) ++{ ++ int ret; ++ struct dt_node_info i2c_info; ++ struct i2c_handle_s *i2c = &i2c_handle; ++ struct stm32_pinctrl *pinctrl; ++ size_t pinctrl_count; ++ struct stm32_i2c_init_s i2c_init; ++ ++ ret = dt_pmic_i2c_config(&i2c_info, &pinctrl, &pinctrl_count, ++ &i2c_init); ++ if (ret < 0) { ++ EMSG("I2C configuration failed %d\n", ret); ++ panic(); ++ } ++ if (ret != 0) { ++ return false; ++ } ++ ++ /* Initialize PMIC I2C */ ++ i2c->pbase = i2c_info.base; ++ i2c->vbase = (uintptr_t)phys_to_virt(i2c_info.base, MEM_AREA_IO_SEC); ++ assert(i2c->vbase); ++ i2c->dt_status = i2c_info.status; ++ i2c->clock = i2c_info.clock; ++ i2c_init.own_address1 = pmic_i2c_addr; ++ i2c_init.addressing_mode = I2C_ADDRESSINGMODE_7BIT; ++ i2c_init.dual_address_mode = I2C_DUALADDRESS_DISABLE; ++ i2c_init.own_address2 = 0; ++ i2c_init.own_address2_masks = I2C_OAR2_OA2NOMASK; ++ i2c_init.general_call_mode = I2C_GENERALCALL_DISABLE; ++ i2c_init.no_stretch_mode = I2C_NOSTRETCH_DISABLE; ++ i2c_init.analog_filter = 1; ++ i2c_init.digital_filter_coef = 0; ++ ++ i2c->pinctrl = pinctrl; ++ i2c->pinctrl_count = pinctrl_count; ++ ++ stm32mp_get_pmic(); ++ ++ ret = stm32_i2c_init(i2c, &i2c_init); ++ if (ret != 0) { ++ EMSG("Cannot initialize I2C %x (%d)\n", i2c->pbase, ret); ++ panic(); ++ } ++ ++ if (!stm32_i2c_is_device_ready(i2c, pmic_i2c_addr, 1, ++ I2C_TIMEOUT_BUSY_MS)) { ++ EMSG("I2C device not ready\n"); ++ panic(); ++ } ++ ++ stpmic1_bind_i2c(i2c, (uint16_t)pmic_i2c_addr); ++ ++ stm32mp_put_pmic(); ++ ++ return true; ++} ++ ++/* ++ * Automated suspend/resume at system suspend/resume is expected ++ * only when the PMIC is secure. If it is non secure, only atomic ++ * execution context acn get/put the PMIC resources. ++ */ ++static void pmic_suspend_resume(enum pm_op op, void __unused *handle) ++{ ++ switch (op) { ++ case PM_OP_SUSPEND: ++ stm32_i2c_suspend(&i2c_handle); ++ break; ++ case PM_OP_RESUME: ++ stm32_i2c_resume(&i2c_handle); ++ break; ++ default: ++ panic(); ++ } ++} ++KEEP_PAGER(pmic_suspend_resume); ++ ++/* stm32mp_get/put_pmic allows secure atomic sequences to use non secure PMIC */ ++void stm32mp_get_pmic(void) ++{ ++ stm32_i2c_resume(&i2c_handle); ++} ++ ++void stm32mp_put_pmic(void) ++{ ++ stm32_i2c_suspend(&i2c_handle); ++} ++ ++static void register_non_secure_pmic(void) ++{ ++ size_t n; ++ ++ if (!i2c_handle.pbase) { ++ return; ++ } ++ ++ stm32mp_register_non_secure_periph_iomem(i2c_handle.pbase); ++ stm32mp_register_clock_parents_secure(i2c_handle.clock); ++ ++ for (n = 0; n < i2c_handle.pinctrl_count; n++) { ++ stm32mp_register_non_secure_gpio(i2c_handle.pinctrl[n].bank, ++ i2c_handle.pinctrl[n].pin); ++ } ++} ++ ++static void register_secure_pmic(void) ++{ ++ size_t n; ++ ++ stm32mp_register_pm_cb(pmic_suspend_resume, NULL); ++ stm32mp_register_secure_periph_iomem(i2c_handle.pbase); ++ ++ for (n = 0; n < i2c_handle.pinctrl_count; n++) { ++ stm32mp_register_secure_gpio(i2c_handle.pinctrl[n].bank, ++ i2c_handle.pinctrl[n].pin); ++ } ++} ++ ++static TEE_Result initialize_pmic(void) ++{ ++ unsigned long pmic_version; ++ ++ if (!initialize_pmic_i2c()) { ++ DMSG("No PMIC"); ++ register_non_secure_pmic(); ++ return TEE_SUCCESS; ++ } ++ ++ stm32mp_get_pmic(); ++ ++ if (stpmic1_get_version(&pmic_version)) { ++ panic("Failed to access PMIC"); ++ } ++ ++ DMSG("PMIC version = 0x%02lx", pmic_version); ++ stpmic1_dump_regulators(); ++ ++ if (save_power_configurations() != 0) { ++ panic(); ++ } ++ ++ if (dt_pmic_is_secure()) { ++ register_secure_pmic(); ++ } else { ++ register_non_secure_pmic(); ++ } ++ ++ stm32mp_put_pmic(); ++ ++ return TEE_SUCCESS; ++} ++driver_init(initialize_pmic); ++ +diff --git a/core/arch/arm/plat-stm32mp1/drivers/stm32mp1_pmic.h b/core/arch/arm/plat-stm32mp1/drivers/stm32mp1_pmic.h +new file mode 100644 +index 0000000..f50943d +--- /dev/null ++++ b/core/arch/arm/plat-stm32mp1/drivers/stm32mp1_pmic.h +@@ -0,0 +1,33 @@ ++/* SPDX-License-Identifier: BSD-3-Clause */ ++/* ++ * Copyright (c) 2017-2018, STMicroelectronics - All Rights Reserved ++ */ ++ ++#ifndef __STM32MP1_PMIC_H__ ++#define __STM32MP1_PMIC_H__ ++ ++#include ++ ++#ifdef CFG_STPMIC1 ++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); ++#else ++void stm32mp_pmic_apply_boot_on_config(void) ++{ ++} ++void stm32mp_pmic_apply_lp_config(const char *lp_state) ++{ ++} ++void stm32mp_get_pmic(void) ++{ ++ panic(); ++} ++void stm32mp_put_pmic(void) ++{ ++ panic(); ++} ++#endif ++ ++#endif /*__STM32MP1_PMIC_H__*/ +diff --git a/core/arch/arm/plat-stm32mp1/drivers/stm32mp1_pwr.c b/core/arch/arm/plat-stm32mp1/drivers/stm32mp1_pwr.c +new file mode 100644 +index 0000000..ce60f50 +--- /dev/null ++++ b/core/arch/arm/plat-stm32mp1/drivers/stm32mp1_pwr.c +@@ -0,0 +1,21 @@ ++// SPDX-License-Identifier: BSD-3-Clause ++/* ++ * Copyright (c) 2017-2018, STMicroelectronics ++ */ ++ ++#include ++#include ++#include ++ ++uintptr_t stm32_pwr_base(void) ++{ ++ static void *va; ++ ++ if (!cpu_mmu_enabled()) ++ return PWR_BASE; ++ ++ if (!va) ++ va = phys_to_virt(PWR_BASE, MEM_AREA_IO_SEC); ++ ++ return (uintptr_t)va; ++} +diff --git a/core/arch/arm/plat-stm32mp1/drivers/stm32mp1_pwr.h b/core/arch/arm/plat-stm32mp1/drivers/stm32mp1_pwr.h +new file mode 100644 +index 0000000..1d44e8b +--- /dev/null ++++ b/core/arch/arm/plat-stm32mp1/drivers/stm32mp1_pwr.h +@@ -0,0 +1,48 @@ ++/* SPDX-License-Identifier: BSD-3-Clause */ ++/* ++ * Copyright (c) 2017-2018, STMicroelectronics ++ */ ++ ++#ifndef __STM32MP1_PWR_H__ ++#define __STM32MP1_PWR_H__ ++ ++#include ++ ++#define PWR_CR1_OFF 0x00 ++#define PWR_CR2_OFF 0x08 ++#define PWR_CR3_OFF 0x0c ++#define PWR_MPUCR_OFF 0x10 ++#define PWR_WKUPCR_OFF 0x20 ++#define PWR_MPUWKUPENR_OFF 0x28 ++ ++#define PWR_OFFSET_MASK GENMASK_32(5, 0) ++ ++#define PWR_CR1_LPDS BIT(0) ++#define PWR_CR1_LPCFG BIT(1) ++#define PWR_CR1_LVDS BIT(2) ++#define PWR_CR1_DBP BIT(8) ++ ++#define PWR_CR2_BREN BIT(0) ++#define PWR_CR2_RREN BIT(1) ++ ++#define PWR_CR3_VBE BIT(8) ++#define PWR_CR3_VBRS BIT(9) ++#define PWR_CR3_DDRSREN BIT(10) ++#define PWR_CR3_DDRSRDIS BIT(11) ++#define PWR_CR3_DDRRETEN BIT(12) ++#define PWR_CR3_USB33DEN BIT(24) ++#define PWR_CR3_REG18EN BIT(28) ++#define PWR_CR3_REG11EN BIT(30) ++ ++#define PWR_MPUCR_PDDS BIT(0) ++#define PWR_MPUCR_CSTDBYDIS BIT(3) ++#define PWR_MPUCR_CSSF BIT(9) ++ ++#define PWR_WKUPCR_MASK (GENMASK_32(27, 16) | \ ++ GENMASK_32(13, 8) | GENMASK_32(5, 0)) ++ ++#define PWR_MPUWKUPENR_MASK GENMASK_32(5, 0) ++ ++uintptr_t stm32_pwr_base(void); ++ ++#endif /*__STM32MP1_PWR_H__*/ +diff --git a/core/arch/arm/plat-stm32mp1/drivers/stm32mp1_rcc.c b/core/arch/arm/plat-stm32mp1/drivers/stm32mp1_rcc.c +new file mode 100644 +index 0000000..a9df116 +--- /dev/null ++++ b/core/arch/arm/plat-stm32mp1/drivers/stm32mp1_rcc.c +@@ -0,0 +1,51 @@ ++// SPDX-License-Identifier: BSD-3-Clause ++/* ++ * Copyright (c) 2017-2018, STMicroelectronics ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++uintptr_t stm32_rcc_base(void) ++{ ++ static void *va; ++ ++ if (!cpu_mmu_enabled()) { ++ return RCC_BASE; ++ } ++ ++ if (!va) { ++ va = phys_to_virt(RCC_BASE, MEM_AREA_IO_SEC); ++ } ++ ++ return (uintptr_t)va; ++} ++ ++void stm32_rcc_secure(int enable) ++{ ++ uintptr_t base = stm32_rcc_base(); ++ ++ if (enable != 0) { ++ io_mask32_stm32shregs(base + RCC_TZCR, RCC_TZCR_TZEN, ++ RCC_TZCR_TZEN); ++ } else { ++ io_mask32_stm32shregs(base + RCC_TZCR, 0, RCC_TZCR_TZEN); ++ } ++} ++ ++bool stm32_rcc_is_secure(void) ++{ ++ uintptr_t base = stm32_rcc_base(); ++ ++ return read32(base + RCC_TZCR) & RCC_TZCR_TZEN; ++} ++ ++bool stm32_rcc_is_mckprot(void) ++{ ++ uintptr_t base = stm32_rcc_base(); ++ ++ return read32(base + RCC_TZCR) & RCC_TZCR_MCKPROT; ++} +diff --git a/core/arch/arm/plat-stm32mp1/drivers/stm32mp1_rcc.h b/core/arch/arm/plat-stm32mp1/drivers/stm32mp1_rcc.h +new file mode 100644 +index 0000000..6a7a665 +--- /dev/null ++++ b/core/arch/arm/plat-stm32mp1/drivers/stm32mp1_rcc.h +@@ -0,0 +1,539 @@ ++/* SPDX-License-Identifier: BSD-3-Clause */ ++/* ++ * Copyright (c) 2017-2018, STMicroelectronics ++ */ ++ ++#ifndef __STM32MP1_RCC_H__ ++#define __STM32MP1_RCC_H__ ++ ++#include ++#include ++ ++#define RCC_TZCR 0x00 ++#define RCC_OCENSETR 0x0C ++#define RCC_OCENCLRR 0x10 ++#define RCC_HSICFGR 0x18 ++#define RCC_CSICFGR 0x1C ++#define RCC_MPCKSELR 0x20 ++#define RCC_ASSCKSELR 0x24 ++#define RCC_RCK12SELR 0x28 ++#define RCC_MPCKDIVR 0x2C ++#define RCC_AXIDIVR 0x30 ++#define RCC_APB4DIVR 0x3C ++#define RCC_APB5DIVR 0x40 ++#define RCC_RTCDIVR 0x44 ++#define RCC_MSSCKSELR 0x48 ++#define RCC_PLL1CR 0x80 ++#define RCC_PLL1CFGR1 0x84 ++#define RCC_PLL1CFGR2 0x88 ++#define RCC_PLL1FRACR 0x8C ++#define RCC_PLL1CSGR 0x90 ++#define RCC_PLL2CR 0x94 ++#define RCC_PLL2CFGR1 0x98 ++#define RCC_PLL2CFGR2 0x9C ++#define RCC_PLL2FRACR 0xA0 ++#define RCC_PLL2CSGR 0xA4 ++#define RCC_I2C46CKSELR 0xC0 ++#define RCC_SPI6CKSELR 0xC4 ++#define RCC_UART1CKSELR 0xC8 ++#define RCC_RNG1CKSELR 0xCC ++#define RCC_CPERCKSELR 0xD0 ++#define RCC_STGENCKSELR 0xD4 ++#define RCC_DDRITFCR 0xD8 ++#define RCC_MP_BOOTCR 0x100 ++#define RCC_MP_SREQSETR 0x104 ++#define RCC_MP_SREQCLRR 0x108 ++#define RCC_MP_GCR 0x10C ++#define RCC_MP_APRSTCR 0x110 ++#define RCC_MP_APRSTSR 0x114 ++#define RCC_BDCR 0x140 ++#define RCC_RDLSICR 0x144 ++#define RCC_APB4RSTSETR 0x180 ++#define RCC_APB4RSTCLRR 0x184 ++#define RCC_APB5RSTSETR 0x188 ++#define RCC_APB5RSTCLRR 0x18C ++#define RCC_AHB5RSTSETR 0x190 ++#define RCC_AHB5RSTCLRR 0x194 ++#define RCC_AHB6RSTSETR 0x198 ++#define RCC_AHB6RSTCLRR 0x19C ++#define RCC_TZAHB6RSTSETR 0x1A0 ++#define RCC_TZAHB6RSTCLRR 0x1A4 ++#define RCC_MP_APB4ENSETR 0x200 ++#define RCC_MP_APB4ENCLRR 0x204 ++#define RCC_MP_APB5ENSETR 0x208 ++#define RCC_MP_APB5ENCLRR 0x20C ++#define RCC_MP_AHB5ENSETR 0x210 ++#define RCC_MP_AHB5ENCLRR 0x214 ++#define RCC_MP_AHB6ENSETR 0x218 ++#define RCC_MP_AHB6ENCLRR 0x21C ++#define RCC_MP_TZAHB6ENSETR 0x220 ++#define RCC_MP_TZAHB6ENCLRR 0x224 ++#define RCC_MC_APB4ENSETR 0x280 ++#define RCC_MC_APB4ENCLRR 0x284 ++#define RCC_MC_APB5ENSETR 0x288 ++#define RCC_MC_APB5ENCLRR 0x28C ++#define RCC_MC_AHB5ENSETR 0x290 ++#define RCC_MC_AHB5ENCLRR 0x294 ++#define RCC_MC_AHB6ENSETR 0x298 ++#define RCC_MC_AHB6ENCLRR 0x29C ++#define RCC_MP_APB4LPENSETR 0x300 ++#define RCC_MP_APB4LPENCLRR 0x304 ++#define RCC_MP_APB5LPENSETR 0x308 ++#define RCC_MP_APB5LPENCLRR 0x30C ++#define RCC_MP_AHB5LPENSETR 0x310 ++#define RCC_MP_AHB5LPENCLRR 0x314 ++#define RCC_MP_AHB6LPENSETR 0x318 ++#define RCC_MP_AHB6LPENCLRR 0x31C ++#define RCC_MP_TZAHB6LPENSETR 0x320 ++#define RCC_MP_TZAHB6LPENCLRR 0x324 ++#define RCC_MC_APB4LPENSETR 0x380 ++#define RCC_MC_APB4LPENCLRR 0x384 ++#define RCC_MC_APB5LPENSETR 0x388 ++#define RCC_MC_APB5LPENCLRR 0x38C ++#define RCC_MC_AHB5LPENSETR 0x390 ++#define RCC_MC_AHB5LPENCLRR 0x394 ++#define RCC_MC_AHB6LPENSETR 0x398 ++#define RCC_MC_AHB6LPENCLRR 0x39C ++#define RCC_BR_RSTSCLRR 0x400 ++#define RCC_MP_GRSTCSETR 0x404 ++#define RCC_MP_RSTSCLRR 0x408 ++#define RCC_MP_IWDGFZSETR 0x40C ++#define RCC_MP_IWDGFZCLRR 0x410 ++#define RCC_MP_CIER 0x414 ++#define RCC_MP_CIFR 0x418 ++#define RCC_PWRLPDLYCR 0x41C ++#define RCC_MP_RSTSSETR 0x420 ++#define RCC_MCO1CFGR 0x800 ++#define RCC_MCO2CFGR 0x804 ++#define RCC_OCRDYR 0x808 ++#define RCC_DBGCFGR 0x80C ++#define RCC_RCK3SELR 0x820 ++#define RCC_RCK4SELR 0x824 ++#define RCC_TIMG1PRER 0x828 ++#define RCC_TIMG2PRER 0x82C ++#define RCC_MCUDIVR 0x830 ++#define RCC_APB1DIVR 0x834 ++#define RCC_APB2DIVR 0x838 ++#define RCC_APB3DIVR 0x83C ++#define RCC_PLL3CR 0x880 ++#define RCC_PLL3CFGR1 0x884 ++#define RCC_PLL3CFGR2 0x888 ++#define RCC_PLL3FRACR 0x88C ++#define RCC_PLL3CSGR 0x890 ++#define RCC_PLL4CR 0x894 ++#define RCC_PLL4CFGR1 0x898 ++#define RCC_PLL4CFGR2 0x89C ++#define RCC_PLL4FRACR 0x8A0 ++#define RCC_PLL4CSGR 0x8A4 ++#define RCC_I2C12CKSELR 0x8C0 ++#define RCC_I2C35CKSELR 0x8C4 ++#define RCC_SAI1CKSELR 0x8C8 ++#define RCC_SAI2CKSELR 0x8CC ++#define RCC_SAI3CKSELR 0x8D0 ++#define RCC_SAI4CKSELR 0x8D4 ++#define RCC_SPI2S1CKSELR 0x8D8 ++#define RCC_SPI2S23CKSELR 0x8DC ++#define RCC_SPI45CKSELR 0x8E0 ++#define RCC_UART6CKSELR 0x8E4 ++#define RCC_UART24CKSELR 0x8E8 ++#define RCC_UART35CKSELR 0x8EC ++#define RCC_UART78CKSELR 0x8F0 ++#define RCC_SDMMC12CKSELR 0x8F4 ++#define RCC_SDMMC3CKSELR 0x8F8 ++#define RCC_ETHCKSELR 0x8FC ++#define RCC_QSPICKSELR 0x900 ++#define RCC_FMCCKSELR 0x904 ++#define RCC_FDCANCKSELR 0x90C ++#define RCC_SPDIFCKSELR 0x914 ++#define RCC_CECCKSELR 0x918 ++#define RCC_USBCKSELR 0x91C ++#define RCC_RNG2CKSELR 0x920 ++#define RCC_DSICKSELR 0x924 ++#define RCC_ADCCKSELR 0x928 ++#define RCC_LPTIM45CKSELR 0x92C ++#define RCC_LPTIM23CKSELR 0x930 ++#define RCC_LPTIM1CKSELR 0x934 ++#define RCC_APB1RSTSETR 0x980 ++#define RCC_APB1RSTCLRR 0x984 ++#define RCC_APB2RSTSETR 0x988 ++#define RCC_APB2RSTCLRR 0x98C ++#define RCC_APB3RSTSETR 0x990 ++#define RCC_APB3RSTCLRR 0x994 ++#define RCC_AHB2RSTSETR 0x998 ++#define RCC_AHB2RSTCLRR 0x99C ++#define RCC_AHB3RSTSETR 0x9A0 ++#define RCC_AHB3RSTCLRR 0x9A4 ++#define RCC_AHB4RSTSETR 0x9A8 ++#define RCC_AHB4RSTCLRR 0x9AC ++#define RCC_MP_APB1ENSETR 0xA00 ++#define RCC_MP_APB1ENCLRR 0xA04 ++#define RCC_MP_APB2ENSETR 0xA08 ++#define RCC_MP_APB2ENCLRR 0xA0C ++#define RCC_MP_APB3ENSETR 0xA10 ++#define RCC_MP_APB3ENCLRR 0xA14 ++#define RCC_MP_AHB2ENSETR 0xA18 ++#define RCC_MP_AHB2ENCLRR 0xA1C ++#define RCC_MP_AHB3ENSETR 0xA20 ++#define RCC_MP_AHB3ENCLRR 0xA24 ++#define RCC_MP_AHB4ENSETR 0xA28 ++#define RCC_MP_AHB4ENCLRR 0xA2C ++#define RCC_MP_MLAHBENSETR 0xA38 ++#define RCC_MP_MLAHBENCLRR 0xA3C ++#define RCC_MC_APB1ENSETR 0xA80 ++#define RCC_MC_APB1ENCLRR 0xA84 ++#define RCC_MC_APB2ENSETR 0xA88 ++#define RCC_MC_APB2ENCLRR 0xA8C ++#define RCC_MC_APB3ENSETR 0xA90 ++#define RCC_MC_APB3ENCLRR 0xA94 ++#define RCC_MC_AHB2ENSETR 0xA98 ++#define RCC_MC_AHB2ENCLRR 0xA9C ++#define RCC_MC_AHB3ENSETR 0xAA0 ++#define RCC_MC_AHB3ENCLRR 0xAA4 ++#define RCC_MC_AHB4ENSETR 0xAA8 ++#define RCC_MC_AHB4ENCLRR 0xAAC ++#define RCC_MC_AXIMENSETR 0xAB0 ++#define RCC_MC_AXIMENCLRR 0xAB4 ++#define RCC_MC_MLAHBENSETR 0xAB8 ++#define RCC_MC_MLAHBENCLRR 0xABC ++#define RCC_MP_APB1LPENSETR 0xB00 ++#define RCC_MP_APB1LPENCLRR 0xB04 ++#define RCC_MP_APB2LPENSETR 0xB08 ++#define RCC_MP_APB2LPENCLRR 0xB0C ++#define RCC_MP_APB3LPENSETR 0xB10 ++#define RCC_MP_APB3LPENCLRR 0xB14 ++#define RCC_MP_AHB2LPENSETR 0xB18 ++#define RCC_MP_AHB2LPENCLRR 0xB1C ++#define RCC_MP_AHB3LPENSETR 0xB20 ++#define RCC_MP_AHB3LPENCLRR 0xB24 ++#define RCC_MP_AHB4LPENSETR 0xB28 ++#define RCC_MP_AHB4LPENCLRR 0xB2C ++#define RCC_MP_AXIMLPENSETR 0xB30 ++#define RCC_MP_AXIMLPENCLRR 0xB34 ++#define RCC_MP_MLAHBLPENSETR 0xB38 ++#define RCC_MP_MLAHBLPENCLRR 0xB3C ++#define RCC_MC_APB1LPENSETR 0xB80 ++#define RCC_MC_APB1LPENCLRR 0xB84 ++#define RCC_MC_APB2LPENSETR 0xB88 ++#define RCC_MC_APB2LPENCLRR 0xB8C ++#define RCC_MC_APB3LPENSETR 0xB90 ++#define RCC_MC_APB3LPENCLRR 0xB94 ++#define RCC_MC_AHB2LPENSETR 0xB98 ++#define RCC_MC_AHB2LPENCLRR 0xB9C ++#define RCC_MC_AHB3LPENSETR 0xBA0 ++#define RCC_MC_AHB3LPENCLRR 0xBA4 ++#define RCC_MC_AHB4LPENSETR 0xBA8 ++#define RCC_MC_AHB4LPENCLRR 0xBAC ++#define RCC_MC_AXIMLPENSETR 0xBB0 ++#define RCC_MC_AXIMLPENCLRR 0xBB4 ++#define RCC_MC_MLAHBLPENSETR 0xBB8 ++#define RCC_MC_MLAHBLPENCLRR 0xBBC ++#define RCC_MC_RSTSCLRR 0xC00 ++#define RCC_MC_CIER 0xC14 ++#define RCC_MC_CIFR 0xC18 ++#define RCC_VERR 0xFF4 ++#define RCC_IDR 0xFF8 ++#define RCC_SIDR 0xFFC ++ ++#define RCC_OFFSET_MASK GENMASK_32(11, 0) ++ ++/* Values for RCC_TZCR register */ ++#define RCC_TZCR_TZEN BIT(0) ++#define RCC_TZCR_MCKPROT BIT(1) ++ ++/* Used for most of RCC_SELR registers */ ++#define RCC_SELR_SRC_MASK GENMASK_32(2, 0) ++#define RCC_SELR_REFCLK_SRC_MASK GENMASK_32(1, 0) ++#define RCC_SELR_SRCRDY BIT(31) ++ ++/* Values of RCC_MPCKSELR register */ ++#define RCC_MPCKSELR_HSI 0x00000000 ++#define RCC_MPCKSELR_HSE 0x00000001 ++#define RCC_MPCKSELR_PLL 0x00000002 ++#define RCC_MPCKSELR_PLL_MPUDIV 0x00000003 ++ ++/* Values of RCC_ASSCKSELR register */ ++#define RCC_ASSCKSELR_HSI 0x00000000 ++#define RCC_ASSCKSELR_HSE 0x00000001 ++#define RCC_ASSCKSELR_PLL 0x00000002 ++ ++/* Values of RCC_MSSCKSELR register */ ++#define RCC_MSSCKSELR_HSI 0x00000000 ++#define RCC_MSSCKSELR_HSE 0x00000001 ++#define RCC_MSSCKSELR_CSI 0x00000002 ++#define RCC_MSSCKSELR_PLL 0x00000003 ++ ++/* Values of RCC_CPERCKSELR register */ ++#define RCC_CPERCKSELR_HSI 0x00000000 ++#define RCC_CPERCKSELR_CSI 0x00000001 ++#define RCC_CPERCKSELR_HSE 0x00000002 ++ ++/* Used for most of DIVR register: max div for RTC */ ++#define RCC_DIVR_DIV_MASK GENMASK_32(5, 0) ++#define RCC_DIVR_DIVRDY BIT(31) ++ ++/* Masks for specific DIVR registers */ ++#define RCC_APBXDIV_MASK GENMASK_32(2, 0) ++#define RCC_MPUDIV_MASK GENMASK_32(2, 0) ++#define RCC_AXIDIV_MASK GENMASK_32(2, 0) ++#define RCC_MCUDIV_MASK GENMASK_32(3, 0) ++ ++/* Used for TIMER Prescaler */ ++#define RCC_TIMGXPRER_TIMGXPRE BIT(0) ++ ++/* Offset between RCC_MP_xxxENSETR and RCC_MP_xxxENCLRR registers */ ++#define RCC_MP_ENCLRR_OFFSET 4u ++ ++/* Fields of RCC_BDCR register */ ++#define RCC_BDCR_LSEON BIT(0) ++#define RCC_BDCR_LSEBYP BIT(1) ++#define RCC_BDCR_LSERDY BIT(2) ++#define RCC_BDCR_DIGBYP BIT(3) ++#define RCC_BDCR_LSEDRV_MASK GENMASK_32(5, 4) ++#define RCC_BDCR_LSEDRV_SHIFT 4 ++#define RCC_BDCR_LSECSSON BIT(8) ++#define RCC_BDCR_RTCCKEN BIT(20) ++#define RCC_BDCR_RTCSRC_MASK GENMASK_32(17, 16) ++#define RCC_BDCR_RTCSRC_SHIFT 16 ++#define RCC_BDCR_VSWRST BIT(31) ++ ++/* Fields of RCC_RDLSICR register */ ++#define RCC_RDLSICR_LSION BIT(0) ++#define RCC_RDLSICR_LSIRDY BIT(1) ++ ++/* Used for all RCC_PLLCR registers */ ++#define RCC_PLLNCR_PLLON BIT(0) ++#define RCC_PLLNCR_PLLRDY BIT(1) ++#define RCC_PLLNCR_SSCG_CTRL BIT(2) ++#define RCC_PLLNCR_DIVPEN BIT(4) ++#define RCC_PLLNCR_DIVQEN BIT(5) ++#define RCC_PLLNCR_DIVREN BIT(6) ++#define RCC_PLLNCR_DIVEN_SHIFT 4 ++ ++/* Used for all RCC_PLLCFGR1 registers */ ++#define RCC_PLLNCFGR1_DIVM_SHIFT 16 ++#define RCC_PLLNCFGR1_DIVM_MASK GENMASK_32(21, 16) ++#define RCC_PLLNCFGR1_DIVN_SHIFT 0 ++#define RCC_PLLNCFGR1_DIVN_MASK GENMASK_32(8, 0) ++/* Only for PLL3 and PLL4 */ ++#define RCC_PLLNCFGR1_IFRGE_SHIFT 24 ++#define RCC_PLLNCFGR1_IFRGE_MASK GENMASK_32(25, 24) ++ ++/* Used for all RCC_PLLCFGR2 registers */ ++#define RCC_PLLNCFGR2_DIVX_MASK GENMASK_32(6, 0) ++#define RCC_PLLNCFGR2_DIVP_SHIFT 0 ++#define RCC_PLLNCFGR2_DIVP_MASK GENMASK_32(6, 0) ++#define RCC_PLLNCFGR2_DIVQ_SHIFT 8 ++#define RCC_PLLNCFGR2_DIVQ_MASK GENMASK_32(14, 8) ++#define RCC_PLLNCFGR2_DIVR_SHIFT 16 ++#define RCC_PLLNCFGR2_DIVR_MASK GENMASK_32(22, 16) ++ ++/* Used for all RCC_PLLFRACR registers */ ++#define RCC_PLLNFRACR_FRACV_SHIFT 3 ++#define RCC_PLLNFRACR_FRACV_MASK GENMASK_32(15, 3) ++#define RCC_PLLNFRACR_FRACLE BIT(16) ++ ++/* Used for all RCC_PLLCSGR registers */ ++#define RCC_PLLNCSGR_INC_STEP_SHIFT 16 ++#define RCC_PLLNCSGR_INC_STEP_MASK GENMASK_32(30, 16) ++#define RCC_PLLNCSGR_MOD_PER_SHIFT 0 ++#define RCC_PLLNCSGR_MOD_PER_MASK GENMASK_32(12, 0) ++#define RCC_PLLNCSGR_SSCG_MODE_SHIFT 15 ++#define RCC_PLLNCSGR_SSCG_MODE_MASK BIT(15) ++ ++/* Used for RCC_OCENSETR and RCC_OCENCLRR registers */ ++#define RCC_OCENR_HSION BIT(0) ++#define RCC_OCENR_HSIKERON BIT(1) ++#define RCC_OCENR_CSION BIT(4) ++#define RCC_OCENR_CSIKERON BIT(5) ++#define RCC_OCENR_DIGBYP BIT(7) ++#define RCC_OCENR_HSEON BIT(8) ++#define RCC_OCENR_HSEKERON BIT(9) ++#define RCC_OCENR_HSEBYP BIT(10) ++#define RCC_OCENR_HSECSSON BIT(11) ++ ++/* Fields of RCC_OCRDYR register */ ++#define RCC_OCRDYR_HSIRDY BIT(0) ++#define RCC_OCRDYR_HSIDIVRDY BIT(2) ++#define RCC_OCRDYR_CSIRDY BIT(4) ++#define RCC_OCRDYR_HSERDY BIT(8) ++ ++/* Fields of RCC_DDRITFCR register */ ++#define RCC_DDRITFCR_DDRC1EN BIT(0) ++#define RCC_DDRITFCR_DDRC1LPEN BIT(1) ++#define RCC_DDRITFCR_DDRC2EN BIT(2) ++#define RCC_DDRITFCR_DDRC2LPEN BIT(3) ++#define RCC_DDRITFCR_DDRPHYCEN BIT(4) ++#define RCC_DDRITFCR_DDRPHYCLPEN BIT(5) ++#define RCC_DDRITFCR_DDRCAPBEN BIT(6) ++#define RCC_DDRITFCR_DDRCAPBLPEN BIT(7) ++#define RCC_DDRITFCR_AXIDCGEN BIT(8) ++#define RCC_DDRITFCR_DDRPHYCAPBEN BIT(9) ++#define RCC_DDRITFCR_DDRPHYCAPBLPEN BIT(10) ++#define RCC_DDRITFCR_DDRCAPBRST BIT(14) ++#define RCC_DDRITFCR_DDRCAXIRST BIT(15) ++#define RCC_DDRITFCR_DDRCORERST BIT(16) ++#define RCC_DDRITFCR_DPHYAPBRST BIT(17) ++#define RCC_DDRITFCR_DPHYRST BIT(18) ++#define RCC_DDRITFCR_DPHYCTLRST BIT(19) ++#define RCC_DDRITFCR_DDRCKMOD_MASK GENMASK_32(22, 20) ++#define RCC_DDRITFCR_DDRCKMOD_SHIFT 20 ++#define RCC_DDRITFCR_DDRCKMOD_SSR 0 ++#define RCC_DDRITFCR_DDRCKMOD_ASR1 BIT(20) ++#define RCC_DDRITFCR_DDRCKMOD_HSR1 BIT(21) ++#define RCC_DDRITFCR_GSKPCTRL BIT(24) ++ ++/* Fields of RCC_HSICFGR register */ ++#define RCC_HSICFGR_HSIDIV_MASK GENMASK_32(1, 0) ++#define RCC_HSICFGR_HSITRIM_SHIFT 8 ++#define RCC_HSICFGR_HSITRIM_MASK GENMASK_32(14, 8) ++#define RCC_HSICFGR_HSICAL_SHIFT 16 ++#define RCC_HSICFGR_HSICAL_MASK GENMASK_32(27, 16) ++ ++/* Fields of RCC_CSICFGR register */ ++#define RCC_CSICFGR_CSITRIM_SHIFT 8 ++#define RCC_CSICFGR_CSITRIM_MASK GENMASK_32(12, 8) ++#define RCC_CSICFGR_CSICAL_SHIFT 16 ++#define RCC_CSICFGR_CSICAL_MASK GENMASK_32(23, 16) ++ ++/* Used for RCC_MCO related operations */ ++#define RCC_MCOCFG_MCOON BIT(12) ++#define RCC_MCOCFG_MCODIV_MASK GENMASK_32(7, 4) ++#define RCC_MCOCFG_MCODIV_SHIFT 4 ++#define RCC_MCOCFG_MCOSRC_MASK GENMASK_32(2, 0) ++ ++/* Fields of RCC_DBGCFGR register */ ++#define RCC_DBGCFGR_DBGCKEN BIT(8) ++ ++/* RCC register fields for reset reasons */ ++#define RCC_MP_RSTSCLRR_PORRSTF BIT(0) ++#define RCC_MP_RSTSCLRR_BORRSTF BIT(1) ++#define RCC_MP_RSTSCLRR_PADRSTF BIT(2) ++#define RCC_MP_RSTSCLRR_HCSSRSTF BIT(3) ++#define RCC_MP_RSTSCLRR_VCORERSTF BIT(4) ++#define RCC_MP_RSTSCLRR_MPSYSRSTF BIT(6) ++#define RCC_MP_RSTSCLRR_MCSYSRSTF BIT(7) ++#define RCC_MP_RSTSCLRR_IWDG1RSTF BIT(8) ++#define RCC_MP_RSTSCLRR_IWDG2RSTF BIT(9) ++#define RCC_MP_RSTSCLRR_STDBYRSTF BIT(11) ++#define RCC_MP_RSTSCLRR_CSTDBYRSTF BIT(12) ++ ++/* Global Reset Register */ ++#define RCC_MP_GRSTCSETR_MPSYSRST BIT(0) ++#define RCC_MP_GRSTCSETR_MCURST BIT(1) ++#define RCC_MP_GRSTCSETR_MPUP0RST BIT(4) ++#define RCC_MP_GRSTCSETR_MPUP1RST BIT(5) ++ ++/* Clock Source Interrupt Flag Register */ ++#define RCC_MP_CIFR_LSIRDYF BIT(0) ++#define RCC_MP_CIFR_LSERDYF BIT(1) ++#define RCC_MP_CIFR_HSIRDYF BIT(2) ++#define RCC_MP_CIFR_HSERDYF BIT(3) ++#define RCC_MP_CIFR_CSIRDYF BIT(4) ++#define RCC_MP_CIFR_PLL1DYF BIT(8) ++#define RCC_MP_CIFR_PLL2DYF BIT(9) ++#define RCC_MP_CIFR_PLL3DYF BIT(10) ++#define RCC_MP_CIFR_PLL4DYF BIT(11) ++#define RCC_MP_CIFR_LSECSSF BIT(16) ++#define RCC_MP_CIFR_WKUPF BIT(20) ++#define RCC_MP_CIFR_MASK (RCC_MP_CIFR_LSIRDYF | RCC_MP_CIFR_LSERDYF | \ ++ RCC_MP_CIFR_HSIRDYF | RCC_MP_CIFR_HSERDYF | \ ++ RCC_MP_CIFR_CSIRDYF | RCC_MP_CIFR_PLL1DYF | \ ++ RCC_MP_CIFR_PLL2DYF | RCC_MP_CIFR_PLL3DYF | \ ++ RCC_MP_CIFR_PLL4DYF | RCC_MP_CIFR_LSECSSF | \ ++ RCC_MP_CIFR_WKUPF) ++ ++/* Stop Request Set Register */ ++#define RCC_MP_SREQSETR_STPREQ_P0 BIT(0) ++#define RCC_MP_SREQSETR_STPREQ_P1 BIT(1) ++ ++/* Stop Request Clear Register */ ++#define RCC_MP_SREQCLRR_STPREQ_P0 BIT(0) ++#define RCC_MP_SREQCLRR_STPREQ_P1 BIT(1) ++ ++/* RCC_MP_APB5RST(SET|CLR)R bit fields */ ++#define RCC_APB5RSTSETR_SPI6RST BIT(0) ++#define RCC_APB5RSTSETR_I2C4RST BIT(2) ++#define RCC_APB5RSTSETR_I2C6RST BIT(3) ++#define RCC_APB5RSTSETR_USART1RST BIT(4) ++#define RCC_APB5RSTSETR_STGENRST BIT(20) ++ ++/* RCC_MP_APB5EN(SET|CLR)R bit fields */ ++#define RCC_MP_APB5ENSETR_SPI6EN_POS 0 ++#define RCC_MP_APB5ENSETR_I2C4EN_POS 2 ++#define RCC_MP_APB5ENSETR_I2C6EN_POS 3 ++#define RCC_MP_APB5ENSETR_USART1EN_POS 4 ++#define RCC_MP_APB5ENSETR_RTCAPBEN_POS 8 ++#define RCC_MP_APB5ENSETR_TZC1EN_POS 11 ++#define RCC_MP_APB5ENSETR_TZC2EN_POS 12 ++#define RCC_MP_APB5ENSETR_TZPCEN_POS 13 ++#define RCC_MP_APB5ENSETR_IWDG1APBEN_POS 15 ++#define RCC_MP_APB5ENSETR_BSECEN_POS 16 ++#define RCC_MP_APB5ENSETR_STGENEN_POS 20 ++ ++#define RCC_MP_APB5ENSETR_SPI6EN BIT(RCC_MP_APB5ENSETR_SPI6EN_POS) ++#define RCC_MP_APB5ENSETR_I2C4EN BIT(RCC_MP_APB5ENSETR_I2C4EN_POS) ++#define RCC_MP_APB5ENSETR_I2C6EN BIT(RCC_MP_APB5ENSETR_I2C6EN_POS) ++#define RCC_MP_APB5ENSETR_USART1EN BIT(RCC_MP_APB5ENSETR_USART1EN_POS) ++#define RCC_MP_APB5ENSETR_RTCAPBEN BIT(RCC_MP_APB5ENSETR_RTCAPBEN_POS) ++#define RCC_MP_APB5ENSETR_TZC1EN BIT(RCC_MP_APB5ENSETR_TZC1EN_POS) ++#define RCC_MP_APB5ENSETR_TZC2EN BIT(RCC_MP_APB5ENSETR_TZC2EN_POS) ++#define RCC_MP_APB5ENSETR_TZPCEN BIT(RCC_MP_APB5ENSETR_TZPCEN_POS) ++#define RCC_MP_APB5ENSETR_IWDG1APBEN BIT(RCC_MP_APB5ENSETR_IWDG1APBEN_POS) ++#define RCC_MP_APB5ENSETR_BSECEN BIT(RCC_MP_APB5ENSETR_BSECEN_POS) ++#define RCC_MP_APB5ENSETR_STGENEN BIT(RCC_MP_APB5ENSETR_STGENEN_POS) ++ ++/* RCC_MP_APB5LPEN(SET|CLR)R bit fields */ ++#define RCC_MP_APB5LPENSETR_SPI6LPEN BIT(0) ++#define RCC_MP_APB5LPENSETR_I2C4LPEN BIT(2) ++#define RCC_MP_APB5LPENSETR_I2C6LPEN BIT(3) ++#define RCC_MP_APB5LPENSETR_USART1LPEN BIT(4) ++#define RCC_MP_APB5LPENSETR_RTCAPBLPEN BIT(8) ++#define RCC_MP_APB5LPENSETR_TZC1LPEN BIT(11) ++#define RCC_MP_APB5LPENSETR_TZC2LPEN BIT(12) ++#define RCC_MP_APB5LPENSETR_TZPCLPEN BIT(13) ++#define RCC_MP_APB5LPENSETR_IWDG1APBLPEN BIT(15) ++#define RCC_MP_APB5LPENSETR_BSECLPEN BIT(16) ++#define RCC_MP_APB5LPENSETR_STGENLPEN BIT(20) ++#define RCC_MP_APB5LPENSETR_STGENSTPEN BIT(21) ++ ++/* RCC_MP_AHB5RST(SET|CLR)R bit fields */ ++#define RCC_AHB5RSTSETR_GPIOZRST BIT(0) ++#define RCC_AHB5RSTSETR_CRYP1RST BIT(4) ++#define RCC_AHB5RSTSETR_HASH1RST BIT(5) ++#define RCC_AHB5RSTSETR_RNG1RST BIT(6) ++#define RCC_AHB5RSTSETR_AXIMCRST BIT(16) ++ ++/* RCC_MP_AHB5EN(SET|CLR)R bit fields */ ++#define RCC_MP_AHB5ENSETR_GPIOZEN_POS 0 ++#define RCC_MP_AHB5ENSETR_CRYP1EN_POS 4 ++#define RCC_MP_AHB5ENSETR_HASH1EN_POS 5 ++#define RCC_MP_AHB5ENSETR_RNG1EN_POS 6 ++#define RCC_MP_AHB5ENSETR_BKPSRAMEN_POS 8 ++#define RCC_MP_AHB5ENSETR_AXIMCEN_POS 16 ++ ++#define RCC_MP_AHB5ENSETR_GPIOZEN BIT(RCC_MP_AHB5ENSETR_GPIOZEN_POS) ++#define RCC_MP_AHB5ENSETR_CRYP1EN BIT(RCC_MP_AHB5ENSETR_CRYP1EN_POS) ++#define RCC_MP_AHB5ENSETR_HASH1EN BIT(RCC_MP_AHB5ENSETR_HASH1EN_POS) ++#define RCC_MP_AHB5ENSETR_RNG1EN BIT(RCC_MP_AHB5ENSETR_RNG1EN_POS) ++#define RCC_MP_AHB5ENSETR_BKPSRAMEN BIT(RCC_MP_AHB5ENSETR_BKPSRAMEN_POS) ++#define RCC_MP_AHB5ENSETR_AXIMCEN BIT(RCC_MP_AHB5ENSETR_AXIMCEN_POS) ++ ++/* RCC_MP_AHB5LPEN(SET|CLR)R bit fields */ ++#define RCC_MP_AHB5LPENSETR_GPIOZLPEN BIT(0) ++#define RCC_MP_AHB5LPENSETR_CRYP1LPEN BIT(4) ++#define RCC_MP_AHB5LPENSETR_HASH1LPEN BIT(5) ++#define RCC_MP_AHB5LPENSETR_RNG1LPEN BIT(6) ++#define RCC_MP_AHB5LPENSETR_BKPSRAMLPEN BIT(8) ++ ++/* RCC_MP_IWDGFZ(SET|CLR)R bit fields */ ++#define RCC_MP_IWDGFZSETR_IWDG1 BIT(0) ++#define RCC_MP_IWDGFZSETR_IWDG2 BIT(1) ++ ++#ifndef ASM ++uintptr_t stm32_rcc_base(void); ++void stm32_rcc_secure(int enable); ++bool stm32_rcc_is_secure(void); ++bool stm32_rcc_is_mckprot(void); ++#endif ++ ++#endif /*__STM32MP1_RCC_H__*/ +diff --git a/core/arch/arm/plat-stm32mp1/drivers/sub.mk b/core/arch/arm/plat-stm32mp1/drivers/sub.mk +new file mode 100644 +index 0000000..c668efa +--- /dev/null ++++ b/core/arch/arm/plat-stm32mp1/drivers/sub.mk +@@ -0,0 +1,8 @@ ++srcs-y += stm32mp1_pwr.c ++srcs-y += stm32mp1_rcc.c ++srcs-$(CFG_STM32_CLOCKSRC_CALIB) += stm32mp1_calib.c ++srcs-y += stm32_reset.c ++srcs-$(CFG_STPMIC1) += stm32mp1_pmic.c ++srcs-y += stm32mp1_clk.c ++srcs-$(CFG_DT) += stm32mp1_clkfunc.c ++srcs-y += stm32mp1_ddrc.c +diff --git a/core/arch/arm/plat-stm32mp1/link.mk b/core/arch/arm/plat-stm32mp1/link.mk +index 97e22ea..01a9b8e 100644 +--- a/core/arch/arm/plat-stm32mp1/link.mk ++++ b/core/arch/arm/plat-stm32mp1/link.mk +@@ -11,14 +11,14 @@ endef + all: $(link-out-dir)/tee-header_v2.stm32 + cleanfiles += $(link-out-dir)/tee-header_v2.stm32 + $(link-out-dir)/tee-header_v2.stm32: $(link-out-dir)/tee-header_v2.bin +- $(stm32image_cmd) --source $< --dest $@ ++ $(stm32image_cmd) --source $< --dest $@ --bintype 0x20 + + all: $(link-out-dir)/tee-pager_v2.stm32 + cleanfiles += $(link-out-dir)/tee-pager_v2.stm32 + $(link-out-dir)/tee-pager_v2.stm32: $(link-out-dir)/tee-pager_v2.bin +- $(stm32image_cmd) --source $< --dest $@ ++ $(stm32image_cmd) --source $< --dest $@ --bintype 0x21 + + all: $(link-out-dir)/tee-pageable_v2.stm32 + cleanfiles += $(link-out-dir)/tee-pageable_v2.stm32 + $(link-out-dir)/tee-pageable_v2.stm32: $(link-out-dir)/tee-pageable_v2.bin +- $(stm32image_cmd) --source $< --dest $@ ++ $(stm32image_cmd) --source $< --dest $@ --bintype 0x22 +diff --git a/core/arch/arm/plat-stm32mp1/main.c b/core/arch/arm/plat-stm32mp1/main.c +index f45e3cd..1921678 100644 +--- a/core/arch/arm/plat-stm32mp1/main.c ++++ b/core/arch/arm/plat-stm32mp1/main.c +@@ -4,32 +4,105 @@ + * Copyright (c) 2016-2018, Linaro Limited + */ + ++#include + #include + #include + #include ++#include ++#include ++#include + #include ++#include ++#include ++#include ++#include ++#include ++#include + #include ++#include + #include + #include + #include ++#include ++#include + #include + #include ++#include + #include ++#include + #include + #include ++#include ++#include ++#include ++#include ++#include ++#include ++#include + +-register_phys_mem(MEM_AREA_IO_NSEC, CONSOLE_UART_BASE, CONSOLE_UART_SIZE); ++#ifdef CFG_WITH_NSEC_GPIOS ++register_phys_mem(MEM_AREA_IO_NSEC, GPIOS_NSEC_BASE, GPIOS_NSEC_SIZE); ++#endif ++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); ++#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); ++register_phys_mem(MEM_AREA_IO_NSEC, USART3_BASE, SMALL_PAGE_SIZE); ++register_phys_mem(MEM_AREA_IO_NSEC, UART4_BASE, SMALL_PAGE_SIZE); ++register_phys_mem(MEM_AREA_IO_NSEC, UART5_BASE, SMALL_PAGE_SIZE); ++register_phys_mem(MEM_AREA_IO_NSEC, USART6_BASE, SMALL_PAGE_SIZE); ++register_phys_mem(MEM_AREA_IO_NSEC, UART7_BASE, SMALL_PAGE_SIZE); ++register_phys_mem(MEM_AREA_IO_NSEC, UART8_BASE, SMALL_PAGE_SIZE); ++#endif + +-register_phys_mem(MEM_AREA_IO_SEC, GIC_BASE, GIC_SIZE); +-register_phys_mem(MEM_AREA_IO_SEC, BKP_REGS_BASE, SMALL_PAGE_SIZE); ++register_phys_mem(MEM_AREA_IO_SEC, GIC_IOMEM_BASE, GIC_IOMEM_SIZE); ++register_phys_mem(MEM_AREA_IO_SEC, TAMP_BASE, SMALL_PAGE_SIZE); ++register_phys_mem(MEM_AREA_IO_SEC, RCC_BASE, SMALL_PAGE_SIZE); ++register_phys_mem(MEM_AREA_IO_SEC, PWR_BASE, SMALL_PAGE_SIZE); ++register_phys_mem(MEM_AREA_IO_SEC, ETZPC_BASE, SMALL_PAGE_SIZE); ++register_phys_mem(MEM_AREA_IO_SEC, BSEC_BASE, SMALL_PAGE_SIZE); ++register_phys_mem(MEM_AREA_IO_SEC, I2C4_BASE, SMALL_PAGE_SIZE); ++register_phys_mem(MEM_AREA_IO_SEC, STGEN_BASE, SMALL_PAGE_SIZE); ++register_phys_mem(MEM_AREA_IO_SEC, GPIOZ_BASE, ++ STM32MP1_GPIOZ_MAX_COUNT * SMALL_PAGE_SIZE); ++register_phys_mem(MEM_AREA_IO_SEC, RNG1_BASE, SMALL_PAGE_SIZE); ++register_phys_mem(MEM_AREA_IO_SEC, IWDG1_BASE, SMALL_PAGE_SIZE); ++register_phys_mem(MEM_AREA_IO_SEC, RTC_BASE, SMALL_PAGE_SIZE); ++register_phys_mem(MEM_AREA_IO_SEC, DDRCTRL_BASE, SMALL_PAGE_SIZE); ++register_phys_mem(MEM_AREA_IO_SEC, DDRPHYC_BASE, SMALL_PAGE_SIZE); ++register_phys_mem(MEM_AREA_IO_SEC, BKPSRAM_BASE, SMALL_PAGE_SIZE); ++register_phys_mem(MEM_AREA_IO_SEC, USART1_BASE, SMALL_PAGE_SIZE); + +-static struct gic_data gic_data; +-static struct console_pdata console_data; ++register_phys_mem(MEM_AREA_ROM_SEC, TEE_RAM_START, TEE_RAM_PH_SIZE); + +-static void main_fiq(void) ++register_ddr(DDR_BASE, STM32MP1_DDR_SIZE_DFLT); ++ ++#ifdef CFG_STM32MP_MAP_NSEC_LOW_DDR ++register_phys_mem(MEM_AREA_RAM_NSEC, DDR_BASE, SMALL_PAGE_SIZE); ++#endif ++ ++#define _ID2STR(id) (#id) ++#define ID2STR(id) _ID2STR(id) ++ ++static TEE_Result platform_banner(void) + { +- gic_it_handle(&gic_data); ++#ifdef CFG_DT ++ IMSG("Platform stm32mp1: flavor %s - device tree %s", ++ ID2STR(PLATFORM_FLAVOR), ID2STR(CFG_SECURE_DT)); ++ IMSG("Model: %s", fdt_get_board_model(get_dt_blob())); ++#else ++ IMSG("Platform stm32mp1: flavor %s - no device tree", ++ ID2STR(PLATFORM_FLAVOR)); ++#endif ++ ++ return TEE_SUCCESS; + } ++service_init(platform_banner); ++ ++static void main_fiq(void); + + static const struct thread_handlers handlers = { + .std_smc = tee_entry_std, +@@ -48,10 +121,132 @@ const struct thread_handlers *generic_boot_get_handlers(void) + return &handlers; + } + ++/* ++ * Console ++ * ++ * We cannot use the generic serial_console support since probing ++ * the console requires the platform clock driver to be already ++ * up and ready which is done only once service_init are completed. ++ * ++ * If the console uses a non secure UART, its clock might have been ++ * disabled by the non secure world, in which case secure traces must ++ * be dropped unless what the driver may stall since the UART FIFO is ++ * never emptied. ++ */ ++#define CONSOLE_WITHOUT_CLOCK_MAGIC ~0UL ++ ++static struct stm32_uart_pdata console_data; ++static struct serial_chip *serial_console; ++ + void console_init(void) + { +- stm32_uart_init(&console_data, CONSOLE_UART_BASE); ++ /* Early console initialization before MMU setup */ ++ struct uart { ++ uintptr_t pa; ++ bool secure; ++ } uarts[] = { ++ [0] = { .pa = 0 }, ++ [1] = { .pa = USART1_BASE, .secure = true, }, ++ [2] = { .pa = USART2_BASE, .secure = false, }, ++ [3] = { .pa = USART3_BASE, .secure = false, }, ++ [4] = { .pa = UART4_BASE, .secure = false, }, ++ [5] = { .pa = UART5_BASE, .secure = false, }, ++ [6] = { .pa = USART6_BASE, .secure = false, }, ++ [7] = { .pa = UART7_BASE, .secure = false, }, ++ [8] = { .pa = UART8_BASE, .secure = false, }, ++ }; ++ ++ COMPILE_TIME_ASSERT(CFG_STM32_EARLY_CONSOLE_UART < ARRAY_SIZE(uarts)); ++ assert(!cpu_mmu_enabled()); ++ ++ if (!uarts[CFG_STM32_EARLY_CONSOLE_UART].pa) { ++ return; ++ } ++ ++ /* No clock/PINCTRL yet bound to the UART console */ ++ console_data.clock = CONSOLE_WITHOUT_CLOCK_MAGIC; ++ ++ console_data.secure = uarts[CFG_STM32_EARLY_CONSOLE_UART].secure; ++ stm32_uart_init(&console_data, uarts[CFG_STM32_EARLY_CONSOLE_UART].pa); ++ ++#ifdef CFG_FORCE_CONSOLE_ON_SUSPEND ++ serial_console = &console_data.chip; ++#else + register_serial_console(&console_data.chip); ++#endif ++ ++ IMSG("Early console on UART#%u", CFG_STM32_EARLY_CONSOLE_UART); ++} ++ ++#ifdef CFG_FORCE_CONSOLE_ON_SUSPEND ++void console_putc(int ch) ++{ ++ if (!serial_console) ++ return; ++ ++ stm32_pinctrl_load_active_cfg(console_data.pinctrl, ++ console_data.pinctrl_count); ++ ++ if (ch == '\n') ++ serial_console->ops->putc(serial_console, '\r'); ++ ++ serial_console->ops->putc(serial_console, ch); ++} ++ ++void console_flush(void) ++{ ++ if (!serial_console) ++ return; ++ ++ serial_console->ops->flush(serial_console); ++} ++#endif ++ ++#if CFG_DT ++/* Probe console once clocks inits (service_init level) are completed */ ++static TEE_Result stm32_uart_console_probe(void) ++{ ++ void *fdt; ++ int node; ++ struct stm32_uart_pdata *pd = NULL; ++ ++ fdt = get_dt_blob(); ++ if (fdt == NULL) { ++ panic(); ++ } ++ ++ node = fdt_get_stdout_node_offset(fdt); ++ if (node >= 0) { ++ pd = probe_uart_from_dt_node(fdt, node); ++ } ++ ++ if (pd) { ++ serial_console = NULL; ++ dmb(); ++ memcpy(&console_data, pd, sizeof(*pd)); ++ dmb(); ++ serial_console = &console_data.chip; ++ free(pd); ++ IMSG("UART console probed from DT (%ssecure)", ++ pd->secure ? "" : "non "); ++ } else { ++ IMSG("No UART console probed from DT"); ++ serial_console = NULL; ++ } ++ ++ return TEE_SUCCESS; ++} ++service_init_late(stm32_uart_console_probe); ++#endif ++ ++/* ++ * GIC init, used also for primary/secondary boot core wake completion ++ */ ++static struct gic_data gic_data; ++ ++static void main_fiq(void) ++{ ++ gic_it_handle(&gic_data); + } + + void main_init_gic(void) +@@ -59,75 +254,378 @@ void main_init_gic(void) + void *gicc_base; + void *gicd_base; + +- gicc_base = phys_to_virt(GIC_BASE + GICC_OFFSET, MEM_AREA_IO_SEC); +- gicd_base = phys_to_virt(GIC_BASE + GICD_OFFSET, MEM_AREA_IO_SEC); ++ gicc_base = phys_to_virt(GIC_IOMEM_BASE + GICC_OFFSET, MEM_AREA_IO_SEC); ++ gicd_base = phys_to_virt(GIC_IOMEM_BASE + GICD_OFFSET, MEM_AREA_IO_SEC); + if (!gicc_base || !gicd_base) + panic(); + + gic_init(&gic_data, (vaddr_t)gicc_base, (vaddr_t)gicd_base); + itr_init(&gic_data.chip); ++ ++#ifdef CFG_PSCI_ARM32 ++ stm32mp_register_online_cpu(); ++#endif + } + + void main_secondary_init_gic(void) + { + gic_cpu_init(&gic_data); ++ ++#if CFG_TEE_CORE_NB_CORE == 2 ++ /* Secondary core release constraint on APB5 clock */ ++ write32(BOOT_API_A7_RESET_MAGIC_NUMBER, ++ stm32mp_bkpreg(BCKR_CORE1_MAGIC_NUMBER)); ++ stm32mp1_clk_disable_secure(RTCAPB); ++#endif ++ ++#ifdef CFG_PSCI_ARM32 ++ stm32mp_register_online_cpu(); ++#endif ++} ++ ++/* Specific GIC suspend/resume function called aside registered PM handlers */ ++void stm32mp_gic_suspend_resume(enum pm_op op) ++{ ++ switch (op) { ++ case PM_OP_SUSPEND: ++ gic_suspend(&gic_data); ++ break; ++ case PM_OP_RESUME: ++ gic_resume(&gic_data); ++ break; ++ default: ++ panic(); ++ } ++} ++KEEP_PAGER(stm32mp_gic_suspend_resume); ++ ++/* stm32mp1 low power sequence needs straight access to GIC */ ++uintptr_t get_gicc_base(void) ++{ ++ uintptr_t pbase = GIC_IOMEM_BASE + GICC_OFFSET; ++ ++ if (cpu_mmu_enabled()) ++ return (uintptr_t)phys_to_virt(pbase, MEM_AREA_IO_SEC); ++ ++ return pbase; ++} ++ ++uintptr_t get_gicd_base(void) ++{ ++ uintptr_t pbase = GIC_IOMEM_BASE + GICD_OFFSET; ++ ++ if (cpu_mmu_enabled()) ++ return (uintptr_t)phys_to_virt(pbase, MEM_AREA_IO_SEC); ++ ++ return pbase; ++} ++ ++/* ++ * Various platform specific functions ++ */ ++unsigned int stm32mp_get_otp_max(void) ++{ ++ return STM32MP1_OTP_MAX_ID; ++} ++unsigned int stm32mp_get_otp_upper_start(void) ++{ ++ return STM32MP1_UPPER_OTP_START; ++} ++ ++bool __weak stm32mp_with_pmic(void) ++{ ++ return false; + } + + /* +- * SMP boot support and access to the mailbox ++ * SIP and other platform specific services + */ +-#define GIC_SEC_SGI_0 8 ++bool sm_platform_handler(struct sm_ctx *ctx) ++{ ++ uint32_t *a0 = (uint32_t *)(&ctx->nsec.r0); ++ uint32_t *a1 = (uint32_t *)(&ctx->nsec.r1); ++ uint32_t *a2 = (uint32_t *)(&ctx->nsec.r2); ++ uint32_t *a3 = (uint32_t *)(&ctx->nsec.r3); ++ ++ if (!OPTEE_SMC_IS_FAST_CALL(*a0)) ++ return true; ++ ++ switch (OPTEE_SMC_OWNER_NUM(*a0)) { ++ case OPTEE_SMC_OWNER_SIP: ++ return stm32_sip_service(ctx, a0, a1, a2, a3); ++ case OPTEE_SMC_OWNER_OEM: ++ return stm32_oem_service(ctx, a0, a1, a2, a3); ++ default: ++ return true; ++ } ++} + +-static vaddr_t bckreg_base(void) ++/* SoC versioning util */ ++uint32_t stm32mp1_dbgmcu_get_chip_version(void) ++{ ++ uintptr_t base = DBGMCU_BASE; ++ ++ if (cpu_mmu_enabled()) ++ base = (uintptr_t)phys_to_virt(DBGMCU_BASE, MEM_AREA_IO_SEC); ++ ++ return read32(base + DBGMCU_IDC) >> 16; ++} ++ ++static uintptr_t stm32_tamp_base(void) + { + static void *va; + + if (!cpu_mmu_enabled()) +- return BKP_REGS_BASE + BKP_REGISTER_OFF; ++ return TAMP_BASE; + + if (!va) +- va = phys_to_virt(BKP_REGS_BASE + BKP_REGISTER_OFF, +- MEM_AREA_IO_SEC); ++ va = phys_to_virt(TAMP_BASE, MEM_AREA_IO_SEC); + +- return (vaddr_t)va; ++ return (uintptr_t)va; + } + +-static uint32_t *bckreg_address(unsigned int idx) ++static uintptr_t bkpreg_base(void) + { +- return (uint32_t *)bckreg_base() + idx; ++ return stm32_tamp_base() + TAMP_BKP_REGISTER_OFF; + } + +-static void release_secondary_early_hpen(size_t pos) ++uintptr_t stm32mp_bkpreg(unsigned int idx) + { +- uint32_t *p_entry = bckreg_address(BCKR_CORE1_BRANCH_ADDRESS); +- uint32_t *p_magic = bckreg_address(BCKR_CORE1_MAGIC_NUMBER); ++ return bkpreg_base() + (idx * sizeof(uint32_t)); ++} + +- *p_entry = TEE_LOAD_ADDR; +- *p_magic = BOOT_API_A7_CORE1_MAGIC_NUMBER; ++uintptr_t stm32mp1_bkpsram_base(void) ++{ ++ static void *va; + +- dmb(); +- isb(); +- itr_raise_sgi(GIC_SEC_SGI_0, BIT(pos)); ++ if (!cpu_mmu_enabled()) ++ return BKPSRAM_BASE; ++ ++ if (!va) ++ va = phys_to_virt(BKPSRAM_BASE, MEM_AREA_IO_SEC); ++ ++ return (uintptr_t)va; ++} ++ ++uintptr_t stm32_get_stgen_base(void) ++{ ++ static uintptr_t va; ++ ++ if (!cpu_mmu_enabled()) ++ return STGEN_BASE; ++ ++ if (!va) ++ va = (uintptr_t)phys_to_virt(STGEN_BASE, MEM_AREA_IO_SEC); ++ ++ return va; + } + +-int psci_cpu_on(uint32_t core_id, uint32_t entry, uint32_t context_id) ++uintptr_t stm32_get_gpio_bank_base(unsigned int bank) + { +- size_t pos = get_core_pos_mpidr(core_id); +- static bool core_is_released[CFG_TEE_CORE_NB_CORE]; ++ /* Non secure banks and mapped together, same for secure banks */ ++ static uintptr_t gpiox_va; ++ static uintptr_t gpioz_va; ++ ++ switch (bank) { ++ case GPIO_BANK_A: ++ case GPIO_BANK_B: ++ case GPIO_BANK_C: ++ case GPIO_BANK_D: ++ case GPIO_BANK_E: ++ case GPIO_BANK_F: ++ case GPIO_BANK_G: ++ case GPIO_BANK_H: ++ case GPIO_BANK_I: ++ case GPIO_BANK_J: ++ case GPIO_BANK_K: ++ if (!gpiox_va && cpu_mmu_enabled()) ++ gpiox_va = (uintptr_t)phys_to_virt(GPIOS_NSEC_BASE, ++ MEM_AREA_IO_NSEC); + +- if (!pos || pos >= CFG_TEE_CORE_NB_CORE) +- return PSCI_RET_INVALID_PARAMETERS; ++ if (cpu_mmu_enabled()) ++ return gpiox_va + (bank * GPIO_BANK_OFFSET); + +- DMSG("core pos: %zu: ns_entry %#" PRIx32, pos, entry); ++ return GPIOS_NSEC_BASE + (bank * GPIO_BANK_OFFSET); + +- if (core_is_released[pos]) { +- DMSG("core %zu already released", pos); +- return PSCI_RET_DENIED; ++ case GPIO_BANK_Z: ++ if (!gpioz_va && cpu_mmu_enabled()) ++ gpioz_va = (uintptr_t)phys_to_virt(GPIOZ_BASE, ++ MEM_AREA_IO_SEC); ++ ++ if (cpu_mmu_enabled()) ++ return gpioz_va; ++ ++ return GPIOZ_BASE; ++ default: ++ panic(); ++ } ++} ++ ++uint32_t stm32_get_gpio_bank_offset(unsigned int bank) ++{ ++ if (bank == GPIO_BANK_Z) { ++ return 0; ++ } else { ++ return bank * GPIO_BANK_OFFSET; ++ } ++} ++ ++/* Return clock ID on success, negative value on error */ ++int stm32_get_gpio_bank_clock(unsigned int bank) ++{ ++ switch (bank) { ++ case GPIO_BANK_A: ++ case GPIO_BANK_B: ++ case GPIO_BANK_C: ++ case GPIO_BANK_D: ++ case GPIO_BANK_E: ++ case GPIO_BANK_F: ++ case GPIO_BANK_G: ++ case GPIO_BANK_H: ++ case GPIO_BANK_I: ++ case GPIO_BANK_J: ++ case GPIO_BANK_K: ++ return (int)GPIOA + (bank - GPIO_BANK_A); ++ case GPIO_BANK_Z: ++ return (int)GPIOZ; ++ default: ++ panic(); + } +- core_is_released[pos] = true; ++} ++ ++int stm32mp_iwdg_irq2instance(size_t irq) ++{ ++ int instance = (int)irq - STM32MP1_IRQ_IWDG1; ++ ++ assert((instance >= IWDG1_INST) && (instance <= IWDG2_INST)); ++ return instance; ++} ++ ++size_t stm32mp_iwdg_instance2irq(int instance) ++{ ++ return (size_t)(instance + STM32MP1_IRQ_IWDG1); ++} + +- generic_boot_set_core_ns_entry(pos, entry, context_id); +- release_secondary_early_hpen(pos); ++unsigned int stm32mp_iwdg_iomem2instance(uintptr_t pbase) ++{ ++ switch (pbase) { ++ case IWDG1_BASE: ++ return IWDG1_INST; ++ case IWDG2_BASE: ++ return IWDG2_INST; ++ default: ++ panic(); ++ } ++} ++ ++unsigned long stm32_get_iwdg_otp_config(uintptr_t pbase) ++{ ++ unsigned int idx; ++ unsigned long iwdg_cfg = 0; ++ uint32_t otp_value; ++ ++ idx = stm32mp_iwdg_iomem2instance(pbase); ++ ++ if (bsec_read_otp(&otp_value, HW2_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_STANDBY_SHIFT))) ++ iwdg_cfg |= IWDG_ENABLE_ON_STANDBY; ++ ++ return iwdg_cfg; ++} ++ ++uintptr_t stm32mp_get_etzpc_base(void) ++{ ++ return ETZPC_BASE; ++} ++ ++/* ++ * This function allows to split bindings between platform and ETZPC ++ * HW mapping. If this conversion was done at driver level, the driver ++ * should include all supported platform bindings. ETZPC may be used on ++ * other platforms. ++ */ ++enum etzpc_decprot_attributes stm32mp_etzpc_binding2decprot(uint32_t mode) ++{ ++ switch (mode) { ++ case DECPROT_S_RW: ++ return TZPC_DECPROT_S_RW; ++ case DECPROT_NS_R_S_W: ++ return TZPC_DECPROT_NS_R_S_W; ++ case DECPROT_MCU_ISOLATION: ++ return TZPC_DECPROT_MCU_ISOLATION; ++ case DECPROT_NS_RW: ++ return TZPC_DECPROT_NS_RW; ++ default: ++ panic(); ++ } ++} ++ ++#ifdef CFG_STM32_RTC ++/******************************************************************************* ++ * This function determines the number of needed RTC calendar read operations ++ * to get consistent values (1 or 2 depending of clock frequencies). ++ * If APB1 frequency is less than 7 times the RTC one, the software has to ++ * read the calendar time and date register twice. ++ * This function computes each of them and does the comparison. ++ * Returns true if read twice is needed, false else. ++ ******************************************************************************/ ++bool stm32_rtc_get_read_twice(void) ++{ ++ unsigned long apb1_freq; ++ unsigned long rtc_freq = 0; ++ uint32_t apb1_div; ++ uintptr_t rcc_base = stm32_rcc_base(); ++ ++ /* Compute RTC frequency */ ++ switch ((mmio_read_32(rcc_base + RCC_BDCR) & ++ RCC_BDCR_RTCSRC_MASK) >> RCC_BDCR_RTCSRC_SHIFT) { ++ case 1: ++ rtc_freq = stm32mp1_clk_get_rate(CK_LSE); ++ break; ++ case 2: ++ rtc_freq = stm32mp1_clk_get_rate(CK_LSI); ++ break; ++ case 3: ++ rtc_freq = stm32mp1_clk_get_rate(CK_HSE); ++ rtc_freq /= (mmio_read_32(rcc_base + RCC_RTCDIVR) & ++ RCC_DIVR_DIV_MASK) + 1U; ++ break; ++ default: ++ /* Forbidden values: consider only one needed read here */ ++ panic(); ++ } ++ ++ /* Compute APB1 frequency */ ++ apb1_div = mmio_read_32(rcc_base + RCC_APB1DIVR) & RCC_APBXDIV_MASK; ++ apb1_freq = stm32mp1_clk_get_rate(CK_MCU) >> apb1_div; ++ ++ /* Compare APB1 and 7*RTC frequencies */ ++ return apb1_freq < (rtc_freq * 7U); ++} ++#endif ++ ++uint32_t may_spin_lock(unsigned int *lock) ++{ ++ if (!lock || !cpu_mmu_enabled()) { ++ return 0; ++ } ++ ++ return cpu_spin_lock_xsave(lock); ++} ++ ++void may_spin_unlock(unsigned int *lock, uint32_t exceptions) ++{ ++ if (!lock || !cpu_mmu_enabled()) { ++ return; ++ } + +- return PSCI_RET_SUCCESS; ++ cpu_spin_unlock_xrestore(lock, exceptions); + } +diff --git a/core/arch/arm/plat-stm32mp1/platform_config.h b/core/arch/arm/plat-stm32mp1/platform_config.h +index 6f5dd97..e8d1660 100644 +--- a/core/arch/arm/plat-stm32mp1/platform_config.h ++++ b/core/arch/arm/plat-stm32mp1/platform_config.h +@@ -8,22 +8,185 @@ + + #include + ++/* Enable/disable use of the core0 reset control from RCC */ ++#undef STM32MP1_USE_MPU0_RESET ++ + /* Make stacks aligned to data cache line length */ + #define STACK_ALIGNMENT 32 + +-#define GIC_BASE 0xA0021000ul +-#define GIC_SIZE 0x2000 +-#define GICC_OFFSET 0x1000 +-#define GICD_OFFSET 0x0000 ++#if defined(CFG_WITH_PAGER) ++#if defined(CFG_WITH_LPAE) ++/* ++ * Optimize unpaged memory size: ++ * - one table for the level2 table for overall vmem range ++ * - two tables for TEE RAM fine grain mapping [2ffc.0000 301f.ffff] ++ * - one table for internal RAMs (PM: ROMed core TEE RAM & DDR first page) ++ * - one table for a 2MByte dynamiq shared virtual memory (SHM_VASPACE) ++ */ ++#define MAX_XLAT_TABLES 5 ++#else ++/* ++ * Optimize unpaged memory size: ++ * - two tables for TEE RAM mapping [2ffc.0000 300f.ffff] ++ * - one table for secure internal RAMs (PM: ROMed core TEE RAM) ++ * - one table for non-secure internal RAMs (PM: DDR first page) ++ * - two tables for a 2MByte dynamiq shared virtual memory (SHM_VASPACE) ++ */ ++#define MAX_XLAT_TABLES 6 ++#endif /*CFG_WITH_LPAE*/ ++#else ++/* Be generous, there is plenty of secure DDR */ ++#define MAX_XLAT_TABLES 10 ++#endif /*CFG_WITH_PAGER*/ ++ ++/* Expected platform default size, if not found in device tree */ ++#define STM32MP1_DDR_SIZE_DFLT (1 * 1024 * 1024 * 1024) + +-#define BKP_REGS_BASE 0x5C00A000 +-#define BKP_REGISTER_OFF 0x100 ++#define GIC_IOMEM_BASE 0xa0021000ul ++#define GIC_IOMEM_SIZE 0x00007000 ++#define DDR_BASE 0xc0000000ul ++#define SYSRAM_BASE 0x2ffc0000 ++#define BKPSRAM_BASE 0x54000000 + ++#define BSEC_BASE 0x5c005000 ++#define CRYP1_BASE 0x54001000 ++#define DBGMCU_BASE 0x50081000 ++#define DDRCTRL_BASE 0x5a003000 ++#define DDRPHYC_BASE 0x5a004000 ++#define ETZPC_BASE 0x5c007000 ++#define EXTI_BASE 0x5000D000 ++#define GPIOA_BASE 0x50002000 ++#define GPIOB_BASE 0x50003000 ++#define GPIOC_BASE 0x50004000 ++#define GPIOD_BASE 0x50005000 ++#define GPIOE_BASE 0x50006000 ++#define GPIOF_BASE 0x50007000 ++#define GPIOG_BASE 0x50008000 ++#define GPIOH_BASE 0x50009000 ++#define GPIOI_BASE 0x5000a000 ++#define GPIOJ_BASE 0x5000b000 ++#define GPIOK_BASE 0x5000c000 ++#define GPIOZ_BASE 0x54004000 ++#define HASH1_BASE 0x54002000 ++#define I2C4_BASE 0x5c002000 ++#define I2C6_BASE 0x5c009000 ++#define IWDG1_BASE 0x5c003000 ++#define IWDG2_BASE 0x5a002000 ++#define PWR_BASE 0x50001000 ++#define RCC_BASE 0x50000000 ++#define RNG1_BASE 0x54003000 ++#define RTC_BASE 0x5c004000 ++#define SPI6_BASE 0x5c001000 ++#define STGEN_BASE 0x5C008000 ++#define TAMP_BASE 0x5c00a000 ++#define USART1_BASE 0x5c000000 ++#define USART2_BASE 0x4000e000 ++#define USART3_BASE 0x4000f000 + #define UART4_BASE 0x40010000 +-#define STM32MP1_DEBUG_USART_BASE UART4_BASE +-#define GIC_SPI_UART4 84 ++#define UART5_BASE 0x40011000 ++#define USART6_BASE 0x44003000 ++#define UART7_BASE 0x40018000 ++#define UART8_BASE 0x40019000 ++#define TZC_BASE 0x5c006000 ++ ++/* BSEC OTP resources */ ++#define STM32MP1_OTP_MAX_ID 0x5FU ++#define STM32MP1_UPPER_OTP_START 0x20U ++ ++#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 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 ++ ++/* ++ * GPIO banks: 11 non secure banks (A to K) and 1 secure bank (Z) ++ * Bank register's base address is computed from the bank ID listed here. ++ */ ++#define GPIOS_NSEC_COUNT 11 ++#define GPIOS_NSEC_BASE GPIOA_BASE ++#define GPIOS_NSEC_SIZE (GPIOS_NSEC_COUNT * SMALL_PAGE_SIZE) ++ ++#define STM32MP1_GPIOZ_MAX_COUNT 1 ++#define STM32MP1_GPIOZ_PIN_MAX_COUNT 8 ++ ++#define GPIO_BANK_OFFSET 0x1000U ++ ++/* Bank IDs used in GPIO driver API */ ++#define GPIO_BANK_A 0U ++#define GPIO_BANK_B 1U ++#define GPIO_BANK_C 2U ++#define GPIO_BANK_D 3U ++#define GPIO_BANK_E 4U ++#define GPIO_BANK_F 5U ++#define GPIO_BANK_G 6U ++#define GPIO_BANK_H 7U ++#define GPIO_BANK_I 8U ++#define GPIO_BANK_J 9U ++#define GPIO_BANK_K 10U ++#define GPIO_BANK_Z 25U ++ ++/* IWDG resources */ ++#define IWDG1_INST 0 ++#define IWDG2_INST 1 ++ ++#define STM32MP1_IRQ_IWDG1 182U ++#define STM32MP1_IRQ_IWDG2 183U ++ ++/* TAMP resources */ ++#define TAMP_BKP_REGISTER_OFF 0x100 ++ ++/* RCC platform resources */ ++#define RCC_WAKEUP_IT 177 ++ ++/* SoC revision */ ++#define STM32MP1_REV_A 0x00001000 ++#define STM32MP1_REV_B 0x00002000 ++ ++/* DBGMCU resources */ ++#define DBGMCU_IDC 0x0 ++ ++/* BKPSRAM layout */ ++#define BKPSRAM_SIZE SMALL_PAGE_SIZE ++#define BKPSRAM_PM_OFFSET 0x000 ++#define BKPSRAM_PM_SIZE (BKPSRAM_PM_MAILBOX_SIZE + \ ++ BKPSRAM_PM_CONTEXT_SIZE) ++ ++#define BKPSRAM_PM_MAILBOX_OFFSET BKPSRAM_PM_OFFSET ++#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 ++ ++/* SYSRAM */ ++#define SYSRAM_SIZE 0x40000 ++ ++/* GIC resources */ ++#define GICD_OFFSET 0x00000000 ++#define GICC_OFFSET 0x00001000 ++#define GICH_OFFSET 0x00003000 ++#define GICV_OFFSET 0x00005000 ++ ++#define GIC_NON_SEC_SGI_0 0 ++#define GIC_SEC_SGI_0 8 ++#define GIC_SEC_SGI_1 9 ++#define GIC_SPI_SEC_PHY_TIMER 29 ++ ++#define TARGET_CPU0_GIC_MASK BIT(0) ++#define TARGET_CPU1_GIC_MASK BIT(1) ++#define TARGET_CPUS_GIC_MASK GENMASK_32(CFG_TEE_CORE_NB_CORE - 1, 0) + +-#define CONSOLE_UART_BASE STM32MP1_DEBUG_USART_BASE +-#define CONSOLE_UART_SIZE 1024 ++#define STM32MP_GIC_PRIORITY_CSTOP 0xc0 + + #endif /*PLATFORM_CONFIG_H*/ +diff --git a/core/arch/arm/plat-stm32mp1/pm/context.c b/core/arch/arm/plat-stm32mp1/pm/context.c +new file mode 100644 +index 0000000..2ce72b3 +--- /dev/null ++++ b/core/arch/arm/plat-stm32mp1/pm/context.c +@@ -0,0 +1,510 @@ ++// SPDX-License-Identifier: BSD-3-Clause ++/* ++ * Copyright (c) 2018, STMicroelectronics - All Rights Reserved ++ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "context.h" ++#include "power.h" ++ ++#define TRAINING_AREA_SIZE 64 ++ ++#define STANDBY_CONTEXT_MAGIC (0x00010000 + TRAINING_AREA_SIZE) ++ ++/* ++ * Context saved in TEE RAM during lower power sequence. ++ * Can be allocated if to big for static allocation. ++ * ++ * @stgen_cnt_h: Upper 32bit of the STGEN counter ++ * @stgen_cnt_l: Lower 32bit of the STGEN counter ++ * @rtc: RTC time read at suspend ++ */ ++struct pm_context { ++ uint32_t stgen_cnt_h; ++ uint32_t stgen_cnt_l; ++ struct stm32_rtc_calendar rtc; ++}; ++ ++static struct pm_context plat_ctx; ++ ++/* ++ * BKPSRAM contains a mailbox used with early boot stages for resume sequence. ++ * The mailbox content data that must be restored before OP-TEE is resumed. ++ * ++ * @magic: magic value read by early boot stage for consistency ++ * @zq0cr0_zdata: DDRPHY configuration to be restored. ++ * @ddr_training_backup: DDR area saved at suspend and backed up at resume ++ */ ++struct pm_mailbox { ++ uint32_t magic; ++ uint32_t core0_resume_ep; ++ uint32_t zq0cr0_zdata; ++ uint8_t ddr_training_backup[TRAINING_AREA_SIZE]; ++}; ++ ++/* ++ * BKPSRAM contains OP-TEE resume instruction sequence which restores ++ * TEE RAM content. The BKPSRAM contains restoration materials ++ * (key, tag) and the resume entry point in restored TEE RAM. ++ */ ++static struct retram_resume_ctx *get_retram_resume_ctx(void) ++{ ++ uintptr_t bkpsram_base = stm32mp1_bkpsram_base(); ++ uintptr_t context_base = bkpsram_base + BKPSRAM_PM_CONTEXT_OFFSET; ++ ++ return (struct retram_resume_ctx *)context_base; ++} ++ ++static struct pm_mailbox *get_pm_mailbox(void) ++{ ++ uintptr_t bkpsram_base = stm32mp1_bkpsram_base(); ++ uintptr_t mailbox_base = bkpsram_base + BKPSRAM_PM_MAILBOX_OFFSET; ++ ++ return (struct pm_mailbox *)mailbox_base; ++} ++ ++#if TRACE_LEVEL >= TRACE_DEBUG ++static void __maybe_unused dump_context(void) ++{ ++ struct pm_mailbox *mailbox = get_pm_mailbox(); ++ struct retram_resume_ctx *ctx = get_retram_resume_ctx(); ++ ++ stm32_clock_enable(RTCAPB); ++ ++ DMSG("Backup registers: address 0x%" PRIx32 ", magic 0x%" PRIx32, ++ *(uint32_t *)stm32mp_bkpreg(BCKR_CORE1_BRANCH_ADDRESS), ++ *(uint32_t *)stm32mp_bkpreg(BCKR_CORE1_MAGIC_NUMBER)); ++ ++ stm32_clock_disable(RTCAPB); ++ ++ stm32_clock_enable(BKPSRAM); ++ ++ DMSG("BKPSRAM mailbox: 0x%" PRIx32 ", zd 0x%" PRIx32 ", ep 0x%" PRIx32, ++ mailbox->magic, mailbox->zq0cr0_zdata, ++ mailbox->core0_resume_ep); ++ ++ DMSG("BKPSRAM context: teeram backup @%" PRIx32 ", resume @0x%" PRIx32, ++ ctx->teeram_bkp_pa, ctx->resume_pa); ++ ++ stm32_clock_disable(BKPSRAM); ++} ++#else ++static void __maybe_unused dump_context(void) ++{ ++} ++#endif ++ ++/* ++ * Save and restore functions ++ */ ++static void save_time(void) ++{ ++ uintptr_t stgen = stm32_get_stgen_base(); ++ ++ plat_ctx.stgen_cnt_h = read32(stgen + CNTCVU_OFFSET); ++ plat_ctx.stgen_cnt_l = read32(stgen + CNTCVL_OFFSET); ++ if (plat_ctx.stgen_cnt_l < 10) { ++ plat_ctx.stgen_cnt_h = read32(stgen + CNTCVU_OFFSET); ++ } ++ ++ stm32_rtc_get_calendar(&plat_ctx.rtc); ++} ++ ++#if TRACE_LEVEL >= TRACE_DEBUG ++static void print_ccm_decryption_duration(void) ++{ ++ uintptr_t stgen = stm32_get_stgen_base(); ++ struct retram_resume_ctx *ctx = get_retram_resume_ctx(); ++ ++ ++ stm32_clock_enable(BKPSRAM); ++ ++ DMSG("CCM decryption duration %llums", ++ ((unsigned long long)ctx->stgen_cnt * 1000) / ++ mmio_read_32(stgen + CNTFID_OFFSET)); ++ ++ stm32_clock_enable(BKPSRAM); ++} ++#else ++static void print_ccm_decryption_duration(void) ++{ ++} ++#endif ++ ++static void restore_time(void) ++{ ++ struct stm32_rtc_calendar current_calendar; ++ unsigned long long stdby_time_in_ms; ++ unsigned long long cnt; ++ uintptr_t stgen = stm32_get_stgen_base(); ++ struct retram_resume_ctx __maybe_unused *ctx = get_retram_resume_ctx(); ++ ++ stm32_rtc_get_calendar(¤t_calendar); ++ stdby_time_in_ms = stm32_rtc_diff_calendar(¤t_calendar, ++ &plat_ctx.rtc); ++ ++ cnt = ((uint64_t)plat_ctx.stgen_cnt_h << 32) | plat_ctx.stgen_cnt_l; ++ cnt += (stdby_time_in_ms * mmio_read_32(stgen + CNTFID_OFFSET)) / 1000U; ++ ++ mmio_clrbits_32(stgen + CNTCR_OFFSET, CNTCR_EN); ++ mmio_write_32(stgen + CNTCVL_OFFSET, (uint32_t)cnt); ++ mmio_write_32(stgen + CNTCVU_OFFSET, (uint32_t)(cnt >> 32)); ++ mmio_setbits_32(stgen + CNTCR_OFFSET, CNTCR_EN); ++ ++ print_ccm_decryption_duration(); ++} ++ ++static bool __maybe_unused pm_cb_is_valid(void (*cb)(enum pm_op op, void *hdl), ++ void *hdl) ++{ ++ void *cb_voidp = (void *)(uintptr_t)cb; ++ paddr_t cb_phy = virt_to_phys(cb_voidp); ++ paddr_t hdl_phy = virt_to_phys(hdl); ++ bool __maybe_unused valid; ++ ++ valid = (phys_to_virt(cb_phy, MEM_AREA_TEE_RAM_RX) == cb_voidp) && ++ ((phys_to_virt(hdl_phy, MEM_AREA_TEE_RAM_RX) == hdl) || ++ (phys_to_virt(hdl_phy, MEM_AREA_TEE_RAM_RO) == hdl) || ++ (phys_to_virt(hdl_phy, MEM_AREA_TEE_RAM_RW) == hdl)); ++ ++ if (!valid) { ++ EMSG("pm_cb mandates unpaged arguments %p %p", cb_voidp, hdl); ++ } ++ ++ return valid; ++} ++ ++struct pm_cb { ++ void (*callback)(enum pm_op op, void *handle); ++ void *handle; ++}; ++static struct pm_cb *pm_cb; ++static size_t pm_cb_count; ++ ++void stm32mp_register_pm_cb(void (*callback)(enum pm_op op, void *handle), ++ void *handle) ++{ ++ assert(pm_cb_is_valid(callback, handle)); ++ ++ pm_cb_count++; ++ pm_cb = realloc(pm_cb, sizeof(struct pm_cb) * pm_cb_count); ++ if (!pm_cb){ ++ panic(); ++ } ++ ++ pm_cb[pm_cb_count - 1].callback = callback; ++ pm_cb[pm_cb_count - 1].handle = handle; ++} ++ ++static void save_soc_context(void) ++{ ++ const enum pm_op suspend = PM_OP_SUSPEND; ++ size_t n; ++ ++ for (n = 0; n < pm_cb_count; n++) { ++ pm_cb[n].callback(suspend, pm_cb[n].handle); ++ } ++ ++ /* Suspend core services */ ++ stm32mp_gic_suspend_resume(suspend); ++ stm32mp_clock_suspend_resume(suspend); ++} ++ ++static void restore_soc_context(void) ++{ ++ const enum pm_op resume = PM_OP_RESUME; ++ size_t n; ++ ++ /* Resume core services */ ++ stm32mp_gic_suspend_resume(resume); ++ stm32mp_clock_suspend_resume(resume); ++ ++ for (n = 0; n < pm_cb_count; n++) { ++ pm_cb[n].callback(resume, pm_cb[n].handle); ++ } ++} ++ ++uintptr_t stm32mp_pm_retram_resume_ep(void) ++{ ++ struct retram_resume_ctx *ctx = get_retram_resume_ctx(); ++ ++ return (uintptr_t)&ctx->resume_sequence; ++} ++ ++/* Clear the content of the PM mailbox */ ++void stm32mp_pm_wipe_context(void) ++{ ++ struct retram_resume_ctx *ctx = get_retram_resume_ctx(); ++ struct pm_mailbox *mailbox = get_pm_mailbox(); ++ ++ stm32_clock_enable(BKPSRAM); ++ ++ memset(ctx, 0xa5, sizeof(*ctx)); ++ memset(mailbox, 0xa5, sizeof(*mailbox)); ++ ++ stm32_clock_disable(BKPSRAM); ++} ++ ++static struct mobj *teeram_bkp_mobj; ++ ++static void init_retram_resume_resources(void) ++{ ++ struct retram_resume_ctx *ctx = get_retram_resume_ctx(); ++ const size_t size = (uintptr_t)stm32mp_bkpsram_image_end - ++ (uintptr_t)stm32mp_bkpsram_resume; ++ paddr_t __maybe_unused pa; ++ ++ COMPILE_TIME_ASSERT(sizeof(struct pm_mailbox) < ++ BKPSRAM_PM_MAILBOX_SIZE); ++ COMPILE_TIME_ASSERT(sizeof(struct retram_resume_ctx) < ++ BKPSRAM_PM_CONTEXT_SIZE); ++ assert((sizeof(*ctx) + size) < BKPSRAM_PM_CONTEXT_SIZE); ++ ++ teeram_bkp_mobj = mobj_mm_alloc(mobj_sec_ddr, TEE_RAM_PH_SIZE, ++ &tee_mm_sec_ddr); ++ if (teeram_bkp_mobj == NULL) { ++ panic(); ++ } ++ assert((mobj_get_va(teeram_bkp_mobj, 0) != NULL) && ++ (mobj_get_pa(teeram_bkp_mobj, 0, 0, &pa) == 0)); ++ ++ stm32_clock_enable(BKPSRAM); ++ memset(ctx, 0, sizeof(*ctx)); ++ stm32_clock_disable(BKPSRAM); ++} ++ ++/* ++ * When returning from STANDBY, the 64 first bytes of DDR will be overwritten ++ * during DDR DQS training. This area must then be saved before going to ++ * standby in the PM mailbox with the earlier boot stages. ++ */ ++static void save_ddr_training_area(void) ++{ ++ struct pm_mailbox *mailbox = get_pm_mailbox(); ++ size_t size = sizeof(mailbox->ddr_training_backup); ++ struct mobj __maybe_unused *mobj = NULL; ++ paddr_t pa = DDR_BASE; ++ void *va = phys_to_virt(pa, MEM_AREA_RAM_NSEC); ++ ++#if !defined(CFG_STM32MP_MAP_NSEC_LOW_DDR) ++ /* Config switch helps not requesting mobj_mapped_shm_alloc() unpaged */ ++ if (!va) { ++ mobj = mobj_mapped_shm_alloc(&pa, SMALL_PAGE_SIZE, 0, 0); ++ va = mobj_get_va(mobj, 0); ++ } ++#endif ++ ++ memcpy(&mailbox->ddr_training_backup[0], va, size); ++ ++ mobj_free(mobj); ++} ++ ++static void load_earlyboot_pm_mailbox(void) ++{ ++ struct pm_mailbox *mailbox = get_pm_mailbox(); ++ ++ COMPILE_TIME_ASSERT(sizeof(struct pm_mailbox) < ++ BKPSRAM_PM_MAILBOX_SIZE); ++ ++ assert(stm32_clock_is_enabled(BKPSRAM)); ++ ++ memset(mailbox, 0, sizeof(*mailbox)); ++ ++ mailbox->zq0cr0_zdata = get_ddrphy_calibration(); ++ ++ save_ddr_training_area(); ++} ++ ++#ifdef CFG_STM32_RNG ++/* ++ * CRYP relies on standard format for CCM IV/B0/CRT0 data. Our sequence uses ++ * no AAD, 4 bytes to encode the payload byte size and a 11 byte nonce. ++ */ ++#define PM_CCM_Q 4 ++#define PM_CCM_Q_FLAGS (PM_CCM_Q - 1) ++#define PM_CCM_TAG_LEN 16 ++#define PM_CCM_TAG_FLAGS (((PM_CCM_TAG_LEN - 2) / 2) << 3) ++ ++static void save_teeram_in_ddr(void) ++{ ++ struct retram_resume_ctx *ctx = get_retram_resume_ctx(); ++ size_t __maybe_unused size = (uintptr_t)stm32mp_bkpsram_image_end - ++ (uintptr_t)stm32mp_bkpsram_resume; ++ paddr_t pa; ++ struct ccm_unpg_ctx *ccm = &ctx->ccm_ctx; ++ void *teeram = phys_to_virt(TEE_RAM_START, MEM_AREA_ROM_SEC); ++ void *teeram_bkp = mobj_get_va(teeram_bkp_mobj, 0); ++ ++ COMPILE_TIME_ASSERT(PM_CTX_CCM_KEY_SIZE == sizeof(ccm->key)); ++ COMPILE_TIME_ASSERT(PM_CTX_CCM_CTR1_SIZE == sizeof(ccm->ctr1)); ++ COMPILE_TIME_ASSERT(PM_CTX_CCM_B0_SIZE == sizeof(ccm->b0)); ++ COMPILE_TIME_ASSERT(PM_CTX_CCM_CTR0_SIZE == sizeof(ccm->ctr0)); ++ COMPILE_TIME_ASSERT(PM_CTX_CCM_TAG_SIZE == sizeof(ccm->tag)); ++ ++ assert(stm32_clock_is_enabled(BKPSRAM) && ++ stm32_clock_is_enabled(CRYP1)); ++ ++ memcpy(ctx->resume_sequence, ++ (void *)(uintptr_t)stm32mp_bkpsram_resume, size); ++ ++ memset(ctx, 0, sizeof(*ctx)); ++ ctx->resume_pa = virt_to_phys((void *)(uintptr_t)stm32mp_sysram_resume); ++ if (mobj_get_pa(teeram_bkp_mobj, 0, 0, &pa)) { ++ panic(); ++ } ++ ctx->teeram_bkp_pa = (uint32_t)pa; ++ ctx->cryp1_base = (uint32_t)phys_to_virt(CRYP1_BASE, MEM_AREA_IO_SEC); ++ ctx->rcc_base = (uint32_t)phys_to_virt(RCC_BASE, MEM_AREA_IO_SEC); ++ ctx->stgen_base = (uint32_t)phys_to_virt(STGEN_BASE, MEM_AREA_IO_SEC); ++ ++ if (stm32_rng_read((uint8_t *)ccm->key, sizeof(ccm->key))) { ++ panic(); ++ } ++ ++ assert(((PM_CCM_TAG_FLAGS & ~0x38U) | (PM_CCM_Q_FLAGS & ~0x07U)) == 0); ++ COMPILE_TIME_ASSERT(PM_CCM_Q <= 4); ++ COMPILE_TIME_ASSERT(TEE_RAM_PH_SIZE > UINT16_MAX); ++ COMPILE_TIME_ASSERT(TEE_RAM_PH_SIZE < UINT32_MAX); ++ ++ if (stm32_rng_read((uint8_t *)ccm->ctr1, sizeof(ccm->ctr1))) { ++ panic(); ++ } ++ ccm->ctr1[0] &= GENMASK_32(24, 0); ++ memcpy(ccm->b0, ccm->ctr1, sizeof(ccm->b0)); ++ memcpy(ccm->ctr0, ccm->ctr1, sizeof(ccm->ctr0)); ++ ++ ccm->ctr0[0] |= PM_CCM_Q_FLAGS << 24; ++ ccm->ctr0[3] = 0; ++ ccm->ctr1[0] |= PM_CCM_Q_FLAGS << 24; ++ ccm->ctr1[3] = 1; ++ ccm->b0[0] |= (PM_CCM_Q_FLAGS | PM_CCM_TAG_FLAGS) << 24; ++ ccm->b0[3] = TEE_RAM_PH_SIZE; ++ ++ stm32mp_ccm_encrypt_teeram(ctx, teeram_bkp, teeram, TEE_RAM_PH_SIZE); ++ dcache_clean_range(teeram_bkp, TEE_RAM_PH_SIZE); ++ ++ memcpy(ctx->ccm_ref_tag, ccm->tag, sizeof(ctx->ccm_ref_tag)); ++ ++ DMSG("CCM encryption duration %llums", ++ ((unsigned long long)ctx->stgen_cnt * 1000) / ++ mmio_read_32(ctx->stgen_base + CNTFID_OFFSET)); ++ ctx->stgen_cnt = 0; ++} ++#else ++static void save_teeram_in_ddr(void) ++{ ++ panic("Mandates RNG support"); ++} ++#endif /*CFG_STM32_RNG*/ ++ ++/* Finalize the PM mailbox now that everything is loaded */ ++static void enable_pm_mailbox(unsigned int suspend) ++{ ++ struct pm_mailbox *mailbox = get_pm_mailbox(); ++ uint32_t magic = BOOT_API_A7_CORE0_MAGIC_NUMBER; ++ uint32_t hint = 0; ++ ++ assert(stm32_clock_is_enabled(BKPSRAM) && ++ stm32_clock_is_enabled(RTCAPB)); ++ ++ if (suspend) { ++ hint = virt_to_phys(&get_retram_resume_ctx()->resume_sequence); ++ } ++ ++ write32(magic, stm32mp_bkpreg(BCKR_CORE1_MAGIC_NUMBER)); ++ write32(hint, stm32mp_bkpreg(BCKR_CORE1_BRANCH_ADDRESS)); ++ ++ mailbox->core0_resume_ep = hint; ++ mailbox->magic = STANDBY_CONTEXT_MAGIC; ++} ++ ++static void gate_pm_context_clocks(bool enable) ++{ ++ static bool clocks_enabled; ++ ++ if (enable) { ++ assert(!clocks_enabled); ++ stm32_clock_enable(BKPSRAM); ++ stm32_clock_enable(RTCAPB); ++ stm32_clock_enable(CRYP1); ++ clocks_enabled = true; ++ } else { ++ /* Suspended TEE RAM state left the clocks enabled */ ++ if (clocks_enabled) { ++ stm32_clock_disable(BKPSRAM); ++ stm32_clock_disable(RTCAPB); ++ stm32_clock_disable(CRYP1); ++ clocks_enabled = false; ++ } ++ } ++} ++ ++/* ++ * Context (TEE RAM content + peripherals) must be restored ++ * only if system may reach STANDBY state. ++ */ ++void stm32mp_pm_save_context(unsigned int soc_mode) ++{ ++ save_time(); ++ ++ if (!need_to_backup_cpu_context(soc_mode)) { ++ return; ++ } ++ ++ gate_pm_context_clocks(true); ++ load_earlyboot_pm_mailbox(); ++ save_soc_context(); ++ save_teeram_in_ddr(); ++ enable_pm_mailbox(1); ++} ++ ++void stm32mp_pm_restore_context(unsigned int soc_mode) ++{ ++ if (need_to_backup_cpu_context(soc_mode)) { ++ restore_soc_context(); ++ gate_pm_context_clocks(false); ++ } ++ ++ restore_time(); ++} ++ ++void stm32mp_pm_shutdown_context(void) ++{ ++ gate_pm_context_clocks(true); ++ load_earlyboot_pm_mailbox(); ++ enable_pm_mailbox(0); ++ gate_pm_context_clocks(false); ++} ++ ++static TEE_Result init_pm_support(void) ++{ ++ init_retram_resume_resources(); ++ ++ stm32mp_pm_wipe_context(); ++ ++ return TEE_SUCCESS; ++} ++driver_init(init_pm_support); +diff --git a/core/arch/arm/plat-stm32mp1/pm/context.h b/core/arch/arm/plat-stm32mp1/pm/context.h +new file mode 100644 +index 0000000..9070fac +--- /dev/null ++++ b/core/arch/arm/plat-stm32mp1/pm/context.h +@@ -0,0 +1,100 @@ ++/* SPDX-License-Identifier: BSD-3-Clause */ ++/* ++ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. ++ */ ++ ++#ifndef __STM32MP_PM_CONTEXT_H__ ++#define __STM32MP_PM_CONTEXT_H__ ++ ++#ifndef ASM ++#include ++#include ++#include ++#include ++#endif ++ ++#define PM_CTX_CCM_KEY_SIZE 32 ++#define PM_CTX_CCM_CTR1_SIZE 16 ++#define PM_CTX_CCM_B0_SIZE 16 ++#define PM_CTX_CCM_CTR0_SIZE 16 ++#define PM_CTX_CCM_TAG_SIZE 16 ++ ++#ifndef ASM ++/* ++ * All materials for the CCM sequence using CRYP support are preloaded ++ * in this specific structure. Note that the sequence does not use AAD. ++ * ++ * @key: AES key material buffer ++ * @ctr1: Preformatted 128bit CTR1 block ++ * @ctr1: Preformatted 128bit B0 block ++ * @ctr1: Preformatted 128bit CTR0 block ++ * @tag: Buffer where the generated CCM tag is stored ++ */ ++struct ccm_unpg_ctx { ++ uint32_t key[PM_CTX_CCM_KEY_SIZE / sizeof(uint32_t)]; ++ uint32_t ctr1[PM_CTX_CCM_CTR1_SIZE / sizeof(uint32_t)]; ++ uint32_t b0[PM_CTX_CCM_B0_SIZE / sizeof(uint32_t)]; ++ uint32_t ctr0[PM_CTX_CCM_CTR0_SIZE / sizeof(uint32_t)]; ++ uint32_t tag[PM_CTX_CCM_TAG_SIZE / sizeof(uint32_t)]; ++}; ++ ++/* ++ * This structure is used by pm_helpers.S at early resume from retention RAM. ++ * It is defined here and used by context_asm_defines.c to generate offset ++ * macros for the assembly implementation in pm_helpers.S. ++ * ++ * To lower the memory footprint of suspend sequence, The same function is ++ * used for encryption (executed from TEE RAM with MMU enabled) and for ++ * decryption (executed from BKPSRAM with MMU disabled). Therefore some ++ * required addresses are provided by the caller through this structure ++ * especially some SoC interface registers that are likely to have different ++ * physical and virtual addresses. ++ * ++ * @resume_pa: OP-TEE resume physical entry in TEE RAM (once restored) ++ * @teeram_bkp_pa: Physical base address in TEE RAM backup in DDR ++ * @cryp1_base: Base address of the CRYP1 registers (physical or virtual) ++ * @rcc_base: Base address of the RCC registers (physical or virtual) ++ * @stgen_base: Base address of the STGEN registers (physical or virtual) ++ * @stgen_cnt: STGEN cycle counter backup cell and measure of cycles spent ++ * @ccm_ref_tag: 128bit arrays storing tag generated during encryption ++ * @ccm_ctx: Structure storing CCM configuration and generated tag ++ * @resume_sequence: Code/data array for the BKPSRAM resume sequence ++ */ ++struct retram_resume_ctx { ++ uint32_t resume_pa; ++ uint32_t teeram_bkp_pa; ++ uint32_t cryp1_base; ++ uint32_t rcc_base; ++ uint32_t stgen_base; ++ uint32_t stgen_cnt; ++ uint8_t ccm_ref_tag[PM_CTX_CCM_TAG_SIZE]; ++ struct ccm_unpg_ctx ccm_ctx; ++ /* Last start the resume routine ARM (32bit) instructions sequence */ ++ uint32_t resume_sequence[]; ++}; ++ ++extern const uint8_t stm32mp_bkpsram_image_end[]; ++void stm32mp_bkpsram_resume(void); ++void stm32mp_sysram_resume(void); ++ ++void stm32mp_cpu_reset_state(void); ++ ++void stm32mp_pm_save_context(unsigned int soc_mode); ++void stm32mp_pm_restore_context(unsigned int soc_mode); ++void stm32mp_pm_shutdown_context(void); ++void stm32mp_pm_wipe_context(void); ++ ++int stm32mp1_set_pm_domain_state(enum stm32mp1_pm_domain domain, bool status); ++ ++uint32_t stm32mp1_get_lp_soc_mode(uint32_t psci_mode); ++int stm32mp1_set_lp_deepest_soc_mode(uint32_t psci_mode, uint32_t soc_mode); ++ ++uintptr_t stm32mp_pm_retram_resume_ep(void); ++ ++int stm32mp_ccm_encrypt_teeram(struct retram_resume_ctx *ctx, ++ void *dst, void *src, size_t size); ++int stm32mp_ccm_decrypt_teeram(struct retram_resume_ctx *ctx, ++ void *dst, void *src, size_t size); ++#endif /*ASM*/ ++ ++#endif /*__STM32MP_PM_CONTEXT_H__*/ +diff --git a/core/arch/arm/plat-stm32mp1/pm/context_asm_defines.c b/core/arch/arm/plat-stm32mp1/pm/context_asm_defines.c +new file mode 100644 +index 0000000..34c797f +--- /dev/null ++++ b/core/arch/arm/plat-stm32mp1/pm/context_asm_defines.c +@@ -0,0 +1,28 @@ ++// SPDX-License-Identifier: BSD-3-Clause ++/* ++ * Copyright (c) 2018, STMicroelectronics ++ * Copyright (c) 2018, Linaro Limited ++ */ ++ ++#include ++ ++#include "context.h" ++ ++#define OFFSET_OF_CTX_STRUCT(_f) offsetof(struct retram_resume_ctx, _f) ++#define OFFSET_OF_CMM_CTX_STRUCT(_f) (OFFSET_OF_CTX_STRUCT(ccm_ctx) + \ ++ offsetof(struct ccm_unpg_ctx, _f)) ++DEFINES ++{ ++ DEFINE(PM_CTX_RESUME_PA, OFFSET_OF_CTX_STRUCT(resume_pa)); ++ DEFINE(PM_CTX_TEERAM_BKP_PA, OFFSET_OF_CTX_STRUCT(teeram_bkp_pa)); ++ DEFINE(PM_CTX_CRYP1_BASE, OFFSET_OF_CTX_STRUCT(cryp1_base)); ++ DEFINE(PM_CTX_RCC_BASE, OFFSET_OF_CTX_STRUCT(rcc_base)); ++ DEFINE(PM_CTX_STGEN_BASE, OFFSET_OF_CTX_STRUCT(stgen_base)); ++ DEFINE(PM_CTX_STGEN_CNT, OFFSET_OF_CTX_STRUCT(stgen_cnt)); ++ DEFINE(PM_CTX_CCM_KEY, OFFSET_OF_CMM_CTX_STRUCT(key)); ++ DEFINE(PM_CTX_CCM_CTR1, OFFSET_OF_CMM_CTX_STRUCT(ctr1)); ++ DEFINE(PM_CTX_CCM_B0, OFFSET_OF_CMM_CTX_STRUCT(b0)); ++ DEFINE(PM_CTX_CCM_CTR0, OFFSET_OF_CMM_CTX_STRUCT(ctr0)); ++ DEFINE(PM_CTX_CCM_TAG, OFFSET_OF_CMM_CTX_STRUCT(tag)); ++ DEFINE(PM_CTX_CCM_REF_TAG, OFFSET_OF_CTX_STRUCT(ccm_ref_tag)); ++} +diff --git a/core/arch/arm/plat-stm32mp1/pm/low_power.c b/core/arch/arm/plat-stm32mp1/pm/low_power.c +new file mode 100644 +index 0000000..bd28014 +--- /dev/null ++++ b/core/arch/arm/plat-stm32mp1/pm/low_power.c +@@ -0,0 +1,431 @@ ++// SPDX-License-Identifier: BSD-3-Clause ++/* ++ * Copyright (c) 2017-2018, STMicroelectronics - All Rights Reserved ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "context.h" ++#include "power.h" ++ ++static uint8_t gicd_rcc_wakeup; ++static uint8_t gicc_pmr; ++static bool ddr_in_selfrefresh; ++ ++struct pwr_lp_config { ++ uint32_t pwr_cr1; ++ uint32_t pwr_mpucr; ++ const char *regul_suspend_node_name; ++}; ++ ++#define PWR_CR1_MASK (PWR_CR1_LPDS | PWR_CR1_LPCFG | PWR_CR1_LVDS) ++#define PWR_MPUCR_MASK (PWR_MPUCR_CSTDBYDIS | PWR_MPUCR_CSSF | PWR_MPUCR_PDDS) ++ ++static const struct pwr_lp_config config_pwr[STM32_PM_MAX_SOC_MODE] = { ++ [STM32_PM_CSLEEP_RUN] = { ++ .pwr_cr1 = 0U, ++ .pwr_mpucr = 0U, ++ .regul_suspend_node_name = NULL, ++ }, ++ [STM32_PM_CSTOP_ALLOW_STOP] = { ++ .pwr_cr1 = 0U, ++ .pwr_mpucr = PWR_MPUCR_CSTDBYDIS | PWR_MPUCR_CSSF, ++ .regul_suspend_node_name = NULL, ++ }, ++ [STM32_PM_CSTOP_ALLOW_LP_STOP] = { ++ .pwr_cr1 = PWR_CR1_LPDS, ++ .pwr_mpucr = PWR_MPUCR_CSTDBYDIS | PWR_MPUCR_CSSF, ++ .regul_suspend_node_name = "lp-stop", ++ }, ++ [STM32_PM_CSTOP_ALLOW_LPLV_STOP] = { ++ .pwr_cr1 = PWR_CR1_LVDS | PWR_CR1_LPDS | PWR_CR1_LPCFG, ++ .pwr_mpucr = PWR_MPUCR_CSTDBYDIS | PWR_MPUCR_CSSF, ++ .regul_suspend_node_name = "lplv-stop", ++ }, ++ [STM32_PM_CSTOP_ALLOW_STANDBY_DDR_SR] = { ++ .pwr_cr1 = 0U, ++ .pwr_mpucr = PWR_MPUCR_CSTDBYDIS | PWR_MPUCR_CSSF | ++ PWR_MPUCR_PDDS, ++ .regul_suspend_node_name = "standby-ddr-sr", ++ }, ++ [STM32_PM_CSTOP_ALLOW_STANDBY_DDR_OFF] = { ++ .pwr_cr1 = 0U, ++ .pwr_mpucr = PWR_MPUCR_CSTDBYDIS | PWR_MPUCR_CSSF | ++ PWR_MPUCR_PDDS, ++ .regul_suspend_node_name = "standby-ddr-off", ++ }, ++ [STM32_PM_SHUTDOWN] = { ++ .pwr_cr1 = 0U, ++ .pwr_mpucr = 0U, ++ .regul_suspend_node_name = "standby-ddr-off", ++ }, ++}; ++ ++static void set_rcc_it_priority(uint8_t *it_prio, uint8_t *pmr) ++{ ++ *it_prio = itr_set_ipriority(RCC_WAKEUP_IT, GIC_HIGHEST_SEC_PRIORITY); ++ *pmr = itr_set_pmr(STM32MP_GIC_PRIORITY_CSTOP); ++} ++ ++static void restore_rcc_it_priority(uint8_t it_prio, uint8_t pmr) ++{ ++ (void)itr_set_ipriority(RCC_WAKEUP_IT, it_prio); ++ (void)itr_set_pmr(pmr); ++} ++ ++static void stm32_apply_pmic_suspend_config(uint32_t mode) ++{ ++ if (stm32mp_with_pmic()) { ++ const char *name = config_pwr[mode].regul_suspend_node_name; ++ ++ assert(mode < ARRAY_SIZE(config_pwr)); ++ stm32mp_get_pmic(); ++ stm32mp_pmic_apply_lp_config(name); ++ stm32mp_pmic_apply_boot_on_config(); // ??? should be done at wakeup only? ++ stm32mp_put_pmic(); ++ } ++} ++ ++#define CONSOLE_FLUSH_DELAY_MS 10 ++ ++#if TRACE_LEVEL >= TRACE_DEBUG ++static void wait_console_flushed(void) ++{ ++ console_flush(); ++ mdelay(CONSOLE_FLUSH_DELAY_MS); ++} ++#else ++static void wait_console_flushed(void) ++{ ++} ++#endif ++ ++static void cpu_wfi(void) ++{ ++ dsb(); ++ isb(); ++ wfi(); ++} ++ ++void stm32_pm_cpu_wfi(void) ++{ ++ wait_console_flushed(); ++ cpu_wfi(); ++} ++ ++/*If IWDG is not supported, provide a stubbed weak watchdog kicker */ ++void __weak stm32_iwdg_refresh(uint32_t __unused instance) ++{ ++} ++ ++/* ++ * stm32_enter_cstop - Prepare CSTOP mode ++ * ++ * @mode - Target low power mode ++ * Return 0 if succeed to suspend, non 0 else. ++ */ ++int stm32_enter_cstop(uint32_t mode) ++{ ++ uint32_t pwr_cr1 = config_pwr[mode].pwr_cr1; ++ uintptr_t pwr_base = stm32_pwr_base(); ++ uintptr_t rcc_base = stm32_rcc_base(); ++ int rc; ++ ++ stm32_apply_pmic_suspend_config(mode); ++ ++ if (stm32mp_with_pmic() && (mode == STM32_PM_CSTOP_ALLOW_LP_STOP)) { ++ pwr_cr1 |= PWR_CR1_LPCFG; ++ } ++ ++ /* Workaround for non secure cache issue: this should not be needed */ ++ dcache_op_all(DCACHE_OP_CLEAN_INV); ++ ++ /* Clear RCC interrupt before enabling it */ ++ mmio_setbits_32(rcc_base + RCC_MP_CIFR, RCC_MP_CIFR_WKUPF); ++ ++ /* Enable RCC Wake-up */ ++ mmio_setbits_32(rcc_base + RCC_MP_CIER, RCC_MP_CIFR_WKUPF); ++ ++ /* Configure low power mode */ ++ mmio_clrsetbits_32(pwr_base + PWR_MPUCR_OFF, PWR_MPUCR_MASK, ++ config_pwr[mode].pwr_mpucr); ++ mmio_clrsetbits_32(pwr_base + PWR_CR1_OFF, PWR_CR1_MASK, pwr_cr1); ++ ++ /* Clear RCC pending interrupt flags */ ++ mmio_write_32(rcc_base + RCC_MP_CIFR, RCC_MP_CIFR_MASK); ++ ++ /* Request CSTOP mode to RCC */ ++ mmio_setbits_32(rcc_base + RCC_MP_SREQSETR, ++ RCC_MP_SREQSETR_STPREQ_P0 | RCC_MP_SREQSETR_STPREQ_P1); ++ ++ stm32_iwdg_refresh(IWDG2_INST); ++ ++ set_rcc_it_priority(&gicd_rcc_wakeup, &gicc_pmr); ++ ++ rc = ddr_standby_sr_entry(NULL); ++ ++ ddr_in_selfrefresh = (rc == 0); ++ ++ return rc; ++} ++ ++/* ++ * stm32_exit_cstop - Exit from CSTOP mode ++ */ ++void stm32_exit_cstop(void) ++{ ++ uintptr_t rcc_base = stm32_rcc_base(); ++ ++ if (ddr_in_selfrefresh) { ++ if (ddr_sw_self_refresh_exit() != 0) { ++ panic(); ++ } ++ ddr_in_selfrefresh = false; ++ } ++ ++ restore_rcc_it_priority(gicd_rcc_wakeup, gicc_pmr); ++ ++ /* Disable STOP request */ ++ mmio_setbits_32(rcc_base + RCC_MP_SREQCLRR, ++ RCC_MP_SREQSETR_STPREQ_P0 | RCC_MP_SREQSETR_STPREQ_P1); ++ ++ /* Disable RCC Wake-up */ ++ mmio_clrbits_32(rcc_base + RCC_MP_CIER, RCC_MP_CIFR_WKUPF); ++ ++ dsb(); ++ isb(); ++} ++ ++static void __noreturn reset_cores(void) ++{ ++ uintptr_t rcc_base = stm32_rcc_base(); ++ uint32_t reset_mask; ++ uint32_t target_mask; ++ ++ if (get_core_pos() == 0) { ++ reset_mask = RCC_MP_GRSTCSETR_MPUP0RST; ++ target_mask = TARGET_CPU1_GIC_MASK; ++ } else { ++ reset_mask = RCC_MP_GRSTCSETR_MPUP1RST; ++ target_mask = TARGET_CPU0_GIC_MASK; ++ } ++ ++ itr_raise_sgi(GIC_SEC_SGI_1, target_mask); ++ dcache_op_all(DCACHE_OP_CLEAN_INV); ++ write32(reset_mask, rcc_base + RCC_MP_GRSTCSETR); ++ cpu_wfi(); ++ panic("Cores reset"); ++} ++ ++/* ++ * stm32_pm_cpus_reset - Reset only cpus ++ */ ++void __noreturn stm32_cores_reset(void) ++{ ++ reset_cores(); ++} ++KEEP_PAGER(stm32_cores_reset); ++ ++/* ++ * stm32_enter_cstop_shutdown - Shutdown CPUs to target low power mode ++ * @mode - Target low power mode ++ */ ++void __noreturn stm32_enter_cstop_shutdown(uint32_t mode) ++{ ++ switch (mode) { ++ case STM32_PM_SHUTDOWN: ++ if (stm32mp_with_pmic()) { ++ wait_console_flushed(); ++ stm32mp_get_pmic(); ++ stpmic1_switch_off(); ++ udelay(100); ++ } ++ break; ++ case STM32_PM_CSTOP_ALLOW_STANDBY_DDR_SR: ++ case STM32_PM_CSTOP_ALLOW_STANDBY_DDR_OFF: ++#ifdef STM32MP1_USE_MPU0_RESET ++ stm32mp_pm_shutdown_context(); ++ stm32_enter_cstop(mode); ++ cpu_wfi(); ++ reset_cores(); ++#else ++ if (stm32mp_with_pmic()) { ++ wait_console_flushed(); ++ stm32mp_get_pmic(); ++ stpmic1_switch_off(); ++ udelay(100); ++ } ++#endif ++ break; ++ default: ++ break; ++ } ++ ++ panic(); ++} ++ ++/* ++ * stm32_enter_cstop_reset - Reset CPUs to target low power mode ++ * @mode - Target low power mode ++ */ ++void __noreturn stm32_enter_cstop_reset(uint32_t mode) ++{ ++ uintptr_t rcc_base = stm32_rcc_base(); ++ ++ switch (mode) { ++ case STM32_PM_SHUTDOWN: ++ write32(RCC_MP_GRSTCSETR_MPSYSRST, rcc_base + RCC_MP_GRSTCSETR); ++ udelay(100); ++ break; ++ default: ++#ifdef STM32MP1_USE_MPU0_RESET ++ reset_cores(); ++#else ++ IMSG("Forced system reset"); ++ wait_console_flushed(); ++ write32(RCC_MP_GRSTCSETR_MPSYSRST, rcc_base + RCC_MP_GRSTCSETR); ++ udelay(100); ++#endif ++ break; ++ } ++ ++ panic(); ++} ++ ++/* ++ * stm32_enter_csleep - enter CSLEEP state while WFI and exit in CRUN ++ * ++ * Configure PWR for CSLEEP state. CPU shall execute a WFI and return ++ * once a interrupt is pending. ++ */ ++void stm32_enter_csleep(void) ++{ ++ uintptr_t pwr_base = stm32_pwr_base(); ++ ++ mmio_clrsetbits_32(pwr_base + PWR_MPUCR_OFF, PWR_MPUCR_MASK, ++ config_pwr[STM32_PM_CSLEEP_RUN].pwr_mpucr); ++ mmio_clrsetbits_32(pwr_base + PWR_CR1_OFF, PWR_CR1_MASK, ++ config_pwr[STM32_PM_CSLEEP_RUN].pwr_cr1); ++ ++ stm32_pm_cpu_wfi(); ++} ++ ++/* ++ * Secure interrupts used in the low power sequences ++ */ ++#define GICC_IAR 0x00C ++#define GICC_IAR_IT_ID_MASK 0x3ff ++#define GICC_EOIR 0x010 ++ ++/* RCC Wakeup interrupt is used to wake from suspeneded mode */ ++static enum itr_return rcc_wakeup_it_handler(struct itr_handler *hdl __unused) ++{ ++ /* This interrupt is not expected to be handled */ ++ panic("RCC wakeup interrupt"); ++ return ITRR_HANDLED; ++} ++ ++static struct itr_handler rcc_wakeup_handler = { ++ .it = RCC_WAKEUP_IT, ++ .handler = rcc_wakeup_it_handler, ++}; ++KEEP_PAGER(rcc_wakeup_handler); ++ ++/* SGI9 (secure SGI 1) informs targeted CPU it shall reset */ ++static enum itr_return sgi9_it_handler(struct itr_handler *handler) ++{ ++ uintptr_t rcc_base = stm32_rcc_base(); ++ uint32_t reset_mask; ++ uintptr_t gicc_base = get_gicc_base(); ++ ++ write32(handler->it, gicc_base + GICC_EOIR); ++ ++ if (get_core_pos() == 0) { ++ reset_mask = RCC_MP_GRSTCSETR_MPUP0RST; ++ } else { ++ reset_mask = RCC_MP_GRSTCSETR_MPUP1RST; ++ } ++ ++ dcache_op_all(DCACHE_OP_CLEAN_INV); ++ write32(reset_mask, rcc_base + RCC_MP_GRSTCSETR); ++ cpu_wfi(); ++ panic("Core reset"); ++ ++ return ITRR_HANDLED; ++} ++ ++static struct itr_handler sgi9_reset_handler = { ++ .it = GIC_SEC_SGI_1, ++ .handler = sgi9_it_handler, ++}; ++KEEP_PAGER(sgi9_reset_handler); ++ ++static TEE_Result init_low_power(void) ++{ ++ uintptr_t pwr_base = stm32_pwr_base(); ++ ++ itr_add(&rcc_wakeup_handler); ++ itr_enable(rcc_wakeup_handler.it); ++ ++ itr_add(&sgi9_reset_handler); ++ itr_enable(sgi9_reset_handler.it); ++ ++ /* Enable retention for BKPSRAM and BKPREG */ ++ io_mask32(pwr_base + PWR_CR2_OFF, ++ PWR_CR2_BREN | PWR_CR2_RREN, PWR_CR2_BREN | PWR_CR2_RREN); ++ ++ return TEE_SUCCESS; ++} ++service_init(init_low_power); ++ ++/* ++ * CPU low power sequences ++ */ ++void __noreturn stm32_pm_cpu_power_down_wfi(void) ++{ ++ if (get_core_pos() == 0) { ++ void (*reset_ep)(void) = stm32mp_sysram_resume; ++ ++ wait_console_flushed(); ++ ++ dsb(); ++ isb(); ++ wfi(); ++ /* STANDBY not reached: resume from retained SYSRAM */ ++ stm32_exit_cstop(); ++ stm32mp_cpu_reset_state(); ++ reset_ep(); ++ panic(); ++ } ++ ++ dcache_op_level1(DCACHE_OP_CLEAN); ++ write32(RCC_MP_GRSTCSETR_MPUP1RST, stm32_rcc_base() + RCC_MP_GRSTCSETR); ++ cpu_wfi(); ++ panic(); ++} +diff --git a/core/arch/arm/plat-stm32mp1/pm/pm_helpers.S b/core/arch/arm/plat-stm32mp1/pm/pm_helpers.S +new file mode 100644 +index 0000000..91c7580 +--- /dev/null ++++ b/core/arch/arm/plat-stm32mp1/pm/pm_helpers.S +@@ -0,0 +1,635 @@ ++/* SPDX-License-Identifier: BSD-2-Clause */ ++/* ++ * Copyright (c) 2018, STMicroelectronics ++ * Copyright (c) 2017 NXP ++ * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "context.h" ++ ++/* ++ * Right bit shift distance to reach timeout from a 1s STGEN freq count ++ * Value N relates to 1000ms / 2^N, i.e 7 relates to 7.8125ms=~8ms ++ */ ++#define CCM_TIMEOUT_128MS 2 ++#define CCM_TIMEOUT_8MS 7 ++#define CCM_TIMEOUT_1MS 10 ++#define CCM_TIMEOUT_16US 16 ++#define CCM_TIMEOUT CCM_TIMEOUT_8MS ++ ++/* ++ * CRYP interface register used for AES CCM ++ */ ++#define CRYP_CR 0x000 ++#define CRYP_SR 0x004 ++#define CRYP_DIN 0x008 ++#define CRYP_DOUT 0x00c ++#define CRYP_KEYR_BASE 0x020 ++#define CRYP_IVR_BASE 0x040 ++ ++#define CRYP_CR_ALGODIR_DECRYPT BIT(2) ++#define CRYP_CR_ALGOMODE_MASK (BIT(19) | GENMASK_32(5, 3)) ++#define CRYP_CR_ALGOMODE(m) (((m & BIT(3)) << 16) | (m & 0x7) << 3) ++#define ALGOMODE_AES_CCM 0x9 ++#define CRYP_CR_DATATYPE_SHIFT 6 ++#define CRYP_CR_DATATYPE_8BIT (2 << CRYP_CR_DATATYPE_SHIFT) ++#define CRYP_CR_KEYSIZE_SHIFT 8 ++#define CRYP_CR_KEYSIZE_256BIT (2U << CRYP_CR_KEYSIZE_SHIFT) ++#define CRYP_CR_CRYPEN BIT(15) ++#define CRYP_CR_FFLUSH BIT(14) ++#define CRYP_CR_GCM_CCMPH_SHIFT 16 ++#define CRYP_CR_PHASE_MASK (0x3 << CRYP_CR_GCM_CCMPH_SHIFT) ++#define CRYP_CR_INIT_PHASE (0 << CRYP_CR_GCM_CCMPH_SHIFT) ++#define CRYP_CR_HEADER_PHASE (1 << CRYP_CR_GCM_CCMPH_SHIFT) ++#define CRYP_CR_PAYLOAD_PHASE (2 << CRYP_CR_GCM_CCMPH_SHIFT) ++#define CRYP_CR_FINAL_PHASE (3 << CRYP_CR_GCM_CCMPH_SHIFT) ++ ++#define CRYP_SR_BUSY BIT(4) ++#define CRYP_SR_OFFU BIT(3) ++#define CRYP_SR_OFNE BIT(2) ++#define CRYP_SR_IFNF BIT(1) ++#define CRYP_SR_IFEM BIT(0) ++ ++ /* Bound of the binary image loaded in retained memory */ ++ .global stm32mp_bkpsram_image_end ++ ++/* ++ * stm32mp_bkpsram_resume - Restore TEE RAM from backup memory and resume into ++ * ++ * This function executes at early resume from suspend state. It is the ++ * entrypoint of the OP-TEE provided to early boot stage when SoC wakes. ++ * This code is located in a retained memory, MMU disabled. This function ++ * shall restore TEE RAM content for OP-TEE to resume execution. Once ++ * TEE RAM is restored, this function branches to the resident resume entry ++ * point in TEE_RAM. This function and its resources shall execute in place. ++ */ ++FUNC stm32mp_bkpsram_resume , : ++UNWIND( .fnstart) ++UNWIND( .cantunwind) ++ /* ++ * Almost all sequences here expect PM context structure base address ++ * from CPU register r11. ++ */ ++ mov_imm r11, (BKPSRAM_BASE + BKPSRAM_PM_CONTEXT_OFFSET) ++ ++ /* stm32mp_ccm_teeram needs some HW interface base addresss */ ++ mov_imm r0, CRYP1_BASE ++ str r0, [r11, #PM_CTX_CRYP1_BASE] ++ mov_imm r0, RCC_BASE ++ str r0, [r11, #PM_CTX_RCC_BASE] ++ mov_imm r0, STGEN_BASE ++ str r0, [r11, #PM_CTX_STGEN_BASE] ++ ++ bl _clear_early_mailbox ++ bl _prepare_time ++ ++ mov_imm r0, TEE_RAM_START ++ ldr r1, [r11, #PM_CTX_TEERAM_BKP_PA] ++ mov_imm r2, TEE_RAM_PH_SIZE ++ mov_imm r3, 1 ++ bl stm32mp_ccm_teeram ++ cmp r0, #0 ++ bne _failed ++ ++ /* Compare the generated and reference tags */ ++ add r8, r11, #PM_CTX_CCM_TAG ++ add r9, r11, #PM_CTX_CCM_REF_TAG ++ ldm r8, {r2-r5} ++ ldm r9, {r6-r9} ++ mov r0, #0 ++ cmp r2, r6 ++ addeq r0, #1 ++ cmp r3, r7 ++ addeq r0, #1 ++ cmp r4, r8 ++ addeq r0, #1 ++ cmp r5, r9 ++ addeq r0, #1 ++ cmp r0, #4 ++ bne _failed ++ bl _save_resume_time ++ ++ /* Resume into the restored TEE RAM */ ++ ldr r1, [r11, #PM_CTX_RESUME_PA] ++ bx r1 ++ ++_failed: ++ /* Clear context including key and reference tag */ ++ mov r0, #0xa5 ++ mov_imm r12, BKPSRAM_PM_CONTEXT_SIZE ++ add r12, r11, r12 ++1: str r0, [r11], #4 ++ cmp r11, r12 ++ blt 1b ++ b . ++ ++ /* ++ * _clear_early_mailbox - Wipe mailbox in case of reset ++ * ++ * Sratches r0-r4. ++ * All other CPU registers are preserved. ++ */ ++_clear_early_mailbox: ++ /* Clear the backup registers (first enable RTCAPB clock) */ ++ mov_imm r0, (RCC_BASE + RCC_MP_APB5ENSETR) ++ mov_imm r2, RCC_MP_APB5ENSETR_RTCAPBEN ++ ldr r1, [r0] ++ ands r1, r1, r2 ++ moveq r1, r2 ++ movne r1, #0 ++ str r2, [r0] ++ mov_imm r2, (TAMP_BASE + TAMP_BKP_REGISTER_OFF) ++ mov_imm r3, (BCKR_CORE1_MAGIC_NUMBER * 4) ++ mov_imm r4, BOOT_API_A7_RESET_MAGIC_NUMBER ++ str r4, [r2, r3] ++ mov_imm r3, (BCKR_CORE1_BRANCH_ADDRESS * 4) ++ mov r4, #0 ++ str r4, [r2, r3] ++ /* Restore RTCAPB clock initial state */ ++ str r1, [r0, #RCC_MP_ENCLRR_OFFSET] ++ bx lr ++ ++ /* ++ * prepare_time - save/reset cycle counter to prevent later overflow ++ * ++ * Save current 32bit lower counter and reset to 0 so that later ++ * timeout test do not need to care about overflow. ++ * ++ * Expects r11 is context base and lr is return address. ++ * Scrathes r0-r2. ++ * All other CPU registers are preserved. ++ */ ++_prepare_time: ++ ldr r2, [r11, #PM_CTX_STGEN_BASE] ++ /* Disable STGEN counter */ ++ ldr r1, [r2, #CNTCR_OFFSET] ++ bic r1, r1, #CNTCR_EN ++ str r1, [r2, #CNTCR_OFFSET] ++1: ldr r1, [r2, #CNTSR_OFFSET] ++ tst r1, #CNTCR_EN ++ bne 1b ++ /* Save and reset STGEN counter */ ++ ldr r0, [r2, #CNTCVL_OFFSET] ++ str r0, [r11, #PM_CTX_STGEN_CNT] ++ mov r0, #0 ++ str r0, [r2, #CNTCVL_OFFSET] ++ ldr r0, [r2, #CNTCVU_OFFSET] ++ str r0, [r2, #CNTCVU_OFFSET] ++ /* Enable STGEN counter */ ++ ldr r1, [r2, #CNTCR_OFFSET] ++ orr r1, r1, #CNTCR_EN ++ str r1, [r2, #CNTCR_OFFSET] ++ bx lr ++ ++ /* ++ * save_resume_time - save time spent and restore STGEN cycle counter ++ * ++ * Restore STGEN counter to initial value incremented by the current ++ * count. Note 32bit upper may need to be incremented. ++ * ++ * Expects r11 is context base and lr is return address. ++ * Scrathes r0-r3. ++ * All other CPU registers are preserved. ++ */ ++_save_resume_time: ++ /* Compute update STGEN counter 32bit LSB value */ ++ ldr r2, [r11, #PM_CTX_STGEN_BASE] ++ ldr r0, [r11, #PM_CTX_STGEN_CNT] ++ ldr r3, [r2, #CNTCVL_OFFSET] ++ str r3, [r11, #PM_CTX_STGEN_CNT] ++ adds r0, r0, r3 ++ /* Disable STGEN */ ++ ldr r1, [r2, #CNTCR_OFFSET] ++ bic r1, r1, #CNTCR_EN ++ str r1, [r2, #CNTCR_OFFSET] ++1: ldr r1, [r2, #CNTSR_OFFSET] ++ tst r1, #CNTCR_EN ++ bne 1b ++ /* Update counter (increment 32bit MSB if requried) */ ++ str r0, [r2, #CNTCVL_OFFSET] ++ ldr r0, [r2, #CNTCVU_OFFSET] ++ addcs r0, r0, #1 ++ str r0, [r2, #CNTCVU_OFFSET] /* Write CNTCVU value ... */ ++ ldr r0, [r2, #CNTCVU_OFFSET] /* ... and wait it is set */ ++ /* Enable STGEN */ ++ ldr r0, [r2, #CNTCR_OFFSET] ++ orr r0, r0, #CNTCR_EN ++ str r0, [r2, #CNTCR_OFFSET] ++ bx lr ++ ++ /* ++ * _setup_cryp1 - Enable CRYP1 hardware: reset & clock ++ * _reset_cryp1 - Reset CRYP1 hardware ++ * ++ * Function call before and after CCM sequence. Note that the CRYP1 ++ * clock remain enabled. It is disabled later by the resume sequence. ++ * ++ * Expects r11 is context base and lr is return address. ++ * Scratches r0-r3. ++ */ ++_setup_cryp1: ++ ldr r1, [r11, #PM_CTX_RCC_BASE] ++ mov_imm r0, RCC_MP_AHB5ENSETR_CRYP1EN ++ str r0, [r1, #RCC_MP_AHB5ENSETR] ++ /* Intentionnally fall through reset_cryp1 */ ++_reset_cryp1: ++ ldr r3, [r11, #PM_CTX_RCC_BASE] ++ mov_imm r0, RCC_AHB5RSTSETR_CRYP1RST ++ str r0, [r3, #RCC_AHB5RSTSETR] ++1: ldr r1, [r3, #RCC_AHB5RSTSETR] ++ ands r1, r1, r0 ++ beq 1b ++ mov_imm r0, RCC_AHB5RSTSETR_CRYP1RST ++ str r0, [r3, #RCC_AHB5RSTCLRR] ++1: ldr r1, [r3, #RCC_AHB5RSTSETR] ++ ands r1, r1, r0 ++ bne 1b ++ bx lr ++ ++ /* ++ * _ccm_arm_8ms_timeout - Init 8ms threshold for _ccm_failed_on_timeout ++ * _ccm_fail_on_timeout - Check STGEN counter against timeout threshold ++ * ++ * These function are used by the macro wait_flag_timeout_8ms. The ++ * former loads the timeout in CPU register r0 while the later get the ++ * timeout counter threshold from CPU register r0. ++ * ++ * Expect r11 is context base and lr is return address. ++ * Scratch r0-r1. ++ * All other CPU registers are preserved. ++ */ ++_ccm_arm_8ms_timeout: ++ ldr r1, [r11, #PM_CTX_STGEN_BASE] ++ ldr r0, [r1, #CNTFID_OFFSET] ++ lsrs r0, r0, #CCM_TIMEOUT ++ moveq r0, #1 ++ ldr r1, [r1, #CNTCVL_OFFSET] ++ adds r0, r0, r1 ++ bcs _ccm_failed ++ bx lr ++ ++_ccm_fail_on_timeout: ++ ldr r1, [r11, #PM_CTX_STGEN_BASE] ++ ldr r1, [r1, #CNTCVL_OFFSET] ++ cmp r1, r0 ++ bge _ccm_failed ++ bx lr ++ ++ /* ++ * Macro WAIT_FLAG_TIMEOUT compares timeout threshold (r0) with ++ * current time and branches the CCM failure entry on timeout. ++ * It is assumed the 32bit timestamps cannot overflow. ++ */ ++ .macro WAIT_FLAG_TIMEOUT register_offset, bit_mask, awaited_mask ++ bl _ccm_arm_8ms_timeout ++ 1: ++ bl _ccm_fail_on_timeout ++ ldr r1, [r10, #(\register_offset)] ++ and r1, r1, #(\bit_mask) ++ cmp r1, #(\awaited_mask) ++ bne 1b ++ .endm ++ ++/* ++ * stm32mp_ccm_teeram - Size optimzed unpaged CCM encryption/decryption ++ * ++ * This sequence encrypts or decrypts a input block using AES CCM with a ++ * 256bit key and no AAD and generates the CCM tag. The key, CTR0, CTR1 ++ * and B0 block are read from PM context structure. The generated tag is ++ * stored in the PM context structure. ++ * ++ * This function is executed from TEE RAM during suspend sequence to generate ++ * the encrypted data and the tag. This function is also executed from BKPSRAM ++ * called with MMU disabled. Therefore this sequence shall be comply with ++ * position independent code constraints. ++ * ++ * Expects at entry: ++ * lr = caller return address ++ * r11 = retram_resume_ctx structure base address ++ * r0 = Destination buffer for the output data (ciphertext or plaintext) ++ * r1 = Source buffer for the input data (plaintext or ciphertext) ++ * r2 = Input (and output) data size in bytes ++ * r3 = 1 if decrypting, 0 if encrypting ++ */ ++stm32mp_ccm_teeram: ++ /* ++ * Use of the CPU registers in the whole stm32mp_ccm_teeram sequence ++ * ++ * sp: preserved, not used ++ * lr: scratch register used to call subroutines. ++ * r12: saves the caller link register for final return ++ * r11: context from BKPSRAM ++ * r10: CRYP1 base address ++ * r9: destination buffer ++ * r8: source buffer to cipher ++ * r7: data byte counter ++ * r0-r6 are scratch registers ++ */ ++ mov r12, lr ++ ldr r10, [r11, #PM_CTX_CRYP1_BASE] ++ mov r9, r0 ++ mov r8, r1 ++ mov r7, r2 ++ mov r6, r3 ++ ++ bl _setup_cryp1 ++ ++ mov_imm r0, (CRYP_CR_ALGOMODE(ALGOMODE_AES_CCM) | \ ++ CRYP_CR_DATATYPE_8BIT | CRYP_CR_FFLUSH | \ ++ CRYP_CR_KEYSIZE_256BIT) ++ cmp r6, #0 ++ orrne r0, r0, #CRYP_CR_ALGODIR_DECRYPT ++ str r0, [r10, #CRYP_CR] ++ ++ /* Check data alignment (addresses and size) */ ++ ands r0, r7, #0x0F ++ bne _ccm_failed ++ ands r0, r8, #0x03 ++ bne _ccm_failed ++ ands r0, r9, #0x03 ++ bne _ccm_failed ++ ++ ldr r0, [r11, #PM_CTX_CCM_KEY] ++ str r0, [r10, #CRYP_KEYR_BASE] ++ ldr r0, [r11, #(PM_CTX_CCM_KEY + 4)] ++ str r0, [r10, #(CRYP_KEYR_BASE + 4)] ++ ldr r0, [r11, #(PM_CTX_CCM_KEY + 8)] ++ str r0, [r10, #(CRYP_KEYR_BASE + 8)] ++ ldr r0, [r11, #(PM_CTX_CCM_KEY + 12)] ++ str r0, [r10, #(CRYP_KEYR_BASE + 12)] ++ ldr r0, [r11, #(PM_CTX_CCM_KEY + 16)] ++ str r0, [r10, #(CRYP_KEYR_BASE + 16)] ++ ldr r0, [r11, #(PM_CTX_CCM_KEY + 20)] ++ str r0, [r10, #(CRYP_KEYR_BASE + 20)] ++ ldr r0, [r11, #(PM_CTX_CCM_KEY + 24)] ++ str r0, [r10, #(CRYP_KEYR_BASE + 24)] ++ ldr r0, [r11, #(PM_CTX_CCM_KEY + 28)] ++ str r0, [r10, #(CRYP_KEYR_BASE + 28)] ++ ++ ldr r0, [r11, #PM_CTX_CCM_CTR1] ++ str r0, [r10, #CRYP_IVR_BASE] ++ ldr r0, [r11, #(PM_CTX_CCM_CTR1 + 4)] ++ str r0, [r10, #(CRYP_IVR_BASE + 4)] ++ ldr r0, [r11, #(PM_CTX_CCM_CTR1 + 8)] ++ str r0, [r10, #(CRYP_IVR_BASE + 8)] ++ ldr r0, [r11, #(PM_CTX_CCM_CTR1 + 12)] ++ str r0, [r10, #(CRYP_IVR_BASE + 12)] ++ ++ /* Setup CRYP for the CCM Init Phase */ ++ ldr r0, [r10, #CRYP_CR] ++ orr r0, r0, #(CRYP_CR_CRYPEN | CRYP_CR_INIT_PHASE) ++ str r0, [r10, #CRYP_CR] ++ ldr r0, [r10, #CRYP_CR] ++ ++ ldr r0, [r11, #PM_CTX_CCM_B0] ++ str r0, [r10, #CRYP_DIN] ++ ldr r0, [r11, #(PM_CTX_CCM_B0 + 4)] ++ str r0, [r10, #CRYP_DIN] ++ ldr r0, [r11, #(PM_CTX_CCM_B0 + 8)] ++ str r0, [r10, #CRYP_DIN] ++ ldr r0, [r11, #(PM_CTX_CCM_B0 + 12)] ++ str r0, [r10, #CRYP_DIN] ++ ++ WAIT_FLAG_TIMEOUT CRYP_CR, CRYP_CR_CRYPEN, 0 ++ ++ /* Setup CRYP for the CCM Payload phase */ ++ ldr r0, [r10, #CRYP_CR] ++ bic r0, r0, #CRYP_CR_PHASE_MASK ++ orr r0, r0, #CRYP_CR_PAYLOAD_PHASE ++ orr r0, r0, #CRYP_CR_CRYPEN ++ str r0, [r10, #CRYP_CR] ++ ldr r0, [r10, #CRYP_CR] ++ ++_next_block: ++ WAIT_FLAG_TIMEOUT CRYP_SR, CRYP_SR_IFEM, CRYP_SR_IFEM ++ ++ /* Feed input data, r8 stores the current source buffer */ ++ ldr r0, [r8], #4 ++ str r0, [r10, #CRYP_DIN] ++ ldr r0, [r8], #4 ++ str r0, [r10, #CRYP_DIN] ++ ldr r0, [r8], #4 ++ str r0, [r10, #CRYP_DIN] ++ ldr r0, [r8], #4 ++ str r0, [r10, #CRYP_DIN] ++ ++ WAIT_FLAG_TIMEOUT CRYP_SR, CRYP_SR_OFNE, CRYP_SR_OFNE ++ ++ /* Store output data, r9 stores the current source buffer */ ++ ldr r0, [r10, #CRYP_DOUT] ++ str r0, [r9], #4 ++ ldr r0, [r10, #CRYP_DOUT] ++ str r0, [r9], #4 ++ ldr r0, [r10, #CRYP_DOUT] ++ str r0, [r9], #4 ++ /* Before last 32bit word, the output FIFO shall not be empty */ ++ ldr r0, [r10, #CRYP_SR] ++ ands r0, r0, #CRYP_SR_OFNE ++ beq _ccm_failed ++ /* After last 32bit word for this 128block, FIFO shall be empty */ ++ ldr r0, [r10, #CRYP_DOUT] ++ str r0, [r9], #4 ++ ldr r0, [r10, #CRYP_SR] ++ ands r0, r0, #CRYP_SR_OFNE ++ bne _ccm_failed ++ ++ /* Another round if remaining data */ ++ subs r7, r7, #16 ++ bne _next_block; ++ ++ WAIT_FLAG_TIMEOUT CRYP_SR, CRYP_SR_BUSY, 0 ++ ++ /* ++ * Data processing completed, now remains the tag generation. ++ * Here expect SR[IFNF]=SR[OFNE]=1 and all others bits are 0. ++ */ ++ ldr r0, [r10, #CRYP_SR] ++ cmp r0, #(CRYP_SR_IFEM | CRYP_SR_IFNF) ++ bne _ccm_failed ++ ++ /* Setup CRYP1 for the CCM Final Phase */ ++ ldr r0, [r10, #CRYP_CR] ++ bic r0, r0, #CRYP_CR_CRYPEN ++ str r0, [r10, #CRYP_CR] ++ ldr r0, [r10, #CRYP_CR] ++ bic r0, r0, #CRYP_CR_PHASE_MASK ++ bic r0, r0, #CRYP_CR_ALGODIR_DECRYPT ++ orr r0, r0, #CRYP_CR_FINAL_PHASE ++ orr r0, r0, #CRYP_CR_CRYPEN ++ str r0, [r10, #CRYP_CR] ++ ldr r0, [r10, #CRYP_CR] ++ ++ /* Load CTR0 to generate the tag */ ++ ldr r0, [r11, #PM_CTX_CCM_CTR0] ++ str r0, [r10, #CRYP_DIN] ++ ldr r0, [r11, #(PM_CTX_CCM_CTR0 + 4)] ++ str r0, [r10, #CRYP_DIN] ++ ldr r0, [r11, #(PM_CTX_CCM_CTR0 + 8)] ++ str r0, [r10, #CRYP_DIN] ++ ldr r0, [r11, #(PM_CTX_CCM_CTR0 + 12)] ++ str r0, [r10, #CRYP_DIN] ++ ++ WAIT_FLAG_TIMEOUT CRYP_SR, CRYP_SR_OFNE, CRYP_SR_OFNE ++ ++ /* Store generated tag in the PM_CTX structure */ ++ ldr r0, [r10, #CRYP_DOUT] ++ str r0, [r11, #PM_CTX_CCM_TAG] ++ ldr r0, [r10, #CRYP_DOUT] ++ str r0, [r11, #(PM_CTX_CCM_TAG + 4)] ++ ldr r0, [r10, #CRYP_DOUT] ++ str r0, [r11, #(PM_CTX_CCM_TAG + 8)] ++ /* Before last 32bit word, the output FIFO shall not be empty */ ++ ldr r0, [r10, #CRYP_SR] ++ ands r0, r0, #CRYP_SR_OFNE ++ beq _ccm_failed ++ /* After last 32bit word for this 128block, FIFO shall be empty */ ++ ldr r0, [r10, #CRYP_DOUT] ++ str r0, [r11, #(PM_CTX_CCM_TAG + 12)] ++ ldr r0, [r10, #CRYP_SR] ++ ands r0, r0, #CRYP_SR_OFNE ++ bne _ccm_failed ++ ++ /* Successful return */ ++ bl _reset_cryp1 ++ mov r0, #0 ++ bx r12 ++ ++_ccm_failed: ++ bl _reset_cryp1 ++ mov r0, #1 ++ bx r12 ++ ++/* End address of the PIC resume sequence copy in retained RAM */ ++stm32mp_bkpsram_image_end: ++ nop ++ ++UNWIND( .fnend) ++END_FUNC stm32mp_bkpsram_resume ++ ++/* ++ * int stm32mp_ccm_encrypt_teeram(ctx, dst, src, len) ++ */ ++FUNC stm32mp_ccm_encrypt_teeram , : ++UNWIND( .fnstart) ++ push {r4-r12, lr} ++UNWIND( .save {r4-r12, lr}) ++ mov r11, r0 ++ mov r0, r1 ++ mov r1, r2 ++ mov r2, r3 ++ mov r3, #0 ++ push {r0-r3} ++ bl _prepare_time ++ pop {r0-r3} ++ bl stm32mp_ccm_teeram ++ bl _save_resume_time ++ pop {r4-r12, pc} ++UNWIND( .fnend) ++END_FUNC stm32mp_ccm_encrypt_teeram ++ ++/* ++ * int stm32mp_ccm_decrypt_teeram(ctx, cryp_base, dst, src) ++ */ ++FUNC stm32mp_ccm_decrypt_teeram , : ++UNWIND( .fnstart) ++ push {r4-r12, lr} ++UNWIND( .save {r4-r12, lr}) ++ mov r11, r0 ++ mov r0, r1 ++ mov r1, r2 ++ mov r2, r3 ++ mov r3, #1 ++ push {r0-r3} ++ bl _prepare_time ++ pop {r0-r3} ++ bl stm32mp_ccm_teeram ++ bl _save_resume_time ++ pop {r4-r12, pc} ++UNWIND( .fnend) ++END_FUNC stm32mp_ccm_decrypt_teeram ++ ++/* ++ * stm32mp_sysram_resume - Resume OP-TEE execution ++ * ++ * This function is the entry point of OP-TEE core resume sequence in the TEE ++ * RAM. When TEE RAM is lost during a power cycle, stm32mp_bkpsram_resume() is ++ * called to restore TEE RAM content and branch to this stm32mp_sysram_resume() ++ * routine. ++ * ++ * This function calls the OP-TEE core generic PM resume API ++ * sm_pm_cpu_resume(). ++ */ ++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 ++ isb ++ ++ /* Resume sequence executes in Monitor mode */ ++ cps #CPSR_MODE_MON ++ ++ blx plat_cpu_reset_early ++ b sm_pm_cpu_resume ++UNWIND( .fnend) ++END_FUNC stm32mp_sysram_resume ++ ++/* ++ * stm32mp_cpu_reset_state - set CPU in a reset like state ++ * ++ * Disable CPU env (interrupts, cache, SMP, MMU) and return. ++ * Preserve the execution mode in CPSR. ++ */ ++FUNC stm32mp_cpu_reset_state, : ++UNWIND( .fnstart) ++ push {r12, lr} ++UNWIND( .save {r12, lr}) ++ ++ cpsid aif ++ ++ bl psci_armv7_cpu_off ++ ++ write_bpiall ++ isb ++ dsb ++ read_sctlr r0 ++ bic r0, r0, #SCTLR_M ++ bic r0, r0, #SCTLR_I ++ write_sctlr r0 ++ isb ++ dsb sy ++ ++ pop {r12, pc} ++UNWIND( .fnend) ++END_FUNC stm32mp_cpu_reset_state +diff --git a/core/arch/arm/plat-stm32mp1/pm/power.h b/core/arch/arm/plat-stm32mp1/pm/power.h +new file mode 100644 +index 0000000..21ca7be +--- /dev/null ++++ b/core/arch/arm/plat-stm32mp1/pm/power.h +@@ -0,0 +1,26 @@ ++/* SPDX-License-Identifier: BSD-3-Clause */ ++/* ++ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. ++ */ ++ ++#ifndef __STM32MP_PM_POWER_H__ ++#define __STM32MP_PM_POWER_H__ ++ ++#include ++#include ++#include ++ ++bool need_to_backup_cpu_context(unsigned int soc_mode); ++ ++void stm32_enter_csleep(void); ++ ++int stm32_enter_cstop(uint32_t mode); ++void stm32_exit_cstop(void); ++ ++void stm32_enter_cstop_shutdown(uint32_t mode) __noreturn; ++void stm32_enter_cstop_reset(uint32_t mode) __noreturn; ++ ++void stm32_pm_cpu_power_down_wfi(void) __noreturn; ++void stm32_pm_cpu_wfi(void); ++ ++#endif /*__STM32MP_PM_POWER_H__*/ +diff --git a/core/arch/arm/plat-stm32mp1/pm/power_config.c b/core/arch/arm/plat-stm32mp1/pm/power_config.c +new file mode 100644 +index 0000000..7845ede +--- /dev/null ++++ b/core/arch/arm/plat-stm32mp1/pm/power_config.c +@@ -0,0 +1,212 @@ ++// SPDX-License-Identifier: BSD-3-Clause ++/* ++ * Copyright (c) 2017-2018, STMicroelectronics - All Rights Reserved ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#ifdef CFG_DT ++#include ++#endif ++ ++#include "context.h" ++#include "power.h" ++ ++#define DT_PWR_COMPAT "st,stm32mp1-pwr" ++#define SYSTEM_SUSPEND_SUPPORTED_MODES "system_suspend_supported_soc_modes" ++#define SYSTEM_OFF_MODE "system_off_soc_mode" ++ ++static uint32_t deepest_suspend_mode = STM32_PM_CSTOP_ALLOW_STANDBY_DDR_SR; ++static uint32_t system_off_mode = STM32_PM_SHUTDOWN; ++ ++/* Default initialized to NOT supported until set from DT directives */ ++static uint8_t stm32mp1_supported_soc_modes[STM32_PM_MAX_SOC_MODE]; ++ ++/* Init with all domains ON */ ++static bool stm32mp1_pm_dom[STM32MP1_PD_MAX_PM_DOMAIN] = { ++ [STM32MP1_PD_VSW] = false, ++ [STM32MP1_PD_CORE_RET] = false, ++ [STM32MP1_PD_CORE] = false ++}; ++ ++bool need_to_backup_cpu_context(unsigned int soc_mode) ++{ ++ switch (soc_mode) { ++ case STM32_PM_CSTOP_ALLOW_STANDBY_DDR_SR: ++ return true; ++ case STM32_PM_CSLEEP_RUN: ++ case STM32_PM_CSTOP_ALLOW_STOP: ++ case STM32_PM_CSTOP_ALLOW_LP_STOP: ++ case STM32_PM_CSTOP_ALLOW_LPLV_STOP: ++ case STM32_PM_CSTOP_ALLOW_STANDBY_DDR_OFF: ++ case STM32_PM_SHUTDOWN: ++ return false; ++ default: ++ EMSG("Invalid mode 0x%x", soc_mode); ++ panic(); ++ } ++} ++ ++#ifdef CFG_DT ++static int dt_get_pwr_node(void *fdt) ++{ ++ return fdt_node_offset_by_compatible(fdt, -1, DT_PWR_COMPAT); ++} ++#endif ++ ++static bool get_pm_domain_state(uint8_t mode) ++{ ++ bool res = true; ++ enum stm32mp1_pm_domain id = STM32MP1_PD_MAX_PM_DOMAIN; ++ ++ while (res && (id > mode)) { ++ id--; ++ res &= stm32mp1_pm_dom[id]; ++ } ++ ++ return res; ++} ++ ++int stm32mp1_set_pm_domain_state(enum stm32mp1_pm_domain domain, bool status) ++{ ++ if (domain >= STM32MP1_PD_MAX_PM_DOMAIN) { ++ return -1; ++ } ++ ++ stm32mp1_pm_dom[domain] = status; ++ ++ return 0; ++} ++ ++#ifdef CFG_DT ++static void save_supported_mode(void *fdt, int pwr_node) ++{ ++ int len; ++ uint32_t count; ++ unsigned int i; ++ uint32_t supported[ARRAY_SIZE(stm32mp1_supported_soc_modes)]; ++ const void *prop; ++ ++ prop = fdt_getprop(fdt, pwr_node, SYSTEM_SUSPEND_SUPPORTED_MODES, &len); ++ if (prop == NULL) { ++ panic(); ++ } ++ ++ count = (uint32_t)len / sizeof(uint32_t); ++ if (count > STM32_PM_MAX_SOC_MODE) { ++ panic(); ++ } ++ ++ if (fdt_read_uint32_array(fdt, pwr_node, SYSTEM_SUSPEND_SUPPORTED_MODES, ++ &supported[0], count) < 0) { ++ panic("PWR DT"); ++ } ++ ++ for (i = 0; i < count; i++) { ++ if (supported[i] >= STM32_PM_MAX_SOC_MODE) { ++ panic("Invalid mode"); ++ } ++ stm32mp1_supported_soc_modes[supported[i]] = true; ++ } ++} ++#endif ++ ++static bool is_supported_mode(uint32_t soc_mode) ++{ ++ assert(soc_mode < ARRAY_SIZE(stm32mp1_supported_soc_modes)); ++ return stm32mp1_supported_soc_modes[soc_mode] == 1; ++} ++ ++uint32_t stm32mp1_get_lp_soc_mode(uint32_t psci_mode) ++{ ++ uint32_t mode; ++ ++ if (psci_mode == PSCI_MODE_SYSTEM_OFF) { ++ return system_off_mode; ++ } ++ ++ mode = deepest_suspend_mode; ++ ++ if ((mode == STM32_PM_CSTOP_ALLOW_STANDBY_DDR_SR) && ++ ((!get_pm_domain_state(STM32MP1_PD_CORE_RET)) || ++ (!is_supported_mode(mode)))) { ++ mode = STM32_PM_CSTOP_ALLOW_LPLV_STOP; ++ } ++ ++ if ((mode == STM32_PM_CSTOP_ALLOW_LPLV_STOP) && ++ ((!get_pm_domain_state(STM32MP1_PD_CORE)) || ++ (!is_supported_mode(mode)))) { ++ mode = STM32_PM_CSTOP_ALLOW_LP_STOP; ++ } ++ ++ if ((mode == STM32_PM_CSTOP_ALLOW_LP_STOP) && ++ (!is_supported_mode(mode))) { ++ mode = STM32_PM_CSTOP_ALLOW_STOP; ++ } ++ ++ if ((mode == STM32_PM_CSTOP_ALLOW_STOP) && ++ (!is_supported_mode(mode))) { ++ mode = STM32_PM_CSLEEP_RUN; ++ } ++ ++ return mode; ++} ++ ++int stm32mp1_set_lp_deepest_soc_mode(uint32_t psci_mode, uint32_t soc_mode) ++{ ++ if (soc_mode >= STM32_PM_MAX_SOC_MODE) { ++ return -1; ++ } ++ ++ if (psci_mode == PSCI_MODE_SYSTEM_SUSPEND) { ++ deepest_suspend_mode = soc_mode; ++ } ++ ++ if (psci_mode == PSCI_MODE_SYSTEM_OFF) { ++ system_off_mode = soc_mode; ++ } ++ ++ return 0; ++} ++ ++#ifdef CFG_DT ++static TEE_Result stm32mp1_init_lp_states(void) ++{ ++ void *fdt; ++ int pwr_node = -1; ++ const fdt32_t *cuint = NULL; ++ ++ fdt = get_dt_blob(); ++ if (fdt != NULL) { ++ pwr_node = dt_get_pwr_node(fdt); ++ } ++ if (pwr_node >= 0) { ++ cuint = fdt_getprop(fdt, pwr_node, SYSTEM_OFF_MODE, NULL); ++ } ++ if ((fdt == NULL) || (pwr_node < 0) || (cuint == NULL)) { ++ IMSG("No power configuration found in DT"); ++ return TEE_SUCCESS; ++ } ++ ++ system_off_mode = fdt32_to_cpu(*cuint); ++ ++ /* Initialize suspend support to the deepest possible mode */ ++ deepest_suspend_mode = STM32_PM_CSTOP_ALLOW_STANDBY_DDR_SR; ++ ++ save_supported_mode(fdt, pwr_node); ++ ++ DMSG("Power configuration: shutdown to %u, suspend to %u", ++ stm32mp1_get_lp_soc_mode(PSCI_MODE_SYSTEM_OFF), ++ stm32mp1_get_lp_soc_mode(PSCI_MODE_SYSTEM_SUSPEND)); ++ ++ return TEE_SUCCESS; ++} ++service_init(stm32mp1_init_lp_states); ++#endif +diff --git a/core/arch/arm/plat-stm32mp1/pm/psci.c b/core/arch/arm/plat-stm32mp1/pm/psci.c +new file mode 100644 +index 0000000..6e8219e +--- /dev/null ++++ b/core/arch/arm/plat-stm32mp1/pm/psci.c +@@ -0,0 +1,427 @@ ++// SPDX-License-Identifier: BSD-2-Clause ++/* ++ * Copyright (c) 2017-2018, STMicroelectronics ++ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "context.h" ++#include "power.h" ++ ++/* ++ * SMP boot support and access to the mailbox ++ */ ++#define CORE_OFF 0 ++#define CORE_AWAKE 1 ++#define CORE_RET 2 ++#define CORE_ON 3 ++ ++static int core_state[CFG_TEE_CORE_NB_CORE]; ++static unsigned int __maybe_unused state_lock = SPINLOCK_UNLOCK; ++ ++static uint32_t __maybe_unused lock_state_access(void) ++{ ++ return may_spin_lock(&state_lock); ++} ++ ++static void __maybe_unused unlock_state_access(uint32_t exceptions) ++{ ++ may_spin_unlock(&state_lock, exceptions); ++} ++ ++int psci_affinity_info(uint32_t affinity, uint32_t lowest_affinity_level) ++{ ++ unsigned int pos = get_core_pos_mpidr(affinity); ++ ++ DMSG("core %zu, state %u", pos, core_state[pos]); ++ ++ if ((pos >= CFG_TEE_CORE_NB_CORE) || ++ (lowest_affinity_level > PSCI_AFFINITY_LEVEL_ON)) { ++ return PSCI_RET_INVALID_PARAMETERS; ++ } ++ ++ switch (core_state[pos]) { ++ case CORE_OFF: ++ case CORE_RET: ++ return PSCI_AFFINITY_LEVEL_OFF; ++ case CORE_AWAKE: ++ return PSCI_AFFINITY_LEVEL_ON_PENDING; ++ case CORE_ON: ++ return PSCI_AFFINITY_LEVEL_ON; ++ default: ++ panic(); ++ } ++} ++ ++#if CFG_TEE_CORE_NB_CORE == 1 ++/* ++ * Function called when a CPU is booted through the OP-TEE. ++ * All cores shall register when online. ++ */ ++void stm32mp_register_online_cpu(void) ++{ ++ assert((core_state[0] == CORE_OFF) || ++ (core_state[0] == CORE_RET)); ++ core_state[0] = CORE_ON; ++} ++#else ++void stm32mp_register_online_cpu(void) ++{ ++ size_t pos = get_core_pos(); ++ uint32_t excep = lock_state_access(); ++ ++ if (pos == 0) { ++ assert((core_state[pos] == CORE_OFF) || ++ (core_state[pos] == CORE_RET)); ++ } else { ++ if (core_state[pos] != CORE_AWAKE) { ++ core_state[pos] = CORE_OFF; ++ unlock_state_access(excep); ++ stm32_pm_cpu_power_down_wfi(); ++ /* No return */ ++ } ++ } ++ ++ core_state[pos] = CORE_ON; ++ unlock_state_access(excep); ++} ++ ++#define GICD_SGIR 0xF00 ++static void raise_sgi0_as_secure(void) ++{ ++ dsb_ishst(); ++ write32(GIC_NON_SEC_SGI_0 | SHIFT_U32(TARGET_CPU1_GIC_MASK, 16), ++ get_gicd_base() + GICD_SGIR); ++} ++ ++static void release_secondary_early_hpen(size_t pos __unused) ++{ ++ /* Need to send SIG#0 over Group0 after individual core 1 reset */ ++ raise_sgi0_as_secure(); ++ udelay(20); ++ ++ stm32_clock_enable(RTCAPB); ++ ++ write32(TEE_LOAD_ADDR, ++ stm32mp_bkpreg(BCKR_CORE1_BRANCH_ADDRESS)); ++ write32(BOOT_API_A7_CORE1_MAGIC_NUMBER, ++ stm32mp_bkpreg(BCKR_CORE1_MAGIC_NUMBER)); ++ ++ stm32_clock_disable(RTCAPB); ++ ++ dsb_ishst(); ++ itr_raise_sgi(GIC_SEC_SGI_0, TARGET_CPU1_GIC_MASK); ++} ++ ++/* Override default psci_cpu_on() with platform specific sequence */ ++int psci_cpu_on(uint32_t core_id, uint32_t entry, uint32_t context_id) ++{ ++ size_t pos = get_core_pos_mpidr(core_id); ++ uint32_t excep; ++ int rc; ++ ++ if (!pos || pos >= CFG_TEE_CORE_NB_CORE) ++ return PSCI_RET_INVALID_PARAMETERS; ++ ++ DMSG("core %zu, ns_entry 0x%" PRIx32 ", state %u", ++ pos, entry, core_state[pos]); ++ ++ excep = lock_state_access(); ++ ++ switch (core_state[pos]) { ++ case CORE_ON: ++ rc = PSCI_RET_ALREADY_ON; ++ break; ++ case CORE_AWAKE: ++ rc = PSCI_RET_ON_PENDING; ++ break; ++ case CORE_RET: ++ rc = PSCI_RET_DENIED; ++ break; ++ case CORE_OFF: ++ core_state[pos] = CORE_AWAKE; ++ rc = PSCI_RET_SUCCESS; ++ break; ++ default: ++ panic(); ++ } ++ ++ unlock_state_access(excep); ++ ++ if (rc == PSCI_RET_SUCCESS) { ++ generic_boot_set_core_ns_entry(pos, entry, context_id); ++ release_secondary_early_hpen(pos); ++ } ++ ++ return rc; ++} ++ ++/* Override default psci_cpu_off() with platform specific sequence */ ++int psci_cpu_off(void) ++{ ++ unsigned int pos = get_core_pos(); ++ uint32_t excep; ++ ++ if (pos == 0) { ++ EMSG("PSCI_CPU_OFF not supported for core0, use system_off"); ++ return PSCI_RET_INTERNAL_FAILURE; ++ } ++ ++ DMSG("core %u", pos); ++ ++ excep = lock_state_access(); ++ ++ assert(core_state[pos] == CORE_ON); ++ core_state[pos] = CORE_OFF; ++ ++ unlock_state_access(excep); ++ ++ /* Enable BKPREG access for the disabled CPU */ ++ stm32_clock_enable(RTCAPB); ++ ++ thread_mask_exceptions(THREAD_EXCP_ALL); ++ stm32_pm_cpu_power_down_wfi(); ++ panic(); ++} ++#endif ++ ++static int enter_cstop_suspend(unsigned int soc_mode) ++{ ++ int rc = 1; ++ ++ if (read_isr() != 0) { ++ return rc; ++ } ++ ++ if (stm32_enter_cstop(soc_mode)) { ++ goto resume; ++ } ++ ++ if (need_to_backup_cpu_context(soc_mode)) { ++ stm32_pm_cpu_power_down_wfi(); ++ } else { ++ stm32_pm_cpu_wfi(); ++ rc = 0; ++ } ++ ++resume: ++ stm32_exit_cstop(); ++ ++ return rc; ++} ++ ++static int plat_suspend(uint32_t arg) ++{ ++ unsigned int soc_mode = arg; ++ size_t pos = get_core_pos(); ++ int rc = 1; ++ ++ if (read_isr() != 0) { ++ return rc; ++ } ++ ++ /* No need to lock state access as CPU is alone when here */ ++ assert(core_state[pos] == CORE_ON); ++ core_state[pos] = CORE_RET; ++ ++ stm32mp_pm_save_context(soc_mode); ++ ++ rc = enter_cstop_suspend(soc_mode); ++ ++ stm32mp_pm_restore_context(soc_mode); ++ stm32mp_pm_wipe_context(); ++ ++ assert(core_state[pos] == CORE_RET); ++ core_state[pos] = CORE_ON; ++ ++ return rc; ++} ++ ++static void plat_resume(uint32_t arg) ++{ ++ unsigned int soc_mode = arg; ++ ++ plat_cpu_reset_late(); ++ main_init_gic(); ++ ++ assert(core_state[get_core_pos()] == CORE_ON); ++ ++ stm32mp_pm_restore_context(soc_mode); ++} ++ ++#if !defined(CFG_STM32_RNG) ++static bool plat_can_suspend(void) ++{ ++ /* RNG is mandated for suspending TEE RAM content */ ++ return false; ++} ++#else ++#if CFG_TEE_CORE_NB_CORE == 1 ++static bool plat_can_suspend(void) ++{ ++ return true; ++} ++#else /*CFG_TEE_CORE_NB_CORE==1*/ ++static bool plat_can_suspend(void) ++{ ++ size_t pos = get_core_pos(); ++ size_t n; ++ uint32_t excep; ++ bool rc = true; ++ ++ excep = lock_state_access(); ++ ++ for (n = 0; n < ARRAY_SIZE(core_state); n++) { ++ if (n == pos) { ++ continue; ++ } ++ if (core_state[n] == CORE_AWAKE) { ++ /* State core as lost and proceed suspend */ ++ core_state[n] = CORE_OFF; ++ } ++ if (core_state[n] != CORE_OFF) { ++ rc = false; ++ } ++ } ++ ++ unlock_state_access(excep); ++ ++ return rc; ++} ++#endif /*CFG_TEE_CORE_NB_CORE==1*/ ++#endif /*CFG_STM32_RNG*/ ++ ++/* Override default psci_system_suspend() with platform specific sequence */ ++int psci_system_suspend(uintptr_t entry, uint32_t context_id __unused, ++ struct sm_nsec_ctx *nsec) ++{ ++ int ret = PSCI_RET_INVALID_PARAMETERS; ++ uint32_t soc_mode; ++ int pos = get_core_pos(); ++ ++ DMSG("core %u", pos); ++ ++ if (!plat_can_suspend()) { ++ return PSCI_RET_DENIED; ++ } ++ ++ soc_mode = stm32mp1_get_lp_soc_mode(PSCI_MODE_SYSTEM_SUSPEND); ++ ++ switch (soc_mode) { ++ case STM32_PM_CSLEEP_RUN: ++ stm32_enter_csleep(); ++ nsec->mon_lr = (uint32_t)entry; ++ return PSCI_RET_SUCCESS; ++ case STM32_PM_SHUTDOWN: ++ stm32_enter_cstop_shutdown(soc_mode); ++ panic(); ++ default: ++ /* Others are suspended mode: at least some context to backup */ ++ break; ++ } ++ ++ assert(cpu_mmu_enabled() && core_state[pos] == CORE_ON); ++ ++ if (need_to_backup_cpu_context(soc_mode)) { ++ sm_save_unbanked_regs(&nsec->ub_regs); ++ /* ++ * sm_pm_cpu_suspend(arg, func) saves the CPU core context in TEE RAM ++ * then calls func(arg) to run the platform lower power sequence. ++ * ++ * If platform fails to suspend, sm_pm_cpu_suspend() returns with a ++ * non null return code. When sm_pm_cpu_suspend() returns 0 platform ++ * context must be restored. ++ */ ++ ret = sm_pm_cpu_suspend((uint32_t)soc_mode, plat_suspend); ++ if (ret == 0) { ++ plat_resume((uint32_t)soc_mode); ++ sm_restore_unbanked_regs(&nsec->ub_regs); ++ } ++ } else { ++ ret = plat_suspend((uint32_t)soc_mode); ++ } ++ ++ if (ret == 0) { ++ nsec->mon_lr = (uint32_t)entry; ++ IMSG("Resumed"); ++ return PSCI_RET_SUCCESS; ++ } ++ ++ return PSCI_RET_INTERNAL_FAILURE; ++} ++ ++/* Override default psci_system_off() with platform specific sequence */ ++void __noreturn psci_system_off(void) ++{ ++ uint32_t soc_mode = stm32mp1_get_lp_soc_mode(PSCI_MODE_SYSTEM_OFF); ++ ++ DMSG("core %u", get_core_pos()); ++ ++ stm32_enter_cstop_shutdown(soc_mode); ++} ++ ++/* Override default psci_system_reset() with platform specific sequence */ ++void __noreturn psci_system_reset(void) ++{ ++ uint32_t soc_mode = stm32mp1_get_lp_soc_mode(PSCI_MODE_SYSTEM_OFF); ++ ++ DMSG("core %u", get_core_pos()); ++ ++ stm32_enter_cstop_reset(soc_mode); ++} ++ ++void __noreturn stm32mp_platform_reset(int __unused cpu) ++{ ++ psci_system_reset(); ++} ++ ++/* Override default psci_cpu_on() with platform supported features */ ++int psci_features(uint32_t psci_fid) ++{ ++ switch (psci_fid) { ++ case PSCI_PSCI_FEATURES: ++ case PSCI_VERSION: ++#if CFG_TEE_CORE_NB_CORE > 1 ++ case PSCI_CPU_ON: ++ case PSCI_CPU_OFF: ++#endif ++ case PSCI_SYSTEM_SUSPEND: ++ case PSCI_SYSTEM_RESET: ++ case PSCI_SYSTEM_OFF: ++ return PSCI_RET_SUCCESS; ++ default: ++ return PSCI_RET_NOT_SUPPORTED; ++ } ++} ++ ++/* Override default psci_version() to enable PSCI_VERSION_1_0 API */ ++uint32_t psci_version(void) ++{ ++ return PSCI_VERSION_1_0; ++} ++ +diff --git a/core/arch/arm/plat-stm32mp1/pm/sub.mk b/core/arch/arm/plat-stm32mp1/pm/sub.mk +new file mode 100644 +index 0000000..d8930a4 +--- /dev/null ++++ b/core/arch/arm/plat-stm32mp1/pm/sub.mk +@@ -0,0 +1,7 @@ ++asm-defines-y += context_asm_defines.c ++ ++srcs-y += context.c ++srcs-y += low_power.c ++srcs-y += pm_helpers.S ++srcs-y += power_config.c ++srcs-$(CFG_PSCI_ARM32) += psci.c +diff --git a/core/arch/arm/plat-stm32mp1/reset.S b/core/arch/arm/plat-stm32mp1/reset.S +index 69ab151..abf8b9a 100644 +--- a/core/arch/arm/plat-stm32mp1/reset.S ++++ b/core/arch/arm/plat-stm32mp1/reset.S +@@ -23,8 +23,34 @@ UNWIND( .fnstart) + mov_imm r1, STM32MP1_NSACR_PRESERVE_MASK + and r0, r0, r1 + write_nsacr r0 ++ isb ++ ++ read_actlr r0 ++ orr r0, r0, #ACTLR_SMP ++ write_actlr r0 ++ ++ /* ++ * Always reset CNTVOFF for the dear non secure world. ++ * This operation requires being in Monitor mode and ++ * non secure state. ++ */ ++ mrs r1, cpsr ++ cps #CPSR_MODE_MON ++ isb ++ ++ read_scr r2 ++ orr r0, r2, #SCR_NS ++ write_scr r0 ++ isb ++ ++ mov r0, #0 ++ write_cntvoff r0, r0 + ++ write_scr r2 + isb +- bx lr ++ msr cpsr, r1 ++ isb ++ ++ bx lr + UNWIND( .fnend) + END_FUNC plat_cpu_reset_early +diff --git a/core/arch/arm/plat-stm32mp1/scripts/stm32image.py b/core/arch/arm/plat-stm32mp1/scripts/stm32image.py +index 55363af..2def5b8 100755 +--- a/core/arch/arm/plat-stm32mp1/scripts/stm32image.py ++++ b/core/arch/arm/plat-stm32mp1/scripts/stm32image.py +@@ -1,4 +1,4 @@ +-#!/usr/bin/env python3 ++#!/usr/bin/env python + # SPDX-License-Identifier: BSD-2-Clause + # + # Copyright (c) 2017-2018, STMicroelectronics +@@ -35,7 +35,7 @@ def stm32image_checksum(dest_fd, sizedest): + return csum + + +-def stm32image_set_header(dest_fd, load, entry): ++def stm32image_set_header(dest_fd, load, entry, bintype): + sizedest = get_size(dest_fd) + + checksum = stm32image_checksum(dest_fd, sizedest) +@@ -68,11 +68,12 @@ def stm32image_set_header(dest_fd, load, entry): + dest_fd.write(b'\x00' * 64) + + # Padding +- dest_fd.write(b'\x00' * 84) ++ dest_fd.write(b'\x00' * 83) ++ dest_fd.write(struct.pack(' ++#include "bsec_svc.h" ++#include "stm32mp1_smc.h" ++ ++uint32_t bsec_main(uint32_t x1, uint32_t x2, uint32_t x3, uint32_t *out) ++{ ++ int result; ++ uint32_t tmp; ++ ++ if (bsec_check_nsec_access_rights(x2) != BSEC_OK) { ++ return BSEC_ERROR; ++ } ++ ++ switch (x1) { ++ case STM32_SIP_BSEC_READ_SHADOW: ++ result = bsec_read_otp(out, x2); ++ FMSG("read shadow @%" PRIx32 " = %" PRIx32, x2, *out); ++ break; ++ case STM32_SIP_BSEC_PROG_OTP: ++ FMSG("program @%" PRIx32, x2); ++ result = bsec_program_otp(x3, x2); ++ break; ++ case STM32_SIP_BSEC_WRITE_SHADOW: ++ FMSG("write shadow @%" PRIx32, x2); ++ result = bsec_write_otp(x3, x2); ++ break; ++ case STM32_SIP_BSEC_READ_OTP: ++ result = bsec_read_otp(&tmp, x2); ++ if (result != BSEC_OK) { ++ break; ++ } ++ ++ result = bsec_shadow_register(x2); ++ if (result != BSEC_OK) { ++ break; ++ } ++ ++ result = bsec_read_otp(out, x2); ++ if (result != BSEC_OK) { ++ break; ++ } ++ ++ result = bsec_write_otp(tmp, x2); ++ FMSG("read @%" PRIx32 " = %" PRIx32, x2, *out); ++ break; ++ default: ++ EMSG("Invalid %" PRIx32, x1); ++ result = BSEC_ERROR; ++ break; ++ } ++ ++ switch (result) { ++ case BSEC_OK: ++ return STM32_SIP_OK; ++ case BSEC_INVALID_PARAM: ++ return STM32_SIP_INVALID_PARAMS; ++ default: ++ return STM32_SIP_FAILED; ++ } ++} +diff --git a/core/arch/arm/plat-stm32mp1/service/bsec_svc.h b/core/arch/arm/plat-stm32mp1/service/bsec_svc.h +new file mode 100644 +index 0000000..4f1babe +--- /dev/null ++++ b/core/arch/arm/plat-stm32mp1/service/bsec_svc.h +@@ -0,0 +1,14 @@ ++/* SPDX-License-Identifier: BSD-3-Clause */ ++/* ++ * Copyright (c) 2016-2018, STMicroelectronics ++ */ ++ ++#ifndef __STM32MP1_BSEC_SVC_H__ ++#define __STM32MP1_BSEC_SVC_H__ ++ ++#include ++ ++uint32_t bsec_main(uint32_t x1, uint32_t x2, uint32_t x3, ++ uint32_t *ret_otp_value); ++ ++#endif /*__STM32MP1_BSEC_SVC_H__*/ +diff --git a/core/arch/arm/plat-stm32mp1/service/low_power_svc.c b/core/arch/arm/plat-stm32mp1/service/low_power_svc.c +new file mode 100644 +index 0000000..626f390 +--- /dev/null ++++ b/core/arch/arm/plat-stm32mp1/service/low_power_svc.c +@@ -0,0 +1,153 @@ ++// SPDX-License-Identifier: BSD-3-Clause ++/* ++ * Copyright (c) 2017-2018, STMicroelectronics - All Rights Reserved ++ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "stm32mp1_smc.h" ++#include "low_power_svc.h" ++#include "../pm/power.h" ++#include "../pm/context.h" ++ ++ ++#undef DDR_SR_TEST ++ ++#ifdef DDR_SR_TEST ++uint32_t sr_mode_scv_handler(uint32_t __maybe_unused x1, uint32_t x2) ++{ ++ unsigned int mode = x2; ++ ++ DMSG("DDR selfrefresh mode 0x%" PRIx32 ", 0x%" PRIx32, mode, x1); ++ ++ switch (mode) { ++ case STM32_SIP_SR_MODE_SSR: ++ ddr_sr_mode_ssr(); ++ break; ++ case STM32_SIP_SR_MODE_ASR: ++ ddr_sr_mode_asr(); ++ break; ++ case STM32_SIP_SR_MODE_HSR: ++ ddr_sr_mode_hsr(); ++ break; ++ default: ++ return STM32_SIP_INVALID_PARAMS; ++ } ++ ++ return STM32_SIP_OK; ++} ++#else ++uint32_t sr_mode_scv_handler(uint32_t __unused x1, uint32_t __unused x2) ++{ ++ return STM32_SIP_NOT_SUPPORTED; ++} ++#endif ++ ++uint32_t cstop_scv_handler(struct sm_ctx __unused *ctx, uint32_t __unused x1, ++ uint32_t __unused x2, uint32_t __unused x3) ++{ ++ DMSG("core %u", get_core_pos()); ++ ++ stm32mp1_set_lp_deepest_soc_mode(PSCI_MODE_SYSTEM_SUSPEND, ++ STM32_PM_CSTOP_ALLOW_LPLV_STOP); ++ ++ return (psci_system_suspend(ctx->nsec.mon_lr, 0, &ctx->nsec) == 0) ? ++ STM32_SIP_OK : STM32_SIP_FAILED; ++} ++ ++uint32_t standby_scv_handler(struct sm_ctx *ctx, uint32_t __unused x1, ++ uint32_t __unused x2, uint32_t x3) ++{ ++ uint32_t nsec_resume_ep = x3; ++ ++ DMSG("core %u", get_core_pos()); ++ ++ if (nsec_resume_ep == 0U) { ++ shutdown_scv_handler(); ++ panic(); ++ } ++ ++ stm32mp1_set_lp_deepest_soc_mode(PSCI_MODE_SYSTEM_SUSPEND, ++ STM32_PM_CSTOP_ALLOW_STANDBY_DDR_SR); ++ ++ return (psci_system_suspend(nsec_resume_ep, 0, &ctx->nsec) == 0) ? ++ STM32_SIP_OK : STM32_SIP_FAILED; ++} ++ ++uint32_t shutdown_scv_handler(void) ++{ ++ DMSG("core %u", get_core_pos()); ++ ++ if (!stm32mp_with_pmic()) { ++ return STM32_SIP_NOT_SUPPORTED; ++ } ++ ++ psci_system_off(); ++ panic(); ++} ++ ++uint32_t pm_domain_scv_handler(uint32_t id, uint32_t enable) ++{ ++ unsigned int pd = id; ++ ++ DMSG("%sable PD %u", enable != 0 ? "En" : "Dis", pd); ++ ++ switch (pd) { ++ case STM32MP1_PD_VSW: ++ case STM32MP1_PD_CORE_RET: ++ case STM32MP1_PD_CORE: ++ break; ++ default: ++ return STM32_SIP_INVALID_PARAMS; ++ } ++ ++ stm32mp1_set_pm_domain_state(pd, enable); ++ ++ return STM32_SIP_OK; ++} ++ ++#ifdef CFG_TEE_CORE_DEBUG ++uint32_t pm_set_lp_state_scv_handler(uint32_t request, uint32_t state) ++{ ++ uint32_t power_mode; ++ ++ switch (request) { ++ case STM32_OEM_LP_FORCE_SUSPEND_PARAMS: ++ DMSG("Set suspend mode to %u", state); ++ power_mode = PSCI_MODE_SYSTEM_SUSPEND; ++ break; ++ case STM32_OEM_LP_FORCE_OFF_PARAMS: ++ DMSG("Set off mode to %u", state); ++ power_mode = PSCI_MODE_SYSTEM_OFF; ++ break; ++ default: ++ return STM32_OEM_INVALID_PARAMS; ++ } ++ ++ if (stm32mp1_set_lp_deepest_soc_mode(power_mode, state) < 0) { ++ return STM32_OEM_FAILED; ++ } ++ ++ return STM32_OEM_OK; ++} ++#else ++uint32_t pm_set_lp_state_scv_handler(uint32_t __unused mode, ++ uint32_t __unused state) ++{ ++ return STM32_SIP_NOT_SUPPORTED; ++} ++#endif +diff --git a/core/arch/arm/plat-stm32mp1/service/low_power_svc.h b/core/arch/arm/plat-stm32mp1/service/low_power_svc.h +new file mode 100644 +index 0000000..5681ea2 +--- /dev/null ++++ b/core/arch/arm/plat-stm32mp1/service/low_power_svc.h +@@ -0,0 +1,22 @@ ++/* SPDX-License-Identifier: BSD-3-Clause */ ++/* ++ * Copyright (c) 2018, STMicroelectronics ++ */ ++ ++#ifndef LOW_POWER_SVC_H ++#define LOW_POWER_SVC_H ++ ++#include ++#include ++ ++uint32_t sr_mode_scv_handler(uint32_t x1, uint32_t x2); ++uint32_t cstop_scv_handler(struct sm_ctx *nsec, ++ uint32_t x1, uint32_t x2, uint32_t x3); ++uint32_t standby_scv_handler(struct sm_ctx *nsec, ++ uint32_t x1, uint32_t x2, uint32_t x3); ++uint32_t shutdown_scv_handler(void); ++uint32_t pm_domain_scv_handler(uint32_t x1, uint32_t x2); ++ ++uint32_t pm_set_lp_state_scv_handler(uint32_t x1, uint32_t x2); ++ ++#endif /* LOW_POWER_SVC_H */ +diff --git a/core/arch/arm/plat-stm32mp1/service/pwr_svc.c b/core/arch/arm/plat-stm32mp1/service/pwr_svc.c +new file mode 100644 +index 0000000..9c314b2 +--- /dev/null ++++ b/core/arch/arm/plat-stm32mp1/service/pwr_svc.c +@@ -0,0 +1,117 @@ ++// SPDX-License-Identifier: BSD-3-Clause ++/* ++ * Copyright (c) 2017-2018, STMicroelectronics ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "pwr_svc.h" ++#include "stm32mp1_smc.h" ++ ++struct pwr_reg_prop { ++ uint32_t offset; ++ uint32_t mask; ++}; ++ ++#define PWR_ALLOWED_MASK(_off, _mask) { .offset = (_off), .mask = (_mask), } ++ ++static const struct pwr_reg_prop allowed_regs[] = { ++ PWR_ALLOWED_MASK(PWR_CR3_OFF, PWR_CR3_VBE | PWR_CR3_VBRS | ++ PWR_CR3_USB33DEN | ++ PWR_CR3_REG18EN | PWR_CR3_REG11EN), ++ PWR_ALLOWED_MASK(PWR_WKUPCR_OFF, PWR_WKUPCR_MASK), ++ PWR_ALLOWED_MASK(PWR_MPUWKUPENR_OFF, PWR_MPUWKUPENR_MASK), ++}; ++ ++static unsigned int lock = SPINLOCK_UNLOCK; ++ ++static uint32_t pwr_regs_lock(void) ++{ ++ return may_spin_lock(&lock); ++} ++ ++static void pwr_regs_unlock(uint32_t exceptions) ++{ ++ may_spin_unlock(&lock, exceptions); ++} ++ ++uint32_t pwr_scv_handler(uint32_t x1, uint32_t x2, uint32_t x3) ++{ ++ uint32_t req = x1; ++ uint32_t offset = x2; ++ uint32_t value = x3; ++ uint32_t va; ++ uint32_t allowed; ++ uint32_t i; ++ uint32_t ret; ++ uint32_t exc; ++ ++ /* ++ * Argument x2 can be either the register physical address of the ++ * register offset toward PWR_BASE. ++ */ ++ if ((offset & ~PWR_OFFSET_MASK) != 0) { ++ if ((offset & ~PWR_OFFSET_MASK) != PWR_BASE) { ++ return STM32_SIP_INVALID_PARAMS; ++ } ++ ++ offset &= PWR_OFFSET_MASK; ++ } ++ ++ DMSG_RAW("PWR service: %s 0x%" PRIx32 " at offset 0x%" PRIx32, ++ req == STM32_SIP_REG_WRITE ? "write" : ++ req == STM32_SIP_REG_SET ? "set" : "clear", ++ value, offset); ++ ++ exc = pwr_regs_lock(); ++ ++ for (i = 0; i < ARRAY_SIZE(allowed_regs); i++) { ++ if (offset != allowed_regs[i].offset) { ++ continue; ++ } ++ ++ va = stm32_pwr_base() + offset; ++ allowed = allowed_regs[i].mask; ++ value &= allowed; ++ ++ switch (req) { ++ case STM32_SIP_REG_WRITE: ++ io_mask32_stm32shregs(va, value, allowed); ++ FMSG("wrt off %" PRIx32 "=%" PRIx32 " => %" PRIx32, ++ offset, value, read32(va)); ++ ret = STM32_SIP_OK; ++ break; ++ case STM32_SIP_REG_SET: ++ io_mask32_stm32shregs(va, value, value); ++ FMSG("set off %" PRIx32 "=%" PRIx32 " => %" PRIx32, ++ offset, value, read32(va)); ++ ret = STM32_SIP_OK; ++ break; ++ case STM32_SIP_REG_CLEAR: ++ io_mask32_stm32shregs(va, 0, value); ++ FMSG("clr off %" PRIx32 "=%" PRIx32 " => %" PRIx32, ++ offset, value, read32(va)); ++ ret = STM32_SIP_OK; ++ break; ++ default: ++ ret = STM32_SIP_INVALID_PARAMS; ++ } ++ ++ pwr_regs_unlock(exc); ++ ++ return ret; ++ } ++ ++ pwr_regs_unlock(exc); ++ ++ return STM32_SIP_INVALID_PARAMS; ++} +diff --git a/core/arch/arm/plat-stm32mp1/service/pwr_svc.h b/core/arch/arm/plat-stm32mp1/service/pwr_svc.h +new file mode 100644 +index 0000000..011cac4 +--- /dev/null ++++ b/core/arch/arm/plat-stm32mp1/service/pwr_svc.h +@@ -0,0 +1,11 @@ ++/* SPDX-License-Identifier: BSD-3-Clause */ ++/* ++ * Copyright (c) 2017-2018, STMicroelectronics ++ */ ++ ++#ifndef __PWR_SVC_H__ ++#define __PWR_SVC_H__ ++ ++uint32_t pwr_scv_handler(uint32_t x1, uint32_t x2, uint32_t x3); ++ ++#endif /* __PWR_SVC_H__*/ +diff --git a/core/arch/arm/plat-stm32mp1/service/rcc_svc.c b/core/arch/arm/plat-stm32mp1/service/rcc_svc.c +new file mode 100644 +index 0000000..7bdaea8 +--- /dev/null ++++ b/core/arch/arm/plat-stm32mp1/service/rcc_svc.c +@@ -0,0 +1,440 @@ ++// SPDX-License-Identifier: BSD-3-Clause ++/* ++ * Copyright (c) 2017-2018, STMicroelectronics ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "rcc_svc.h" ++#include "stm32mp1_smc.h" ++ ++#define STD_REG 0 ++#define SET_REG 1 ++#define CLR_REG 2 ++ ++static void shared_clk_request(uint32_t request, ++ uint32_t offset, uint32_t value) ++{ ++ unsigned int id; ++ unsigned int bit; ++ uint32_t enable_bits = 0; ++ int clr_std_set = STD_REG; ++ ++ switch (request) { ++ case STM32_SIP_REG_WRITE: ++ case STM32_SIP_REG_SET: ++ case STM32_SIP_REG_CLEAR: ++ break; ++ default: ++ return; ++ } ++ ++ switch (offset) { ++ case RCC_MP_APB5ENSETR: ++ clr_std_set = SET_REG; ++ /* Non secure backup registers requires RTCAPB clock */ ++ enable_bits |= RCC_MP_APB5ENSETR_RTCAPBEN; ++ break; ++ case RCC_MP_APB5ENCLRR: ++ clr_std_set = CLR_REG; ++ /* Non secure backup registers requires RTCAPB clock */ ++ enable_bits |= RCC_MP_APB5ENSETR_RTCAPBEN; ++ break; ++ ++ case RCC_MP_AHB5ENSETR: ++ clr_std_set = SET_REG; ++ if (stm32mp_gpio_bank_is_shared(GPIO_BANK_Z)) { ++ enable_bits |= RCC_MP_AHB5ENSETR_GPIOZEN; ++ } ++ break; ++ case RCC_MP_AHB5ENCLRR: ++ clr_std_set = CLR_REG; ++ if (stm32mp_gpio_bank_is_shared(GPIO_BANK_Z)) { ++ enable_bits |= RCC_MP_AHB5ENSETR_GPIOZEN; ++ } ++ break; ++ default: ++ return; ++ } ++ ++ if ((clr_std_set != STD_REG) && (request == STM32_SIP_REG_CLEAR)) ++ return; ++ ++ /* ++ * Parse bit that relate to a functional clock. ++ * Call stm32mp1_clk_enable/disable_non_secure() for that clock ++ * according to request (write/set/clear) and target register ++ * (write or set/clear). ++ */ ++ for (bit = 0; enable_bits && bit < 32; bit++) { ++ ++ if (!(BIT(bit) & enable_bits)) ++ continue; ++ ++ id = stm32mp1_clk_rcc2id(offset, bit); ++ if (id == ~0U) ++ panic(); ++ ++ switch (clr_std_set) { ++ case SET_REG: ++ if (BIT(bit) & value) { ++ DMSG("Enable non-secure clock %u", id); ++ stm32mp1_clk_enable_non_secure(id); ++ } ++ break; ++ case CLR_REG: ++ if (BIT(bit) & value) { ++ DMSG("Disable non-secure clock %u", id); ++ stm32mp1_clk_disable_non_secure(id); ++ } ++ break; ++ default: ++ /* Standard registers case */ ++ switch (request) { ++ case STM32_SIP_REG_WRITE: ++ if (BIT(bit) & value) { ++ DMSG("Enable non-secure clock %u", id); ++ stm32mp1_clk_enable_non_secure(id); ++ } else { ++ DMSG("Disable non-secure clock %u", id); ++ stm32mp1_clk_disable_non_secure(id); ++ } ++ break; ++ case STM32_SIP_REG_SET: ++ if (BIT(bit) & value) { ++ DMSG("Enable non-secure clock %u", id); ++ stm32mp1_clk_enable_non_secure(id); ++ } ++ break; ++ case STM32_SIP_REG_CLEAR: ++ if (BIT(bit) & value) { ++ DMSG("Disable non-secure clock %u", id); ++ stm32mp1_clk_disable_non_secure(id); ++ } ++ break; ++ default: ++ return; ++ } ++ break; ++ } ++ ++ enable_bits &= ~BIT(bit); ++ } ++} ++ ++static bool offset_is_clear_register(uint32_t offset) ++{ ++ switch (offset) { ++ case RCC_OCENCLRR: ++ case RCC_MP_SREQCLRR: ++ case RCC_APB5RSTCLRR: ++ case RCC_AHB5RSTCLRR: ++ case RCC_MP_APB5ENCLRR: ++ case RCC_MP_AHB5ENCLRR: ++ case RCC_MP_APB5LPENCLRR: ++ case RCC_MP_AHB5LPENCLRR: ++ case RCC_MP_IWDGFZCLRR: ++ return true; ++ default: ++ return false; ++ } ++} ++ ++static void access_allowed_mask(uint32_t request, uint32_t offset, ++ uint32_t value, uint32_t allowed_mask) ++{ ++ uint32_t va = stm32_rcc_base() + offset; ++ ++ switch (request) { ++ case STM32_SIP_REG_WRITE: ++ if (offset_is_clear_register(offset)) { ++ /* CLR registers show the SET state, not the CLR state */ ++ write32(value & allowed_mask, va); ++ } else { ++ io_mask32_stm32shregs(va, value, allowed_mask); ++ } ++ FMSG("wrt 0x%" PRIx32 "=0x%" PRIx32 " => 0x%" PRIx32, ++ offset, value, read32(va)); ++ break; ++ ++ case STM32_SIP_REG_SET: ++ if (offset_is_clear_register(offset)) { ++ /* CLR registers show the SET state, not the CLR state */ ++ write32(value & allowed_mask, va); ++ } else { ++ io_mask32_stm32shregs(va, value, value & allowed_mask); ++ } ++ FMSG("set 0x%" PRIx32 "=0x%" PRIx32 " => 0x%" PRIx32, ++ offset, value, read32(va)); ++ break; ++ ++ case STM32_SIP_REG_CLEAR: ++ if (offset_is_clear_register(offset)) { ++ /* Nothing to do on CLR registers */ ++ } else { ++ io_mask32_stm32shregs(va, 0, value & allowed_mask); ++ } ++ FMSG("clear 0x%" PRIx32 "=0x%" PRIx32 " => 0x%" PRIx32, ++ offset, value, read32(va)); ++ break; ++ ++ default: ++ break; ++ } ++} ++ ++static void raw_allowed_access_request(uint32_t request, ++ uint32_t offset, uint32_t value) ++{ ++ uint32_t allowed_mask = 0; ++ ++ /* Use UINT32_MAX if no secure restriction on register access */ ++ switch (offset) { ++ case RCC_OCENSETR: ++ case RCC_OCENCLRR: ++ if (stm32mp_periph_is_non_secure(STM32MP1_SHRES_HSI)) { ++ allowed_mask |= RCC_OCENR_HSION | RCC_OCENR_HSIKERON; ++ } ++ if (stm32mp_periph_is_non_secure(STM32MP1_SHRES_CSI)) { ++ allowed_mask |= RCC_OCENR_CSION | RCC_OCENR_CSIKERON; ++ } ++ if (stm32mp_periph_is_non_secure(STM32MP1_SHRES_HSE)) { ++ allowed_mask |= RCC_OCENR_HSEON | RCC_OCENR_HSEKERON | ++ RCC_OCENR_HSEBYP | RCC_OCENR_HSECSSON | ++ RCC_OCENR_DIGBYP; ++ } ++ break; ++ ++ case RCC_HSICFGR: ++ if (stm32mp_periph_is_non_secure(STM32MP1_SHRES_HSI)) { ++ allowed_mask = UINT32_MAX; ++ } ++ break; ++ ++ case RCC_CSICFGR: ++ if (stm32mp_periph_is_non_secure(STM32MP1_SHRES_CSI)) { ++ allowed_mask = UINT32_MAX; ++ } ++ break; ++ ++ case RCC_MP_CIER: ++ case RCC_MP_CIFR: ++ /* RCC_MP_CIFR_xxxRDYF matches CIER and CIFR bit mapping */ ++ allowed_mask |= RCC_MP_CIFR_WKUPF | RCC_MP_CIFR_PLL4DYF; ++ ++ if (stm32mp_periph_is_non_secure(STM32MP1_SHRES_LSI)) { ++ allowed_mask |= RCC_MP_CIFR_LSIRDYF; ++ } ++ if (stm32mp_periph_is_non_secure(STM32MP1_SHRES_LSE)) { ++ allowed_mask |= RCC_MP_CIFR_LSERDYF; ++ } ++ if (stm32mp_periph_is_non_secure(STM32MP1_SHRES_HSI)) { ++ allowed_mask |= RCC_MP_CIFR_HSIRDYF; ++ } ++ if (stm32mp_periph_is_non_secure(STM32MP1_SHRES_HSE)) { ++ allowed_mask |= RCC_MP_CIFR_HSERDYF; ++ } ++ if (stm32mp_periph_is_non_secure(STM32MP1_SHRES_CSI)) { ++ allowed_mask |= RCC_MP_CIFR_CSIRDYF; ++ } ++ if (stm32mp_periph_is_non_secure(STM32MP1_SHRES_PLL1)) { ++ allowed_mask |= RCC_MP_CIFR_PLL1DYF; ++ } ++ if (stm32mp_periph_is_non_secure(STM32MP1_SHRES_PLL2)) { ++ allowed_mask |= RCC_MP_CIFR_PLL2DYF; ++ } ++ if (stm32mp_periph_is_non_secure(STM32MP1_SHRES_PLL3)) { ++ allowed_mask |= RCC_MP_CIFR_PLL3DYF; ++ } ++ break; ++ ++ case RCC_PLL1CR: ++ if (stm32mp_periph_is_non_secure(STM32MP1_SHRES_PLL1_P)) { ++ allowed_mask |= RCC_PLLNCR_DIVPEN; ++ } ++ if (stm32mp_periph_is_non_secure(STM32MP1_SHRES_PLL1_Q)) { ++ allowed_mask |= RCC_PLLNCR_DIVQEN; ++ } ++ if (stm32mp_periph_is_non_secure(STM32MP1_SHRES_PLL1_R)) { ++ allowed_mask |= RCC_PLLNCR_DIVREN; ++ } ++ if (stm32mp_periph_is_non_secure(STM32MP1_SHRES_PLL1)) { ++ allowed_mask |= RCC_PLLNCR_PLLON | RCC_PLLNCR_PLLRDY | ++ RCC_PLLNCR_SSCG_CTRL; ++ } ++ break; ++ ++ case RCC_PLL2CR: ++ if (stm32mp_periph_is_non_secure(STM32MP1_SHRES_PLL2_P)) { ++ allowed_mask |= RCC_PLLNCR_DIVPEN; ++ } ++ if (stm32mp_periph_is_non_secure(STM32MP1_SHRES_PLL2_Q)) { ++ allowed_mask |= RCC_PLLNCR_DIVQEN; ++ } ++ if (stm32mp_periph_is_non_secure(STM32MP1_SHRES_PLL2_R)) { ++ allowed_mask |= RCC_PLLNCR_DIVREN; ++ } ++ if (stm32mp_periph_is_non_secure(STM32MP1_SHRES_PLL2)) { ++ allowed_mask |= RCC_PLLNCR_PLLON | RCC_PLLNCR_PLLRDY | ++ RCC_PLLNCR_SSCG_CTRL; ++ } ++ break; ++ ++ case RCC_PLL3CR: ++ if (stm32mp_periph_is_non_secure(STM32MP1_SHRES_PLL3_P)) { ++ allowed_mask |= RCC_PLLNCR_DIVPEN; ++ } ++ if (stm32mp_periph_is_non_secure(STM32MP1_SHRES_PLL3_Q)) { ++ allowed_mask |= RCC_PLLNCR_DIVQEN; ++ } ++ if (stm32mp_periph_is_non_secure(STM32MP1_SHRES_PLL3_R)) { ++ allowed_mask |= RCC_PLLNCR_DIVREN; ++ } ++ if (stm32mp_periph_is_non_secure(STM32MP1_SHRES_PLL3)) { ++ allowed_mask |= RCC_PLLNCR_PLLON | RCC_PLLNCR_PLLRDY | ++ RCC_PLLNCR_SSCG_CTRL; ++ } ++ break; ++ ++ case RCC_MP_BOOTCR: /* Allowed MPU/MCU reboot cfg */ ++ case RCC_MP_GCR: /* Allowed MPU/MCU reboot cfg */ ++ case RCC_MP_GRSTCSETR: /* Allowed MCU and system reset */ ++ case RCC_BR_RSTSCLRR: /* Allowed system reset status */ ++ case RCC_MC_RSTSCLRR: /* Allowed system reset status */ ++ case RCC_MP_RSTSCLRR: /* Allowed system reset status */ ++ allowed_mask = UINT32_MAX; ++ break; ++ case RCC_APB5RSTSETR: ++ case RCC_APB5RSTCLRR: ++ case RCC_MP_APB5ENSETR: ++ case RCC_MP_APB5ENCLRR: ++ case RCC_MP_APB5LPENSETR: ++ case RCC_MP_APB5LPENCLRR: ++ /* ++ * SPI6/I2C4/I2C6/USART1/RTC/IWDG1 resources may be non secure. ++ * TZPC/TZC/BSEC/STGEN resources are secure only. ++ * Bit mask RCC_MP_APB5ENSETR_xxxEN fits EN, RST and LPEN. ++ */ ++ if (stm32mp_periph_is_non_secure(STM32MP1_SHRES_SPI6)) { ++ allowed_mask |= RCC_MP_APB5ENSETR_SPI6EN; ++ } ++ if (stm32mp_periph_is_non_secure(STM32MP1_SHRES_I2C4)) { ++ allowed_mask |= RCC_MP_APB5ENSETR_I2C4EN; ++ } ++ if (stm32mp_periph_is_non_secure(STM32MP1_SHRES_I2C6)) { ++ allowed_mask |= RCC_MP_APB5ENSETR_I2C6EN; ++ } ++ if (stm32mp_periph_is_non_secure(STM32MP1_SHRES_USART1)) { ++ allowed_mask |= RCC_MP_APB5ENSETR_USART1EN; ++ } ++ if (stm32mp_periph_is_non_secure(STM32MP1_SHRES_IWDG1)) { ++ allowed_mask |= RCC_MP_APB5ENSETR_IWDG1APBEN; ++ } ++ break; ++ case RCC_AHB5RSTSETR: ++ case RCC_AHB5RSTCLRR: ++ case RCC_MP_AHB5ENSETR: ++ case RCC_MP_AHB5ENCLRR: ++ case RCC_MP_AHB5LPENSETR: ++ case RCC_MP_AHB5LPENCLRR: ++ /* ++ * RNG1/HASH1/CRYP1/GPIOZ/AXIMC resources are accessible if related ++ * BKPSRAM resources are reserved to secure services. ++ * Bit mask RCC_MP_AHB5ENSETR_xxxEN fits EN, RST and LPEN. ++ */ ++ if (stm32mp_gpio_bank_is_non_secure(GPIO_BANK_Z)) { ++ allowed_mask |= RCC_MP_AHB5ENSETR_GPIOZEN; ++ } ++ if (stm32mp_periph_is_non_secure(STM32MP1_SHRES_CRYP1)) { ++ allowed_mask |= RCC_MP_AHB5ENSETR_CRYP1EN; ++ } ++ if (stm32mp_periph_is_non_secure(STM32MP1_SHRES_HASH1)) { ++ allowed_mask |= RCC_MP_AHB5ENSETR_HASH1EN; ++ } ++ if (stm32mp_periph_is_non_secure(STM32MP1_SHRES_RNG1)) { ++ allowed_mask |= RCC_MP_AHB5ENSETR_RNG1EN; ++ } ++ break; ++ case RCC_RTCDIVR: ++ if (stm32mp_periph_is_non_secure(STM32MP1_SHRES_RTC)) { ++ allowed_mask = UINT32_MAX; ++ } ++ break; ++ case RCC_I2C46CKSELR: ++ if (stm32mp_periph_is_non_secure(STM32MP1_SHRES_I2C4) && ++ stm32mp_periph_is_non_secure(STM32MP1_SHRES_I2C6)) { ++ allowed_mask = UINT32_MAX; ++ } ++ break; ++ case RCC_SPI6CKSELR: ++ if (stm32mp_periph_is_non_secure(STM32MP1_SHRES_SPI6)) { ++ allowed_mask = UINT32_MAX; ++ } ++ break; ++ case RCC_UART1CKSELR: ++ if (stm32mp_periph_is_non_secure(STM32MP1_SHRES_USART1)) { ++ allowed_mask = UINT32_MAX; ++ } ++ break; ++ case RCC_RNG1CKSELR: ++ if (stm32mp_periph_is_non_secure(STM32MP1_SHRES_RNG1)) { ++ allowed_mask = UINT32_MAX; ++ } ++ break; ++ case RCC_MP_IWDGFZSETR: ++ case RCC_MP_IWDGFZCLRR: ++ if (stm32mp_periph_is_non_secure(STM32MP1_SHRES_IWDG1)) { ++ allowed_mask |= RCC_MP_IWDGFZSETR_IWDG1; ++ } ++ allowed_mask |= RCC_MP_IWDGFZSETR_IWDG2; ++ break; ++ default: ++ return; ++ } ++ ++ if (allowed_mask != 0U) { ++ access_allowed_mask(request, offset, value, allowed_mask); ++ } ++} ++ ++uint32_t rcc_scv_handler(uint32_t x1, uint32_t x2, uint32_t x3) ++{ ++ uint32_t request = x1; ++ uint32_t offset = x2; ++ uint32_t value = x3; ++ ++ /* ++ * Argument x2 can be either the register physical address of the ++ * register offset toward RCC_BASE. ++ */ ++ if ((offset & ~RCC_OFFSET_MASK) != 0) { ++ if ((offset & ~RCC_OFFSET_MASK) != RCC_BASE) { ++ return STM32_SIP_INVALID_PARAMS; ++ } ++ ++ offset &= RCC_OFFSET_MASK; ++ } ++ ++ DMSG_RAW("RCC service: %s 0x%" PRIx32 " at offset 0x%" PRIx32, ++ request == STM32_SIP_REG_WRITE ? "write" : ++ request == STM32_SIP_REG_SET ? "set" : "clear", ++ value, offset); ++ ++ /* Some clocks may be managed by some secure services */ ++ shared_clk_request(request, offset, value); ++ ++ /* RCC controls for non secure resource may be accessed straight */ ++ raw_allowed_access_request(request, offset, value); ++ ++ 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 +new file mode 100644 +index 0000000..f198ebd +--- /dev/null ++++ b/core/arch/arm/plat-stm32mp1/service/rcc_svc.h +@@ -0,0 +1,11 @@ ++/* SPDX-License-Identifier: BSD-2-Clause */ ++/* ++ * Copyright (c) 2017-2018, STMicroelectronics ++ */ ++ ++#ifndef __RCC_SVC_H__ ++#define __RCC_SVC_H__ ++ ++uint32_t rcc_scv_handler(uint32_t x1, uint32_t x2, uint32_t x3); ++ ++#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 +new file mode 100644 +index 0000000..2db7b10 +--- /dev/null ++++ b/core/arch/arm/plat-stm32mp1/service/stm32mp1_smc.h +@@ -0,0 +1,211 @@ ++/* SPDX-License-Identifier: BSD-3-Clause */ ++/* ++ * Copyright (c) 2016-2018, STMicroelectronics ++ * Copyright (c) 2018, Linaro Limited ++ */ ++#ifndef __STM32MP1_SMC_H__ ++#define __STM32MP1_SMC_H__ ++ ++/* ++ * SIP Functions ++ */ ++#define STM32_SIP_SVC_VERSION_MAJOR 0x0 ++#define STM32_SIP_SVC_VERSION_MINOR 0x1 ++ ++/* SIP service generic return codes */ ++#define STM32_SIP_OK 0x0 ++#define STM32_SIP_NOT_SUPPORTED 0xffffffffU ++#define STM32_SIP_FAILED 0xfffffffeU ++#define STM32_SIP_INVALID_PARAMS 0xfffffffdU ++ ++/* ++ * SMC function IDs for STM32 Service queries ++ * STM32 SMC services use the space between 0x82000000 and 0x8200FFFF ++ * like this is defined in SMC calling Convention by ARM ++ * for SiP (silicon Partner) ++ * http://infocenter.arm.com/help/topic/com.arm.doc.den0028a/index.html ++ */ ++ ++/* ++ * SIP function STM32_SIP_FUNC_CALL_COUNT ++ * ++ * Argument a0: (input) SMCC ID ++ * (output) dummy value 0 ++ */ ++#define STM32_SIP_FUNC_CALL_COUNT 0xff00 ++ ++/* ++ * SIP function STM32_SIP_FUNC_UID ++ * ++ * Argument a0: (input) SMCC ID ++ * (output) Lowest 32bit of the stm32mp1 SIP service UUID ++ * Argument a1: (output) Next 32bit of the stm32mp1 SIP service UUID ++ * Argument a2: (output) Next 32bit of the stm32mp1 SIP service UUID ++ * Argument a3: (output) Last 32bit of the stm32mp1 SIP service UUID ++ */ ++#define STM32_SIP_FUNC_UID 0xff01 ++ ++/* ++ * SIP function STM32_SIP_FUNC_VERSION ++ * ++ * Argument a0: (input) SMCC ID ++ * (output) STM32 SIP service major ++ * Argument a1: (output) STM32 SIP service minor ++ */ ++#define STM32_SIP_FUNC_VERSION 0xff03 ++ ++/* ++ * SIP function STM32_SIP_FUNC_RCC ++ * ++ * Argument a0: (input) SMCC ID ++ * (output) status return code ++ * Argument a1: (input) Service ID (STM32_SIP_REG_xxx) ++ * Argument a2: (input) register offset or physical address ++ * (output) register read value, if applicable ++ * Argument a3: (input) register target value if applicable ++ */ ++#define STM32_SIP_FUNC_RCC 0x1000 ++ ++/* ++ * SIP function STM32_SIP_FUNC_PWR ++ * ++ * Argument a0: (input) SMCC ID ++ * (output) status return code ++ * Argument a1: (input) Service ID (STM32_SIP_REG_xxx) ++ * Argument a2: (input) register offset or physical address ++ * (output) register read value, if applicable ++ * Argument a3: (input) register target value if applicable ++ */ ++#define STM32_SIP_FUNC_PWR 0x1001 ++ ++/* Service ID for STM32_SIP_FUNC_RCC/_PWR */ ++#define STM32_SIP_REG_READ 0x0 ++#define STM32_SIP_REG_WRITE 0x1 ++#define STM32_SIP_REG_SET 0x2 ++#define STM32_SIP_REG_CLEAR 0x3 ++ ++/* ++ * SIP functions STM32_SIP_FUNC_BSEC ++ * ++ * Argument a0: (input) SMCC ID ++ * (output) status return code ++ * Argument a1: (input) Clock ID (from DT clock bindings) ++ */ ++#define STM32_SIP_RCC_CAL 0x1002 ++ ++/* ++ * SIP functions STM32_SIP_FUNC_BSEC ++ * ++ * Argument a0: (input) SMCC ID ++ * (output) status return code ++ * Argument a1: (input) Service ID (STM32_SIP_BSEC_xxx) ++ * Argument a2: (input) OTP index ++ * (output) OTP read value, if applicable ++ * Argument a3: (input) OTP value if applicable ++ */ ++#define STM32_SIP_FUNC_BSEC 0x1003 ++ ++/* Service ID for STM32_SIP_FUNC_BSEC */ ++#define STM32_SIP_BSEC_READ_SHADOW 0x1 ++#define STM32_SIP_BSEC_PROG_OTP 0x2 ++#define STM32_SIP_BSEC_WRITE_SHADOW 0x3 ++#define STM32_SIP_BSEC_READ_OTP 0x4 ++ ++/* ++ * SIP functions STM32_SIP_FUNC_SR_MODE ++ * ++ * Argument a0: (input) SMCC ID ++ * (output) status return code ++ * Argument a1: (unused) ++ * Argument a2: (input) Target selfrefresh mode ++ */ ++#define STM32_SIP_FUNC_SR_MODE 0x1004 ++ ++/* DDR Self-Refresh modes */ ++#define STM32_SIP_SR_MODE_SSR 0x0 ++#define STM32_SIP_SR_MODE_ASR 0x1 ++#define STM32_SIP_SR_MODE_HSR 0x2 ++ ++/* ++ * SIP functions STM32_SIP_FUNC_CSTOP ++ * ++ * Argument a0: (input) SMCC ID ++ * (output) status return code ++ * Argument a1: (unused) ++ * Argument a2: (unused) ++ * Argument a3: (input) Target SoC mode ++ */ ++#define STM32_SIP_FUNC_CSTOP 0x1005 ++ ++/* Valid SoC modes used for CSTOP, */ ++#define STM32_SIP_CSLEEP_RUN 0x0 ++#define STM32_SIP_CSTOP_ALLOW_STOP 0x1 ++#define STM32_SIP_CSTOP_ALLOW_LP_STOP 0x2 ++#define STM32_SIP_CSTOP_ALLOW_LPLV_STOP 0x3 ++#define STM32_SIP_CSTOP_ALLOW_STANDBY 0x4 ++#define STM32_SIP_CSTOP_ALLOW_STANDBY_DDR_OFF 0x5 ++#define STM32_SIP_CSTOP_SHUTDOWN 0x6 ++ ++/* ++ * SIP functions STM32_SIP_FUNC_STANDBY ++ * ++ * Argument a0: (input) SMCC ID ++ * (output) status return code ++ * Argument a1: (unused) ++ * Argument a2: (unused) ++ * Argument a3: (input) non null only for DDR off standby ++ */ ++#define STM32_SIP_FUNC_STANDBY 0x1006 ++ ++/* ++ * SIP function STM32_SIP_FUNC_SHUTDOWN ++ * ++ * Argument a0: (input) SMCC ID ++ * (output) status return code ++ */ ++#define STM32_SIP_FUNC_SHUTDOWN 0x1007 ++ ++/* ++ * SIP function STM32_SIP_FUNC_PD_DOMAIN ++ * ++ * Argument a0: (input) SMCC ID ++ * (output) status return code ++ * Argument a2: (index) ID of target power domain to be enabled/disabled ++ * Argument a3: (input) 0 to disable, 1 to eanble target domain ++ */ ++#define STM32_SIP_FUNC_PD_DOMAIN 0x1008 ++ ++/* Valid IDs for power domain for function STM32_SIP_FUNC_PD_DOMAIN */ ++#define STM32_SIP_PD_VSW 0x0 ++#define STM32_SIP_PD_CORE_RET 0x1 ++#define STM32_SIP_PD_CORE 0x2 ++#define STM32_SIP_PD_MAX_PM_DOMAIN 0x3 ++ ++/* ++ * OEM Functions ++ */ ++#define STM32_OEM_SVC_VERSION_MAJOR 0x0 ++#define STM32_OEM_SVC_VERSION_MINOR 0x1 ++ ++/* OEM service generic return codes */ ++#define STM32_OEM_OK 0x0 ++#define STM32_OEM_NOT_SUPPORTED 0xffffffffU ++#define STM32_OEM_FAILED 0xfffffffeU ++#define STM32_OEM_INVALID_PARAMS 0xfffffffdU ++ ++/* ++ * OEM function STM32_OEM_FUNC_LP_FORCE_PARAMS ++ * ++ * Argument a0: (input) SMCC ID ++ * (output) status return code ++ * Argument a2: (input) ID of the mode: suspend or shutdown (off) ++ * Argument a3: (input) ID of the power state to be reached for the mode ++ * Refer to stm32mp1 power bindings. ++ */ ++#define STM32_OEM_FUNC_LP_FORCE_PARAMS 0x0f800 ++ ++/* Valid IDs for power mode configured with STM32_OEM_FUNC_LP_FORCE_PARAMS */ ++#define STM32_OEM_LP_FORCE_SUSPEND_PARAMS 0 ++#define STM32_OEM_LP_FORCE_OFF_PARAMS 1 ++ ++#endif /* __STM32MP1_SMC_H__*/ +diff --git a/core/arch/arm/plat-stm32mp1/service/stm32mp1_svc_setup.c b/core/arch/arm/plat-stm32mp1/service/stm32mp1_svc_setup.c +new file mode 100644 +index 0000000..3c7958c +--- /dev/null ++++ b/core/arch/arm/plat-stm32mp1/service/stm32mp1_svc_setup.c +@@ -0,0 +1,129 @@ ++// SPDX-License-Identifier: BSD-3-Clause ++/* ++ * Copyright (c) 2017-2018, STMicroelectronics ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "bsec_svc.h" ++#include "low_power_svc.h" ++#include "pwr_svc.h" ++#include "rcc_svc.h" ++#include "stm32mp1_smc.h" ++ ++static uint32_t __maybe_unused calib_scv_handler(uint32_t x1) ++{ ++ unsigned long clock_id = x1; ++ ++ return (stm32mp_start_clock_calib(clock_id) == 0) ? ++ STM32_SIP_OK : STM32_SIP_FAILED; ++} ++ ++/* STM32 SiP Service UUID */ ++static const TEE_UUID stm32mp1_sip_svc_uid = { ++ 0x50aa78a7, 0x9bf4, 0x4a14, ++ { 0x8a, 0x5e, 0x26, 0x4d, 0x59, 0x94, 0xc2, 0x14 } ++}; ++ ++static void get_sip_func_uid(uint32_t *a0, uint32_t *a1, ++ uint32_t *a2, uint32_t *a3) ++{ ++ const void *uid = &stm32mp1_sip_svc_uid; ++ ++ memcpy(a0, (char *)uid, sizeof(uint32_t)); ++ memcpy(a1, (char *)uid + sizeof(uint32_t), sizeof(uint32_t)); ++ memcpy(a2, (char *)uid + (sizeof(uint32_t) * 2), sizeof(uint32_t)); ++ memcpy(a3, (char *)uid + (sizeof(uint32_t) * 3), sizeof(uint32_t)); ++} ++ ++bool stm32_sip_service(struct sm_ctx __unused *ctx, ++ uint32_t *a0, uint32_t *a1, uint32_t *a2, uint32_t *a3) ++{ ++ switch (OPTEE_SMC_FUNC_NUM(*a0)) { ++ case STM32_SIP_FUNC_CALL_COUNT: ++ /* This service is meaningless, return a dummy value */ ++ *a0 = 0; ++ break; ++ case STM32_SIP_FUNC_VERSION: ++ *a0 = STM32_SIP_SVC_VERSION_MAJOR; ++ *a1 = STM32_SIP_SVC_VERSION_MINOR; ++ break; ++ case STM32_SIP_FUNC_UID: ++ get_sip_func_uid(a0, a1, a2, a3); ++ break; ++#ifdef CFG_STM32_BSEC_SIP ++ case STM32_SIP_FUNC_BSEC: ++ *a0 = bsec_main(*a1, *a2, *a3, a1); ++ break; ++#endif ++#ifdef CFG_STM32_RCC_SIP ++ case STM32_SIP_FUNC_RCC: ++ *a0 = rcc_scv_handler(*a1, *a2, *a3); ++ break; ++#endif ++#ifdef CFG_STM32_CLOCKSRC_CALIB ++ case STM32_SIP_RCC_CAL: ++ *a0 = calib_scv_handler(*a1); ++ break; ++#endif ++#ifdef CFG_STM32_PWR_SIP ++ case STM32_SIP_FUNC_PWR: ++ *a0 = pwr_scv_handler(*a1, *a2, *a3); ++ break; ++#endif ++#ifdef CFG_STM32_POWER_SERVICES ++ case STM32_SIP_FUNC_SR_MODE: ++ *a0 = sr_mode_scv_handler(*a1, *a2); ++ break; ++ ++ case STM32_SIP_FUNC_CSTOP: ++ *a0 = cstop_scv_handler(ctx, *a1, *a2, *a3); ++ break; ++ ++ case STM32_SIP_FUNC_STANDBY: ++ *a0 = standby_scv_handler(ctx, *a1, *a2, *a3); ++ break; ++ ++ case STM32_SIP_FUNC_SHUTDOWN: ++ *a0 = shutdown_scv_handler(); ++ break; ++ ++ case STM32_SIP_FUNC_PD_DOMAIN: ++ *a0 = pm_domain_scv_handler(*a1, *a2); ++ break; ++#endif ++ ++ default: ++ return true; ++ } ++ ++ return false; ++} ++ ++bool stm32_oem_service(struct sm_ctx __unused *ctx, ++ uint32_t *a0, uint32_t *a1 __maybe_unused, ++ uint32_t *a2 __maybe_unused, uint32_t *a3 __unused) ++{ ++ switch (OPTEE_SMC_FUNC_NUM(*a0)) { ++#ifdef CFG_STM32_POWER_SERVICES ++ case STM32_OEM_FUNC_LP_FORCE_PARAMS: ++ *a0 = pm_set_lp_state_scv_handler(*a1, *a2); ++ break; ++#endif ++ ++ default: ++ return true; ++ } ++ ++ return false; ++} +diff --git a/core/arch/arm/plat-stm32mp1/service/sub.mk b/core/arch/arm/plat-stm32mp1/service/sub.mk +new file mode 100644 +index 0000000..0797b8f +--- /dev/null ++++ b/core/arch/arm/plat-stm32mp1/service/sub.mk +@@ -0,0 +1,7 @@ ++global-incdirs-y += . ++ ++srcs-y += stm32mp1_svc_setup.c ++srcs-$(CFG_STM32_BSEC_SIP) += bsec_svc.c ++srcs-$(CFG_STM32_PWR_SIP) += pwr_svc.c ++srcs-$(CFG_STM32_RCC_SIP) += rcc_svc.c ++srcs-$(CFG_STM32_POWER_SERVICES) += low_power_svc.c +diff --git a/core/arch/arm/plat-stm32mp1/shared_resources.c b/core/arch/arm/plat-stm32mp1/shared_resources.c +new file mode 100644 +index 0000000..0eb929c +--- /dev/null ++++ b/core/arch/arm/plat-stm32mp1/shared_resources.c +@@ -0,0 +1,1007 @@ ++// SPDX-License-Identifier: BSD-3-Clause ++/* ++ * Copyright (c) 2017-2018, STMicroelectronics ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static unsigned int shregs_lock = SPINLOCK_UNLOCK; ++static bool registering_locked; ++ ++/* Shared resource lock: assume not required if MMU is disabled */ ++uint32_t lock_stm32shregs(void) ++{ ++ return may_spin_lock(&shregs_lock); ++} ++ ++void unlock_stm32shregs(uint32_t exceptions) ++{ ++ may_spin_unlock(&shregs_lock, exceptions); ++} ++ ++/* Shared register access: upon shared resource lock */ ++void io_mask32_stm32shregs(uintptr_t va, uint32_t value, uint32_t mask) ++{ ++ uint32_t exceptions = lock_stm32shregs(); ++ ++ io_mask32(va, value, mask); ++ ++ unlock_stm32shregs(exceptions); ++} ++ ++/* ++ * Generic clock enable/disable from secure world. ++ * Some drivers may use non secure resources in specific execution context: ++ * when the other SMP core(s) are offline and non secure is never reached. ++ * In such cases, drivers shall enable/disable the HW clock only if it was not ++ * left enabled by the non secure world. ++ * ++ * During driver initializations, before registering_locked is locked, all ++ * driver simply enable/disable the clock as if the peripheral was secure. ++ */ ++void stm32_clock_enable(unsigned long id) ++{ ++ if (registering_locked) { ++ if (stm32mp_clock_is_non_secure(id)) { ++ assert(!stm32mp1_clk_get_refcount(id)); ++ ++ if (stm32mp1_clk_is_enabled(id)) { ++ return; ++ } ++ } ++ } ++ ++ stm32mp1_clk_enable_secure(id); ++} ++ ++void stm32_clock_disable(unsigned long id) ++{ ++ if (registering_locked) { ++ if (stm32mp_clock_is_non_secure(id)) { ++ if (!stm32mp1_clk_get_refcount(id)) { ++ return; ++ } ++ } ++ } ++ ++ stm32mp1_clk_disable_secure(id); ++} ++ ++/* ++ * Shared peripherals and resources. ++ * Defines resource that may be non secure, secure or shared. ++ * May be a device, a bus, a clock, a memory. ++ * ++ * State default to PERIPH_UNREGISTERED resource is not explicitly ++ * set here. ++ * ++ * Resource driver not built (upon CFG_xxx), the resource defaults ++ * to non secure ownership. ++ * ++ * Each IO of the GPIOZ IO can be secure or non secure. ++ * When the GPIO driver is enabled, the GPIOZ bank is fully non secure ++ * only if each IO is non secure and the GPIOZ bank is shared if it ++ * includes secure and non secure IOs. ++ * ++ * BKPSRAM is assumed shared. ++ * DDR control (DDRC and DDRPHY) is secure. ++ * Inits will define the resource state according the device tree ++ * and the driver initialization sequences. ++ * ++ * The platform initialization uses these information to set the ETZPC ++ * configuration. Non secure services (as clocks or regulator accesses) ++ * rely on these information to drive the related service execution. ++ */ ++#define SHRES_NON_SECURE 3 ++#define SHRES_SHARED 2 ++#define SHRES_SECURE 1 ++#define SHRES_UNREGISTERED 0 ++ ++static uint8_t shres_state[STM32MP1_SHRES_COUNT] = { ++#if !defined(CFG_STM32_IWDG) ++ [STM32MP1_SHRES_IWDG1] = SHRES_NON_SECURE, ++#endif ++#if !defined(CFG_STM32_UART) ++ [STM32MP1_SHRES_USART1] = SHRES_NON_SECURE, ++#endif ++#if !defined(CFG_STM32_SPI) ++ [STM32MP1_SHRES_SPI6] = SHRES_NON_SECURE, ++#endif ++#if !defined(CFG_STM32_I2C) ++ [STM32MP1_SHRES_I2C4] = SHRES_NON_SECURE, ++ [STM32MP1_SHRES_I2C6] = SHRES_NON_SECURE, ++#endif ++#if !defined(CFG_STM32_GPIO) ++ [STM32MP1_SHRES_GPIOZ(0)] = SHRES_NON_SECURE, ++ [STM32MP1_SHRES_GPIOZ(1)] = SHRES_NON_SECURE, ++ [STM32MP1_SHRES_GPIOZ(2)] = SHRES_NON_SECURE, ++ [STM32MP1_SHRES_GPIOZ(3)] = SHRES_NON_SECURE, ++ [STM32MP1_SHRES_GPIOZ(4)] = SHRES_NON_SECURE, ++ [STM32MP1_SHRES_GPIOZ(5)] = SHRES_NON_SECURE, ++ [STM32MP1_SHRES_GPIOZ(6)] = SHRES_NON_SECURE, ++ [STM32MP1_SHRES_GPIOZ(7)] = SHRES_NON_SECURE, ++#endif ++#if !defined(CFG_STM32_RNG) ++ [STM32MP1_SHRES_RNG1] = SHRES_NON_SECURE, ++#endif ++#if !defined(CFG_STM32_HASH) ++ [STM32MP1_SHRES_HASH1] = SHRES_NON_SECURE, ++#endif ++#if !defined(CFG_STM32_CRYP) ++ [STM32MP1_SHRES_CRYP1] = SHRES_NON_SECURE, ++#endif ++#if !defined(CFG_STM32_RTC) ++ [STM32MP1_SHRES_RTC] = SHRES_NON_SECURE, ++#endif ++}; ++ ++#if CFG_TEE_CORE_LOG_LEVEL > 0 ++static const char *shres2str_id_tbl[STM32MP1_SHRES_COUNT] = { ++ [STM32MP1_SHRES_GPIOZ(0)] = "GPIOZ0", ++ [STM32MP1_SHRES_GPIOZ(1)] = "GPIOZ1", ++ [STM32MP1_SHRES_GPIOZ(2)] = "GPIOZ2", ++ [STM32MP1_SHRES_GPIOZ(3)] = "GPIOZ3", ++ [STM32MP1_SHRES_GPIOZ(4)] = "GPIOZ4", ++ [STM32MP1_SHRES_GPIOZ(5)] = "GPIOZ5", ++ [STM32MP1_SHRES_GPIOZ(6)] = "GPIOZ6", ++ [STM32MP1_SHRES_GPIOZ(7)] = "GPIOZ7", ++ [STM32MP1_SHRES_IWDG1] = "IWDG1", ++ [STM32MP1_SHRES_USART1] = "USART1", ++ [STM32MP1_SHRES_SPI6] = "SPI6", ++ [STM32MP1_SHRES_I2C4] = "I2C4", ++ [STM32MP1_SHRES_RNG1] = "RNG1", ++ [STM32MP1_SHRES_HASH1] = "HASH1", ++ [STM32MP1_SHRES_CRYP1] = "CRYP1", ++ [STM32MP1_SHRES_I2C6] = "I2C6", ++ [STM32MP1_SHRES_RTC] = "RTC", ++ [STM32MP1_SHRES_MCU] = "MCU", ++ [STM32MP1_SHRES_HSI] = "HSI", ++ [STM32MP1_SHRES_LSI] = "LSI", ++ [STM32MP1_SHRES_HSE] = "HSE", ++ [STM32MP1_SHRES_LSE] = "LSE", ++ [STM32MP1_SHRES_CSI] = "CSI", ++ [STM32MP1_SHRES_PLL1] = "PLL1", ++ [STM32MP1_SHRES_PLL1_P] = "PLL1_P", ++ [STM32MP1_SHRES_PLL1_Q] = "PLL1_Q", ++ [STM32MP1_SHRES_PLL1_R] = "PLL1_R", ++ [STM32MP1_SHRES_PLL2] = "PLL2", ++ [STM32MP1_SHRES_PLL2_P] = "PLL2_P", ++ [STM32MP1_SHRES_PLL2_Q] = "PLL2_Q", ++ [STM32MP1_SHRES_PLL2_R] = "PLL2_R", ++ [STM32MP1_SHRES_PLL3] = "PLL3", ++ [STM32MP1_SHRES_PLL3_P] = "PLL3_P", ++ [STM32MP1_SHRES_PLL3_Q] = "PLL3_Q", ++ [STM32MP1_SHRES_PLL3_R] = "PLL3_R", ++}; ++ ++static const char *shres2str_id(unsigned int id) ++{ ++ return shres2str_id_tbl[id]; ++} ++ ++static const char *shres2str_state_tbl[4] = { ++ [SHRES_SHARED] = "shared", ++ [SHRES_NON_SECURE] = "non secure", ++ [SHRES_SECURE] = "secure", ++ [SHRES_UNREGISTERED] = "unregistered", ++}; ++ ++static const char *shres2str_state(unsigned int id) ++{ ++ return shres2str_state_tbl[id]; ++} ++#else ++static __maybe_unused const char *shres2str_id(unsigned int __unused id) ++{ ++ return NULL; ++} ++ ++static __maybe_unused const char *shres2str_state(unsigned int __unused id) ++{ ++ return NULL; ++} ++#endif ++ ++struct shres2decprot { ++ unsigned int shres_id; ++ unsigned int decprot_id; ++ const char *decprot_str; ++}; ++ ++#define SHRES2DECPROT(shres, decprot, str) { \ ++ .shres_id = shres, \ ++ .decprot_id = decprot, \ ++ .decprot_str = str, \ ++ } ++ ++#define SHRES_INVALID ~0U ++static const struct shres2decprot shres2decprot_tbl[] = { ++ SHRES2DECPROT(STM32MP1_SHRES_IWDG1, STM32MP1_ETZPC_IWDG1_ID, "IWDG1"), ++ SHRES2DECPROT(STM32MP1_SHRES_USART1, STM32MP1_ETZPC_USART1_ID, "UART1"), ++ SHRES2DECPROT(STM32MP1_SHRES_SPI6, STM32MP1_ETZPC_SPI6_ID, "SPI6"), ++ SHRES2DECPROT(STM32MP1_SHRES_I2C4, STM32MP1_ETZPC_I2C4_ID, "I2C4"), ++ SHRES2DECPROT(STM32MP1_SHRES_RNG1, STM32MP1_ETZPC_RNG1_ID, "RNG1"), ++ SHRES2DECPROT(STM32MP1_SHRES_HASH1, STM32MP1_ETZPC_HASH1_ID, "HASH1"), ++ SHRES2DECPROT(STM32MP1_SHRES_CRYP1, STM32MP1_ETZPC_CRYP1_ID, "CRYP1"), ++ SHRES2DECPROT(STM32MP1_SHRES_I2C6, STM32MP1_ETZPC_I2C6_ID, "I2C6"), ++ /* Below are specific IDs without a 1-to-1 mapping to SHRES IDs */ ++ SHRES2DECPROT(SHRES_INVALID, STM32MP1_ETZPC_STGENC_ID, "STGEN"), ++ SHRES2DECPROT(SHRES_INVALID, STM32MP1_ETZPC_BKPSRAM_ID, "BKPSRAM"), ++ SHRES2DECPROT(SHRES_INVALID, STM32MP1_ETZPC_GPIOZ_ID, "GPIOZ"), ++ SHRES2DECPROT(SHRES_INVALID, STM32MP1_ETZPC_DDRCTRL_ID, "DDRCTRL"), ++ SHRES2DECPROT(SHRES_INVALID, STM32MP1_ETZPC_DDRPHYC_ID, "DDRPHY"), ++}; ++ ++static unsigned int decprot2shres(unsigned int decprot_id) ++{ ++ size_t i; ++ ++ for (i = 0; i < ARRAY_SIZE(shres2decprot_tbl); i++) { ++ if (shres2decprot_tbl[i].decprot_id == decprot_id) { ++ return shres2decprot_tbl[i].shres_id; ++ } ++ } ++ ++ DMSG("No share resource ID %u", decprot_id); ++ return SHRES_INVALID; ++} ++ ++static const char *decprot2str(unsigned int decprot_id) ++{ ++ size_t i; ++ ++ for (i = 0; i < ARRAY_SIZE(shres2decprot_tbl); i++) { ++ if (shres2decprot_tbl[i].decprot_id == decprot_id) { ++ return shres2decprot_tbl[i].decprot_str; ++ } ++ } ++ ++ EMSG("Invalid ID %u", decprot_id); ++ panic(); ++} ++ ++/* GPIOZ bank may have several number of pins */ ++#if CFG_DT ++static int gpioz_nbpin = -1; ++ ++static unsigned int get_gpioz_nbpin_unpg(void) ++{ ++ if (gpioz_nbpin >= 0) { ++ return (unsigned int)gpioz_nbpin; ++ } ++ ++ panic(); ++} ++KEEP_PAGER(get_gpioz_nbpin_unpg); ++ ++static unsigned int get_gpioz_nbpin(void) ++{ ++ if (gpioz_nbpin < 0) { ++ void *fdt; ++ ++ fdt = get_dt_blob(); ++ if (fdt == NULL) { ++ panic(); ++ } ++ ++ gpioz_nbpin = fdt_get_gpioz_nbpins_from_dt(fdt); ++ assert((gpioz_nbpin == 0) || ++ (gpioz_nbpin == STM32MP1_GPIOZ_PIN_MAX_COUNT)); ++ } ++ ++ return (unsigned int)gpioz_nbpin; ++} ++#else ++static unsigned int get_gpioz_nbpin_unpg(void) ++{ ++ return STM32MP1_GPIOZ_PIN_MAX_COUNT; ++} ++ ++static unsigned int get_gpioz_nbpin(void) ++{ ++ return get_gpioz_nbpin_unpg(); ++} ++#endif ++ ++static bool shareable_resource(unsigned int id) ++{ ++ switch (id) { ++ default: ++ /* Currently no shareable resource */ ++ return false; ++ } ++} ++ ++static bool mckprot_resource(unsigned int id) ++{ ++ switch (id) { ++ case STM32MP1_SHRES_MCU: ++ case STM32MP1_SHRES_PLL3: ++ case STM32MP1_SHRES_PLL3_P: ++ case STM32MP1_SHRES_PLL3_Q: ++ case STM32MP1_SHRES_PLL3_R: ++ return true; ++ default: ++ return false; ++ } ++} ++ ++static void register_periph(unsigned int id, unsigned int state) ++{ ++ assert(id < STM32MP1_SHRES_COUNT && ++ state > SHRES_UNREGISTERED && ++ state <= SHRES_NON_SECURE); ++ ++ if (registering_locked) { ++ panic(); ++ } ++ ++ if ((state == SHRES_SHARED && !shareable_resource(id)) || ++ ((shres_state[id] != SHRES_UNREGISTERED) && ++ (shres_state[id] != state))) { ++ DMSG("Cannot change %s from %s to %s", ++ shres2str_id(id), ++ shres2str_state(shres_state[id]), ++ shres2str_state(state)); ++ panic(); ++ } ++ ++ if (shres_state[id] == SHRES_UNREGISTERED) { ++ DMSG("Register %s as %s", ++ shres2str_id(id), shres2str_state(state)); ++ } ++ ++ switch (id) { ++ case STM32MP1_SHRES_GPIOZ(0): ++ case STM32MP1_SHRES_GPIOZ(1): ++ case STM32MP1_SHRES_GPIOZ(2): ++ case STM32MP1_SHRES_GPIOZ(3): ++ case STM32MP1_SHRES_GPIOZ(4): ++ case STM32MP1_SHRES_GPIOZ(5): ++ case STM32MP1_SHRES_GPIOZ(6): ++ case STM32MP1_SHRES_GPIOZ(7): ++ if ((id - STM32MP1_SHRES_GPIOZ(0)) >= get_gpioz_nbpin()) { ++ EMSG("Invalid GPIO pin %u, %u pin(s) available", ++ id - STM32MP1_SHRES_GPIOZ(0), get_gpioz_nbpin()); ++ panic(); ++ } ++ break; ++ default: ++ break; ++ } ++ ++ shres_state[id] = (uint8_t)state; ++ ++ /* Explore clock tree to lock dependencies */ ++ if ((state == SHRES_SECURE) || (state == SHRES_SHARED)) { ++ switch (id) { ++ case STM32MP1_SHRES_GPIOZ(0): ++ case STM32MP1_SHRES_GPIOZ(1): ++ case STM32MP1_SHRES_GPIOZ(2): ++ case STM32MP1_SHRES_GPIOZ(3): ++ case STM32MP1_SHRES_GPIOZ(4): ++ case STM32MP1_SHRES_GPIOZ(5): ++ case STM32MP1_SHRES_GPIOZ(6): ++ case STM32MP1_SHRES_GPIOZ(7): ++ stm32mp_register_clock_parents_secure(GPIOZ); ++ break; ++ case STM32MP1_SHRES_IWDG1: ++ stm32mp_register_clock_parents_secure(IWDG1); ++ break; ++ case STM32MP1_SHRES_USART1: ++ stm32mp_register_clock_parents_secure(USART1_K); ++ break; ++ case STM32MP1_SHRES_SPI6: ++ stm32mp_register_clock_parents_secure(SPI6_K); ++ break; ++ case STM32MP1_SHRES_I2C4: ++ stm32mp_register_clock_parents_secure(I2C4_K); ++ break; ++ case STM32MP1_SHRES_RNG1: ++ stm32mp_register_clock_parents_secure(RNG1_K); ++ break; ++ case STM32MP1_SHRES_HASH1: ++ stm32mp_register_clock_parents_secure(HASH1); ++ break; ++ case STM32MP1_SHRES_CRYP1: ++ stm32mp_register_clock_parents_secure(CRYP1); ++ break; ++ case STM32MP1_SHRES_I2C6: ++ stm32mp_register_clock_parents_secure(I2C6_K); ++ break; ++ case STM32MP1_SHRES_RTC: ++ stm32mp_register_clock_parents_secure(RTC); ++ break; ++ case STM32MP1_SHRES_PLL1_P: ++ case STM32MP1_SHRES_PLL1_Q: ++ case STM32MP1_SHRES_PLL1_R: ++ register_periph(STM32MP1_SHRES_PLL1, SHRES_SECURE); ++ stm32mp_register_clock_parents_secure(PLL1); ++ break; ++ case STM32MP1_SHRES_PLL2_P: ++ case STM32MP1_SHRES_PLL2_Q: ++ case STM32MP1_SHRES_PLL2_R: ++ register_periph(STM32MP1_SHRES_PLL2, SHRES_SECURE); ++ stm32mp_register_clock_parents_secure(PLL2); ++ break; ++ case STM32MP1_SHRES_PLL3_P: ++ case STM32MP1_SHRES_PLL3_Q: ++ case STM32MP1_SHRES_PLL3_R: ++ register_periph(STM32MP1_SHRES_PLL3, SHRES_SECURE); ++ stm32mp_register_clock_parents_secure(PLL3); ++ break; ++ default: ++ /* No expected resource dependency */ ++ break; ++ } ++ } ++} ++ ++/* Register resource by ID */ ++void stm32mp_register_secure_periph(unsigned int id) ++{ ++ register_periph(id, SHRES_SECURE); ++} ++ ++void stm32mp_register_shared_periph(unsigned int id) ++{ ++ register_periph(id, SHRES_SHARED); ++} ++ ++void stm32mp_register_non_secure_periph(unsigned int id) ++{ ++ register_periph(id, SHRES_NON_SECURE); ++} ++ ++/* Register resource by IO memory base address */ ++static void register_periph_iomem(uintptr_t base, unsigned int state) ++{ ++ unsigned int id; ++ ++ switch (base) { ++ case IWDG1_BASE: ++ id = STM32MP1_SHRES_IWDG1; ++ break; ++ case USART1_BASE: ++ id = STM32MP1_SHRES_USART1; ++ break; ++ case SPI6_BASE: ++ id = STM32MP1_SHRES_SPI6; ++ break; ++ case I2C4_BASE: ++ id = STM32MP1_SHRES_I2C4; ++ break; ++ case I2C6_BASE: ++ id = STM32MP1_SHRES_I2C6; ++ break; ++ case RTC_BASE: ++ id = STM32MP1_SHRES_RTC; ++ break; ++ case RNG1_BASE: ++ id = STM32MP1_SHRES_RNG1; ++ break; ++ case CRYP1_BASE: ++ id = STM32MP1_SHRES_CRYP1; ++ break; ++ case HASH1_BASE: ++ id = STM32MP1_SHRES_HASH1; ++ break; ++ ++#ifdef CFG_WITH_NSEC_GPIOS ++ case GPIOA_BASE: ++ case GPIOB_BASE: ++ case GPIOC_BASE: ++ case GPIOD_BASE: ++ case GPIOE_BASE: ++ case GPIOF_BASE: ++ case GPIOG_BASE: ++ case GPIOH_BASE: ++ case GPIOI_BASE: ++ case GPIOJ_BASE: ++ case GPIOK_BASE: ++#endif ++#ifdef CFG_WITH_NSEC_UARTS ++ case USART2_BASE: ++ case USART3_BASE: ++ case UART4_BASE: ++ case UART5_BASE: ++ case USART6_BASE: ++ case UART7_BASE: ++ case UART8_BASE: ++#endif ++ case IWDG2_BASE: ++ /* Allow drivers to register some non secure resources */ ++ DMSG("IO for non secure resource 0x%lx", base); ++ if (state != SHRES_NON_SECURE) ++ panic(); ++ ++ return; ++ ++ default: ++ panic(); ++ break; ++ } ++ ++ register_periph(id, state); ++} ++ ++void stm32mp_register_secure_periph_iomem(uintptr_t base) ++{ ++ register_periph_iomem(base, SHRES_SECURE); ++} ++ ++void stm32mp_register_non_secure_periph_iomem(uintptr_t base) ++{ ++ register_periph_iomem(base, SHRES_NON_SECURE); ++} ++ ++/* Register GPIO resource */ ++void stm32mp_register_secure_gpio(unsigned int bank, unsigned int pin) ++{ ++ switch (bank) { ++ case GPIO_BANK_Z: ++ register_periph(STM32MP1_SHRES_GPIOZ(pin), SHRES_SECURE); ++ break; ++ default: ++ EMSG("GPIO bank %u cannot be secured", bank); ++ panic(); ++ } ++} ++ ++void stm32mp_register_non_secure_gpio(unsigned int bank, unsigned int pin) ++{ ++ switch (bank) { ++ case GPIO_BANK_Z: ++ register_periph(STM32MP1_SHRES_GPIOZ(pin), SHRES_NON_SECURE); ++ break; ++ default: ++ break; ++ } ++} ++ ++void stm32mp_register_etzpc_decprot(unsigned int id, ++ enum etzpc_decprot_attributes attr) ++{ ++ unsigned int state = SHRES_SECURE; ++ unsigned int id_shres; ++ ++ switch (attr) { ++ case TZPC_DECPROT_S_RW: ++ break; ++ case TZPC_DECPROT_NS_R_S_W: ++ case TZPC_DECPROT_MCU_ISOLATION: ++ case TZPC_DECPROT_NS_RW: ++ state = SHRES_NON_SECURE; ++ break; ++ default: ++ panic(); ++ } ++ ++ switch (id) { ++ case STM32MP1_ETZPC_GPIOZ_ID: ++ if (state == SHRES_SECURE) { ++ /* GPIOZ cannot be hardened from the ETZPC */ ++ panic(); ++ } ++ break; ++ default: ++ id_shres = decprot2shres(id); ++ if (id_shres == SHRES_INVALID) { ++ if (state != SHRES_NON_SECURE) ++ panic(); ++ } else { ++ register_periph(id_shres, state); ++ } ++ break; ++ } ++} ++ ++/* Get resource state: these accesses lock the registering support */ ++static void lock_registering(void) ++{ ++ registering_locked = true; ++} ++ ++bool stm32mp_periph_is_shared(unsigned long id) ++{ ++ lock_registering(); ++ ++ return shres_state[id] == SHRES_SHARED; ++} ++ ++bool stm32mp_periph_is_non_secure(unsigned long id) ++{ ++ lock_registering(); ++ ++ return shres_state[id] == SHRES_NON_SECURE; ++} ++ ++bool stm32mp_periph_is_secure(unsigned long id) ++{ ++ lock_registering(); ++ ++ return shres_state[id] == SHRES_SECURE; ++} ++ ++bool stm32mp_periph_is_unregistered(unsigned long id) ++{ ++ lock_registering(); ++ ++ return shres_state[id] == SHRES_UNREGISTERED; ++} ++ ++bool stm32mp_gpio_bank_is_shared(unsigned int bank) ++{ ++ unsigned int non_secure = 0; ++ unsigned int i; ++ ++ lock_registering(); ++ ++ if (bank != GPIO_BANK_Z) { ++ return false; ++ } ++ ++ for (i = 0; i < get_gpioz_nbpin_unpg(); i++) { ++ if (stm32mp_periph_is_non_secure(STM32MP1_SHRES_GPIOZ(i)) || ++ stm32mp_periph_is_unregistered(STM32MP1_SHRES_GPIOZ(i))) { ++ non_secure++; ++ } ++ } ++ ++ return (non_secure != 0) && (non_secure < get_gpioz_nbpin_unpg()); ++} ++ ++bool stm32mp_gpio_bank_is_non_secure(unsigned int bank) ++{ ++ unsigned int non_secure = 0; ++ unsigned int i; ++ ++ lock_registering(); ++ ++ if (bank != GPIO_BANK_Z) { ++ return true; ++ } ++ ++ for (i = 0; i < get_gpioz_nbpin_unpg(); i++) { ++ if (stm32mp_periph_is_non_secure(STM32MP1_SHRES_GPIOZ(i)) || ++ stm32mp_periph_is_unregistered(STM32MP1_SHRES_GPIOZ(i))) { ++ non_secure++; ++ } ++ } ++ ++ return non_secure == get_gpioz_nbpin_unpg(); ++} ++ ++bool stm32mp_gpio_bank_is_secure(unsigned int bank) ++{ ++ unsigned int secure = 0; ++ unsigned int i; ++ ++ lock_registering(); ++ ++ if (bank != GPIO_BANK_Z) { ++ return false; ++ } ++ ++ for (i = 0; i < get_gpioz_nbpin_unpg(); i++) { ++ if (stm32mp_periph_is_secure(STM32MP1_SHRES_GPIOZ(i))) { ++ secure++; ++ } ++ } ++ ++ return secure == get_gpioz_nbpin_unpg(); ++} ++ ++bool stm32mp_clock_is_shareable(unsigned long clock_id) ++{ ++ switch (clock_id) { ++ case GPIOZ: ++ return get_gpioz_nbpin() > 0; ++ case RTCAPB: ++ return true; ++ default: ++ return false; ++ } ++} ++ ++bool stm32mp_clock_is_shared(unsigned long clock_id) ++{ ++ lock_registering(); ++ ++ switch (clock_id) { ++ case GPIOZ: ++ if (get_gpioz_nbpin_unpg() > 0) { ++ return stm32mp_gpio_bank_is_shared(GPIO_BANK_Z); ++ } else { ++ return false; ++ } ++ case RTCAPB: ++ /* RTCAPB is shared for non secure backup registers */ ++ return true; ++ default: ++ return false; ++ } ++} ++ ++bool stm32mp_clock_is_non_secure(unsigned long clock_id) ++{ ++ unsigned int shres_id; ++ ++ lock_registering(); ++ ++ if (stm32mp_clock_is_shared(clock_id)) { ++ return false; ++ } ++ ++ switch (clock_id) { ++ case BSEC: ++ case BKPSRAM: ++ case TZPC: ++ case TZC1: ++ case TZC2: ++ case STGEN_K: ++ case DDRC1: ++ case DDRC1LP: ++ case DDRC2: ++ case DDRC2LP: ++ case DDRPHYC: ++ case DDRPHYCLP: ++ case DDRCAPB: ++ case DDRCAPBLP: ++ case AXIDCG: ++ case DDRPHYCAPB: ++ case DDRPHYCAPBLP: ++ return false; ++ case IWDG1: ++ shres_id = STM32MP1_SHRES_IWDG1; ++ break; ++ case USART1_K: ++ shres_id = STM32MP1_SHRES_USART1; ++ break; ++ case SPI6_K: ++ shres_id = STM32MP1_SHRES_SPI6; ++ break; ++ case I2C4_K: ++ shres_id = STM32MP1_SHRES_I2C4; ++ break; ++ case RNG1_K: ++ shres_id = STM32MP1_SHRES_RNG1; ++ break; ++ case HASH1: ++ shres_id = STM32MP1_SHRES_HASH1; ++ break; ++ case CRYP1: ++ shres_id = STM32MP1_SHRES_CRYP1; ++ break; ++ case I2C6_K: ++ shres_id = STM32MP1_SHRES_I2C6; ++ break; ++ case RTC: ++ shres_id = STM32MP1_SHRES_RTC; ++ break; ++ default: ++ return true; ++ } ++ ++ return stm32mp_periph_is_non_secure(shres_id); ++} ++ ++/* ETZPC configuration at drivers initialization completion */ ++static enum etzpc_decprot_attributes decprot_periph_attr(unsigned int id) ++{ ++ switch (id) { ++ case STM32MP1_SHRES_GPIOZ(0): ++ case STM32MP1_SHRES_GPIOZ(1): ++ case STM32MP1_SHRES_GPIOZ(2): ++ case STM32MP1_SHRES_GPIOZ(3): ++ case STM32MP1_SHRES_GPIOZ(4): ++ case STM32MP1_SHRES_GPIOZ(5): ++ case STM32MP1_SHRES_GPIOZ(6): ++ case STM32MP1_SHRES_GPIOZ(7): ++ assert((id - STM32MP1_SHRES_GPIOZ(0)) < get_gpioz_nbpin_unpg()); ++ return TZPC_DECPROT_NS_RW; ++ default: ++ if (stm32mp_periph_is_non_secure(id)) { ++ return TZPC_DECPROT_NS_RW; ++ } ++ ++ return TZPC_DECPROT_S_RW; ++ } ++} ++ ++static bool check_decprot(unsigned int id, enum etzpc_decprot_attributes exp) ++{ ++ enum etzpc_decprot_attributes cur = etzpc_get_decprot(id); ++ ++ if (cur == exp) { ++ return true; ++ } ++ ++ switch (exp) { ++ case TZPC_DECPROT_NS_RW: ++ if (cur == TZPC_DECPROT_S_RW) { ++#ifdef CFG_DT ++ IMSG("Warning ETZPC: %s could be non secure", ++ decprot2str(id)); ++#else ++ etzpc_configure_decprot(id, TZPC_DECPROT_NS_RW); ++ IMSG("Warning ETZPC: %s forced non secure", ++ decprot2str(id)); ++#endif ++ } ++ return true; ++ ++ case TZPC_DECPROT_S_RW: ++ EMSG("ETZPC DECPROT: %s (%u) expected secure but DECPROT=%d", ++ decprot2str(id), id, cur); ++ break; ++ ++ case TZPC_DECPROT_NS_R_S_W: ++ case TZPC_DECPROT_MCU_ISOLATION: ++ default: ++ panic(); ++ } ++ ++ return false; ++} ++ ++static void check_etzpc_secure_configuration(void) ++{ ++ bool error = false; ++ ++ assert(registering_locked); ++ ++ error |= !check_decprot(STM32MP1_ETZPC_STGENC_ID, ++ TZPC_DECPROT_S_RW); ++ ++ error |= !check_decprot(STM32MP1_ETZPC_BKPSRAM_ID, ++ TZPC_DECPROT_S_RW); ++ ++ error |= !check_decprot(STM32MP1_ETZPC_IWDG1_ID, ++ decprot_periph_attr(STM32MP1_SHRES_IWDG1)); ++ ++ error |= !check_decprot(STM32MP1_ETZPC_USART1_ID, ++ decprot_periph_attr(STM32MP1_SHRES_USART1)); ++ ++ error |= !check_decprot(STM32MP1_ETZPC_SPI6_ID, ++ decprot_periph_attr(STM32MP1_SHRES_SPI6)); ++ ++ error |= !check_decprot(STM32MP1_ETZPC_I2C4_ID, ++ decprot_periph_attr(STM32MP1_SHRES_I2C4)); ++ ++ error |= !check_decprot(STM32MP1_ETZPC_RNG1_ID, ++ decprot_periph_attr(STM32MP1_SHRES_RNG1)); ++ ++ error |= !check_decprot(STM32MP1_ETZPC_HASH1_ID, ++ decprot_periph_attr(STM32MP1_SHRES_HASH1)); ++ ++ error |= !check_decprot(STM32MP1_ETZPC_CRYP1_ID, ++ decprot_periph_attr(STM32MP1_SHRES_CRYP1)); ++ ++ error |= !check_decprot(STM32MP1_ETZPC_DDRCTRL_ID, ++ TZPC_DECPROT_S_RW); ++ ++ error |= !check_decprot(STM32MP1_ETZPC_DDRPHYC_ID, ++ TZPC_DECPROT_S_RW); ++ ++ error |= !check_decprot(STM32MP1_ETZPC_I2C6_ID, ++ decprot_periph_attr(STM32MP1_SHRES_I2C6)); ++ ++ if (!error) { ++ return; ++ } ++ ++ panic(); ++} ++ ++static void check_rcc_secure_configuration(void) ++{ ++ bool secure = stm32_rcc_is_secure(); ++ bool mckprot = stm32_rcc_is_mckprot(); ++ unsigned int n; ++ unsigned int error = 0; ++ ++ for (n = 0; n < ARRAY_SIZE(shres_state); n++) { ++ if ((shres_state[n] == SHRES_SECURE) || ++ (shres_state[n] == SHRES_SHARED)) { ++ if ((mckprot_resource(n) && (!mckprot)) || !secure) { ++ EMSG("RCC %s MCKPROT %s and %s (%u) secure", ++ secure ? "secure" : "non secure", ++ mckprot ? "set" : "not set", ++ shres2str_id(n), n); ++ error++; ++ } ++ } ++ } ++ ++ if (error != 0U) { ++ panic(); ++ } ++} ++ ++static void gpio_secure_suspend_resume(enum pm_op op, void __unused *handle) ++{ ++ unsigned int pin; ++ ++ switch (op) { ++ case PM_OP_SUSPEND: ++ return; ++ case PM_OP_RESUME: ++ break; ++ default: ++ panic(); ++ } ++ ++ /* Release secure hardening of non secure pins at resume */ ++ for (pin = 0; pin < get_gpioz_nbpin_unpg(); pin++) { ++ unsigned int id = STM32MP1_SHRES_GPIOZ(pin); ++ ++ if (stm32mp_periph_is_non_secure(id) || ++ stm32mp_periph_is_unregistered(id)) { ++ stm32_gpio_set_secure_cfg(GPIO_BANK_Z, pin, false); ++ } ++ } ++} ++KEEP_PAGER(gpio_secure_suspend_resume); ++ ++static void check_gpio_secure_configuration(void) ++{ ++ unsigned int pin; ++ bool secure; ++ ++ for (pin = 0; pin < get_gpioz_nbpin(); pin++) { ++ secure = stm32mp_periph_is_secure(STM32MP1_SHRES_GPIOZ(pin)); ++ stm32_gpio_set_secure_cfg(GPIO_BANK_Z, pin, secure); ++ } ++ ++ stm32mp_register_pm_cb(gpio_secure_suspend_resume, NULL); ++} ++ ++static TEE_Result stm32mp1_init_drivers(void) ++{ ++ size_t id; ++ ++ registering_locked = true; ++ ++ for (id = 0; id < STM32MP1_SHRES_COUNT; id++) { ++ uint8_t *state = &shres_state[id]; ++ ++#if TRACE_LEVEL == TRACE_INFO ++ /* Display only the secure and shared resources */ ++ if ((*state == SHRES_NON_SECURE) || ++ ((*state == SHRES_UNREGISTERED))) { ++ continue; ++ } ++#endif ++ ++ IMSG("stm32mp %-8s (%2u): %-14s", ++ shres2str_id(id), id, shres2str_state(*state)); ++ } ++ ++ stm32mp_update_earlyboot_clocks_state(); ++ ++ check_rcc_secure_configuration(); ++ check_etzpc_secure_configuration(); ++ check_gpio_secure_configuration(); ++ ++ return TEE_SUCCESS; ++} ++driver_init_late(stm32mp1_init_drivers); +diff --git a/core/arch/arm/plat-stm32mp1/stm32_util.h b/core/arch/arm/plat-stm32mp1/stm32_util.h +new file mode 100644 +index 0000000..0164855 +--- /dev/null ++++ b/core/arch/arm/plat-stm32mp1/stm32_util.h +@@ -0,0 +1,287 @@ ++/* SPDX-License-Identifier: BSD-3-Clause */ ++/* ++ * Copyright (c) 2017-2018, STMicroelectronics ++ */ ++ ++#ifndef __STM32_UTIL_H__ ++#define __STM32_UTIL_H__ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* SoC versioning */ ++uint32_t stm32mp1_dbgmcu_get_chip_version(void); ++ ++/* SiP & OEM platform services */ ++bool stm32_sip_service(struct sm_ctx *ctx, ++ uint32_t *a0, uint32_t *a1, uint32_t *a2, uint32_t *a3); ++bool stm32_oem_service(struct sm_ctx *ctx, ++ uint32_t *a0, uint32_t *a1, uint32_t *a2, uint32_t *a3); ++ ++ ++/* Platform util for the STGEN driver */ ++uintptr_t stm32_get_stgen_base(void); ++ ++/* Platform util for the GIC */ ++uintptr_t get_gicc_base(void); ++uintptr_t get_gicd_base(void); ++ ++/* Platform util for clock gating. ID refers to clock DT bindings ID. */ ++void stm32_clock_enable(unsigned long id); ++void stm32_clock_disable(unsigned long id); ++ ++static inline unsigned long stm32_clock_get_rate(unsigned long id) ++{ ++ return stm32mp1_clk_get_rate(id); ++} ++ ++static inline unsigned long stm32_clock_is_enabled(unsigned long id) ++{ ++ return stm32mp1_clk_is_enabled(id); ++} ++ ++/* Platform util for the GPIO driver */ ++uintptr_t stm32_get_gpio_bank_base(unsigned int bank); ++uint32_t stm32_get_gpio_bank_offset(unsigned int bank); ++int stm32_get_gpio_bank_clock(unsigned int bank); ++ ++/* Platform util for the IWDG driver */ ++unsigned long stm32_get_iwdg_otp_config(uintptr_t pbase); ++int stm32mp_iwdg_irq2instance(size_t irq); ++size_t stm32mp_iwdg_instance2irq(int instance); ++unsigned int stm32mp_iwdg_iomem2instance(uintptr_t pbase); ++ ++/* Platform util for the BSEC driver */ ++unsigned int stm32mp_get_otp_max(void); ++unsigned int stm32mp_get_otp_upper_start(void); ++ ++/* Platform util for the ETZPC driver */ ++uintptr_t stm32mp_get_etzpc_base(void); ++enum etzpc_decprot_attributes stm32mp_etzpc_binding2decprot(uint32_t mode); ++ ++/* Platform util for the RTC driver */ ++bool stm32_rtc_get_read_twice(void); ++ ++/* Backup registers and RAM utils */ ++uintptr_t stm32mp_bkpreg(unsigned int idx); ++ ++uintptr_t stm32mp1_bkpsram_base(void); ++ ++/* Platform util for PMIC support */ ++bool stm32mp_with_pmic(void); ++ ++/* Power management service */ ++void stm32mp_register_online_cpu(void); ++ ++/* ++ * Lock/unlock access to shared registers ++ * ++ * @lock - NULL or pointer to spin lock ++ */ ++uint32_t lock_stm32shregs(void); ++void unlock_stm32shregs(uint32_t exceptions); ++ ++void io_mask32_stm32shregs(uintptr_t va, uint32_t value, uint32_t mask); ++ ++static inline void stm32shregs_setbits(uintptr_t va, uint32_t value) ++{ ++ io_mask32_stm32shregs(va, value, value); ++} ++ ++static inline void stm32shregs_clrbits(uintptr_t va, uint32_t value) ++{ ++ io_mask32_stm32shregs(va, 0, value); ++} ++ ++static inline void stm32shregs_clrsetbits(uintptr_t va, uint32_t mask, ++ uint32_t value) ++{ ++ io_mask32_stm32shregs(va, value, mask); ++} ++ ++/* ++ * Generic spinlock function that bypass spinlock if MMU is disabled or ++ * lock is NULL. ++ */ ++uint32_t may_spin_lock(unsigned int *lock); ++void may_spin_unlock(unsigned int *lock, uint32_t exceptions); ++ ++/* Reset function for early watchdog management */ ++void stm32mp_platform_reset(int cpu); ++ ++/* Clock calibration */ ++int stm32mp_start_clock_calib(unsigned int clock_id); ++ ++/* ++ * 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 ++ * non-secure decrement request. These counter initializes to ++ * either 0, 1 or 2 upon their expect default state. ++ * Increment refcount and return if incremented from 0. ++ * Counters saturates once above UINT_MAX / 2. ++ */ ++#define SHREFCNT_NONSECURE_FLAG 0x1ul ++#define SHREFCNT_SECURE_STEP 0x2ul ++#define SHREFCNT_MAX (UINT_MAX / 2) ++ ++/* Return 1 if refcnt decrements to 0, else return 0 */ ++static inline int incr_shrefcnt(unsigned int *refcnt, bool secure) ++{ ++ int rc = !*refcnt; ++ ++ if (secure) { ++ if (*refcnt < SHREFCNT_MAX) { ++ *refcnt += SHREFCNT_SECURE_STEP; ++ assert(*refcnt < SHREFCNT_MAX); ++ } ++ } else { ++ *refcnt |= SHREFCNT_NONSECURE_FLAG; ++ } ++ ++ return rc; ++} ++ ++/* Return 1 if refcnt decrements to 0, else return 0 */ ++static inline int decr_shrefcnt(unsigned int *refcnt, bool secure) ++{ ++ int rc = 0; ++ ++ if (secure) { ++ if (*refcnt < SHREFCNT_MAX) { ++ if (*refcnt < SHREFCNT_SECURE_STEP) { ++ panic(); ++ } ++ ++ *refcnt -= SHREFCNT_SECURE_STEP; ++ rc = !*refcnt; ++ } ++ } else { ++ rc = (*refcnt == SHREFCNT_NONSECURE_FLAG); ++ *refcnt &= ~SHREFCNT_NONSECURE_FLAG; ++ } ++ ++ return rc; ++} ++ ++static inline int incr_refcnt(unsigned int *refcnt) ++{ ++ return incr_shrefcnt(refcnt, true); ++} ++ ++static inline int decr_refcnt(unsigned int *refcnt) ++{ ++ return decr_shrefcnt(refcnt, true); ++} ++ ++#define STM32MP1_SHRES_GPIOZ(i) (STM32MP1_SHRES_GPIOZ_0 + i) ++ ++enum stm32mp_shres { ++ STM32MP1_SHRES_GPIOZ_0 = 0, ++ STM32MP1_SHRES_GPIOZ_1, ++ STM32MP1_SHRES_GPIOZ_2, ++ STM32MP1_SHRES_GPIOZ_3, ++ STM32MP1_SHRES_GPIOZ_4, ++ STM32MP1_SHRES_GPIOZ_5, ++ STM32MP1_SHRES_GPIOZ_6, ++ STM32MP1_SHRES_GPIOZ_7, ++ STM32MP1_SHRES_IWDG1, ++ STM32MP1_SHRES_USART1, ++ STM32MP1_SHRES_SPI6, ++ STM32MP1_SHRES_I2C4, ++ STM32MP1_SHRES_RNG1, ++ STM32MP1_SHRES_HASH1, ++ STM32MP1_SHRES_CRYP1, ++ STM32MP1_SHRES_I2C6, ++ STM32MP1_SHRES_RTC, ++ STM32MP1_SHRES_MCU, ++ STM32MP1_SHRES_HSI, ++ STM32MP1_SHRES_LSI, ++ STM32MP1_SHRES_HSE, ++ STM32MP1_SHRES_LSE, ++ STM32MP1_SHRES_CSI, ++ STM32MP1_SHRES_PLL1, ++ STM32MP1_SHRES_PLL1_P, ++ STM32MP1_SHRES_PLL1_Q, ++ STM32MP1_SHRES_PLL1_R, ++ STM32MP1_SHRES_PLL2, ++ STM32MP1_SHRES_PLL2_P, ++ STM32MP1_SHRES_PLL2_Q, ++ STM32MP1_SHRES_PLL2_R, ++ STM32MP1_SHRES_PLL3, ++ STM32MP1_SHRES_PLL3_P, ++ STM32MP1_SHRES_PLL3_Q, ++ STM32MP1_SHRES_PLL3_R, ++ ++ STM32MP1_SHRES_COUNT ++}; ++ ++void stm32mp_register_secure_periph(unsigned int id); ++void stm32mp_register_shared_periph(unsigned int id); ++void stm32mp_register_non_secure_periph(unsigned int id); ++void stm32mp_register_secure_periph_iomem(uintptr_t base); ++void stm32mp_register_non_secure_periph_iomem(uintptr_t base); ++void stm32mp_register_secure_gpio(unsigned int bank, unsigned int pin); ++void stm32mp_register_non_secure_gpio(unsigned int bank, unsigned int pin); ++void stm32mp_register_etzpc_decprot(unsigned int id, ++ enum etzpc_decprot_attributes attr); ++ ++bool stm32mp_periph_is_shared(unsigned long id); ++bool stm32mp_periph_is_non_secure(unsigned long id); ++bool stm32mp_periph_is_secure(unsigned long id); ++bool stm32mp_periph_is_unregistered(unsigned long id); ++ ++bool stm32mp_gpio_bank_is_shared(unsigned int bank); ++bool stm32mp_gpio_bank_is_non_secure(unsigned int bank); ++bool stm32mp_gpio_bank_is_secure(unsigned int bank); ++ ++bool stm32mp_clock_is_shareable(unsigned long clock_id); ++bool stm32mp_clock_is_shared(unsigned long clock_id); ++bool stm32mp_clock_is_non_secure(unsigned long clock_id); ++ ++/* ++ * Set bit fields, clear bit flieds, clear bits and set bits utils ++ */ ++static inline void mmio_write_8(uintptr_t addr, uint8_t value) ++{ ++ write8(value, addr); ++} ++ ++static inline uint8_t mmio_read_8(uintptr_t addr) ++{ ++ return read8(addr); ++} ++ ++static inline void mmio_write_32(uintptr_t addr, uint32_t value) ++{ ++ write32(value, addr); ++} ++ ++static inline uint32_t mmio_read_32(uintptr_t addr) ++{ ++ return read32(addr); ++} ++ ++static inline void mmio_setbits_32(uintptr_t addr, uint32_t mask) ++{ ++ write32(read32(addr) | mask, addr); ++} ++ ++static inline void mmio_clrbits_32(uintptr_t addr, uint32_t mask) ++{ ++ write32(read32(addr) & ~mask, addr); ++} ++ ++static inline void mmio_clrsetbits_32(uintptr_t addr, uint32_t clear_mask, ++ uint32_t set_mask) ++{ ++ write32((read32(addr) & ~clear_mask) | set_mask, addr); ++} ++ ++#endif /*__STM32_UTIL_H__*/ +diff --git a/core/arch/arm/plat-stm32mp1/stm32mp1_dt.c b/core/arch/arm/plat-stm32mp1/stm32mp1_dt.c +new file mode 100644 +index 0000000..9ce6ba8 +--- /dev/null ++++ b/core/arch/arm/plat-stm32mp1/stm32mp1_dt.c +@@ -0,0 +1,338 @@ ++// SPDX-License-Identifier: BSD-3-Clause ++/* ++ * Copyright (c) 2018, STMicroelectronics - All Rights Reserved ++ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/******************************************************************************* ++ * This function check the presence of a node (generic use of fdt library). ++ * Returns true if present else returns false. ++ ******************************************************************************/ ++bool fdt_check_node(void *fdt, int node) ++{ ++ int len; ++ const char *cchar; ++ ++ cchar = fdt_get_name(fdt, node, &len); ++ ++ return (cchar != NULL) && (len >= 0); ++} ++ ++/******************************************************************************* ++ * This function reads a value of a node property (generic use of fdt ++ * library). ++ * Returns value if success, and a default value if property not found. ++ * Default value is passed as parameter. ++ ******************************************************************************/ ++uint32_t fdt_read_uint32_default(void *fdt, int node, const char *prop_name, ++ uint32_t dflt_value) ++{ ++ const fdt32_t *cuint; ++ int lenp; ++ ++ cuint = fdt_getprop(fdt, node, prop_name, &lenp); ++ if (cuint == NULL) { ++ return dflt_value; ++ } ++ ++ return fdt32_to_cpu(*cuint); ++} ++ ++/******************************************************************************* ++ * This function reads a series of parameters in a node property ++ * (generic use of fdt library). ++ * It reads the values inside the device tree, from property name and node. ++ * The number of parameters is also indicated as entry parameter. ++ * Returns 0 if success, and a negative value else. ++ * If success, values are stored at the third parameter address. ++ ******************************************************************************/ ++int fdt_read_uint32_array(void *fdt, int node, const char *prop_name, ++ uint32_t *array, uint32_t count) ++{ ++ const fdt32_t *cuint; ++ int len; ++ uint32_t i; ++ ++ cuint = fdt_getprop(fdt, node, prop_name, &len); ++ if (cuint == NULL) { ++ return -FDT_ERR_NOTFOUND; ++ } ++ ++ if ((uint32_t)len != (count * sizeof(uint32_t))) { ++ return -FDT_ERR_BADLAYOUT; ++ } ++ ++ for (i = 0; i < ((uint32_t)len / sizeof(uint32_t)); i++) { ++ *array = fdt32_to_cpu(*cuint); ++ array++; ++ cuint++; ++ } ++ ++ return 0; ++} ++ ++/******************************************************************************* ++ * This function gets the clock ID of the given node. ++ * It reads the value indicated inside the device tree. ++ * Returns ID on success and a negative FDT error code on failure. ++ ******************************************************************************/ ++int fdt_get_clock_id(void *fdt, int node) ++{ ++ const fdt32_t *cuint; ++ ++ cuint = fdt_getprop(fdt, node, "clocks", NULL); ++ if (cuint == NULL) { ++ return -FDT_ERR_NOTFOUND; ++ } ++ ++ cuint++; ++ return (int)fdt32_to_cpu(*cuint); ++} ++ ++/******************************************************************************* ++ * This function gets the clock ID of the given node using clock-names. ++ * It reads the value indicated inside the device tree. ++ * Returns ID on success and a negative FDT error code on failure. ++ ******************************************************************************/ ++int fdt_get_clock_id_by_name(void *fdt, int node, const char *name) ++{ ++ const fdt32_t *cuint; ++ int index; ++ int len; ++ ++ index = fdt_stringlist_search(fdt, node, "clock-names", name); ++ if (index < 0) { ++ return index; ++ } ++ ++ cuint = fdt_getprop(fdt, node, "clocks", &len); ++ if (cuint == NULL) { ++ return -FDT_ERR_NOTFOUND; ++ } ++ ++ if ((index * (int)sizeof(uint32_t)) > len) { ++ return -FDT_ERR_BADVALUE; ++ } ++ ++ cuint += (index << 1) + 1; ++ return (int)fdt32_to_cpu(*cuint); ++} ++ ++/******************************************************************************* ++ * This function fills the generic information from a given node. ++ ******************************************************************************/ ++void fdt_fill_device_info(void *fdt, struct dt_node_info *info, int node) ++{ ++ const fdt32_t *cuint; ++ ++ cuint = fdt_getprop(fdt, node, "reg", NULL); ++ if (cuint != NULL) { ++ info->base = fdt32_to_cpu(*cuint); ++ } else { ++ info->base = 0; ++ } ++ ++ cuint = fdt_getprop(fdt, node, "clocks", NULL); ++ if (cuint != NULL) { ++ cuint++; ++ info->clock = (int)fdt32_to_cpu(*cuint); ++ } else { ++ info->clock = -1; ++ } ++ ++ cuint = fdt_getprop(fdt, node, "resets", NULL); ++ if (cuint != NULL) { ++ cuint++; ++ info->reset = (int)fdt32_to_cpu(*cuint); ++ } else { ++ info->reset = -1; ++ } ++ ++ info->status = _fdt_get_status(fdt, node); ++} ++ ++/******************************************************************************* ++ * This function retrieve the generic information from DT. ++ * Returns node if success, and a negative value else. ++ ******************************************************************************/ ++int fdt_get_node(void *fdt, struct dt_node_info *info, int offset, ++ const char *compat) ++{ ++ int node; ++ ++ node = fdt_node_offset_by_compatible(fdt, offset, compat); ++ if (node < 0) { ++ return -FDT_ERR_NOTFOUND; ++ } ++ ++ fdt_fill_device_info(fdt, info, node); ++ ++ return node; ++} ++ ++/******************************************************************************* ++ * This function gets the stdout path node. ++ * It reads the value indicated inside the device tree. ++ * Returns node on success and a negative FDT error code on failure. ++ ******************************************************************************/ ++int fdt_get_stdout_node_offset(void *fdt) ++{ ++ int node; ++ const char *cchar; ++ ++ node = fdt_path_offset(fdt, "/secure-chosen"); ++ if (node < 0) { ++ node = fdt_path_offset(fdt, "/chosen"); ++ if (node < 0) { ++ return -FDT_ERR_NOTFOUND; ++ } ++ } ++ ++ cchar = fdt_getprop(fdt, node, "stdout-path", NULL); ++ if (cchar == NULL) { ++ return -FDT_ERR_NOTFOUND; ++ } ++ ++ node = -FDT_ERR_NOTFOUND; ++ if (strchr(cchar, (int)':') != NULL) { ++ const char *name; ++ char *str = (char *)cchar; ++ int len = 0; ++ ++ while (strncmp(":", str, 1)) { ++ len++; ++ str++; ++ } ++ ++ name = fdt_get_alias_namelen(fdt, cchar, len); ++ ++ if (name != NULL) { ++ node = fdt_path_offset(fdt, name); ++ } ++ } else { ++ node = fdt_path_offset(fdt, cchar); ++ } ++ ++ return node; ++} ++ ++/******************************************************************************* ++ * This function gets DDR size information from the DT. ++ * Returns value in bytes if success, and STM32MP1_DDR_SIZE_DFLT else. ++ ******************************************************************************/ ++uint32_t fdt_get_ddr_size(void *fdt) ++{ ++ int node; ++ ++ node = fdt_node_offset_by_compatible(fdt, -1, DT_DDR_COMPAT); ++ if (node < 0) { ++ IMSG("%s: Cannot read DDR node in DT\n", __func__); ++ return STM32MP1_DDR_SIZE_DFLT; ++ } ++ ++ return fdt_read_uint32_default(fdt, node, "st,mem-size", ++ STM32MP1_DDR_SIZE_DFLT); ++} ++ ++/******************************************************************************* ++ * This function retrieves board model from DT. ++ * Returns string taken from model node, NULL otherwise ++ ******************************************************************************/ ++const char *fdt_get_board_model(void *fdt) ++{ ++ int node = fdt_path_offset(fdt, "/"); ++ ++ if (node < 0) { ++ return NULL; ++ } ++ ++ return (const char *)fdt_getprop(fdt, node, "model", NULL); ++} ++ ++/******************************************************************************* ++ * This function gets GPIO bank PINCTRL node information from the DT. ++ * Returns node value. ++ ******************************************************************************/ ++int fdt_get_gpio_bank_pinctrl_node(void *fdt, unsigned int bank) ++{ ++ switch (bank) { ++ case GPIO_BANK_A: ++ case GPIO_BANK_B: ++ case GPIO_BANK_C: ++ case GPIO_BANK_D: ++ case GPIO_BANK_E: ++ case GPIO_BANK_F: ++ case GPIO_BANK_G: ++ case GPIO_BANK_H: ++ case GPIO_BANK_I: ++ case GPIO_BANK_J: ++ case GPIO_BANK_K: ++ return fdt_path_offset(fdt, "/soc/pin-controller"); ++ case GPIO_BANK_Z: ++ return fdt_path_offset(fdt, "/soc/pin-controller-z"); ++ default: ++ panic(); ++ } ++} ++ ++/******************************************************************************* ++ * This function gets GPIOZ pin number information from the DT. ++ * It also checks node consistency. ++ ******************************************************************************/ ++int fdt_get_gpioz_nbpins_from_dt(void *fdt) ++{ ++ int pinctrl_node; ++ int pinctrl_subnode; ++ ++ pinctrl_node = fdt_get_gpio_bank_pinctrl_node(fdt, GPIO_BANK_Z); ++ if (pinctrl_node < 0) { ++ return -FDT_ERR_NOTFOUND; ++ } ++ ++ fdt_for_each_subnode(pinctrl_subnode, fdt, pinctrl_node) { ++ uint32_t bank_offset; ++ const fdt32_t *cuint; ++ ++ if (fdt_getprop(fdt, pinctrl_subnode, ++ "gpio-controller", NULL) == NULL) { ++ continue; ++ } ++ ++ cuint = fdt_getprop(fdt, pinctrl_subnode, "reg", NULL); ++ if (cuint == NULL) { ++ continue; ++ } ++ ++ bank_offset = stm32_get_gpio_bank_offset(GPIO_BANK_Z); ++ if (fdt32_to_cpu(*cuint) != bank_offset) { ++ continue; ++ } ++ ++ if (_fdt_get_status(fdt, pinctrl_subnode) == ++ DT_STATUS_DISABLED) { ++ return 0; ++ } ++ ++ cuint = fdt_getprop(fdt, pinctrl_subnode, "ngpios", NULL); ++ if (cuint == NULL) { ++ return -FDT_ERR_NOTFOUND; ++ } ++ ++ return (int)fdt32_to_cpu(*cuint); ++ } ++ ++ return 0; ++} +diff --git a/core/arch/arm/plat-stm32mp1/stm32mp_dt.h b/core/arch/arm/plat-stm32mp1/stm32mp_dt.h +new file mode 100644 +index 0000000..ec8aa4d +--- /dev/null ++++ b/core/arch/arm/plat-stm32mp1/stm32mp_dt.h +@@ -0,0 +1,39 @@ ++/* SPDX-License-Identifier: BSD-3-Clause */ ++/* ++ * Copyright (c) 2018, STMicroelectronics - All Rights Reserved ++ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. ++ */ ++ ++#ifndef __STM32MP1_DT_H__ ++#define __STM32MP1_DT_H__ ++ ++#include ++#include ++ ++#define DT_DDR_COMPAT "st,stm32mp1-ddr" ++ ++struct dt_node_info { ++ uint32_t base; ++ int32_t clock; ++ int32_t reset; ++ unsigned int status; ++}; ++ ++bool fdt_check_node(void *fdt, int node); ++uint32_t fdt_read_uint32_default(void *fdt, int node, const char *prop_name, ++ uint32_t dflt_value); ++int fdt_read_uint32_array(void *fdt, int node, const char *prop_name, ++ uint32_t *array, uint32_t count); ++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); ++uint32_t fdt_get_ddr_size(void *fdt); ++const char *fdt_get_board_model(void *fdt); ++ ++int fdt_get_clock_id(void *fdt, int node); ++int fdt_get_clock_id_by_name(void *fdt, int node, const char *name); ++int fdt_get_gpio_bank_pinctrl_node(void *fdt, unsigned int bank); ++int fdt_get_gpioz_nbpins_from_dt(void *fdt); ++ ++#endif /* __STM32MP1_DT_H__ */ +diff --git a/core/arch/arm/plat-stm32mp1/stm32mp_pm.h b/core/arch/arm/plat-stm32mp1/stm32mp_pm.h +new file mode 100644 +index 0000000..8395ccc +--- /dev/null ++++ b/core/arch/arm/plat-stm32mp1/stm32mp_pm.h +@@ -0,0 +1,49 @@ ++/* SPDX-License-Identifier: BSD-2-Clause */ ++/* ++ * Copyright (c) 2017-2018, STMicroelectronics ++ */ ++#ifndef __STM32MP_PM_H__ ++#define __STM32MP_PM_H__ ++ ++#ifndef ASM ++ ++#include ++#include ++#include ++ ++#define PSCI_MODE_SYSTEM_SUSPEND 0 ++#define PSCI_MODE_SYSTEM_OFF 1 ++ ++enum stm32mp1_pm_domain { ++ STM32MP1_PD_VSW, ++ STM32MP1_PD_CORE_RET, ++ STM32MP1_PD_CORE, ++ STM32MP1_PD_MAX_PM_DOMAIN ++}; ++ ++enum pm_op { ++ PM_OP_SUSPEND, ++ PM_OP_RESUME, ++}; ++ ++/* ++ * Drivers can register a callback for the suspend and resume sequences and ++ * a private cookie passed as argument to the callback. ++ * The same callback is used for suspend and resume. First argument of the ++ * callback defines whether the device shall suspend or resume. ++ * ++ * Driver should tag its callback resource as unpaged (i.e KEEP_PAGER()) ++ * since the callback is called from an unpaged execution context. ++ */ ++void stm32mp_register_pm_cb(void (*callback)(enum pm_op op, void *handle), ++ void *handle); ++ ++void stm32_cores_reset(void); ++ ++void stm32mp_gic_suspend_resume(enum pm_op op); ++void stm32mp_clock_suspend_resume(enum pm_op op); ++ ++#endif /*ASM*/ ++ ++#endif /*__STM32MP_PM_H__*/ ++ +diff --git a/core/arch/arm/plat-stm32mp1/sub.mk b/core/arch/arm/plat-stm32mp1/sub.mk +index 4a559ea..c5a0deb 100644 +--- a/core/arch/arm/plat-stm32mp1/sub.mk ++++ b/core/arch/arm/plat-stm32mp1/sub.mk +@@ -2,3 +2,9 @@ global-incdirs-y += . + + srcs-y += main.c + srcs-y += reset.S ++srcs-y += shared_resources.c ++srcs-$(CFG_DT) += stm32mp1_dt.c ++ ++subdirs-y += service ++subdirs-y += drivers ++subdirs-y += pm +diff --git a/core/arch/arm/sm/pm_a32.S b/core/arch/arm/sm/pm_a32.S +index 9421b2d..8a59cd2 100644 +--- a/core/arch/arm/sm/pm_a32.S ++++ b/core/arch/arm/sm/pm_a32.S +@@ -69,25 +69,30 @@ a9_suspend: + a7_suspend: + read_fcseidr r4 + read_tpidruro r5 +- stmia r0!, {r4 - r5} +- read_dacr r4 ++ read_dacr r6 ++ stmia r0!, {r4 - r6} + #ifdef CFG_WITH_LPAE +-#error "Not supported" ++ read_ttbr0_64bit r4, r5 ++ read_ttbr1_64bit r6, r7 ++ read_mair0 r8 ++ read_mair1 r9 ++ stmia r0!, {r4 - r9} + #else +- read_ttbr0 r5 +- read_ttbr1 r6 +- read_ttbcr r7 ++ read_ttbr0 r4 ++ read_ttbr1 r5 ++ read_prrr r6 ++ read_nmrr r7 ++ stmia r0!, {r4 - r7} + #endif +- read_sctlr r8 +- read_actlr r9 +- read_cpacr r10 +- read_mvbar r11 +- stmia r0!, {r4 - r11} +- read_prrr r4 +- read_nmrr r5 +- read_vbar r6 +- read_nsacr r7 +- stmia r0, {r4 - r7} ++ read_ttbcr r4 ++ read_actlr r5 ++ read_cpacr r6 ++ read_mvbar r7 ++ read_vbar r8 ++ read_nsacr r9 ++ read_sctlr r10 ++ stmia r0, {r4 - r10} ++ + pop {r4 - r11} + bx lr + UNWIND( .fnend) +@@ -154,50 +159,50 @@ UNWIND( .cantunwind) + cmp r5, r4 + beq a7_resume + +- /* +- * A9 needs PCR/DIAG +- */ ++ /* A9 needs PCR/DIAG */ + ldmia r0!, {r4 - r5} + write_pcr r4 + write_diag r5 +- + a7_resume: +- /* v7 resume */ ++ /* Armv7 generic resume */ + mov ip, #0 + /* Invalidate icache to PoU */ + write_iciallu + /* set reserved context */ + write_contextidr ip +- ldmia r0!, {r4 - r5} ++ ldmia r0!, {r4 - r6} + write_fcseidr r4 + write_tpidruro r5 +- ldmia r0!, {r4 - r11} + /* Invalidate entire TLB */ + write_tlbiall +- write_dacr r4 ++ write_dacr r6 + #ifdef CFG_WITH_LPAE +-#error "Not supported -" ++ ldmia r0!, {r4 - r9} ++ write_ttbr0_64bit r4, r5 ++ write_ttbr1_64bit r6, r7 ++ write_mair0 r8 ++ write_mair1 r9 + #else +- write_ttbr0 r5 +- write_ttbr1 r6 +- write_ttbcr r7 ++ ldmia r0!, {r4 - r7} ++ write_ttbr0 r4 ++ write_ttbr1 r5 ++ write_prrr r6 ++ write_nmrr r7 + #endif +- +- ldmia r0, {r4 - r7} +- write_prrr r4 +- write_nmrr r5 +- write_vbar r6 +- write_nsacr r7 +- +- write_actlr r9 +- write_cpacr r10 +- write_mvbar r11 ++ ldmia r0!, {r4 - r10} ++ write_ttbcr r4 ++ write_actlr r5 ++ write_cpacr r6 ++ write_mvbar r7 ++ write_vbar r8 ++ write_nsacr r9 + write_bpiall + isb + dsb + /* MMU will be enabled here */ +- write_sctlr r8 ++ write_sctlr r10 + isb ++ + mov r0, #0 + b suspend_return + UNWIND( .fnend) +diff --git a/core/arch/arm/tee/entry_std.c b/core/arch/arm/tee/entry_std.c +index 92fdf0f..e0836ed 100644 +--- a/core/arch/arm/tee/entry_std.c ++++ b/core/arch/arm/tee/entry_std.c +@@ -602,4 +602,4 @@ static TEE_Result default_mobj_init(void) + return TEE_SUCCESS; + } + +-driver_init_late(default_mobj_init); ++service_init(default_mobj_init); +diff --git a/core/drivers/gic.c b/core/drivers/gic.c +index 9baffee..a000bff 100644 +--- a/core/drivers/gic.c ++++ b/core/drivers/gic.c +@@ -1,5 +1,6 @@ + // SPDX-License-Identifier: BSD-2-Clause + /* ++ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2016-2017, Linaro Limited + * Copyright (c) 2014, STMicroelectronics International N.V. + */ +@@ -7,12 +8,14 @@ + #include + #include + #include ++#include + #include + #include + #include ++#include + #include +-#include + #include ++#include + + /* Offsets from gic.gicc_base */ + #define GICC_CTLR (0x000) +@@ -32,8 +35,12 @@ + #define GICD_ICENABLER(n) (0x180 + (n) * 4) + #define GICD_ISPENDR(n) (0x200 + (n) * 4) + #define GICD_ICPENDR(n) (0x280 + (n) * 4) ++#define GICD_ISACTIVER(n) (0x300 + (n) * 4) ++#define GICD_ICACTIVER(n) (0x380 + (n) * 4) + #define GICD_IPRIORITYR(n) (0x400 + (n) * 4) + #define GICD_ITARGETSR(n) (0x800 + (n) * 4) ++#define GICD_ICFGR(n) (0xC00 + (n) * 4) ++#define GICD_NSACR(n) (0xE00 + (n) * 4) + #define GICD_SGIR (0xF00) + + #define GICD_CTLR_ENABLEGRP0 (1 << 0) +@@ -74,6 +81,12 @@ static void gic_op_raise_sgi(struct itr_chip *chip, size_t it, + static void gic_op_set_affinity(struct itr_chip *chip, size_t it, + uint8_t cpu_mask); + ++#if !defined(CFG_ARM_GICV3) ++static uint8_t gic_op_set_pmr(struct itr_chip *chip, uint8_t mask); ++static uint8_t gic_op_set_ipriority(struct itr_chip *chip, size_t it, ++ uint8_t mask); ++#endif ++ + static const struct itr_ops gic_ops = { + .add = gic_op_add, + .enable = gic_op_enable, +@@ -81,6 +94,10 @@ static const struct itr_ops gic_ops = { + .raise_pi = gic_op_raise_pi, + .raise_sgi = gic_op_raise_sgi, + .set_affinity = gic_op_set_affinity, ++#if !defined(CFG_ARM_GICV3) ++ .set_pmr = gic_op_set_pmr, ++ .set_ipriority = gic_op_set_ipriority, ++#endif + }; + KEEP_PAGER(gic_ops); + +@@ -146,11 +163,11 @@ void gic_cpu_init(struct gic_data *gd) + * allow the Non-secure world to adjust the priority mask itself + */ + #if defined(CFG_ARM_GICV3) +- write_icc_pmr(0x80); ++ write_icc_pmr(GIC_HIGHEST_NS_PRIORITY); + write_icc_ctlr(GICC_CTLR_ENABLEGRP0 | GICC_CTLR_ENABLEGRP1 | + GICC_CTLR_FIQEN); + #else +- write32(0x80, gd->gicc_base + GICC_PMR); ++ write32(GIC_HIGHEST_NS_PRIORITY, gd->gicc_base + GICC_PMR); + + /* Enable GIC */ + write32(GICC_CTLR_ENABLEGRP0 | GICC_CTLR_ENABLEGRP1 | GICC_CTLR_FIQEN, +@@ -189,11 +206,11 @@ void gic_init(struct gic_data *gd, vaddr_t gicc_base __maybe_unused, + * allow the Non-secure world to adjust the priority mask itself + */ + #if defined(CFG_ARM_GICV3) +- write_icc_pmr(0x80); ++ write_icc_pmr(GIC_HIGHEST_NS_PRIORITY); + write_icc_ctlr(GICC_CTLR_ENABLEGRP0 | GICC_CTLR_ENABLEGRP1 | + GICC_CTLR_FIQEN); + #else +- write32(0x80, gd->gicc_base + GICC_PMR); ++ write32(GIC_HIGHEST_NS_PRIORITY, gd->gicc_base + GICC_PMR); + + /* Enable GIC */ + write32(GICC_CTLR_ENABLEGRP0 | GICC_CTLR_ENABLEGRP1 | GICC_CTLR_FIQEN, +@@ -254,9 +271,20 @@ static void gic_it_set_prio(struct gic_data *gd, size_t it, uint8_t prio) + { + size_t idx __maybe_unused = it / NUM_INTS_PER_REG; + uint32_t mask __maybe_unused = 1 << (it % NUM_INTS_PER_REG); ++ bool group0 = ((read32(gd->gicd_base + GICD_IGROUPR(idx)) & mask) == 0); + +- /* Assigned to group0 */ +- assert(!(read32(gd->gicd_base + GICD_IGROUPR(idx)) & mask)); ++ /* ++ * Check priority against ARM recommendation: Group1 interrupts always ++ * have a lower priority than group0 interrupts. ++ * Note, lower numerical values have higher priorities so the comparison ++ * checks below are reversed from what might be expected. ++ */ ++ if (group0) { ++ assert(prio <= GIC_LOWEST_SEC_PRIORITY); ++ } else { ++ assert(prio >= GIC_HIGHEST_NS_PRIORITY && ++ prio <= GIC_LOWEST_NS_PRIORITY); ++ } + + /* Set prio it to selected CPUs */ + DMSG("prio: writing 0x%x to 0x%" PRIxVA, +@@ -264,6 +292,34 @@ static void gic_it_set_prio(struct gic_data *gd, size_t it, uint8_t prio) + write8(prio, gd->gicd_base + GICD_IPRIORITYR(0) + it); + } + ++static uint8_t gic_op_set_pmr(struct itr_chip *chip, uint8_t mask) ++{ ++ struct gic_data *gd = container_of(chip, struct gic_data, chip); ++ uint32_t pmr = read32(gd->gicc_base + GICC_PMR); ++ ++ /* ++ * Order memory updates w.r.t. PMR write, and ensure they're visible ++ * before potential out of band interrupt trigger because of PMR update. ++ */ ++ dsb_ishst(); ++ write32(mask, gd->gicc_base + GICC_PMR); ++ dsb_ishst(); ++ ++ return (uint8_t)pmr; ++} ++ ++static uint8_t gic_op_set_ipriority(struct itr_chip *chip, size_t it, ++ uint8_t mask) ++{ ++ struct gic_data *gd = container_of(chip, struct gic_data, chip); ++ uint8_t prio = read8(gd->gicd_base + GICD_IPRIORITYR(0) + it); ++ ++ gic_it_set_prio(gd, it, mask); ++ ++ return prio; ++} ++ ++ + static void gic_it_enable(struct gic_data *gd, size_t it) + { + size_t idx = it / NUM_INTS_PER_REG; +@@ -472,3 +528,143 @@ static void gic_op_set_affinity(struct itr_chip *chip, size_t it, + + gic_it_set_cpu_mask(gd, it, cpu_mask); + } ++ ++#define IT_PM_GPOUP1_BIT BIT(0) ++#define IT_PM_ENABLE_BIT BIT(1) ++#define IT_PM_PENDING_BIT BIT(2) ++#define IT_PM_ACTIVE_BIT BIT(3) ++#define IT_PM_CONFIG_MASK GENMASK_32(1, 0) ++ ++struct gic_it_pm { ++ uint16_t it; ++ uint8_t flags; ++ uint8_t iprio; ++ uint8_t itarget; ++ uint8_t icfg; ++}; ++ ++static void gic_save_it(struct gic_data *gd, ++ unsigned int it, struct gic_it_pm *pm) ++{ ++ size_t idx; ++ uint32_t bit_mask = BIT(it % NUM_INTS_PER_REG); ++ uint32_t shift2 = it % (NUM_INTS_PER_REG / 2); ++ uint32_t shift8 = it % (NUM_INTS_PER_REG / 8); ++ uint32_t data32; ++ ++ assert(it < UINT16_MAX); ++ pm->it = (uint16_t)it; ++ ++ idx = it / NUM_INTS_PER_REG; ++ ++ pm->flags = 0; ++ if ((read32(gd->gicd_base + GICD_IGROUPR(idx)) & bit_mask) != 0) { ++ pm->flags |= IT_PM_GPOUP1_BIT; ++ } ++ if ((read32(gd->gicd_base + GICD_ISENABLER(idx)) & bit_mask) != 0) { ++ pm->flags |= IT_PM_ENABLE_BIT; ++ } ++ if ((read32(gd->gicd_base + GICD_ISPENDR(idx)) & bit_mask) != 0) { ++ pm->flags |= IT_PM_PENDING_BIT; ++ } ++ if ((read32(gd->gicd_base + GICD_ISACTIVER(idx)) & bit_mask) != 0) { ++ pm->flags |= IT_PM_ACTIVE_BIT; ++ } ++ ++ idx = (8 * it) / NUM_INTS_PER_REG; ++ ++ data32 = read32(gd->gicd_base + GICD_IPRIORITYR(idx)) >> shift8; ++ pm->iprio = (uint8_t)data32; ++ ++ data32 = read32(gd->gicd_base + GICD_ITARGETSR(idx)) >> shift8; ++ pm->itarget = (uint8_t)data32; ++ ++ /* Note: ICFGR is RAO for SPIs and PPIs */ ++ idx = (2 * it) / NUM_INTS_PER_REG; ++ data32 = read32(gd->gicd_base + GICD_ICFGR(idx)) >> shift2; ++ pm->icfg = (uint8_t)data32 & IT_PM_CONFIG_MASK; ++} ++ ++static void gic_restore_it(struct gic_data *gd, struct gic_it_pm *pm) ++{ ++ size_t idx; ++ unsigned int it = (unsigned int)pm->it; ++ uint32_t mask = BIT(it % NUM_INTS_PER_REG); ++ uint32_t shift2 = it % (NUM_INTS_PER_REG / 2); ++ uint32_t shift8 = it % (NUM_INTS_PER_REG / 8); ++ ++ idx = it / NUM_INTS_PER_REG; ++ ++ io_mask32(gd->gicd_base + GICD_IGROUPR(idx), ++ (pm->flags & IT_PM_GPOUP1_BIT) != 0 ? mask : 0, mask); ++ ++ io_mask32(gd->gicd_base + GICD_ISENABLER(idx), ++ (pm->flags & IT_PM_ENABLE_BIT) != 0 ? mask : 0, mask); ++ ++ io_mask32(gd->gicd_base + GICD_ISPENDR(idx), ++ (pm->flags & IT_PM_PENDING_BIT) != 0 ? mask : 0, mask); ++ ++ io_mask32(gd->gicd_base + GICD_ISACTIVER(idx), ++ (pm->flags & IT_PM_ACTIVE_BIT) != 0 ? mask : 0, mask); ++ ++ idx = (8 * it) / NUM_INTS_PER_REG; ++ ++ io_mask32(gd->gicd_base + GICD_IPRIORITYR(idx), ++ (uint32_t)pm->iprio << shift8, UINT8_MAX << shift8); ++ ++ io_mask32(gd->gicd_base + GICD_ITARGETSR(idx), ++ (uint32_t)pm->itarget << shift8, UINT8_MAX << shift8); ++ ++ /* Note: ICFGR is WI for SPIs and PPIs */ ++ idx = (2 * it) / NUM_INTS_PER_REG; ++ io_mask32(gd->gicd_base + GICD_ICFGR(idx), ++ (uint32_t)pm->icfg << shift2, IT_PM_CONFIG_MASK << shift2); ++} ++ ++static bool it_is_group0(struct gic_data *gd, unsigned int it) ++{ ++ size_t idx = it / NUM_INTS_PER_REG; ++ uint32_t groupr = read32(gd->gicd_base + GICD_IGROUPR(idx)); ++ uint32_t bit_mask = BIT(it % NUM_INTS_PER_REG); ++ ++ return (groupr & bit_mask) == 0; ++} ++ ++/* Save the configuration for interrupts in group0 only */ ++void gic_suspend(struct gic_data *gd) ++{ ++ struct gic_pm *pm = &gd->pm; ++ unsigned int n; ++ size_t count; ++ ++ for (count = 0, n = 0; n <= gd->max_it; n++) { ++ if (it_is_group0(gd, n)) { ++ count++; ++ } ++ } ++ pm->count = count; ++ ++ if (count == 0) { ++ return; ++ } ++ ++ pm->pm_cfg = realloc(pm->pm_cfg, count * sizeof(*pm->pm_cfg)); ++ assert(pm->pm_cfg != NULL); ++ ++ for (count = 0, n = 0; n <= gd->max_it; n++) { ++ if (it_is_group0(gd, n)) { ++ gic_save_it(gd, n, &pm->pm_cfg[count]); ++ count++; ++ } ++ } ++} ++ ++void gic_resume(struct gic_data *gd) ++{ ++ struct gic_pm *pm = &gd->pm; ++ size_t n; ++ ++ for (n = 0; n < pm->count; n++) { ++ gic_restore_it(gd, &pm->pm_cfg[n]); ++ } ++} +diff --git a/core/drivers/stm32_bsec.c b/core/drivers/stm32_bsec.c +new file mode 100644 +index 0000000..3355e0a +--- /dev/null ++++ b/core/drivers/stm32_bsec.c +@@ -0,0 +1,824 @@ ++// SPDX-License-Identifier: BSD-3-Clause ++/* ++ * Copyright (c) 2017-2018, STMicroelectronics ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#ifdef CFG_DT ++#include ++#endif ++ ++#define BSEC_COMPAT "st,stm32mp15-bsec" ++#define BITS_PER_WORD (CHAR_BIT * sizeof(uint32_t)) ++#define OTP_ACCESS_SIZE (ROUNDUP(OTP_MAX_SIZE, BITS_PER_WORD) / BITS_PER_WORD) ++ ++static uint32_t __maybe_unused otp_nsec_access[OTP_ACCESS_SIZE]; ++ ++static uint32_t bsec_power_safmem(bool enable); ++ ++/* Bsec access protection */ ++static unsigned int lock = SPINLOCK_UNLOCK; ++ ++static uint32_t bsec_lock(void) ++{ ++ return may_spin_lock(&lock); ++} ++ ++static void bsec_unlock(uint32_t exceptions) ++{ ++ may_spin_unlock(&lock, exceptions); ++} ++ ++#ifdef CFG_DT ++static int bsec_get_dt_node(void *fdt, struct dt_node_info *info) ++{ ++ int node; ++ ++ node = fdt_get_node(fdt, info, -1, BSEC_COMPAT); ++ if (node < 0) { ++ return -FDT_ERR_NOTFOUND; ++ } ++ ++ return node; ++} ++ ++static void enable_non_secure_access(uint32_t otp) ++{ ++ otp_nsec_access[otp / BITS_PER_WORD] |= BIT(otp % BITS_PER_WORD); ++ ++ if (bsec_shadow_register(otp) != BSEC_OK) { ++ panic(); ++ } ++} ++ ++static bool non_secure_can_access(uint32_t otp) ++{ ++ return (otp_nsec_access[otp / BITS_PER_WORD] & ++ BIT(otp % BITS_PER_WORD)) != 0; ++} ++ ++static int bsec_dt_otp_nsec_access(void *fdt, int bsec_node) ++{ ++ int bsec_subnode; ++ ++ fdt_for_each_subnode(bsec_subnode, fdt, bsec_node) { ++ const fdt32_t *cuint; ++ uint32_t reg; ++ uint32_t i; ++ uint32_t size; ++ uint8_t status; ++ ++ cuint = fdt_getprop(fdt, bsec_subnode, "reg", NULL); ++ if (cuint == NULL) { ++ panic(); ++ } ++ ++ reg = fdt32_to_cpu(*cuint) / sizeof(uint32_t); ++ if (reg < STM32MP1_UPPER_OTP_START) { ++ continue; ++ } ++ ++ status = _fdt_get_status(fdt, bsec_subnode); ++ if ((status & DT_STATUS_OK_NSEC) == 0U) { ++ continue; ++ } ++ ++ size = fdt32_to_cpu(*(cuint + 1)) / sizeof(uint32_t); ++ ++ if ((fdt32_to_cpu(*(cuint + 1)) % sizeof(uint32_t)) != 0) { ++ size++; ++ } ++ ++ for (i = reg; i < (reg + size); i++) { ++ enable_non_secure_access(i); ++ } ++ } ++ ++ return 0; ++} ++#endif ++ ++static uint32_t otp_bank_offset(uint32_t otp) ++{ ++ assert(otp <= stm32mp_get_otp_max()); ++ ++ return ((otp & ~BSEC_OTP_MASK) >> BSEC_OTP_BANK_SHIFT) * ++ sizeof(uint32_t); ++} ++ ++static uintptr_t bsec_get_base(void) ++{ ++ static void *va; ++ ++ if (!cpu_mmu_enabled()) ++ return BSEC_BASE; ++ ++ if (!va) ++ va = phys_to_virt(BSEC_BASE, MEM_AREA_IO_SEC); ++ ++ return (vaddr_t)va; ++} ++ ++/* ++ * bsec_check_error ++ * otp : OTP number. ++ * return value : BSEC_OK if no error. ++ */ ++static uint32_t bsec_check_error(uint32_t otp) ++{ ++ uint32_t bit = BIT(otp & BSEC_OTP_MASK); ++ uint32_t bank = otp_bank_offset(otp); ++ ++ if ((read32(bsec_get_base() + BSEC_DISTURBED_OFF + bank) & bit) != 0U) { ++ return BSEC_DISTURBED; ++ } ++ ++ if ((read32(bsec_get_base() + BSEC_ERROR_OFF + bank) & bit) != 0U) { ++ return BSEC_ERROR; ++ } ++ ++ return BSEC_OK; ++} ++ ++/* ++ * bsec_shadow_register: copy SAFMEM OTP to BSEC data. ++ * otp: OTP number. ++ * return value: BSEC_OK if no error. ++ */ ++uint32_t bsec_shadow_register(uint32_t otp) ++{ ++ uint32_t result; ++ uint32_t exc; ++ ++ if (otp > stm32mp_get_otp_max()) { ++ return BSEC_INVALID_PARAM; ++ } ++ ++ /* Check if shadowing of OTP is locked */ ++ if (bsec_read_sr_lock(otp)) { ++ IMSG("BSEC: OTP locked, register will not be refreshed"); ++ } ++ ++ result = bsec_power_safmem(true); ++ if (result != BSEC_OK) { ++ return result; ++ } ++ ++ exc = bsec_lock(); ++ ++ write32(otp | BSEC_READ, bsec_get_base() + BSEC_OTP_CTRL_OFF); ++ ++ while ((bsec_get_status() & BSEC_MODE_BUSY_MASK) != 0U) { ++ ; ++ } ++ ++ result = bsec_check_error(otp); ++ ++ bsec_unlock(exc); ++ ++ bsec_power_safmem(false); ++ ++ return result; ++} ++ ++/* ++ * bsec_read_otp: read an OTP data value. ++ * val: read value. ++ * otp: OTP number. ++ * return value: BSEC_OK if no error. ++ */ ++uint32_t bsec_read_otp(uint32_t *val, uint32_t otp) ++{ ++ uint32_t exc; ++ uint32_t result; ++ ++ if (otp > stm32mp_get_otp_max()) { ++ return BSEC_INVALID_PARAM; ++ } ++ ++ exc = bsec_lock(); ++ ++ *val = read32(bsec_get_base() + BSEC_OTP_DATA_OFF + ++ (otp * sizeof(uint32_t))); ++ ++ result = bsec_check_error(otp); ++ ++ bsec_unlock(exc); ++ ++ return result; ++} ++ ++/* ++ * bsec_write_otp: write value in BSEC data register. ++ * val: value to write. ++ * otp: OTP number. ++ * return value: BSEC_OK if no error. ++ */ ++uint32_t bsec_write_otp(uint32_t val, uint32_t otp) ++{ ++ uint32_t exc; ++ uint32_t result; ++ ++ if (otp > stm32mp_get_otp_max()) { ++ return BSEC_INVALID_PARAM; ++ } ++ ++ /* Check if programming of OTP is locked */ ++ if (bsec_read_sw_lock(otp)) { ++ IMSG("BSEC: OTP locked, write will be ignored"); ++ } ++ ++ exc = bsec_lock(); ++ ++ write32(val, bsec_get_base() + BSEC_OTP_DATA_OFF + ++ (otp * sizeof(uint32_t))); ++ ++ result = bsec_check_error(otp); ++ ++ bsec_unlock(exc); ++ ++ return result; ++} ++ ++/* ++ * bsec_program_otp: program a bit in SAFMEM after the prog. ++ * The OTP data is not refreshed. ++ * val: value to program. ++ * otp: OTP number. ++ * return value: BSEC_OK if no error. ++ */ ++uint32_t bsec_program_otp(uint32_t val, uint32_t otp) ++{ ++ uint32_t result; ++ uint32_t exc; ++ ++ if (otp > stm32mp_get_otp_max()) { ++ return BSEC_INVALID_PARAM; ++ } ++ ++ /* Check if programming of OTP is locked */ ++ if (bsec_read_sp_lock(otp)) { ++ IMSG("BSEC: OTP locked, prog will be ignored"); ++ } ++ ++ if ((read32(bsec_get_base() + BSEC_OTP_LOCK_OFF) & ++ BIT(BSEC_LOCK_PROGRAM)) != 0U) { ++ IMSG("BSEC: GPLOCK activated, prog will be ignored"); ++ } ++ ++ result = bsec_power_safmem(true); ++ if (result != BSEC_OK) { ++ return result; ++ } ++ ++ exc = bsec_lock(); ++ ++ write32(val, bsec_get_base() + BSEC_OTP_WRDATA_OFF); ++ write32(otp | BSEC_WRITE, bsec_get_base() + BSEC_OTP_CTRL_OFF); ++ ++ while ((bsec_get_status() & BSEC_MODE_BUSY_MASK) != 0U) { ++ ; ++ } ++ ++ if ((bsec_get_status() & BSEC_MODE_PROGFAIL_MASK) != 0U) { ++ result = BSEC_PROG_FAIL; ++ } else { ++ result = bsec_check_error(otp); ++ } ++ ++ bsec_unlock(exc); ++ ++ bsec_power_safmem(false); ++ ++ return result; ++} ++ ++/* ++ * bsec_permanent_lock_otp: permanent lock of OTP in SAFMEM. ++ * otp: OTP number. ++ * return value: BSEC_OK if no error. ++ */ ++uint32_t bsec_permanent_lock_otp(uint32_t otp) ++{ ++ uint32_t result; ++ uint32_t data; ++ uint32_t addr; ++ uint32_t exc; ++ ++ if (otp > stm32mp_get_otp_max()) { ++ return BSEC_INVALID_PARAM; ++ } ++ ++ result = bsec_power_safmem(true); ++ if (result != BSEC_OK) { ++ return result; ++ } ++ ++ if (otp < stm32mp_get_otp_upper_start()) { ++ addr = otp >> ADDR_LOWER_OTP_PERLOCK_SHIFT; ++ data = DATA_LOWER_OTP_PERLOCK_BIT << ++ ((otp & DATA_LOWER_OTP_PERLOCK_MASK) << 1U); ++ } else { ++ addr = (otp >> ADDR_UPPER_OTP_PERLOCK_SHIFT) + 2U; ++ data = DATA_UPPER_OTP_PERLOCK_BIT << ++ (otp & DATA_UPPER_OTP_PERLOCK_MASK); ++ } ++ ++ exc = bsec_lock(); ++ ++ write32(data, bsec_get_base() + BSEC_OTP_WRDATA_OFF); ++ write32(addr | BSEC_WRITE | BSEC_LOCK, ++ bsec_get_base() + BSEC_OTP_CTRL_OFF); ++ ++ while ((bsec_get_status() & BSEC_MODE_BUSY_MASK) != 0U) { ++ ; ++ } ++ ++ if ((bsec_get_status() & BSEC_MODE_PROGFAIL_MASK) != 0U) { ++ result = BSEC_PROG_FAIL; ++ } else { ++ result = bsec_check_error(otp); ++ } ++ ++ bsec_unlock(exc); ++ ++ bsec_power_safmem(false); ++ ++ return result; ++} ++ ++/* ++ * bsec_write_debug_conf: write value in debug feature ++ * to enable/disable debug service. ++ * val: value to write. ++ * return value: BSEC_OK if no error. ++ */ ++uint32_t bsec_write_debug_conf(uint32_t val) ++{ ++ uint32_t result = BSEC_ERROR; ++ uint32_t masked_val = val & BSEC_DEN_ALL_MSK; ++ unsigned int exc; ++ ++ exc = bsec_lock(); ++ ++ write32(val, bsec_get_base() + BSEC_DEN_OFF); ++ ++ if ((read32(bsec_get_base() + BSEC_DEN_OFF) ^ masked_val) == 0U) { ++ result = BSEC_OK; ++ } ++ ++ bsec_unlock(exc); ++ ++ return result; ++} ++ ++/* ++ * bsec_read_debug_conf : read debug configuration. ++ */ ++uint32_t bsec_read_debug_conf(void) ++{ ++ return read32(bsec_get_base() + BSEC_DEN_OFF); ++} ++ ++/* ++ * bsec_get_status : return status register value. ++ */ ++uint32_t bsec_get_status(void) ++{ ++ return read32(bsec_get_base() + BSEC_OTP_STATUS_OFF); ++} ++ ++/* ++ * bsec_get_hw_conf : return hardware configuration. ++ */ ++uint32_t bsec_get_hw_conf(void) ++{ ++ return read32(bsec_get_base() + BSEC_IPHW_CFG_OFF); ++} ++ ++/* ++ * bsec_get_version : return BSEC version. ++ */ ++uint32_t bsec_get_version(void) ++{ ++ return read32(bsec_get_base() + BSEC_IPVR_OFF); ++} ++ ++/* ++ * bsec_get_id : return BSEC ID. ++ */ ++uint32_t bsec_get_id(void) ++{ ++ return read32(bsec_get_base() + BSEC_IP_ID_OFF); ++} ++ ++/* ++ * bsec_get_magic_id : return BSEC magic number. ++ */ ++uint32_t bsec_get_magic_id(void) ++{ ++ return read32(bsec_get_base() + BSEC_IP_MAGIC_ID_OFF); ++} ++ ++/* ++ * bsec_write_sr_lock: write shadow-read lock. ++ * otp: OTP number. ++ * value: value to write in the register. ++ * Must be always 1. ++ * return: true if OTP is locked, else false. ++ */ ++bool bsec_write_sr_lock(uint32_t otp, uint32_t value) ++{ ++ bool result = false; ++ uint32_t bank = otp_bank_offset(otp); ++ uint32_t bank_value; ++ uint32_t otp_mask = BIT(otp & BSEC_OTP_MASK); ++ uint32_t exc; ++ ++ exc = bsec_lock(); ++ ++ bank_value = read32(bsec_get_base() + BSEC_SRLOCK_OFF + bank); ++ ++ if ((bank_value & otp_mask) == value) { ++ /* ++ * In case of write don't need to write, ++ * the lock is already set. ++ */ ++ if (value != 0U) { ++ result = true; ++ } ++ } else { ++ if (value != 0U) { ++ bank_value = bank_value | otp_mask; ++ } else { ++ bank_value = bank_value & ~otp_mask; ++ } ++ ++ /* ++ * We can write 0 in all other OTP ++ * if the lock is activated in one of other OTP. ++ * Write 0 has no effect. ++ */ ++ write32(bank_value, bsec_get_base() + BSEC_SRLOCK_OFF + bank); ++ result = true; ++ } ++ ++ bsec_unlock(exc); ++ ++ return result; ++} ++ ++/* ++ * bsec_read_sr_lock: read shadow-read lock. ++ * otp: OTP number. ++ * return: true if otp is locked, else false. ++ */ ++bool bsec_read_sr_lock(uint32_t otp) ++{ ++ uint32_t bank = otp_bank_offset(otp); ++ uint32_t otp_mask = BIT(otp & BSEC_OTP_MASK); ++ uint32_t bank_value = read32(bsec_get_base() + BSEC_SRLOCK_OFF + bank); ++ ++ return (bank_value & otp_mask) != 0U; ++} ++ ++/* ++ * bsec_write_sw_lock: write shadow-write lock. ++ * otp: OTP number. ++ * value: Value to write in the register. ++ * Must be always 1. ++ * return: true if OTP is locked, else false. ++ */ ++bool bsec_write_sw_lock(uint32_t otp, uint32_t value) ++{ ++ bool result = false; ++ uint32_t bank = otp_bank_offset(otp); ++ uint32_t otp_mask = BIT(otp & BSEC_OTP_MASK); ++ uint32_t bank_value; ++ unsigned int exc; ++ ++ exc = bsec_lock(); ++ ++ bank_value = read32(bsec_get_base() + BSEC_SWLOCK_OFF + bank); ++ ++ if ((bank_value & otp_mask) == value) { ++ /* ++ * In case of write don't need to write, ++ * the lock is already set. ++ */ ++ if (value != 0U) { ++ result = true; ++ } ++ } else { ++ if (value != 0U) { ++ bank_value = bank_value | otp_mask; ++ } else { ++ bank_value = bank_value & ~otp_mask; ++ } ++ ++ /* ++ * We can write 0 in all other OTP ++ * if the lock is activated in one of other OTP. ++ * Write 0 has no effect. ++ */ ++ write32(bank_value, bsec_get_base() + BSEC_SWLOCK_OFF + bank); ++ result = true; ++ } ++ ++ bsec_unlock(exc); ++ ++ return result; ++} ++ ++/* ++ * bsec_read_sw_lock: read shadow-write lock. ++ * otp: OTP number. ++ * return: true if OTP is locked, else false. ++ */ ++bool bsec_read_sw_lock(uint32_t otp) ++{ ++ uint32_t bank = otp_bank_offset(otp); ++ uint32_t otp_mask = BIT(otp & BSEC_OTP_MASK); ++ uint32_t bank_value = read32(bsec_get_base() + BSEC_SWLOCK_OFF + bank); ++ ++ return (bank_value & otp_mask) != 0U; ++} ++ ++/* ++ * bsec_write_sp_lock: write shadow-program lock. ++ * otp: OTP number. ++ * value: Value to write in the register. ++ * Must be always 1. ++ * return: true if OTP is locked, else false. ++ */ ++bool bsec_write_sp_lock(uint32_t otp, uint32_t value) ++{ ++ bool result = false; ++ uint32_t bank = otp_bank_offset(otp); ++ uint32_t bank_value; ++ uint32_t otp_mask = BIT(otp & BSEC_OTP_MASK); ++ unsigned int exc; ++ ++ exc = bsec_lock(); ++ ++ bank_value = read32(bsec_get_base() + BSEC_SPLOCK_OFF + bank); ++ ++ if ((bank_value & otp_mask) == value) { ++ /* ++ * In case of write don't need to write, ++ * the lock is already set. ++ */ ++ if (value != 0U) { ++ result = true; ++ } ++ } else { ++ if (value != 0U) { ++ bank_value = bank_value | otp_mask; ++ } else { ++ bank_value = bank_value & ~otp_mask; ++ } ++ ++ /* ++ * We can write 0 in all other OTP ++ * if the lock is activated in one of other OTP. ++ * Write 0 has no effect. ++ */ ++ write32(bank_value, bsec_get_base() + BSEC_SPLOCK_OFF + bank); ++ result = true; ++ } ++ ++ bsec_unlock(exc); ++ ++ return result; ++} ++ ++/* ++ * bsec_read_sp_lock: read shadow-program lock. ++ * otp: OTP number. ++ * return: true if OTP is locked, else false. ++ */ ++bool bsec_read_sp_lock(uint32_t otp) ++{ ++ uint32_t bank = otp_bank_offset(otp); ++ uint32_t otp_mask = BIT(otp & BSEC_OTP_MASK); ++ uint32_t bank_value = read32(bsec_get_base() + BSEC_SPLOCK_OFF + bank); ++ ++ return (bank_value & otp_mask) != 0U; ++} ++ ++/* ++ * bsec_wr_lock: Read permanent lock status. ++ * otp: OTP number. ++ * return: true if OTP is locked, else false. ++ */ ++bool bsec_wr_lock(uint32_t otp) ++{ ++ uint32_t bank = otp_bank_offset(otp); ++ uint32_t lock_bit = BIT(otp & BSEC_OTP_MASK); ++ ++ if ((read32(bsec_get_base() + BSEC_WRLOCK_OFF + bank) & ++ lock_bit) != 0U) { ++ /* ++ * In case of write don't need to write, ++ * the lock is already set. ++ */ ++ return true; ++ } ++ ++ return false; ++} ++ ++/* ++ * bsec_otp_lock: Lock Upper OTP or Global programming or debug enable ++ * service: Service to lock see header file. ++ * value: Value to write must always set to 1 (only use for debug purpose). ++ * return: BSEC_OK if succeed. ++ */ ++uint32_t bsec_otp_lock(uint32_t service, uint32_t value) ++{ ++ uintptr_t reg = bsec_get_base() + BSEC_OTP_LOCK_OFF; ++ ++ switch (service) { ++ case BSEC_LOCK_UPPER_OTP: ++ write32(value << BSEC_LOCK_UPPER_OTP, reg); ++ break; ++ case BSEC_LOCK_DEBUG: ++ write32(value << BSEC_LOCK_DEBUG, reg); ++ break; ++ case BSEC_LOCK_PROGRAM: ++ write32(value << BSEC_LOCK_PROGRAM, reg); ++ break; ++ default: ++ return BSEC_INVALID_PARAM; ++ } ++ ++ return BSEC_OK; ++} ++ ++static uint32_t enable_power(void) ++{ ++ size_t cntdown; ++ ++ io_mask32(bsec_get_base() + BSEC_OTP_CONF_OFF, BSEC_CONF_POWER_UP_MASK, ++ BSEC_CONF_POWER_UP_MASK); ++ ++ for (cntdown = BSEC_TIMEOUT_VALUE; cntdown; cntdown--) { ++ if (bsec_get_status() & BSEC_MODE_PWR_MASK) { ++ break; ++ } ++ } ++ ++ return cntdown ? BSEC_OK : BSEC_TIMEOUT; ++} ++ ++static uint32_t disable_power(void) ++{ ++ size_t cntdown; ++ ++ io_mask32(bsec_get_base() + BSEC_OTP_CONF_OFF, 0, ++ BSEC_CONF_POWER_UP_MASK); ++ ++ for (cntdown = BSEC_TIMEOUT_VALUE; cntdown; cntdown--) { ++ if (!(bsec_get_status() & BSEC_MODE_PWR_MASK)) { ++ break; ++ } ++ } ++ ++ return cntdown ? BSEC_OK : BSEC_TIMEOUT; ++} ++ ++/* ++ * bsec_power_safmem: Activate or deactivate SAFMEM power. ++ * power: true to power up, false to power down. ++ * return: BSEC_OK if succeed. ++ */ ++static uint32_t bsec_power_safmem(bool enable) ++{ ++ static unsigned int refcnt = ~0UL; ++ uint32_t result = BSEC_OK; ++ uint32_t exc = 0; ++ ++ /* Get the initial state */ ++ if (refcnt == ~0UL) { ++ refcnt = !!(bsec_get_status() & BSEC_MODE_PWR_MASK); ++ DMSG("Reset SAFMEM refcnt to %u", refcnt); ++ } ++ ++ exc = bsec_lock(); ++ ++ if (enable && (incr_refcnt(&refcnt) != 0U)) { ++ result = enable_power(); ++ } ++ ++ if (!enable && (decr_refcnt(&refcnt) != 0U)) { ++ result = disable_power(); ++ } ++ ++ bsec_unlock(exc); ++ ++ return result; ++} ++ ++/* ++ * bsec_mode_is_closed_device: read OTP secure sub-mode. ++ * return: false if open_device and true of closed_device. ++ */ ++bool bsec_mode_is_closed_device(void) ++{ ++ uint32_t value; ++ ++ if ((bsec_shadow_register(DATA0_OTP) != BSEC_OK) || ++ (bsec_read_otp(&value, DATA0_OTP) != BSEC_OK)) { ++ return true; ++ } ++ ++ return (value & DATA0_OTP_SECURED) == DATA0_OTP_SECURED; ++} ++ ++/* ++ * bsec_shadow_read_otp: Load OTP from SAFMEM and provide its value ++ * otp_value: read value. ++ * word: OTP number. ++ * return value: BSEC_OK if no error. ++ */ ++uint32_t bsec_shadow_read_otp(uint32_t *otp_value, uint32_t word) ++{ ++ uint32_t result; ++ ++ result = bsec_shadow_register(word); ++ if (result != BSEC_OK) { ++ EMSG("BSEC: %u Shadowing Error %i\n", word, result); ++ return result; ++ } ++ ++ result = bsec_read_otp(otp_value, word); ++ if (result != BSEC_OK) { ++ EMSG("BSEC: %u Read Error %i\n", word, result); ++ } ++ ++ return result; ++} ++ ++/* ++ * bsec_check_nsec_access_rights: check non-secure access rights to target OTP. ++ * otp: OTP number. ++ * return: BSEC_OK if authorized access. ++ */ ++uint32_t bsec_check_nsec_access_rights(uint32_t otp) ++{ ++ if (otp > stm32mp_get_otp_max()) { ++ return BSEC_INVALID_PARAM; ++ } ++ ++ if (otp >= stm32mp_get_otp_upper_start()) { ++ /* Check if BSEC is in OTP-SECURED closed_device state. */ ++ if (bsec_mode_is_closed_device()) { ++#ifdef CFG_DT ++ if (!non_secure_can_access(otp)) { ++ return BSEC_ERROR; ++ } ++#else ++ return BSEC_ERROR; ++#endif ++ } ++ } ++ ++ return BSEC_OK; ++} ++ ++#ifdef CFG_DT ++static TEE_Result initialize_bsec(void) ++{ ++ void *fdt; ++ int node; ++ struct dt_node_info bsec_info; ++ ++ fdt = get_dt_blob(); ++ if (fdt == NULL) { ++ panic(); ++ } ++ ++ node = bsec_get_dt_node(fdt, &bsec_info); ++ if (node < 0) { ++ panic(); ++ } ++ ++ bsec_dt_otp_nsec_access(fdt, node); ++ ++ return TEE_SUCCESS; ++} ++driver_init(initialize_bsec); ++#endif +diff --git a/core/drivers/stm32_etzpc.c b/core/drivers/stm32_etzpc.c +new file mode 100644 +index 0000000..fcb32e6 +--- /dev/null ++++ b/core/drivers/stm32_etzpc.c +@@ -0,0 +1,337 @@ ++// SPDX-License-Identifier: BSD-3-Clause ++/* ++ * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved. ++ * Copyright (c) 2017-2018, STMicroelectronics ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#ifdef CFG_DT ++#include ++#endif ++ ++#define ETZPC_COMPAT "st,stm32-etzpc" ++#define ETZPC_LOCK_MASK 0x1U ++#define ETZPC_MODE_SHIFT 8 ++#define ETZPC_MODE_MASK GENMASK_32(1, 0) ++#define ETZPC_ID_SHIFT 16 ++#define ETZPC_ID_MASK GENMASK_32(7, 0) ++ ++/* ID Registers */ ++#define ETZPC_TZMA0_SIZE 0x000U ++#define ETZPC_DECPROT0 0x010U ++#define ETZPC_DECPROT_LOCK0 0x030U ++#define ETZPC_HWCFGR 0x3F0U ++#define ETZPC_VERR 0x3F4U ++ ++/* ID Registers fields */ ++#define ETZPC_TZMA0_SIZE_LOCK BIT(31) ++#define ETZPC_DECPROT0_MASK GENMASK_32(1, 0) ++#define ETZPC_HWCFGR_NUM_TZMA_SHIFT 0 ++#define ETZPC_HWCFGR_NUM_PER_SEC_SHIFT 8 ++#define ETZPC_HWCFGR_NUM_AHB_SEC_SHIFT 16 ++#define ETZPC_HWCFGR_CHUNCKS1N4_SHIFT 24 ++ ++#define DECPROT_SHIFT 1 ++#define IDS_PER_DECPROT_REGS 16U ++#define IDS_PER_DECPROT_LOCK_REGS 32U ++ ++#define ETZPC_TZMA_ALL_SECURE 0x3FF ++#define ETZPC_TZMA_ALL_NO_SECURE 0x000 ++ ++/* ++ * etzpc_instance. ++ * base : register virtual base address set during init given by user ++ * pbase : register physical base address set during init given by user ++ * chunk_size : supported TZMA size steps ++ * num_tzma: number of TZMA zone read from register at init ++ * num_ahb_sec : number of securable AHB master zone read from register ++ * num_per_sec : number of securable AHB & APB Peripherals read from register ++ * revision : IP revision read from register at init ++ * periph_cfg : buffer storing holding the DECPROT configuration for peripherals ++ */ ++struct etzpc_instance { ++ uintptr_t base; ++ paddr_t pbase; ++ uint8_t chunck_size; ++ uint8_t num_tzma; ++ uint8_t num_per_sec; ++ uint8_t num_ahb_sec; ++ uint8_t revision; ++ uint8_t *periph_cfg; ++}; ++ ++/* Only 1 instance of the ETZPC is expected per platform */ ++static struct etzpc_instance etzpc_dev; ++ ++#ifdef CFG_DT ++struct dt_id_attr { ++ /* The effective size of the array is meaningless here */ ++ fdt32_t id_attr[1]; ++}; ++#endif ++ ++/* ++ * Implementation uses uint8_t to store each securable DECPROT configuration. ++ * When resuming from deep suspend, the DECPROT configurations are restored. ++ */ ++#define PERIPH_LOCK_BIT BIT(7) ++#define PERIPH_ATTR_MASK GENMASK_32(2, 0) ++ ++static uintptr_t etzpc_base(void) ++{ ++ if (!cpu_mmu_enabled()) ++ return etzpc_dev.pbase; ++ ++ if (!etzpc_dev.base) ++ etzpc_dev.base = (uintptr_t)phys_to_virt(etzpc_dev.pbase, ++ MEM_AREA_IO_SEC); ++ ++ return etzpc_dev.base; ++} ++ ++static bool valid_decprot_id(unsigned int id) ++{ ++ return id < (unsigned int)etzpc_dev.num_per_sec; ++} ++ ++static bool valid_tzma_id(unsigned int id) ++{ ++ return id < (unsigned int)etzpc_dev.num_tzma; ++} ++ ++#ifdef CFG_DT ++static int etzpc_dt_conf_decprot(void *fdt, int node) ++{ ++ const struct dt_id_attr *conf_list; ++ unsigned int i; ++ int len = 0; ++ ++ conf_list = (const struct dt_id_attr *)fdt_getprop(fdt, node, ++ "st,decprot", &len); ++ if (conf_list == NULL) { ++ IMSG("No ETZPC configuration in DT, use default"); ++ return 0; ++ } ++ ++ for (i = 0; i < len / sizeof(uint32_t); i++) { ++ enum etzpc_decprot_attributes attr; ++ uint32_t value; ++ uint32_t id; ++ uint32_t mode; ++ ++ value = fdt32_to_cpu(conf_list->id_attr[i]); ++ ++ id = ((value >> ETZPC_ID_SHIFT) & ETZPC_ID_MASK); ++ if (!valid_decprot_id(id)) { ++ EMSG("Invalid DECPROT %" PRIu32, id); ++ return -1; ++ } ++ ++ mode = (value >> ETZPC_MODE_SHIFT) & ETZPC_MODE_MASK; ++ attr = stm32mp_etzpc_binding2decprot(mode); ++ ++ stm32mp_register_etzpc_decprot(id, attr); ++ ++ etzpc_configure_decprot(id, attr); ++ ++ if ((value & ETZPC_LOCK_MASK) != 0U) { ++ etzpc_lock_decprot(id); ++ } ++ } ++ ++ return 0; ++} ++#endif ++ ++void etzpc_configure_decprot(uint32_t decprot_id, ++ enum etzpc_decprot_attributes decprot_attr) ++{ ++ uintptr_t offset = 4U * (decprot_id / IDS_PER_DECPROT_REGS); ++ uint32_t shift = (decprot_id % IDS_PER_DECPROT_REGS) << DECPROT_SHIFT; ++ uint32_t masked_decprot = (uint32_t)decprot_attr & ETZPC_DECPROT0_MASK; ++ uintptr_t base = etzpc_base(); ++ ++ assert(valid_decprot_id(decprot_id)); ++ ++ mmio_clrsetbits_32(base + ETZPC_DECPROT0 + offset, ++ (uint32_t)ETZPC_DECPROT0_MASK << shift, ++ masked_decprot << shift); ++ ++ etzpc_dev.periph_cfg[decprot_id] = (uint8_t)decprot_attr; ++ ++ assert((decprot_attr & ~PERIPH_ATTR_MASK) == 0); ++ COMPILE_TIME_ASSERT(TZPC_DECPROT_MAX <= UINT8_MAX); ++} ++ ++enum etzpc_decprot_attributes etzpc_get_decprot(uint32_t decprot_id) ++{ ++ uintptr_t offset = 4U * (decprot_id / IDS_PER_DECPROT_REGS); ++ uint32_t shift = (decprot_id % IDS_PER_DECPROT_REGS) << DECPROT_SHIFT; ++ uintptr_t base_decprot = etzpc_base() + offset; ++ uint32_t value; ++ ++ assert(valid_decprot_id(decprot_id)); ++ ++ value = (read32(base_decprot + ETZPC_DECPROT0) >> shift) & ++ ETZPC_DECPROT0_MASK; ++ ++ return (enum etzpc_decprot_attributes)value; ++} ++ ++void etzpc_lock_decprot(uint32_t decprot_id) ++{ ++ uintptr_t offset = 4U * (decprot_id / IDS_PER_DECPROT_LOCK_REGS); ++ uint32_t shift = BIT(decprot_id % IDS_PER_DECPROT_LOCK_REGS); ++ uintptr_t base_decprot = etzpc_base() + offset; ++ ++ assert(valid_decprot_id(decprot_id)); ++ ++ write32(shift, base_decprot + ETZPC_DECPROT_LOCK0); ++ ++ etzpc_dev.periph_cfg[decprot_id] |= PERIPH_LOCK_BIT; ++} ++ ++void etzpc_configure_tzma(uint32_t tzma_id, uint16_t tzma_value) ++{ ++ assert(valid_tzma_id(tzma_id)); ++ ++ write32(tzma_value, etzpc_base() + ETZPC_TZMA0_SIZE + ++ (sizeof(uint32_t) * tzma_id)); ++} ++ ++uint16_t etzpc_get_tzma(uint32_t tzma_id) ++{ ++ assert(valid_tzma_id(tzma_id)); ++ ++ return read32(etzpc_base() + ETZPC_TZMA0_SIZE + ++ (sizeof(uint32_t) * tzma_id)); ++} ++ ++void etzpc_lock_tzma(uint32_t tzma_id) ++{ ++ assert(valid_tzma_id(tzma_id)); ++ ++ mmio_setbits_32(etzpc_base() + ETZPC_TZMA0_SIZE + ++ (sizeof(uint32_t) * tzma_id), ETZPC_TZMA0_SIZE_LOCK); ++} ++ ++bool etzpc_get_lock_tzma(uint32_t tzma_id) ++{ ++ uint32_t tzma_size; ++ ++ assert(valid_tzma_id(tzma_id)); ++ ++ tzma_size = read32(etzpc_base() + ETZPC_TZMA0_SIZE + ++ (sizeof(uint32_t) * tzma_id)); ++ ++ return (tzma_size & ETZPC_TZMA0_SIZE_LOCK) != 0; ++} ++ ++static void etzpc_suspend_resume(enum pm_op op, void __unused *handle) ++{ ++ unsigned int n; ++ ++ if (op == PM_OP_SUSPEND) { ++ return; ++ } ++ ++ /* OP-TEE owns the whole in SYSRAM */ ++ etzpc_configure_tzma(1, ETZPC_TZMA_ALL_SECURE); ++ etzpc_lock_tzma(1); ++ ++ for (n = 0; n < etzpc_dev.num_per_sec; n++) { ++ unsigned int attr = etzpc_dev.periph_cfg[n] & PERIPH_ATTR_MASK; ++ ++ etzpc_configure_decprot(n, (enum etzpc_decprot_attributes)attr); ++ ++ if (etzpc_dev.periph_cfg[n] & PERIPH_LOCK_BIT) { ++ etzpc_lock_decprot(n); ++ } ++ } ++} ++KEEP_PAGER(etzpc_suspend_resume); ++ ++static TEE_Result etzpc_init(void) ++{ ++ void *fdt __maybe_unused; ++ int node __maybe_unused; ++ struct dt_node_info etzpc_info __maybe_unused; ++ uintptr_t base; ++ uint32_t hwcfg; ++ size_t n; ++ ++#ifdef CFG_DT ++ fdt = get_dt_blob(); ++ if (!fdt) { ++ panic(); ++ } ++ ++ node = fdt_get_node(fdt, &etzpc_info, -1, ETZPC_COMPAT); ++ if (node >= 0) { ++ etzpc_dev.pbase = etzpc_info.base; ++ assert(etzpc_dev.pbase == stm32mp_get_etzpc_base()); ++ ++ if (etzpc_info.status != DT_STATUS_OK_SEC) { ++ EMSG("ETZPC DT status"); ++ panic(); ++ } ++ } ++#endif ++ ++ if (!etzpc_dev.pbase) { ++ etzpc_dev.pbase = stm32mp_get_etzpc_base(); ++ } ++ ++ base = etzpc_base(); ++ ++ hwcfg = read32(base + ETZPC_HWCFGR); ++ etzpc_dev.num_tzma = (uint8_t)(hwcfg >> ETZPC_HWCFGR_NUM_TZMA_SHIFT); ++ etzpc_dev.num_per_sec = (uint8_t)(hwcfg >> ++ ETZPC_HWCFGR_NUM_PER_SEC_SHIFT); ++ etzpc_dev.num_ahb_sec = (uint8_t)(hwcfg >> ++ ETZPC_HWCFGR_NUM_AHB_SEC_SHIFT); ++ etzpc_dev.chunck_size = (uint8_t)(hwcfg >> ++ ETZPC_HWCFGR_CHUNCKS1N4_SHIFT); ++ ++ etzpc_dev.revision = read8(base + ETZPC_VERR); ++ ++ etzpc_dev.periph_cfg = calloc(etzpc_dev.num_per_sec, ++ sizeof(*etzpc_dev.periph_cfg)); ++ if (etzpc_dev.periph_cfg == NULL) { ++ panic(); ++ } ++ for (n = 0; n < etzpc_dev.num_per_sec; n++) { ++ etzpc_configure_decprot(n, etzpc_get_decprot(n)); ++ } ++ ++ DMSG("ETZPC version 0x%" PRIx8, etzpc_dev.revision); ++ ++#ifdef CFG_DT ++ if (etzpc_dt_conf_decprot(fdt, node)) { ++ panic(); ++ } ++#endif ++ ++ /* OP-TEE owns the whole in SYSRAM */ ++ etzpc_configure_tzma(1, ETZPC_TZMA_ALL_SECURE); ++ etzpc_lock_tzma(1); ++ ++ stm32mp_register_pm_cb(etzpc_suspend_resume, NULL); ++ ++ return TEE_SUCCESS; ++} ++driver_init(etzpc_init); +diff --git a/core/drivers/stm32_gpio.c b/core/drivers/stm32_gpio.c +new file mode 100644 +index 0000000..cb18271 +--- /dev/null ++++ b/core/drivers/stm32_gpio.c +@@ -0,0 +1,417 @@ ++// SPDX-License-Identifier: BSD-3-Clause ++/* ++ * Copyright (c) 2016-2018, STMicroelectronics - All Rights Reserved ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#ifdef CFG_DT ++#include ++#endif ++ ++#define DT_GPIO_BANK_SHIFT 12 ++#define DT_GPIO_BANK_MASK GENMASK_32(16, 12) ++#define DT_GPIO_PIN_SHIFT 8 ++#define DT_GPIO_PIN_MASK GENMASK_32(11, 8) ++#define DT_GPIO_MODE_MASK GENMASK_32(7, 0) ++ ++static void get_gpio_cfg(uint32_t bank, uint32_t pin, struct gpio_cfg *cfg) ++{ ++ uintptr_t base = stm32_get_gpio_bank_base(bank); ++ int clock = stm32_get_gpio_bank_clock(bank); ++ ++ stm32_clock_enable((unsigned long)clock); ++ ++ cfg->moder = (mmio_read_32(base + GPIO_MODE_OFFSET) >> (pin << 1)) & ++ GPIO_MODE_MAX; ++ ++ cfg->otyper = (mmio_read_32(base + GPIO_TYPE_OFFSET) >> pin) & 1; ++ cfg->ospeedr = (mmio_read_32(base + GPIO_SPEED_OFFSET) >> (pin << 1)) & ++ GPIO_SPEED_MAX; ++ cfg->pupdr = (mmio_read_32(base + GPIO_PUPD_OFFSET) >> (pin << 1)) & ++ GPIO_PULL_MAX; ++ ++ cfg->odr = (mmio_read_32(base + GPIO_ODR_OFFSET) >> (pin << 1)) & 1; ++ ++ if (pin < GPIO_ALT_LOWER_LIMIT) { ++ cfg->afr = (mmio_read_32(base + GPIO_AFRL_OFFSET) >> ++ (pin << 2)) & GPIO_ALTERNATE_MAX; ++ } else { ++ cfg->afr = (mmio_read_32(base + GPIO_AFRH_OFFSET) >> ++ ((pin - GPIO_ALT_LOWER_LIMIT) << 2)) & ++ GPIO_ALTERNATE_MAX; ++ } ++ ++ stm32_clock_disable((unsigned long)clock); ++} ++ ++static void set_gpio_cfg(uint32_t bank, uint32_t pin, struct gpio_cfg *cfg) ++{ ++ uintptr_t base = stm32_get_gpio_bank_base(bank); ++ int clock = stm32_get_gpio_bank_clock(bank); ++ ++ stm32_clock_enable((unsigned long)clock); ++ ++ mmio_clrsetbits_32(base + GPIO_MODE_OFFSET, ++ GPIO_MODE_MAX << (pin << 1), ++ cfg->moder << (pin << 1)); ++ ++ mmio_clrsetbits_32(base + GPIO_TYPE_OFFSET, ++ BIT(pin), ++ cfg->otyper << pin); ++ ++ mmio_clrsetbits_32(base + GPIO_SPEED_OFFSET, ++ GPIO_SPEED_MAX << (pin << 1), ++ cfg->ospeedr << (pin << 1)); ++ ++ mmio_clrsetbits_32(base + GPIO_PUPD_OFFSET, ++ BIT(pin), ++ cfg->pupdr << (pin << 1)); ++ ++ if (pin < GPIO_ALT_LOWER_LIMIT) { ++ mmio_clrsetbits_32(base + GPIO_AFRL_OFFSET, ++ GPIO_ALTERNATE_MAX << (pin << 2), ++ cfg->afr << (pin << 2)); ++ } else { ++ size_t shift = (pin - GPIO_ALT_LOWER_LIMIT) << 2; ++ ++ mmio_clrsetbits_32(base + GPIO_AFRH_OFFSET, ++ GPIO_ALTERNATE_MAX << shift, ++ cfg->afr << shift); ++ } ++ ++ mmio_clrsetbits_32(base + GPIO_ODR_OFFSET, ++ BIT(pin), cfg->odr << pin); ++ ++ stm32_clock_disable((unsigned long)clock); ++} ++ ++/* ++ * stm32_gpio_set_output_level - Set level of an output GPIO instance ++ * ++ * @bank: GPIO bank ++ * @pin: GPIO pin position in bank ++ * @level: target level, either 0 (level low) or non zero (level high) ++ */ ++void stm32_gpio_set_output_level(uint32_t bank, uint32_t pin, int level) ++{ ++ uintptr_t base = stm32_get_gpio_bank_base(bank); ++ int clock = stm32_get_gpio_bank_clock(bank); ++ ++ assert(pin <= GPIO_PIN_MAX); ++ ++ stm32_clock_enable((unsigned long)clock); ++ ++ if (level) { ++ write32(BIT(pin), base + GPIO_BSRR_OFFSET); ++ } else { ++ write32(BIT(pin + 16), base + GPIO_BSRR_OFFSET); ++ } ++ ++ stm32_clock_disable((unsigned long)clock); ++} ++ ++/* ++ * stm32_pinctrl_load_active_cfg - Load the PINCTRLs active configuration ++ * ++ * @pinctrl: array of PINCTRL configurations to apply ++ * @cnt: number of elements in array pinctrl ++ */ ++void stm32_pinctrl_load_active_cfg(struct stm32_pinctrl *pinctrl, size_t cnt) ++{ ++ size_t n; ++ ++ for (n = 0; n < cnt; n++) { ++ set_gpio_cfg(pinctrl[n].bank, pinctrl[n].pin, ++ &pinctrl[n].active_cfg); ++ } ++} ++ ++/* ++ * stm32_pinctrl_load_standby_cfg - Load the PINCTRLs standby configuration ++ * ++ * @pinctrl: array of PINCTRL configurations to apply ++ * @cnt: number of elements in array pinctrl ++ */ ++void stm32_pinctrl_load_standby_cfg(struct stm32_pinctrl *pinctrl, size_t cnt) ++{ ++ size_t n; ++ ++ for (n = 0; n < cnt; n++) { ++ set_gpio_cfg(pinctrl[n].bank, pinctrl[n].pin, ++ &pinctrl[n].standby_cfg); ++ } ++} ++ ++/* ++ * stm32_pinctrl_store_standby_cfg - Save current PINCTRLs config as standby ++ * ++ * @pinctrl: array of PINCTRL configurations to store ++ * @cnt: number of elements in array pinctrl ++ */ ++void stm32_pinctrl_store_standby_cfg(struct stm32_pinctrl *pinctrl, size_t cnt) ++{ ++ size_t n; ++ ++ for (n = 0; n < cnt; n++) { ++ get_gpio_cfg(pinctrl[n].bank, pinctrl[n].pin, ++ &pinctrl[n].standby_cfg); ++ } ++} ++ ++#ifdef CFG_DT ++/* Return GPIO bank node if status is okay in DT, else return 0 */ ++static int ckeck_gpio_bank(void *fdt, uint32_t bank, int pinctrl_node) ++{ ++ int pinctrl_subnode; ++ ++ fdt_for_each_subnode(pinctrl_subnode, fdt, pinctrl_node) { ++ uint32_t bank_offset; ++ const fdt32_t *cuint; ++ ++ if (fdt_getprop(fdt, pinctrl_subnode, ++ "gpio-controller", NULL) == NULL) { ++ continue; ++ } ++ ++ cuint = fdt_getprop(fdt, pinctrl_subnode, "reg", NULL); ++ if (cuint == NULL) { ++ continue; ++ } ++ ++ bank_offset = stm32_get_gpio_bank_offset(bank); ++ ++ if ((fdt32_to_cpu(*cuint) == bank_offset) && ++ (_fdt_get_status(fdt,pinctrl_subnode) != ++ DT_STATUS_DISABLED)) { ++ return pinctrl_subnode; ++ } ++ } ++ ++ return 0; ++} ++ ++static int get_pinctrl_from_fdt(void *fdt, int node, ++ struct stm32_pinctrl *pinctrl, size_t count) ++{ ++ const fdt32_t *cuint, *slewrate; ++ int len; ++ int pinctrl_node; ++ int bank_node; ++ int clk; ++ uint32_t i; ++ uint32_t speed = GPIO_SPEED_LOW; ++ uint32_t pull = GPIO_NO_PULL; ++ size_t found = 0; ++ ++ cuint = fdt_getprop(fdt, node, "pinmux", &len); ++ if (cuint == NULL) { ++ return -FDT_ERR_NOTFOUND; ++ } ++ ++ pinctrl_node = fdt_parent_offset(fdt, fdt_parent_offset(fdt, node)); ++ if (pinctrl_node < 0) { ++ return -FDT_ERR_NOTFOUND; ++ } ++ ++ slewrate = fdt_getprop(fdt, node, "slew-rate", NULL); ++ if (slewrate != NULL) { ++ speed = fdt32_to_cpu(*slewrate); ++ } ++ ++ if (fdt_getprop(fdt, node, "bias-pull-up", NULL) != NULL) { ++ pull = GPIO_PULL_UP; ++ } else if (fdt_getprop(fdt, node, "bias-pull-down", NULL) != NULL) { ++ pull = GPIO_PULL_DOWN; ++ } else { ++ DMSG("No bias configured in node %d\n", node); ++ } ++ ++ for (i = 0; i < ((uint32_t)len / sizeof(uint32_t)); i++) { ++ uint32_t pincfg; ++ uint32_t bank; ++ uint32_t pin; ++ uint32_t mode; ++ uint32_t alternate = GPIO_ALTERNATE_0; ++ ++ pincfg = fdt32_to_cpu(*cuint); ++ cuint++; ++ ++ bank = (pincfg & DT_GPIO_BANK_MASK) >> DT_GPIO_BANK_SHIFT; ++ ++ pin = (pincfg & DT_GPIO_PIN_MASK) >> DT_GPIO_PIN_SHIFT; ++ ++ mode = pincfg & DT_GPIO_MODE_MASK; ++ ++ switch (mode) { ++ case 0: ++ mode = GPIO_MODE_INPUT; ++ break; ++ case 1: ++ case 2: ++ case 3: ++ case 4: ++ case 5: ++ case 6: ++ case 7: ++ case 8: ++ case 9: ++ case 10: ++ case 11: ++ case 12: ++ case 13: ++ case 14: ++ case 15: ++ case 16: ++ alternate = mode - 1U; ++ mode = GPIO_MODE_ALTERNATE; ++ break; ++ case 17: ++ mode = GPIO_MODE_ANALOG; ++ break; ++ default: ++ mode = GPIO_MODE_OUTPUT; ++ break; ++ } ++ ++ if (fdt_getprop(fdt, node, "drive-open-drain", NULL) != NULL) { ++ mode |= GPIO_OPEN_DRAIN; ++ } ++ ++ bank_node = ckeck_gpio_bank(fdt, bank, pinctrl_node); ++ if (bank_node == 0) { ++ panic("PINCTRL inconsistent in DT"); ++ } ++ ++ clk = fdt_get_clock_id(fdt, bank_node); ++ if (clk < 0) { ++ return -FDT_ERR_NOTFOUND; ++ } ++ ++ /* Platform knows the clock: assert it is okay */ ++ assert(clk == stm32_get_gpio_bank_clock(bank)); ++ stm32_clock_enable((unsigned int)clk); ++ stm32_clock_disable((unsigned int)clk); ++ ++ if (found < count) { ++ struct stm32_pinctrl *cfg = &pinctrl[found]; ++ ++ cfg->bank = (uint8_t)bank; ++ cfg->pin = (uint8_t)pin; ++ cfg->active_cfg.moder = mode & ~GPIO_OPEN_DRAIN; ++ cfg->active_cfg.otyper = mode & GPIO_OPEN_DRAIN ? 1 : 0; ++ cfg->active_cfg.ospeedr = speed; ++ cfg->active_cfg.pupdr = pull; ++ cfg->active_cfg.odr = 0; ++ cfg->active_cfg.afr = alternate; ++ cfg->standby_cfg.moder = GPIO_MODE_ANALOG; ++ cfg->standby_cfg.pupdr = GPIO_NO_PULL; ++ } ++ ++ found++; ++ } ++ ++ return (int)found; ++} ++ ++/* ++ * stm32_pinctrl_fdt_get_pinctrl - get PINCTRL config from a DT device node ++ * ++ * Argument cfg can be set to NULL or count to 0: the function will return only ++ * the number of PINCTRL instances found in the device tree for the target ++ * device. ++ * ++ * If more instances than count are found then the function returns the ++ * effective number of PINCTRL found but will fill array cfg only according ++ * to the value of count. ++ * ++ * @fdt: device tree ++ * @node: device node in the device tree ++ * @cfg: NULL or pointer to array of struct stm32_pinctrl ++ * @count: number of elements pointed by argument cfg ++ * ++ * Return the number of PINCTRL instances found and a negative value on error ++ */ ++int stm32_pinctrl_fdt_get_pinctrl(void *fdt, int device_node, ++ struct stm32_pinctrl *cfg, size_t count) ++{ ++ const fdt32_t *cuint; ++ int lenp; ++ uint32_t i; ++ size_t found = 0; ++ ++ cuint = fdt_getprop(fdt, device_node, "pinctrl-0", &lenp); ++ if (cuint == NULL) { ++ return -FDT_ERR_NOTFOUND; ++ } ++ ++ for (i = 0; i < ((uint32_t)lenp / 4U); i++) { ++ int node; ++ int subnode; ++ ++ node = fdt_node_offset_by_phandle(fdt, fdt32_to_cpu(*cuint)); ++ if (node < 0) { ++ return -FDT_ERR_NOTFOUND; ++ } ++ ++ fdt_for_each_subnode(subnode, fdt, node) { ++ size_t n; ++ int rc; ++ ++ if (count > found) { ++ n = count - found; ++ } else { ++ n = 0; ++ } ++ ++ rc = get_pinctrl_from_fdt(fdt, subnode, &cfg[found], n); ++ if (rc < 0) { ++ return rc; ++ } ++ ++ found += (size_t)rc; ++ } ++ ++ cuint++; ++ } ++ ++ return (int)found; ++} ++#endif /*CFG_DT*/ ++ ++/* ++ * stm32_gpio_set_secure_cfg - Set secure field of an output GPIO instance ++ * ++ * @bank: GPIO bank ++ * @pin: GPIO pin position in bank ++ * @secure: Secure field, either false (non secure) or true (secure) ++ */ ++void stm32_gpio_set_secure_cfg(uint32_t bank, uint32_t pin, bool secure) ++{ ++ uintptr_t base = stm32_get_gpio_bank_base(bank); ++ int clock = stm32_get_gpio_bank_clock(bank); ++ ++ assert(pin <= GPIO_PIN_MAX); ++ ++ assert(!(secure && stm32mp_gpio_bank_is_non_secure(bank))); ++ ++ stm32_clock_enable((unsigned long)clock); ++ ++ if (secure) { ++ mmio_setbits_32(base + GPIO_SECR_OFFSET, BIT(pin)); ++ } else { ++ mmio_clrbits_32(base + GPIO_SECR_OFFSET, BIT(pin)); ++ } ++ ++ stm32_clock_disable((unsigned long)clock); ++} +diff --git a/core/drivers/stm32_i2c.c b/core/drivers/stm32_i2c.c +new file mode 100644 +index 0000000..f7f0f70 +--- /dev/null ++++ b/core/drivers/stm32_i2c.c +@@ -0,0 +1,1629 @@ ++// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause ++/* ++ * Copyright (c) 2016-2018, STMicroelectronics - All Rights Reserved ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* STM32 I2C registers offsets */ ++#define I2C_CR1 0x00U ++#define I2C_CR2 0x04U ++#define I2C_OAR1 0x08U ++#define I2C_OAR2 0x0CU ++#define I2C_TIMINGR 0x10U ++#define I2C_TIMEOUTR 0x14U ++#define I2C_ISR 0x18U ++#define I2C_ICR 0x1CU ++#define I2C_PECR 0x20U ++#define I2C_RXDR 0x24U ++#define I2C_TXDR 0x28U ++ ++#define TIMINGR_CLEAR_MASK 0xF0FFFFFFU ++ ++#define MAX_NBYTE_SIZE 255U ++ ++#define I2C_NSEC_PER_SEC 1000000000L ++ ++/* ++ * 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) ++ * @vddat_max: Max data valid time (ns) ++ * @sudat_min: Min data setup time (ns) ++ * @l_min: Min low period of the SCL clock (ns) ++ * @h_min: Min high period of the SCL clock (ns) ++ */ ++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; ++ uint32_t vddat_max; ++ uint32_t sudat_min; ++ uint32_t l_min; ++ uint32_t h_min; ++}; ++ ++/* ++ * struct i2c_timing_s - Private I2C output parameters. ++ * @scldel: Data setup time ++ * @sdadel: Data hold time ++ * @sclh: SCL high period (master mode) ++ * @sclh: SCL low period (master mode) ++ * @is_saved: True if relating to a configuration candidate ++ */ ++struct i2c_timing_s { ++ uint8_t scldel; ++ uint8_t sdadel; ++ uint8_t sclh; ++ uint8_t scll; ++ bool is_saved; ++}; ++ ++/** ++ * All these values are coming from I2C Specification, Version 6.0, 4th of ++ * April 2014. ++ * ++ * Table10. Characteristics of the SDA and SCL bus lines for Standard, Fast, ++ * and Fast-mode Plus I2C-bus devices. ++ */ ++static const struct i2c_spec_s i2c_specs[] = { ++ [I2C_SPEED_STANDARD] = { ++ .rate = STANDARD_RATE, ++ .rate_min = 8000, ++ .rate_max = 120000, ++ .fall_max = 300, ++ .rise_max = 1000, ++ .hddat_min = 0, ++ .vddat_max = 3450, ++ .sudat_min = 250, ++ .l_min = 4700, ++ .h_min = 4000, ++ }, ++ [I2C_SPEED_FAST] = { ++ .rate = FAST_RATE, ++ .rate_min = 320000, ++ .rate_max = 480000, ++ .fall_max = 300, ++ .rise_max = 300, ++ .hddat_min = 0, ++ .vddat_max = 900, ++ .sudat_min = 100, ++ .l_min = 1300, ++ .h_min = 600, ++ }, ++ [I2C_SPEED_FAST_PLUS] = { ++ .rate = FAST_PLUS_RATE, ++ .rate_min = 800000, ++ .rate_max = 1200000, ++ .fall_max = 100, ++ .rise_max = 120, ++ .hddat_min = 0, ++ .vddat_max = 450, ++ .sudat_min = 50, ++ .l_min = 500, ++ .h_min = 260, ++ }, ++}; ++ ++static int i2c_request_memory_write(struct i2c_handle_s *hi2c, ++ uint16_t dev_addr, uint16_t mem_addr, ++ uint16_t mem_add_size, ++ uint64_t tick_to, uint64_t tick_start); ++static int i2c_request_memory_read(struct i2c_handle_s *hi2c, uint16_t dev_addr, ++ uint16_t mem_addr, uint16_t mem_add_size, ++ uint64_t tick_to, uint64_t tick_start); ++ ++/* Private functions to handle flags during polling transfer */ ++static int i2c_wait_flag(struct i2c_handle_s *hi2c, uint32_t flag, ++ uint8_t awaited_value, ++ uint64_t tick_to, uint64_t tick_start); ++static int i2c_wait_txis(struct i2c_handle_s *hi2c, ++ uint64_t tick_to, uint64_t tick_start); ++static int i2c_wait_stop(struct i2c_handle_s *hi2c, ++ uint64_t tick_to, uint64_t tick_start); ++static int i2c_ack_failed(struct i2c_handle_s *hi2c, ++ uint64_t tick_to, uint64_t tick_start); ++ ++/* Private function to flush TXDR register */ ++static void i2c_flush_txdr(struct i2c_handle_s *hi2c); ++ ++/* Private function to start, restart or stop a transfer */ ++static void i2c_transfer_config(struct i2c_handle_s *hi2c, uint16_t dev_addr, ++ uint16_t size, uint32_t i2c_mode, ++ uint32_t request); ++ ++static uintptr_t get_base(struct i2c_handle_s *hi2c) ++{ ++ if (!cpu_mmu_enabled()) ++ return hi2c->pbase; ++ ++ return hi2c->vbase; ++} ++ ++static bool i2c_is_secure(struct i2c_handle_s *hi2c) ++{ ++ return hi2c->dt_status == DT_STATUS_OK_SEC; ++} ++ ++static uint64_t ms2tick(uint32_t timeout_ms) ++{ ++ return ((uint64_t)timeout_ms * read_cntfrq()) / 1000; ++} ++ ++static uint64_t timeout_start(void) ++{ ++ return read_cntpct(); ++} ++ ++static bool timeout_elapsed(uint64_t tick_start, uint64_t tick_to) ++{ ++ return (tick_to != 0U) && ((read_cntpct() - tick_start) > tick_to); ++} ++ ++static void notif_i2c_timeout(struct i2c_handle_s *hi2c) ++{ ++ hi2c->i2c_err |= I2C_ERROR_TIMEOUT; ++ hi2c->i2c_mode = I2C_MODE_NONE; ++ hi2c->i2c_state = I2C_STATE_READY; ++} ++ ++static void save_cfg(struct i2c_handle_s *hi2c, struct i2c_cfg *cfg) ++{ ++ uintptr_t base = get_base(hi2c); ++ ++ stm32_clock_enable(hi2c->clock); ++ ++ cfg->cr1 = mmio_read_32(base + I2C_CR1); ++ cfg->cr2 = mmio_read_32(base + I2C_CR2); ++ cfg->oar1 = mmio_read_32(base + I2C_OAR1); ++ cfg->oar2 = mmio_read_32(base + I2C_OAR2); ++ cfg->timingr = mmio_read_32(base + I2C_TIMINGR); ++ ++ stm32_clock_disable(hi2c->clock); ++} ++ ++static void restore_cfg(struct i2c_handle_s *hi2c, struct i2c_cfg *cfg) ++{ ++ uintptr_t base = get_base(hi2c); ++ ++ if (hi2c->lock) { ++ panic(); ++ } ++ ++ stm32_clock_enable(hi2c->clock); ++ ++ mmio_clrbits_32(base + I2C_CR1, I2C_CR1_PE); ++ mmio_write_32(base + I2C_TIMINGR, cfg->timingr & TIMINGR_CLEAR_MASK); ++ mmio_write_32(base + I2C_OAR1, cfg->oar1); ++ mmio_write_32(base + I2C_CR2, cfg->cr2); ++ mmio_write_32(base + I2C_OAR2, cfg->oar2); ++ mmio_write_32(base + I2C_CR1, cfg->cr1 & ~I2C_CR1_PE); ++ mmio_setbits_32(base + I2C_CR1, cfg->cr1 & I2C_CR1_PE); ++ ++ stm32_clock_disable(hi2c->clock); ++} ++ ++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); ++} ++ ++static void __maybe_unused dump_i2c(struct i2c_handle_s *hi2c) ++{ ++ uintptr_t __maybe_unused base = get_base(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)); ++ ++ stm32_clock_disable(hi2c->clock); ++} ++ ++/* ++ * @brief Compute the I2C device timings. ++ * @param init: Ref to the initialization configuration structure ++ * @param clock_src: I2C clock source frequency (Hz) ++ * @param timing: Pointer to the final computed timing result ++ * @retval 0 if OK, negative value else ++ */ ++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; ++ uint32_t speed_freq; ++ uint32_t i2cclk = UDIV_ROUND_NEAREST(I2C_NSEC_PER_SEC, clock_src); ++ uint32_t i2cbus; ++ uint32_t p_prev = I2C_TIMINGR_PRESC_MAX; ++ uint32_t af_delay_min; ++ uint32_t af_delay_max; ++ uint32_t dnf_delay; ++ uint32_t tsync; ++ uint32_t clk_min; ++ uint32_t clk_max; ++ int clk_error_prev; ++ uint16_t p; ++ uint16_t l; ++ uint16_t a; ++ uint16_t h; ++ unsigned int sdadel_min; ++ unsigned int sdadel_max; ++ unsigned int scldel_min; ++ unsigned int delay; ++ 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); ++ return -1; ++ } ++ ++ speed_freq = i2c_specs[mode].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); ++ return -1; ++ } ++ ++ if (init->digital_filter_coef > STM32_I2C_DIGITAL_FILTER_MAX) { ++ EMSG("DNF out of bound %d/%d\n", ++ init->digital_filter_coef, STM32_I2C_DIGITAL_FILTER_MAX); ++ return -1; ++ } ++ ++ /* Analog and Digital Filters */ ++ af_delay_min = (init->analog_filter ? ++ STM32_I2C_ANALOG_FILTER_DELAY_MIN : 0); ++ af_delay_max = (init->analog_filter ? ++ STM32_I2C_ANALOG_FILTER_DELAY_MAX : 0); ++ dnf_delay = init->digital_filter_coef * i2cclk; ++ ++ sdadel_min = i2c_specs[mode].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; ++ 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; ++ ++ DMSG("I2C SDADEL(min/max): %u/%u, SCLDEL(Min): %u\n", ++ sdadel_min, sdadel_max, scldel_min); ++ ++ memset(&solutions, 0, sizeof(solutions)); ++ ++ /* Compute possible values for PRESC, SCLDEL and SDADEL */ ++ for (p = 0; p < I2C_TIMINGR_PRESC_MAX; p++) { ++ for (l = 0; l < I2C_TIMINGR_SCLDEL_MAX; l++) { ++ uint32_t scldel = (l + 1) * (p + 1) * i2cclk; ++ ++ if (scldel < scldel_min) { ++ continue; ++ } ++ ++ for (a = 0; a < I2C_TIMINGR_SDADEL_MAX; a++) { ++ uint32_t sdadel = (a * (p + 1) + 1) * i2cclk; ++ ++ if ((sdadel >= sdadel_min) && ++ (sdadel <= sdadel_max) && ++ (p != p_prev)) { ++ solutions[p].scldel = l; ++ solutions[p].sdadel = a; ++ solutions[p].is_saved = true; ++ p_prev = p; ++ break; ++ } ++ } ++ ++ if (p_prev == p) { ++ break; ++ } ++ } ++ } ++ ++ if (p_prev == I2C_TIMINGR_PRESC_MAX) { ++ EMSG(" I2C no Prescaler solution\n"); ++ 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; ++ ++ /* ++ * Among prescaler possibilities discovered above figures out SCL Low ++ * and High Period. Provided: ++ * - SCL Low Period has to be higher than Low Period of the SCL Clock ++ * defined by I2C Specification. I2C Clock has to be lower than ++ * (SCL Low Period - Analog/Digital filters) / 4. ++ * - SCL High Period has to be lower than High Period of the SCL Clock ++ * defined by I2C Specification. ++ * - I2C Clock has to be lower than SCL High Period. ++ */ ++ for (p = 0; p < I2C_TIMINGR_PRESC_MAX; p++) { ++ uint32_t prescaler = (p + 1) * i2cclk; ++ ++ if (!solutions[p].is_saved) { ++ continue; ++ } ++ ++ 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) || ++ (i2cclk >= ++ ((tscl_l - af_delay_min - dnf_delay) / 4))) { ++ continue; ++ } ++ ++ for (h = 0; h < I2C_TIMINGR_SCLH_MAX; h++) { ++ uint32_t tscl_h = ((h + 1) * prescaler) + tsync; ++ uint32_t tscl = tscl_l + tscl_h + ++ init->rise_time + ++ init->fall_time; ++ ++ if ((tscl >= clk_min) && (tscl <= clk_max) && ++ (tscl_h >= i2c_specs[mode].h_min) && ++ (i2cclk < tscl_h)) { ++ int clk_error = tscl - i2cbus; ++ ++ if (clk_error < 0) { ++ clk_error = -clk_error; ++ } ++ ++ if (clk_error < clk_error_prev) { ++ clk_error_prev = clk_error; ++ solutions[p].scll = l; ++ solutions[p].sclh = h; ++ s = p; ++ } ++ } ++ } ++ } ++ } ++ ++ if (s < 0) { ++ EMSG(" I2C no solution at all\n"); ++ return -1; ++ } ++ ++ /* Finalize timing settings */ ++ *timing = I2C_SET_TIMINGR_PRESC(s) | ++ I2C_SET_TIMINGR_SCLDEL(solutions[s].scldel) | ++ I2C_SET_TIMINGR_SDADEL(solutions[s].sdadel) | ++ I2C_SET_TIMINGR_SCLH(solutions[s].sclh) | ++ I2C_SET_TIMINGR_SCLL(solutions[s].scll); ++ ++ DMSG("I2C TIMINGR (PRESC/SCLDEL/SDADEL): %i/%i/%i\n", ++ s, solutions[s].scldel, solutions[s].sdadel); ++ DMSG("I2C TIMINGR (SCLH/SCLL): %i/%i\n", ++ solutions[s].sclh, solutions[s].scll); ++ DMSG("I2C TIMINGR: 0x%x\n", *timing); ++ ++ return 0; ++} ++ ++/* ++ * @brief Setup the I2C device timings. ++ * @param hi2c: Pointer to a struct i2c_handle_s structure that contains ++ * the configuration information for the specified I2C. ++ * @param init: Ref to the initialization configuration structure ++ * @param timing: Pointer to the final computed timing result ++ * @retval 0 if OK, negative value else ++ */ ++static int i2c_setup_timing(struct i2c_handle_s *hi2c, ++ struct stm32_i2c_init_s *init, ++ uint32_t *timing) ++{ ++ int rc = 0; ++ uint32_t clock_src; ++ ++ clock_src = stm32_clock_get_rate(hi2c->clock); ++ if (clock_src == 0U) { ++ EMSG("I2C clock rate is 0\n"); ++ return -1; ++ } ++ ++ 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); ++ } else { ++ break; ++ } ++ } ++ } while (rc != 0); ++ ++ if (rc != 0) { ++ EMSG("Impossible to compute I2C timings\n"); ++ 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", ++ init->rise_time, init->fall_time); ++ DMSG("I2C Analog Filter(%s), DNF(%i)\n", ++ (init->analog_filter ? "On" : "Off"), init->digital_filter_coef); ++ ++ return 0; ++} ++ ++/* ++ * @brief Configure I2C Analog noise filter. ++ * @param hi2c: Pointer to a struct i2c_handle_s structure that contains ++ * the configuration information for the specified I2C peripheral. ++ * @param analog_filter: New state of the Analog filter ++ * @retval 0 if OK, negative value else ++ */ ++static int i2c_config_analog_filter(struct i2c_handle_s *hi2c, ++ uint32_t analog_filter) ++{ ++ uintptr_t base = get_base(hi2c); ++ ++ if ((hi2c->i2c_state != I2C_STATE_READY) || (hi2c->lock != 0U)) { ++ return -1; ++ } ++ ++ hi2c->lock = 1; ++ ++ hi2c->i2c_state = I2C_STATE_BUSY; ++ ++ /* Disable the selected I2C peripheral */ ++ mmio_clrbits_32(base + I2C_CR1, I2C_CR1_PE); ++ ++ /* Reset I2Cx ANOFF bit */ ++ mmio_clrbits_32(base + I2C_CR1, I2C_CR1_ANFOFF); ++ ++ /* Set analog filter bit*/ ++ mmio_setbits_32(base + I2C_CR1, analog_filter); ++ ++ /* Enable the selected I2C peripheral */ ++ mmio_setbits_32(base + I2C_CR1, I2C_CR1_PE); ++ ++ hi2c->i2c_state = I2C_STATE_READY; ++ ++ hi2c->lock = 0; ++ ++ return 0; ++} ++ ++/* ++ * @brief Get I2C setup information from the device tree and set pinctrl ++ * configuration. ++ * @param fdt: Pointer to the device tree ++ * @param node: I2C node offset ++ * @param init: Ref to the initialization configuration structure ++ * @retval 0 if OK, negative value else ++ */ ++int stm32_i2c_get_setup_from_fdt(void *fdt, int node, ++ struct stm32_i2c_init_s *init, ++ struct stm32_pinctrl **pinctrl, ++ size_t *pinctrl_count) ++{ ++ const fdt32_t *cuint; ++ 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); ++ } ++ ++ cuint = fdt_getprop(fdt, node, "i2c-scl-falling-time-ns", NULL); ++ if (cuint == NULL) { ++ init->fall_time = STM32_I2C_FALL_TIME_DEFAULT; ++ } else { ++ init->fall_time = fdt32_to_cpu(*cuint); ++ } ++ ++ cuint = fdt_getprop(fdt, node, "clock-frequency", NULL); ++ if (cuint == NULL) { ++ init->speed_mode = STM32_I2C_SPEED_DEFAULT; ++ } else { ++ switch (fdt32_to_cpu(*cuint)) { ++ case STANDARD_RATE: ++ init->speed_mode = I2C_SPEED_STANDARD; ++ break; ++ case FAST_RATE: ++ init->speed_mode = I2C_SPEED_FAST; ++ break; ++ case FAST_PLUS_RATE: ++ init->speed_mode = I2C_SPEED_FAST_PLUS; ++ break; ++ default: ++ init->speed_mode = STM32_I2C_SPEED_DEFAULT; ++ break; ++ } ++ } ++ ++ count = stm32_pinctrl_fdt_get_pinctrl(fdt, node, NULL, 0); ++ if (count <= 0) { ++ *pinctrl = NULL; ++ *pinctrl_count = 0; ++ return count; ++ } ++ ++ if (count > 2) { ++ panic("Too many PINCTRLs found"); ++ } ++ ++ *pinctrl = calloc(count, sizeof(**pinctrl)); ++ if (!*pinctrl) { ++ panic(); ++ } ++ ++ *pinctrl_count = stm32_pinctrl_fdt_get_pinctrl(fdt, node, ++ *pinctrl, count); ++ assert(*pinctrl_count == (unsigned int)count); ++ ++ return 0; ++} ++ ++/* ++ * @brief Initialize the I2C device. ++ * @param hi2c: Pointer to a struct i2c_handle_s structure that contains ++ * the configuration information for the specified I2C. ++ * @param init_data: Ref to the initialization configuration structure ++ * @retval 0 if OK, negative value else ++ */ ++int stm32_i2c_init(struct i2c_handle_s *hi2c, ++ struct stm32_i2c_init_s *init_data) ++{ ++ int rc = 0; ++ uint32_t timing; ++ uintptr_t base = get_base(hi2c); ++ ++ if (hi2c == NULL) { ++ return -1; ++ } ++ ++ if (hi2c->i2c_state == I2C_STATE_RESET) { ++ hi2c->lock = 0; ++ } ++ ++ hi2c->i2c_state = I2C_STATE_BUSY; ++ ++ rc = i2c_setup_timing(hi2c, init_data, &timing); ++ if (rc != 0) { ++ return rc; ++ } ++ ++ stm32_clock_enable(hi2c->clock); ++ ++ /* Disable the selected I2C peripheral */ ++ mmio_clrbits_32(base + I2C_CR1, I2C_CR1_PE); ++ ++ /* Configure I2Cx: Frequency range */ ++ mmio_write_32(base + I2C_TIMINGR, timing & TIMINGR_CLEAR_MASK); ++ ++ /* Disable Own Address1 before set the Own Address1 configuration */ ++ mmio_clrbits_32(base + I2C_OAR1, I2C_OAR1_OA1EN); ++ ++ /* Configure I2Cx: Own Address1 and ack own address1 mode */ ++ if (init_data->addressing_mode == I2C_ADDRESSINGMODE_7BIT) { ++ mmio_write_32(base + I2C_OAR1, ++ I2C_OAR1_OA1EN | init_data->own_address1); ++ } else { /* I2C_ADDRESSINGMODE_10BIT */ ++ mmio_write_32(base + I2C_OAR1, ++ I2C_OAR1_OA1EN | I2C_OAR1_OA1MODE | ++ init_data->own_address1); ++ } ++ ++ mmio_write_32(base + I2C_CR2, 0); ++ ++ /* Configure I2Cx: Addressing Master mode */ ++ if (init_data->addressing_mode == I2C_ADDRESSINGMODE_10BIT) { ++ mmio_setbits_32(base + I2C_CR2, I2C_CR2_ADD10); ++ } ++ ++ /* ++ * Enable the AUTOEND by default, and enable NACK ++ * (should be disabled only during Slave process). ++ */ ++ mmio_setbits_32(base + I2C_CR2, I2C_CR2_AUTOEND | I2C_CR2_NACK); ++ ++ /* Disable Own Address2 before set the Own Address2 configuration */ ++ mmio_clrbits_32(base + I2C_OAR2, I2C_DUALADDRESS_ENABLE); ++ ++ /* Configure I2Cx: Dual mode and Own Address2 */ ++ mmio_write_32(base + I2C_OAR2, ++ init_data->dual_address_mode | ++ init_data->own_address2 | ++ (init_data->own_address2_masks << 8)); ++ ++ /* Configure I2Cx: Generalcall and NoStretch mode */ ++ mmio_write_32(base + I2C_CR1, ++ init_data->general_call_mode | ++ init_data->no_stretch_mode); ++ ++ /* Enable the selected I2C peripheral */ ++ mmio_setbits_32(base + I2C_CR1, I2C_CR1_PE); ++ ++ hi2c->i2c_err = I2C_ERROR_NONE; ++ hi2c->i2c_state = I2C_STATE_READY; ++ hi2c->i2c_mode = I2C_MODE_NONE; ++ ++ rc = i2c_config_analog_filter(hi2c, init_data->analog_filter ? ++ I2C_ANALOGFILTER_ENABLE : ++ I2C_ANALOGFILTER_DISABLE); ++ if (rc != 0) { ++ EMSG("Cannot initialize I2C analog filter (%d)\n", rc); ++ stm32_clock_disable(hi2c->clock); ++ return rc; ++ } ++ ++ stm32_clock_disable(hi2c->clock); ++ ++ return rc; ++} ++ ++/* ++ * @brief Generic function to write an amount of data in blocking mode ++ * (for Memory Mode and Master Mode) ++ * @param hi2c: Pointer to a struct i2c_handle_s structure that contains ++ * the configuration information for the specified I2C. ++ * @param dev_addr: Target device address ++ * @param mem_addr: Internal memory address (if Memory Mode) ++ * @param mem_add_size: Size of internal memory address (if Memory Mode) ++ * @param p_data: Pointer to data buffer ++ * @param size: Amount of data to be sent ++ * @param timeout_ms: Timeout duration in milliseconds ++ * @param mode: Communication mode ++ * @retval 0 if OK, negative value else ++ */ ++static int i2c_write(struct i2c_handle_s *hi2c, uint16_t dev_addr, ++ uint16_t mem_addr, uint16_t mem_add_size, ++ uint8_t *p_data, uint16_t size, uint32_t timeout_ms, ++ enum i2c_mode_e mode) ++{ ++ uint64_t tick_start; ++ uintptr_t base = get_base(hi2c); ++ int rc = -1; ++ uint64_t tick_to = ms2tick(timeout_ms); ++ uint8_t *p_buff = p_data; ++ size_t xfer_size; ++ size_t xfer_count = size; ++ ++ if ((mode != I2C_MODE_MASTER) && (mode != I2C_MODE_MEM)) { ++ return -1; ++ } ++ ++ if ((hi2c->i2c_state != I2C_STATE_READY) || (hi2c->lock != 0U)) { ++ return -1; ++ } ++ ++ if ((p_data == NULL) || (size == 0U)) { ++ return -1; ++ } ++ ++ stm32_clock_enable(hi2c->clock); ++ ++ hi2c->lock = 1; ++ ++ tick_start = timeout_start(); ++ ++ if (i2c_wait_flag(hi2c, I2C_FLAG_BUSY, 1, ms2tick(I2C_TIMEOUT_BUSY_MS), ++ tick_start) != 0) { ++ goto bail; ++ } ++ ++ hi2c->i2c_state = I2C_STATE_BUSY_TX; ++ hi2c->i2c_mode = mode; ++ hi2c->i2c_err = I2C_ERROR_NONE; ++ ++ if (mode == I2C_MODE_MEM) { ++ /* In Memory Mode, Send Slave Address and Memory Address */ ++ if (i2c_request_memory_write(hi2c, dev_addr, ++ mem_addr, mem_add_size, ++ tick_to, tick_start) != 0) { ++ goto bail; ++ } ++ ++ if (xfer_count > MAX_NBYTE_SIZE) { ++ xfer_size = MAX_NBYTE_SIZE; ++ i2c_transfer_config(hi2c, dev_addr, xfer_size, ++ I2C_RELOAD_MODE, I2C_NO_STARTSTOP); ++ } else { ++ xfer_size = xfer_count; ++ i2c_transfer_config(hi2c, dev_addr, xfer_size, ++ I2C_AUTOEND_MODE, I2C_NO_STARTSTOP); ++ } ++ } else { ++ /* In Master Mode, Send Slave Address */ ++ if (xfer_count > MAX_NBYTE_SIZE) { ++ xfer_size = MAX_NBYTE_SIZE; ++ i2c_transfer_config(hi2c, dev_addr, xfer_size, ++ I2C_RELOAD_MODE, ++ I2C_GENERATE_START_WRITE); ++ } else { ++ xfer_size = xfer_count; ++ i2c_transfer_config(hi2c, dev_addr, xfer_size, ++ I2C_AUTOEND_MODE, ++ I2C_GENERATE_START_WRITE); ++ } ++ } ++ ++ do { ++ if (i2c_wait_txis(hi2c, tick_to, tick_start) != 0) { ++ goto bail; ++ } ++ ++ mmio_write_8(base + I2C_TXDR, *p_buff); ++ p_buff++; ++ xfer_count--; ++ xfer_size--; ++ ++ if ((xfer_count != 0U) && (xfer_size == 0U)) { ++ /* Wait until TCR flag is set */ ++ if (i2c_wait_flag(hi2c, I2C_FLAG_TCR, 0, tick_to, ++ tick_start) != 0) { ++ goto bail; ++ } ++ ++ if (xfer_count > MAX_NBYTE_SIZE) { ++ xfer_size = MAX_NBYTE_SIZE; ++ i2c_transfer_config(hi2c, dev_addr, ++ xfer_size, ++ I2C_RELOAD_MODE, ++ I2C_NO_STARTSTOP); ++ } else { ++ xfer_size = xfer_count; ++ i2c_transfer_config(hi2c, dev_addr, ++ xfer_size, ++ I2C_AUTOEND_MODE, ++ I2C_NO_STARTSTOP); ++ } ++ } ++ ++ } while (xfer_count > 0U); ++ ++ /* ++ * No need to Check TC flag, with AUTOEND mode the stop ++ * is automatically generated. ++ * Wait until STOPF flag is reset. ++ */ ++ if (i2c_wait_stop(hi2c, tick_to, tick_start) != 0) { ++ goto bail; ++ } ++ ++ mmio_write_32(base + I2C_ICR, I2C_FLAG_STOPF); ++ ++ mmio_clrbits_32(base + I2C_CR2, I2C_RESET_CR2); ++ ++ hi2c->i2c_state = I2C_STATE_READY; ++ hi2c->i2c_mode = I2C_MODE_NONE; ++ ++ rc = 0; ++ ++bail: ++ hi2c->lock = 0; ++ stm32_clock_disable(hi2c->clock); ++ ++ return rc; ++} ++ ++/* ++ * @brief Write an amount of data in blocking mode to a specific memory ++ * address. ++ * @param hi2c: Pointer to a struct i2c_handle_s structure that contains ++ * the configuration information for the specified I2C. ++ * @param dev_addr: Target device address ++ * @param mem_addr: Internal memory address ++ * @param mem_add_size: Size of internal memory address ++ * @param p_data: Pointer to data buffer ++ * @param size: Amount of data to be sent ++ * @param timeout_ms: Timeout duration in milliseconds ++ * @retval 0 if OK, negative value else ++ */ ++int stm32_i2c_mem_write(struct i2c_handle_s *hi2c, uint16_t dev_addr, ++ uint16_t mem_addr, uint16_t mem_add_size, ++ uint8_t *p_data, uint16_t size, uint32_t timeout_ms) ++{ ++ return i2c_write(hi2c, dev_addr, mem_addr, mem_add_size, ++ p_data, size, timeout_ms, I2C_MODE_MEM); ++} ++ ++/* ++ * @brief Transmits in master mode an amount of data in blocking mode. ++ * @param hi2c: Pointer to a struct i2c_handle_s structure that contains ++ * the configuration information for the specified I2C. ++ * @param dev_addr: Target device address ++ * @param p_data: Pointer to data buffer ++ * @param size: Amount of data to be sent ++ * @param timeout_ms: Timeout duration in milliseconds ++ * @retval 0 if OK, negative value else ++ */ ++int stm32_i2c_master_transmit(struct i2c_handle_s *hi2c, uint16_t dev_addr, ++ uint8_t *p_data, uint16_t size, ++ uint32_t timeout_ms) ++{ ++ return i2c_write(hi2c, dev_addr, 0, 0, ++ p_data, size, timeout_ms, I2C_MODE_MASTER); ++} ++ ++/* ++ * Optimized 1 byte read/write function for unpaged sequences. ++ * 8-bit addressing mode / single byte transferred / use default I2C timeout. ++ * 'unpg88' refers to 8bit address/8bit value. ++ */ ++int stm32_i2c_read_write_membyte(struct i2c_handle_s *hi2c, uint16_t dev_addr, ++ unsigned int mem_addr, uint8_t *p_data, ++ bool write) ++{ ++ uint64_t tick_start; ++ uintptr_t base = get_base(hi2c); ++ int rc = 1; ++ uint64_t tick_to = ms2tick(I2C_TIMEOUT_BUSY_MS); ++ uint8_t *p_buff = p_data; ++ ++ if ((hi2c->i2c_state != I2C_STATE_READY) || ++ (hi2c->lock != 0U) || ++ (p_data == NULL)) { ++ return 1; ++ } ++ ++ stm32_clock_enable(hi2c->clock); ++ ++ hi2c->lock = 1; ++ ++ tick_start = timeout_start(); ++ if (i2c_wait_flag(hi2c, I2C_FLAG_BUSY, 1, tick_to, tick_start) != 0) { ++ goto bail; ++ } ++ ++ hi2c->i2c_state = write ? I2C_STATE_BUSY_TX : I2C_STATE_BUSY_RX; ++ hi2c->i2c_mode = I2C_MODE_MEM; ++ hi2c->i2c_err = I2C_ERROR_NONE; ++ ++ i2c_transfer_config(hi2c, dev_addr, I2C_MEMADD_SIZE_8BIT, ++ write ? I2C_RELOAD_MODE : I2C_SOFTEND_MODE, ++ I2C_GENERATE_START_WRITE); ++ ++ tick_start = timeout_start(); ++ if (i2c_wait_txis(hi2c, tick_to, tick_start) != 0) { ++ goto bail; ++ } ++ ++ mmio_write_8(base + I2C_TXDR, (uint8_t)(mem_addr & 0x0FFU)); ++ ++ tick_start = timeout_start(); ++ if (i2c_wait_flag(hi2c, write ? I2C_FLAG_TCR : I2C_FLAG_TC, 0, ++ tick_to, tick_start) != 0) { ++ goto bail; ++ } ++ ++ i2c_transfer_config(hi2c, dev_addr, I2C_MEMADD_SIZE_8BIT, ++ I2C_AUTOEND_MODE, ++ write ? I2C_NO_STARTSTOP : I2C_GENERATE_START_READ); ++ ++ tick_start = timeout_start(); ++ if (write) { ++ if (i2c_wait_txis(hi2c, tick_to, tick_start) != 0) { ++ goto bail; ++ } ++ mmio_write_8(base + I2C_TXDR, *p_buff); ++ ++ } else { ++ if (i2c_wait_flag(hi2c, I2C_FLAG_RXNE, 0, ++ tick_to, tick_start) != 0) { ++ goto bail; ++ } ++ *p_buff = mmio_read_8(base + I2C_RXDR); ++ } ++ ++ tick_start = timeout_start(); ++ if (i2c_wait_stop(hi2c, tick_to, tick_start) != 0) { ++ goto bail; ++ } ++ ++ mmio_write_32(base + I2C_ICR, I2C_FLAG_STOPF); ++ mmio_clrbits_32(base + I2C_CR2, I2C_RESET_CR2); ++ ++ hi2c->i2c_state = I2C_STATE_READY; ++ hi2c->i2c_mode = I2C_MODE_NONE; ++ ++ rc = 0; ++ ++bail: ++ hi2c->lock = 0; ++ stm32_clock_disable(hi2c->clock); ++ ++ return rc; ++} ++ ++/* ++ * @brief Generic function to read an amount of data in blocking mode ++ * (for Memory Mode and Master Mode) ++ * @param hi2c: Pointer to a struct i2c_handle_s structure that contains ++ * the configuration information for the specified I2C. ++ * @param dev_addr: Target device address ++ * @param mem_addr: Internal memory address (if Memory Mode) ++ * @param mem_add_size: Size of internal memory address (if Memory Mode) ++ * @param p_data: Pointer to data buffer ++ * @param size: Amount of data to be sent ++ * @param timeout_ms: Timeout duration in milliseconds ++ * @param mode: Communication mode ++ * @retval 0 if OK, negative value else ++ */ ++static int i2c_read(struct i2c_handle_s *hi2c, uint16_t dev_addr, ++ uint16_t mem_addr, uint16_t mem_add_size, ++ uint8_t *p_data, uint16_t size, uint32_t timeout_ms, ++ enum i2c_mode_e mode) ++{ ++ uintptr_t base = get_base(hi2c); ++ uint64_t tick_start; ++ int rc = -1; ++ uint64_t tick_to = ms2tick(timeout_ms); ++ uint8_t *p_buff = p_data; ++ size_t xfer_count = size; ++ size_t xfer_size; ++ ++ if ((mode != I2C_MODE_MASTER) && (mode != I2C_MODE_MEM)) { ++ return -1; ++ } ++ ++ if ((hi2c->i2c_state != I2C_STATE_READY) || (hi2c->lock != 0U)) { ++ return -1; ++ } ++ ++ if ((p_data == NULL) || (size == 0U)) { ++ return -1; ++ } ++ ++ stm32_clock_enable(hi2c->clock); ++ ++ hi2c->lock = 1; ++ ++ tick_start = timeout_start(); ++ if (i2c_wait_flag(hi2c, I2C_FLAG_BUSY, 1, ms2tick(I2C_TIMEOUT_BUSY_MS), ++ tick_start) != 0) { ++ goto bail; ++ } ++ ++ hi2c->i2c_state = I2C_STATE_BUSY_RX; ++ hi2c->i2c_mode = mode; ++ hi2c->i2c_err = I2C_ERROR_NONE; ++ ++ if (mode == I2C_MODE_MEM) { ++ /* Send Memory Address */ ++ if (i2c_request_memory_read(hi2c, dev_addr, ++ mem_addr, mem_add_size, ++ tick_to, tick_start) != 0) { ++ goto bail; ++ } ++ } ++ ++ /* ++ * Send Slave Address. ++ * Set NBYTES to write and reload if xfer_count > MAX_NBYTE_SIZE ++ * and generate RESTART. ++ */ ++ if (xfer_count > MAX_NBYTE_SIZE) { ++ xfer_size = MAX_NBYTE_SIZE; ++ i2c_transfer_config(hi2c, dev_addr, xfer_size, ++ I2C_RELOAD_MODE, I2C_GENERATE_START_READ); ++ } else { ++ xfer_size = xfer_count; ++ i2c_transfer_config(hi2c, dev_addr, xfer_size, ++ I2C_AUTOEND_MODE, I2C_GENERATE_START_READ); ++ } ++ ++ do { ++ if (i2c_wait_flag(hi2c, I2C_FLAG_RXNE, 0, tick_to, ++ tick_start) != 0) { ++ goto bail; ++ } ++ ++ *p_buff = mmio_read_8(base + I2C_RXDR); ++ p_buff++; ++ xfer_size--; ++ xfer_count--; ++ ++ if ((xfer_count != 0U) && (xfer_size == 0U)) { ++ if (i2c_wait_flag(hi2c, I2C_FLAG_TCR, 0, tick_to, ++ tick_start) != 0) { ++ goto bail; ++ } ++ ++ if (xfer_count > MAX_NBYTE_SIZE) { ++ xfer_size = MAX_NBYTE_SIZE; ++ i2c_transfer_config(hi2c, dev_addr, ++ xfer_size, ++ I2C_RELOAD_MODE, ++ I2C_NO_STARTSTOP); ++ } else { ++ xfer_size = xfer_count; ++ i2c_transfer_config(hi2c, dev_addr, ++ xfer_size, ++ I2C_AUTOEND_MODE, ++ I2C_NO_STARTSTOP); ++ } ++ } ++ } while (xfer_count > 0U); ++ ++ /* ++ * No need to Check TC flag, with AUTOEND mode the stop ++ * is automatically generated. ++ * Wait until STOPF flag is reset. ++ */ ++ if (i2c_wait_stop(hi2c, tick_to, tick_start) != 0) { ++ goto bail; ++ } ++ ++ mmio_write_32(base + I2C_ICR, I2C_FLAG_STOPF); ++ ++ mmio_clrbits_32(base + I2C_CR2, I2C_RESET_CR2); ++ ++ hi2c->i2c_state = I2C_STATE_READY; ++ hi2c->i2c_mode = I2C_MODE_NONE; ++ ++ rc = 0; ++ ++bail: ++ hi2c->lock = 0; ++ stm32_clock_disable(hi2c->clock); ++ ++ return rc; ++} ++ ++/* ++ * @brief Read an amount of data in blocking mode from a specific memory ++ * address. ++ * @param hi2c: Pointer to a struct i2c_handle_s structure that contains ++ * the configuration information for the specified I2C. ++ * @param dev_addr: Target device address ++ * @param mem_addr: Internal memory address ++ * @param mem_add_size: Size of internal memory address ++ * @param p_data: Pointer to data buffer ++ * @param size: Amount of data to be sent ++ * @param timeout_ms: Timeout duration in milliseconds ++ * @retval 0 if OK, negative value else ++ */ ++int stm32_i2c_mem_read(struct i2c_handle_s *hi2c, uint16_t dev_addr, ++ uint16_t mem_addr, uint16_t mem_add_size, ++ uint8_t *p_data, uint16_t size, uint32_t timeout_ms) ++{ ++ return i2c_read(hi2c, dev_addr, mem_addr, mem_add_size, ++ p_data, size, timeout_ms, I2C_MODE_MEM); ++} ++ ++/* ++ * @brief Receives in master mode an amount of data in blocking mode. ++ * @param hi2c: Pointer to a struct i2c_handle_s structure that contains ++ * the configuration information for the specified I2C. ++ * @param dev_addr: Target device address ++ * @param p_data: Pointer to data buffer ++ * @param size: Amount of data to be sent ++ * @param timeout_ms: Timeout duration in milliseconds ++ * @retval 0 if OK, negative value else ++ */ ++int stm32_i2c_master_receive(struct i2c_handle_s *hi2c, uint16_t dev_addr, ++ uint8_t *p_data, uint16_t size, ++ uint32_t timeout_ms) ++{ ++ return i2c_read(hi2c, dev_addr, 0, 0, ++ p_data, size, timeout_ms, I2C_MODE_MASTER); ++} ++ ++/* ++ * @brief Checks if target device is ready for communication. ++ * @note This function is used with Memory devices ++ * @param hi2c: Pointer to a struct i2c_handle_s structure that contains ++ * the configuration information for the specified I2C. ++ * @param dev_addr: Target device address ++ * @param trials: Number of trials ++ * @param timeout_ms: Timeout duration in milliseconds ++ * @retval True if device is ready, false else ++ */ ++bool stm32_i2c_is_device_ready(struct i2c_handle_s *hi2c, ++ uint16_t dev_addr, uint32_t trials, ++ uint32_t timeout_ms) ++{ ++ uintptr_t base = get_base(hi2c); ++ uint32_t i2c_trials = 0U; ++ bool rc = false; ++ uint64_t tick_to = ms2tick(timeout_ms); ++ ++ if ((hi2c->i2c_state != I2C_STATE_READY) || (hi2c->lock != 0U)) { ++ return rc; ++ } ++ ++ stm32_clock_enable(hi2c->clock); ++ ++ hi2c->lock = 1; ++ hi2c->i2c_mode = I2C_MODE_NONE; ++ ++ if ((mmio_read_32(base + I2C_ISR) & I2C_FLAG_BUSY) != 0U) { ++ goto bail; ++ } ++ ++ hi2c->i2c_state = I2C_STATE_BUSY; ++ hi2c->i2c_err = I2C_ERROR_NONE; ++ ++ do { ++ uint64_t tick_start; ++ uint32_t isr; ++ ++ /* Generate Start */ ++ if ((mmio_read_32(base + I2C_OAR1) & I2C_OAR1_OA1MODE) == 0) { ++ mmio_write_32(base + I2C_CR2, ++ (((uint32_t)dev_addr & I2C_CR2_SADD) | ++ I2C_CR2_START | I2C_CR2_AUTOEND) & ++ ~I2C_CR2_RD_WRN); ++ } else { ++ mmio_write_32(base + I2C_CR2, ++ (((uint32_t)dev_addr & I2C_CR2_SADD) | ++ I2C_CR2_START | I2C_CR2_ADD10) & ++ ~I2C_CR2_RD_WRN); ++ } ++ ++ /* ++ * No need to Check TC flag, with AUTOEND mode the stop ++ * is automatically generated. ++ * Wait until STOPF flag is set or a NACK flag is set. ++ */ ++ tick_start = timeout_start(); ++ do { ++ if (timeout_elapsed(tick_start, tick_to)) { ++ notif_i2c_timeout(hi2c); ++ goto bail; ++ } ++ ++ isr = mmio_read_32(base + I2C_ISR); ++ } while ((isr & (I2C_FLAG_STOPF | I2C_FLAG_AF)) == 0); ++ ++ if ((mmio_read_32(base + I2C_ISR) & I2C_FLAG_AF) == 0U) { ++ if (i2c_wait_flag(hi2c, I2C_FLAG_STOPF, 0, tick_to, ++ tick_start) != 0) { ++ goto bail; ++ } ++ ++ mmio_write_32(base + I2C_ICR, I2C_FLAG_STOPF); ++ ++ hi2c->i2c_state = I2C_STATE_READY; ++ ++ rc = true; ++ goto bail; ++ } ++ ++ if (i2c_wait_flag(hi2c, I2C_FLAG_STOPF, 0, tick_to, ++ tick_start) != 0) { ++ goto bail; ++ } ++ ++ mmio_write_32(base + I2C_ICR, I2C_FLAG_AF); ++ ++ mmio_write_32(base + I2C_ICR, I2C_FLAG_STOPF); ++ ++ if (i2c_trials == trials) { ++ mmio_setbits_32(base + I2C_CR2, I2C_CR2_STOP); ++ ++ if (i2c_wait_flag(hi2c, I2C_FLAG_STOPF, 0, tick_to, ++ tick_start) != 0) { ++ goto bail; ++ } ++ ++ mmio_write_32(base + I2C_ICR, I2C_FLAG_STOPF); ++ } ++ ++ i2c_trials++; ++ } while (i2c_trials < trials); ++ ++ notif_i2c_timeout(hi2c); ++ ++bail: ++#ifdef STM32_I2C_MAYBE_NON_SECURE ++ if (rc) { ++ /* Save the active secure configuraton */ ++ save_cfg(hi2c, &hi2c->sec_cfg); ++ } ++#endif ++ ++ hi2c->lock = 0; ++ stm32_clock_disable(hi2c->clock); ++ ++ return rc; ++} ++ ++/* ++ * @brief Master sends target device address followed by internal memory ++ * address for write request. ++ * @param hi2c: Pointer to a struct i2c_handle_s structure that contains ++ * the configuration information for the specified I2C. ++ * @param dev_addr: Target device address ++ * @param mem_addr: Internal memory address ++ * @param mem_add_size: Size of internal memory address ++ * @param tick_to: Tick timeout duration ++ * @param tick_start: Tick start value ++ * @retval 0 if OK, negative value else ++ */ ++static int i2c_request_memory_write(struct i2c_handle_s *hi2c, ++ uint16_t dev_addr, uint16_t mem_addr, ++ uint16_t mem_add_size, uint64_t tick_to, ++ uint64_t tick_start) ++{ ++ uintptr_t base = get_base(hi2c); ++ ++ i2c_transfer_config(hi2c, dev_addr, mem_add_size, I2C_RELOAD_MODE, ++ I2C_GENERATE_START_WRITE); ++ ++ if (i2c_wait_txis(hi2c, tick_to, tick_start) != 0) { ++ return -1; ++ } ++ ++ if (mem_add_size == I2C_MEMADD_SIZE_8BIT) { ++ /* Send Memory Address */ ++ mmio_write_8(base + I2C_TXDR, ++ (uint8_t)(mem_addr & 0x00FFU)); ++ } else { ++ /* Send MSB of Memory Address */ ++ mmio_write_8(base + I2C_TXDR, ++ (uint8_t)((mem_addr & 0xFF00U) >> 8)); ++ ++ if (i2c_wait_txis(hi2c, tick_to, tick_start) != 0) { ++ return -1; ++ } ++ ++ /* Send LSB of Memory Address */ ++ mmio_write_8(base + I2C_TXDR, ++ (uint8_t)(mem_addr & 0x00FFU)); ++ } ++ ++ if (i2c_wait_flag(hi2c, I2C_FLAG_TCR, 0, tick_to, tick_start) != 0) { ++ return -1; ++ } ++ ++ return 0; ++} ++ ++/* ++ * @brief Master sends target device address followed by internal memory ++ * address for read request. ++ * @param hi2c: Pointer to a struct i2c_handle_s structure that contains ++ * the configuration information for the specified I2C. ++ * @param dev_addr: Target device address ++ * @param mem_addr: Internal memory address ++ * @param mem_add_size: Size of internal memory address ++ * @param tick_to: Tick timeout duration ++ * @param tick_start: Tick start value ++ * @retval 0 if OK, negative value else ++ */ ++static int i2c_request_memory_read(struct i2c_handle_s *hi2c, uint16_t dev_addr, ++ uint16_t mem_addr, uint16_t mem_add_size, ++ uint64_t tick_to, uint64_t tick_start) ++{ ++ uintptr_t base = get_base(hi2c); ++ ++ i2c_transfer_config(hi2c, dev_addr, mem_add_size, I2C_SOFTEND_MODE, ++ I2C_GENERATE_START_WRITE); ++ ++ if (i2c_wait_txis(hi2c, tick_to, tick_start) != 0) { ++ return -1; ++ } ++ ++ if (mem_add_size == I2C_MEMADD_SIZE_8BIT) { ++ /* Send Memory Address */ ++ mmio_write_8(base + I2C_TXDR, ++ (uint8_t)(mem_addr & 0x00FFU)); ++ } else { ++ /* Send MSB of Memory Address */ ++ mmio_write_8(base + I2C_TXDR, ++ (uint8_t)((mem_addr & 0xFF00U) >> 8)); ++ ++ if (i2c_wait_txis(hi2c, tick_to, tick_start) != 0) { ++ return -1; ++ } ++ ++ /* Send LSB of Memory Address */ ++ mmio_write_8(base + I2C_TXDR, ++ (uint8_t)(mem_addr & 0x00FFU)); ++ } ++ ++ if (i2c_wait_flag(hi2c, I2C_FLAG_TC, 0, tick_to, tick_start) != 0) { ++ return -1; ++ } ++ ++ return 0; ++} ++ ++/* ++ * @brief I2C Tx data register flush process. ++ * @param hi2c: I2C handle ++ * @retval None ++ */ ++static void i2c_flush_txdr(struct i2c_handle_s *hi2c) ++{ ++ uintptr_t base = get_base(hi2c); ++ ++ /* ++ * If a pending TXIS flag is set, ++ * write a dummy data in TXDR to clear it. ++ */ ++ if ((mmio_read_32(base + I2C_ISR) & I2C_FLAG_TXIS) != 0U) { ++ mmio_write_32(base + I2C_TXDR, 0); ++ } ++ ++ /* Flush TX register if not empty */ ++ if ((mmio_read_32(base + I2C_ISR) & I2C_FLAG_TXE) == 0U) { ++ mmio_setbits_32(base + I2C_ISR, I2C_FLAG_TXE); ++ } ++} ++ ++/* ++ * @brief This function handles I2C Communication timeout. ++ * @param hi2c: Pointer to a struct i2c_handle_s structure that contains ++ * the configuration information for the specified I2C. ++ * @param flag: Specifies the I2C flag to check ++ * @param awaited_value: The awaited bit value for the flag (0 or 1) ++ * @param tick_to: Tick timeout duration ++ * @param tick_start: Tick start value ++ * @retval 0 if OK, negative value else ++ */ ++static int i2c_wait_flag(struct i2c_handle_s *hi2c, uint32_t flag, ++ uint8_t awaited_value, uint64_t tick_to, ++ uint64_t tick_start) ++{ ++ for ( ; ; ) { ++ uint32_t isr = read32(get_base(hi2c) + I2C_ISR); ++ ++ if (!!(isr & flag) != !!awaited_value) { ++ return 0; ++ } ++ ++ if (timeout_elapsed(tick_start, tick_to)) { ++ notif_i2c_timeout(hi2c); ++ hi2c->lock = 0; ++ ++ return -1; ++ } ++ } ++} ++ ++/* ++ * @brief This function handles I2C Communication timeout for specific usage ++ * of TXIS flag. ++ * @param hi2c: Pointer to a struct i2c_handle_s structure that contains ++ * the configuration information for the specified I2C. ++ * @param tick_to: Tick timeout duration ++ * @param tick_start: Tick start value ++ * @retval 0 if OK, negative value else ++ */ ++static int i2c_wait_txis(struct i2c_handle_s *hi2c, uint64_t tick_to, ++ uint64_t tick_start) ++{ ++ while ((read32(get_base(hi2c) + I2C_ISR) & I2C_FLAG_TXIS) == 0U) { ++ if (i2c_ack_failed(hi2c, tick_to, tick_start) != 0) { ++ return -1; ++ } ++ ++ if (timeout_elapsed(tick_start, tick_to)) { ++ notif_i2c_timeout(hi2c); ++ hi2c->lock = 0; ++ ++ return -1; ++ } ++ } ++ ++ return 0; ++} ++ ++/* ++ * @brief This function handles I2C Communication timeout for specific ++ * usage of STOP flag. ++ * @param hi2c: Pointer to a struct i2c_handle_s structure that contains ++ * the configuration information for the specified I2C. ++ * @param tick_to: Tick timeout duration ++ * @param tick_start: Tick start value ++ * @retval 0 if OK, negative value else ++ */ ++static int i2c_wait_stop(struct i2c_handle_s *hi2c, uint64_t tick_to, ++ uint64_t tick_start) ++{ ++ while ((read32(get_base(hi2c) + I2C_ISR) & I2C_FLAG_STOPF) == 0U) { ++ if (i2c_ack_failed(hi2c, tick_to, tick_start) != 0) { ++ return -1; ++ } ++ ++ if (timeout_elapsed(tick_start, tick_to)) { ++ notif_i2c_timeout(hi2c); ++ hi2c->lock = 0; ++ ++ return -1; ++ } ++ } ++ ++ return 0; ++} ++ ++/* ++ * @brief This function handles Acknowledge failed detection during ++ * an I2C Communication. ++ * @param hi2c: Pointer to a struct i2c_handle_s structure that contains ++ * the configuration information for the specified I2C. ++ * @param tick_to: Tick timeout duration ++ * @param tick_start: Tick start value ++ * @retval 0 if OK, negative value else ++ */ ++static int i2c_ack_failed(struct i2c_handle_s *hi2c, uint64_t tick_to, ++ uint64_t tick_start) ++{ ++ uintptr_t base = get_base(hi2c); ++ ++ if ((mmio_read_32(base + I2C_ISR) & I2C_FLAG_AF) == 0U) { ++ return 0; ++ } ++ ++ /* ++ * Wait until STOP Flag is reset. ++ * AutoEnd should be initiate after AF. ++ */ ++ while ((mmio_read_32(base + I2C_ISR) & I2C_FLAG_STOPF) == 0U) { ++ if (timeout_elapsed(tick_start, tick_to)) { ++ notif_i2c_timeout(hi2c); ++ hi2c->lock = 0; ++ ++ return -1; ++ } ++ } ++ ++ mmio_write_32(base + I2C_ICR, I2C_FLAG_AF); ++ ++ mmio_write_32(base + I2C_ICR, I2C_FLAG_STOPF); ++ ++ i2c_flush_txdr(hi2c); ++ ++ mmio_clrbits_32(base + I2C_CR2, I2C_RESET_CR2); ++ ++ hi2c->i2c_err |= I2C_ERROR_AF; ++ hi2c->i2c_state = I2C_STATE_READY; ++ hi2c->i2c_mode = I2C_MODE_NONE; ++ ++ hi2c->lock = 0; ++ ++ return -1; ++} ++ ++/* ++ * @brief Handles I2Cx communication when starting transfer or during transfer ++ * (TC or TCR flag are set). ++ * @param hi2c: I2C handle ++ * @param dev_addr: Specifies the slave address to be programmed ++ * @param size: Specifies the number of bytes to be programmed. ++ * This parameter must be a value between 0 and 255. ++ * @param i2c_mode: New state of the I2C START condition generation. ++ * This parameter can be one of the following values: ++ * @arg @ref I2C_RELOAD_MODE: Enable Reload mode. ++ * @arg @ref I2C_AUTOEND_MODE: Enable Automatic end mode. ++ * @arg @ref I2C_SOFTEND_MODE: Enable Software end mode. ++ * @param request: New state of the I2C START condition generation. ++ * This parameter can be one of the following values: ++ * @arg @ref I2C_NO_STARTSTOP: Don't Generate stop and start condition. ++ * @arg @ref I2C_GENERATE_STOP: Generate stop condition ++ * (size should be set to 0). ++ * @arg @ref I2C_GENERATE_START_READ: Generate Restart for read request. ++ * @arg @ref I2C_GENERATE_START_WRITE: Generate Restart for write request. ++ * @retval None ++ */ ++static void i2c_transfer_config(struct i2c_handle_s *hi2c, uint16_t dev_addr, ++ uint16_t size, uint32_t i2c_mode, ++ uint32_t request) ++{ ++ uint32_t clr_value, set_value; ++ ++ clr_value = (I2C_CR2_SADD | I2C_CR2_NBYTES | I2C_CR2_RELOAD | ++ I2C_CR2_AUTOEND | I2C_CR2_START | I2C_CR2_STOP) | ++ (I2C_CR2_RD_WRN & (request >> (31U - I2C_CR2_RD_WRN_OFFSET))); ++ ++ set_value = ((uint32_t)dev_addr & I2C_CR2_SADD) | ++ (((uint32_t)size << I2C_CR2_NBYTES_OFFSET) & I2C_CR2_NBYTES) | ++ i2c_mode | request; ++ ++ mmio_clrsetbits_32(get_base(hi2c) + I2C_CR2, clr_value, set_value); ++} ++ ++#ifdef STM32_I2C_MAYBE_NON_SECURE ++/* ++ * Secure side needs the PMIC. If it is secure, it can be freely used. ++ * If the PMIC is non secure, the configuration must be save/restored ++ * when used by the secure side. ++ */ ++#endif ++ ++void stm32_i2c_resume(struct i2c_handle_s *hi2c) ++{ ++ if (hi2c->i2c_state == I2C_STATE_READY) { ++ return; ++ } ++ ++ if ((hi2c->i2c_state != I2C_STATE_RESET) && ++ (hi2c->i2c_state != I2C_STATE_SUSPENDED)) { ++ panic(); ++ } ++ ++#ifdef STM32_I2C_MAYBE_NON_SECURE ++ if (!i2c_is_secure(hi2c)) { ++ stm32_pinctrl_store_standby_cfg(hi2c->pinctrl, ++ hi2c->pinctrl_count); ++ save_cfg(hi2c, &hi2c->alt_cfg); ++ } ++#endif ++ ++ stm32_pinctrl_load_active_cfg(hi2c->pinctrl, hi2c->pinctrl_count); ++ ++ if (hi2c->i2c_state == I2C_STATE_RESET) { ++ /* This is no valid I2C configuration loaded yet */ ++ return; ++ } ++ ++ restore_cfg(hi2c, &hi2c->sec_cfg); ++ ++ hi2c->i2c_state = I2C_STATE_READY; ++} ++ ++void stm32_i2c_suspend(struct i2c_handle_s *hi2c) ++{ ++ if ((hi2c->i2c_state == I2C_STATE_SUSPENDED)) { ++ return; ++ } ++ ++ if ((hi2c->i2c_state != I2C_STATE_READY)) { ++ panic(); ++ } ++ ++ save_cfg(hi2c, &hi2c->sec_cfg); ++ ++ stm32_pinctrl_load_standby_cfg(hi2c->pinctrl, ++ hi2c->pinctrl_count); ++ ++#ifdef STM32_I2C_MAYBE_NON_SECURE ++ if (!i2c_is_secure(hi2c)) { ++ restore_cfg(hi2c, &hi2c->alt_cfg); ++ } ++#endif ++ ++ hi2c->i2c_state = I2C_STATE_SUSPENDED; ++} +diff --git a/core/drivers/stm32_iwdg.c b/core/drivers/stm32_iwdg.c +new file mode 100644 +index 0000000..b2c8a68 +--- /dev/null ++++ b/core/drivers/stm32_iwdg.c +@@ -0,0 +1,308 @@ ++// SPDX-License-Identifier: BSD-3-Clause ++/* ++ * Copyright (c) 2017-2018, STMicroelectronics - All Rights Reserved ++ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* IWDG Compatibility */ ++#define IWDG_COMPAT "st,stm32mp1-iwdg" ++#define IWDG_TIMEOUT_US 100000U ++ ++/* IWDG registers offsets */ ++#define IWDG_KR_OFFSET 0x00U ++#define IWDG_PR_OFFSET 0x04U ++#define IWDG_RLR_OFFSET 0x08U ++#define IWDG_SR_OFFSET 0x0CU ++#define IWDG_EWCR_OFFSET 0x14U ++ ++/* Registers values */ ++#define IWDG_KR_ACCESS_KEY 0x5555 ++#define IWDG_KR_RELOAD_KEY 0xAAAA ++#define IWDG_KR_START_KEY 0xCCCC ++ ++#define IWDG_PR_DIV_4 0x00 ++#define IWDG_PR_DIV_256 0x06 ++ ++#define IWDG_RLR_MAX_VAL 0xFFF ++ ++#define IWDG_SR_EWU BIT(3) ++ ++#define IWDG_EWCR_EWIE BIT(15) ++#define IWDG_EWCR_EWIC BIT(14) ++#define IWDG_EWCR_EWIT_MASK GENMASK_32(11, 0) ++ ++struct stm32_iwdg_instance { ++ uintptr_t pbase; ++ uintptr_t vbase; ++ unsigned long clock; ++ uint8_t instance; ++ uint8_t flags; ++}; ++ ++static struct stm32_iwdg_instance *stm32_iwdg; ++static size_t stm32_iwdg_count; ++ ++static uintptr_t get_base(struct stm32_iwdg_instance *iwdg) ++{ ++ if (!cpu_mmu_enabled()) { ++ return iwdg->pbase; ++ } ++ ++ return iwdg->vbase; ++} ++ ++static int stm32_iwdg_get_dt_node(void *fdt, struct dt_node_info *info, ++ int offset) ++{ ++ int node; ++ ++ node = fdt_get_node(fdt, info, offset, IWDG_COMPAT); ++ if (node < 0) { ++ if (offset == -1) { ++ DMSG("No IDWG found"); ++ } ++ return -FDT_ERR_NOTFOUND; ++ } ++ ++ return node; ++} ++ ++static struct stm32_iwdg_instance *get_iwdg(unsigned int instance) ++{ ++ size_t i; ++ ++ for (i = 0; i < stm32_iwdg_count; i++) { ++ if (stm32_iwdg[i].instance == instance) { ++ return &stm32_iwdg[i]; ++ } ++ } ++ ++ return NULL; ++} ++ ++static enum itr_return stm32_iwdg_it_handler(struct itr_handler *handler) ++{ ++ unsigned int __maybe_unused cpu = get_core_pos(); ++ int instance = stm32mp_iwdg_irq2instance(handler->it); ++ struct stm32_iwdg_instance *iwdg = get_iwdg(instance); ++ uintptr_t iwdg_base = get_base(iwdg); ++ ++ DMSG("CPU %u IT Watchdog %d\n", cpu, instance + 1); ++ ++ stm32_iwdg_refresh(instance); ++ ++ stm32_clock_enable(iwdg->clock); ++ ++ mmio_setbits_32(iwdg_base + IWDG_EWCR_OFFSET, IWDG_EWCR_EWIC); ++ ++ stm32_clock_disable(iwdg->clock); ++ ++ stm32_cores_reset(); ++ ++ return ITRR_HANDLED; ++} ++KEEP_PAGER(stm32_iwdg_it_handler); ++ ++static int stm32_iwdg_get_secure_timeout(void *fdt, int node) ++{ ++ const fdt32_t *cuint; ++ ++ cuint = fdt_getprop(fdt, node, "secure-timeout-sec", NULL); ++ if (cuint == NULL) { ++ return -1; ++ } ++ ++ return (int)fdt32_to_cpu(*cuint); ++} ++ ++static int stm32_iwdg_conf_etimeout(void *fdt, int node, ++ struct stm32_iwdg_instance *iwdg) ++{ ++ int id_lsi; ++ int dt_secure_timeout = stm32_iwdg_get_secure_timeout(fdt, node); ++ uint32_t reload, status; ++ uint64_t timeout_ref; ++ unsigned long long reload_ll; ++ uintptr_t iwdg_base = get_base(iwdg); ++ struct itr_handler *itr; ++ ++ if (dt_secure_timeout < 0) { ++ return 0; ++ } ++ ++ if (dt_secure_timeout == 0) { ++ return -1; ++ } ++ ++ id_lsi = fdt_get_clock_id_by_name(fdt, node, "lsi"); ++ if (id_lsi < 0) { ++ return -1; ++ } ++ ++ /* Prescaler fix to 256 */ ++ reload_ll = (unsigned long long)dt_secure_timeout * ++ stm32mp1_clk_get_rate(id_lsi); ++ reload = ((uint32_t)(reload_ll >> 8) - 1U) & IWDG_EWCR_EWIT_MASK; ++ ++ stm32_clock_enable(iwdg->clock); ++ ++ write32(IWDG_KR_START_KEY, iwdg_base + IWDG_KR_OFFSET); ++ write32(IWDG_KR_ACCESS_KEY, iwdg_base + IWDG_KR_OFFSET); ++ write32(IWDG_PR_DIV_256, iwdg_base + IWDG_PR_OFFSET); ++ write32(IWDG_EWCR_EWIE | reload, iwdg_base + IWDG_EWCR_OFFSET); ++ ++ timeout_ref = utimeout_init(IWDG_TIMEOUT_US); ++ do { ++ status = read32(iwdg_base + IWDG_SR_OFFSET) & IWDG_SR_EWU; ++ if (utimeout_elapsed(IWDG_TIMEOUT_US, timeout_ref)) { ++ stm32_clock_disable(iwdg->clock); ++ return -1; ++ } ++ } while (status != 0U); ++ ++ stm32_clock_disable(iwdg->clock); ++ ++ itr = calloc(1, sizeof(struct itr_handler)); ++ if (itr == NULL) { ++ panic("out of memory"); ++ } ++ ++ itr->it = stm32mp_iwdg_instance2irq(iwdg->instance); ++ itr->handler = stm32_iwdg_it_handler; ++ itr_add(itr); ++ itr_enable(itr->it); ++ ++ return 0; ++} ++ ++void stm32_iwdg_refresh(uint32_t instance) ++{ ++ struct stm32_iwdg_instance *iwdg = get_iwdg(instance); ++ uintptr_t iwdg_base = get_base(iwdg); ++ ++ assert(iwdg); ++ ++ stm32_clock_enable(iwdg->clock); ++ ++ write32(IWDG_KR_RELOAD_KEY, iwdg_base + IWDG_KR_OFFSET); ++ ++ stm32_clock_disable(iwdg->clock); ++} ++ ++static TEE_Result iwdg_init(void) ++{ ++ int node = -1; ++ int res; ++ struct dt_node_info dt_info; ++ void *fdt; ++ size_t count; ++ ++ fdt = get_dt_blob(); ++ if (!fdt) { ++ panic(); ++ } ++ ++ assert((stm32_iwdg == NULL) && (stm32_iwdg_count == 0)); ++ count = 0; ++ ++ for (node = stm32_iwdg_get_dt_node(fdt, &dt_info, node); ++ node != -FDT_ERR_NOTFOUND; ++ node = stm32_iwdg_get_dt_node(fdt, &dt_info, node)) { ++ struct stm32_iwdg_instance iwdg; ++ enum teecore_memtypes memtype; ++ uint32_t hw_init; ++ ++ memset(&iwdg, 0, sizeof(iwdg)); ++ iwdg.pbase = dt_info.base; ++ iwdg.clock = (unsigned long)dt_info.clock; ++ iwdg.instance = (uint8_t)stm32mp_iwdg_iomem2instance(iwdg.pbase); ++ ++ memtype = ((dt_info.status & DT_STATUS_OK_NSEC) != 0) ? ++ MEM_AREA_IO_NSEC : MEM_AREA_IO_SEC; ++ 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) != ++ NULL) { ++ iwdg.flags |= IWDG_ENABLE_ON_STOP; ++ } ++ ++ if (fdt_getprop(fdt, node, "stm32,enable-on-standby", NULL) != ++ NULL) { ++ iwdg.flags |= IWDG_ENABLE_ON_STANDBY; ++ } ++ ++ hw_init = stm32_get_iwdg_otp_config(iwdg.pbase); ++ ++ if ((hw_init & IWDG_HW_ENABLED) != 0) { ++ if (dt_info.status == DT_STATUS_DISABLED) { ++ panic("IWDG HW enabled"); ++ } ++ iwdg.flags |= IWDG_HW_ENABLED; ++ } ++ ++ if ((hw_init & IWDG_ENABLE_ON_STOP) != 0) { ++ iwdg.flags |= IWDG_ENABLE_ON_STOP; ++ } ++ ++ if ((hw_init & IWDG_ENABLE_ON_STANDBY) != 0) { ++ iwdg.flags |= IWDG_ENABLE_ON_STANDBY; ++ } ++ ++ if (dt_info.status == DT_STATUS_DISABLED) { ++ continue; ++ } ++ ++ DMSG("IWDG%u found, %ssecure", iwdg.instance + 1, ++ ((dt_info.status & DT_STATUS_OK_NSEC) != 0) ? "non " : ""); ++ ++ if ((dt_info.status & DT_STATUS_OK_NSEC) != 0) { ++ stm32mp_register_non_secure_periph_iomem(iwdg.pbase); ++ } else { ++ stm32mp_register_secure_periph_iomem(iwdg.pbase); ++ } ++ ++ stm32_clock_enable(iwdg.clock); ++ stm32_clock_disable(iwdg.clock); ++ ++ res = stm32_iwdg_conf_etimeout(fdt, node, &iwdg); ++ if (res != 0) { ++ EMSG("IWDG%x early timeout config failed (%d)\n", ++ iwdg.instance + 1, res); ++ panic(); ++ } ++ ++ stm32_iwdg = realloc(stm32_iwdg, (count + 1) * sizeof(iwdg)); ++ if (stm32_iwdg == NULL) { ++ panic("out of memory"); ++ } ++ ++ memcpy(&stm32_iwdg[count], &iwdg, sizeof(iwdg)); ++ count++; ++ } ++ ++ stm32_iwdg_count = count; ++ ++ DMSG("%u IWDG instance%s found", count, count > 1 ? "s" : ""); ++ ++ return TEE_SUCCESS; ++} ++driver_init(iwdg_init); +diff --git a/core/drivers/stm32_rng.c b/core/drivers/stm32_rng.c +new file mode 100644 +index 0000000..75bbef7 +--- /dev/null ++++ b/core/drivers/stm32_rng.c +@@ -0,0 +1,200 @@ ++// SPDX-License-Identifier: BSD-3-Clause ++/* ++ * Copyright (c) 2018, STMicroelectronics - All Rights Reserved ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define DT_RNG_COMPAT "st,stm32-rng" ++#define RNG_CR 0x00U ++#define RNG_SR 0x04U ++#define RNG_DR 0x08U ++ ++#define RNG_CR_RNGEN BIT(2) ++#define RNG_CR_IE BIT(3) ++#define RNG_CR_CED BIT(5) ++ ++#define RNG_SR_DRDY BIT(0) ++#define RNG_SR_CECS BIT(1) ++#define RNG_SR_SECS BIT(2) ++#define RNG_SR_CEIS BIT(5) ++#define RNG_SR_SEIS BIT(6) ++ ++#define RNG_TIMEOUT_US 100000 ++ ++struct stm32_rng_instance { ++ uintptr_t pbase; ++ uintptr_t vbase; ++ unsigned long clock; ++}; ++ ++static struct stm32_rng_instance *stm32_rng; ++ ++static uintptr_t get_base(void) ++{ ++ if (!cpu_mmu_enabled()) { ++ return stm32_rng->pbase; ++ } ++ ++ return stm32_rng->vbase; ++} ++ ++int stm32_rng_read(uint8_t *out, size_t size) ++{ ++ uint8_t *buf = out; ++ size_t len = size; ++ uint64_t timeout_ref; ++ uint32_t data32; ++ uintptr_t rng_base = get_base(); ++ int rc = 0; ++ int count; ++ ++ if (stm32_rng == 0) { ++ return -1; ++ } ++ ++ stm32_clock_enable(stm32_rng->clock); ++ ++ if ((read32(rng_base + RNG_CR) & RNG_CR_RNGEN) == 0U) { ++ write32(RNG_CR_RNGEN | RNG_CR_CED, rng_base + RNG_CR); ++ } ++ ++ while (len != 0) { ++ timeout_ref = utimeout_init(RNG_TIMEOUT_US); ++ do { ++ uint32_t status = read32(rng_base + RNG_SR); ++ ++ if ((status & (RNG_SR_SECS | RNG_SR_SEIS)) != 0U) { ++ size_t i; ++ ++ /* Recommended by the SoC reference manual */ ++ io_mask32(rng_base + RNG_SR, 0, RNG_SR_SEIS); ++ dmb(); ++ for (i = 12; i != 0; i--) { ++ (void)read32(rng_base + RNG_DR); ++ } ++ dmb(); ++ ++ if ((read32(rng_base + RNG_SR) & RNG_SR_SEIS) != ++ 0U) { ++ panic("RNG noise"); ++ } ++ } ++ ++ if (utimeout_elapsed(RNG_TIMEOUT_US, timeout_ref)) { ++ rc = -1; ++ goto bail; ++ } ++ } while ((read32(rng_base + RNG_SR) & RNG_SR_DRDY) == 0U); ++ ++ count = 4; ++ while (len != 0) { ++ data32 = read32(rng_base + RNG_DR); ++ count--; ++ ++ memcpy(buf, &data32, MIN(len, sizeof(uint32_t))); ++ buf += MIN(len, sizeof(uint32_t)); ++ len -= MIN(len, sizeof(uint32_t)); ++ ++ if (count == 0) { ++ break; ++ } ++ } ++ } ++ ++bail: ++ stm32_clock_disable(stm32_rng->clock); ++ ++ if (rc != 0) { ++ memset(out, 0, buf - out); ++ } ++ ++ return rc; ++} ++ ++static TEE_Result stm32_rng_init(void) ++{ ++ void *fdt; ++ struct dt_node_info dt_rng; ++ int node; ++ uint8_t __maybe_unused test[43]; ++ enum teecore_memtypes memtype; ++ ++ fdt = get_dt_blob(); ++ if (!fdt) { ++ panic(); ++ } ++ ++ node = fdt_get_node(fdt, &dt_rng, -1, DT_RNG_COMPAT); ++ if (node < 0) { ++ return TEE_SUCCESS; ++ } ++ ++ if ((dt_rng.status & DT_STATUS_OK_SEC) == 0) { ++ return TEE_SUCCESS; ++ } ++ ++ assert(dt_rng.base == RNG1_BASE); ++ ++ if (stm32_rng) { ++ panic(); ++ } ++ stm32_rng = calloc(1, sizeof(*stm32_rng)); ++ if (!stm32_rng) { ++ panic(); ++ } ++ ++ stm32_rng->pbase = dt_rng.base; ++ ++ if ((dt_rng.status & DT_STATUS_OK_NSEC) != 0) { ++ memtype = MEM_AREA_IO_NSEC; ++ stm32mp_register_non_secure_periph_iomem(stm32_rng->pbase); ++ } else { ++ memtype = MEM_AREA_IO_SEC; ++ stm32mp_register_secure_periph_iomem(stm32_rng->pbase); ++ } ++ ++ stm32_rng->vbase = (uintptr_t)phys_to_virt(stm32_rng->pbase, memtype); ++ ++ if (dt_rng.clock < 0) { ++ panic(); ++ } ++ stm32_rng->clock = (unsigned long)dt_rng.clock; ++ ++ stm32_clock_enable(stm32_rng->clock); ++ stm32_clock_disable(stm32_rng->clock); ++ ++ if (dt_rng.reset >= 0) { ++ stm32_reset_assert((unsigned long)dt_rng.reset); ++ udelay(20); ++ stm32_reset_deassert((unsigned long)dt_rng.reset); ++ } ++ ++ DMSG("Init RNG done"); ++ ++#if TRACE_LEVEL >= TRACE_DEBUG ++ memset(test, 0xa5, sizeof(test)); ++ if (stm32_rng_read(test, sizeof(test))) { ++ panic("RNG test"); ++ } ++ ++ DHEXDUMP(test, sizeof(test)); ++#endif ++ ++ return TEE_SUCCESS; ++} ++driver_init(stm32_rng_init); +diff --git a/core/drivers/stm32_rtc.c b/core/drivers/stm32_rtc.c +new file mode 100644 +index 0000000..709fafa +--- /dev/null ++++ b/core/drivers/stm32_rtc.c +@@ -0,0 +1,503 @@ ++/* ++ * Copyright (c) 2018, STMicroelectronics - All Rights Reserved ++ * ++ * SPDX-License-Identifier: BSD-3-Clause ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define RTC_COMPAT "st,stm32mp1-rtc" ++ ++#define RTC_TR_SU_MASK 0x0000000FU ++#define RTC_TR_ST_MASK 0x00000070U ++#define RTC_TR_ST_SHIFT 4 ++#define RTC_TR_MNU_MASK 0x00000F00U ++#define RTC_TR_MNU_SHIFT 8 ++#define RTC_TR_MNT_MASK 0x00007000U ++#define RTC_TR_MNT_SHIFT 12 ++#define RTC_TR_HU_MASK 0x000F0000U ++#define RTC_TR_HU_SHIFT 16 ++#define RTC_TR_HT_MASK 0x00300000U ++#define RTC_TR_HT_SHIFT 20 ++#define RTC_TR_PM BIT(22) ++ ++#define RTC_DR_DU_MASK 0x0000000FU ++#define RTC_DR_DT_MASK 0x00000030U ++#define RTC_DR_DT_SHIFT 4 ++#define RTC_DR_MU_MASK 0x00000F00U ++#define RTC_DR_MU_SHIFT 8 ++#define RTC_DR_MT BIT(12) ++#define RTC_DR_MT_SHIFT 12 ++#define RTC_DR_WDU_MASK 0x0000E000U ++#define RTC_DR_WDU_SHIFT 13 ++#define RTC_DR_YU_MASK 0x000F0000U ++#define RTC_DR_YU_SHIFT 16 ++#define RTC_DR_YT_MASK 0x00F00000U ++#define RTC_DR_YT_SHIFT 20 ++ ++#define RTC_SSR_SS_MASK 0x0000FFFFU ++ ++#define RTC_ICSR_RSF BIT(5) ++ ++#define RTC_PRER_PREDIV_S_MASK 0x0000FFFFU ++ ++#define RTC_CR_BYPSHAD BIT(5) ++#define RTC_CR_BYPSHAD_SHIFT 5 ++#define RTC_CR_TAMPTS BIT(25) ++ ++#define RTC_SMCR_TS_DPROT BIT(3) ++#define RTC_SR_TSF BIT(3) ++#define RTC_SCR_CTSF BIT(3) ++#define RTC_SR_TSOVF BIT(4) ++#define RTC_SCR_CTSOVF BIT(4) ++ ++#define RTC_TSDR_MU_MASK 0x00000F00U ++#define RTC_TSDR_MU_SHIFT 8 ++#define RTC_TSDR_DT_MASK 0x00000030U ++#define RTC_TSDR_DT_SHIFT 4 ++#define RTC_TSDR_DU_MASK 0x0000000FU ++#define RTC_TSDR_DU_SHIFT 0 ++ ++#define RTC_WPR_KEY1 0xCA ++#define RTC_WPR_KEY2 0x53 ++#define RTC_WPR_KEY_LOCK 0xFF ++ ++#define RTC_FLAGS_READ_TWICE BIT(0) ++#define RTC_FLAGS_SECURE BIT(1) ++ ++struct rtc_device { ++ uintptr_t pbase; ++ uintptr_t vbase; ++ uint16_t clock; ++ uint8_t flags; ++}; ++ ++struct rtc_device rtc_dev; ++ ++static uintptr_t get_base(void) ++{ ++ if (!cpu_mmu_enabled()) ++ return rtc_dev.pbase; ++ ++ return rtc_dev.vbase; ++} ++ ++static void stm32_rtc_write_unprotect(void) ++{ ++ uintptr_t rtc_base = get_base(); ++ ++ mmio_write_32(rtc_base + RTC_WPR, RTC_WPR_KEY1); ++ mmio_write_32(rtc_base + RTC_WPR, RTC_WPR_KEY2); ++} ++ ++static void stm32_rtc_write_protect(void) ++{ ++ uintptr_t rtc_base = get_base(); ++ ++ mmio_write_32(rtc_base + RTC_WPR, RTC_WPR_KEY_LOCK); ++} ++ ++/******************************************************************************* ++ * This function gets the BYPSHAD bit value of the RTC_CR register. ++ * It will determine if we need to reset RTC_ISCR.RSF after each RTC calendar ++ * read, and also wait for RTC_ISCR.RSF=1 before next read. ++ * Returns true or false depending on the bit value. ++ ******************************************************************************/ ++static bool stm32_rtc_get_bypshad(void) ++{ ++ return ((mmio_read_32(get_base() + RTC_CR) & RTC_CR_BYPSHAD) >> ++ RTC_CR_BYPSHAD_SHIFT) != 0U; ++} ++ ++/******************************************************************************* ++ * This function reads the RTC calendar register values. ++ * If shadow registers are not bypassed, then a reset/poll is done. ++ ******************************************************************************/ ++static void stm32_rtc_read_calendar(struct stm32_rtc_calendar *calendar) ++{ ++ uintptr_t rtc_base = get_base(); ++ bool bypshad = stm32_rtc_get_bypshad(); ++ ++ if (!bypshad) { ++ mmio_clrbits_32((uint32_t)(rtc_base + RTC_ICSR), RTC_ICSR_RSF); ++ while ((mmio_read_32(rtc_base + RTC_ICSR) & RTC_ICSR_RSF) != ++ RTC_ICSR_RSF) { ++ ; ++ } ++ } ++ ++ calendar->ssr = mmio_read_32(rtc_base + RTC_SSR); ++ calendar->tr = mmio_read_32(rtc_base + RTC_TR); ++ calendar->dr = mmio_read_32(rtc_base + RTC_DR); ++} ++ ++/******************************************************************************* ++ * This function fill the rtc_time structure based on rtc_calendar register. ++ ******************************************************************************/ ++static void stm32_rtc_get_time(struct stm32_rtc_calendar *cal, ++ struct stm32_rtc_time *tm) ++{ ++ tm->hour = (((cal->tr & RTC_TR_HT_MASK) >> RTC_TR_HT_SHIFT) * 10U) + ++ ((cal->tr & RTC_TR_HU_MASK) >> RTC_TR_HU_SHIFT); ++ ++ if ((cal->tr & RTC_TR_PM) != 0U) { ++ tm->hour += 12U; ++ } ++ ++ tm->min = (((cal->tr & RTC_TR_MNT_MASK) >> RTC_TR_MNT_SHIFT) * 10U) + ++ ((cal->tr & RTC_TR_MNU_MASK) >> RTC_TR_MNU_SHIFT); ++ tm->sec = (((cal->tr & RTC_TR_ST_MASK) >> RTC_TR_ST_SHIFT) * 10U) + ++ (cal->tr & RTC_TR_SU_MASK); ++} ++ ++/******************************************************************************* ++ * This function fill the rtc_time structure with the given date register. ++ ******************************************************************************/ ++static void stm32_rtc_get_date(struct stm32_rtc_calendar *cal, ++ struct stm32_rtc_time *tm) ++{ ++ tm->wday = (((cal->dr & RTC_DR_WDU_MASK) >> RTC_DR_WDU_SHIFT)); ++ ++ tm->day = (((cal->dr & RTC_DR_DT_MASK) >> RTC_DR_DT_SHIFT) * 10U) + ++ (cal->dr & RTC_DR_DU_MASK); ++ ++ tm->month = (((cal->dr & RTC_DR_MT) >> RTC_DR_MT_SHIFT) * 10U) + ++ ((cal->dr & RTC_DR_MU_MASK) >> RTC_DR_MU_SHIFT); ++ ++ tm->year = (((cal->dr & RTC_DR_YT_MASK) >> RTC_DR_YT_SHIFT) * 10U) + ++ ((cal->dr & RTC_DR_YU_MASK) >> RTC_DR_YU_SHIFT) + 2000U; ++} ++ ++/******************************************************************************* ++ * This function reads the RTC timestamp register values and update time ++ * structure with the corresponding value. ++ ******************************************************************************/ ++static void stm32_rtc_read_timestamp(struct stm32_rtc_time *time) ++{ ++ struct stm32_rtc_calendar cal_tamp; ++ uintptr_t rtc_base = get_base(); ++ ++ cal_tamp.tr = mmio_read_32(rtc_base + RTC_TSTR); ++ cal_tamp.dr = mmio_read_32(rtc_base + RTC_TSDR); ++ stm32_rtc_get_time(&cal_tamp, time); ++ stm32_rtc_get_date(&cal_tamp, time); ++} ++ ++/******************************************************************************* ++ * This function gets the RTC calendar register values. ++ * It takes into account the need of reading twice or not, depending on ++ * frequencies previously setted, and the bypass or not of the shadow ++ * registers. This service is exposed externally. ++ ******************************************************************************/ ++void stm32_rtc_get_calendar(struct stm32_rtc_calendar *calendar) ++{ ++ stm32_clock_enable(rtc_dev.clock); ++ ++ stm32_rtc_read_calendar(calendar); ++ ++ if (rtc_dev.flags & RTC_FLAGS_READ_TWICE) { ++ uint32_t tr_save = calendar->tr; ++ ++ stm32_rtc_read_calendar(calendar); ++ ++ if (calendar->tr != tr_save) { ++ stm32_rtc_read_calendar(calendar); ++ } ++ } ++ ++ stm32_clock_disable(rtc_dev.clock); ++} ++ ++/******************************************************************************* ++ * This function computes the second fraction in milliseconds. ++ * The returned value is a uint32_t between 0 and 1000. ++ ******************************************************************************/ ++static uint32_t stm32_rtc_get_second_fraction(struct stm32_rtc_calendar *cal) ++{ ++ uint32_t prediv_s = mmio_read_32(get_base() + RTC_PRER) & ++ RTC_PRER_PREDIV_S_MASK; ++ uint32_t ss = cal->ssr & RTC_SSR_SS_MASK; ++ ++ return ((prediv_s - ss) * 1000U) / (prediv_s + 1U); ++} ++ ++/******************************************************************************* ++ * 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) ++{ ++ 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; ++ } ++} ++ ++/******************************************************************************* ++ * This function computes the time difference between two timestamps. ++ * 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) ++{ ++ signed long long diff_in_s; ++ signed long long curr_s; ++ signed long long ref_s; ++ ++ curr_s = (signed long long)current->sec + ++ (((signed long long)current->min + ++ (((signed long long)current->hour * 60))) * 60); ++ ++ ref_s = (signed long long)ref->sec + ++ (((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; ++} ++ ++/******************************************************************************* ++ * This function determines if the year is leap or not. ++ * Returned value is true or false. ++ ******************************************************************************/ ++static bool stm32_is_a_leap_year(uint32_t year) ++{ ++ return ((year % 4U) == 0U) && ++ (((year % 100U) != 0U) || ((year % 400U) == 0U)); ++} ++ ++/******************************************************************************* ++ * This function computes the date difference between two timestamps. ++ * 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) ++{ ++ uint32_t diff_in_days = 0; ++ uint32_t m; ++ static const uint8_t month_len[NB_MONTHS] = { ++ 31, 28, 31, 30, 31, 30, ++ 31, 31, 30, 31, 30, 31 ++ }; ++ ++ /* Get the number of non-entire month days */ ++ if (current->day >= ref->day) { ++ diff_in_days += current->day - ref->day; ++ } else { ++ diff_in_days += (uint32_t)month_len[ref->month - 1U] - ++ ref->day + current->day; ++ } ++ ++ /* Get the number of entire months, and compute the related days */ ++ if (current->month > (ref->month + 1U)) { ++ for (m = (ref->month + 1U); (m < current->month) && ++ (m < 12U); m++) { ++ diff_in_days += (uint32_t)month_len[m - 1U]; ++ } ++ } ++ ++ if (current->month < (ref->month - 1U)) { ++ for (m = 1U; (m < current->month) && (m < 12U); m++) { ++ diff_in_days += (uint32_t)month_len[m - 1U]; ++ } ++ ++ for (m = (ref->month + 1U); m < 12U; m++) { ++ diff_in_days += (uint32_t)month_len[m - 1U]; ++ } ++ } ++ ++ /* Get complete years */ ++ if (current->year > (ref->year + 1U)) { ++ diff_in_days += (current->year - ref->year - 1U) * 365U; ++ } ++ ++ /* Particular cases: leap years (one day more) */ ++ if (diff_in_days > 0U) { ++ if (current->year == ref->year) { ++ if (stm32_is_a_leap_year(current->year)) { ++ if ((ref->month <= 2U) && ++ (current->month >= 3U) && ++ (current->day <= 28U)) { ++ diff_in_days++; ++ } ++ } ++ } else { ++ uint32_t y; ++ ++ /* Ref year is leap */ ++ if ((stm32_is_a_leap_year(ref->year)) && ++ (ref->month <= 2U) && (ref->day <= 28U)) { ++ diff_in_days++; ++ } ++ ++ /* Current year is leap */ ++ if ((stm32_is_a_leap_year(current->year)) && ++ (current->month >= 3U)) { ++ diff_in_days++; ++ } ++ ++ /* Interleaved years are leap */ ++ for (y = ref->year + 1U; y < current->year; y++) { ++ if (stm32_is_a_leap_year(y)) { ++ diff_in_days++; ++ } ++ } ++ } ++ } ++ ++ return (24ULL * 60U * 60U * 1000U) * (unsigned long long)diff_in_days; ++} ++ ++/******************************************************************************* ++ * This function computes the date difference between two rtc value. ++ * Here again the returned value is in milliseconds. ++ ******************************************************************************/ ++unsigned long long stm32_rtc_diff_calendar(struct stm32_rtc_calendar *cur, ++ struct stm32_rtc_calendar *ref) ++{ ++ unsigned long long diff_in_ms = 0; ++ struct stm32_rtc_time curr_t; ++ struct stm32_rtc_time ref_t; ++ ++ stm32_clock_enable(rtc_dev.clock); ++ ++ stm32_rtc_get_date(cur, &curr_t); ++ stm32_rtc_get_date(ref, &ref_t); ++ stm32_rtc_get_time(cur, &curr_t); ++ stm32_rtc_get_time(ref, &ref_t); ++ ++ diff_in_ms += stm32_rtc_diff_frac(cur, ref); ++ diff_in_ms += stm32_rtc_diff_time(&curr_t, &ref_t); ++ diff_in_ms += stm32_rtc_diff_date(&curr_t, &ref_t); ++ ++ stm32_clock_disable(rtc_dev.clock); ++ ++ return diff_in_ms; ++} ++ ++/******************************************************************************* ++ * This function fill the RTC timestamp structure. ++ ******************************************************************************/ ++void stm32_rtc_get_timestamp(struct stm32_rtc_time *tamp_ts) ++{ ++ uintptr_t rtc_base = get_base(); ++ ++ stm32_clock_enable(rtc_dev.clock); ++ ++ if ((mmio_read_32(rtc_base + RTC_SR) & RTC_SR_TSF) != 0U) { ++ /* Print timestamp for tamper event */ ++ stm32_rtc_read_timestamp(tamp_ts); ++ mmio_setbits_32(rtc_base + RTC_SCR, RTC_SCR_CTSF); ++ if ((mmio_read_32(rtc_base + RTC_SR) & RTC_SR_TSOVF) != ++ 0U) { ++ /* Overflow detected */ ++ mmio_setbits_32(rtc_base + RTC_SCR, RTC_SCR_CTSOVF); ++ } ++ } ++ ++ stm32_clock_disable(rtc_dev.clock); ++} ++ ++/******************************************************************************* ++ * This function enable the timestamp bit for tamper and secure timestamp ++ * access. ++ ******************************************************************************/ ++void stm32_rtc_set_tamper_timestamp(void) ++{ ++ uintptr_t rtc_base = get_base(); ++ ++ stm32_clock_enable(rtc_dev.clock); ++ ++ stm32_rtc_write_unprotect(); ++ ++ /* Enable tamper timestamper */ ++ mmio_setbits_32(rtc_base + RTC_CR, RTC_CR_TAMPTS); ++ ++ /* Secure Timestamp bit */ ++ mmio_clrbits_32(rtc_base + RTC_SMCR, RTC_SMCR_TS_DPROT); ++ ++ stm32_rtc_write_protect(); ++ ++ stm32_clock_disable(rtc_dev.clock); ++} ++ ++/******************************************************************************* ++ * This function return state of tamper timestamp. ++ ******************************************************************************/ ++bool stm32_rtc_is_timestamp_enable(void) ++{ ++ bool ret; ++ ++ stm32_clock_enable(rtc_dev.clock); ++ ++ ret = (mmio_read_32(get_base() + RTC_CR) & RTC_CR_TAMPTS) != 0U; ++ ++ stm32_clock_disable(rtc_dev.clock); ++ ++ return ret; ++} ++ ++#ifdef CFG_DT ++/******************************************************************************* ++ * RTC initialisation function. ++ ******************************************************************************/ ++static TEE_Result stm32_rtc_init(void) ++{ ++ int node; ++ struct dt_node_info dt_info; ++ void *fdt = get_dt_blob(); ++ ++ if (!fdt) { ++ panic(); ++ } ++ ++ node = fdt_get_node(fdt, &dt_info, -1, RTC_COMPAT); ++ if (node < 0) { ++ return node; ++ } ++ ++ rtc_dev.pbase = dt_info.base; ++ ++ if (dt_info.status == DT_STATUS_OK_SEC) { ++ rtc_dev.flags |= RTC_FLAGS_SECURE; ++ stm32mp_register_secure_periph_iomem(rtc_dev.pbase); ++ rtc_dev.vbase = (uintptr_t)phys_to_virt(rtc_dev.pbase, ++ MEM_AREA_IO_SEC); ++ } else { ++ stm32mp_register_non_secure_periph_iomem(rtc_dev.pbase); ++ rtc_dev.vbase = (uintptr_t)phys_to_virt(rtc_dev.pbase, ++ MEM_AREA_IO_NSEC); ++ } ++ ++ rtc_dev.clock = (unsigned long)dt_info.clock; ++ ++ if (stm32_rtc_get_read_twice()) { ++ rtc_dev.flags |= RTC_FLAGS_READ_TWICE; ++ } ++ ++ return 0; ++} ++driver_init(stm32_rtc_init); ++#endif +diff --git a/core/drivers/stm32_timer.c b/core/drivers/stm32_timer.c +new file mode 100644 +index 0000000..be03577 +--- /dev/null ++++ b/core/drivers/stm32_timer.c +@@ -0,0 +1,272 @@ ++// SPDX-License-Identifier: BSD-3-Clause ++/* ++ * Copyright (c) 2018, STMicroelectronics ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define TIM_CR1 0x00U /* Control Register 1 */ ++#define TIM_CR2 0x04U /* Control Register 2 */ ++#define TIM_SMCR 0x08U /* Slave mode control reg */ ++#define TIM_DIER 0x0CU /* DMA/interrupt register */ ++#define TIM_SR 0x10U /* Status register */ ++#define TIM_EGR 0x14U /* Event Generation Reg */ ++#define TIM_CCMR1 0x18U /* Capt/Comp 1 Mode Reg */ ++#define TIM_CCMR2 0x1CU /* Capt/Comp 2 Mode Reg */ ++#define TIM_CCER 0x20U /* Capt/Comp Enable Reg */ ++#define TIM_CNT 0x24U /* Counter */ ++#define TIM_PSC 0x28U /* Prescaler */ ++#define TIM_ARR 0x2CU /* Auto-Reload Register */ ++#define TIM_CCR1 0x34U /* Capt/Comp Register 1 */ ++#define TIM_CCR2 0x38U /* Capt/Comp Register 2 */ ++#define TIM_CCR3 0x3CU /* Capt/Comp Register 3 */ ++#define TIM_CCR4 0x40U /* Capt/Comp Register 4 */ ++#define TIM_BDTR 0x44U /* Break and Dead-Time Reg */ ++#define TIM_DCR 0x48U /* DMA control register */ ++#define TIM_DMAR 0x4CU /* DMA transfer register */ ++#define TIM_AF1 0x60U /* Alt Function Reg 1 */ ++#define TIM_AF2 0x64U /* Alt Function Reg 2 */ ++#define TIM_TISEL 0x68U /* Input Selection */ ++ ++#define TIM_CR1_CEN BIT(0) ++#define TIM_SMCR_SMS GENMASK_32(2, 0) /* Slave mode selection */ ++#define TIM_SMCR_TS GENMASK_32(6, 4) /* Trigger selection */ ++#define TIM_CCMR_CC1S_TI1 BIT(0) /* IC1/IC3 selects TI1/TI3 */ ++#define TIM_CCMR_CC1S_TI2 BIT(1) /* IC1/IC3 selects TI2/TI4 */ ++#define TIM_CCMR_CC2S_TI2 BIT(8) /* IC2/IC4 selects TI2/TI4 */ ++#define TIM_CCMR_CC2S_TI1 BIT(9) /* IC2/IC4 selects TI1/TI3 */ ++#define TIM_CCER_CC1E BIT(0) /* Capt/Comp 1 out Ena */ ++#define TIM_CCER_CC1P BIT(1) /* Capt/Comp 1 Polarity */ ++#define TIM_CCER_CC1NP BIT(3) /* Capt/Comp 1N Polarity */ ++#define TIM_SR_UIF BIT(0) /* UIF interrupt flag */ ++#define TIM_SR_CC1IF BIT(1) /* CC1 interrupt flag */ ++#define TIM_TISEL_TI1SEL_MASK GENMASK_32(3, 0) ++#define TIM_SMCR_SMS_RESET 0x4U ++#define TIM_SMCR_TS_SHIFT 4U ++#define TIM_SMCR_TS_TI1FP1 0x5U ++ ++#define TIM_COMPAT "st,stm32-timers" ++#define TIM_TIMEOUT_US 100000 ++#define TIM_TIMEOUT_STEP_US 10 ++#define TIM_PRESCAL_HSI 10U ++#define TIM_PRESCAL_CSI 7U ++ ++struct stm32_timer_instance { ++ struct io_pa_va base; ++ unsigned long clk; ++ unsigned long freq; ++ uint8_t cal_input; ++}; ++ ++static uintptr_t timer_base(struct stm32_timer_instance *timer) ++{ ++ return (uintptr_t)io_pa_or_va(&timer->base); ++} ++ ++/* Currently support HSI and CSI calibratrion */ ++#define TIM_MAX_INSTANCE 2 ++ ++static struct stm32_timer_instance stm32_timer[TIM_MAX_INSTANCE]; ++ ++static int timer_get_dt_node(void *fdt, struct dt_node_info *info, int offset) ++{ ++ int node; ++ ++ node = fdt_get_node(fdt, info, offset, TIM_COMPAT); ++ if (node < 0) { ++ return -FDT_ERR_NOTFOUND; ++ } ++ ++ return node; ++} ++ ++static void timer_config(struct stm32_timer_instance *timer) ++{ ++ uintptr_t base = timer_base(timer); ++ ++ stm32_clock_enable(timer->clk); ++ ++ timer->freq = stm32_clock_get_rate(timer->clk); ++ ++ if ((mmio_read_32(base + TIM_TISEL) & TIM_TISEL_TI1SEL_MASK) != ++ timer->cal_input) { ++ mmio_clrsetbits_32(base + TIM_CCMR1, ++ TIM_CCMR_CC1S_TI1 | TIM_CCMR_CC1S_TI2, ++ TIM_CCMR_CC1S_TI1); ++ ++ mmio_clrbits_32(base + TIM_CCER, ++ TIM_CCER_CC1P | TIM_CCER_CC1NP); ++ ++ mmio_clrsetbits_32(base + TIM_SMCR, ++ TIM_SMCR_TS | TIM_SMCR_SMS, ++ (TIM_SMCR_TS_TI1FP1 << TIM_SMCR_TS_SHIFT) | ++ TIM_SMCR_SMS_RESET); ++ ++ mmio_write_32(base + TIM_TISEL, timer->cal_input); ++ mmio_setbits_32(base + TIM_CR1, TIM_CR1_CEN); ++ mmio_setbits_32(base + TIM_CCER, TIM_CCER_CC1E); ++ } ++ ++ stm32_clock_disable(timer->clk); ++} ++ ++static uint32_t timer_start_capture(struct stm32_timer_instance *timer) ++{ ++ uint64_t timeout_ref; ++ uint32_t counter = 0U; ++ uint32_t old_counter = 0U; ++ int twice; ++ uintptr_t base = timer_base(timer); ++ ++ timer_config(timer); ++ ++ stm32_clock_enable(timer->clk); ++ ++ mmio_write_32(base + TIM_SR, 0U); ++ ++ timeout_ref = utimeout_init(TIM_TIMEOUT_US); ++ ++ while ((mmio_read_32(base + TIM_SR) & TIM_SR_UIF) == 0U) { ++ if (utimeout_elapsed(TIM_TIMEOUT_US, timeout_ref)) { ++ goto bail; ++ } ++ } ++ ++ mmio_write_32(base + TIM_SR, 0U); ++ ++ for (twice = 0; (twice < 2) || (counter != old_counter); twice++) { ++ timeout_ref = utimeout_init(TIM_TIMEOUT_US); ++ ++ while ((mmio_read_32(base + TIM_SR) & TIM_SR_CC1IF) == 0U) { ++ if (utimeout_elapsed(TIM_TIMEOUT_US, timeout_ref)) { ++ counter = 0U; ++ goto bail; ++ } ++ } ++ ++ old_counter = counter; ++ counter = mmio_read_32(base + TIM_CCR1); ++ } ++ ++bail: ++ stm32_clock_disable(timer->clk); ++ ++ return counter; ++} ++ ++unsigned long stm32_timer_hsi_freq(void) ++{ ++ struct stm32_timer_instance *timer = &stm32_timer[HSI_CAL]; ++ uint32_t counter = 0; ++ ++ if (timer->base.pa != 0) { ++ counter = timer_start_capture(timer); ++ } ++ ++ return (counter == 0) ? 0 : (timer->freq / counter) << TIM_PRESCAL_HSI; ++} ++KEEP_PAGER(stm32_timer_hsi_freq); ++ ++unsigned long stm32_timer_csi_freq(void) ++{ ++ struct stm32_timer_instance *timer = &stm32_timer[CSI_CAL]; ++ uint32_t counter = 0; ++ ++ if (timer->base.pa != 0) { ++ counter = timer_start_capture(timer); ++ } ++ ++ return (counter == 0U) ? 0 : (timer->freq / counter) << TIM_PRESCAL_CSI; ++} ++KEEP_PAGER(stm32_timer_csi_freq); ++ ++static void _init_stm32_timer(void) ++{ ++ void *fdt = get_dt_blob(); ++ struct dt_node_info dt_timer; ++ int node = -1; ++ static bool inited; ++ ++ if (inited) ++ return; ++ inited = true; ++ ++ if (!fdt) { ++ panic(); ++ } ++ ++ for (node = timer_get_dt_node(fdt, &dt_timer, node); ++ node != -FDT_ERR_NOTFOUND; ++ node = timer_get_dt_node(fdt, &dt_timer, node)) { ++ struct stm32_timer_instance *timer; ++ const uint32_t *cuint; ++ ++ if (!(dt_timer.status & DT_STATUS_OK_SEC)) { ++ continue; ++ } ++ ++ cuint = fdt_getprop(fdt, node, "st,hsi-cal-input", NULL); ++ if (cuint != NULL) { ++ timer = &stm32_timer[HSI_CAL]; ++ timer->base.pa = dt_timer.base; ++ timer->clk = dt_timer.clock; ++ timer->freq = stm32_clock_get_rate(timer->clk); ++ timer->cal_input = (uint8_t)fdt32_to_cpu(*cuint); ++ timer_config(timer); ++ } ++ ++ cuint = fdt_getprop(fdt, node, "st,csi_cal-input", NULL); ++ if (cuint != NULL) { ++ timer = &stm32_timer[CSI_CAL]; ++ timer->base.pa = dt_timer.base; ++ timer->clk = dt_timer.clock; ++ timer->freq = stm32_clock_get_rate(timer->clk); ++ timer->cal_input = (uint8_t)fdt32_to_cpu(*cuint); ++ timer_config(timer); ++ } ++ } ++} ++ ++void stm32_timer_freq_func(unsigned long (**timer_freq_cb)(void), ++ enum timer_cal type) ++{ ++ _init_stm32_timer(); ++ ++ *timer_freq_cb = NULL; ++ ++ switch (type) { ++ case HSI_CAL: ++ if (stm32_timer[HSI_CAL].base.pa != 0) { ++ *timer_freq_cb = stm32_timer_hsi_freq; ++ } ++ break; ++ ++ case CSI_CAL: ++ if (stm32_timer[CSI_CAL].base.pa != 0) { ++ *timer_freq_cb = stm32_timer_csi_freq; ++ } ++ break; ++ default: ++ panic(); ++ } ++} ++ ++static TEE_Result init_stm32_timer(void) ++{ ++ _init_stm32_timer(); ++ ++ return TEE_SUCCESS; ++} ++driver_init(init_stm32_timer); +diff --git a/core/drivers/stm32_uart.c b/core/drivers/stm32_uart.c +index 1febd84..4afbac8 100644 +--- a/core/drivers/stm32_uart.c ++++ b/core/drivers/stm32_uart.c +@@ -4,10 +4,18 @@ + */ + + #include ++#include + #include + #include ++#include + #include + #include ++#include ++#include ++#include ++#include ++#include ++#include + #include + + #define UART_REG_CR1 0x00 /* Control register 1 */ +@@ -21,6 +29,11 @@ + #define UART_REG_TDR 0x28 /* Transmit data register */ + #define UART_REG_PRESC 0x2c /* Prescaler register */ + ++#define STM32_UART_IOMEM_SIZE 0x400 ++ ++#define PUTC_TIMEOUT_US 1000 ++#define FLUSH_TIMEOUT_US 16000 ++ + /* + * Uart Interrupt & status register bits + * +@@ -36,26 +49,52 @@ + + static vaddr_t loc_chip_to_base(struct serial_chip *chip) + { +- struct console_pdata *pd = +- container_of(chip, struct console_pdata, chip); +- +- return io_pa_or_va(&pd->base); ++ struct stm32_uart_pdata *pd = ++ container_of(chip, struct stm32_uart_pdata, chip); ++ ++ if (cpu_mmu_enabled()) { ++ if (!pd->base.va) { ++ pd->base.va = (vaddr_t)phys_to_virt(pd->base.pa, ++ pd->secure ? ++ MEM_AREA_IO_SEC : ++ MEM_AREA_IO_NSEC); ++ assert(pd->base.va); ++ } ++ ++ return pd->base.va; ++ } ++ ++ return pd->base.pa; + } + + static void loc_flush(struct serial_chip *chip) + { + vaddr_t base = loc_chip_to_base(chip); +- +- while (!(read32(base + UART_REG_ISR) & USART_ISR_TXFE)) +- ; ++ uint64_t timeout_ref = utimeout_init(FLUSH_TIMEOUT_US); ++ ++ while (!(read32(base + UART_REG_ISR) & USART_ISR_TXFE)) { ++ if (utimeout_elapsed(FLUSH_TIMEOUT_US, timeout_ref)) { ++ if (read32(base + UART_REG_ISR) & USART_ISR_TXFE) { ++ break; ++ } ++ return; ++ } ++ } + } + + static void loc_putc(struct serial_chip *chip, int ch) + { + vaddr_t base = loc_chip_to_base(chip); ++ uint64_t timeout_ref = utimeout_init(PUTC_TIMEOUT_US); + +- while (!(read32(base + UART_REG_ISR) & USART_ISR_TXE_TXFNF)) +- ; ++ while (!(read32(base + UART_REG_ISR) & USART_ISR_TXE_TXFNF)) { ++ if (utimeout_elapsed(PUTC_TIMEOUT_US, timeout_ref)) { ++ if (read32(base + UART_REG_ISR) & USART_ISR_TXE_TXFNF) { ++ break; ++ } ++ return; ++ } ++ } + + write32(ch, base + UART_REG_TDR); + } +@@ -77,17 +116,94 @@ static int loc_getchar(struct serial_chip *chip) + return read32(base + UART_REG_RDR) & 0xff; + } + +-static const struct serial_ops serial_ops = { ++static const struct serial_ops stm32_uart_serial_ops = { + .flush = loc_flush, + .putc = loc_putc, + .have_rx_data = loc_have_rx_data, + .getchar = loc_getchar, + + }; +-KEEP_PAGER(serial_ops); ++KEEP_PAGER(stm32_uart_serial_ops); + +-void stm32_uart_init(struct console_pdata *pd, vaddr_t base) ++void stm32_uart_init(struct stm32_uart_pdata *pd, vaddr_t base) + { + pd->base.pa = base; +- pd->chip.ops = &serial_ops; ++ pd->chip.ops = &stm32_uart_serial_ops; ++} ++ ++#ifdef CFG_DT ++static void register_secure_uart(struct stm32_uart_pdata *pd) ++{ ++ size_t n; ++ ++ stm32mp_register_secure_periph_iomem(pd->base.pa); ++ for (n = 0; n < pd->pinctrl_count; n++) { ++ stm32mp_register_secure_gpio(pd->pinctrl[n].bank, ++ pd->pinctrl[n].pin); ++ } ++} ++ ++static void register_non_secure_uart(struct stm32_uart_pdata *pd) ++{ ++ size_t n; ++ ++ stm32mp_register_non_secure_periph_iomem(pd->base.pa); ++ for (n = 0; n < pd->pinctrl_count; n++) { ++ stm32mp_register_non_secure_gpio(pd->pinctrl[n].bank, ++ pd->pinctrl[n].pin); ++ } + } ++ ++struct stm32_uart_pdata *probe_uart_from_dt_node(void *fdt, int node) ++{ ++ struct stm32_uart_pdata *pd; ++ struct dt_node_info info; ++ struct stm32_pinctrl *pinctrl_cfg = NULL; ++ int count; ++ ++ fdt_fill_device_info(fdt, &info, node); ++ ++ if (info.status == DT_STATUS_DISABLED) { ++ return NULL; ++ } ++ ++ pd = calloc(1, sizeof(*pd)); ++ if (!pd) { ++ panic(); ++ } ++ ++ pd->secure = (info.status == DT_STATUS_OK_SEC); ++ pd->base.pa = info.base; ++ ++ if (info.clock < 0) { ++ panic(); ++ } ++ pd->clock = (unsigned int)info.clock; ++ ++ count = stm32_pinctrl_fdt_get_pinctrl(fdt, node, NULL, 0); ++ if (count < 0) { ++ panic(); ++ } ++ if (count != 0) { ++ pinctrl_cfg = calloc(count, sizeof(*pinctrl_cfg)); ++ if (!pinctrl_cfg) { ++ panic(); ++ } ++ stm32_pinctrl_fdt_get_pinctrl(fdt, node, pinctrl_cfg, count); ++ stm32_pinctrl_load_active_cfg(pinctrl_cfg, count); ++ } ++ pd->pinctrl = pinctrl_cfg; ++ pd->pinctrl_count = count; ++ ++ stm32_uart_init(pd, info.base); ++ ++ if (pd->secure) { ++ register_secure_uart(pd); ++ } else { ++ register_non_secure_uart(pd); ++ } ++ ++ return pd; ++} ++#endif /*CFG_DT*/ ++ +diff --git a/core/drivers/stpmic1.c b/core/drivers/stpmic1.c +new file mode 100644 +index 0000000..3aa3afc +--- /dev/null ++++ b/core/drivers/stpmic1.c +@@ -0,0 +1,954 @@ ++// SPDX-License-Identifier: BSD-3-Clause ++/* ++ * Copyright (c) 2016-2018, STMicroelectronics - All Rights Reserved ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define I2C_TIMEOUT_MS 25 ++ ++struct regul_struct { ++ const char *dt_node_name; ++ const uint16_t *voltage_table; ++ uint8_t voltage_table_size; ++ uint8_t control_reg; ++ uint8_t low_power_reg; ++ uint8_t pull_down_reg; ++ uint8_t pull_down; ++ uint8_t mask_reset_reg; ++ uint8_t mask_reset; ++}; ++ ++static struct i2c_handle_s *pmic_i2c_handle; ++static uint16_t pmic_i2c_addr; ++ ++/* Voltage tables in mV */ ++static const uint16_t buck1_voltage_table[] = { ++ 725, ++ 725, ++ 725, ++ 725, ++ 725, ++ 725, ++ 750, ++ 775, ++ 800, ++ 825, ++ 850, ++ 875, ++ 900, ++ 925, ++ 950, ++ 975, ++ 1000, ++ 1025, ++ 1050, ++ 1075, ++ 1100, ++ 1125, ++ 1150, ++ 1175, ++ 1200, ++ 1225, ++ 1250, ++ 1275, ++ 1300, ++ 1325, ++ 1350, ++ 1375, ++ 1400, ++ 1425, ++ 1450, ++ 1475, ++ 1500, ++ 1500, ++ 1500, ++ 1500, ++ 1500, ++ 1500, ++ 1500, ++ 1500, ++ 1500, ++ 1500, ++ 1500, ++ 1500, ++ 1500, ++ 1500, ++ 1500, ++ 1500, ++ 1500, ++ 1500, ++ 1500, ++ 1500, ++ 1500, ++ 1500, ++ 1500, ++ 1500, ++ 1500, ++ 1500, ++ 1500, ++ 1500, ++}; ++ ++static const uint16_t buck2_voltage_table[] = { ++ 1000, ++ 1000, ++ 1000, ++ 1000, ++ 1000, ++ 1000, ++ 1000, ++ 1000, ++ 1000, ++ 1000, ++ 1000, ++ 1000, ++ 1000, ++ 1000, ++ 1000, ++ 1000, ++ 1000, ++ 1000, ++ 1050, ++ 1050, ++ 1100, ++ 1100, ++ 1150, ++ 1150, ++ 1200, ++ 1200, ++ 1250, ++ 1250, ++ 1300, ++ 1300, ++ 1350, ++ 1350, ++ 1400, ++ 1400, ++ 1450, ++ 1450, ++ 1500, ++}; ++ ++static const uint16_t buck3_voltage_table[] = { ++ 1000, ++ 1000, ++ 1000, ++ 1000, ++ 1000, ++ 1000, ++ 1000, ++ 1000, ++ 1000, ++ 1000, ++ 1000, ++ 1000, ++ 1000, ++ 1000, ++ 1000, ++ 1000, ++ 1000, ++ 1000, ++ 1000, ++ 1000, ++ 1100, ++ 1100, ++ 1100, ++ 1100, ++ 1200, ++ 1200, ++ 1200, ++ 1200, ++ 1300, ++ 1300, ++ 1300, ++ 1300, ++ 1400, ++ 1400, ++ 1400, ++ 1400, ++ 1500, ++ 1600, ++ 1700, ++ 1800, ++ 1900, ++ 2000, ++ 2100, ++ 2200, ++ 2300, ++ 2400, ++ 2500, ++ 2600, ++ 2700, ++ 2800, ++ 2900, ++ 3000, ++ 3100, ++ 3200, ++ 3300, ++ 3400, ++}; ++ ++static const uint16_t buck4_voltage_table[] = { ++ 600, ++ 625, ++ 650, ++ 675, ++ 700, ++ 725, ++ 750, ++ 775, ++ 800, ++ 825, ++ 850, ++ 875, ++ 900, ++ 925, ++ 950, ++ 975, ++ 1000, ++ 1025, ++ 1050, ++ 1075, ++ 1100, ++ 1125, ++ 1150, ++ 1175, ++ 1200, ++ 1225, ++ 1250, ++ 1275, ++ 1300, ++ 1300, ++ 1350, ++ 1350, ++ 1400, ++ 1400, ++ 1450, ++ 1450, ++ 1500, ++ 1600, ++ 1700, ++ 1800, ++ 1900, ++ 2000, ++ 2100, ++ 2200, ++ 2300, ++ 2400, ++ 2500, ++ 2600, ++ 2700, ++ 2800, ++ 2900, ++ 3000, ++ 3100, ++ 3200, ++ 3300, ++ 3400, ++ 3500, ++ 3600, ++ 3700, ++ 3800, ++ 3900, ++}; ++ ++static const uint16_t ldo1_voltage_table[] = { ++ 1700, ++ 1700, ++ 1700, ++ 1700, ++ 1700, ++ 1700, ++ 1700, ++ 1700, ++ 1700, ++ 1800, ++ 1900, ++ 2000, ++ 2100, ++ 2200, ++ 2300, ++ 2400, ++ 2500, ++ 2600, ++ 2700, ++ 2800, ++ 2900, ++ 3000, ++ 3100, ++ 3200, ++ 3300, ++}; ++ ++static const uint16_t ldo2_voltage_table[] = { ++ 1700, ++ 1700, ++ 1700, ++ 1700, ++ 1700, ++ 1700, ++ 1700, ++ 1700, ++ 1700, ++ 1800, ++ 1900, ++ 2000, ++ 2100, ++ 2200, ++ 2300, ++ 2400, ++ 2500, ++ 2600, ++ 2700, ++ 2800, ++ 2900, ++ 3000, ++ 3100, ++ 3200, ++ 3300, ++}; ++ ++static const uint16_t ldo3_voltage_table[] = { ++ 1700, ++ 1700, ++ 1700, ++ 1700, ++ 1700, ++ 1700, ++ 1700, ++ 1700, ++ 1700, ++ 1800, ++ 1900, ++ 2000, ++ 2100, ++ 2200, ++ 2300, ++ 2400, ++ 2500, ++ 2600, ++ 2700, ++ 2800, ++ 2900, ++ 3000, ++ 3100, ++ 3200, ++ 3300, ++ 3300, ++ 3300, ++ 3300, ++ 3300, ++ 3300, ++ 3300, ++ 0xFFFF, /* VREFDDR */ ++}; ++ ++static const uint16_t ldo5_voltage_table[] = { ++ 1700, ++ 1700, ++ 1700, ++ 1700, ++ 1700, ++ 1700, ++ 1700, ++ 1700, ++ 1700, ++ 1800, ++ 1900, ++ 2000, ++ 2100, ++ 2200, ++ 2300, ++ 2400, ++ 2500, ++ 2600, ++ 2700, ++ 2800, ++ 2900, ++ 3000, ++ 3100, ++ 3200, ++ 3300, ++ 3400, ++ 3500, ++ 3600, ++ 3700, ++ 3800, ++ 3900, ++}; ++ ++static const uint16_t ldo6_voltage_table[] = { ++ 900, ++ 1000, ++ 1100, ++ 1200, ++ 1300, ++ 1400, ++ 1500, ++ 1600, ++ 1700, ++ 1800, ++ 1900, ++ 2000, ++ 2100, ++ 2200, ++ 2300, ++ 2400, ++ 2500, ++ 2600, ++ 2700, ++ 2800, ++ 2900, ++ 3000, ++ 3100, ++ 3200, ++ 3300, ++}; ++ ++static const uint16_t ldo4_voltage_table[] = { ++ 3300, ++}; ++ ++static const uint16_t vref_ddr_voltage_table[] = { ++ 3300, ++}; ++ ++/* Table of Regulators in PMIC SoC */ ++static const struct regul_struct regulators_table[] = { ++ { ++ .dt_node_name = "buck1", ++ .voltage_table = buck1_voltage_table, ++ .voltage_table_size = ARRAY_SIZE(buck1_voltage_table), ++ .control_reg = BUCK1_CONTROL_REG, ++ .low_power_reg = BUCK1_PWRCTRL_REG, ++ .pull_down_reg = BUCK_PULL_DOWN_REG, ++ .pull_down = BUCK1_PULL_DOWN_SHIFT, ++ .mask_reset_reg = MASK_RESET_BUCK_REG, ++ .mask_reset = BUCK1_MASK_RESET_SHIFT, ++ }, ++ { ++ .dt_node_name = "buck2", ++ .voltage_table = buck2_voltage_table, ++ .voltage_table_size = ARRAY_SIZE(buck2_voltage_table), ++ .control_reg = BUCK2_CONTROL_REG, ++ .low_power_reg = BUCK2_PWRCTRL_REG, ++ .pull_down_reg = BUCK_PULL_DOWN_REG, ++ .pull_down = BUCK2_PULL_DOWN_SHIFT, ++ .mask_reset_reg = MASK_RESET_BUCK_REG, ++ .mask_reset = BUCK2_MASK_RESET_SHIFT, ++ }, ++ { ++ .dt_node_name = "buck3", ++ .voltage_table = buck3_voltage_table, ++ .voltage_table_size = ARRAY_SIZE(buck3_voltage_table), ++ .control_reg = BUCK3_CONTROL_REG, ++ .low_power_reg = BUCK3_PWRCTRL_REG, ++ .pull_down_reg = BUCK_PULL_DOWN_REG, ++ .pull_down = BUCK3_PULL_DOWN_SHIFT, ++ .mask_reset_reg = MASK_RESET_BUCK_REG, ++ .mask_reset = BUCK3_MASK_RESET_SHIFT, ++ }, ++ { ++ .dt_node_name = "buck4", ++ .voltage_table = buck4_voltage_table, ++ .voltage_table_size = ARRAY_SIZE(buck4_voltage_table), ++ .control_reg = BUCK4_CONTROL_REG, ++ .low_power_reg = BUCK4_PWRCTRL_REG, ++ .pull_down_reg = BUCK_PULL_DOWN_REG, ++ .pull_down = BUCK4_PULL_DOWN_SHIFT, ++ .mask_reset_reg = MASK_RESET_BUCK_REG, ++ .mask_reset = BUCK4_MASK_RESET_SHIFT, ++ }, ++ { ++ .dt_node_name = "ldo1", ++ .voltage_table = ldo1_voltage_table, ++ .voltage_table_size = ARRAY_SIZE(ldo1_voltage_table), ++ .control_reg = LDO1_CONTROL_REG, ++ .low_power_reg = LDO1_PWRCTRL_REG, ++ .mask_reset_reg = MASK_RESET_LDO_REG, ++ .mask_reset = LDO1_MASK_RESET_SHIFT, ++ }, ++ { ++ .dt_node_name = "ldo2", ++ .voltage_table = ldo2_voltage_table, ++ .voltage_table_size = ARRAY_SIZE(ldo2_voltage_table), ++ .control_reg = LDO2_CONTROL_REG, ++ .low_power_reg = LDO2_PWRCTRL_REG, ++ .mask_reset_reg = MASK_RESET_LDO_REG, ++ .mask_reset = LDO2_MASK_RESET_SHIFT, ++ }, ++ { ++ .dt_node_name = "ldo3", ++ .voltage_table = ldo3_voltage_table, ++ .voltage_table_size = ARRAY_SIZE(ldo3_voltage_table), ++ .control_reg = LDO3_CONTROL_REG, ++ .low_power_reg = LDO3_PWRCTRL_REG, ++ .mask_reset_reg = MASK_RESET_LDO_REG, ++ .mask_reset = LDO3_MASK_RESET_SHIFT, ++ }, ++ { ++ .dt_node_name = "ldo4", ++ .voltage_table = ldo4_voltage_table, ++ .voltage_table_size = ARRAY_SIZE(ldo4_voltage_table), ++ .control_reg = LDO4_CONTROL_REG, ++ .low_power_reg = LDO4_PWRCTRL_REG, ++ .mask_reset_reg = MASK_RESET_LDO_REG, ++ .mask_reset = LDO4_MASK_RESET_SHIFT, ++ }, ++ { ++ .dt_node_name = "ldo5", ++ .voltage_table = ldo5_voltage_table, ++ .voltage_table_size = ARRAY_SIZE(ldo5_voltage_table), ++ .control_reg = LDO5_CONTROL_REG, ++ .low_power_reg = LDO5_PWRCTRL_REG, ++ .mask_reset_reg = MASK_RESET_LDO_REG, ++ .mask_reset = LDO5_MASK_RESET_SHIFT, ++ }, ++ { ++ .dt_node_name = "ldo6", ++ .voltage_table = ldo6_voltage_table, ++ .voltage_table_size = ARRAY_SIZE(ldo6_voltage_table), ++ .control_reg = LDO6_CONTROL_REG, ++ .low_power_reg = LDO6_PWRCTRL_REG, ++ .mask_reset_reg = MASK_RESET_LDO_REG, ++ .mask_reset = LDO6_MASK_RESET_SHIFT, ++ }, ++ { ++ .dt_node_name = "vref_ddr", ++ .voltage_table = vref_ddr_voltage_table, ++ .voltage_table_size = ARRAY_SIZE(vref_ddr_voltage_table), ++ .control_reg = VREF_DDR_CONTROL_REG, ++ .low_power_reg = VREF_DDR_PWRCTRL_REG, ++ .mask_reset_reg = MASK_RESET_LDO_REG, ++ .mask_reset = VREF_DDR_MASK_RESET_SHIFT, ++ }, ++}; ++ ++#define MAX_REGUL ARRAY_SIZE(regulators_table) ++ ++static const struct regul_struct *get_regulator_data(const char *name) ++{ ++ uint8_t i; ++ ++ for (i = 0 ; i < MAX_REGUL ; i++) { ++ if (strncmp(name, regulators_table[i].dt_node_name, ++ strlen(regulators_table[i].dt_node_name)) == 0) { ++ return ®ulators_table[i]; ++ } ++ } ++ ++ /* Regulator not found */ ++ panic(); ++ return NULL; ++} ++ ++static uint8_t voltage_to_index(const char *name, uint16_t millivolts) ++{ ++ const struct regul_struct *regul = get_regulator_data(name); ++ uint8_t i; ++ ++ for (i = 0 ; i < regul->voltage_table_size ; i++) { ++ if (regul->voltage_table[i] == millivolts) { ++ return i; ++ } ++ } ++ ++ /* Voltage not found */ ++ panic(); ++ ++ return 0; ++} ++ ++int stpmic1_powerctrl_on(void) ++{ ++ return stpmic1_register_update(MAIN_CONTROL_REG, PWRCTRL_PIN_VALID, ++ PWRCTRL_PIN_VALID); ++} ++ ++int stpmic1_switch_off(void) ++{ ++ return stpmic1_register_update(MAIN_CONTROL_REG, 1, ++ SOFTWARE_SWITCH_OFF_ENABLED); ++} ++ ++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)); ++} ++ ++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)); ++} ++ ++uint8_t stpmic1_is_regulator_enabled(const char *name) ++{ ++ uint8_t val; ++ const struct regul_struct *regul = get_regulator_data(name); ++ ++ if (stpmic1_register_read(regul->control_reg, &val) != 0) { ++ panic(); ++ } ++ ++ return (val & 0x1U); ++} ++ ++int stpmic1_regulator_voltage_set(const char *name, uint16_t millivolts) ++{ ++ uint8_t voltage_index = voltage_to_index(name, millivolts); ++ const struct regul_struct *regul = get_regulator_data(name); ++ uint8_t mask; ++ ++ /* Voltage can be set for buck or ldo (except ldo4) regulators */ ++ if (strncmp(name, "buck", 4) == 0) { ++ mask = BUCK_VOLTAGE_MASK; ++ } else if ((strncmp(name, "ldo", 3) == 0) && ++ (strncmp(name, "ldo4", 4) != 0)) { ++ mask = LDO_VOLTAGE_MASK; ++ } else { ++ return 0; ++ } ++ ++ return stpmic1_register_update(regul->control_reg, ++ voltage_index << LDO_BUCK_VOLTAGE_SHIFT, ++ mask); ++} ++ ++int stpmic1_regulator_pull_down_set(const char *name) ++{ ++ const struct regul_struct *regul = get_regulator_data(name); ++ ++ if (regul->pull_down_reg != 0) { ++ return stpmic1_register_update(regul->pull_down_reg, ++ BIT(regul->pull_down), ++ LDO_BUCK_PULL_DOWN_MASK << ++ regul->pull_down); ++ } ++ ++ return 0; ++} ++ ++int stpmic1_regulator_mask_reset_set(const char *name) ++{ ++ const struct regul_struct *regul = get_regulator_data(name); ++ ++ return stpmic1_register_update(regul->mask_reset_reg, ++ BIT(regul->mask_reset), ++ LDO_BUCK_RESET_MASK << ++ regul->mask_reset); ++} ++ ++int stpmic1_bo_enable_unpg(struct stpmic1_bo_cfg *cfg) ++{ ++ return stpmic1_register_update(cfg->ctrl_reg, BIT(0), BIT(0)); ++} ++ ++/* Returns 1 if no configuration are expected applied at runtime, 0 otherwise */ ++int stpmic1_bo_voltage_cfg(const char *name, uint16_t millivolts, ++ struct stpmic1_bo_cfg *cfg) ++{ ++ uint8_t voltage_index = voltage_to_index(name, millivolts); ++ const struct regul_struct *regul = get_regulator_data(name); ++ uint8_t mask; ++ ++ /* Voltage can be set for buck or ldo (except ldo4) regulators */ ++ if (strncmp(name, "buck", 4) == 0) { ++ mask = BUCK_VOLTAGE_MASK; ++ } else if ((strncmp(name, "ldo", 3) == 0) && ++ (strncmp(name, "ldo4", 4) != 0)) { ++ mask = LDO_VOLTAGE_MASK; ++ } else { ++ return 1; ++ } ++ ++ cfg->ctrl_reg = regul->control_reg; ++ cfg->value = voltage_index << LDO_BUCK_VOLTAGE_SHIFT; ++ cfg->mask = mask; ++ ++ return 0; ++} ++ ++int stpmic1_bo_voltage_unpg(struct stpmic1_bo_cfg *cfg) ++{ ++ return stpmic1_register_update(cfg->ctrl_reg, cfg->value, cfg->mask); ++} ++ ++int stpmic1_bo_pull_down_cfg(const char *name, struct stpmic1_bo_cfg *cfg) ++{ ++ const struct regul_struct *regul = get_regulator_data(name); ++ ++ cfg->pd_reg = regul->pull_down_reg; ++ cfg->pd_value = BIT(regul->pull_down); ++ cfg->pd_mask = LDO_BUCK_PULL_DOWN_MASK << regul->pull_down; ++ ++ return 0; ++} ++ ++int stpmic1_bo_pull_down_unpg(struct stpmic1_bo_cfg *cfg) ++{ ++ return stpmic1_register_update(cfg->pd_reg, cfg->pd_value, ++ cfg->pd_mask); ++} ++ ++int stpmic1_bo_mask_reset_cfg(const char *name, struct stpmic1_bo_cfg *cfg) ++{ ++ const struct regul_struct *regul = get_regulator_data(name); ++ ++ cfg->mrst_reg = regul->mask_reset_reg; ++ cfg->mrst_value = BIT(regul->mask_reset); ++ cfg->mrst_mask = LDO_BUCK_RESET_MASK << regul->mask_reset; ++ ++ return 0; ++} ++ ++int stpmic1_bo_mask_reset_unpg(struct stpmic1_bo_cfg *cfg) ++{ ++ return stpmic1_register_update(cfg->mrst_reg, cfg->mrst_value, ++ cfg->mrst_mask); ++} ++ ++int stpmic1_regulator_voltage_get(const char *name) ++{ ++ const struct regul_struct *regul = get_regulator_data(name); ++ uint8_t value; ++ uint8_t mask; ++ ++ /* Voltage can be set for buck or ldo (except ldo4) regulators */ ++ if (strncmp(name, "buck", 4) == 0) { ++ mask = BUCK_VOLTAGE_MASK; ++ } else if ((strncmp(name, "ldo", 3) == 0) && ++ (strncmp(name, "ldo4", 4) != 0)) { ++ mask = LDO_VOLTAGE_MASK; ++ } else { ++ return 0; ++ } ++ ++ if (stpmic1_register_read(regul->control_reg, &value)) ++ return -1; ++ ++ value = (value & mask) >> LDO_BUCK_VOLTAGE_SHIFT; ++ ++ if (value > regul->voltage_table_size) ++ return -1; ++ ++ return (int)regul->voltage_table[value]; ++} ++ ++int stpmic1_lp_copy_reg(const char *name) ++{ ++ uint8_t val; ++ int status; ++ const struct regul_struct *regul = get_regulator_data(name); ++ ++ status = stpmic1_register_read(regul->control_reg, &val); ++ if (status != 0) { ++ return status; ++ } ++ ++ return stpmic1_register_write(regul->low_power_reg, val); ++} ++ ++int stpmic1_lp_cfg(const char *name, struct stpmic1_lp_cfg *cfg) ++{ ++ const struct regul_struct *regul = get_regulator_data(name); ++ ++ cfg->ctrl_reg = regul->control_reg; ++ cfg->lp_reg = regul->low_power_reg; ++ ++ return 0; ++} ++ ++int stpmic1_lp_load_unpg(struct stpmic1_lp_cfg *cfg) ++{ ++ uint8_t val; ++ int status; ++ ++ status = stpmic1_register_read(cfg->ctrl_reg, &val); ++ if (status == 0) { ++ status = stpmic1_register_write(cfg->lp_reg, val); ++ } ++ return status; ++} ++ ++int stpmic1_lp_reg_on_off(const char *name, uint8_t enable) ++{ ++ const struct regul_struct *regul = get_regulator_data(name); ++ ++ return stpmic1_register_update(regul->low_power_reg, enable, ++ LDO_BUCK_ENABLE_MASK); ++} ++ ++int stpmic1_lp_on_off_unpg(struct stpmic1_lp_cfg *cfg, int enable) ++{ ++ assert(enable == 0 || enable == 1); ++ return stpmic1_register_update(cfg->lp_reg, enable, ++ LDO_BUCK_ENABLE_MASK); ++} ++ ++int stpmic1_lp_set_mode(const char *name, uint8_t hplp) ++{ ++ const struct regul_struct *regul = get_regulator_data(name); ++ ++ return stpmic1_register_update(regul->low_power_reg, ++ hplp << LDO_BUCK_HPLP_SHIFT, ++ LDO_BUCK_HPLP_ENABLE_MASK); ++} ++ ++int stpmic1_lp_mode_unpg(struct stpmic1_lp_cfg *cfg, unsigned int mode) ++{ ++ assert(mode == 0 || mode == 1); ++ return stpmic1_register_update(cfg->lp_reg, ++ mode << LDO_BUCK_HPLP_SHIFT, ++ LDO_BUCK_HPLP_ENABLE_MASK); ++} ++ ++int stpmic1_lp_set_voltage(const char *name, uint16_t millivolts) ++{ ++ uint8_t voltage_index = voltage_to_index(name, millivolts); ++ const struct regul_struct *regul = get_regulator_data(name); ++ uint8_t mask; ++ ++ /* Voltage can be set for buck or ldo (except ldo4) regulators */ ++ if (strncmp(name, "buck", 4) == 0) { ++ mask = BUCK_VOLTAGE_MASK; ++ } else if ((strncmp(name, "ldo", 3) == 0) && ++ (strncmp(name, "ldo4", 4) != 0)) { ++ mask = LDO_VOLTAGE_MASK; ++ } else { ++ return 0; ++ } ++ ++ return stpmic1_register_update(regul->low_power_reg, voltage_index << 2, ++ mask); ++} ++ ++/* Returns 1 if no configuration are expected applied at runtime, 0 otherwise */ ++int stpmic1_lp_voltage_cfg(const char *name, uint16_t millivolts, ++ struct stpmic1_lp_cfg *cfg) ++ ++{ ++ uint8_t voltage_index = voltage_to_index(name, millivolts); ++ const struct regul_struct *regul = get_regulator_data(name); ++ uint8_t mask; ++ ++ /* Voltage can be set for buck or ldo (except ldo4) regulators */ ++ if (strncmp(name, "buck", 4) == 0) { ++ mask = BUCK_VOLTAGE_MASK; ++ } else if ((strncmp(name, "ldo", 3) == 0) && ++ (strncmp(name, "ldo4", 4) != 0)) { ++ mask = LDO_VOLTAGE_MASK; ++ } else { ++ return 1; ++ } ++ ++ assert(cfg->lp_reg == regul->low_power_reg); ++ cfg->value = voltage_index << 2; ++ cfg->mask = mask; ++ ++ return 0; ++} ++ ++int stpmic1_lp_voltage_unpg(struct stpmic1_lp_cfg *cfg) ++{ ++ return stpmic1_register_update(cfg->lp_reg, cfg->value, cfg->mask); ++} ++ ++int stpmic1_register_read(uint8_t register_id, uint8_t *value) ++{ ++ struct i2c_handle_s *i2c = pmic_i2c_handle; ++ ++ return stm32_i2c_read_write_membyte(i2c, pmic_i2c_addr, ++ register_id, value, false); ++} ++ ++int stpmic1_register_write(uint8_t register_id, uint8_t value) ++{ ++ int status; ++ struct i2c_handle_s *i2c = pmic_i2c_handle; ++ ++ status = stm32_i2c_read_write_membyte(i2c, pmic_i2c_addr, ++ register_id, &value, true); ++ ++#ifdef CFG_TEE_CORE_DEBUG ++ if (status != 0) { ++ return status; ++ } ++ ++ if ((register_id != WATCHDOG_CONTROL_REG) && (register_id <= 0x40U)) { ++ uint8_t readval; ++ ++ status = stpmic1_register_read(register_id, &readval); ++ if (status != 0) { ++ return status; ++ } ++ ++ if (readval != value) { ++ return -1; ++ } ++ } ++#endif ++ ++ return status; ++} ++ ++int stpmic1_register_update(uint8_t register_id, uint8_t value, uint8_t mask) ++{ ++ int status; ++ uint8_t val; ++ ++ status = stpmic1_register_read(register_id, &val); ++ if (status != 0) { ++ return status; ++ } ++ ++ val = (val & ~mask) | (value & mask); ++ ++ return stpmic1_register_write(register_id, val); ++} ++ ++void stpmic1_bind_i2c(struct i2c_handle_s *i2c_handle, uint16_t i2c_addr) ++{ ++ pmic_i2c_handle = i2c_handle; ++ pmic_i2c_addr = i2c_addr; ++} ++ ++void stpmic1_dump_regulators(void) ++{ ++ size_t i; ++ char __maybe_unused const *name; ++ ++ for (i = 0 ; i < MAX_REGUL ; i++) { ++ name = regulators_table[i].dt_node_name; ++ ++ DMSG("PMIC regul %s: %sable, %dmV", ++ name, ++ stpmic1_is_regulator_enabled(name) ? "en" : "dis", ++ stpmic1_regulator_voltage_get(name)); ++ } ++} ++ ++int stpmic1_get_version(unsigned long *version) ++{ ++ int rc; ++ uint8_t read_val; ++ ++ rc = stpmic1_register_read(VERSION_STATUS_REG, &read_val); ++ if (rc) { ++ return -1; ++ } ++ ++ *version = (unsigned long)read_val; ++ ++ return 0; ++} +diff --git a/core/drivers/sub.mk b/core/drivers/sub.mk +index b2bcf15..41f01fa 100644 +--- a/core/drivers/sub.mk ++++ b/core/drivers/sub.mk +@@ -19,4 +19,13 @@ srcs-$(CFG_DRA7_RNG) += dra7_rng.c + srcs-$(CFG_STIH_UART) += stih_asc.c + srcs-$(CFG_ATMEL_UART) += atmel_uart.c + srcs-$(CFG_MVEBU_UART) += mvebu_uart.c ++srcs-$(CFG_STM32_BSEC) += stm32_bsec.c ++srcs-$(CFG_STM32_ETZPC) += stm32_etzpc.c ++srcs-$(CFG_STM32_GPIO) += stm32_gpio.c ++srcs-$(CFG_STM32_I2C) += stm32_i2c.c ++srcs-$(CFG_STM32_IWDG) += stm32_iwdg.c ++srcs-$(CFG_STM32_RNG) += stm32_rng.c ++srcs-$(CFG_STM32_RTC) += stm32_rtc.c ++srcs-$(CFG_STM32_TIMER) += stm32_timer.c + srcs-$(CFG_STM32_UART) += stm32_uart.c ++srcs-$(CFG_STPMIC1) += stpmic1.c +diff --git a/core/include/drivers/gic.h b/core/include/drivers/gic.h +index a4f60b7..df1e9af 100644 +--- a/core/include/drivers/gic.h ++++ b/core/include/drivers/gic.h +@@ -9,14 +9,39 @@ + #include + #include + ++/* Constants to categorize priorities */ ++#define GIC_HIGHEST_SEC_PRIORITY 0x0U ++#define GIC_LOWEST_SEC_PRIORITY 0x7fU ++#define GIC_HIGHEST_NS_PRIORITY 0x80U ++#define GIC_LOWEST_NS_PRIORITY 0xfeU ++/* 0xff would disable all interrupts */ ++ + #define GIC_DIST_REG_SIZE 0x10000 + #define GIC_CPU_REG_SIZE 0x10000 + ++#if !defined(CFG_WITH_ARM_TRUSTED_FW) && defined(CFG_ARM_GICV3) ++#error CFG_ARM_GICV3 is not supported without CFG_WITH_ARM_TRUSTED_FW ++#endif ++ ++struct gic_it_pm; ++ ++/* ++ * Save and restore some interrupts configuration during low power sequences. ++ * This is used on platforms using OP-TEE secure monitor. ++ */ ++struct gic_pm { ++ struct gic_it_pm *pm_cfg; ++ size_t count; ++}; ++ + struct gic_data { + vaddr_t gicc_base; + vaddr_t gicd_base; + size_t max_it; + struct itr_chip chip; ++#if !defined(CFG_WITH_ARM_TRUSTED_FW) ++ struct gic_pm pm; ++#endif + }; + + /* +@@ -34,4 +59,8 @@ void gic_cpu_init(struct gic_data *gd); + void gic_it_handle(struct gic_data *gd); + + void gic_dump_state(struct gic_data *gd); ++ ++void gic_suspend(struct gic_data *gd); ++void gic_resume(struct gic_data *gd); ++ + #endif /*__DRIVERS_GIC_H*/ +diff --git a/core/include/drivers/stm32_bsec.h b/core/include/drivers/stm32_bsec.h +new file mode 100644 +index 0000000..de4d20b +--- /dev/null ++++ b/core/include/drivers/stm32_bsec.h +@@ -0,0 +1,143 @@ ++/* SPDX-License-Identifier: BSD-3-Clause */ ++/* ++ * Copyright (c) 2015-2018, STMicroelectronics ++ */ ++ ++#ifndef __STM32_BSEC_H__ ++#define __STM32_BSEC_H__ ++ ++#include ++#include ++ ++#define BSEC_OTP_MASK GENMASK_32(4, 0) ++#define BSEC_OTP_BANK_SHIFT 5 ++ ++#define BSEC_TIMEOUT_VALUE 0xFFFF ++ ++#define ADDR_LOWER_OTP_PERLOCK_SHIFT 3 ++#define DATA_LOWER_OTP_PERLOCK_BIT 3 ++#define DATA_LOWER_OTP_PERLOCK_MASK GENMASK_32(2, 0) ++#define ADDR_UPPER_OTP_PERLOCK_SHIFT 4 ++#define DATA_UPPER_OTP_PERLOCK_BIT 1 ++#define DATA_UPPER_OTP_PERLOCK_MASK GENMASK_32(3, 0) ++ ++/* Return status */ ++#define BSEC_OK 0U ++#define BSEC_ERROR 0xFFFFFFFFU ++#define BSEC_DISTURBED 0xFFFFFFFEU ++#define BSEC_FEATURE_LOCK 0xFFFFFFFDU ++#define BSEC_INVALID_PARAM 0xFFFFFFFCU ++#define BSEC_PROG_FAIL 0xFFFFFFFBU ++#define BSEC_LOCK_FAIL 0xFFFFFFFAU ++#define BSEC_WRITE_FAIL 0xFFFFFFF9U ++#define BSEC_SHADOW_FAIL 0xFFFFFFF8U ++#define BSEC_TIMEOUT 0xFFFFFFF7U ++ ++/* BSEC REGISTER OFFSET (base relative) */ ++#define BSEC_OTP_CONF_OFF 0x000U ++#define BSEC_OTP_CTRL_OFF 0x004U ++#define BSEC_OTP_WRDATA_OFF 0x008U ++#define BSEC_OTP_STATUS_OFF 0x00CU ++#define BSEC_OTP_LOCK_OFF 0x010U ++#define BSEC_DEN_OFF 0x014U ++#define BSEC_FEN_OFF 0x018U ++#define BSEC_DISTURBED_OFF 0x01CU ++#define BSEC_DISTURBED1_OFF 0x020U ++#define BSEC_DISTURBED2_OFF 0x024U ++#define BSEC_ERROR_OFF 0x034U ++#define BSEC_ERROR1_OFF 0x038U ++#define BSEC_ERROR2_OFF 0x03CU ++#define BSEC_WRLOCK_OFF 0x04CU ++#define BSEC_WRLOCK1_OFF 0x050U ++#define BSEC_WRLOCK2_OFF 0x054U ++#define BSEC_SPLOCK_OFF 0x064U ++#define BSEC_SPLOCK1_OFF 0x068U ++#define BSEC_SPLOCK2_OFF 0x06CU ++#define BSEC_SWLOCK_OFF 0x07CU ++#define BSEC_SWLOCK1_OFF 0x080U ++#define BSEC_SWLOCK2_OFF 0x084U ++#define BSEC_SRLOCK_OFF 0x094U ++#define BSEC_SRLOCK1_OFF 0x098U ++#define BSEC_SRLOCK2_OFF 0x09CU ++#define BSEC_JTAG_IN_OFF 0x0ACU ++#define BSEC_JTAG_OUT_OFF 0x0B0U ++#define BSEC_SCRATCH_OFF 0x0B4U ++#define BSEC_OTP_DATA_OFF 0x200U ++#define BSEC_IPHW_CFG_OFF 0xFF0U ++#define BSEC_IPVR_OFF 0xFF4U ++#define BSEC_IP_ID_OFF 0xFF8U ++#define BSEC_IP_MAGIC_ID_OFF 0xFFCU ++ ++/* BSEC_CONFIGURATION Register */ ++#define BSEC_CONF_POWER_UP_MASK BIT(0) ++#define BSEC_CONF_POWER_UP_SHIFT 0 ++#define BSEC_CONF_FRQ_MASK GENMASK_32(2, 1) ++#define BSEC_CONF_FRQ_SHIFT 1 ++#define BSEC_CONF_PRG_WIDTH_MASK GENMASK_32(6, 3) ++#define BSEC_CONF_PRG_WIDTH_SHIFT 3 ++#define BSEC_CONF_TREAD_MASK GENMASK_32(8, 7) ++#define BSEC_CONF_TREAD_SHIFT 7 ++ ++/* BSEC_CONTROL Register */ ++#define BSEC_READ 0x000U ++#define BSEC_WRITE 0x100U ++#define BSEC_LOCK 0x200U ++ ++/* STATUS Register */ ++#define BSEC_MODE_STATUS_MASK GENMASK_32(2, 0) ++#define BSEC_MODE_BUSY_MASK BIT(3) ++#define BSEC_MODE_PROGFAIL_MASK BIT(4) ++#define BSEC_MODE_PWR_MASK BIT(5) ++#define BSEC_MODE_BIST1_LOCK_MASK BIT(6) ++#define BSEC_MODE_BIST2_LOCK_MASK BIT(7) ++ ++/* Debug */ ++#define BSEC_HDPEN BIT(4) ++#define BSEC_SPIDEN BIT(5) ++#define BSEC_SPINDEN BIT(6) ++#define BSEC_DBGSWGEN BIT(10) ++#define BSEC_DEN_ALL_MSK GENMASK_32(10, 0) ++ ++/* ++ * OTP Lock services definition ++ * Value must corresponding to the bit number in the register ++ */ ++#define BSEC_LOCK_UPPER_OTP 0x00 ++#define BSEC_LOCK_DEBUG 0x02 ++#define BSEC_LOCK_PROGRAM 0x03 ++ ++/* Values for struct bsec_config::freq */ ++#define FREQ_10_20_MHZ 0x0 ++#define FREQ_20_30_MHZ 0x1 ++#define FREQ_30_45_MHZ 0x2 ++#define FREQ_45_67_MHZ 0x3 ++ ++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); ++uint32_t bsec_program_otp(uint32_t val, uint32_t otp); ++uint32_t bsec_permanent_lock_otp(uint32_t otp); ++ ++uint32_t bsec_write_debug_conf(uint32_t val); ++uint32_t bsec_read_debug_conf(void); ++ ++uint32_t bsec_get_status(void); ++uint32_t bsec_get_hw_conf(void); ++uint32_t bsec_get_version(void); ++uint32_t bsec_get_id(void); ++uint32_t bsec_get_magic_id(void); ++ ++bool bsec_write_sr_lock(uint32_t otp, uint32_t value); ++bool bsec_read_sr_lock(uint32_t otp); ++bool bsec_write_sw_lock(uint32_t otp, uint32_t value); ++bool bsec_read_sw_lock(uint32_t otp); ++bool bsec_write_sp_lock(uint32_t otp, uint32_t value); ++bool bsec_read_sp_lock(uint32_t otp); ++bool bsec_wr_lock(uint32_t otp); ++uint32_t bsec_otp_lock(uint32_t service, uint32_t value); ++ ++bool bsec_mode_is_closed_device(void); ++uint32_t bsec_shadow_read_otp(uint32_t *otp_value, uint32_t word); ++uint32_t bsec_check_nsec_access_rights(uint32_t otp); ++ ++#endif /*__STM32_BSEC_H__*/ +diff --git a/core/include/drivers/stm32_etzpc.h b/core/include/drivers/stm32_etzpc.h +new file mode 100644 +index 0000000..bd34955 +--- /dev/null ++++ b/core/include/drivers/stm32_etzpc.h +@@ -0,0 +1,75 @@ ++/* SPDX-License-Identifier: BSD-3-Clause */ ++/* ++ * Copyright (c) 2014, ARM Limited and Contributors. All rights reserved. ++ * Copyright (c) 2017-2018, STMicroelectronics ++ */ ++ ++#ifndef __STM32_ETZPC_H__ ++#define __STM32_ETZPC_H__ ++ ++#include ++#include ++ ++#define ETZPC_V1_0 0x10 ++#define ETZPC_V2_0 0x20 ++ ++/* ++ * Define security level for each peripheral (DECPROT) ++ */ ++enum etzpc_decprot_attributes { ++ TZPC_DECPROT_S_RW = 0, ++ TZPC_DECPROT_NS_R_S_W = 1, ++ TZPC_DECPROT_MCU_ISOLATION = 2, ++ TZPC_DECPROT_NS_RW = 3, ++ TZPC_DECPROT_MAX = 4, ++}; ++ ++/* ++ * etzpc_configure_decprot : Load a DECPROT configuration ++ * decprot_id : ID of the IP ++ * decprot_attr : Restriction access attributes ++ */ ++void etzpc_configure_decprot(uint32_t decprot_id, ++ enum etzpc_decprot_attributes decprot_attr); ++ ++/* ++ * etzpc_get_decprot : Get the DECPROT attribute ++ * decprot_id : ID of the IP ++ * return : Attribute of this DECPROT ++ */ ++enum etzpc_decprot_attributes etzpc_get_decprot(uint32_t decprot_id); ++ ++/* ++ * etzpc_lock_decprot : Lock access to the DECPROT attributes ++ * decprot_id : ID of the IP ++ */ ++void etzpc_lock_decprot(uint32_t decprot_id); ++ ++/* ++ * etzpc_configure_tzma : Configure the target TZMA read only size ++ * tzma_id : ID of the memory ++ * tzma_value : read-only size ++ */ ++void etzpc_configure_tzma(uint32_t tzma_id, uint16_t tzma_value); ++ ++/* ++ * etzpc_get_tzma : Get the target TZMA read only size ++ * tzma_id : TZMA ID ++ * return : Size of read only size ++ */ ++uint16_t etzpc_get_tzma(uint32_t tzma_id); ++ ++/* ++ * etzpc_lock_tzma : Lock the target TZMA ++ * tzma_id : TZMA ID ++ */ ++void etzpc_lock_tzma(uint32_t tzma_id); ++ ++/* ++ * etzpc_get_lock_tzma : Return the lock status of the target TZMA ++ * tzma_id : TZMA ID ++ * return : True if TZMA is locked, false otherwise ++ */ ++bool etzpc_get_lock_tzma(uint32_t tzma_id); ++ ++#endif /*__STM32_ETZPC_H__*/ +diff --git a/core/include/drivers/stm32_gpio.h b/core/include/drivers/stm32_gpio.h +new file mode 100644 +index 0000000..67de10f +--- /dev/null ++++ b/core/include/drivers/stm32_gpio.h +@@ -0,0 +1,107 @@ ++/* SPDX-License-Identifier: BSD-3-Clause */ ++/* ++ * Copyright (c) 2015-2018, STMicroelectronics - All Rights Reserved ++ */ ++ ++#ifndef __STM32_GPIO_H__ ++#define __STM32_GPIO_H__ ++ ++#include ++#include ++#include ++ ++#define GPIO_MODE_OFFSET 0x00U ++#define GPIO_TYPE_OFFSET 0x04U ++#define GPIO_SPEED_OFFSET 0x08U ++#define GPIO_PUPD_OFFSET 0x0CU ++#define GPIO_ODR_OFFSET 0x14U ++#define GPIO_BSRR_OFFSET 0x18U ++#define GPIO_AFRL_OFFSET 0x20U ++#define GPIO_AFRH_OFFSET 0x24U ++#define GPIO_SECR_OFFSET 0x30U ++ ++#define GPIO_ALT_LOWER_LIMIT 0x08U ++ ++#define GPIO_PIN_0 0x00U ++#define GPIO_PIN_1 0x01U ++#define GPIO_PIN_2 0x02U ++#define GPIO_PIN_3 0x03U ++#define GPIO_PIN_4 0x04U ++#define GPIO_PIN_5 0x05U ++#define GPIO_PIN_6 0x06U ++#define GPIO_PIN_7 0x07U ++#define GPIO_PIN_8 0x08U ++#define GPIO_PIN_9 0x09U ++#define GPIO_PIN_10 0x0AU ++#define GPIO_PIN_11 0x0BU ++#define GPIO_PIN_12 0x0CU ++#define GPIO_PIN_13 0x0DU ++#define GPIO_PIN_14 0x0EU ++#define GPIO_PIN_15 0x0FU ++#define GPIO_PIN_MAX GPIO_PIN_15 ++ ++#define GPIO_ALTERNATE_0 0x00 ++#define GPIO_ALTERNATE_1 0x01 ++#define GPIO_ALTERNATE_2 0x02 ++#define GPIO_ALTERNATE_3 0x03 ++#define GPIO_ALTERNATE_4 0x04 ++#define GPIO_ALTERNATE_5 0x05 ++#define GPIO_ALTERNATE_6 0x06 ++#define GPIO_ALTERNATE_7 0x07 ++#define GPIO_ALTERNATE_8 0x08 ++#define GPIO_ALTERNATE_9 0x09 ++#define GPIO_ALTERNATE_10 0x0A ++#define GPIO_ALTERNATE_11 0x0B ++#define GPIO_ALTERNATE_12 0x0C ++#define GPIO_ALTERNATE_13 0x0D ++#define GPIO_ALTERNATE_14 0x0E ++#define GPIO_ALTERNATE_15 0x0F ++#define GPIO_ALTERNATE_MAX 0x0FU ++ ++#define GPIO_MODE_INPUT 0x00 ++#define GPIO_MODE_OUTPUT 0x01 ++#define GPIO_MODE_ALTERNATE 0x02 ++#define GPIO_MODE_ANALOG 0x03 ++#define GPIO_MODE_MAX 0x03U ++ ++#define GPIO_OPEN_DRAIN 0x10U ++ ++#define GPIO_SPEED_LOW 0x00 ++#define GPIO_SPEED_MEDIUM 0x01 ++#define GPIO_SPEED_HIGH 0x02 ++#define GPIO_SPEED_VERY_HIGH 0x03 ++#define GPIO_SPEED_MAX 0x03U ++ ++#define GPIO_NO_PULL 0x00 ++#define GPIO_PULL_UP 0x01 ++#define GPIO_PULL_DOWN 0x02 ++#define GPIO_PULL_MAX 0x03U ++ ++struct gpio_cfg { ++ uint16_t moder: 2; ++ uint16_t otyper: 1; ++ uint16_t ospeedr: 2; ++ uint16_t pupdr: 2; ++ uint16_t odr: 1; ++ uint16_t afr: 4; ++}; ++ ++struct stm32_pinctrl { ++ uint8_t bank; ++ uint8_t pin; ++ struct gpio_cfg active_cfg; ++ struct gpio_cfg standby_cfg; ++}; ++ ++void stm32_pinctrl_load_active_cfg(struct stm32_pinctrl *pinctrl, size_t cnt); ++void stm32_pinctrl_load_standby_cfg(struct stm32_pinctrl *pinctrl, size_t cnt); ++void stm32_pinctrl_store_standby_cfg(struct stm32_pinctrl *pinctrl, size_t cnt); ++ ++int stm32_pinctrl_fdt_get_pinctrl(void *fdt, int node, ++ struct stm32_pinctrl *cfg, size_t count); ++ ++void stm32_gpio_set_output_level(uint32_t bank, uint32_t pin, int high); ++ ++void stm32_gpio_set_secure_cfg(uint32_t bank, uint32_t pin, bool secure); ++ ++#endif /*__STM32_GPIO_H__*/ +diff --git a/core/include/drivers/stm32_i2c.h b/core/include/drivers/stm32_i2c.h +new file mode 100644 +index 0000000..3c6e326 +--- /dev/null ++++ b/core/include/drivers/stm32_i2c.h +@@ -0,0 +1,377 @@ ++/* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */ ++/* ++ * Copyright (c) 2016-2018, STMicroelectronics - All Rights Reserved ++ */ ++ ++#ifndef __STM32_I2C_H ++#define __STM32_I2C_H ++ ++#include ++#include ++#include ++#include ++ ++/* ++ * When STM32_I2C_MAYBE_NON_SECURE is defined, the I2C bus maybe ++ * non secure and yet used by the secure world. In such case, ++ * secure world may use the I2C only in atomic conditions ++ * where the non secure world cannot be executed. ++ */ ++#define STM32_I2C_MAYBE_NON_SECURE ++ ++/* Bit definition for I2C_CR1 register */ ++#define I2C_CR1_PE BIT(0) ++#define I2C_CR1_TXIE BIT(1) ++#define I2C_CR1_RXIE BIT(2) ++#define I2C_CR1_ADDRIE BIT(3) ++#define I2C_CR1_NACKIE BIT(4) ++#define I2C_CR1_STOPIE BIT(5) ++#define I2C_CR1_TCIE BIT(6) ++#define I2C_CR1_ERRIE BIT(7) ++#define I2C_CR1_DNF GENMASK_32(11, 8) ++#define I2C_CR1_ANFOFF BIT(12) ++#define I2C_CR1_SWRST BIT(13) ++#define I2C_CR1_TXDMAEN BIT(14) ++#define I2C_CR1_RXDMAEN BIT(15) ++#define I2C_CR1_SBC BIT(16) ++#define I2C_CR1_NOSTRETCH BIT(17) ++#define I2C_CR1_WUPEN BIT(18) ++#define I2C_CR1_GCEN BIT(19) ++#define I2C_CR1_SMBHEN BIT(22) ++#define I2C_CR1_SMBDEN BIT(21) ++#define I2C_CR1_ALERTEN BIT(22) ++#define I2C_CR1_PECEN BIT(23) ++ ++/* Bit definition for I2C_CR2 register */ ++#define I2C_CR2_SADD GENMASK_32(9, 0) ++#define I2C_CR2_RD_WRN BIT(10) ++#define I2C_CR2_RD_WRN_OFFSET 10U ++#define I2C_CR2_ADD10 BIT(11) ++#define I2C_CR2_HEAD10R BIT(12) ++#define I2C_CR2_START BIT(13) ++#define I2C_CR2_STOP BIT(14) ++#define I2C_CR2_NACK BIT(15) ++#define I2C_CR2_NBYTES GENMASK_32(23, 16) ++#define I2C_CR2_NBYTES_OFFSET 16U ++#define I2C_CR2_RELOAD BIT(24) ++#define I2C_CR2_AUTOEND BIT(25) ++#define I2C_CR2_PECBYTE BIT(26) ++ ++/* Bit definition for I2C_OAR1 register */ ++#define I2C_OAR1_OA1 GENMASK_32(9, 0) ++#define I2C_OAR1_OA1MODE BIT(10) ++#define I2C_OAR1_OA1EN BIT(15) ++ ++/* Bit definition for I2C_OAR2 register */ ++#define I2C_OAR2_OA2 GENMASK_32(7, 1) ++#define I2C_OAR2_OA2MSK GENMASK_32(10, 8) ++#define I2C_OAR2_OA2NOMASK 0 ++#define I2C_OAR2_OA2MASK01 BIT(8) ++#define I2C_OAR2_OA2MASK02 BIT(9) ++#define I2C_OAR2_OA2MASK03 GENMASK_32(9, 8) ++#define I2C_OAR2_OA2MASK04 BIT(10) ++#define I2C_OAR2_OA2MASK05 (BIT(8) | BIT(10)) ++#define I2C_OAR2_OA2MASK06 (BIT(9) | BIT(10)) ++#define I2C_OAR2_OA2MASK07 GENMASK_32(10, 8) ++#define I2C_OAR2_OA2EN BIT(15) ++ ++/* Bit definition for I2C_TIMINGR register */ ++#define I2C_TIMINGR_SCLL GENMASK_32(7, 0) ++#define I2C_TIMINGR_SCLH GENMASK_32(15, 8) ++#define I2C_TIMINGR_SDADEL GENMASK_32(19, 16) ++#define I2C_TIMINGR_SCLDEL GENMASK_32(23, 20) ++#define I2C_TIMINGR_PRESC GENMASK_32(31, 28) ++#define I2C_TIMINGR_SCLL_MAX (I2C_TIMINGR_SCLL + 1) ++#define I2C_TIMINGR_SCLH_MAX ((I2C_TIMINGR_SCLH >> 8) + 1) ++#define I2C_TIMINGR_SDADEL_MAX ((I2C_TIMINGR_SDADEL >> 16) + 1) ++#define I2C_TIMINGR_SCLDEL_MAX ((I2C_TIMINGR_SCLDEL >> 20) + 1) ++#define I2C_TIMINGR_PRESC_MAX ((I2C_TIMINGR_PRESC >> 28) + 1) ++#define I2C_SET_TIMINGR_SCLL(n) ((n) & \ ++ (I2C_TIMINGR_SCLL_MAX - 1)) ++#define I2C_SET_TIMINGR_SCLH(n) (((n) & \ ++ (I2C_TIMINGR_SCLH_MAX - 1)) << 8) ++#define I2C_SET_TIMINGR_SDADEL(n) (((n) & \ ++ (I2C_TIMINGR_SDADEL_MAX - 1)) << 16) ++#define I2C_SET_TIMINGR_SCLDEL(n) (((n) & \ ++ (I2C_TIMINGR_SCLDEL_MAX - 1)) << 20) ++#define I2C_SET_TIMINGR_PRESC(n) (((n) & \ ++ (I2C_TIMINGR_PRESC_MAX - 1)) << 28) ++ ++/* Bit definition for I2C_TIMEOUTR register */ ++#define I2C_TIMEOUTR_TIMEOUTA GENMASK_32(11, 0) ++#define I2C_TIMEOUTR_TIDLE BIT(12) ++#define I2C_TIMEOUTR_TIMOUTEN BIT(15) ++#define I2C_TIMEOUTR_TIMEOUTB GENMASK_32(27, 16) ++#define I2C_TIMEOUTR_TEXTEN BIT(31) ++ ++/* Bit definition for I2C_ISR register */ ++#define I2C_ISR_TXE BIT(0) ++#define I2C_ISR_TXIS BIT(1) ++#define I2C_ISR_RXNE BIT(2) ++#define I2C_ISR_ADDR BIT(3) ++#define I2C_ISR_NACKF BIT(4) ++#define I2C_ISR_STOPF BIT(5) ++#define I2C_ISR_TC BIT(6) ++#define I2C_ISR_TCR BIT(7) ++#define I2C_ISR_BERR BIT(8) ++#define I2C_ISR_ARLO BIT(9) ++#define I2C_ISR_OVR BIT(10) ++#define I2C_ISR_PECERR BIT(11) ++#define I2C_ISR_TIMEOUT BIT(12) ++#define I2C_ISR_ALERT BIT(13) ++#define I2C_ISR_BUSY BIT(15) ++#define I2C_ISR_DIR BIT(16) ++#define I2C_ISR_ADDCODE GENMASK_32(23, 17) ++ ++/* Bit definition for I2C_ICR register */ ++#define I2C_ICR_ADDRCF BIT(3) ++#define I2C_ICR_NACKCF BIT(4) ++#define I2C_ICR_STOPCF BIT(5) ++#define I2C_ICR_BERRCF BIT(8) ++#define I2C_ICR_ARLOCF BIT(9) ++#define I2C_ICR_OVRCF BIT(10) ++#define I2C_ICR_PECCF BIT(11) ++#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 ++ ++struct stm32_i2c_init_s { ++ uint32_t own_address1; /* ++ * Specifies the first device own ++ * address. This parameter can be a ++ * 7-bit or 10-bit address. ++ */ ++ ++ uint32_t addressing_mode; /* ++ * Specifies if 7-bit or 10-bit ++ * addressing mode is selected. ++ * This parameter can be a value of ++ * @ref I2C_ADDRESSING_MODE. ++ */ ++ ++ uint32_t dual_address_mode; /* ++ * Specifies if dual addressing mode is ++ * selected. ++ * This parameter can be a value of @ref ++ * I2C_DUAL_ADDRESSING_MODE. ++ */ ++ ++ uint32_t own_address2; /* ++ * Specifies the second device own ++ * address if dual addressing mode is ++ * selected. This parameter can be a ++ * 7-bit address. ++ */ ++ ++ uint32_t own_address2_masks; /* ++ * Specifies the acknowledge mask ++ * address second device own address ++ * if dual addressing mode is selected ++ * This parameter can be a value of @ref ++ * I2C_OWN_ADDRESS2_MASKS. ++ */ ++ ++ uint32_t general_call_mode; /* ++ * Specifies if general call mode is ++ * selected. ++ * This parameter can be a value of @ref ++ * I2C_GENERAL_CALL_ADDRESSING_MODE. ++ */ ++ ++ uint32_t no_stretch_mode; /* ++ * Specifies if nostretch mode is ++ * selected. ++ * This parameter can be a value of @ref ++ * I2C_NOSTRETCH_MODE. ++ */ ++ ++ uint32_t rise_time; /* ++ * Specifies the SCL clock pin rising ++ * time in nanoseconds. ++ */ ++ ++ uint32_t fall_time; /* ++ * Specifies the SCL clock pin falling ++ * 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. ++ */ ++ ++ int analog_filter; /* ++ * Specifies if the I2C analog noise ++ * filter is selected. ++ * This parameter can be 0 (filter ++ * off), all other values mean filter ++ * on. ++ */ ++ ++ uint8_t digital_filter_coef; /* ++ * Specifies the I2C digital noise ++ * filter coefficient. ++ * This parameter can be a value ++ * between 0 and ++ * STM32_I2C_DIGITAL_FILTER_MAX. ++ */ ++}; ++ ++enum i2c_state_e { ++ I2C_STATE_RESET = 0x00U, /* Not yet initialized */ ++ I2C_STATE_READY = 0x20U, /* Ready for use */ ++ I2C_STATE_BUSY = 0x24U, /* Internal process ongoing */ ++ I2C_STATE_BUSY_TX = 0x21U, /* Data Transmission ongoing */ ++ I2C_STATE_BUSY_RX = 0x22U, /* Data Reception ongoing */ ++ I2C_STATE_SUSPENDED = 0xF0U, /* Bus is supended */ ++}; ++ ++enum i2c_mode_e { ++ I2C_MODE_NONE = 0x00U, /* No active communication */ ++ I2C_MODE_MASTER = 0x10U, /* Communication in Master Mode */ ++ I2C_MODE_SLAVE = 0x20U, /* Communication in Slave Mode */ ++ I2C_MODE_MEM = 0x40U /* Communication in Memory Mode */ ++ ++}; ++ ++#define I2C_ERROR_NONE 0x00000000U /* No error */ ++#define I2C_ERROR_BERR 0x00000001U /* BERR error */ ++#define I2C_ERROR_ARLO 0x00000002U /* ARLO error */ ++#define I2C_ERROR_AF 0x00000004U /* ACKF error */ ++#define I2C_ERROR_OVR 0x00000008U /* OVR error */ ++#define I2C_ERROR_DMA 0x00000010U /* DMA transfer error */ ++#define I2C_ERROR_TIMEOUT 0x00000020U /* Timeout error */ ++#define I2C_ERROR_SIZE 0x00000040U /* Size Management error */ ++ ++#ifdef STM32_I2C_MAYBE_NON_SECURE ++struct i2c_cfg { ++ uint32_t timingr; ++ uint32_t oar1; ++ uint32_t oar2; ++ uint32_t cr1; ++ uint32_t cr2; ++}; ++#endif ++ ++struct i2c_handle_s { ++ uintptr_t pbase; /* Registers phys base address */ ++ uintptr_t vbase; /* Registers virt base address */ ++ unsigned int dt_status; /* DT nsec/sec status */ ++ unsigned int clock; /* Clock reference */ ++ uint8_t lock; /* Locking object (FIXME: really usefull?) */ ++ enum i2c_state_e i2c_state; /* Communication state */ ++ enum i2c_mode_e i2c_mode; /* Communication mode */ ++ uint32_t i2c_err; /* Error code */ ++ 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 */ ++#ifdef STM32_I2C_MAYBE_NON_SECURE ++ struct i2c_cfg alt_cfg; /* Alternate usage context */ ++#endif ++}; ++ ++#define I2C_ADDRESSINGMODE_7BIT 0x00000001U ++#define I2C_ADDRESSINGMODE_10BIT 0x00000002U ++ ++#define I2C_DUALADDRESS_DISABLE 0x00000000U ++#define I2C_DUALADDRESS_ENABLE I2C_OAR2_OA2EN ++ ++#define I2C_GENERALCALL_DISABLE 0x00000000U ++#define I2C_GENERALCALL_ENABLE I2C_CR1_GCEN ++ ++#define I2C_NOSTRETCH_DISABLE 0x00000000U ++#define I2C_NOSTRETCH_ENABLE I2C_CR1_NOSTRETCH ++ ++#define I2C_MEMADD_SIZE_8BIT 0x00000001U ++#define I2C_MEMADD_SIZE_16BIT 0x00000002U ++ ++#define I2C_RELOAD_MODE I2C_CR2_RELOAD ++#define I2C_AUTOEND_MODE I2C_CR2_AUTOEND ++#define I2C_SOFTEND_MODE 0x00000000U ++ ++#define I2C_NO_STARTSTOP 0x00000000U ++#define I2C_GENERATE_STOP (BIT(31) | I2C_CR2_STOP) ++#define I2C_GENERATE_START_READ (BIT(31) | I2C_CR2_START | \ ++ I2C_CR2_RD_WRN) ++#define I2C_GENERATE_START_WRITE (BIT(31) | I2C_CR2_START) ++ ++#define I2C_FLAG_TXE I2C_ISR_TXE ++#define I2C_FLAG_TXIS I2C_ISR_TXIS ++#define I2C_FLAG_RXNE I2C_ISR_RXNE ++#define I2C_FLAG_ADDR I2C_ISR_ADDR ++#define I2C_FLAG_AF I2C_ISR_NACKF ++#define I2C_FLAG_STOPF I2C_ISR_STOPF ++#define I2C_FLAG_TC I2C_ISR_TC ++#define I2C_FLAG_TCR I2C_ISR_TCR ++#define I2C_FLAG_BERR I2C_ISR_BERR ++#define I2C_FLAG_ARLO I2C_ISR_ARLO ++#define I2C_FLAG_OVR I2C_ISR_OVR ++#define I2C_FLAG_PECERR I2C_ISR_PECERR ++#define I2C_FLAG_TIMEOUT I2C_ISR_TIMEOUT ++#define I2C_FLAG_ALERT I2C_ISR_ALERT ++#define I2C_FLAG_BUSY I2C_ISR_BUSY ++#define I2C_FLAG_DIR I2C_ISR_DIR ++ ++#define I2C_RESET_CR2 (I2C_CR2_SADD | I2C_CR2_HEAD10R | \ ++ I2C_CR2_NBYTES | I2C_CR2_RELOAD | \ ++ I2C_CR2_RD_WRN) ++ ++#define I2C_TIMEOUT_BUSY_MS 25U ++ ++#define I2C_ANALOGFILTER_ENABLE 0x00000000U ++#define I2C_ANALOGFILTER_DISABLE I2C_CR1_ANFOFF ++ ++/* 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 ++ ++int stm32_i2c_get_setup_from_fdt(void *fdt, int node, ++ struct stm32_i2c_init_s *init, ++ struct stm32_pinctrl **pinctrl, ++ size_t *pinctrl_count); ++ ++int stm32_i2c_init(struct i2c_handle_s *hi2c, ++ struct stm32_i2c_init_s *init_data); ++ ++int stm32_i2c_mem_write(struct i2c_handle_s *hi2c, uint16_t dev_addr, ++ uint16_t mem_addr, uint16_t mem_add_size, ++ uint8_t *p_data, uint16_t size, uint32_t timeout_ms); ++ ++int stm32_i2c_mem_read(struct i2c_handle_s *hi2c, uint16_t dev_addr, ++ uint16_t mem_addr, uint16_t mem_add_size, ++ uint8_t *p_data, uint16_t size, uint32_t timeout_ms); ++ ++int stm32_i2c_master_transmit(struct i2c_handle_s *hi2c, uint16_t dev_addr, ++ uint8_t *p_data, uint16_t size, ++ uint32_t timeout_ms); ++ ++int stm32_i2c_master_receive(struct i2c_handle_s *hi2c, uint16_t dev_addr, ++ uint8_t *p_data, uint16_t size, ++ uint32_t timeout_ms); ++ ++bool stm32_i2c_is_device_ready(struct i2c_handle_s *hi2c, uint16_t dev_addr, ++ uint32_t trials, uint32_t timeout_ms); ++ ++int stm32_i2c_read_write_membyte(struct i2c_handle_s *hi2c, uint16_t dev_addr, ++ unsigned int mem_addr, uint8_t *p_data, ++ bool write); ++ ++void stm32_i2c_suspend(struct i2c_handle_s *hi2c); ++void stm32_i2c_resume(struct i2c_handle_s *hi2c); ++ ++#endif /* __STM32_I2C_H */ +diff --git a/core/include/drivers/stm32_iwdg.h b/core/include/drivers/stm32_iwdg.h +new file mode 100644 +index 0000000..b649dee +--- /dev/null ++++ b/core/include/drivers/stm32_iwdg.h +@@ -0,0 +1,17 @@ ++/* SPDX-License-Identifier: BSD-3-Clause */ ++/* ++ * Copyright (c) 2018, STMicroelectronics - All Rights Reserved ++ */ ++ ++#ifndef __STM32_IWDG_H__ ++#define __STM32_IWDG_H__ ++ ++#include ++ ++#define IWDG_HW_ENABLED BIT(0) ++#define IWDG_ENABLE_ON_STOP BIT(1) ++#define IWDG_ENABLE_ON_STANDBY BIT(2) ++ ++void stm32_iwdg_refresh(uint32_t instance); ++ ++#endif /*__STM32_IWDG_H__*/ +diff --git a/core/include/drivers/stm32_rng.h b/core/include/drivers/stm32_rng.h +new file mode 100644 +index 0000000..1ba098f +--- /dev/null ++++ b/core/include/drivers/stm32_rng.h +@@ -0,0 +1,14 @@ ++/* SPDX-License-Identifier: BSD-3-Clause */ ++/* ++ * Copyright (c) 2018, STMicroelectronics - All Rights Reserved ++ */ ++ ++#ifndef __STM32_RNG_H__ ++#define __STM32_RNG_H__ ++ ++#include ++#include ++ ++int stm32_rng_read(uint8_t *out, size_t size); ++ ++#endif /*__STM32_RNG__*/ +diff --git a/core/include/drivers/stm32_rtc.h b/core/include/drivers/stm32_rtc.h +new file mode 100644 +index 0000000..39a262c +--- /dev/null ++++ b/core/include/drivers/stm32_rtc.h +@@ -0,0 +1,73 @@ ++/* SPDX-License-Identifier: BSD-3-Clause */ ++/* ++ * Copyright (c) 2017-2018, STMicroelectronics - All Rights Reserved ++ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. ++ */ ++ ++#ifndef __PLAT_RTC_H__ ++#define __PLAT_RTC_H__ ++ ++#include ++ ++#define RTC_TR 0x00U ++#define RTC_DR 0x04U ++#define RTC_SSR 0x08U ++#define RTC_ICSR 0x0CU ++#define RTC_PRER 0x10U ++#define RTC_WUTR 0x14U ++#define RTC_CR 0x18U ++#define RTC_SMCR 0x20U ++#define RTC_WPR 0x24U ++#define RTC_CALR 0x28U ++#define RTC_SHIFTR 0x2CU ++#define RTC_TSTR 0x30U ++#define RTC_TSDR 0x34U ++#define RTC_TSSSR 0x38U ++#define RTC_ALRMAR 0x40U ++#define RTC_ALRMASSR 0x44U ++#define RTC_ALRMBR 0x48U ++#define RTC_ALRMBSSR 0x4CU ++#define RTC_SR 0x50U ++#define RTC_SCR 0x5CU ++#define RTC_OR 0x60U ++ ++struct stm32_rtc_calendar { ++ uint32_t ssr; ++ uint32_t tr; ++ uint32_t dr; ++}; ++ ++enum months { ++ JANUARY = 1, ++ FEBRUARY, ++ MARCH, ++ APRIL, ++ MAY, ++ JUNE, ++ JULY, ++ AUGUST, ++ SEPTEMBER, ++ OCTOBER, ++ NOVEMBER, ++ DECEMBER, ++ NB_MONTHS = 12 ++}; ++ ++struct stm32_rtc_time { ++ uint32_t hour; ++ uint32_t min; ++ uint32_t sec; ++ uint32_t wday; ++ uint32_t day; ++ enum months month; ++ uint32_t year; ++}; ++ ++void stm32_rtc_get_calendar(struct stm32_rtc_calendar *calendar); ++unsigned long long stm32_rtc_diff_calendar(struct stm32_rtc_calendar *current, ++ struct stm32_rtc_calendar *ref); ++void stm32_rtc_set_tamper_timestamp(void); ++bool stm32_rtc_is_timestamp_enable(void); ++void stm32_rtc_get_timestamp(struct stm32_rtc_time *tamp_ts); ++ ++#endif /* __PLAT_RTC_H__ */ +diff --git a/core/include/drivers/stm32_timer.h b/core/include/drivers/stm32_timer.h +new file mode 100644 +index 0000000..b7e6751 +--- /dev/null ++++ b/core/include/drivers/stm32_timer.h +@@ -0,0 +1,25 @@ ++/* SPDX-License-Identifier: BSD-3-Clause */ ++/* ++ * Copyright (c) 2018, STMicroelectronics - All Rights Reserved ++ */ ++ ++#ifndef STM32_TIMER_H ++#define STM32_TIMER_H ++ ++enum timer_cal { ++ HSI_CAL = 0, ++ CSI_CAL ++}; ++ ++unsigned long stm32_timer_hsi_freq(void); ++unsigned long stm32_timer_csi_freq(void); ++ ++/* ++ * Get the timer frequence callback function for a target clock calibration ++ * @timer_freq_cb - Output callback function ++ * @type - Target clock calibration ID ++ */ ++void stm32_timer_freq_func(unsigned long (**timer_freq_cb)(void), ++ enum timer_cal type); ++ ++#endif /* STM32_TIMER_H */ +diff --git a/core/include/drivers/stm32_uart.h b/core/include/drivers/stm32_uart.h +index 58c7077..6ddb8c4 100644 +--- a/core/include/drivers/stm32_uart.h ++++ b/core/include/drivers/stm32_uart.h +@@ -7,12 +7,18 @@ + #define __STM32_UART_H__ + + #include ++#include + +-struct console_pdata { ++struct stm32_uart_pdata { + struct io_pa_va base; + struct serial_chip chip; ++ bool secure; ++ struct stm32_pinctrl *pinctrl; ++ size_t pinctrl_count; ++ unsigned long clock; + }; + +-void stm32_uart_init(struct console_pdata *pd, vaddr_t base); ++void stm32_uart_init(struct stm32_uart_pdata *pd, vaddr_t base); ++struct stm32_uart_pdata *probe_uart_from_dt_node(void *fdt, int node); + + #endif /*__STM32_UART_H__*/ +diff --git a/core/include/drivers/stpmic1.h b/core/include/drivers/stpmic1.h +new file mode 100644 +index 0000000..3073662 +--- /dev/null ++++ b/core/include/drivers/stpmic1.h +@@ -0,0 +1,228 @@ ++/* SPDX-License-Identifier: BSD-3-Clause */ ++/* ++ * Copyright (c) 2016-2018, STMicroelectronics - All Rights Reserved ++ */ ++ ++#ifndef __STPMIC1_H__ ++#define __STPMIC1_H__ ++ ++#include ++#include ++ ++#define TURN_ON_REG 0x1U ++#define TURN_OFF_REG 0x2U ++#define ICC_LDO_TURN_OFF_REG 0x3U ++#define ICC_BUCK_TURN_OFF_REG 0x4U ++#define RESET_STATUS_REG 0x5U ++#define VERSION_STATUS_REG 0x6U ++#define MAIN_CONTROL_REG 0x10U ++#define PADS_PULL_REG 0x11U ++#define BUCK_PULL_DOWN_REG 0x12U ++#define LDO14_PULL_DOWN_REG 0x13U ++#define LDO56_PULL_DOWN_REG 0x14U ++#define VIN_CONTROL_REG 0x15U ++#define PONKEY_TIMER_REG 0x16U ++#define MASK_RANK_BUCK_REG 0x17U ++#define MASK_RESET_BUCK_REG 0x18U ++#define MASK_RANK_LDO_REG 0x19U ++#define MASK_RESET_LDO_REG 0x1AU ++#define WATCHDOG_CONTROL_REG 0x1BU ++#define WATCHDOG_TIMER_REG 0x1CU ++#define BUCK_ICC_TURNOFF_REG 0x1DU ++#define LDO_ICC_TURNOFF_REG 0x1EU ++#define BUCK_APM_CONTROL_REG 0x1FU ++#define BUCK1_CONTROL_REG 0x20U ++#define BUCK2_CONTROL_REG 0x21U ++#define BUCK3_CONTROL_REG 0x22U ++#define BUCK4_CONTROL_REG 0x23U ++#define VREF_DDR_CONTROL_REG 0x24U ++#define LDO1_CONTROL_REG 0x25U ++#define LDO2_CONTROL_REG 0x26U ++#define LDO3_CONTROL_REG 0x27U ++#define LDO4_CONTROL_REG 0x28U ++#define LDO5_CONTROL_REG 0x29U ++#define LDO6_CONTROL_REG 0x2AU ++#define BUCK1_PWRCTRL_REG 0x30U ++#define BUCK2_PWRCTRL_REG 0x31U ++#define BUCK3_PWRCTRL_REG 0x32U ++#define BUCK4_PWRCTRL_REG 0x33U ++#define VREF_DDR_PWRCTRL_REG 0x34U ++#define LDO1_PWRCTRL_REG 0x35U ++#define LDO2_PWRCTRL_REG 0x36U ++#define LDO3_PWRCTRL_REG 0x37U ++#define LDO4_PWRCTRL_REG 0x38U ++#define LDO5_PWRCTRL_REG 0x39U ++#define LDO6_PWRCTRL_REG 0x3AU ++#define FREQUENCY_SPREADING_REG 0x3BU ++#define USB_CONTROL_REG 0x40U ++#define ITLATCH1_REG 0x50U ++#define ITLATCH2_REG 0x51U ++#define ITLATCH3_REG 0x52U ++#define ITLATCH4_REG 0x53U ++#define ITSETLATCH1_REG 0x60U ++#define ITSETLATCH2_REG 0x61U ++#define ITSETLATCH3_REG 0x62U ++#define ITSETLATCH4_REG 0x63U ++#define ITCLEARLATCH1_REG 0x70U ++#define ITCLEARLATCH2_REG 0x71U ++#define ITCLEARLATCH3_REG 0x72U ++#define ITCLEARLATCH4_REG 0x73U ++#define ITMASK1_REG 0x80U ++#define ITMASK2_REG 0x81U ++#define ITMASK3_REG 0x82U ++#define ITMASK4_REG 0x83U ++#define ITSETMASK1_REG 0x90U ++#define ITSETMASK2_REG 0x91U ++#define ITSETMASK3_REG 0x92U ++#define ITSETMASK4_REG 0x93U ++#define ITCLEARMASK1_REG 0xA0U ++#define ITCLEARMASK2_REG 0xA1U ++#define ITCLEARMASK3_REG 0xA2U ++#define ITCLEARMASK4_REG 0xA3U ++#define ITSOURCE1_REG 0xB0U ++#define ITSOURCE2_REG 0xB1U ++#define ITSOURCE3_REG 0xB2U ++#define ITSOURCE4_REG 0xB3U ++ ++/* Registers masks */ ++#define LDO_VOLTAGE_MASK 0x7CU ++#define BUCK_VOLTAGE_MASK 0xFCU ++#define LDO_BUCK_VOLTAGE_SHIFT 2 ++#define LDO_BUCK_ENABLE_MASK 0x01U ++#define LDO_BUCK_HPLP_ENABLE_MASK 0x02U ++#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 ++ ++/* Pull down register */ ++#define BUCK1_PULL_DOWN_SHIFT 0 ++#define BUCK2_PULL_DOWN_SHIFT 2 ++#define BUCK3_PULL_DOWN_SHIFT 4 ++#define BUCK4_PULL_DOWN_SHIFT 6 ++#define VREF_DDR_PULL_DOWN_SHIFT 4 ++ ++/* Buck Mask reset register */ ++#define BUCK1_MASK_RESET_SHIFT 0 ++#define BUCK2_MASK_RESET_SHIFT 1 ++#define BUCK3_MASK_RESET_SHIFT 2 ++#define BUCK4_MASK_RESET_SHIFT 3 ++ ++/* LDO Mask reset register */ ++#define LDO1_MASK_RESET_SHIFT 0 ++#define LDO2_MASK_RESET_SHIFT 1 ++#define LDO3_MASK_RESET_SHIFT 2 ++#define LDO4_MASK_RESET_SHIFT 3 ++#define LDO5_MASK_RESET_SHIFT 4 ++#define LDO6_MASK_RESET_SHIFT 5 ++#define VREF_DDR_MASK_RESET_SHIFT 6 ++ ++/* Main PMIC Control Register (MAIN_CONTROL_REG) */ ++#define ICC_EVENT_ENABLED BIT(4) ++#define PWRCTRL_POLARITY_HIGH BIT(3) ++#define PWRCTRL_PIN_VALID BIT(2) ++#define RESTART_REQUEST_ENABLED BIT(1) ++#define SOFTWARE_SWITCH_OFF_ENABLED BIT(0) ++ ++/* Main PMIC PADS Control Register (PADS_PULL_REG) */ ++#define WAKEUP_DETECTOR_DISABLED BIT(4) ++#define PWRCTRL_PD_ACTIVE BIT(3) ++#define PWRCTRL_PU_ACTIVE BIT(2) ++#define WAKEUP_PD_ACTIVE BIT(1) ++#define PONKEY_PU_ACTIVE BIT(0) ++ ++/* 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_SHIFT 4 ++#define VINLOW_THRESHOLD_MASK 0x7 ++#define VINLOW_THRESHOLD_SHIFT 1 ++#define VINLOW_ENABLED 0x01 ++#define VINLOW_CTRL_REG_MASK 0xFF ++ ++/* USB Control Register */ ++#define BOOST_OVP_DISABLED BIT(7) ++#define VBUS_OTG_DETECTION_DISABLED BIT(6) ++#define OCP_LIMIT_HIGH BIT(3) ++#define SWIN_SWOUT_ENABLED BIT(2) ++#define USBSW_OTG_SWITCH_ENABLED BIT(1) ++ ++int stpmic1_powerctrl_on(void); ++int stpmic1_switch_off(void); ++ ++int stpmic1_register_read(uint8_t register_id, uint8_t *value); ++int stpmic1_register_write(uint8_t register_id, uint8_t value); ++int stpmic1_register_update(uint8_t register_id, uint8_t value, uint8_t mask); ++ ++int stpmic1_regulator_enable(const char *name); ++int stpmic1_regulator_disable(const char *name); ++uint8_t stpmic1_is_regulator_enabled(const char *name); ++ ++int stpmic1_regulator_voltage_set(const char *name, uint16_t millivolts); ++int stpmic1_regulator_voltage_get(const char *name); ++int stpmic1_regulator_mask_reset_set(const char *name); ++ ++int stpmic1_lp_copy_reg(const char *name); ++int stpmic1_lp_reg_on_off(const char *name, uint8_t enable); ++int stpmic1_lp_set_mode(const char *name, uint8_t hplp); ++int stpmic1_lp_set_voltage(const char *name, uint16_t millivolts); ++ ++/* ++ * The STPMIC1 is accessed during low power sequence in unpaged ++ * execution context. To prevent adding an unpaged constraint on ++ * STPMIC1 regulator definitions, conversion tables and device tree ++ * content, the regulators configurations are read from device tree ++ * at boot time and saved in memory for being applied at runtime ++ * without needing pager support. ++ * ++ * There are 2 types of regulator configuration loaded during such ++ * low power and unpaged sequences: boot-on (bo) configuration and ++ * low power (lp) configuration. ++ */ ++struct stpmic1_bo_cfg { ++ uint8_t ctrl_reg; ++ uint8_t value; ++ uint8_t mask; ++ uint8_t pd_reg; ++ uint8_t pd_value; ++ uint8_t pd_mask; ++ uint8_t mrst_reg; ++ uint8_t mrst_value; ++ uint8_t mrst_mask; ++}; ++ ++struct stpmic1_lp_cfg { ++ uint8_t ctrl_reg; ++ uint8_t lp_reg; ++ uint8_t value; ++ uint8_t mask; ++}; ++ ++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); ++int stpmic1_bo_voltage_unpg(struct stpmic1_bo_cfg *cfg); ++ ++int stpmic1_bo_pull_down_cfg(const char *name, ++ struct stpmic1_bo_cfg *cfg); ++int stpmic1_bo_pull_down_unpg(struct stpmic1_bo_cfg *cfg); ++ ++int stpmic1_bo_mask_reset_cfg(const char *name, struct stpmic1_bo_cfg *cfg); ++int stpmic1_bo_mask_reset_unpg(struct stpmic1_bo_cfg *cfg); ++ ++int stpmic1_lp_cfg(const char *name, struct stpmic1_lp_cfg *cfg); ++int stpmic1_lp_load_unpg(struct stpmic1_lp_cfg *cfg); ++int stpmic1_lp_on_off_unpg(struct stpmic1_lp_cfg *cfg, int enable); ++int stpmic1_lp_mode_unpg(struct stpmic1_lp_cfg *cfg, ++ unsigned int mode); ++int stpmic1_lp_voltage_cfg(const char *name, uint16_t millivolts, ++ struct stpmic1_lp_cfg *cfg); ++int stpmic1_lp_voltage_unpg(struct stpmic1_lp_cfg *cfg); ++ ++void stpmic1_bind_i2c(struct i2c_handle_s *i2c_handle, uint16_t i2c_addr); ++ ++int stpmic1_get_version(unsigned long *version); ++void stpmic1_dump_regulators(void); ++ ++#endif /*__STPMIC1_H__*/ +diff --git a/core/include/dt-bindings/clock/stm32mp1-clks.h b/core/include/dt-bindings/clock/stm32mp1-clks.h +new file mode 100644 +index 0000000..f5254cf +--- /dev/null ++++ b/core/include/dt-bindings/clock/stm32mp1-clks.h +@@ -0,0 +1,252 @@ ++/* SPDX-License-Identifier: GPL-2.0 or BSD-3-Clause */ ++/* ++ * Copyright (C) STMicroelectronics 2018 - All Rights Reserved ++ * Author: Gabriel Fernandez for STMicroelectronics. ++ */ ++ ++#ifndef _DT_BINDINGS_STM32MP1_CLKS_H_ ++#define _DT_BINDINGS_STM32MP1_CLKS_H_ ++ ++/* OSCILLATOR clocks */ ++#define CK_HSE 0 ++#define CK_CSI 1 ++#define CK_LSI 2 ++#define CK_LSE 3 ++#define CK_HSI 4 ++#define CK_HSE_DIV2 5 ++ ++/* Bus clocks */ ++#define TIM2 6 ++#define TIM3 7 ++#define TIM4 8 ++#define TIM5 9 ++#define TIM6 10 ++#define TIM7 11 ++#define TIM12 12 ++#define TIM13 13 ++#define TIM14 14 ++#define LPTIM1 15 ++#define SPI2 16 ++#define SPI3 17 ++#define USART2 18 ++#define USART3 19 ++#define UART4 20 ++#define UART5 21 ++#define UART7 22 ++#define UART8 23 ++#define I2C1 24 ++#define I2C2 25 ++#define I2C3 26 ++#define I2C5 27 ++#define SPDIF 28 ++#define CEC 29 ++#define DAC12 30 ++#define MDIO 31 ++#define TIM1 32 ++#define TIM8 33 ++#define TIM15 34 ++#define TIM16 35 ++#define TIM17 36 ++#define SPI1 37 ++#define SPI4 38 ++#define SPI5 39 ++#define USART6 40 ++#define SAI1 41 ++#define SAI2 42 ++#define SAI3 43 ++#define DFSDM 44 ++#define FDCAN 45 ++#define LPTIM2 46 ++#define LPTIM3 47 ++#define LPTIM4 48 ++#define LPTIM5 49 ++#define SAI4 50 ++#define SYSCFG 51 ++#define VREF 52 ++#define TMPSENS 53 ++#define PMBCTRL 54 ++#define HDP 55 ++#define LTDC 56 ++#define DSI 57 ++#define IWDG2 58 ++#define USBPHY 59 ++#define STGENRO 60 ++#define SPI6 61 ++#define I2C4 62 ++#define I2C6 63 ++#define USART1 64 ++#define RTCAPB 65 ++#define TZC1 66 ++#define TZPC 67 ++#define IWDG1 68 ++#define BSEC 69 ++#define STGEN 70 ++#define DMA1 71 ++#define DMA2 72 ++#define DMAMUX 73 ++#define ADC12 74 ++#define USBO 75 ++#define SDMMC3 76 ++#define DCMI 77 ++#define CRYP2 78 ++#define HASH2 79 ++#define RNG2 80 ++#define CRC2 81 ++#define HSEM 82 ++#define IPCC 83 ++#define GPIOA 84 ++#define GPIOB 85 ++#define GPIOC 86 ++#define GPIOD 87 ++#define GPIOE 88 ++#define GPIOF 89 ++#define GPIOG 90 ++#define GPIOH 91 ++#define GPIOI 92 ++#define GPIOJ 93 ++#define GPIOK 94 ++#define GPIOZ 95 ++#define CRYP1 96 ++#define HASH1 97 ++#define RNG1 98 ++#define BKPSRAM 99 ++#define MDMA 100 ++#define GPU 101 ++#define ETHCK 102 ++#define ETHTX 103 ++#define ETHRX 104 ++#define ETHMAC 105 ++#define FMC 106 ++#define QSPI 107 ++#define SDMMC1 108 ++#define SDMMC2 109 ++#define CRC1 110 ++#define USBH 111 ++#define ETHSTP 112 ++#define TZC2 113 ++ ++/* Kernel clocks */ ++#define SDMMC1_K 118 ++#define SDMMC2_K 119 ++#define SDMMC3_K 120 ++#define FMC_K 121 ++#define QSPI_K 122 ++#define ETHCK_K 123 ++#define RNG1_K 124 ++#define RNG2_K 125 ++#define GPU_K 126 ++#define USBPHY_K 127 ++#define STGEN_K 128 ++#define SPDIF_K 129 ++#define SPI1_K 130 ++#define SPI2_K 131 ++#define SPI3_K 132 ++#define SPI4_K 133 ++#define SPI5_K 134 ++#define SPI6_K 135 ++#define CEC_K 136 ++#define I2C1_K 137 ++#define I2C2_K 138 ++#define I2C3_K 139 ++#define I2C4_K 140 ++#define I2C5_K 141 ++#define I2C6_K 142 ++#define LPTIM1_K 143 ++#define LPTIM2_K 144 ++#define LPTIM3_K 145 ++#define LPTIM4_K 146 ++#define LPTIM5_K 147 ++#define USART1_K 148 ++#define USART2_K 149 ++#define USART3_K 150 ++#define UART4_K 151 ++#define UART5_K 152 ++#define USART6_K 153 ++#define UART7_K 154 ++#define UART8_K 155 ++#define DFSDM_K 156 ++#define FDCAN_K 157 ++#define SAI1_K 158 ++#define SAI2_K 159 ++#define SAI3_K 160 ++#define SAI4_K 161 ++#define ADC12_K 162 ++#define DSI_K 163 ++#define DSI_PX 164 ++#define ADFSDM_K 165 ++#define USBO_K 166 ++#define LTDC_PX 167 ++#define DAC12_K 168 ++#define ETHPTP_K 169 ++ ++/* PLL */ ++#define PLL1 176 ++#define PLL2 177 ++#define PLL3 178 ++#define PLL4 179 ++ ++/* ODF */ ++#define PLL1_P 180 ++#define PLL1_Q 181 ++#define PLL1_R 182 ++#define PLL2_P 183 ++#define PLL2_Q 184 ++#define PLL2_R 185 ++#define PLL3_P 186 ++#define PLL3_Q 187 ++#define PLL3_R 188 ++#define PLL4_P 189 ++#define PLL4_Q 190 ++#define PLL4_R 191 ++ ++/* AUX */ ++#define RTC 192 ++ ++/* MCLK */ ++#define CK_PER 193 ++#define CK_MPU 194 ++#define CK_AXI 195 ++#define CK_MCU 196 ++ ++/* Time base */ ++#define TIM2_K 197 ++#define TIM3_K 198 ++#define TIM4_K 199 ++#define TIM5_K 200 ++#define TIM6_K 201 ++#define TIM7_K 202 ++#define TIM12_K 203 ++#define TIM13_K 204 ++#define TIM14_K 205 ++#define TIM1_K 206 ++#define TIM8_K 207 ++#define TIM15_K 208 ++#define TIM16_K 209 ++#define TIM17_K 210 ++ ++/* MCO clocks */ ++#define CK_MCO1 211 ++#define CK_MCO2 212 ++ ++/* TRACE & DEBUG clocks */ ++#define DBG 213 ++#define CK_DBG 214 ++#define CK_TRACE 215 ++ ++/* DDR */ ++#define DDRC1 220 ++#define DDRC1LP 221 ++#define DDRC2 222 ++#define DDRC2LP 223 ++#define DDRPHYC 224 ++#define DDRPHYCLP 225 ++#define DDRCAPB 226 ++#define DDRCAPBLP 227 ++#define AXIDCG 228 ++#define DDRPHYCAPB 229 ++#define DDRPHYCAPBLP 230 ++#define DDRPERFM 231 ++ ++#define STM32MP1_LAST_CLK 232 ++ ++#endif /* _DT_BINDINGS_STM32MP1_CLKS_H_ */ +diff --git a/core/include/dt-bindings/clock/stm32mp1-clksrc.h b/core/include/dt-bindings/clock/stm32mp1-clksrc.h +new file mode 100644 +index 0000000..de7d160 +--- /dev/null ++++ b/core/include/dt-bindings/clock/stm32mp1-clksrc.h +@@ -0,0 +1,284 @@ ++/* ++ * Copyright (C) 2017, STMicroelectronics - All Rights Reserved ++ * ++ * SPDX-License-Identifier: GPL-2.0+ BSD-3-Clause ++ */ ++ ++#ifndef _DT_BINDINGS_CLOCK_STM32MP1_CLKSRC_H_ ++#define _DT_BINDINGS_CLOCK_STM32MP1_CLKSRC_H_ ++ ++/* PLL output is enable when x=1, with x=p,q or r */ ++#define PQR(p, q, r) (((p) & 1) | (((q) & 1) << 1) | (((r) & 1) << 2)) ++ ++/* st,clksrc: mandatory clock source */ ++ ++#define CLK_MPU_HSI 0x00000200 ++#define CLK_MPU_HSE 0x00000201 ++#define CLK_MPU_PLL1P 0x00000202 ++#define CLK_MPU_PLL1P_DIV 0x00000203 ++ ++#define CLK_AXI_HSI 0x00000240 ++#define CLK_AXI_HSE 0x00000241 ++#define CLK_AXI_PLL2P 0x00000242 ++ ++#define CLK_MCU_HSI 0x00000480 ++#define CLK_MCU_HSE 0x00000481 ++#define CLK_MCU_CSI 0x00000482 ++#define CLK_MCU_PLL3P 0x00000483 ++ ++#define CLK_PLL12_HSI 0x00000280 ++#define CLK_PLL12_HSE 0x00000281 ++ ++#define CLK_PLL3_HSI 0x00008200 ++#define CLK_PLL3_HSE 0x00008201 ++#define CLK_PLL3_CSI 0x00008202 ++ ++#define CLK_PLL4_HSI 0x00008240 ++#define CLK_PLL4_HSE 0x00008241 ++#define CLK_PLL4_CSI 0x00008242 ++#define CLK_PLL4_I2SCKIN 0x00008243 ++ ++#define CLK_RTC_DISABLED 0x00001400 ++#define CLK_RTC_LSE 0x00001401 ++#define CLK_RTC_LSI 0x00001402 ++#define CLK_RTC_HSE 0x00001403 ++ ++#define CLK_MCO1_HSI 0x00008000 ++#define CLK_MCO1_HSE 0x00008001 ++#define CLK_MCO1_CSI 0x00008002 ++#define CLK_MCO1_LSI 0x00008003 ++#define CLK_MCO1_LSE 0x00008004 ++#define CLK_MCO1_DISABLED 0x0000800F ++ ++#define CLK_MCO2_MPU 0x00008040 ++#define CLK_MCO2_AXI 0x00008041 ++#define CLK_MCO2_MCU 0x00008042 ++#define CLK_MCO2_PLL4P 0x00008043 ++#define CLK_MCO2_HSE 0x00008044 ++#define CLK_MCO2_HSI 0x00008045 ++#define CLK_MCO2_DISABLED 0x0000804F ++ ++/* st,pkcs: peripheral kernel clock source */ ++ ++#define CLK_I2C12_PCLK1 0x00008C00 ++#define CLK_I2C12_PLL4R 0x00008C01 ++#define CLK_I2C12_HSI 0x00008C02 ++#define CLK_I2C12_CSI 0x00008C03 ++#define CLK_I2C12_DISABLED 0x00008C07 ++ ++#define CLK_I2C35_PCLK1 0x00008C40 ++#define CLK_I2C35_PLL4R 0x00008C41 ++#define CLK_I2C35_HSI 0x00008C42 ++#define CLK_I2C35_CSI 0x00008C43 ++#define CLK_I2C35_DISABLED 0x00008C47 ++ ++#define CLK_I2C46_PCLK5 0x00000C00 ++#define CLK_I2C46_PLL3Q 0x00000C01 ++#define CLK_I2C46_HSI 0x00000C02 ++#define CLK_I2C46_CSI 0x00000C03 ++#define CLK_I2C46_DISABLED 0x00000C07 ++ ++#define CLK_SAI1_PLL4Q 0x00008C80 ++#define CLK_SAI1_PLL3Q 0x00008C81 ++#define CLK_SAI1_I2SCKIN 0x00008C82 ++#define CLK_SAI1_CKPER 0x00008C83 ++#define CLK_SAI1_PLL3R 0x00008C84 ++#define CLK_SAI1_DISABLED 0x00008C87 ++ ++#define CLK_SAI2_PLL4Q 0x00008CC0 ++#define CLK_SAI2_PLL3Q 0x00008CC1 ++#define CLK_SAI2_I2SCKIN 0x00008CC2 ++#define CLK_SAI2_CKPER 0x00008CC3 ++#define CLK_SAI2_SPDIF 0x00008CC4 ++#define CLK_SAI2_PLL3R 0x00008CC5 ++#define CLK_SAI2_DISABLED 0x00008CC7 ++ ++#define CLK_SAI3_PLL4Q 0x00008D00 ++#define CLK_SAI3_PLL3Q 0x00008D01 ++#define CLK_SAI3_I2SCKIN 0x00008D02 ++#define CLK_SAI3_CKPER 0x00008D03 ++#define CLK_SAI3_PLL3R 0x00008D04 ++#define CLK_SAI3_DISABLED 0x00008D07 ++ ++#define CLK_SAI4_PLL4Q 0x00008D40 ++#define CLK_SAI4_PLL3Q 0x00008D41 ++#define CLK_SAI4_I2SCKIN 0x00008D42 ++#define CLK_SAI4_CKPER 0x00008D43 ++#define CLK_SAI4_PLL3R 0x00008D44 ++#define CLK_SAI4_DISABLED 0x00008D47 ++ ++#define CLK_SPI2S1_PLL4P 0x00008D80 ++#define CLK_SPI2S1_PLL3Q 0x00008D81 ++#define CLK_SPI2S1_I2SCKIN 0x00008D82 ++#define CLK_SPI2S1_CKPER 0x00008D83 ++#define CLK_SPI2S1_PLL3R 0x00008D84 ++#define CLK_SPI2S1_DISABLED 0x00008D87 ++ ++#define CLK_SPI2S23_PLL4P 0x00008DC0 ++#define CLK_SPI2S23_PLL3Q 0x00008DC1 ++#define CLK_SPI2S23_I2SCKIN 0x00008DC2 ++#define CLK_SPI2S23_CKPER 0x00008DC3 ++#define CLK_SPI2S23_PLL3R 0x00008DC4 ++#define CLK_SPI2S23_DISABLED 0x00008DC7 ++ ++#define CLK_SPI45_PCLK2 0x00008E00 ++#define CLK_SPI45_PLL4Q 0x00008E01 ++#define CLK_SPI45_HSI 0x00008E02 ++#define CLK_SPI45_CSI 0x00008E03 ++#define CLK_SPI45_HSE 0x00008E04 ++#define CLK_SPI45_DISABLED 0x00008E07 ++ ++#define CLK_SPI6_PCLK5 0x00000C40 ++#define CLK_SPI6_PLL4Q 0x00000C41 ++#define CLK_SPI6_HSI 0x00000C42 ++#define CLK_SPI6_CSI 0x00000C43 ++#define CLK_SPI6_HSE 0x00000C44 ++#define CLK_SPI6_PLL3Q 0x00000C45 ++#define CLK_SPI6_DISABLED 0x00000C47 ++ ++#define CLK_UART6_PCLK2 0x00008E40 ++#define CLK_UART6_PLL4Q 0x00008E41 ++#define CLK_UART6_HSI 0x00008E42 ++#define CLK_UART6_CSI 0x00008E43 ++#define CLK_UART6_HSE 0x00008E44 ++#define CLK_UART6_DISABLED 0x00008E47 ++ ++#define CLK_UART24_PCLK1 0x00008E80 ++#define CLK_UART24_PLL4Q 0x00008E81 ++#define CLK_UART24_HSI 0x00008E82 ++#define CLK_UART24_CSI 0x00008E83 ++#define CLK_UART24_HSE 0x00008E84 ++#define CLK_UART24_DISABLED 0x00008E87 ++ ++#define CLK_UART35_PCLK1 0x00008EC0 ++#define CLK_UART35_PLL4Q 0x00008EC1 ++#define CLK_UART35_HSI 0x00008EC2 ++#define CLK_UART35_CSI 0x00008EC3 ++#define CLK_UART35_HSE 0x00008EC4 ++#define CLK_UART35_DISABLED 0x00008EC7 ++ ++#define CLK_UART78_PCLK1 0x00008F00 ++#define CLK_UART78_PLL4Q 0x00008F01 ++#define CLK_UART78_HSI 0x00008F02 ++#define CLK_UART78_CSI 0x00008F03 ++#define CLK_UART78_HSE 0x00008F04 ++#define CLK_UART78_DISABLED 0x00008F07 ++ ++#define CLK_UART1_PCLK5 0x00000C80 ++#define CLK_UART1_PLL3Q 0x00000C81 ++#define CLK_UART1_HSI 0x00000C82 ++#define CLK_UART1_CSI 0x00000C83 ++#define CLK_UART1_PLL4Q 0x00000C84 ++#define CLK_UART1_HSE 0x00000C85 ++#define CLK_UART1_DISABLED 0x00000C87 ++ ++#define CLK_SDMMC12_HCLK6 0x00008F40 ++#define CLK_SDMMC12_PLL3R 0x00008F41 ++#define CLK_SDMMC12_PLL4P 0x00008F42 ++#define CLK_SDMMC12_HSI 0x00008F43 ++#define CLK_SDMMC12_DISABLED 0x00008F47 ++ ++#define CLK_SDMMC3_HCLK2 0x00008F80 ++#define CLK_SDMMC3_PLL3R 0x00008F81 ++#define CLK_SDMMC3_PLL4P 0x00008F82 ++#define CLK_SDMMC3_HSI 0x00008F83 ++#define CLK_SDMMC3_DISABLED 0x00008F87 ++ ++#define CLK_ETH_PLL4P 0x00008FC0 ++#define CLK_ETH_PLL3Q 0x00008FC1 ++#define CLK_ETH_DISABLED 0x00008FC3 ++ ++#define CLK_QSPI_ACLK 0x00009000 ++#define CLK_QSPI_PLL3R 0x00009001 ++#define CLK_QSPI_PLL4P 0x00009002 ++#define CLK_QSPI_CKPER 0x00009003 ++ ++#define CLK_FMC_ACLK 0x00009040 ++#define CLK_FMC_PLL3R 0x00009041 ++#define CLK_FMC_PLL4P 0x00009042 ++#define CLK_FMC_CKPER 0x00009043 ++ ++#define CLK_FDCAN_HSE 0x000090C0 ++#define CLK_FDCAN_PLL3Q 0x000090C1 ++#define CLK_FDCAN_PLL4Q 0x000090C2 ++#define CLK_FDCAN_PLL4R 0x000090C3 ++ ++#define CLK_SPDIF_PLL4P 0x00009140 ++#define CLK_SPDIF_PLL3Q 0x00009141 ++#define CLK_SPDIF_HSI 0x00009142 ++#define CLK_SPDIF_DISABLED 0x00009143 ++ ++#define CLK_CEC_LSE 0x00009180 ++#define CLK_CEC_LSI 0x00009181 ++#define CLK_CEC_CSI_DIV122 0x00009182 ++#define CLK_CEC_DISABLED 0x00009183 ++ ++#define CLK_USBPHY_HSE 0x000091C0 ++#define CLK_USBPHY_PLL4R 0x000091C1 ++#define CLK_USBPHY_HSE_DIV2 0x000091C2 ++#define CLK_USBPHY_DISABLED 0x000091C3 ++ ++#define CLK_USBO_PLL4R 0x800091C0 ++#define CLK_USBO_USBPHY 0x800091C1 ++ ++#define CLK_RNG1_CSI 0x00000CC0 ++#define CLK_RNG1_PLL4R 0x00000CC1 ++#define CLK_RNG1_LSE 0x00000CC2 ++#define CLK_RNG1_LSI 0x00000CC3 ++ ++#define CLK_RNG2_CSI 0x00009200 ++#define CLK_RNG2_PLL4R 0x00009201 ++#define CLK_RNG2_LSE 0x00009202 ++#define CLK_RNG2_LSI 0x00009203 ++ ++#define CLK_CKPER_HSI 0x00000D00 ++#define CLK_CKPER_CSI 0x00000D01 ++#define CLK_CKPER_HSE 0x00000D02 ++#define CLK_CKPER_DISABLED 0x00000D03 ++ ++#define CLK_STGEN_HSI 0x00000D40 ++#define CLK_STGEN_HSE 0x00000D41 ++#define CLK_STGEN_DISABLED 0x00000D43 ++ ++#define CLK_DSI_DSIPLL 0x00009240 ++#define CLK_DSI_PLL4P 0x00009241 ++ ++#define CLK_ADC_PLL4R 0x00009280 ++#define CLK_ADC_CKPER 0x00009281 ++#define CLK_ADC_PLL3Q 0x00009282 ++#define CLK_ADC_DISABLED 0x00009283 ++ ++#define CLK_LPTIM45_PCLK3 0x000092C0 ++#define CLK_LPTIM45_PLL4P 0x000092C1 ++#define CLK_LPTIM45_PLL3Q 0x000092C2 ++#define CLK_LPTIM45_LSE 0x000092C3 ++#define CLK_LPTIM45_LSI 0x000092C4 ++#define CLK_LPTIM45_CKPER 0x000092C5 ++#define CLK_LPTIM45_DISABLED 0x000092C7 ++ ++#define CLK_LPTIM23_PCLK3 0x00009300 ++#define CLK_LPTIM23_PLL4Q 0x00009301 ++#define CLK_LPTIM23_CKPER 0x00009302 ++#define CLK_LPTIM23_LSE 0x00009303 ++#define CLK_LPTIM23_LSI 0x00009304 ++#define CLK_LPTIM23_DISABLED 0x00009307 ++ ++#define CLK_LPTIM1_PCLK1 0x00009340 ++#define CLK_LPTIM1_PLL4P 0x00009341 ++#define CLK_LPTIM1_PLL3Q 0x00009342 ++#define CLK_LPTIM1_LSE 0x00009343 ++#define CLK_LPTIM1_LSI 0x00009344 ++#define CLK_LPTIM1_CKPER 0x00009345 ++#define CLK_LPTIM1_DISABLED 0x00009347 ++ ++/* define for st,pll /csg */ ++#define SSCG_MODE_CENTER_SPREAD 0 ++#define SSCG_MODE_DOWN_SPREAD 1 ++ ++/* define for st,drive */ ++#define LSEDRV_LOWEST 0 ++#define LSEDRV_MEDIUM_LOW 1 ++#define LSEDRV_MEDIUM_HIGH 2 ++#define LSEDRV_HIGHEST 3 ++ ++#endif +diff --git a/core/include/dt-bindings/etzpc/stm32-etzpc.h b/core/include/dt-bindings/etzpc/stm32-etzpc.h +new file mode 100644 +index 0000000..f498651 +--- /dev/null ++++ b/core/include/dt-bindings/etzpc/stm32-etzpc.h +@@ -0,0 +1,108 @@ ++/* ++ * Copyright (C) 2017, STMicroelectronics - All Rights Reserved ++ * ++ * SPDX-License-Identifier: GPL-2.0+ BSD-3-Clause ++ */ ++ ++#ifndef _DT_BINDINGS_STM32_ETZPC_H ++#define _DT_BINDINGS_STM32_ETZPC_H ++ ++/* define DECPROT modes */ ++#define DECPROT_S_RW 0x0 ++#define DECPROT_NS_R_S_W 0x1 ++#define DECPROT_MCU_ISOLATION 0x2 ++#define DECPROT_NS_RW 0x3 ++ ++/* define DECPROT lock */ ++#define DECPROT_UNLOCK 0x0 ++#define DECPROT_LOCK 0x1 ++ ++/* define ETZPC ID */ ++#define STM32MP1_ETZPC_STGENC_ID 0 ++#define STM32MP1_ETZPC_BKPSRAM_ID 1 ++#define STM32MP1_ETZPC_IWDG1_ID 2 ++#define STM32MP1_ETZPC_USART1_ID 3 ++#define STM32MP1_ETZPC_SPI6_ID 4 ++#define STM32MP1_ETZPC_I2C4_ID 5 ++#define STM32MP1_ETZPC_GPIOZ_ID 6 ++#define STM32MP1_ETZPC_RNG1_ID 7 ++#define STM32MP1_ETZPC_HASH1_ID 8 ++#define STM32MP1_ETZPC_CRYP1_ID 9 ++#define STM32MP1_ETZPC_DDRCTRL_ID 10 ++#define STM32MP1_ETZPC_DDRPHYC_ID 11 ++#define STM32MP1_ETZPC_I2C6_ID 12 ++#define STM32MP1_ETZPC_TIM2_ID 16 ++#define STM32MP1_ETZPC_TIM3_ID 17 ++#define STM32MP1_ETZPC_TIM4_ID 18 ++#define STM32MP1_ETZPC_TIM5_ID 19 ++#define STM32MP1_ETZPC_TIM6_ID 20 ++#define STM32MP1_ETZPC_TIM7_ID 21 ++#define STM32MP1_ETZPC_TIM12_ID 22 ++#define STM32MP1_ETZPC_TIM13_ID 23 ++#define STM32MP1_ETZPC_TIM14_ID 24 ++#define STM32MP1_ETZPC_LPTIM1_ID 25 ++#define STM32MP1_ETZPC_WWDG1_ID 26 ++#define STM32MP1_ETZPC_SPI2_ID 27 ++#define STM32MP1_ETZPC_SPI3_ID 28 ++#define STM32MP1_ETZPC_SPDIFRX_ID 29 ++#define STM32MP1_ETZPC_USART2_ID 30 ++#define STM32MP1_ETZPC_USART3_ID 31 ++#define STM32MP1_ETZPC_UART4_ID 32 ++#define STM32MP1_ETZPC_UART5_ID 33 ++#define STM32MP1_ETZPC_I2C1_ID 34 ++#define STM32MP1_ETZPC_I2C2_ID 35 ++#define STM32MP1_ETZPC_I2C3_ID 36 ++#define STM32MP1_ETZPC_I2C5_ID 37 ++#define STM32MP1_ETZPC_CEC_ID 38 ++#define STM32MP1_ETZPC_DAC_ID 39 ++#define STM32MP1_ETZPC_UART7_ID 40 ++#define STM32MP1_ETZPC_UART8_ID 41 ++#define STM32MP1_ETZPC_MDIOS_ID 44 ++#define STM32MP1_ETZPC_TIM1_ID 48 ++#define STM32MP1_ETZPC_TIM8_ID 49 ++#define STM32MP1_ETZPC_USART6_ID 51 ++#define STM32MP1_ETZPC_SPI1_ID 52 ++#define STM32MP1_ETZPC_SPI4_ID 53 ++#define STM32MP1_ETZPC_TIM15_ID 54 ++#define STM32MP1_ETZPC_TIM16_ID 55 ++#define STM32MP1_ETZPC_TIM17_ID 56 ++#define STM32MP1_ETZPC_SPI5_ID 57 ++#define STM32MP1_ETZPC_SAI1_ID 58 ++#define STM32MP1_ETZPC_SAI2_ID 59 ++#define STM32MP1_ETZPC_SAI3_ID 60 ++#define STM32MP1_ETZPC_DFSDM_ID 61 ++#define STM32MP1_ETZPC_TT_FDCAN_ID 62 ++#define STM32MP1_ETZPC_LPTIM2_ID 64 ++#define STM32MP1_ETZPC_LPTIM3_ID 65 ++#define STM32MP1_ETZPC_LPTIM4_ID 66 ++#define STM32MP1_ETZPC_LPTIM5_ID 67 ++#define STM32MP1_ETZPC_SAI4_ID 68 ++#define STM32MP1_ETZPC_VREFBUF_ID 69 ++#define STM32MP1_ETZPC_DCMI_ID 70 ++#define STM32MP1_ETZPC_CRC2_ID 71 ++#define STM32MP1_ETZPC_ADC_ID 72 ++#define STM32MP1_ETZPC_HASH2_ID 73 ++#define STM32MP1_ETZPC_RNG2_ID 74 ++#define STM32MP1_ETZPC_CRYP2_ID 75 ++#define STM32MP1_ETZPC_SRAM1_ID 80 ++#define STM32MP1_ETZPC_SRAM2_ID 81 ++#define STM32MP1_ETZPC_SRAM3_ID 82 ++#define STM32MP1_ETZPC_SRAM4_ID 83 ++#define STM32MP1_ETZPC_RETRAM_ID 84 ++#define STM32MP1_ETZPC_OTG_ID 85 ++#define STM32MP1_ETZPC_SDMMC3_ID 86 ++#define STM32MP1_ETZPC_DLYBSD3_ID 87 ++#define STM32MP1_ETZPC_DMA1_ID 88 ++#define STM32MP1_ETZPC_DMA2_ID 89 ++#define STM32MP1_ETZPC_DMAMUX_ID 90 ++#define STM32MP1_ETZPC_FMC_ID 91 ++#define STM32MP1_ETZPC_QSPI_ID 92 ++#define STM32MP1_ETZPC_DLYBQ_ID 93 ++#define STM32MP1_ETZPC_ETH_ID 94 ++ ++#define STM32MP1_ETZPC_MAX_ID 96 ++ ++#define DECPROT(ip_id, mode, lock) ((ip_id << 16) | (mode << 8) | lock) ++ ++#endif /* _DT_BINDINGS_STM32_ETZPC_H */ ++ +diff --git a/core/include/dt-bindings/interrupt-controller/arm-gic.h b/core/include/dt-bindings/interrupt-controller/arm-gic.h +new file mode 100644 +index 0000000..6863d5e +--- /dev/null ++++ b/core/include/dt-bindings/interrupt-controller/arm-gic.h +@@ -0,0 +1,21 @@ ++/* SPDX-License-Identifier: GPL-2.0 or BSD-3-Clause */ ++/* ++ * Copyright (C) 2018, STMicroelectronics - All Rights Reserved ++ */ ++ ++#ifndef _DT_BINDINGS_INTERRUPT_CONTROLLER_ARM_GIC_H ++#define _DT_BINDINGS_INTERRUPT_CONTROLLER_ARM_GIC_H ++ ++/* Interrupt specifier cell 0 */ ++ ++#define GIC_SPI 0 ++#define GIC_PPI 1 ++ ++#define IRQ_TYPE_NONE 0 ++#define IRQ_TYPE_EDGE_RISING 1 ++#define IRQ_TYPE_EDGE_FALLING 2 ++#define IRQ_TYPE_EDGE_BOTH (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING) ++#define IRQ_TYPE_LEVEL_HIGH 4 ++#define IRQ_TYPE_LEVEL_LOW 8 ++ ++#endif +diff --git a/core/include/dt-bindings/pinctrl/stm32-pinfunc.h b/core/include/dt-bindings/pinctrl/stm32-pinfunc.h +new file mode 100644 +index 0000000..7f6e4b9 +--- /dev/null ++++ b/core/include/dt-bindings/pinctrl/stm32-pinfunc.h +@@ -0,0 +1,41 @@ ++/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */ ++/* ++ * Copyright (C) STMicroelectronics 2017 - All Rights Reserved ++ * Author: Torgue Alexandre for STMicroelectronics. ++ */ ++ ++#ifndef _DT_BINDINGS_STM32_PINFUNC_H ++#define _DT_BINDINGS_STM32_PINFUNC_H ++ ++/* define PIN modes */ ++#define GPIO 0x0 ++#define AF0 0x1 ++#define AF1 0x2 ++#define AF2 0x3 ++#define AF3 0x4 ++#define AF4 0x5 ++#define AF5 0x6 ++#define AF6 0x7 ++#define AF7 0x8 ++#define AF8 0x9 ++#define AF9 0xa ++#define AF10 0xb ++#define AF11 0xc ++#define AF12 0xd ++#define AF13 0xe ++#define AF14 0xf ++#define AF15 0x10 ++#define ANALOG 0x11 ++ ++/* define Pins number*/ ++#define PIN_NO(port, line) (((port) - 'A') * 0x10 + (line)) ++ ++#define STM32_PINMUX(port, line, mode) (((PIN_NO(port, line)) << 8) | (mode)) ++ ++/* package information */ ++#define STM32MP157CAA 0x1 ++#define STM32MP157CAB 0x2 ++#define STM32MP157CAC 0x4 ++#define STM32MP157CAD 0x8 ++ ++#endif /* _DT_BINDINGS_STM32_PINFUNC_H */ +diff --git a/core/include/dt-bindings/power/stm32mp1-power.h b/core/include/dt-bindings/power/stm32mp1-power.h +new file mode 100644 +index 0000000..bfb7f78 +--- /dev/null ++++ b/core/include/dt-bindings/power/stm32mp1-power.h +@@ -0,0 +1,19 @@ ++/* SPDX-License-Identifier: GPL-2.0 or BSD-3-Clause */ ++/* ++ * Copyright (C) STMicroelectronics 2018 - All Rights Reserved ++ * Author: Yann Gautier for STMicroelectronics. ++ */ ++ ++#ifndef DT_BINDINGS_STM32MP1_POWER_H ++#define DT_BINDINGS_STM32MP1_POWER_H ++ ++#define STM32_PM_CSLEEP_RUN 0 ++#define STM32_PM_CSTOP_ALLOW_STOP 1 ++#define STM32_PM_CSTOP_ALLOW_LP_STOP 2 ++#define STM32_PM_CSTOP_ALLOW_LPLV_STOP 3 ++#define STM32_PM_CSTOP_ALLOW_STANDBY_DDR_SR 4 ++#define STM32_PM_CSTOP_ALLOW_STANDBY_DDR_OFF 5 ++#define STM32_PM_SHUTDOWN 6 ++#define STM32_PM_MAX_SOC_MODE 7 ++ ++#endif /* DT_BINDINGS_STM32MP1_POWER_H */ +diff --git a/core/include/dt-bindings/reset/stm32mp1-resets.h b/core/include/dt-bindings/reset/stm32mp1-resets.h +new file mode 100644 +index 0000000..f0c3aae +--- /dev/null ++++ b/core/include/dt-bindings/reset/stm32mp1-resets.h +@@ -0,0 +1,108 @@ ++/* SPDX-License-Identifier: GPL-2.0 or BSD-3-Clause */ ++/* ++ * Copyright (C) STMicroelectronics 2018 - All Rights Reserved ++ * Author: Gabriel Fernandez for STMicroelectronics. ++ */ ++ ++#ifndef _DT_BINDINGS_STM32MP1_RESET_H_ ++#define _DT_BINDINGS_STM32MP1_RESET_H_ ++ ++#define LTDC_R 3072 ++#define DSI_R 3076 ++#define DDRPERFM_R 3080 ++#define USBPHY_R 3088 ++#define SPI6_R 3136 ++#define I2C4_R 3138 ++#define I2C6_R 3139 ++#define USART1_R 3140 ++#define STGEN_R 3156 ++#define GPIOZ_R 3200 ++#define CRYP1_R 3204 ++#define HASH1_R 3205 ++#define RNG1_R 3206 ++#define AXIM_R 3216 ++#define GPU_R 3269 ++#define ETHMAC_R 3274 ++#define FMC_R 3276 ++#define QSPI_R 3278 ++#define SDMMC1_R 3280 ++#define SDMMC2_R 3281 ++#define CRC1_R 3284 ++#define USBH_R 3288 ++#define MDMA_R 3328 ++#define MCU_R 8225 ++#define TIM2_R 19456 ++#define TIM3_R 19457 ++#define TIM4_R 19458 ++#define TIM5_R 19459 ++#define TIM6_R 19460 ++#define TIM7_R 19461 ++#define TIM12_R 16462 ++#define TIM13_R 16463 ++#define TIM14_R 16464 ++#define LPTIM1_R 19465 ++#define SPI2_R 19467 ++#define SPI3_R 19468 ++#define USART2_R 19470 ++#define USART3_R 19471 ++#define UART4_R 19472 ++#define UART5_R 19473 ++#define UART7_R 19474 ++#define UART8_R 19475 ++#define I2C1_R 19477 ++#define I2C2_R 19478 ++#define I2C3_R 19479 ++#define I2C5_R 19480 ++#define SPDIF_R 19482 ++#define CEC_R 19483 ++#define DAC12_R 19485 ++#define MDIO_R 19847 ++#define TIM1_R 19520 ++#define TIM8_R 19521 ++#define TIM15_R 19522 ++#define TIM16_R 19523 ++#define TIM17_R 19524 ++#define SPI1_R 19528 ++#define SPI4_R 19529 ++#define SPI5_R 19530 ++#define USART6_R 19533 ++#define SAI1_R 19536 ++#define SAI2_R 19537 ++#define SAI3_R 19538 ++#define DFSDM_R 19540 ++#define FDCAN_R 19544 ++#define LPTIM2_R 19584 ++#define LPTIM3_R 19585 ++#define LPTIM4_R 19586 ++#define LPTIM5_R 19587 ++#define SAI4_R 19592 ++#define SYSCFG_R 19595 ++#define VREF_R 19597 ++#define TMPSENS_R 19600 ++#define PMBCTRL_R 19601 ++#define DMA1_R 19648 ++#define DMA2_R 19649 ++#define DMAMUX_R 19650 ++#define ADC12_R 19653 ++#define USBO_R 19656 ++#define SDMMC3_R 19664 ++#define CAMITF_R 19712 ++#define CRYP2_R 19716 ++#define HASH2_R 19717 ++#define RNG2_R 19718 ++#define CRC2_R 19719 ++#define HSEM_R 19723 ++#define MBOX_R 19724 ++#define GPIOA_R 19776 ++#define GPIOB_R 19777 ++#define GPIOC_R 19778 ++#define GPIOD_R 19779 ++#define GPIOE_R 19780 ++#define GPIOF_R 19781 ++#define GPIOG_R 19782 ++#define GPIOH_R 19783 ++#define GPIOI_R 19784 ++#define GPIOJ_R 19785 ++#define GPIOK_R 19786 ++ ++#endif /* _DT_BINDINGS_STM32MP1_RESET_H_ */ +diff --git a/core/include/kernel/interrupt.h b/core/include/kernel/interrupt.h +index d7b8abd..5a7e18d 100644 +--- a/core/include/kernel/interrupt.h ++++ b/core/include/kernel/interrupt.h +@@ -23,6 +23,11 @@ struct itr_ops { + uint8_t cpu_mask); + void (*set_affinity)(struct itr_chip *chip, size_t it, + uint8_t cpu_mask); ++#if !defined(CFG_ARM_GICV3) ++ uint8_t (*set_pmr)(struct itr_chip *chip, uint8_t mask); ++ uint8_t (*set_ipriority)(struct itr_chip *chip, size_t it, ++ uint8_t mask); ++#endif + }; + + enum itr_return { +@@ -57,4 +62,14 @@ void itr_raise_sgi(size_t it, uint8_t cpu_mask); + */ + void itr_set_affinity(size_t it, uint8_t cpu_mask); + ++/* ++ * Set the Priority Mask Regarding and return its previous value ++ */ ++uint8_t itr_set_pmr(uint8_t mask); ++ ++/* ++ * Set the targe tinterrupt priority mask and return its previous value ++ */ ++uint8_t itr_set_ipriority(size_t it, uint8_t mask); ++ + #endif /*__KERNEL_INTERRUPT_H*/ +diff --git a/core/kernel/console.c b/core/kernel/console.c +index 1f11503..98fde7c 100644 +--- a/core/kernel/console.c ++++ b/core/kernel/console.c +@@ -65,8 +65,13 @@ void configure_console_from_dt(void) + return; + + offs = fdt_path_offset(fdt, "/secure-chosen"); +- if (offs < 0) +- return; ++ if (offs < 0) { ++ /* Fallback to node /chosen */ ++ offs = fdt_path_offset(fdt, "/chosen"); ++ if (offs < 0) { ++ return; ++ } ++ } + prop = fdt_get_property(fdt, offs, "stdout-path", NULL); + if (!prop) { + /* +diff --git a/core/kernel/interrupt.c b/core/kernel/interrupt.c +index cff1f80..ce27aca 100644 +--- a/core/kernel/interrupt.c ++++ b/core/kernel/interrupt.c +@@ -78,3 +78,13 @@ void itr_set_affinity(size_t it, uint8_t cpu_mask) + { + itr_chip->ops->set_affinity(itr_chip, it, cpu_mask); + } ++ ++uint8_t itr_set_pmr(uint8_t mask) ++{ ++ return itr_chip->ops->set_pmr(itr_chip, mask); ++} ++ ++uint8_t itr_set_ipriority(size_t it, uint8_t mask) ++{ ++ return itr_chip->ops->set_ipriority(itr_chip, it, mask); ++} +diff --git a/core/lib/libfdt/fdt_ro.c b/core/lib/libfdt/fdt_ro.c +index 34110da..79b1b6d 100644 +--- a/core/lib/libfdt/fdt_ro.c ++++ b/core/lib/libfdt/fdt_ro.c +@@ -89,6 +89,32 @@ static int _fdt_string_eq(const void *fdt, int stroffset, + return (strlen(p) == len) && (memcmp(p, s, len) == 0); + } + ++uint32_t fdt_get_max_phandle(const void *fdt) ++{ ++ uint32_t max_phandle = 0; ++ int offset; ++ ++ for (offset = fdt_next_node(fdt, -1, NULL);; ++ offset = fdt_next_node(fdt, offset, NULL)) { ++ uint32_t phandle; ++ ++ if (offset == -FDT_ERR_NOTFOUND) ++ return max_phandle; ++ ++ if (offset < 0) ++ return (uint32_t)-1; ++ ++ phandle = fdt_get_phandle(fdt, offset); ++ if (phandle == (uint32_t)-1) ++ continue; ++ ++ if (phandle > max_phandle) ++ max_phandle = phandle; ++ } ++ ++ return 0; ++} ++ + int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size) + { + FDT_CHECK_HEADER(fdt); +@@ -155,9 +181,9 @@ int fdt_subnode_offset(const void *fdt, int parentoffset, + return fdt_subnode_offset_namelen(fdt, parentoffset, name, strlen(name)); + } + +-int fdt_path_offset(const void *fdt, const char *path) ++int fdt_path_offset_namelen(const void *fdt, const char *path, int namelen) + { +- const char *end = path + strlen(path); ++ const char *end = path + namelen; + const char *p = path; + int offset = 0; + +@@ -165,7 +191,7 @@ int fdt_path_offset(const void *fdt, const char *path) + + /* see if we have an alias */ + if (*path != '/') { +- const char *q = strchr(path, '/'); ++ const char *q = memchr(path, '/', end - p); + + if (!q) + q = end; +@@ -178,14 +204,15 @@ int fdt_path_offset(const void *fdt, const char *path) + p = q; + } + +- while (*p) { ++ while (p < end) { + const char *q; + +- while (*p == '/') ++ while (*p == '/') { + p++; +- if (! *p) +- return offset; +- q = strchr(p, '/'); ++ if (p == end) ++ return offset; ++ } ++ q = memchr(p, '/', end - p); + if (! q) + q = end; + +@@ -199,6 +226,11 @@ int fdt_path_offset(const void *fdt, const char *path) + return offset; + } + ++int fdt_path_offset(const void *fdt, const char *path) ++{ ++ return fdt_path_offset_namelen(fdt, path, strlen(path)); ++} ++ + const char *fdt_get_name(const void *fdt, int nodeoffset, int *len) + { + const struct fdt_node_header *nh = _fdt_offset_ptr(fdt, nodeoffset); +@@ -533,6 +565,106 @@ int fdt_stringlist_contains(const char *strlist, int listlen, const char *str) + return 0; + } + ++int fdt_stringlist_count(const void *fdt, int nodeoffset, const char *property) ++{ ++ const char *list, *end; ++ int length, count = 0; ++ ++ list = fdt_getprop(fdt, nodeoffset, property, &length); ++ if (!list) ++ return -length; ++ ++ end = list + length; ++ ++ while (list < end) { ++ length = strnlen(list, end - list) + 1; ++ ++ /* Abort if the last string isn't properly NUL-terminated. */ ++ if (list + length > end) ++ return -FDT_ERR_BADVALUE; ++ ++ list += length; ++ count++; ++ } ++ ++ return count; ++} ++ ++int fdt_stringlist_search(const void *fdt, int nodeoffset, const char *property, ++ const char *string) ++{ ++ int length, len, idx = 0; ++ const char *list, *end; ++ ++ list = fdt_getprop(fdt, nodeoffset, property, &length); ++ if (!list) ++ return -length; ++ ++ len = strlen(string) + 1; ++ end = list + length; ++ ++ while (list < end) { ++ length = strnlen(list, end - list) + 1; ++ ++ /* Abort if the last string isn't properly NUL-terminated. */ ++ if (list + length > end) ++ return -FDT_ERR_BADVALUE; ++ ++ if (length == len && memcmp(list, string, length) == 0) ++ return idx; ++ ++ list += length; ++ idx++; ++ } ++ ++ return -FDT_ERR_NOTFOUND; ++} ++ ++const char *fdt_stringlist_get(const void *fdt, int nodeoffset, ++ const char *property, int idx, ++ int *lenp) ++{ ++ const char *list, *end; ++ int length; ++ ++ list = fdt_getprop(fdt, nodeoffset, property, &length); ++ if (!list) { ++ if (lenp) ++ *lenp = length; ++ ++ return NULL; ++ } ++ ++ end = list + length; ++ ++ while (list < end) { ++ length = strnlen(list, end - list) + 1; ++ ++ /* Abort if the last string isn't properly NUL-terminated. */ ++ if (list + length > end) { ++ if (lenp) ++ *lenp = -FDT_ERR_BADVALUE; ++ ++ return NULL; ++ } ++ ++ if (idx == 0) { ++ if (lenp) ++ *lenp = length - 1; ++ ++ return list; ++ } ++ ++ list += length; ++ idx--; ++ } ++ ++ if (lenp) ++ *lenp = -FDT_ERR_NOTFOUND; ++ ++ return NULL; ++} ++ + int fdt_node_check_compatible(const void *fdt, int nodeoffset, + const char *compatible) + { +@@ -542,10 +674,8 @@ int fdt_node_check_compatible(const void *fdt, int nodeoffset, + prop = fdt_getprop(fdt, nodeoffset, "compatible", &len); + if (!prop) + return len; +- if (fdt_stringlist_contains(prop, len, compatible)) +- return 0; +- else +- return 1; ++ ++ return !fdt_stringlist_contains(prop, len, compatible); + } + + int fdt_node_offset_by_compatible(const void *fdt, int startoffset, +diff --git a/core/lib/libfdt/fdt_rw.c b/core/lib/libfdt/fdt_rw.c +index 1785a51..15897b7 100644 +--- a/core/lib/libfdt/fdt_rw.c ++++ b/core/lib/libfdt/fdt_rw.c +@@ -102,6 +102,8 @@ static int _fdt_splice(void *fdt, void *splicepoint, int oldlen, int newlen) + + if (((p + oldlen) < p) || ((p + oldlen) > end)) + return -FDT_ERR_BADOFFSET; ++ if ((p < (char *)fdt) || ((end - oldlen + newlen) < (char *)fdt)) ++ return -FDT_ERR_BADOFFSET; + if ((end - oldlen + newlen) > ((char *)fdt + fdt_totalsize(fdt))) + return -FDT_ERR_NOSPACE; + memmove(p + newlen, p + oldlen, end - p - oldlen); +@@ -190,17 +192,13 @@ int fdt_add_mem_rsv(void *fdt, uint64_t address, uint64_t size) + int fdt_del_mem_rsv(void *fdt, int n) + { + struct fdt_reserve_entry *re = _fdt_mem_rsv_w(fdt, n); +- int err; + + FDT_RW_CHECK_HEADER(fdt); + + if (n >= fdt_num_mem_rsv(fdt)) + return -FDT_ERR_NOTFOUND; + +- err = _fdt_splice_mem_rsv(fdt, re, 1, 0); +- if (err) +- return err; +- return 0; ++ return _fdt_splice_mem_rsv(fdt, re, 1, 0); + } + + static int _fdt_resize_property(void *fdt, int nodeoffset, const char *name, +@@ -286,8 +284,7 @@ int fdt_setprop(void *fdt, int nodeoffset, const char *name, + if (err) + return err; + +- if (len) +- memcpy(prop->data, val, len); ++ memcpy(prop->data, val, len); + return 0; + } + +diff --git a/core/lib/libfdt/fdt_wip.c b/core/lib/libfdt/fdt_wip.c +index c97c5f7..ee9df5c 100644 +--- a/core/lib/libfdt/fdt_wip.c ++++ b/core/lib/libfdt/fdt_wip.c +@@ -56,21 +56,42 @@ + + #include "libfdt_internal.h" + ++int fdt_setprop_inplace_namelen_partial(void *fdt, int nodeoffset, ++ const char *name, int namelen, ++ uint32_t idx, const void *val, ++ int len) ++{ ++ void *propval; ++ int proplen; ++ ++ propval = fdt_getprop_namelen_w(fdt, nodeoffset, name, namelen, ++ &proplen); ++ if (!propval) ++ return proplen; ++ ++ if (proplen < (len + idx)) ++ return -FDT_ERR_NOSPACE; ++ ++ memcpy((char *)propval + idx, val, len); ++ return 0; ++} ++ + int fdt_setprop_inplace(void *fdt, int nodeoffset, const char *name, + const void *val, int len) + { +- void *propval; ++ const void *propval; + int proplen; + +- propval = fdt_getprop_w(fdt, nodeoffset, name, &proplen); ++ propval = fdt_getprop(fdt, nodeoffset, name, &proplen); + if (! propval) + return proplen; + + if (proplen != len) + return -FDT_ERR_NOSPACE; + +- memcpy(propval, val, len); +- return 0; ++ return fdt_setprop_inplace_namelen_partial(fdt, nodeoffset, name, ++ strlen(name), 0, ++ val, len); + } + + static void _fdt_nop_region(void *start, int len) +diff --git a/core/lib/libfdt/include/fdt.h b/core/lib/libfdt/include/fdt.h +index 520bdcf..faa8046 100644 +--- a/core/lib/libfdt/include/fdt.h ++++ b/core/lib/libfdt/include/fdt.h +@@ -53,8 +53,16 @@ + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + ++/* ++ * Portions copyright (c) 2016-2017, ARM Limited and Contributors. ++ * All rights reserved. ++ */ ++ + #ifndef __ASSEMBLY__ + ++#include ++ ++ + struct fdt_header { + fdt32_t magic; /* magic word FDT_MAGIC */ + fdt32_t totalsize; /* total size of DT block */ +diff --git a/core/lib/libfdt/include/libfdt.h b/core/lib/libfdt/include/libfdt.h +index 01a9065..5ce9bfb 100644 +--- a/core/lib/libfdt/include/libfdt.h ++++ b/core/lib/libfdt/include/libfdt.h +@@ -52,6 +52,11 @@ + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + ++/* ++ * Portions copyright (c) 2016-2017, ARM Limited and Contributors. ++ * All rights reserved. ++ */ ++ + #include + #include + +@@ -122,7 +127,12 @@ + /* FDT_ERR_BADNCELLS: Device tree has a #address-cells, #size-cells + * or similar property with a bad format or value */ + +-#define FDT_ERR_MAX 14 ++#define FDT_ERR_BADVALUE 15 ++ /* FDT_ERR_BADVALUE: Device tree has a property with an unexpected ++ * value. For example: a property expected to contain a string list ++ * is not NUL-terminated within the length of its value. */ ++ ++#define FDT_ERR_MAX 15 + + /**********************************************************************/ + /* Low-level functions (you probably don't need these) */ +@@ -164,27 +174,55 @@ int fdt_first_subnode(const void *fdt, int offset); + */ + int fdt_next_subnode(const void *fdt, int offset); + ++/** ++ * fdt_for_each_subnode - iterate over all subnodes of a parent ++ * ++ * @node: child node (int, lvalue) ++ * @fdt: FDT blob (const void *) ++ * @parent: parent node (int) ++ * ++ * This is actually a wrapper around a for loop and would be used like so: ++ * ++ * fdt_for_each_subnode(node, fdt, parent) { ++ * Use node ++ * ... ++ * } ++ * ++ * if ((node < 0) && (node != -FDT_ERR_NOT_FOUND)) { ++ * Error handling ++ * } ++ * ++ * Note that this is implemented as a macro and @node is used as ++ * iterator in the loop. The parent variable be constant or even a ++ * literal. ++ * ++ */ ++#define fdt_for_each_subnode(node, fdt, parent) \ ++ for (node = fdt_first_subnode(fdt, parent); \ ++ node >= 0; \ ++ node = fdt_next_subnode(fdt, node)) ++ + /**********************************************************************/ + /* General functions */ + /**********************************************************************/ + + #define fdt_get_header(fdt, field) \ + (fdt32_to_cpu(((const struct fdt_header *)(fdt))->field)) +-#define fdt_magic(fdt) (fdt_get_header(fdt, magic)) ++#define fdt_magic(fdt) (fdt_get_header(fdt, magic)) + #define fdt_totalsize(fdt) (fdt_get_header(fdt, totalsize)) + #define fdt_off_dt_struct(fdt) (fdt_get_header(fdt, off_dt_struct)) + #define fdt_off_dt_strings(fdt) (fdt_get_header(fdt, off_dt_strings)) + #define fdt_off_mem_rsvmap(fdt) (fdt_get_header(fdt, off_mem_rsvmap)) + #define fdt_version(fdt) (fdt_get_header(fdt, version)) +-#define fdt_last_comp_version(fdt) (fdt_get_header(fdt, last_comp_version)) +-#define fdt_boot_cpuid_phys(fdt) (fdt_get_header(fdt, boot_cpuid_phys)) +-#define fdt_size_dt_strings(fdt) (fdt_get_header(fdt, size_dt_strings)) ++#define fdt_last_comp_version(fdt) (fdt_get_header(fdt, last_comp_version)) ++#define fdt_boot_cpuid_phys(fdt) (fdt_get_header(fdt, boot_cpuid_phys)) ++#define fdt_size_dt_strings(fdt) (fdt_get_header(fdt, size_dt_strings)) + #define fdt_size_dt_struct(fdt) (fdt_get_header(fdt, size_dt_struct)) + + #define __fdt_set_hdr(name) \ + static inline void fdt_set_##name(void *fdt, uint32_t val) \ + { \ +- struct fdt_header *fdth = (struct fdt_header*)fdt; \ ++ struct fdt_header *fdth = (struct fdt_header *)fdt; \ + fdth->name = cpu_to_fdt32(val); \ + } + __fdt_set_hdr(magic) +@@ -255,6 +293,21 @@ int fdt_move(const void *fdt, void *buf, int bufsize); + const char *fdt_string(const void *fdt, int stroffset); + + /** ++ * fdt_get_max_phandle - retrieves the highest phandle in a tree ++ * @fdt: pointer to the device tree blob ++ * ++ * fdt_get_max_phandle retrieves the highest phandle in the given ++ * device tree. This will ignore badly formatted phandles, or phandles ++ * with a value of 0 or -1. ++ * ++ * returns: ++ * the highest phandle on success ++ * 0, if no phandle was found in the device tree ++ * -1, if an error occurred ++ */ ++uint32_t fdt_get_max_phandle(const void *fdt); ++ ++/** + * fdt_num_mem_rsv - retrieve the number of memory reserve map entries + * @fdt: pointer to the device tree blob + * +@@ -314,8 +367,9 @@ int fdt_subnode_offset_namelen(const void *fdt, int parentoffset, + * returns: + * structure block offset of the requested subnode (>=0), on success + * -FDT_ERR_NOTFOUND, if the requested subnode does not exist +- * -FDT_ERR_BADOFFSET, if parentoffset did not point to an FDT_BEGIN_NODE tag +- * -FDT_ERR_BADMAGIC, ++ * -FDT_ERR_BADOFFSET, if parentoffset did not point to an FDT_BEGIN_NODE ++ * tag ++ * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, +@@ -324,6 +378,17 @@ int fdt_subnode_offset_namelen(const void *fdt, int parentoffset, + int fdt_subnode_offset(const void *fdt, int parentoffset, const char *name); + + /** ++ * fdt_path_offset_namelen - find a tree node by its full path ++ * @fdt: pointer to the device tree blob ++ * @path: full path of the node to locate ++ * @namelen: number of characters of path to consider ++ * ++ * Identical to fdt_path_offset(), but only consider the first namelen ++ * characters of path as the path name. ++ */ ++int fdt_path_offset_namelen(const void *fdt, const char *path, int namelen); ++ ++/** + * fdt_path_offset - find a tree node by its full path + * @fdt: pointer to the device tree blob + * @path: full path of the node to locate +@@ -336,7 +401,8 @@ int fdt_subnode_offset(const void *fdt, int parentoffset, const char *name); + * address). + * + * returns: +- * structure block offset of the node with the requested path (>=0), on success ++ * structure block offset of the node with the requested path (>=0), on ++ * success + * -FDT_ERR_BADPATH, given path does not begin with '/' or is invalid + * -FDT_ERR_NOTFOUND, if the requested node does not exist + * -FDT_ERR_BADMAGIC, +@@ -360,10 +426,12 @@ int fdt_path_offset(const void *fdt, const char *path); + * + * returns: + * pointer to the node's name, on success +- * If lenp is non-NULL, *lenp contains the length of that name (>=0) ++ * If lenp is non-NULL, *lenp contains the length of that name ++ * (>=0) + * NULL, on error + * if lenp is non-NULL *lenp contains an error code (<0): +- * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag ++ * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE ++ * tag + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, standard meanings +@@ -412,6 +480,33 @@ int fdt_first_property_offset(const void *fdt, int nodeoffset); + int fdt_next_property_offset(const void *fdt, int offset); + + /** ++ * fdt_for_each_property_offset - iterate over all properties of a node ++ * ++ * @property_offset: property offset (int, lvalue) ++ * @fdt: FDT blob (const void *) ++ * @node: node offset (int) ++ * ++ * This is actually a wrapper around a for loop and would be used like so: ++ * ++ * fdt_for_each_property_offset(property, fdt, node) { ++ * Use property ++ * ... ++ * } ++ * ++ * if ((property < 0) && (property != -FDT_ERR_NOT_FOUND)) { ++ * Error handling ++ * } ++ * ++ * Note that this is implemented as a macro and property is used as ++ * iterator in the loop. The node variable can be constant or even a ++ * literal. ++ */ ++#define fdt_for_each_property_offset(property, fdt, node) \ ++ for (property = fdt_first_property_offset(fdt, node); \ ++ property >= 0; \ ++ property = fdt_next_property_offset(fdt, property)) ++ ++/** + * fdt_get_property_by_offset - retrieve the property at a given offset + * @fdt: pointer to the device tree blob + * @offset: offset of the property to retrieve +@@ -447,8 +542,8 @@ const struct fdt_property *fdt_get_property_by_offset(const void *fdt, + * @namelen: number of characters of name to consider + * @lenp: pointer to an integer variable (will be overwritten) or NULL + * +- * Identical to fdt_get_property_namelen(), but only examine the first +- * namelen characters of name for matching the property name. ++ * Identical to fdt_get_property(), but only examine the first namelen ++ * characters of name for matching the property name. + */ + const struct fdt_property *fdt_get_property_namelen(const void *fdt, + int nodeoffset, +@@ -475,7 +570,8 @@ const struct fdt_property *fdt_get_property_namelen(const void *fdt, + * NULL, on error + * if lenp is non-NULL, *lenp contains an error code (<0): + * -FDT_ERR_NOTFOUND, node does not have named property +- * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag ++ * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE ++ * tag + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, +@@ -539,6 +635,13 @@ const void *fdt_getprop_by_offset(const void *fdt, int offset, + */ + const void *fdt_getprop_namelen(const void *fdt, int nodeoffset, + const char *name, int namelen, int *lenp); ++static inline void *fdt_getprop_namelen_w(void *fdt, int nodeoffset, ++ const char *name, int namelen, ++ int *lenp) ++{ ++ return (void *)(uintptr_t)fdt_getprop_namelen(fdt, nodeoffset, name, ++ namelen, lenp); ++} + + /** + * fdt_getprop - retrieve the value of a given property +@@ -560,7 +663,8 @@ const void *fdt_getprop_namelen(const void *fdt, int nodeoffset, + * NULL, on error + * if lenp is non-NULL, *lenp contains an error code (<0): + * -FDT_ERR_NOTFOUND, node does not have named property +- * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag ++ * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE ++ * tag + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, +@@ -632,7 +736,7 @@ const char *fdt_get_alias(const void *fdt, const char *name); + * 0, on success + * buf contains the absolute path of the node at + * nodeoffset, as a NUL-terminated string. +- * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag ++ * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag + * -FDT_ERR_NOSPACE, the path of the given node is longer than (bufsize-1) + * characters and will not fit in the given buffer. + * -FDT_ERR_BADMAGIC, +@@ -662,11 +766,11 @@ int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen); + * structure from the start to nodeoffset. + * + * returns: +- + * structure block offset of the node at node offset's ancestor + * of depth supernodedepth (>=0), on success +- * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag +-* -FDT_ERR_NOTFOUND, supernodedepth was greater than the depth of nodeoffset ++ * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag ++ * -FDT_ERR_NOTFOUND, supernodedepth was greater than the depth of ++ * nodeoffset + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, +@@ -688,7 +792,7 @@ int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset, + * + * returns: + * depth of the node at nodeoffset (>=0), on success +- * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag ++ * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, +@@ -711,7 +815,7 @@ int fdt_node_depth(const void *fdt, int nodeoffset); + * returns: + * structure block offset of the parent of the node at nodeoffset + * (>=0), on success +- * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag ++ * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, +@@ -751,7 +855,7 @@ int fdt_parent_offset(const void *fdt, int nodeoffset); + * on success + * -FDT_ERR_NOTFOUND, no node matching the criterion exists in the + * tree after startoffset +- * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag ++ * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, +@@ -798,7 +902,7 @@ int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle); + * 1, if the node has a 'compatible' property, but it does not list + * the given string + * -FDT_ERR_NOTFOUND, if the given node has no 'compatible' property +- * -FDT_ERR_BADOFFSET, if nodeoffset does not refer to a BEGIN_NODE tag ++ * -FDT_ERR_BADOFFSET, if nodeoffset does not refer to a BEGIN_NODE tag + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, +@@ -835,7 +939,7 @@ int fdt_node_check_compatible(const void *fdt, int nodeoffset, + * on success + * -FDT_ERR_NOTFOUND, no node matching the criterion exists in the + * tree after startoffset +- * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag ++ * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, +@@ -858,6 +962,68 @@ int fdt_node_offset_by_compatible(const void *fdt, int startoffset, + */ + int fdt_stringlist_contains(const char *strlist, int listlen, const char *str); + ++/** ++ * fdt_stringlist_count - count the number of strings in a string list ++ * @fdt: pointer to the device tree blob ++ * @nodeoffset: offset of a tree node ++ * @property: name of the property containing the string list ++ * @return: ++ * the number of strings in the given property ++ * -FDT_ERR_BADVALUE if the property value is not NUL-terminated ++ * -FDT_ERR_NOTFOUND if the property does not exist ++ */ ++int fdt_stringlist_count(const void *fdt, int nodeoffset, const char *property); ++ ++/** ++ * fdt_stringlist_search - find a string in a string list and return its index ++ * @fdt: pointer to the device tree blob ++ * @nodeoffset: offset of a tree node ++ * @property: name of the property containing the string list ++ * @string: string to look up in the string list ++ * ++ * Note that it is possible for this function to succeed on property values ++ * that are not NUL-terminated. That's because the function will stop after ++ * finding the first occurrence of @string. This can for example happen with ++ * small-valued cell properties, such as #address-cells, when searching for ++ * the empty string. ++ * ++ * @return: ++ * the index of the string in the list of strings ++ * -FDT_ERR_BADVALUE if the property value is not NUL-terminated ++ * -FDT_ERR_NOTFOUND if the property does not exist or does not contain ++ * the given string ++ */ ++int fdt_stringlist_search(const void *fdt, int nodeoffset, const char *property, ++ const char *string); ++ ++/** ++ * fdt_stringlist_get() - obtain the string at a given index in a string list ++ * @fdt: pointer to the device tree blob ++ * @nodeoffset: offset of a tree node ++ * @property: name of the property containing the string list ++ * @index: index of the string to return ++ * @lenp: return location for the string length or an error code on failure ++ * ++ * Note that this will successfully extract strings from properties with ++ * non-NUL-terminated values. For example on small-valued cell properties ++ * this function will return the empty string. ++ * ++ * If non-NULL, the length of the string (on success) or a negative error-code ++ * (on failure) will be stored in the integer pointer to by lenp. ++ * ++ * @return: ++ * A pointer to the string at the given index in the string list or NULL on ++ * failure. On success the length of the string will be stored in the memory ++ * location pointed to by the lenp parameter, if non-NULL. On failure one of ++ * the following negative error codes will be returned in the lenp parameter ++ * (if non-NULL): ++ * -FDT_ERR_BADVALUE if the property value is not NUL-terminated ++ * -FDT_ERR_NOTFOUND if the property does not exist ++ */ ++const char *fdt_stringlist_get(const void *fdt, int nodeoffset, ++ const char *property, int index, ++ int *lenp); ++ + /**********************************************************************/ + /* Read-only functions (addressing related) */ + /**********************************************************************/ +@@ -883,7 +1049,8 @@ int fdt_stringlist_contains(const char *strlist, int listlen, const char *str); + * returns: + * 0 <= n < FDT_MAX_NCELLS, on success + * 2, if the node has no #address-cells property +- * -FDT_ERR_BADNCELLS, if the node has a badly formatted or invalid #address-cells property ++ * -FDT_ERR_BADNCELLS, if the node has a badly formatted or invalid ++ * #address-cells property + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, +@@ -903,7 +1070,8 @@ int fdt_address_cells(const void *fdt, int nodeoffset); + * returns: + * 0 <= n < FDT_MAX_NCELLS, on success + * 2, if the node has no #address-cells property +- * -FDT_ERR_BADNCELLS, if the node has a badly formatted or invalid #size-cells property ++ * -FDT_ERR_BADNCELLS, if the node has a badly formatted or invalid ++ * #size-cells property + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, +@@ -918,6 +1086,27 @@ int fdt_size_cells(const void *fdt, int nodeoffset); + /**********************************************************************/ + + /** ++ * fdt_setprop_inplace_namelen_partial - change a property's value, ++ * but not its size ++ * @fdt: pointer to the device tree blob ++ * @nodeoffset: offset of the node whose property to change ++ * @name: name of the property to change ++ * @namelen: number of characters of name to consider ++ * @idx: index of the property to change in the array ++ * @val: pointer to data to replace the property value with ++ * @len: length of the property value ++ * ++ * Identical to fdt_setprop_inplace(), but modifies the given property ++ * starting from the given index, and using only the first characters ++ * of the name. It is useful when you want to manipulate only one value of ++ * an array and you have a string that doesn't end with \0. ++ */ ++int fdt_setprop_inplace_namelen_partial(void *fdt, int nodeoffset, ++ const char *name, int namelen, ++ uint32_t idx, const void *val, ++ int len); ++ ++/** + * fdt_setprop_inplace - change a property's value, but not its size + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose property to change +@@ -1527,9 +1716,11 @@ int fdt_add_subnode_namelen(void *fdt, int parentoffset, + * change the offsets of some existing nodes. + + * returns: +- * structure block offset of the created nodeequested subnode (>=0), on success ++ * structure block offset of the created nodeequested subnode (>=0), on ++ * success + * -FDT_ERR_NOTFOUND, if the requested subnode does not exist +- * -FDT_ERR_BADOFFSET, if parentoffset did not point to an FDT_BEGIN_NODE tag ++ * -FDT_ERR_BADOFFSET, if parentoffset did not point to an FDT_BEGIN_NODE ++ * tag + * -FDT_ERR_EXISTS, if the node at parentoffset already has a subnode of + * the given name + * -FDT_ERR_NOSPACE, if there is insufficient free space in the +diff --git a/core/secure_dt.mk b/core/secure_dt.mk +new file mode 100644 +index 0000000..16ea741 +--- /dev/null ++++ b/core/secure_dt.mk +@@ -0,0 +1,107 @@ ++# ++# Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. ++# ++# SPDX-License-Identifier: BSD-3-Clause ++# ++ ++DTC_FLAGS += -I dts -O dtb ++DTC := dtc ++ ++define MAKE_PREREQ_DIR ++ifneq (${1},${2}) ++${1} : ++ @mkdir -p "${1}" ++ ++endif ++endef ++ ++# Convert device tree source file names to matching blobs ++# $(1) = input dts ++define SOURCES_TO_DTBS ++ $(notdir $(patsubst %.dts,%.dtb,$(filter %.dts,$(1)))) ++endef ++ ++# MAKE_FDT_DIRS macro creates the prerequisite directories that host the ++# FDT binaries ++# $(1) = output directory ++# $(2) = input dts ++define MAKE_FDT_DIRS ++ $(eval DTBS := $(addprefix $(1)/,$(call SOURCES_TO_DTBS,$(2)))) ++ $(eval TEMP_DTB_DIRS := $(sort $(dir ${DTBS}))) ++ # The $(dir ) function leaves a trailing / on the directory names ++ # Rip off the / to match directory names with make rule targets. ++ $(eval DTB_DIRS := $(patsubst %/,%,$(TEMP_DTB_DIRS))) ++ ++$(eval $(foreach objd,${DTB_DIRS},$(call MAKE_PREREQ_DIR,${objd},${out-dir}))) ++ ++fdt_dirs: ${DTB_DIRS} ++endef ++ ++# MAKE_DTB generate the Flattened device tree binary ++# $(1) = output directory ++# $(2) = input dts ++define MAKE_DTB ++ ++# List of DTB file(s) to generate, based on DTS file basename list ++$(eval DTBOBJ := $(addprefix $(1)/,$(call SOURCES_TO_DTBS,$(2)))) ++# List of the pre-compiled DTS file(s) ++$(eval DTSPRE := $(addprefix $(1)/,$(patsubst %.dts,%.pre.dts,$(notdir $(2))))) ++# Dependencies of the pre-compiled DTS file(s) on its source and included files ++$(eval DTSDEP := $(patsubst %.dtb,%.o.d,$(DTBOBJ))) ++# Dependencies of the DT compilation on its pre-compiled DTS ++$(eval DTBDEP := $(patsubst %.dtb,%.d,$(DTBOBJ))) ++ ++$(DTBOBJ): $(2) $(filter-out %.d,$(MAKEFILE_LIST)) | fdt_dirs ++ @echo " CPP $$<" ++ $(eval DTBS := $(addprefix $(1)/,$(call SOURCES_TO_DTBS,$(2)))) ++ @$(CPP$(sm)) $$(CPPFLAGS) -Icore/include/ -x assembler-with-cpp \ ++ -E -ffreestanding -MT $(DTBS) -MMD -MF $(DTSDEP) -o $(DTSPRE) $$< ++ @echo " DTC $$<" ++ @$(DTC) $$(DTC_FLAGS) -d $(DTBDEP) -o $$@ $(DTSPRE) ++ ++-include $(DTBDEP) ++-include $(DTSDEP) ++endef ++ ++# MAKE_DTBS builds flattened device tree sources ++# $(1) = output directory ++# $(2) = list of flattened device tree source files ++define MAKE_DTBS ++ $(eval DTBOBJS := $(filter %.dts,$(2))) ++ $(eval REMAIN := $(filter-out %.dts,$(2))) ++ $(and $(REMAIN),$(error FDT_SOURCES contain non-DTS files: $(REMAIN))) ++ $(eval $(foreach obj,$(DTBOBJS),$(call MAKE_DTB,$(1),$(obj)))) ++ $(eval $(call MAKE_FDT_DIRS,$(1),$(2))) ++ ++dtbs: $(DTBS) ++all: dtbs ++endef ++ ++# Generating the DTB from the DTS and integrating into OP-TEE core. ++# ++# CFG_SECURE_DT provides the DTS base name. It is looked up as file ++# name as $(CFG_SECURE_DT).dts from the platform sub directory fdts/. ++# ++# Build precompiles $(CFG_SECURE_DT).dts to resolve pre compilation features ++# (build directive, file inclusion, ...) then generates $(CFG_SECURE_DT).dtb. ++# ++# If CFG_STATIC_SECURE_DT is enabled, $(CFG_SECURE_DT).dtb content is wrapped ++# into C source file builtin_secure_dtb.c that defines the DTB byte array ++# CFG_STATIC_SECURE_DT expects. ++ ++DTB_FILE_NAME := $(CFG_SECURE_DT).dtb ++FDT_SOURCES := $(addprefix $(arch-dir)/fdts/, $(CFG_SECURE_DT).dts) ++ ++DTC_FLAGS += -Wno-unit_address_vs_reg ++ ++$(eval $(call MAKE_DTBS,$(out-dir)/core/fdts,$(FDT_SOURCES))) ++ ++ifeq ($(CFG_STATIC_SECURE_DT),y) ++gensrcs-y += builtin_secure_dtb ++produce-builtin_secure_dtb = fdts/builtin_secure_dtb.c ++depends-builtin_secure_dtb = $(DTBOBJ) scripts/ta_bin_to_c.py ++recipe-builtin_secure_dtb = scripts/bin_to_c.py --dtb $(DTBOBJ) \ ++ --label static_secure_dtb \ ++ --out $(out-dir)/core/fdts/builtin_secure_dtb.c ++cleanfiles += $(out-dir)/core/fdts/builtin_secure_dtb.c ++endif +diff --git a/core/sub.mk b/core/sub.mk +index 9aee1b4..3119b58 100644 +--- a/core/sub.mk ++++ b/core/sub.mk +@@ -26,3 +26,10 @@ $(foreach f, $(EARLY_TA_PATHS), $(eval $(call process_early_ta,$(f)))) + $(foreach f, $(CFG_IN_TREE_EARLY_TAS), $(eval $(call \ + process_early_ta,$(out-dir)/ta/$(f).stripped.elf))) + endif ++ ++# ++# Secure device tree support ++# ++ifneq ($(CFG_SECURE_DT),) ++include core/secure_dt.mk ++endif +diff --git a/lib/libutils/ext/include/util.h b/lib/libutils/ext/include/util.h +index 4561758..2509b07 100644 +--- a/lib/libutils/ext/include/util.h ++++ b/lib/libutils/ext/include/util.h +@@ -49,9 +49,16 @@ + + /* Round down the even multiple of size, size has to be a multiple of 2 */ + #define ROUNDDOWN(v, size) ((v) & ~((__typeof__(v))(size) - 1)) ++ ++/* Unsigned integer division with nearest rounding variant */ ++#define UDIV_ROUND_NEAREST(x, y) \ ++ (__extension__ ({ __typeof__(x) _x = (x); \ ++ __typeof__(y) _y = (y); \ ++ (_x + (_y / 2)) / _y; })) + #else + #define ROUNDUP(x, y) ((((x) + (y) - 1) / (y)) * (y)) + #define ROUNDDOWN(x, y) (((x) / (y)) * (y)) ++#define UDIV_ROUND_NEAREST(x, y) (((x) + ((y) / 2)) / (y)) + #endif + + /* x has to be of an unsigned type */ +diff --git a/mk/config.mk b/mk/config.mk +index e0c050a..21ba469 100644 +--- a/mk/config.mk ++++ b/mk/config.mk +@@ -236,10 +236,25 @@ CFG_CORE_SANITIZE_UNDEFINED ?= n + CFG_CORE_SANITIZE_KADDRESS ?= n + + # Device Tree support +-# When enabled, the TEE _start function expects to find the address of a +-# Device Tree Blob (DTB) in register r2. The DT parsing code relies on +-# libfdt. Currently only used to add the optee node and a reserved-memory +-# node for shared memory. ++# ++# - When CFG_DT is enabled, the libfdt is embedded in the core. It allows ++# to parse a device tree. ++# - When CFG_STATIC_SECURE_DT is enabled, TEE core embeds a statically linked ++# device tree blob. ++# - When CFG_SECURE_DT is defined, it defines the base name of the device tree ++# source file from which a device tree blob is generated at core build. ++# ++# If CFG_DT is enabled and CFG_STATIC_SECURE_DT is disabled, the TEE _start ++# function expects to find the address of a Device Tree Blob (DTB) in ++# register r2 and is currently only used to add the optee node and a ++# reserved-memory node for shared memory. ++ifneq ($(CFG_SECURE_DT),) ++$(call force,CFG_STATIC_SECURE_DT,y) ++endif ++CFG_STATIC_SECURE_DT ?= n ++ifeq ($(CFG_STATIC_SECURE_DT),y) ++$(call force,CFG_DT,y) ++endif + CFG_DT ?= n + + # Maximum size of the Device Tree Blob, has to be large enough to allow +diff --git a/scripts/bin_to_c.py b/scripts/bin_to_c.py +new file mode 100755 +index 0000000..6fe7772 +--- /dev/null ++++ b/scripts/bin_to_c.py +@@ -0,0 +1,58 @@ ++#!/usr/bin/env python ++# SPDX-License-Identifier: BSD-2-Clause ++# ++# Copyright (c) 2018, Linaro Limited ++# ++ ++import argparse ++import array ++import os ++import re ++ ++def get_args(): ++ ++ parser = argparse.ArgumentParser(description='Converts a binary ' ++ 'file into C source file defining binary data as a' ++ 'constant byte array.') ++ ++ parser.add_argument('--dtb', required=True, ++ help='Path to the input binary file') ++ ++ parser.add_argument('--label', required=True, ++ help='Label for the generated table in the C source file.') ++ ++ parser.add_argument('--out', required=True, ++ help='Path of the output C file') ++ ++ return parser.parse_args() ++ ++def main(): ++ ++ args = get_args(); ++ ++ with open(args.dtb, 'rb') as indata: ++ bytes = indata.read() ++ size = len(bytes) ++ ++ f = open(args.out, 'w') ++ f.write('/* Generated from ' + args.dtb + ' by ' + ++ os.path.basename(__file__) + ' */\n\n') ++ f.write('#include \n'); ++ f.write('#include \n'); ++ f.write('__extension__ const uint8_t ' + args.label + '[] ' + ++ ' __aligned(__alignof__(uint64_t)) = {\n') ++ i = 0 ++ while i < size: ++ if i % 8 == 0: ++ f.write('\t\t'); ++ f.write('0x' + '{:02x}'.format(ord(bytes[i])) + ',') ++ i = i + 1 ++ if i % 8 == 0 or i == size: ++ f.write('\n') ++ else: ++ f.write(' ') ++ f.write('};\n'); ++ f.close() ++ ++if __name__ == "__main__": ++ main() +-- +2.7.4 + diff --git a/recipes-security/optee/optee-os/README.HOW_TO.txt b/recipes-security/optee/optee-os/README.HOW_TO.txt new file mode 100644 index 0000000..210bcba --- /dev/null +++ b/recipes-security/optee/optee-os/README.HOW_TO.txt @@ -0,0 +1,147 @@ +Compilation of Optee-os (Trusted Execution Environment): +1. Pre-requisite +2. Initialise cross-compilation via SDK +3. Prepare optee-os source code +4. Management of optee-os source code +5. Compile optee-os source code +6. Update software on board + +1. Pre-requisite: +----------------- +OpenSTLinux SDK must be installed. + +For optee-os build you need to install: +- Wand python and/or python crypto package + Ubuntu: sudo apt-get install python-wand python-crypto python-pycryptopp + Fedora: sudo yum install python-wand python-crypto +- git: + Ubuntu: sudo apt-get install git-core gitk + Fedora: sudo yum install git + +If you have never configured you git configuration: + $> git config --global user.name "your_name" + $> git config --global user.email "your_email@example.com" + +2. Initialise cross-compilation via SDK: +--------------------------------------- + Source SDK environment: + $> source /environment-setup-cortexa7t2hf-neon-vfpv4-openstlinux_weston-linux-gnueabi + + To verify if your cross-compilation environment have put in place: + $> set | grep CROSS + CROSS_COMPILE=arm-openstlinux_weston-linux-gnueabi- + +Warning: the environment are valid only on the shell session where you have + sourced the sdk environment. + +3. Prepare optee-os source: +------------------------ +If you have the tarball and the list of patch then you must extract the +tarball and apply the patch. + $> tar xfz .tar.gz + or + $> tar xfj .tar.bz2 + or + $> tar xfJ .tar.xz + $> cd +NB: if there is no git management on source code and you would like to have a git management +on the code see section 4 [Management of optee-os source code] + if there is some patch, please apply it on source code + $> for p in `ls -1 /*.patch`; do patch -p1 < $p; done + +4. Management of optee-os source code: +----------------------------------- +If you like to have a better management of change made on optee-os source, you +can use git: + $> cd + $> test -d .git || git init . && git add . && git commit -m "optee-ossource code" && git gc + $> git checkout -b WORKING + $> for p in `ls -1 /*.patch`; do git am $p; done + +MANDATORY: You must update sources + $> cd + $> chmod 755 scripts/bin_to_c.py + +NB: you can use directly the source from the community: + URL: git://github.com/OP-TEE/optee_os.git + Branch: ##GIT_BRANCH## + Revision: ##GIT_SRCREV## + + $> git clone git://github.com/OP-TEE/optee_os.git + $> cd + $> git checkout -b WORKING ##GIT_SRCREV## + $> for p in `ls -1 /*.patch`; do git am $p; done + +MANDATORY: You must update sources + $> cd + $> chmod 755 scripts/bin_to_c.py + +5. Build optee-os source code: +-------------------------------- +To compile optee-os source code + $> cd + $> make -f $PWD/../Makefile.sdk +or for a specific config : + $> make -f $PWD/../Makefile.sdk CFG_SECURE_DT=stm32mp157c-ev1 + +By default, binaries are located in $PWD/../build + +6. Update software on board: +---------------------------- +6.1. partitioning of binaries: +----------------------------- +Using the above command, the OP-TEE provides 3 binary files which MUST +be loaded in their respective partition as listed below: +- "tee-header-*-optee.stm32" in "teeh" partition +- "tee-pageable-*-optee.stm32" in "teed" partition +- "tee-pager-*-optee.stm32" in "teex" partition + +6.2. Update via SDCARD: +----------------------- +Copy each binary to its dedicated partition, on SDCARD/USB disk +the OP-TEE partitions are the partitions 4/5/6: + - SDCARD: /dev/mmcblkXp4 /dev/mmcblkXp5 /dev/mmcblkXp6 + (where X is the instance number) + - SDCARD via USB reader: /dev/sdX4 /dev/sdX5 /dev/sdX6 + (where X is the instance identifier) +So, for each binary: +$> dd if= of=/dev/ bs=1M conv=fdatasync + +6.3. Update via USB mass storage on U-boot: +------------------------------------------- +* Plug the SDCARD on Board. +* Start the board and stop on U-boot shell: + Hit any key to stop autoboot: 0 + STM32MP> +* plug an USB cable between the PC and the board via USB OTG port. +* On U-Boot shell, call the USB mass storage functionnality: + STM32MP> ums 0 mmc 0 + + ums + ex.: +For SDCARD: ums 0 mmc 0 +For USB disk: ums 0 usb 0 + +* Follow section 6.2 to load the "tee-*-optee.stm32" image files in the target + partitions /dev/sd. + + + +FAQ: Partitions identification + +To find the partition associated to a specific label, connect the +SDCARD to your PC or run on target U-boot 'ums' command +and list /dev/disk/by-partlabel/ content, i.e: + + $> ls -l /dev/disk/by-partlabel/ + total 0 + lrwxrwxrwx 1 root root 15 Jan 23 19:11 bootfs -> ../../mmcblk0p7 + lrwxrwxrwx 1 root root 15 Jan 23 19:11 fsbl1 -> ../../mmcblk0p1 # FSBL (TF-A) + lrwxrwxrwx 1 root root 15 Jan 23 19:11 fsbl2 -> ../../mmcblk0p2 # FSBL backup (TF-A backup – same content as FSBL) + lrwxrwxrwx 1 root root 15 Jan 23 19:11 rootfs -> ../../mmcblk0p9 + lrwxrwxrwx 1 root root 15 Jan 23 19:11 ssbl -> ../../mmcblk0p3 # SSBL (U-Boot) + lrwxrwxrwx 1 root root 15 Jan 23 19:11 teed -> ../../mmcblk0p5 # TEED (OP-TEE tee-pageable) + lrwxrwxrwx 1 root root 15 Jan 23 19:11 teeh -> ../../mmcblk0p4 # TEEH (OP-TEE tee-header) + lrwxrwxrwx 1 root root 15 Jan 23 19:11 teex -> ../../mmcblk0p6 # TEEX (OP-TEE tee-pager) + lrwxrwxrwx 1 root root 16 Jan 23 19:11 userfs -> ../../mmcblk0p10 + lrwxrwxrwx 1 root root 15 Jan 23 19:11 vendorfs -> ../../mmcblk0p8