diff --git a/recipes-bsp/trusted-firmware-a/tf-a-stm32mp-common.inc b/recipes-bsp/trusted-firmware-a/tf-a-stm32mp-common.inc new file mode 100644 index 0000000..8b6e702 --- /dev/null +++ b/recipes-bsp/trusted-firmware-a/tf-a-stm32mp-common.inc @@ -0,0 +1,261 @@ +COMPATIBLE_MACHINE = "(stm32mpcommon)" + +PACKAGE_ARCH = "${MACHINE_ARCH}" + +FILESEXTRAPATHS_prepend := "${THISDIR}/tf-a-stm32mp:" + +inherit deploy + +B = "${WORKDIR}/build" +# Configure build dir for externalsrc class usage through devtool +EXTERNALSRC_BUILD_pn-${PN} = "${WORKDIR}/build" + +DEPENDS += "dtc-native" + +# Define default TF-A namings +TF_A_BASENAME ?= "tf-a" +TF_A_SUFFIX ?= "stm32" + +# Output the ELF generated +ELF_DEBUG_ENABLE ?= "" +TF_A_ELF_SUFFIX = "elf" + +BL1_NAME ?= "bl1/bl1" +BL1_ELF = "${BL1_NAME}.${TF_A_ELF_SUFFIX}" +BL1_BASENAME = "${@os.path.basename(d.getVar("BL1_NAME"))}" + +BL2_NAME ?= "bl2/bl2" +BL2_ELF = "${BL2_NAME}.${TF_A_ELF_SUFFIX}" +BL2_BASENAME = "${@os.path.basename(d.getVar("BL2_NAME"))}" + +BL32_NAME ?= "bl32/bl32" +BL32_ELF = "${BL32_NAME}.${TF_A_ELF_SUFFIX}" +BL32_BASENAME = "${@os.path.basename(d.getVar("BL32_NAME"))}" + +# Extra make settings +EXTRA_OEMAKE = 'CROSS_COMPILE=${TARGET_PREFIX}' +EXTRA_OEMAKE += 'PLAT=stm32mp1' +EXTRA_OEMAKE += 'ARCH=aarch32' +EXTRA_OEMAKE += 'ARM_ARCH_MAJOR=7' + +# Debug support +EXTRA_OEMAKE += 'DEBUG=1' +EXTRA_OEMAKE += "LOG_LEVEL=40" + +# Set default TF-A config +TF_A_CONFIG ?= "" + +# ----------------------------------------------- +# Enable use of work-shared folder +STAGING_TFA_DIR = "${TMPDIR}/work-shared/${MACHINE}/tfa-source" +# Make sure to move ${S} to STAGING_TFA_DIR. We can't just +# create the symlink in advance as the git fetcher can't cope with +# the symlink. +do_unpack[cleandirs] += " ${S} ${STAGING_TFA_DIR}" +do_clean[cleandirs] += " ${S} ${STAGING_TFA_DIR}" +base_do_unpack_append () { + # Specific part to update devtool-source class + if bb.data.inherits_class('devtool-source', d): + # We don't want to move the source to STAGING_TFA_DIR here + if d.getVar('STAGING_TFA_DIR', d): + d.setVar('STAGING_TFA_DIR', '${S}') + + # Copy/Paste from kernel class with adaptation to TFA var + s = d.getVar("S") + if s[-1] == '/': + # drop trailing slash, so that os.symlink(tfasrc, s) doesn't use s as directory name and fail + s=s[:-1] + tfasrc = d.getVar("STAGING_TFA_DIR") + if s != tfasrc: + bb.utils.mkdirhier(tfasrc) + bb.utils.remove(tfasrc, recurse=True) + if d.getVar("EXTERNALSRC"): + # With EXTERNALSRC S will not be wiped so we can symlink to it + os.symlink(s, tfasrc) + else: + import shutil + shutil.move(s, tfasrc) + os.symlink(tfasrc, s) +} + + +# Manage to export any specific setting for defined configs +python tfaconfig_env () { + if d.getVar('TF_A_CONFIG'): + try: + f = open( ("%s/tfaconfig_env" % d.getVar('T')), 'w') + for config in d.getVar('TF_A_CONFIG').split(): + f.write( "export TF_A_CONFIG_%s=\"%s\"\n" % (config, d.getVar(('TF_A_CONFIG_' + config))) ) + f.close() + except: + pass +} +do_compile[prefuncs] += "tfaconfig_env" + +do_compile() { + . ${T}/tfaconfig_env + + unset LDFLAGS + unset CFLAGS + unset CPPFLAGS + + for config in ${TF_A_CONFIG}; do + # Get any specific EXTRA_OEMAKE for current config + eval local add_extraoemake=\"\$TF_A_CONFIG_${config}\" + if [ -n "${TF_A_DEVICETREE}" ]; then + for dt in ${TF_A_DEVICETREE}; do + oe_runmake -C ${S} DTB_FILE_NAME=${dt}.dtb BUILD_PLAT=${B}/${config} ${add_extraoemake} + cp ${B}/${config}/${TF_A_BASENAME}-${dt}.${TF_A_SUFFIX} ${B}/${config}/${TF_A_BASENAME}-${dt}-${config}.${TF_A_SUFFIX} + done + else + oe_runmake -C ${S} BUILD_PLAT=${B}/${config} ${add_extraoemake} + fi + done +} + +do_deploy() { + install -d ${DEPLOYDIR} + + for config in ${TF_A_CONFIG}; do + if [ -n "${TF_A_DEVICETREE}" ]; then + for dt in ${TF_A_DEVICETREE}; do + install -m 644 ${B}/${config}/${TF_A_BASENAME}-${dt}-${config}.${TF_A_SUFFIX} ${DEPLOYDIR} + done + else + # Get tf-a binary basename to copy + tf_a_binary_basename=$(find ${B}/${config} -name "${TF_A_BASENAME}-*.${TF_A_SUFFIX}" -exec basename {} \; | sed 's|\.'"${TF_A_SUFFIX}"'||g') + install -m 644 ${B}/${config}/${tf_a_binary_basename}.${TF_A_SUFFIX} ${DEPLOYDIR}/${tf_a_binary_basename}-${config}.${TF_A_SUFFIX} + fi + done + + if [ -n "${ELF_DEBUG_ENABLE}" ]; then + for config in ${TF_A_CONFIG}; do + if [ -f ${B}/${config}/${BL1_ELF} ]; then + install -m 644 ${B}/${config}/${BL1_ELF} ${DEPLOYDIR}/${TF_A_BASENAME}-${BL1_BASENAME}-${config}.${TF_A_ELF_SUFFIX} + fi + if [ -f ${B}/${config}/${BL2_ELF} ]; then + install -m 644 ${B}/${config}/${BL2_ELF} ${DEPLOYDIR}/${TF_A_BASENAME}-${BL2_BASENAME}-${config}.${TF_A_ELF_SUFFIX} + fi + if [ -f ${B}/${config}/${BL32_ELF} ]; then + install -m 644 ${B}/${config}/${BL32_ELF} ${DEPLOYDIR}/${TF_A_BASENAME}-${BL32_BASENAME}-${config}.${TF_A_ELF_SUFFIX} + fi + done + fi +} +addtask deploy before do_build after do_compile + + +# ----------------------------------------------- +# Archiver +inherit archiver +ARCHIVER_MODE[src] = "${@'original' if d.getVar('ST_ARCHIVER_ENABLE') == '1' else ''}" + +inherit archiver_stm32mp_clean +SRC_URI =+ " file://README.HOW_TO.txt " + +archiver_create_makefile_for_sdk() { + . ${T}/tfaconfig_env + + # Init internal var for tfa_config_oemake: should be 'config,extraoemake' + for config in ${TF_A_CONFIG}; do + tf_a_config_oemake="${tf_a_config_oemake} ${config},$(eval echo \$TF_A_CONFIG_${config})" + done + + 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 "CC=" >> ${ARCHIVER_OUTDIR}/Makefile.sdk + echo "CPP=" >> ${ARCHIVER_OUTDIR}/Makefile.sdk + echo "AS=" >> ${ARCHIVER_OUTDIR}/Makefile.sdk + echo "AR=" >> ${ARCHIVER_OUTDIR}/Makefile.sdk + echo "LD=" >> ${ARCHIVER_OUTDIR}/Makefile.sdk + echo "NM=" >> ${ARCHIVER_OUTDIR}/Makefile.sdk + echo "" >> ${ARCHIVER_OUTDIR}/Makefile.sdk + + echo "LOCAL_PATH=\$(PWD)" >> ${ARCHIVER_OUTDIR}/Makefile.sdk + echo "" >> ${ARCHIVER_OUTDIR}/Makefile.sdk + + echo "EXTRA_OEMAKE=${EXTRA_OEMAKE}" >> ${ARCHIVER_OUTDIR}/Makefile.sdk + echo "" >> ${ARCHIVER_OUTDIR}/Makefile.sdk + + # Set default config + echo "ELF_DEBUG_ENABLE ?= ${ELF_DEBUG_ENABLE}" >> ${ARCHIVER_OUTDIR}/Makefile.sdk + echo "TF_A_CONFIG ?= ${TF_A_CONFIG}" >> ${ARCHIVER_OUTDIR}/Makefile.sdk + echo "" >> ${ARCHIVER_OUTDIR}/Makefile.sdk + # Set specific OEMAKE config + echo "TF_A_CONFIG_OEMAKE = ${tf_a_config_oemake}" >> ${ARCHIVER_OUTDIR}/Makefile.sdk + + # Set default TFA_DEVICETREE with configured TF_A_DEVICETREE + if [ -n "${TF_A_DEVICETREE}" ]; then + echo "TFA_DEVICETREE ?= ${TF_A_DEVICETREE}" >> ${ARCHIVER_OUTDIR}/Makefile.sdk + else + echo "TFA_DEVICETREE ?=" >> ${ARCHIVER_OUTDIR}/Makefile.sdk + fi + echo "" >> ${ARCHIVER_OUTDIR}/Makefile.sdk + + echo "help:" >> ${ARCHIVER_OUTDIR}/Makefile.sdk + echo " @echo" >> ${ARCHIVER_OUTDIR}/Makefile.sdk + echo " @echo \"Available targets:\"" >> ${ARCHIVER_OUTDIR}/Makefile.sdk + echo " @echo \" all : build TF-A binaries for defined config(s)\"" >> ${ARCHIVER_OUTDIR}/Makefile.sdk + echo " @echo \" clean : clean build directories from generated files\"" >> ${ARCHIVER_OUTDIR}/Makefile.sdk + echo " @echo" >> ${ARCHIVER_OUTDIR}/Makefile.sdk + echo " @echo \"TF-A configuration:\"" >> ${ARCHIVER_OUTDIR}/Makefile.sdk + echo " @echo \" TF_A_CONFIG = \$(TF_A_CONFIG)\"" >> ${ARCHIVER_OUTDIR}/Makefile.sdk + echo " @echo \" TFA_DEVICETREE = \$(TFA_DEVICETREE)\"" >> ${ARCHIVER_OUTDIR}/Makefile.sdk + echo " @echo \" ELF_DEBUG_ENABLE = '\$(ELF_DEBUG_ENABLE)' ('1' to export elf files)\"" >> ${ARCHIVER_OUTDIR}/Makefile.sdk + echo " @echo" >> ${ARCHIVER_OUTDIR}/Makefile.sdk + echo "" >> ${ARCHIVER_OUTDIR}/Makefile.sdk + + echo "all: tf" >> ${ARCHIVER_OUTDIR}/Makefile.sdk + echo "" >> ${ARCHIVER_OUTDIR}/Makefile.sdk + + echo "host_tools:" >> ${ARCHIVER_OUTDIR}/Makefile.sdk + echo " @\$(MAKE) --no-print-directory -C \$(LOCAL_PATH)/tools/stm32image" >> ${ARCHIVER_OUTDIR}/Makefile.sdk + echo "" >> ${ARCHIVER_OUTDIR}/Makefile.sdk + + echo "tf: host_tools" >> ${ARCHIVER_OUTDIR}/Makefile.sdk + echo " for config in \$(TF_A_CONFIG) ; do \\" >> ${ARCHIVER_OUTDIR}/Makefile.sdk + # Init any extraoemake + echo " add_extraoemake= ; \\" >> ${ARCHIVER_OUTDIR}/Makefile.sdk + echo " for fullconfig in \$(TF_A_CONFIG_OEMAKE) ; do \\" >> ${ARCHIVER_OUTDIR}/Makefile.sdk + echo " extraconfig=\$\$(echo \$\$fullconfig | cut -d',' -f1) ; \\" >> ${ARCHIVER_OUTDIR}/Makefile.sdk + echo " if [ \"\$\$extraconfig\" = \"\$\$config\" ]; then \\" >> ${ARCHIVER_OUTDIR}/Makefile.sdk + echo " add_extraoemake=\$\$(echo \$\$fullconfig | cut -d',' -f2) ; \\" >> ${ARCHIVER_OUTDIR}/Makefile.sdk + echo " fi ; \\" >> ${ARCHIVER_OUTDIR}/Makefile.sdk + echo " done ; \\" >> ${ARCHIVER_OUTDIR}/Makefile.sdk + echo " mkdir -p \$(LOCAL_PATH)/../build/\$\$config ; \\" >> ${ARCHIVER_OUTDIR}/Makefile.sdk + echo " if test -n \"\$(TFA_DEVICETREE)\" ; then \\" >> ${ARCHIVER_OUTDIR}/Makefile.sdk + echo " for dt in \$(TFA_DEVICETREE) ; do \\" >> ${ARCHIVER_OUTDIR}/Makefile.sdk + echo " \$(MAKE) \$(EXTRA_OEMAKE) -C \$(LOCAL_PATH) DTB_FILE_NAME=\$\$dt.dtb BUILD_PLAT=\$(LOCAL_PATH)/../build/\$\$config \$\$add_extraoemake ; \\" >> ${ARCHIVER_OUTDIR}/Makefile.sdk + # Copy binary file with explicit name + echo " cp -f \$(LOCAL_PATH)/../build/\$\$config/${TF_A_BASENAME}-\$\$dt.${TF_A_SUFFIX} \$(LOCAL_PATH)/../build/\$\$config/${TF_A_BASENAME}-\$\$dt-\$\$config.${TF_A_SUFFIX} ; \\" >> ${ARCHIVER_OUTDIR}/Makefile.sdk + echo " done ; \\" >> ${ARCHIVER_OUTDIR}/Makefile.sdk + echo " else \\" >> ${ARCHIVER_OUTDIR}/Makefile.sdk + echo " \$(MAKE) \$(EXTRA_OEMAKE) -C \$(LOCAL_PATH) BUILD_PLAT=\$(LOCAL_PATH)/../build/\$\$config \$\$add_extraoemake; \\" >> ${ARCHIVER_OUTDIR}/Makefile.sdk + # Copy binary file with explicit name + echo " tf_version=\$\$(find \$(LOCAL_PATH)/../build/\$\$config -name ${TF_A_BASENAME}*.${TF_A_SUFFIX} -exec basename {} \; | sed \"s/\.${TF_A_SUFFIX}//\") ; \\" >> ${ARCHIVER_OUTDIR}/Makefile.sdk + echo " cp -f \$(LOCAL_PATH)/../build/\$\$config/\$\$tf_version.${TF_A_SUFFIX} \$(LOCAL_PATH)/../build/\$\$config/\$\$tf_version-\$\$config.${TF_A_SUFFIX} ; \\" >> ${ARCHIVER_OUTDIR}/Makefile.sdk + echo " fi ; \\" >> ${ARCHIVER_OUTDIR}/Makefile.sdk + # Copy elf files with explicit name + echo " if [ \"\$(ELF_DEBUG_ENABLE)\" = \"1\" ] ; then \\" >> ${ARCHIVER_OUTDIR}/Makefile.sdk + echo " if [ -f \$(LOCAL_PATH)/../build/\$\$config/${BL1_ELF} ] ; then \\" >> ${ARCHIVER_OUTDIR}/Makefile.sdk + echo " cp -f \$(LOCAL_PATH)/../build/\$\$config/${BL1_ELF} \$(LOCAL_PATH)/../build/\$\$config/${TF_A_BASENAME}-${BL1_BASENAME}-\$\$config.${TF_A_ELF_SUFFIX} ; \\" >> ${ARCHIVER_OUTDIR}/Makefile.sdk + echo " fi ; \\" >> ${ARCHIVER_OUTDIR}/Makefile.sdk + echo " if [ -f \$(LOCAL_PATH)/../build/\$\$config/${BL2_ELF} ] ; then \\" >> ${ARCHIVER_OUTDIR}/Makefile.sdk + echo " cp -f \$(LOCAL_PATH)/../build/\$\$config/${BL2_ELF} \$(LOCAL_PATH)/../build/\$\$config/${TF_A_BASENAME}-${BL2_BASENAME}-\$\$config.${TF_A_ELF_SUFFIX} ; \\" >> ${ARCHIVER_OUTDIR}/Makefile.sdk + echo " fi ; \\" >> ${ARCHIVER_OUTDIR}/Makefile.sdk + echo " if [ -f \$(LOCAL_PATH)/../build/\$\$config/${BL32_ELF} ] ; then \\" >> ${ARCHIVER_OUTDIR}/Makefile.sdk + echo " cp -f \$(LOCAL_PATH)/../build/\$\$config/${BL32_ELF} \$(LOCAL_PATH)/../build/\$\$config/${TF_A_BASENAME}-${BL32_BASENAME}-\$\$config.${TF_A_ELF_SUFFIX} ; \\" >> ${ARCHIVER_OUTDIR}/Makefile.sdk + echo " fi ; \\" >> ${ARCHIVER_OUTDIR}/Makefile.sdk + echo " fi ; \\" >> ${ARCHIVER_OUTDIR}/Makefile.sdk + echo " done" >> ${ARCHIVER_OUTDIR}/Makefile.sdk + echo "" >> ${ARCHIVER_OUTDIR}/Makefile.sdk + + echo "clean:" >> ${ARCHIVER_OUTDIR}/Makefile.sdk + echo " @for config in \$(TF_A_CONFIG) ; do \\" >> ${ARCHIVER_OUTDIR}/Makefile.sdk + echo " rm -rf \$(LOCAL_PATH)/../build/\$\$config ; \\" >> ${ARCHIVER_OUTDIR}/Makefile.sdk + echo " done" >> ${ARCHIVER_OUTDIR}/Makefile.sdk +} +do_ar_original[prefuncs] += "tfaconfig_env archiver_create_makefile_for_sdk" diff --git a/recipes-bsp/trusted-firmware-a/tf-a-stm32mp/0001-st-update-r1.patch b/recipes-bsp/trusted-firmware-a/tf-a-stm32mp/0001-st-update-r1.patch new file mode 100644 index 0000000..ae24495 --- /dev/null +++ b/recipes-bsp/trusted-firmware-a/tf-a-stm32mp/0001-st-update-r1.patch @@ -0,0 +1,45590 @@ +From b378eb77ad6177d7bd5cb1a5befc4b0c52f70e2c Mon Sep 17 00:00:00 2001 +From: christophe montaud +Date: Tue, 29 Jan 2019 18:16:44 +0100 +Subject: [PATCH] st update r1 + +--- + .checkpatch.conf | 18 + + Makefile | 56 +- + bl2/aarch32/bl2_arch_setup.c | 1 + + bl2/aarch32/bl2_el3_entrypoint.S | 4 + + bl2/aarch32/bl2_el3_exceptions.S | 9 + + bl2/aarch32/bl2_entrypoint.S | 9 + + bl2/bl2_image_load_v2.c | 14 +- + bl2/bl2_private.h | 3 + + bl2u/aarch32/bl2u_entrypoint.S | 9 + + bl32/sp_min/aarch32/entrypoint.S | 9 + + common/aarch32/debug.S | 54 +- + docs/devicetree/bindings/arm/secure.txt | 53 + + docs/devicetree/bindings/clock/st,stm32mp1-rcc.txt | 324 +++ + docs/devicetree/bindings/i2c/i2c-stm32.txt | 54 + + docs/devicetree/bindings/mmc/mmci.txt | 72 + + docs/devicetree/bindings/mmc/st,stm32-sdmmc2.txt | 22 + + docs/devicetree/bindings/power/st,stm32mp1-pwr.txt | 42 + + docs/devicetree/bindings/power/st,stpmic1.txt | 132 ++ + docs/devicetree/bindings/reset/st,stm32mp1-rcc.txt | 6 + + docs/devicetree/bindings/rng/st,stm32-rng.txt | 23 + + docs/devicetree/bindings/serial/st,stm32-usart.txt | 88 + + docs/devicetree/bindings/soc/st,stm32-etzpc.txt | 56 + + docs/devicetree/bindings/soc/st,stm32-romem.txt | 31 + + docs/devicetree/bindings/soc/st,stm32-stgen.txt | 18 + + docs/devicetree/bindings/soc/st,stm32-tamp.txt | 22 + + .../devicetree/bindings/watchdog/st,stm32-iwdg.txt | 28 + + docs/plat/stm32mp1.rst | 16 + + docs/porting-guide.rst | 44 +- + drivers/arm/pl011/aarch32/pl011_console.S | 139 +- + drivers/arm/pl011/aarch64/pl011_console.S | 3 +- + drivers/arm/tzc/tzc400.c | 129 ++ + drivers/cadence/uart/aarch64/cdns_console.S | 4 +- + drivers/console/aarch32/console.S | 105 +- + drivers/console/aarch32/deprecated_console.S | 112 + + drivers/console/aarch32/multi_console.S | 318 +++ + drivers/console/aarch64/skeleton_console.S | 9 +- + .../coreboot/cbmem_console/aarch64/cbmem_console.S | 3 +- + drivers/io/io_block.c | 8 +- + drivers/io/io_memmap.c | 5 +- + drivers/io/io_semihosting.c | 4 +- + drivers/io/io_storage.c | 2 +- + drivers/mmc/mmc.c | 23 +- + drivers/partition/gpt.c | 10 +- + drivers/partition/partition.c | 2 +- + drivers/st/bsec/bsec.c | 911 ++++++++ + drivers/st/clk/stm32mp1_clk.c | 2247 +++++++++++++++----- + drivers/st/clk/stm32mp1_clkfunc.c | 211 +- + drivers/st/clk/stm32mp_clkfunc.c | 307 +++ + drivers/st/ddr/stm32mp1_ddr.c | 484 +++-- + drivers/st/ddr/stm32mp1_ddr_helpers.c | 510 ++++- + drivers/st/ddr/stm32mp1_ram.c | 194 +- + drivers/st/etzpc/etzpc.c | 310 +++ + drivers/st/gpio/stm32_gpio.c | 267 ++- + drivers/st/hash/hash_sec.c | 369 ++++ + drivers/st/i2c/stm32_i2c.c | 1371 ++++++++++++ + drivers/st/io/io_mmc.c | 134 ++ + drivers/st/io/io_programmer_st_usb.c | 379 ++++ + drivers/st/io/io_stm32image.c | 381 ++++ + drivers/st/iwdg/stm32_iwdg.c | 289 +++ + drivers/st/mmc/stm32_sdmmc2.c | 752 +++++++ + drivers/st/nand/io_nand.c | 228 ++ + drivers/st/nand/nand.c | 1548 ++++++++++++++ + drivers/st/pmic/stm32_i2c.c | 851 -------- + drivers/st/pmic/stm32mp1_pmic.c | 346 --- + drivers/st/pmic/stm32mp_pmic.c | 522 +++++ + drivers/st/pmic/stpmic1.c | 817 +++++++ + drivers/st/pmic/stpmu1.c | 600 ------ + drivers/st/qspi/io_qspi.c | 349 +++ + drivers/st/reset/stm32mp1_reset.c | 64 +- + drivers/st/rng/stm32_rng.c | 191 ++ + drivers/st/rtc/stm32_rtc.c | 499 +++++ + drivers/st/tamper/stm32_tamp.c | 375 ++++ + drivers/st/timer/stm32_timer.c | 297 +++ + drivers/st/uart/aarch32/stm32_console.S | 151 +- + drivers/st/uart/io_programmer_uart.c | 597 ++++++ + drivers/st/uart/stm32mp1xx_hal_uart.c | 799 +++++++ + drivers/st/usb_dwc2/usb_dwc2.c | 858 ++++++++ + drivers/ti/uart/aarch64/16550_console.S | 3 +- + fdts/stm32mp15-ddr.dtsi | 2 +- + fdts/stm32mp15-ddr3-1x4Gb-1066-binG.dtsi | 121 ++ + fdts/stm32mp15-ddr3-2x4Gb-1066-binG.dtsi | 19 +- + fdts/stm32mp157-pinctrl.dtsi | 154 +- + fdts/stm32mp157a-dk1.dts | 464 ++++ + fdts/stm32mp157c-dk2.dts | 16 + + fdts/stm32mp157c-ed1.dts | 342 ++- + fdts/stm32mp157c-ev1.dts | 52 +- + fdts/stm32mp157c-security.dtsi | 71 + + fdts/stm32mp157c.dtsi | 215 +- + fdts/stm32mp157caa-pinctrl.dtsi | 8 +- + fdts/stm32mp157cab-pinctrl.dtsi | 62 + + fdts/stm32mp157cac-pinctrl.dtsi | 78 + + fdts/stm32mp157cad-pinctrl.dtsi | 62 + + include/common/aarch32/console_macros.S | 84 + + include/common/aarch64/console_macros.S | 46 +- + include/common/tbbr/tbbr_img_def.h | 8 +- + include/drivers/arm/tzc400.h | 4 + + include/drivers/io/io_driver.h | 2 +- + include/drivers/io/io_storage.h | 8 +- + include/drivers/st/bsec.h | 205 ++ + include/drivers/st/etzpc.h | 32 + + include/drivers/st/hash_sec.h | 113 + + include/drivers/st/io_mmc.h | 14 + + include/drivers/st/io_nand.h | 19 + + include/drivers/st/io_programmer.h | 51 + + include/drivers/st/io_programmer_st_usb.h | 20 + + include/drivers/st/io_qspi.h | 92 + + include/drivers/st/io_stm32image.h | 32 + + include/drivers/st/io_uart.h | 12 + + include/drivers/st/nand.h | 252 +++ + include/drivers/st/stm32_console.h | 34 + + include/drivers/st/stm32_gpio.h | 68 +- + include/drivers/st/stm32_hal_hash_reg.h | 136 ++ + include/drivers/st/stm32_i2c.h | 303 +-- + include/drivers/st/stm32_iwdg.h | 20 + + include/drivers/st/stm32_rng.h | 13 + + include/drivers/st/stm32_rtc.h | 79 + + include/drivers/st/stm32_sdmmc2.h | 31 + + include/drivers/st/stm32_tamp.h | 163 ++ + include/drivers/st/stm32_timer.h | 21 + + include/drivers/st/stm32_uart_regs.h | 199 ++ + include/drivers/st/stm32mp1_clk.h | 71 +- + include/drivers/st/stm32mp1_clkfunc.h | 18 +- + include/drivers/st/stm32mp1_ddr.h | 13 +- + include/drivers/st/stm32mp1_ddr_helpers.h | 14 +- + include/drivers/st/stm32mp1_ddr_regs.h | 15 +- + include/drivers/st/stm32mp1_pmic.h | 18 - + include/drivers/st/stm32mp1_pwr.h | 31 +- + include/drivers/st/stm32mp1_ram.h | 6 +- + include/drivers/st/stm32mp1_rcc.h | 138 +- + include/drivers/st/stm32mp1_reset.h | 15 - + include/drivers/st/stm32mp1xx_hal.h | 203 ++ + include/drivers/st/stm32mp1xx_hal_uart.h | 1586 ++++++++++++++ + include/drivers/st/stm32mp1xx_hal_uart_ex.h | 87 + + include/drivers/st/stm32mp_clkfunc.h | 28 + + include/drivers/st/stm32mp_pmic.h | 24 + + include/drivers/st/stm32mp_reset.h | 15 + + include/drivers/st/stpmic1.h | 173 ++ + include/drivers/st/stpmu1.h | 141 -- + include/drivers/st/usb_dwc2.h | 443 ++++ + include/dt-bindings/interrupt-controller/arm-gic.h | 21 + + include/dt-bindings/pinctrl/stm32-pinfunc.h | 6 + + include/dt-bindings/power/stm32mp1-power.h | 19 + + include/dt-bindings/soc/st,stm32-etzpc.h | 107 + + include/lib/aarch32/arch.h | 14 + + include/lib/aarch32/arch_helpers.h | 3 + + include/lib/cpus/aarch32/cortex_a9.h | 5 + + include/lib/optee_utils.h | 1 + + include/lib/psci/psci.h | 8 +- + include/lib/usb/usb_core.h | 352 +++ + include/lib/usb/usb_st_dfu.h | 115 + + include/lib/utils.h | 29 +- + include/lib/utils_def.h | 20 +- + include/lib/xlat_tables/xlat_tables_v2_helpers.h | 41 +- + include/plat/common/platform.h | 5 + + lib/compiler-rt/builtins/int_lib.h | 13 +- + lib/compiler-rt/builtins/lshrdi3.c | 45 + + lib/compiler-rt/compiler-rt.mk | 3 +- + lib/libfdt/fdt_ro.c | 2 +- + lib/optee/optee_utils.c | 30 + + lib/usb/usb_core.c | 732 +++++++ + lib/usb/usb_st_dfu.c | 865 ++++++++ + lib/xlat_tables/aarch32/xlat_tables.c | 9 + + lib/xlat_tables/aarch64/xlat_tables.c | 4 + + lib/xlat_tables/xlat_tables_common.c | 18 + + lib/xlat_tables_v2/xlat_tables_core.c | 7 +- + make_helpers/build_macros.mk | 15 +- + make_helpers/defaults.mk | 3 + + plat/arm/common/aarch32/arm_helpers.S | 6 +- + plat/arm/common/arm_common.mk | 4 +- + plat/arm/common/sp_min/arm_sp_min_setup.c | 7 +- + plat/common/aarch32/crash_console_helpers.S | 92 + + plat/common/aarch32/plat_sp_min_common.c | 4 + + plat/common/aarch32/platform_helpers.S | 38 + + plat/common/aarch64/crash_console_helpers.S | 92 + + plat/common/aarch64/platform_helpers.S | 4 + + plat/common/plat_log_common.c | 1 + + plat/imx/common/lpuart_console.S | 3 +- + plat/layerscape/common/aarch64/ls_console.S | 3 +- + plat/st/common/bl2_io_storage.c | 773 +++++++ + plat/st/common/include/stm32mp_auth.h | 15 + + plat/st/common/include/stm32mp_common.h | 49 + + plat/st/common/include/stm32mp_dt.h | 54 + + plat/st/common/include/stm32mp_shres_helpers.h | 86 + + plat/st/common/stm32mp_auth.c | 121 ++ + plat/st/common/stm32mp_common.c | 168 ++ + plat/st/common/stm32mp_dt.c | 559 +++++ + plat/st/common/stm32mp_shres_helpers.c | 71 + + plat/st/stm32mp1/bl2_io_storage.c | 193 -- + plat/st/stm32mp1/bl2_plat_setup.c | 447 +++- + plat/st/stm32mp1/include/boot_api.h | 411 +++- + plat/st/stm32mp1/include/platform_def.h | 64 +- + plat/st/stm32mp1/include/stm32mp1_context.h | 18 +- + plat/st/stm32mp1/include/stm32mp1_dbgmcu.h | 26 + + plat/st/stm32mp1/include/stm32mp1_dt.h | 41 - + plat/st/stm32mp1/include/stm32mp1_low_power.h | 19 + + plat/st/stm32mp1/include/stm32mp1_power_config.h | 28 + + plat/st/stm32mp1/include/stm32mp1_private.h | 30 +- + .../stm32mp1/include/stm32mp1_shared_resources.h | 83 + + plat/st/stm32mp1/include/stm32mp1_smc.h | 68 + + plat/st/stm32mp1/include/stm32mp1_usb_desc.h | 55 + + plat/st/stm32mp1/include/usb_ctx.h | 17 + + plat/st/stm32mp1/plat_bl2_mem_params_desc.c | 49 +- + plat/st/stm32mp1/plat_image_load.c | 103 + + plat/st/stm32mp1/platform.mk | 144 +- + plat/st/stm32mp1/services/bsec_svc.c | 460 ++++ + plat/st/stm32mp1/services/bsec_svc.h | 21 + + plat/st/stm32mp1/services/low_power_svc.c | 46 + + plat/st/stm32mp1/services/low_power_svc.h | 15 + + plat/st/stm32mp1/services/pwr_svc.c | 124 ++ + plat/st/stm32mp1/services/pwr_svc.h | 13 + + plat/st/stm32mp1/services/rcc_svc.c | 477 +++++ + plat/st/stm32mp1/services/rcc_svc.h | 14 + + plat/st/stm32mp1/services/stm32mp1_svc_setup.c | 113 + + plat/st/stm32mp1/sp_min/sp_min-stm32mp1.mk | 14 + + plat/st/stm32mp1/sp_min/sp_min_setup.c | 243 ++- + plat/st/stm32mp1/stm32mp1.ld.S | 19 +- + plat/st/stm32mp1/stm32mp1_common.c | 101 - + plat/st/stm32mp1/stm32mp1_context.c | 220 +- + plat/st/stm32mp1/stm32mp1_dbgmcu.c | 153 ++ + plat/st/stm32mp1/stm32mp1_def.h | 441 +++- + plat/st/stm32mp1/stm32mp1_dt.c | 476 ----- + plat/st/stm32mp1/stm32mp1_gic.c | 173 +- + plat/st/stm32mp1/stm32mp1_helper.S | 248 ++- + plat/st/stm32mp1/stm32mp1_helper_dbg.S | 227 ++ + plat/st/stm32mp1/stm32mp1_low_power.c | 311 +++ + plat/st/stm32mp1/stm32mp1_pm.c | 118 +- + plat/st/stm32mp1/stm32mp1_power_config.c | 193 ++ + plat/st/stm32mp1/stm32mp1_private.c | 379 ++++ + plat/st/stm32mp1/stm32mp1_security.c | 91 +- + plat/st/stm32mp1/stm32mp1_shared_resources.c | 833 ++++++++ + plat/st/stm32mp1/stm32mp1_syscfg.c | 144 ++ + plat/st/stm32mp1/stm32mp1_usb_desc.c | 401 ++++ + tools/cert_create/Makefile | 18 +- + tools/doimage/Makefile | 20 +- + tools/fiptool/Makefile | 14 +- + tools/stm32image/Makefile | 20 +- + tools/stm32image/stm32image.c | 2 +- + 237 files changed, 34905 insertions(+), 4745 deletions(-) + create mode 100644 docs/devicetree/bindings/arm/secure.txt + create mode 100644 docs/devicetree/bindings/clock/st,stm32mp1-rcc.txt + create mode 100644 docs/devicetree/bindings/i2c/i2c-stm32.txt + create mode 100644 docs/devicetree/bindings/mmc/mmci.txt + create mode 100644 docs/devicetree/bindings/mmc/st,stm32-sdmmc2.txt + create mode 100644 docs/devicetree/bindings/power/st,stm32mp1-pwr.txt + create mode 100644 docs/devicetree/bindings/power/st,stpmic1.txt + create mode 100644 docs/devicetree/bindings/reset/st,stm32mp1-rcc.txt + create mode 100644 docs/devicetree/bindings/rng/st,stm32-rng.txt + create mode 100644 docs/devicetree/bindings/serial/st,stm32-usart.txt + create mode 100644 docs/devicetree/bindings/soc/st,stm32-etzpc.txt + create mode 100644 docs/devicetree/bindings/soc/st,stm32-romem.txt + create mode 100644 docs/devicetree/bindings/soc/st,stm32-stgen.txt + create mode 100644 docs/devicetree/bindings/soc/st,stm32-tamp.txt + create mode 100644 docs/devicetree/bindings/watchdog/st,stm32-iwdg.txt + create mode 100644 drivers/console/aarch32/deprecated_console.S + create mode 100644 drivers/console/aarch32/multi_console.S + create mode 100644 drivers/st/bsec/bsec.c + create mode 100644 drivers/st/clk/stm32mp_clkfunc.c + create mode 100644 drivers/st/etzpc/etzpc.c + create mode 100644 drivers/st/hash/hash_sec.c + create mode 100644 drivers/st/i2c/stm32_i2c.c + create mode 100644 drivers/st/io/io_mmc.c + create mode 100644 drivers/st/io/io_programmer_st_usb.c + create mode 100644 drivers/st/io/io_stm32image.c + create mode 100644 drivers/st/iwdg/stm32_iwdg.c + create mode 100644 drivers/st/mmc/stm32_sdmmc2.c + create mode 100644 drivers/st/nand/io_nand.c + create mode 100644 drivers/st/nand/nand.c + delete mode 100644 drivers/st/pmic/stm32_i2c.c + delete mode 100644 drivers/st/pmic/stm32mp1_pmic.c + create mode 100644 drivers/st/pmic/stm32mp_pmic.c + create mode 100644 drivers/st/pmic/stpmic1.c + delete mode 100644 drivers/st/pmic/stpmu1.c + create mode 100644 drivers/st/qspi/io_qspi.c + create mode 100644 drivers/st/rng/stm32_rng.c + create mode 100644 drivers/st/rtc/stm32_rtc.c + create mode 100644 drivers/st/tamper/stm32_tamp.c + create mode 100644 drivers/st/timer/stm32_timer.c + create mode 100644 drivers/st/uart/io_programmer_uart.c + create mode 100644 drivers/st/uart/stm32mp1xx_hal_uart.c + create mode 100644 drivers/st/usb_dwc2/usb_dwc2.c + create mode 100644 fdts/stm32mp15-ddr3-1x4Gb-1066-binG.dtsi + create mode 100644 fdts/stm32mp157a-dk1.dts + create mode 100644 fdts/stm32mp157c-dk2.dts + create mode 100644 fdts/stm32mp157c-security.dtsi + create mode 100644 fdts/stm32mp157cab-pinctrl.dtsi + create mode 100644 fdts/stm32mp157cac-pinctrl.dtsi + create mode 100644 fdts/stm32mp157cad-pinctrl.dtsi + create mode 100644 include/common/aarch32/console_macros.S + create mode 100644 include/drivers/st/bsec.h + create mode 100644 include/drivers/st/etzpc.h + create mode 100644 include/drivers/st/hash_sec.h + create mode 100644 include/drivers/st/io_mmc.h + create mode 100644 include/drivers/st/io_nand.h + create mode 100644 include/drivers/st/io_programmer.h + create mode 100644 include/drivers/st/io_programmer_st_usb.h + create mode 100644 include/drivers/st/io_qspi.h + create mode 100644 include/drivers/st/io_stm32image.h + create mode 100644 include/drivers/st/io_uart.h + create mode 100644 include/drivers/st/nand.h + create mode 100644 include/drivers/st/stm32_console.h + create mode 100644 include/drivers/st/stm32_hal_hash_reg.h + create mode 100644 include/drivers/st/stm32_iwdg.h + create mode 100644 include/drivers/st/stm32_rng.h + create mode 100644 include/drivers/st/stm32_rtc.h + create mode 100644 include/drivers/st/stm32_sdmmc2.h + create mode 100644 include/drivers/st/stm32_tamp.h + create mode 100644 include/drivers/st/stm32_timer.h + create mode 100644 include/drivers/st/stm32_uart_regs.h + delete mode 100644 include/drivers/st/stm32mp1_pmic.h + delete mode 100644 include/drivers/st/stm32mp1_reset.h + create mode 100644 include/drivers/st/stm32mp1xx_hal.h + create mode 100644 include/drivers/st/stm32mp1xx_hal_uart.h + create mode 100644 include/drivers/st/stm32mp1xx_hal_uart_ex.h + create mode 100644 include/drivers/st/stm32mp_clkfunc.h + create mode 100644 include/drivers/st/stm32mp_pmic.h + create mode 100644 include/drivers/st/stm32mp_reset.h + create mode 100644 include/drivers/st/stpmic1.h + delete mode 100644 include/drivers/st/stpmu1.h + create mode 100644 include/drivers/st/usb_dwc2.h + create mode 100644 include/dt-bindings/interrupt-controller/arm-gic.h + create mode 100644 include/dt-bindings/power/stm32mp1-power.h + create mode 100644 include/dt-bindings/soc/st,stm32-etzpc.h + create mode 100644 include/lib/usb/usb_core.h + create mode 100644 include/lib/usb/usb_st_dfu.h + create mode 100644 lib/compiler-rt/builtins/lshrdi3.c + create mode 100644 lib/usb/usb_core.c + create mode 100644 lib/usb/usb_st_dfu.c + create mode 100644 plat/common/aarch32/crash_console_helpers.S + create mode 100644 plat/common/aarch64/crash_console_helpers.S + create mode 100644 plat/st/common/bl2_io_storage.c + create mode 100644 plat/st/common/include/stm32mp_auth.h + create mode 100644 plat/st/common/include/stm32mp_common.h + create mode 100644 plat/st/common/include/stm32mp_dt.h + create mode 100644 plat/st/common/include/stm32mp_shres_helpers.h + create mode 100644 plat/st/common/stm32mp_auth.c + create mode 100644 plat/st/common/stm32mp_common.c + create mode 100644 plat/st/common/stm32mp_dt.c + create mode 100644 plat/st/common/stm32mp_shres_helpers.c + delete mode 100644 plat/st/stm32mp1/bl2_io_storage.c + create mode 100644 plat/st/stm32mp1/include/stm32mp1_dbgmcu.h + delete mode 100644 plat/st/stm32mp1/include/stm32mp1_dt.h + create mode 100644 plat/st/stm32mp1/include/stm32mp1_low_power.h + create mode 100644 plat/st/stm32mp1/include/stm32mp1_power_config.h + create mode 100644 plat/st/stm32mp1/include/stm32mp1_shared_resources.h + create mode 100644 plat/st/stm32mp1/include/stm32mp1_smc.h + create mode 100644 plat/st/stm32mp1/include/stm32mp1_usb_desc.h + create mode 100644 plat/st/stm32mp1/include/usb_ctx.h + create mode 100644 plat/st/stm32mp1/services/bsec_svc.c + create mode 100644 plat/st/stm32mp1/services/bsec_svc.h + create mode 100644 plat/st/stm32mp1/services/low_power_svc.c + create mode 100644 plat/st/stm32mp1/services/low_power_svc.h + create mode 100644 plat/st/stm32mp1/services/pwr_svc.c + create mode 100644 plat/st/stm32mp1/services/pwr_svc.h + create mode 100644 plat/st/stm32mp1/services/rcc_svc.c + create mode 100644 plat/st/stm32mp1/services/rcc_svc.h + create mode 100644 plat/st/stm32mp1/services/stm32mp1_svc_setup.c + delete mode 100644 plat/st/stm32mp1/stm32mp1_common.c + create mode 100644 plat/st/stm32mp1/stm32mp1_dbgmcu.c + delete mode 100644 plat/st/stm32mp1/stm32mp1_dt.c + create mode 100644 plat/st/stm32mp1/stm32mp1_helper_dbg.S + create mode 100644 plat/st/stm32mp1/stm32mp1_low_power.c + create mode 100644 plat/st/stm32mp1/stm32mp1_power_config.c + create mode 100644 plat/st/stm32mp1/stm32mp1_private.c + create mode 100644 plat/st/stm32mp1/stm32mp1_shared_resources.c + create mode 100644 plat/st/stm32mp1/stm32mp1_syscfg.c + create mode 100644 plat/st/stm32mp1/stm32mp1_usb_desc.c + +diff --git a/.checkpatch.conf b/.checkpatch.conf +index 63bdf7b..066207b 100644 +--- a/.checkpatch.conf ++++ b/.checkpatch.conf +@@ -93,3 +93,21 @@ + # "Use of volatile is usually wrong: see Documentation/volatile-considered-harmful.txt" + # We allow the usage of the volatile keyword in TF. + --ignore VOLATILE ++ ++# PREFER_KERNEL_TYPES reports this kind of messages (when using --strict): ++# "Prefer kernel type 'u32' over 'uint32_t'" ++--ignore PREFER_KERNEL_TYPES ++ ++# USLEEP_RANGE reports this kind of messages (when using --strict): ++# "usleep_range is preferred over udelay; see Documentation/timers/timers-howto.txt" ++--ignore USLEEP_RANGE ++ ++# COMPARISON_TO_NULL reports this kind of messages (when using --strict): ++# Comparison to NULL could be written "" ++--ignore COMPARISON_TO_NULL ++ ++# UNNECESSARY_PARENTHESES reports this kind of messages (when using --strict): ++# Unnecessary parentheses around "" ++--ignore UNNECESSARY_PARENTHESES ++ ++--ignore BRACES +diff --git a/Makefile b/Makefile +index 23a1b0a..cda7e7d 100644 +--- a/Makefile ++++ b/Makefile +@@ -187,8 +187,48 @@ TF_CFLAGS_aarch64 += -mgeneral-regs-only -mstrict-align + ASFLAGS_aarch32 = $(march32-directive) + ASFLAGS_aarch64 = -march=armv8-a + ++WARNING1 := -Wextra ++WARNING1 += -Wunused -Wno-unused-parameter ++WARNING1 += -Wmissing-declarations ++WARNING1 += -Wmissing-format-attribute ++WARNING1 += -Wmissing-prototypes ++WARNING1 += -Wold-style-definition ++WARNING1 += -Wunused-but-set-variable ++WARNING1 += -Wunused-const-variable ++ ++WARNING2 := -Waggregate-return ++WARNING2 += -Wcast-align ++WARNING2 += -Wdisabled-optimization ++WARNING2 += -Wnested-externs ++WARNING2 += -Wshadow ++WARNING2 += -Wlogical-op ++WARNING2 += -Wmissing-field-initializers ++WARNING2 += -Wsign-compare ++WARNING2 += -Wmaybe-uninitialized ++ ++WARNING3 := -Wbad-function-cast ++WARNING3 += -Wcast-qual ++WARNING3 += -Wconversion ++WARNING3 += -Wpacked ++WARNING3 += -Wpadded ++WARNING3 += -Wpointer-arith ++WARNING3 += -Wredundant-decls ++WARNING3 += -Wswitch-default ++WARNING3 += -Wpacked-bitfield-compat ++WARNING3 += -Wvla ++ ++ifeq (${W},1) ++WARN_OR_ERROR := $(WARNING1) ++else ifeq (${W},2) ++WARN_OR_ERROR := $(WARNING1) $(WARNING2) ++else ifeq (${W},3) ++WARN_OR_ERROR := $(WARNING1) $(WARNING2) $(WARNING3) ++else ++WARN_OR_ERROR := -Werror ++endif ++ + CPPFLAGS = ${DEFINES} ${INCLUDES} ${MBEDTLS_INC} -nostdinc \ +- -Wmissing-include-dirs -Werror ++ -Wmissing-include-dirs $(WARN_OR_ERROR) + ASFLAGS += $(CPPFLAGS) $(ASFLAGS_$(ARCH)) \ + -D__ASSEMBLY__ -ffreestanding \ + -Wa,--fatal-warnings +@@ -396,12 +436,6 @@ ifeq ($(HW_ASSISTED_COHERENCY)-$(USE_COHERENT_MEM),1-1) + $(error USE_COHERENT_MEM cannot be enabled with HW_ASSISTED_COHERENCY) + endif + +-ifneq ($(MULTI_CONSOLE_API), 0) +- ifeq (${ARCH},aarch32) +- $(error "Error: MULTI_CONSOLE_API is not supported for AArch32") +- endif +-endif +- + #For now, BL2_IN_XIP_MEM is only supported when BL2_AT_EL3 is 1. + ifeq ($(BL2_AT_EL3)-$(BL2_IN_XIP_MEM),0-1) + $(error "BL2_IN_XIP_MEM is only supported when BL2_AT_EL3 is enabled") +@@ -592,6 +626,7 @@ $(eval $(call assert_boolean,USE_TBBR_DEFS)) + $(eval $(call assert_boolean,WARMBOOT_ENABLE_DCACHE_EARLY)) + $(eval $(call assert_boolean,BL2_AT_EL3)) + $(eval $(call assert_boolean,BL2_IN_XIP_MEM)) ++$(eval $(call assert_boolean,AARCH32_EXCEPTION_DEBUG)) + + $(eval $(call assert_numeric,ARM_ARCH_MAJOR)) + $(eval $(call assert_numeric,ARM_ARCH_MINOR)) +@@ -644,6 +679,7 @@ $(eval $(call add_define,USE_TBBR_DEFS)) + $(eval $(call add_define,WARMBOOT_ENABLE_DCACHE_EARLY)) + $(eval $(call add_define,BL2_AT_EL3)) + $(eval $(call add_define,BL2_IN_XIP_MEM)) ++$(eval $(call add_define,AARCH32_EXCEPTION_DEBUG)) + + # Define the EL3_PAYLOAD_BASE flag only if it is provided. + ifdef EL3_PAYLOAD_BASE +@@ -784,9 +820,11 @@ checkpatch: locate-checkpatch + for commit in `git rev-list $$COMMON_COMMIT..HEAD`; do \ + printf "\n[*] Checking style of '$$commit'\n\n"; \ + git log --format=email "$$commit~..$$commit" \ +- -- ${CHECK_PATHS} | ${CHECKPATCH} - || true; \ ++ -- ${CHECK_PATHS} | ${CHECKPATCH} --strict - || \ ++ true; \ + git diff --format=email "$$commit~..$$commit" \ +- -- ${CHECK_PATHS} | ${CHECKPATCH} - || true; \ ++ -- ${CHECK_PATHS} | ${CHECKPATCH} --strict - || \ ++ true; \ + done + + certtool: ${CRTTOOL} +diff --git a/bl2/aarch32/bl2_arch_setup.c b/bl2/aarch32/bl2_arch_setup.c +index db8a068..4fd8d07 100644 +--- a/bl2/aarch32/bl2_arch_setup.c ++++ b/bl2/aarch32/bl2_arch_setup.c +@@ -4,6 +4,7 @@ + * SPDX-License-Identifier: BSD-3-Clause + */ + ++#include "../bl2_private.h" + + /******************************************************************************* + * Place holder function to perform any Secure SVC specific architectural +diff --git a/bl2/aarch32/bl2_el3_entrypoint.S b/bl2/aarch32/bl2_el3_entrypoint.S +index 0c7b064..437188e 100644 +--- a/bl2/aarch32/bl2_el3_entrypoint.S ++++ b/bl2/aarch32/bl2_el3_entrypoint.S +@@ -15,6 +15,10 @@ + + + func bl2_entrypoint ++#if STM32MP1_RESET_HALT_WORKAROUND ++ bl plat_dbg_attach_loop ++#endif ++ + /* Save arguments x0-x3 from previous Boot loader */ + mov r9, r0 + mov r10, r1 +diff --git a/bl2/aarch32/bl2_el3_exceptions.S b/bl2/aarch32/bl2_el3_exceptions.S +index 11ddf37..7058b07 100644 +--- a/bl2/aarch32/bl2_el3_exceptions.S ++++ b/bl2/aarch32/bl2_el3_exceptions.S +@@ -12,10 +12,19 @@ + + vector_base bl2_vector_table + b bl2_entrypoint ++#if AARCH32_EXCEPTION_DEBUG ++ b report_undef_inst /* Undef */ ++#else + b report_exception /* Undef */ ++#endif + b report_exception /* SVC call */ ++#if AARCH32_EXCEPTION_DEBUG ++ b report_prefetch_abort /* Prefetch abort */ ++ b report_data_abort /* Data abort */ ++#else + b report_exception /* Prefetch abort */ + b report_exception /* Data abort */ ++#endif + b report_exception /* Reserved */ + b report_exception /* IRQ */ + b report_exception /* FIQ */ +diff --git a/bl2/aarch32/bl2_entrypoint.S b/bl2/aarch32/bl2_entrypoint.S +index d215f48..f76c1c9 100644 +--- a/bl2/aarch32/bl2_entrypoint.S ++++ b/bl2/aarch32/bl2_entrypoint.S +@@ -15,10 +15,19 @@ + + vector_base bl2_vector_table + b bl2_entrypoint ++#if AARCH32_EXCEPTION_DEBUG ++ b report_undef_inst /* Undef */ ++#else + b report_exception /* Undef */ ++#endif + b report_exception /* SVC call */ ++#if AARCH32_EXCEPTION_DEBUG ++ b report_prefetch_abort /* Prefetch abort */ ++ b report_data_abort /* Data abort */ ++#else + b report_exception /* Prefetch abort */ + b report_exception /* Data abort */ ++#endif + b report_exception /* Reserved */ + b report_exception /* IRQ */ + b report_exception /* FIQ */ +diff --git a/bl2/bl2_image_load_v2.c b/bl2/bl2_image_load_v2.c +index 0f40785..2e3e145 100644 +--- a/bl2/bl2_image_load_v2.c ++++ b/bl2/bl2_image_load_v2.c +@@ -69,17 +69,17 @@ struct entry_point_info *bl2_load_images(void) + ERROR("BL2: Failed to load image (%i)\n", err); + plat_error_handler(err); + } ++ ++ /* Allow platform to handle image information. */ ++ err = bl2_plat_handle_post_image_load(bl2_node_info->image_id); ++ if (err) { ++ ERROR("BL2: Failure in post image load handling (%i)\n", err); ++ plat_error_handler(err); ++ } + } else { + INFO("BL2: Skip loading image id %d\n", bl2_node_info->image_id); + } + +- /* Allow platform to handle image information. */ +- err = bl2_plat_handle_post_image_load(bl2_node_info->image_id); +- if (err) { +- ERROR("BL2: Failure in post image load handling (%i)\n", err); +- plat_error_handler(err); +- } +- + /* Go to next image */ + bl2_node_info = bl2_node_info->next_load_info; + } +diff --git a/bl2/bl2_private.h b/bl2/bl2_private.h +index f93a179..8e602ff 100644 +--- a/bl2/bl2_private.h ++++ b/bl2/bl2_private.h +@@ -8,6 +8,9 @@ + #define __BL2_PRIVATE_H__ + + #if BL2_IN_XIP_MEM ++ ++#include ++ + /******************************************************************************* + * Declarations of linker defined symbols which will tell us where BL2 lives + * in Trusted ROM and RAM +diff --git a/bl2u/aarch32/bl2u_entrypoint.S b/bl2u/aarch32/bl2u_entrypoint.S +index 7fb64f3..b511499 100644 +--- a/bl2u/aarch32/bl2u_entrypoint.S ++++ b/bl2u/aarch32/bl2u_entrypoint.S +@@ -15,10 +15,19 @@ + + vector_base bl2u_vector_table + b bl2u_entrypoint ++#if AARCH32_EXCEPTION_DEBUG ++ b report_undef_inst /* Undef */ ++#else + b report_exception /* Undef */ ++#endif + b report_exception /* SVC call */ ++#if AARCH32_EXCEPTION_DEBUG ++ b report_prefetch_abort /* Prefetch abort */ ++ b report_data_abort /* Data abort */ ++#else + b report_exception /* Prefetch abort */ + b report_exception /* Data abort */ ++#endif + b report_exception /* Reserved */ + b report_exception /* IRQ */ + b report_exception /* FIQ */ +diff --git a/bl32/sp_min/aarch32/entrypoint.S b/bl32/sp_min/aarch32/entrypoint.S +index d6853cc..2d67af3 100644 +--- a/bl32/sp_min/aarch32/entrypoint.S ++++ b/bl32/sp_min/aarch32/entrypoint.S +@@ -44,10 +44,19 @@ + + vector_base sp_min_vector_table + b sp_min_entrypoint ++#if AARCH32_EXCEPTION_DEBUG ++ b report_undef_inst /* Undef */ ++#else + b plat_panic_handler /* Undef */ ++#endif + b sp_min_handle_smc /* Syscall */ ++#if AARCH32_EXCEPTION_DEBUG ++ b report_prefetch_abort /* Prefetch abort */ ++ b report_data_abort /* Data abort */ ++#else + b plat_panic_handler /* Prefetch abort */ + b plat_panic_handler /* Data abort */ ++#endif + b plat_panic_handler /* Reserved */ + b plat_panic_handler /* IRQ */ + b sp_min_handle_fiq /* FIQ */ +diff --git a/common/aarch32/debug.S b/common/aarch32/debug.S +index f506356..a058645 100644 +--- a/common/aarch32/debug.S ++++ b/common/aarch32/debug.S +@@ -7,9 +7,16 @@ + #include + #include + ++ .globl asm_print_str ++ .globl asm_print_hex + .globl asm_assert + .globl do_panic + .globl report_exception ++#if AARCH32_EXCEPTION_DEBUG ++ .globl report_undef_inst ++ .globl report_prefetch_abort ++ .globl report_data_abort ++#endif + + /* Since the max decimal input number is 65536 */ + #define MAX_DEC_DIVISOR 10000 +@@ -66,6 +73,41 @@ func report_exception + no_ret plat_panic_handler + endfunc report_exception + ++#if AARCH32_EXCEPTION_DEBUG ++ /*********************************************************** ++ * This function is called from the vector table for ++ * undefined instruction. The lr_und is given as an ++ * argument to platform handler. ++ ***********************************************************/ ++func report_undef_inst ++ mrs r0, lr_und ++ bl plat_report_undef_inst ++ no_ret plat_panic_handler ++endfunc report_undef_inst ++ ++ /*********************************************************** ++ * This function is called from the vector table for ++ * unhandled exceptions. The lr_abt is given as an ++ * argument to platform handler. ++ ***********************************************************/ ++func report_prefetch_abort ++ mrs r0, lr_abt ++ bl plat_report_prefetch_abort ++ no_ret plat_panic_handler ++endfunc report_prefetch_abort ++ ++ /*********************************************************** ++ * This function is called from the vector table for ++ * unhandled exceptions. The lr_abt is given as an ++ * argument to platform handler. ++ ***********************************************************/ ++func report_data_abort ++ mrs r0, lr_abt ++ bl plat_report_data_abort ++ no_ret plat_panic_handler ++endfunc report_data_abort ++#endif ++ + #if ENABLE_ASSERTIONS + .section .rodata.assert_str, "aS" + assert_msg1: +@@ -151,10 +193,10 @@ endfunc asm_assert + + /* + * This function prints a string from address in r4 +- * Clobber: lr, r0 - r4 ++ * Clobber: lr, r0 - r4, r7 + */ + func asm_print_str +- mov r3, lr ++ mov r7, lr + 1: + ldrb r0, [r4], #0x1 + cmp r0, #0 +@@ -162,16 +204,16 @@ func asm_print_str + bl plat_crash_console_putc + b 1b + 2: +- bx r3 ++ bx r7 + endfunc asm_print_str + + /* + * This function prints a hexadecimal number in r4. + * In: r4 = the hexadecimal to print. +- * Clobber: lr, r0 - r3, r5 ++ * Clobber: lr, r0 - r3, r5, r7 + */ + func asm_print_hex +- mov r3, lr ++ mov r7, lr + mov r5, #32 /* No of bits to convert to ascii */ + 1: + sub r5, r5, #4 +@@ -188,5 +230,5 @@ func asm_print_hex + bl plat_crash_console_putc + cmp r5, #0 + bne 1b +- bx r3 ++ bx r7 + endfunc asm_print_hex +diff --git a/docs/devicetree/bindings/arm/secure.txt b/docs/devicetree/bindings/arm/secure.txt +new file mode 100644 +index 0000000..e31303f +--- /dev/null ++++ b/docs/devicetree/bindings/arm/secure.txt +@@ -0,0 +1,53 @@ ++* ARM Secure world bindings ++ ++ARM CPUs with TrustZone support have two distinct address spaces, ++"Normal" and "Secure". Most devicetree consumers (including the Linux ++kernel) are not TrustZone aware and run entirely in either the Normal ++world or the Secure world. However some devicetree consumers are ++TrustZone aware and need to be able to determine whether devices are ++visible only in the Secure address space, only in the Normal address ++space, or visible in both. (One example of that situation would be a ++virtual machine which boots Secure firmware and wants to tell the ++firmware about the layout of the machine via devicetree.) ++ ++The general principle of the naming scheme for Secure world bindings ++is that any property that needs a different value in the Secure world ++can be supported by prefixing the property name with "secure-". So for ++instance "secure-foo" would override "foo". For property names with ++a vendor prefix, the Secure variant of "vendor,foo" would be ++"vendor,secure-foo". If there is no "secure-" property then the Secure ++world value is the same as specified for the Normal world by the ++non-prefixed property. However, only the properties listed below may ++validly have "secure-" versions; this list will be enlarged on a ++case-by-case basis. ++ ++Defining the bindings in this way means that a device tree which has ++been annotated to indicate the presence of Secure-only devices can ++still be processed unmodified by existing Non-secure software (and in ++particular by the kernel). ++ ++Note that it is still valid for bindings intended for purely Secure ++world consumers (like kernels that run entirely in Secure) to simply ++describe the view of Secure world using the standard bindings. These ++secure- bindings only need to be used where both the Secure and Normal ++world views need to be described in a single device tree. ++ ++Valid Secure world properties: ++ ++- secure-status : specifies whether the device is present and usable ++ in the secure world. The combination of this with "status" allows ++ the various possible combinations of device visibility to be ++ specified. If "secure-status" is not specified it defaults to the ++ same value as "status"; if "status" is not specified either then ++ both default to "okay". This means the following combinations are ++ possible: ++ ++ /* Neither specified: default to visible in both S and NS */ ++ secure-status = "okay"; /* visible in both */ ++ status = "okay"; /* visible in both */ ++ status = "okay"; secure-status = "okay"; /* visible in both */ ++ secure-status = "disabled"; /* NS-only */ ++ status = "okay"; secure-status = "disabled"; /* NS-only */ ++ status = "disabled"; secure-status = "okay"; /* S-only */ ++ status = "disabled"; /* disabled in both */ ++ status = "disabled"; secure-status = "disabled"; /* disabled in both */ +diff --git a/docs/devicetree/bindings/clock/st,stm32mp1-rcc.txt b/docs/devicetree/bindings/clock/st,stm32mp1-rcc.txt +new file mode 100644 +index 0000000..7021486 +--- /dev/null ++++ b/docs/devicetree/bindings/clock/st,stm32mp1-rcc.txt +@@ -0,0 +1,324 @@ ++STMicroelectronics STM32 Peripheral Reset Clock Controller ++========================================================== ++ ++The RCC IP is both a reset and a clock controller. ++ ++RCC makes also power management (resume/supend and wakeup interrupt). ++ ++Please also refer to reset.txt for common reset controller binding usage. ++ ++Please also refer to clock-bindings.txt for common clock controller ++binding usage. ++ ++ ++Required properties: ++- compatible: "st,stm32mp1-rcc", "syscon" ++- reg: should be register base and length as documented in the datasheet ++- #clock-cells: 1, device nodes should specify the clock in their ++ "clocks" property, containing a phandle to the clock device node, ++ an index specifying the clock to use. ++- #reset-cells: Shall be 1 ++- interrupts: Should contain a general interrupt line and a interrupt line ++ to the wake-up of processor (CSTOP). ++ ++Example: ++ rcc: rcc@50000000 { ++ compatible = "st,stm32mp1-rcc", "syscon"; ++ reg = <0x50000000 0x1000>; ++ #clock-cells = <1>; ++ #reset-cells = <1>; ++ interrupts = , ++ ; ++ }; ++ ++Other properties: ++- secure-status: Relates to RCC TZ_ENABLE configuration to restrict RCC access. ++- st,clksrc : The clock sources configuration array in a platform specific order. ++- st,clkdiv : The clock dividers configuration array in a paltform specific order. ++- st,pll : A specific PLL configuration ++- st,pkcs : The peripheral kernel clock distribution configuration array. ++ ++Specifying clocks ++================= ++ ++All available clocks are defined as preprocessor macros in ++dt-bindings/clock/stm32mp1-clks.h header and can be used in device ++tree sources. ++ ++Specifying softreset control of devices ++======================================= ++ ++Device nodes should specify the reset channel required in their "resets" ++property, containing a phandle to the reset device node and an index specifying ++which channel to use. ++The index is the bit number within the RCC registers bank, starting from RCC ++base address. ++It is calculated as: index = register_offset / 4 * 32 + bit_offset. ++Where bit_offset is the bit offset within the register. ++ ++For example on STM32MP1, for LTDC reset: ++ ltdc = APB4_RSTSETR_offset / 4 * 32 + LTDC_bit_offset ++ = 0x180 / 4 * 32 + 0 = 3072 ++ ++The list of valid indices for STM32MP1 is available in: ++include/dt-bindings/reset-controller/stm32mp1-resets.h ++ ++This file implements defines like: ++#define LTDC_R 3072 ++ ++ ++Defining clock source distribution with property st,clksrc ++========================================================== ++ ++Property can be used to configure the clock distribution tree. ++When used, it shall describe the whole distribution tree. ++ ++For the STM32MP15x family there are 9 clock sources selector which are ++configured in the following order: ++ MPU AXI MCU PLL12 PLL3 PLL4 RTC MCO1 MCO2 ++ ++Clock source configuration values are defined by macros CLK__ ++from dt-bindings/clock/stm32mp1-clksrc.h. ++ ++Example: ++ st,clksrc = < ++ CLK_MPU_PLL1P ++ CLK_AXI_PLL2P ++ CLK_MCU_PLL3P ++ CLK_PLL12_HSE ++ CLK_PLL3_HSE ++ CLK_PLL4_HSE ++ CLK_RTC_LSE ++ CLK_MCO1_DISABLED ++ CLK_MCO2_DISABLED ++ >; ++ ++ ++Defining clock dividers with property st,clkdiv ++=============================================== ++ ++Property can be used to configure the clock main dividers value. ++When used, it shall describe the whole clock dividers tree. ++ ++For the STM32MP15x family there are 11 dividers values expected. ++They shall be configured in the following order: ++ MPU AXI MCU APB1 APB2 APB3 APB4 APB5 RTC MCO1 MCO2 ++ ++The each divider value uses the DIV coding defined in RCC associated ++register RCC_xxxDIVR. In most cases, it is: ++ 0x0: not divided ++ 0x1: division by 2 ++ 0x2: division by 4 ++ 0x3: division by 8 ++ ... ++ ++Note that for RTC MCO1 MCO2, the coding is different: ++ 0x0: not divided ++ 0x1: division by 2 ++ 0x2: division by 3 ++ 0x3: division by 4 ++ ... ++ ++Example: ++ st,clkdiv = < ++ 1 /*MPU*/ ++ 0 /*AXI*/ ++ 0 /*MCU*/ ++ 1 /*APB1*/ ++ 1 /*APB2*/ ++ 1 /*APB3*/ ++ 1 /*APB4*/ ++ 2 /*APB5*/ ++ 23 /*RTC*/ ++ 0 /*MCO1*/ ++ 0 /*MCO2*/ ++ >; ++ ++Defining peripheral PLL frequencies with property st,pll ++======================================================== ++ ++This property can be used to configure PLL frequencies. ++ ++PLL children nodes for PLL1 to PLL4 (see ref manual for details) ++are listed with associated index 0 to 3 (st,pll@0 to st,pll@3). ++PLLx is off when the associated node is absent. ++ ++Here are the available properties for each PLL node: ++ ++- cfg: The parameters for PLL configuration in the following order: ++ DIVM DIVN DIVP DIVQ DIVR Output. ++ ++ DIVx values are defined as in RCC spec: ++ 0x0: bypass (division by 1) ++ 0x1: division by 2 ++ 0x2: division by 3 ++ 0x3: division by 4 ++ ... ++ ++ Output contains a bitfield for each output value (1:ON/0:OFF) ++ BIT(0) => output P : DIVPEN ++ BIT(1) => output Q : DIVQEN ++ BIT(2) => output R : DIVREN ++ NB: macro PQR(p,q,r) can be used to build this value ++ with p,q,r = 0 or 1. ++ ++- frac: Fractional part of the multiplication factor ++ (optional, PLL is in integer mode when absent). ++ ++- csg: Clock Spreading Generator (optional) with parameters in the following ++ order: MOD_PER INC_STEP SSCG_MODE. ++ ++ MOD_PER: Modulation Period Adjustment ++ INC_STEP: Modulation Depth Adjustment ++ SSCG_MODE: Spread spectrum clock generator mode, with associated ++ defined from stm32mp1-clksrc.h: ++ - SSCG_MODE_CENTER_SPREAD = 0 ++ - SSCG_MODE_DOWN_SPREAD = 1 ++ ++Example: ++ st,pll@0 { ++ cfg = < 1 53 0 0 0 1 >; ++ frac = < 0x810 >; ++ }; ++ st,pll@1 { ++ cfg = < 1 43 1 0 0 PQR(0,1,1) >; ++ csg = < 10 20 1 >; ++ }; ++ st,pll@2 { ++ cfg = < 2 85 3 13 3 0 >; ++ csg = < 10 20 SSCG_MODE_CENTER_SPREAD >; ++ }; ++ st,pll@3 { ++ cfg = < 2 78 4 7 9 3 >; ++ }; ++ ++Defining peripherals kernel clock tree distribution with property st,pkcs ++========================================================================= ++ ++This property can be used to configure the peripherals kernel clock selection. ++ ++The property is a list of peripheral kernel clock source identifiers defined ++by macros CLK__ as defined by header file ++dt-bindings/clock/stm32mp1-clksrc.h. ++ ++st,pkcs may not list all the kernel clocks and has no ordering requirements. ++ ++Example: ++ st,pkcs = < ++ CLK_STGEN_HSE ++ CLK_CKPER_HSI ++ CLK_USBPHY_PLL2P ++ CLK_DSI_PLL2Q ++ CLK_I2C46_HSI ++ CLK_UART1_HSI ++ CLK_UART24_HSI ++ >; ++ ++Fixed clocks description ++======================== ++ ++The clock tree is also based on 5 fixed-clock in clocks node ++used to define the state of associated ST32MP1 oscillators: ++- clk-lsi ++- clk-lse ++- clk-hsi ++- clk-hse ++- clk-csi ++ ++At boot the clock tree initialization will ++- enable oscillators present in device tree ++- disable HSI oscillator if the node is absent (always activated by bootrom) ++ ++Optional properties : ++ ++a) for external oscillator: "clk-lse", "clk-hse" ++ ++ 4 optional fields are managed ++ - "st,bypass" configures the oscillator bypass mode (HSEBYP, LSEBYP) ++ - "st,digbypass" configures the bypass mode as full-swing digital ++ signal (DIGBYP) ++ - "st,css" activates the clock security system (HSECSSON, LSECSSON) ++ - "st,drive" (only for LSE) contains the value of the drive for the ++ oscillator (see LSEDRV_ defined in the file ++ dt-bindings/clock/stm32mp1-clksrc.h) ++ ++ Example board file: ++ ++ / { ++ clocks { ++ clk_hse: clk-hse { ++ #clock-cells = <0>; ++ compatible = "fixed-clock"; ++ clock-frequency = <64000000>; ++ st,bypass; ++ }; ++ ++ clk_lse: clk-lse { ++ #clock-cells = <0>; ++ compatible = "fixed-clock"; ++ clock-frequency = <32768>; ++ st,css; ++ st,drive = ; ++ }; ++ }; ++ ++b) for internal oscillator: "clk-hsi" ++ ++ Internally HSI clock is fixed to 64MHz for STM32MP157 SoC. ++ In device tree, clk-hsi is the clock after HSIDIV (clk_hsi in RCC ++ doc). So this clock frequency is used to compute the expected HSI_DIV ++ for the clock tree initialization. ++ ++ Example with HSIDIV = /1: ++ ++ / { ++ clocks { ++ clk_hsi: clk-hsi { ++ #clock-cells = <0>; ++ compatible = "fixed-clock"; ++ clock-frequency = <64000000>; ++ }; ++ }; ++ ++ Example with HSIDIV = /2 ++ ++ / { ++ clocks { ++ clk_hsi: clk-hsi { ++ #clock-cells = <0>; ++ compatible = "fixed-clock"; ++ clock-frequency = <32000000>; ++ }; ++ }; ++ ++HSI & CSI calibration ++======================== ++ ++Calibration is an optional feature that may be enabled from device tree. It ++allows to request calibration of the HSI or the CSI clocks from several means: ++ - SiP SMC service ++ - Periodic calibration every X seconds ++ - Interrupt raised by the MCU ++ ++This feature requires that a HW timer is assigned to the calibration sequence. ++ ++Dedicated interrupt must be defined using "mcu_sev" name to start a calibration ++on detection of an interrupt raised by MCU. ++ ++- st,hsi-cal: used to enable HSI clock calibration feature. ++ ++- st,csi-cal; used to enable CSI clock calibration feature. ++ ++- st,cal-sec: used to enable periodic calibration every specified seconds from ++ secure monitor. Time must be given in seconds. If not specified, calibration ++ is processed for each incoming request. ++ ++Example: ++ &rcc { ++ st,hsi-cal; ++ st,csi-cal; ++ st,cal-sec = <15>; ++ secure-interrupts = , ++ ; ++ interrupt-names = "mcu_sev", "wakeup"; ++ }; +diff --git a/docs/devicetree/bindings/i2c/i2c-stm32.txt b/docs/devicetree/bindings/i2c/i2c-stm32.txt +new file mode 100644 +index 0000000..68aefa6 +--- /dev/null ++++ b/docs/devicetree/bindings/i2c/i2c-stm32.txt +@@ -0,0 +1,54 @@ ++* I2C controller embedded in STMicroelectronics STM32 I2C platform ++ ++Required properties : ++- compatible : Must be one of the following ++ - "st,stm32f7-i2c" ++- reg : Offset and length of the register set for the device ++- resets: Must contain the phandle to the reset controller. ++- clocks: Must contain the input clock of the I2C instance. ++- A pinctrl state named "default" must be defined to set pins in mode of ++ operation for I2C transfer. An optional pinctrl state named "sleep" has to ++ be defined as well as to put I2C in low power mode in suspend mode. ++- #address-cells = <1>; ++- #size-cells = <0>; ++ ++Optional properties : ++- clock-frequency : Desired I2C bus clock frequency in Hz. If not specified, ++ the default 100 kHz frequency will be used. ++- i2c-scl-rising-time-ns : Only for STM32F7, I2C SCL Rising time for the board ++ (default: 25) ++- i2c-scl-falling-time-ns : Only for STM32F7, I2C SCL Falling time for the board ++ (default: 10) ++ I2C Timings are derived from these 2 values ++- st,syscfg-fmp: Only for STM32F7, use to set Fast Mode Plus bit within SYSCFG ++ whether Fast Mode Plus speed is selected by slave. ++ 1st cell : phandle to syscfg ++ 2nd cell : register offset within SYSCFG ++ 3rd cell : register bitmask for FMP bit ++ ++Example : ++ ++ i2c@40005400 { ++ compatible = "st,stm32f4-i2c"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <0x40005400 0x400>; ++ resets = <&rcc 277>; ++ clocks = <&rcc 0 149>; ++ pinctrl-0 = <&i2c1_sda_pin>, <&i2c1_scl_pin>; ++ pinctrl-names = "default"; ++ }; ++ ++ i2c@40005400 { ++ compatible = "st,stm32f7-i2c"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <0x40005400 0x400>; ++ resets = <&rcc STM32F7_APB1_RESET(I2C1)>; ++ clocks = <&rcc 1 CLK_I2C1>; ++ pinctrl-0 = <&i2c1_sda_pin>, <&i2c1_scl_pin>; ++ pinctrl-1 = <&i2c1_sda_pin_sleep>, <&i2c1_scl_pin_sleep>; ++ pinctrl-names = "default", "sleep"; ++ st,syscfg-fmp = <&syscfg 0x4 0x1>; ++ }; ++ +diff --git a/docs/devicetree/bindings/mmc/mmci.txt b/docs/devicetree/bindings/mmc/mmci.txt +new file mode 100644 +index 0000000..6d3c626 +--- /dev/null ++++ b/docs/devicetree/bindings/mmc/mmci.txt +@@ -0,0 +1,72 @@ ++* ARM PrimeCell MultiMedia Card Interface (MMCI) PL180/1 ++ ++The ARM PrimeCell MMCI PL180 and PL181 provides an interface for ++reading and writing to MultiMedia and SD cards alike. ++ ++This file documents differences between the core properties described ++by mmc.txt and the properties used by the mmci driver. Using "st" as ++the prefix for a property, indicates support by the ST Micro variant. ++ ++Required properties: ++- compatible : contains "arm,pl18x", "arm,primecell". ++- vmmc-supply : phandle to the regulator device tree node, mentioned ++ as the VCC/VDD supply in the eMMC/SD specs. ++ ++Optional properties: ++- arm,primecell-periphid : contains the PrimeCell Peripheral ID, it overrides ++ the ID provided by the HW ++- resets : phandle to internal reset line. ++ Should be defined for sdmmc variant. ++- vqmmc-supply : phandle to the regulator device tree node, mentioned ++ as the VCCQ/VDD_IO supply in the eMMC/SD specs. ++specific for ux500 variant: ++- st,sig-dir-dat0 : bus signal direction pin used for DAT[0]. ++- st,sig-dir-dat2 : bus signal direction pin used for DAT[2]. ++- st,sig-dir-dat31 : bus signal direction pin used for DAT[3] and DAT[1]. ++- st,sig-dir-dat74 : bus signal direction pin used for DAT[4] to DAT[7]. ++- st,sig-dir-cmd : cmd signal direction pin used for CMD. ++- st,sig-pin-fbclk : feedback clock signal pin used. ++ ++specific for sdmmc variant: ++- st,sig-dir : signal direction polarity used for cmd, dat0 dat123. ++- st,neg-edge : data & command phase relation, generated on ++ sd clock falling edge. ++- st,use-ckin : use ckin pin from an external driver to sample ++ the receive data (example: with voltage ++ switch transceiver). ++ ++Deprecated properties: ++- mmc-cap-mmc-highspeed : indicates whether MMC is high speed capable. ++- mmc-cap-sd-highspeed : indicates whether SD is high speed capable. ++ ++Example: ++ ++sdi0_per1@80126000 { ++ compatible = "arm,pl18x", "arm,primecell"; ++ reg = <0x80126000 0x1000>; ++ interrupts = <0 60 IRQ_TYPE_LEVEL_HIGH>; ++ ++ dmas = <&dma 29 0 0x2>, /* Logical - DevToMem */ ++ <&dma 29 0 0x0>; /* Logical - MemToDev */ ++ dma-names = "rx", "tx"; ++ ++ clocks = <&prcc_kclk 1 5>, <&prcc_pclk 1 5>; ++ clock-names = "sdi", "apb_pclk"; ++ ++ max-frequency = <100000000>; ++ bus-width = <4>; ++ cap-sd-highspeed; ++ cap-mmc-highspeed; ++ cd-gpios = <&gpio2 31 0x4>; // 95 ++ st,sig-dir-dat0; ++ st,sig-dir-dat2; ++ st,sig-dir-cmd; ++ st,sig-pin-fbclk; ++ ++ vmmc-supply = <&ab8500_ldo_aux3_reg>; ++ vqmmc-supply = <&vmmci>; ++ ++ pinctrl-names = "default", "sleep"; ++ pinctrl-0 = <&sdi0_default_mode>; ++ pinctrl-1 = <&sdi0_sleep_mode>; ++}; +diff --git a/docs/devicetree/bindings/mmc/st,stm32-sdmmc2.txt b/docs/devicetree/bindings/mmc/st,stm32-sdmmc2.txt +new file mode 100644 +index 0000000..51576a3 +--- /dev/null ++++ b/docs/devicetree/bindings/mmc/st,stm32-sdmmc2.txt +@@ -0,0 +1,22 @@ ++* STMicroelectronics STM32 SDMMC2 controller ++ ++The highspeed MMC host controller on STM32 soc family ++provides an interface for MMC, SD and SDIO types of memory cards. ++ ++This file documents differences between the core properties described ++by mmci.txt and the properties used by the sdmmc2 driver. ++ ++Required properties: ++ - compatible: should be one of: ++ "st,stm32-sdmmc2" ++ ++Example: ++ sdmmc1: sdmmc@0x58005000 { ++ compatible = "st,stm32-sdmmc2"; ++ reg = <0x58005000 0x1000>; ++ clocks = <&rcc SDMMC1_K>; ++ resets = <&rcc SDMMC1_R>; ++ cap-sd-highspeed; ++ cap-mmc-highspeed; ++ status = "disabled"; ++ }; +diff --git a/docs/devicetree/bindings/power/st,stm32mp1-pwr.txt b/docs/devicetree/bindings/power/st,stm32mp1-pwr.txt +new file mode 100644 +index 0000000..bd56e19 +--- /dev/null ++++ b/docs/devicetree/bindings/power/st,stm32mp1-pwr.txt +@@ -0,0 +1,42 @@ ++STMicroelectronics STM32MP1 Power Management Controller ++======================================================= ++ ++The PWR IP is responsible for handling the power related resources such as ++clocks, power supplies and resets. It provides 6 wake-up pins that are handled ++by an interrupt-controller. Wake-up pin can be used to wake-up from STANDBY SoC ++state. ++ ++Required properties: ++- compatible should be: "st,stm32mp1-pwr", "st,stm32-pwr" ++- reg: should be register base and length as documented in the ++ datasheet ++ ++Optional Properties: ++- Nodes corresponding to PSCI commands issued by kernel: ++ - system_suspend_supported_soc_modes: list of supported SoC modes in suspend ++ - system_off_soc_mode: SoC mode for shutdown ++ ++The list of SoC modes is in include/dt-bindings/power/stm32mp1-power.h: ++ - modes for system_suspend ++ 1 -> STM32_PM_CSTOP_ALLOW_STOP ++ 2 -> STM32_PM_CSTOP_ALLOW_LP_STOP ++ 3 -> STM32_PM_CSTOP_ALLOW_LPLV_STOP ++ 4 -> STM32_PM_CSTOP_ALLOW_STANDBY_DDR_SR ++ - modes for system_off ++ 6 -> STM32_PM_CSTOP_ALLOW_STANDBY_DDR_OFF ++ 7 -> STM32_PM_SHUTDOWN ++ ++Example: ++ ++pwr: pwr@50001000 { ++ compatible = "st,stm32mp1-pwr", "st,stm32-pwr", "syscon", "simple-mfd"; ++ reg = <0x50001000 0x400>; ++ ++ 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 = ; ++}; +diff --git a/docs/devicetree/bindings/power/st,stpmic1.txt b/docs/devicetree/bindings/power/st,stpmic1.txt +new file mode 100644 +index 0000000..54b64e2 +--- /dev/null ++++ b/docs/devicetree/bindings/power/st,stpmic1.txt +@@ -0,0 +1,132 @@ ++* STMicroelectronics STPMIC1 Power Management IC ++ ++Required parent device properties: ++- compatible: "st,stpmic1" ++- reg: The I2C slave address for the STPMIC1 chip. ++- interrupts: The interrupt lines the device is connected to. ++ The second interrupt is used for wake-up. ++- #interrupt-cells: Should be 2. ++- interrupt-controller: Describes the STPMIC1 as an interrupt ++ controller (has its own domain). Interrupt number are the following: ++ /* Interrupt Register 1 (0x50 for latch) */ ++ IT_SWOUT_R=0 ++ IT_SWOUT_F=1 ++ IT_VBUS_OTG_R=2 ++ IT_VBUS_OTG_F=3 ++ IT_WAKEUP_R=4 ++ IT_WAKEUP_F=5 ++ IT_PONKEY_R=6 ++ IT_PONKEY_F=7 ++ /* Interrupt Register 2 (0x51 for latch) */ ++ IT_OVP_BOOST=8 ++ IT_OCP_BOOST=9 ++ IT_OCP_SWOUT=10 ++ IT_OCP_OTG=11 ++ IT_CURLIM_BUCK4=12 ++ IT_CURLIM_BUCK3=13 ++ IT_CURLIM_BUCK2=14 ++ IT_CURLIM_BUCK1=15 ++ /* Interrupt Register 3 (0x52 for latch) */ ++ IT_SHORT_SWOUT=16 ++ IT_SHORT_SWOTG=17 ++ IT_CURLIM_LDO6=18 ++ IT_CURLIM_LDO5=19 ++ IT_CURLIM_LDO4=20 ++ IT_CURLIM_LDO3=21 ++ IT_CURLIM_LDO2=22 ++ IT_CURLIM_LDO1=23 ++ /* Interrupt Register 3 (0x52 for latch) */ ++ IT_SWIN_R=24 ++ IT_SWIN_F=25 ++ IT_RESERVED_1=26 ++ IT_RESERVED_2=27 ++ IT_VINLOW_R=28 ++ IT_VINLOW_F=29 ++ IT_TWARN_R=30 ++ IT_TWARN_F=31 ++ ++Optional parent device properties: ++- st,main-control-register: ++ -bit 1: Power cycling will be performed on turn OFF condition ++ -bit 2: PWRCTRL is functional ++ -bit 3: PWRCTRL active high ++- st,pads-pull-register: ++ -bit 1: WAKEUP pull down is not active ++ -bit 2: PWRCTRL pull up is active ++ -bit 3: PWRCTRL pull down is active ++ -bit 4: WAKEUP detector is disabled ++- st,vin-control-register: ++ -bit 0: VINLOW monitoring is enabled ++ -bit [1...3]: VINLOW rising threshold ++ 000 VINOK_f + 50mV ++ 001 VINOK_f + 100mV ++ 010 VINOK_f + 150mV ++ 011 VINOK_f + 200mV ++ 100 VINOK_f + 250mV ++ 101 VINOK_f + 300mV ++ 110 VINOK_f + 350mV ++ 111 VINOK_f + 400mV ++ -bit [4...5]: VINLOW hyst ++ 00 100mV ++ 01 200mV ++ 10 300mV ++ 11 400mV ++ -bit 6: SW_OUT detector is disabled ++ -bit 7: SW_IN detector is enabled. ++- st,usb-control-register: ++ -bit 3: SW_OUT current limit ++ 0: 600mA ++ 1: 1.1A ++ -bit 4: VBUS_OTG discharge is enabled ++ -bit 5: SW_OUT discharge is enabled ++ -bit 6: VBUS_OTG detection is enabled ++ -bit 7: BOOST_OVP is disabled ++ ++STPMIC1 consists in a varied group of sub-devices. ++Each sub-device binding is be described in own documentation file. ++ ++Device Description ++------ ------------ ++st,stpmic1-onkey : Power on key, see ../input/st,stpmic1-onkey.txt ++st,stpmic1-regulators : Regulators, see ../regulator/st,stpmic1-regulator.txt ++st,stpmic1-wdt : Watchdog, see ../watchdog/st,stpmic1-wdt.txt ++ ++Example: ++ ++pmic: pmic@33 { ++ compatible = "st,stpmic1"; ++ reg = <0x33>; ++ interrupt-parent = <&gpioa>; ++ interrupts = <0 2>; ++ st,main-control-register=<0x0c>; ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ ++ onkey { ++ compatible = "st,stpmic1-onkey"; ++ interrupts = ,; ++ interrupt-names = "onkey-falling", "onkey-rising"; ++ power-off-time-sec = <10>; ++ }; ++ ++ watchdog { ++ compatible = "st,stpmic1-wdt"; ++ }; ++ ++ regulators { ++ compatible = "st,stpmic1-regulators"; ++ ++ vdd_core: buck1 { ++ regulator-name = "vdd_core"; ++ regulator-boot-on; ++ regulator-min-microvolt = <700000>; ++ regulator-max-microvolt = <1200000>; ++ }; ++ vdd: buck3 { ++ regulator-name = "vdd"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ regulator-boot-on; ++ regulator-pull-down; ++ }; ++ }; +diff --git a/docs/devicetree/bindings/reset/st,stm32mp1-rcc.txt b/docs/devicetree/bindings/reset/st,stm32mp1-rcc.txt +new file mode 100644 +index 0000000..b4edaf7 +--- /dev/null ++++ b/docs/devicetree/bindings/reset/st,stm32mp1-rcc.txt +@@ -0,0 +1,6 @@ ++STMicroelectronics STM32MP1 Peripheral Reset Controller ++======================================================= ++ ++The RCC IP is both a reset and a clock controller. ++ ++Please see Documentation/devicetree/bindings/clock/st,stm32mp1-rcc.txt +diff --git a/docs/devicetree/bindings/rng/st,stm32-rng.txt b/docs/devicetree/bindings/rng/st,stm32-rng.txt +new file mode 100644 +index 0000000..3c613d7 +--- /dev/null ++++ b/docs/devicetree/bindings/rng/st,stm32-rng.txt +@@ -0,0 +1,23 @@ ++STMicroelectronics STM32 HW RNG ++=============================== ++ ++The STM32 hardware random number generator is a simple fixed purpose IP and ++is fully separated from other crypto functions. ++ ++Required properties: ++ ++- compatible : Should be "st,stm32-rng" ++- reg : Should be register base and length as documented in the datasheet ++- clocks : The clock needed to enable the RNG ++ ++Optional properties: ++- resets : The reset to properly start RNG ++- clock-error-detect : Enable the clock detection management ++ ++Example: ++ ++ rng: rng@50060800 { ++ compatible = "st,stm32-rng"; ++ reg = <0x50060800 0x400>; ++ clocks = <&rcc 0 38>; ++ }; +diff --git a/docs/devicetree/bindings/serial/st,stm32-usart.txt b/docs/devicetree/bindings/serial/st,stm32-usart.txt +new file mode 100644 +index 0000000..08b4990 +--- /dev/null ++++ b/docs/devicetree/bindings/serial/st,stm32-usart.txt +@@ -0,0 +1,88 @@ ++* STMicroelectronics STM32 USART ++ ++Required properties: ++- compatible: can be either: ++ - "st,stm32-uart", ++ - "st,stm32f7-uart", ++ - "st,stm32h7-uart". ++ depending is compatible with stm32(f4), stm32f7 or stm32h7. ++- reg: The address and length of the peripheral registers space ++- interrupts: ++ - The interrupt line for the USART instance, ++ - An optional wake-up interrupt. ++- interrupt-names: Contains "event" for the USART interrupt line. ++- clocks: The input clock of the USART instance ++ ++Optional properties: ++- resets: Must contain the phandle to the reset controller. ++- pinctrl-names: Set to "default". An additional "sleep" state can be defined ++ to set pins in sleep state when in low power. In case the device is used as ++ a wakeup source, "idle" state is defined in order to keep RX pin active. ++ For a console device, an optional state "no_console_suspend" can be defined ++ to enable console messages during suspend. Typically, "no_console_suspend" and ++ "default" states can refer to the same pin configuration. ++- pinctrl-n: Phandle(s) pointing to pin configuration nodes. ++ For Pinctrl properties see ../pinctrl/pinctrl-bindings.txt ++- st,hw-flow-ctrl: bool flag to enable hardware flow control. ++- rs485-rts-delay, rs485-rx-during-tx, rs485-rts-active-low, ++ linux,rs485-enabled-at-boot-time: see rs485.txt. ++- dmas: phandle(s) to DMA controller node(s). Refer to stm32-dma.txt ++- dma-names: "rx" and/or "tx" ++- wakeup-source: bool flag to indicate this device has wakeup capabilities ++- interrupt-names : Should contain "wakeup" if optional wake-up interrupt is ++ used. ++ ++Note for dma using: ++- "tx" dma can be used without any constraint since it uses single ++dma transfers. ++- "rx" dma using requires some attention: ++ 1) if you cannot anticipate the length of your received packets ++ and if your usart device embeds an internal fifo, then DON'T use ++ dma mode. ++ 2) if you enable dma mode WITHOUT mdma intermediate copy (cf. ++ stm32-dma.txt), then the availability of the received data will ++ depend on the dma driver policy and it may be delayed until dma ++ internal fifo is full. The usart driver will see this checking ++ the dma residue when rx interrupt (RXNE or RTO) occurs. ++ 3) if you enable dma mode WITH mdma intermediate copy (cf. ++ stm32-dma.txt) then the usart driver will never see the dma ++ residue becoming smaller than RX_BUF_P but it will get its ++ rx dma complete callback called when the cyclic transfer period ++ (RX_BUF_P) is reached. ++The three possibilities above are ordered from the most cpu time ++consuming one to the least one. The counterpart of this optimisation ++is the reception granularity achievable by the usart driver, from ++one byte up to RX_BUF_P. ++ ++Examples: ++usart4: serial@40004c00 { ++ compatible = "st,stm32-uart"; ++ reg = <0x40004c00 0x400>; ++ interrupts = <52>; ++ clocks = <&clk_pclk1>; ++ pinctrl-names = "default", "sleep", "idle", "no_console_suspend"; ++ pinctrl-0 = <&pinctrl_usart4>; ++ pinctrl-1 = <&pinctrl_usart4_sleep>; ++ pinctrl-2 = <&pinctrl_usart4_idle>; ++ pinctrl-3 = <&pinctrl_usart4>; ++}; ++ ++usart2: serial@40004400 { ++ compatible = "st,stm32-uart"; ++ reg = <0x40004400 0x400>; ++ interrupts = <38>; ++ clocks = <&clk_pclk1>; ++ st,hw-flow-ctrl; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_usart2 &pinctrl_usart2_rtscts>; ++}; ++ ++usart1: serial@40011000 { ++ compatible = "st,stm32-uart"; ++ reg = <0x40011000 0x400>; ++ interrupts = <37>; ++ clocks = <&rcc 0 164>; ++ dmas = <&dma2 2 4 0x414 0x0>, ++ <&dma2 7 4 0x414 0x0>; ++ dma-names = "rx", "tx"; ++}; +diff --git a/docs/devicetree/bindings/soc/st,stm32-etzpc.txt b/docs/devicetree/bindings/soc/st,stm32-etzpc.txt +new file mode 100644 +index 0000000..a2ac263 +--- /dev/null ++++ b/docs/devicetree/bindings/soc/st,stm32-etzpc.txt +@@ -0,0 +1,56 @@ ++STM32 ETZPC ++--------------------------------- ++ ++Required properties: ++- compatible: should be "st,stm32-etzpc" ++- reg: physical base address and length of the registers set for the device ++- clocks: reference to the clock entry ++ ++Optional property: ++- st,decprot: Configure option to properly set firewall for IPs. ++ ++Examples: ++etzpc: etzpc@5C007000 { ++ compatible = "st,stm32-etzpc"; ++ reg = <0x5C007000 0x400>; ++ clocks = <&rcc TZPC>; ++ status = "disabled"; ++ secure-status = "okay"; ++ }; ++ ++Firewall specifications ++======================= ++ ++DECPROT macro must be used to properly configure IP firewalling. It must ++specify ID, domain and locking register status. ++ ++The macro is defined in the binding header file [1]. ++ ++Example: ++ ... { ++ st,decprot = < ++ DECPROT(STM32MP1_ETZPC_I2C4_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) ++ DECPROT(STM32MP1_ETZPC_GPIOZ_ID, DECPROT_NS_RW, DECPROT_UNLOCK)>; ++ }; ++ ++Specify Peripheral IDs ++======================= ++ ++Each peripheral is identified with a specific ID. Each platform defines the ++identifiers relevant to that platform. Peripheral IDs are defined in [1]. ++ ++Specify domain ++============== ++Firewall controls peripherals in specific domains: ++ ++DECPROT_S_RW 0x0 -> Read/write Secure ++DECPROT_NS_R_S_W 0x1 -> Non secure read / Read/write Secure ++DECPROT_MCU_ISOLATION 0x2 -> MCU access only ++DECPROT_NS_RW 0x3 -> Non secure read/write ++ ++ ++[1] include/dt-bindings/soc/st,stm32-etzpc.h ++ +diff --git a/docs/devicetree/bindings/soc/st,stm32-romem.txt b/docs/devicetree/bindings/soc/st,stm32-romem.txt +new file mode 100644 +index 0000000..fbff52e +--- /dev/null ++++ b/docs/devicetree/bindings/soc/st,stm32-romem.txt +@@ -0,0 +1,31 @@ ++STMicroelectronics STM32 Factory-programmed data device tree bindings ++ ++This represents STM32 Factory-programmed read only non-volatile area: locked ++flash, OTP, read-only HW regs... This contains various information such as: ++analog calibration data for temperature sensor (e.g. TS_CAL1, TS_CAL2), ++internal vref (VREFIN_CAL), unique device ID... ++ ++Required properties: ++- compatible: Should be one of: ++ "st,stm32-romem" ++ "st,stm32mp15-bsec" ++- reg: Offset and length of factory-programmed area. ++- #address-cells: Should be '<1>'. ++- #size-cells: Should be '<1>'. ++ ++Optional Data cells: ++- Must be child nodes as described in nvmem.txt. ++ ++Example on stm32f4: ++ romem: nvmem@1fff7800 { ++ compatible = "st,stm32-romem"; ++ reg = <0x1fff7800 0x400>; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ++ /* Data cells: ts_cal1 at 0x1fff7a2c */ ++ ts_cal1: calib@22c { ++ reg = <0x22c 0x2>; ++ }; ++ ... ++ }; +diff --git a/docs/devicetree/bindings/soc/st,stm32-stgen.txt b/docs/devicetree/bindings/soc/st,stm32-stgen.txt +new file mode 100644 +index 0000000..dbd962e +--- /dev/null ++++ b/docs/devicetree/bindings/soc/st,stm32-stgen.txt +@@ -0,0 +1,18 @@ ++STMicroelectronics STM32 STGEN ++=============================== ++ ++The STM32 System Generic Counter generate a time count value. This ++is a 64 bits wide counter. ++ ++Required properties: ++ ++- compatible : Should be "st,stm32-stgen" ++- reg : Should be register base and length as documented in the datasheet ++ ++Example: ++ ++ stgen: stgen@5C008000 { ++ compatible = "st,stm32-stgen"; ++ reg = <0x5C008000 0x1000>; ++ status = "okay"; ++ }; +diff --git a/docs/devicetree/bindings/soc/st,stm32-tamp.txt b/docs/devicetree/bindings/soc/st,stm32-tamp.txt +new file mode 100644 +index 0000000..4d21c6b +--- /dev/null ++++ b/docs/devicetree/bindings/soc/st,stm32-tamp.txt +@@ -0,0 +1,22 @@ ++STM32 TAMPER ++--------------------------------- ++ ++Required properties: ++- compatible: should be "st,stm32-tamp" ++- reg: physical base address and length of the registers set for the device ++- clocks: reference to the clock entry ++- secure-status: Required to properly disable/enable secure IP ++ ++Optional property: ++- st,out3-pc13: Configure option register to map OUT3 on PC13 ++- wakeup-source : Configure tamp as wakeup-src ++ ++Examples: ++tamp: tamp@5C00A000 { ++ compatible = "st,stm32-tamp"; ++ reg = <0x5C00A000 0x100>; ++ clocks = <&rcc_clk RTCAPB>; ++ st,out3-pc13; ++ wakeup-source; ++ secure-status = "okay"; ++}; +diff --git a/docs/devicetree/bindings/watchdog/st,stm32-iwdg.txt b/docs/devicetree/bindings/watchdog/st,stm32-iwdg.txt +new file mode 100644 +index 0000000..2453603 +--- /dev/null ++++ b/docs/devicetree/bindings/watchdog/st,stm32-iwdg.txt +@@ -0,0 +1,28 @@ ++STM32 Independent WatchDoG (IWDG) ++--------------------------------- ++ ++Required properties: ++- compatible: should be "st,stm32mp1-iwdg". ++- reg: physical base address and length of the registers set for the device. ++- clocks: reference to the clock entry lsi. Additional pclk clock entry. ++ is required only for st,stm32mp1-iwdg. ++- clock-names: name of the clocks used. ++ "pclk", "lsi" for st,stm32mp1-iwdg. ++ ++Optional properties: ++- timeout-sec: Watchdog timeout value in seconds. ++- secure-timeout-sec: Watchdog early timeout management in seconds. ++- stm32,enable-on-stop: Keep watchdog enable during stop. ++- stm32,enable-on-standby: Keep watchdog enable durung standby. ++- secure-status: Required to properly enable/disable secure IP. ++ ++Examples: ++ ++iwdg2: iwdg@5a002000 { ++ compatible = "st,stm32mp1-iwdg"; ++ reg = <0x5a002000 0x400>; ++ clocks = <&rcc IWDG2>, <&clk_lsi>; ++ clock-names = "pclk", "lsi"; ++ instance = <2>; ++ timeout-sec = <30>; ++}; +diff --git a/docs/plat/stm32mp1.rst b/docs/plat/stm32mp1.rst +index 9e731a4..10ad00e 100644 +--- a/docs/plat/stm32mp1.rst ++++ b/docs/plat/stm32mp1.rst +@@ -76,7 +76,23 @@ To build: + .. code:: bash + + make CROSS_COMPILE=arm-linux-gnueabihf- PLAT=stm32mp1 ARCH=aarch32 ARM_ARCH_MAJOR=7 AARCH32_SP=sp_min ++ cd ++ make stm32mp15_trusted_defconfig ++ make DEVICE_TREE=stm32mp157c_ev1 all ++ ./tools/mkimage -T stm32image -a 0xC0100000 -e 0xC0100000 -d u-boot.bin u-boot.stm32 + + The following build options are supported: + + - ``ENABLE_STACK_PROTECTOR``: To enable the stack protection. ++ ++ ++Populate SD-card ++---------------- ++ ++The SD-card has to be formated with GPT. ++It should contain at least those partitions: ++ ++- fsbl: to copy the tf-a-stm32mp157c-ev1.stm32 binary ++- ssbl: to copy the u-boot.stm32 binary ++ ++Usually, two copies of fsbl are used (fsbl1 and fsbl2) instead of one partition fsbl. +diff --git a/docs/porting-guide.rst b/docs/porting-guide.rst +index 1667cce..bef4af6 100644 +--- a/docs/porting-guide.rst ++++ b/docs/porting-guide.rst +@@ -2554,8 +2554,13 @@ NOTE: This section assumes that your platform is enabling the MULTI_CONSOLE_API + flag in its platform.mk. Not using this flag is deprecated for new platforms. + + BL31 implements a crash reporting mechanism which prints the various registers +-of the CPU to enable quick crash analysis and debugging. By default, the +-definitions in ``plat/common/aarch64/platform\_helpers.S`` will cause the crash ++of the CPU to enable quick crash analysis and debugging. This mechanism relies ++on the platform implementating ``plat_crash_console_init``, ++``plat_crash_console_putc`` and ``plat_crash_console_flush``. ++ ++The file ``plat/common/aarch64/crash_console_helpers.S`` contains sample ++implementation of all of them. Platforms may include this file to their ++makefiles in order to benefit from them. By default, they will cause the crash + output to be routed over the normal console infrastructure and get printed on + consoles configured to output in crash state. ``console_set_scope()`` can be + used to control whether a console is used for crash output. +@@ -2565,8 +2570,12 @@ normal boot console can be set up), platforms may want to control crash output + more explicitly. For these, the following functions can be overridden by + platform code. They are executed outside of a C environment and without a stack. + +-Function : plat\_crash\_console\_init +-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ++If this behaviour is not desirable, the platform may implement functions that ++redirect the prints to the console driver (``console_xxx_core_init``, etc). Most ++platforms (including Arm platforms) do this and they can be used as an example. ++ ++Function : plat\_crash\_console\_init [mandatory] ++~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + :: + +@@ -2577,9 +2586,10 @@ This API is used by the crash reporting mechanism to initialize the crash + console. It must only use the general purpose registers x0 through x7 to do the + initialization and returns 1 on success. + +-If you are trying to debug crashes before the console driver would normally get +-registered, you can use this to register a driver from assembly with hardcoded +-parameters. For example, you could register the 16550 driver like this: ++When using the sample implementation, if you are trying to debug crashes before ++the console driver would normally get registered, you can use this to register a ++driver from assembly with hardcoded parameters. For example, you could register ++the 16550 driver like this: + + :: + +@@ -2595,11 +2605,11 @@ parameters. For example, you could register the 16550 driver like this: + b console_16550_register /* tail call, returns 1 on success */ + endfunc plat_crash_console_init + +-If you're trying to debug crashes in BL1, you can call the console_xxx_core_init +-function exported by some console drivers from here. ++If you're trying to debug crashes in BL1, you can call the ++``console_xxx_core_init`` function exported by some console drivers from here. + +-Function : plat\_crash\_console\_putc +-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ++Function : plat\_crash\_console\_putc [mandatory] ++~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + :: + +@@ -2612,13 +2622,13 @@ x2 to do its work. The parameter and the return value are in general purpose + register x0. + + If you have registered a normal console driver in ``plat_crash_console_init``, +-you can keep the default implementation here (which calls ``console_putc()``). ++you can keep the sample implementation here (which calls ``console_putc()``). + +-If you're trying to debug crashes in BL1, you can call the console_xxx_core_putc +-function exported by some console drivers from here. ++If you're trying to debug crashes in BL1, you can call the ++``console_xxx_core_putc`` function exported by some console drivers from here. + +-Function : plat\_crash\_console\_flush +-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ++Function : plat\_crash\_console\_flush [mandatory] ++~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + :: + +@@ -2631,7 +2641,7 @@ registers x0 through x5 to do its work. The return value is 0 on successful + completion; otherwise the return value is -1. + + If you have registered a normal console driver in ``plat_crash_console_init``, +-you can keep the default implementation here (which calls ``console_flush()``). ++you can keep the sample implementation here (which calls ``console_flush()``). + + If you're trying to debug crashes in BL1, you can call the console_xx_core_flush + function exported by some console drivers from here. +diff --git a/drivers/arm/pl011/aarch32/pl011_console.S b/drivers/arm/pl011/aarch32/pl011_console.S +index 3718fff..edadaa4 100644 +--- a/drivers/arm/pl011/aarch32/pl011_console.S ++++ b/drivers/arm/pl011/aarch32/pl011_console.S +@@ -1,10 +1,13 @@ + /* +- * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved. ++ * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + #include + #include ++#include ++#define USE_FINISH_CONSOLE_REG_2 ++#include + #include + + /* +@@ -13,10 +16,18 @@ + */ + #include "../../../console/aarch32/console.S" + +- .globl console_core_init +- .globl console_core_putc +- .globl console_core_getc +- .globl console_core_flush ++ /* ++ * "core" functions are low-level implementations that don't require ++ * writeable memory and are thus safe to call in BL1 crash context. ++ */ ++ .globl console_pl011_core_init ++ .globl console_pl011_core_putc ++ .globl console_pl011_core_getc ++ .globl console_pl011_core_flush ++ ++ .globl console_pl011_putc ++ .globl console_pl011_getc ++ .globl console_pl011_flush + + + /* ----------------------------------------------- +@@ -33,7 +44,7 @@ + * Clobber list : r1, r2, r3 + * ----------------------------------------------- + */ +-func console_core_init ++func console_pl011_core_init + /* Check the input base address */ + cmp r0, #0 + beq core_init_fail +@@ -73,7 +84,53 @@ func console_core_init + core_init_fail: + mov r0, #0 + bx lr +-endfunc console_core_init ++endfunc console_pl011_core_init ++ ++#if MULTI_CONSOLE_API ++ .globl console_pl011_register ++ ++ /* ------------------------------------------------------- ++ * init console_pl011_register(console_pl011_t *console, ++ * uintptr_t base, uint32_t clk, uint32_t baud) ++ * Function to initialize and register a new PL011 ++ * console. Storage passed in for the console struct ++ * *must* be persistent (i.e. not from the stack). ++ * In: r0 - UART register base address ++ * r1 - UART clock in Hz ++ * r2 - Baud rate ++ * r3 - pointer to empty console_pl011_t struct ++ * Out: return 1 on success, 0 on error ++ * Clobber list : r0, r1, r2 ++ * ------------------------------------------------------- ++ */ ++func console_pl011_register ++ push {r4, lr} ++ mov r4, r3 ++ cmp r4, #0 ++ beq register_fail ++ str r0, [r4, #CONSOLE_T_PL011_BASE] ++ ++ bl console_pl011_core_init ++ cmp r0, #0 ++ beq register_fail ++ ++ mov r0, r4 ++ pop {r4, lr} ++ finish_console_register pl011 putc=1, getc=1, flush=1 ++ ++register_fail: ++ pop {r4, pc} ++endfunc console_pl011_register ++#else ++ .globl console_core_init ++ .globl console_core_putc ++ .globl console_core_getc ++ .globl console_core_flush ++ .equ console_core_init, console_pl011_core_init ++ .equ console_core_putc, console_pl011_core_putc ++ .equ console_core_getc, console_pl011_core_getc ++ .equ console_core_flush, console_pl011_core_flush ++#endif + + /* -------------------------------------------------------- + * int console_core_putc(int c, uintptr_t base_addr) +@@ -85,7 +142,7 @@ endfunc console_core_init + * Clobber list : r2 + * -------------------------------------------------------- + */ +-func console_core_putc ++func console_pl011_core_putc + /* Check the input parameter */ + cmp r1, #0 + beq putc_error +@@ -109,7 +166,26 @@ func console_core_putc + putc_error: + mov r0, #-1 + bx lr +-endfunc console_core_putc ++endfunc console_pl011_core_putc ++ ++ /* -------------------------------------------------------- ++ * int console_pl011_putc(int c, console_pl011_t *console) ++ * Function to output a character over the console. It ++ * returns the character printed on success or -1 on error. ++ * In: r0 - character to be printed ++ * r1 - pointer to console_t structure ++ * Out : return -1 on error else return character. ++ * Clobber list: r2 ++ * ------------------------------------------------------- ++ */ ++func console_pl011_putc ++#if ENABLE_ASSERTIONS ++ cmp r1, #0 ++ ASM_ASSERT(ne) ++#endif /* ENABLE_ASSERTIONS */ ++ ldr r1, [r1, #CONSOLE_T_PL011_BASE] ++ b console_pl011_core_putc ++endfunc console_pl011_putc + + /* --------------------------------------------- + * int console_core_getc(uintptr_t base_addr) +@@ -120,7 +196,7 @@ endfunc console_core_putc + * Clobber list : r0, r1 + * --------------------------------------------- + */ +-func console_core_getc ++func console_pl011_core_getc + cmp r0, #0 + beq getc_error + 1: +@@ -134,7 +210,26 @@ func console_core_getc + getc_error: + mov r0, #-1 + bx lr +-endfunc console_core_getc ++endfunc console_pl011_core_getc ++ ++ /* ------------------------------------------------ ++ * int console_pl011_getc(console_pl011_t *console) ++ * Function to get a character from the console. ++ * It returns the character grabbed on success ++ * or -1 if no character is available. ++ * In : r0 - pointer to console_t structure ++ * Out: r0 - character if available, else -1 ++ * Clobber list: r0, r1 ++ * ------------------------------------------------ ++ */ ++func console_pl011_getc ++#if ENABLE_ASSERTIONS ++ cmp r0, #0 ++ ASM_ASSERT(ne) ++#endif /* ENABLE_ASSERTIONS */ ++ ldr r0, [r0, #CONSOLE_T_PL011_BASE] ++ b console_pl011_core_getc ++endfunc console_pl011_getc + + /* --------------------------------------------- + * int console_core_flush(uintptr_t base_addr) +@@ -145,7 +240,7 @@ endfunc console_core_getc + * Clobber list : r0, r1 + * --------------------------------------------- + */ +-func console_core_flush ++func console_pl011_core_flush + cmp r0, #0 + beq flush_error + +@@ -160,4 +255,22 @@ func console_core_flush + flush_error: + mov r0, #-1 + bx lr +-endfunc console_core_flush ++endfunc console_pl011_core_flush ++ ++ /* --------------------------------------------- ++ * int console_pl011_flush(console_pl011_t *console) ++ * Function to force a write of all buffered ++ * data that hasn't been output. ++ * In : r0 - pointer to console_t structure ++ * Out : return -1 on error else return 0. ++ * Clobber list: r0, r1 ++ * --------------------------------------------- ++ */ ++func console_pl011_flush ++#if ENABLE_ASSERTIONS ++ cmp r0, #0 ++ ASM_ASSERT(ne) ++#endif /* ENABLE_ASSERTIONS */ ++ ldr r0, [r0, #CONSOLE_T_PL011_BASE] ++ b console_pl011_core_flush ++endfunc console_pl011_flush +diff --git a/drivers/arm/pl011/aarch64/pl011_console.S b/drivers/arm/pl011/aarch64/pl011_console.S +index 448501a..c4d51c8 100644 +--- a/drivers/arm/pl011/aarch64/pl011_console.S ++++ b/drivers/arm/pl011/aarch64/pl011_console.S +@@ -6,6 +6,7 @@ + #include + #include + #include ++#define USE_FINISH_CONSOLE_REG_2 + #include + #include + +@@ -109,7 +110,7 @@ func console_pl011_register + + mov x0, x6 + mov x30, x7 +- finish_console_register pl011 ++ finish_console_register pl011 putc=1, getc=1, flush=1 + + register_fail: + ret x7 +diff --git a/drivers/arm/tzc/tzc400.c b/drivers/arm/tzc/tzc400.c +index db4f88a..1849e5a 100644 +--- a/drivers/arm/tzc/tzc400.c ++++ b/drivers/arm/tzc/tzc400.c +@@ -68,6 +68,59 @@ DEFINE_TZC_COMMON_WRITE_REGION_ID_ACCESS(400, 400) + DEFINE_TZC_COMMON_CONFIGURE_REGION0(400) + DEFINE_TZC_COMMON_CONFIGURE_REGION(400) + ++static inline void tzc400_clear_it(long base, uint32_t filter) ++{ ++ mmio_write_32(base + INT_CLEAR, 1 << filter); ++} ++ ++static inline uint32_t tzc400_get_int_by_filter(long base, uint32_t filter) ++{ ++ return (mmio_read_32(base + INT_STATUS) & (1 << filter)); ++} ++ ++#if DEBUG ++static long tzc400_get_fail_address(long base, uint32_t filter) ++{ ++ long fail_address = 0; ++ ++ if (sizeof(long) == sizeof(uint32_t)) { ++ if (filter) { ++ fail_address = mmio_read_32(base + ++ FAIL_ADDRESS_LOW_OFF + ++ FILTER_OFFSET); ++ } else { ++ fail_address = mmio_read_32(base + ++ FAIL_ADDRESS_LOW_OFF); ++ } ++ } else { ++ if (filter) { ++ fail_address = mmio_read_32(base + ++ FAIL_ADDRESS_LOW_OFF + ++ FILTER_OFFSET) + ++ mmio_read_32(base + ++ FAIL_ADDRESS_HIGH_OFF + ++ FILTER_OFFSET); ++ } else { ++ fail_address = mmio_read_32(base + ++ FAIL_ADDRESS_LOW_OFF) + ++ mmio_read_32(base + ++ FAIL_ADDRESS_HIGH_OFF); ++ } ++ } ++ return fail_address; ++} ++#endif ++ ++static inline uint32_t tzc400_get_fail_control(long base, uint32_t filter) ++{ ++ if (filter) { ++ return mmio_read_32(base + FAIL_CONTROL_OFF + ++ FILTER_OFFSET); ++ } else { ++ return mmio_read_32(base + FAIL_CONTROL_OFF); ++ } ++} ++ + static unsigned int _tzc400_get_gate_keeper(uintptr_t base, + unsigned int filter) + { +@@ -236,3 +289,79 @@ void tzc400_disable_filters(void) + for (filter = 0; filter < tzc400.num_filters; filter++) + _tzc400_set_gate_keeper(tzc400.base, filter, 0); + } ++ ++void tzc400_clear_all_interrupts(void) ++{ ++ unsigned int filter; ++ ++ assert(tzc400.base); ++ for (filter = 0; filter < tzc400.num_filters; filter++) { ++ mmio_write_32(tzc400.base + INT_CLEAR, 1 << filter); ++ } ++} ++ ++int tzc400_is_pending_interrupt(void) ++{ ++ unsigned int filter; ++ ++ assert(tzc400.base); ++ for (filter = 0; filter < tzc400.num_filters; filter++) { ++ if (mmio_read_32(tzc400.base + INT_STATUS) & (1 << filter)) { ++ return 1; ++ } ++ } ++ return 0; ++} ++ ++void tzc400_it_handler(void) ++{ ++ uint32_t filter = 0; ++ uint32_t filter_it_pending = tzc400.num_filters; ++ uint32_t control_fail = 0; ++#if DEBUG ++ long address_fail = 0; ++#endif ++ ++ assert(tzc400.base); ++ ++ /* first display information conerning the fault access */ ++ for (filter = 0; (filter < tzc400.num_filters) && ++ (filter_it_pending == tzc400.num_filters); filter++) { ++ if (tzc400_get_int_by_filter(tzc400.base, filter)) ++ filter_it_pending = filter; ++ } ++ ++ if (filter_it_pending == tzc400.num_filters) { ++ ERROR("Error no it pending!!"); ++ panic(); ++ } ++ ++#if DEBUG ++ address_fail = tzc400_get_fail_address(tzc400.base, filter_it_pending); ++ ERROR("Illegal access to 0x%lx in :\n",address_fail); ++#endif ++ ++ control_fail = tzc400_get_fail_control(tzc400.base, filter_it_pending); ++ ++ ++ ++ if ((control_fail & FAIL_CONTROL_NS_SHIFT) == FAIL_CONTROL_NS_SECURE) { ++ ERROR("\tSecure\n"); ++ } else { ++ ERROR("\tNo Secure\n"); ++ } ++ ++ if ((control_fail & FAIL_CONTROL_PRIV_SHIFT) == FAIL_CONTROL_PRIV_PRIV) { ++ ERROR("\tPrivilege\n"); ++ } else { ++ ERROR("\tUnprivilege\n"); ++ } ++ ++ if ((control_fail & FAIL_CONTROL_DIR_SHIFT) == FAIL_CONTROL_DIR_READ) { ++ ERROR("\tRead\n"); ++ } else { ++ ERROR("\tWrite\n"); ++ } ++ ++ tzc400_clear_it(tzc400.base, filter_it_pending); ++} +diff --git a/drivers/cadence/uart/aarch64/cdns_console.S b/drivers/cadence/uart/aarch64/cdns_console.S +index 6732631..116c9d8 100644 +--- a/drivers/cadence/uart/aarch64/cdns_console.S ++++ b/drivers/cadence/uart/aarch64/cdns_console.S +@@ -7,6 +7,8 @@ + #include + #include + #include ++#define USE_FINISH_CONSOLE_REG_2 ++#include + + /* + * "core" functions are low-level implementations that don't require +@@ -76,7 +78,7 @@ func console_cdns_register + + mov x0, x6 + mov x30, v7 +- finish_console_register cdns ++ finish_console_register cdns putc=1, getc=1, flush=1 + + register_fail: + ret x7 +diff --git a/drivers/console/aarch32/console.S b/drivers/console/aarch32/console.S +index a3c6546..f909609 100644 +--- a/drivers/console/aarch32/console.S ++++ b/drivers/console/aarch32/console.S +@@ -3,104 +3,9 @@ + * + * SPDX-License-Identifier: BSD-3-Clause + */ +-#include + +- .globl console_init +- .globl console_uninit +- .globl console_putc +- .globl console_getc +- .globl console_flush +- +- /* +- * The console base is in the data section and not in .bss +- * even though it is zero-init. In particular, this allows +- * the console functions to start using this variable before +- * the runtime memory is initialized for images which do not +- * need to copy the .data section from ROM to RAM. +- */ +-.section .data.console_base ; .align 2 +- console_base: .word 0x0 +- +- /* ----------------------------------------------- +- * int console_init(uintptr_t base_addr, +- * unsigned int uart_clk, unsigned int baud_rate) +- * Function to initialize the console without a +- * C Runtime to print debug information. It saves +- * the console base to the data section. +- * In: r0 - console base address +- * r1 - Uart clock in Hz +- * r2 - Baud rate +- * out: return 1 on success else 0 on error +- * Clobber list : r1 - r3 +- * ----------------------------------------------- +- */ +-func console_init +- /* Check the input base address */ +- cmp r0, #0 +- beq init_fail +- ldr r3, =console_base +- str r0, [r3] +- b console_core_init +-init_fail: +- bx lr +-endfunc console_init +- +- /* ----------------------------------------------- +- * void console_uninit(void) +- * Function to finish the use of console driver. +- * It sets the console_base as NULL so that any +- * further invocation of `console_putc` or +- * `console_getc` APIs would return error. +- * ----------------------------------------------- +- */ +-func console_uninit +- mov r0, #0 +- ldr r3, =console_base +- str r0, [r3] +- bx lr +-endfunc console_uninit +- +- /* --------------------------------------------- +- * int console_putc(int c) +- * Function to output a character over the +- * console. It returns the character printed on +- * success or -1 on error. +- * In : r0 - character to be printed +- * Out : return -1 on error else return character. +- * Clobber list : r1, r2 +- * --------------------------------------------- +- */ +-func console_putc +- ldr r2, =console_base +- ldr r1, [r2] +- b console_core_putc +-endfunc console_putc +- +- /* --------------------------------------------- +- * int console_getc(void) +- * Function to get a character from the console. +- * It returns the character grabbed on success +- * or -1 on error. +- * Clobber list : r0, r1 +- * --------------------------------------------- +- */ +-func console_getc +- ldr r1, =console_base +- ldr r0, [r1] +- b console_core_getc +-endfunc console_getc +- +- /* --------------------------------------------- +- * int console_flush(void) +- * Function to force a write of all buffered +- * data that hasn't been output. It returns 0 +- * upon successful completion, otherwise it +- * returns -1. +- * Clobber list : r0, r1 +- * --------------------------------------------- +- */ +-func console_flush +- ldr r1, =console_base +- ldr r0, [r1] +- b console_core_flush +-endfunc console_flush ++ #if MULTI_CONSOLE_API ++ #include "multi_console.S" ++ #else ++ #include "deprecated_console.S" ++ #endif +diff --git a/drivers/console/aarch32/deprecated_console.S b/drivers/console/aarch32/deprecated_console.S +new file mode 100644 +index 0000000..f7e3c4f +--- /dev/null ++++ b/drivers/console/aarch32/deprecated_console.S +@@ -0,0 +1,112 @@ ++/* ++ * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved. ++ * ++ * SPDX-License-Identifier: BSD-3-Clause ++ */ ++#include ++ ++/* ++ * This is the common console core code for the deprecated single-console API. ++ * New platforms should set MULTI_CONSOLE_API=1 and not use this file. ++ */ ++#warning "Using deprecated console implementation. Please migrate to MULTI_CONSOLE_API" ++ ++ .globl console_init ++ .globl console_uninit ++ .globl console_putc ++ .globl console_getc ++ .globl console_flush ++ ++ /* ++ * The console base is in the data section and not in .bss ++ * even though it is zero-init. In particular, this allows ++ * the console functions to start using this variable before ++ * the runtime memory is initialized for images which do not ++ * need to copy the .data section from ROM to RAM. ++ */ ++.section .data.console_base ; .align 2 ++ console_base: .word 0x0 ++ ++ /* ----------------------------------------------- ++ * int console_init(uintptr_t base_addr, ++ * unsigned int uart_clk, unsigned int baud_rate) ++ * Function to initialize the console without a ++ * C Runtime to print debug information. It saves ++ * the console base to the data section. ++ * In: r0 - console base address ++ * r1 - Uart clock in Hz ++ * r2 - Baud rate ++ * out: return 1 on success else 0 on error ++ * Clobber list : r1 - r3 ++ * ----------------------------------------------- ++ */ ++func console_init ++ /* Check the input base address */ ++ cmp r0, #0 ++ beq init_fail ++ ldr r3, =console_base ++ str r0, [r3] ++ b console_core_init ++init_fail: ++ bx lr ++endfunc console_init ++ ++ /* ----------------------------------------------- ++ * void console_uninit(void) ++ * Function to finish the use of console driver. ++ * It sets the console_base as NULL so that any ++ * further invocation of `console_putc` or ++ * `console_getc` APIs would return error. ++ * ----------------------------------------------- ++ */ ++func console_uninit ++ mov r0, #0 ++ ldr r3, =console_base ++ str r0, [r3] ++ bx lr ++endfunc console_uninit ++ ++ /* --------------------------------------------- ++ * int console_putc(int c) ++ * Function to output a character over the ++ * console. It returns the character printed on ++ * success or -1 on error. ++ * In : r0 - character to be printed ++ * Out : return -1 on error else return character. ++ * Clobber list : r1, r2 ++ * --------------------------------------------- ++ */ ++func console_putc ++ ldr r2, =console_base ++ ldr r1, [r2] ++ b console_core_putc ++endfunc console_putc ++ ++ /* --------------------------------------------- ++ * int console_getc(void) ++ * Function to get a character from the console. ++ * It returns the character grabbed on success ++ * or -1 on error. ++ * Clobber list : r0, r1 ++ * --------------------------------------------- ++ */ ++func console_getc ++ ldr r1, =console_base ++ ldr r0, [r1] ++ b console_core_getc ++endfunc console_getc ++ ++ /* --------------------------------------------- ++ * int console_flush(void) ++ * Function to force a write of all buffered ++ * data that hasn't been output. It returns 0 ++ * upon successful completion, otherwise it ++ * returns -1. ++ * Clobber list : r0, r1 ++ * --------------------------------------------- ++ */ ++func console_flush ++ ldr r1, =console_base ++ ldr r0, [r1] ++ b console_core_flush ++endfunc console_flush +diff --git a/drivers/console/aarch32/multi_console.S b/drivers/console/aarch32/multi_console.S +new file mode 100644 +index 0000000..e23b20e +--- /dev/null ++++ b/drivers/console/aarch32/multi_console.S +@@ -0,0 +1,318 @@ ++/* ++ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. ++ * ++ * SPDX-License-Identifier: BSD-3-Clause ++ */ ++ ++#include ++#include ++#include ++ ++ .globl console_register ++ .globl console_unregister ++ .globl console_is_registered ++ .globl console_set_scope ++ .globl console_switch_state ++ .globl console_putc ++ .globl console_getc ++ .globl console_flush ++ ++ /* ++ * The console list pointer is in the data section and not in ++ * .bss even though it is zero-init. In particular, this allows ++ * the console functions to start using this variable before ++ * the runtime memory is initialized for images which do not ++ * need to copy the .data section from ROM to RAM. ++ */ ++.section .data.console_list ; .align 2 ++ console_list: .word 0x0 ++.section .data.console_state ; .align 0 ++ console_state: .byte CONSOLE_FLAG_BOOT ++ ++ /* ----------------------------------------------- ++ * int console_register(console_t *console) ++ * Function to insert a new console structure into ++ * the console list. Should usually be called by ++ * console__register implementations. The ++ * data structure passed will be taken over by the ++ * console framework and *MUST* be allocated in ++ * persistent memory (e.g. the data section). ++ * In : r0 - address of console_t structure ++ * Out: r0 - Always 1 (for easier tail calling) ++ * Clobber list: r0, r1 ++ * ----------------------------------------------- ++ */ ++func console_register ++ push {r6, lr} ++#if ENABLE_ASSERTIONS ++ /* Assert that r0 isn't a NULL pointer */ ++ cmp r0, #0 ++ ASM_ASSERT(ne) ++ /* Assert that the struct isn't in the stack */ ++ ldr r1, =__STACKS_START__ ++ cmp r0, r1 ++ blo not_on_stack ++ ldr r1, =__STACKS_END__ ++ cmp r0, r1 ++ ASM_ASSERT(hs) ++not_on_stack: ++ /* Assert that this struct isn't in the list */ ++ mov r1, r0 /* Preserve r0 and lr */ ++ bl console_is_registered ++ cmp r0, #0 ++ ASM_ASSERT(eq) ++ mov r0, r1 ++#endif /* ENABLE_ASSERTIONS */ ++ ldr r6, =console_list ++ ldr r1, [r6] /* R1 = first struct in list */ ++ str r0, [r6] /* list head = new console */ ++ str r1, [r0, #CONSOLE_T_NEXT] /* new console next ptr = R1 */ ++ mov r0, #1 ++ pop {r6, pc} ++endfunc console_register ++ ++ /* ----------------------------------------------- ++ * int console_unregister(console_t *console) ++ * Function to find a specific console in the list ++ * of currently active consoles and remove it. ++ * In: r0 - address of console_t struct to remove ++ * Out: r0 - removed address, or NULL if not found ++ * Clobber list: r0, r1 ++ * ----------------------------------------------- ++ */ ++func console_unregister ++#if ENABLE_ASSERTIONS ++ /* Assert that r0 isn't a NULL pointer */ ++ cmp r0, #0 ++ ASM_ASSERT(ne) ++#endif /* ENABLE_ASSERTIONS */ ++ push {r6} ++ ldr r6, =console_list /* R6 = ptr to first struct */ ++ ldr r1, [r6] /* R1 = first struct */ ++ ++unregister_loop: ++ cmp r1, #0 ++ beq unregister_not_found ++ cmp r0, r1 ++ beq unregister_found ++ ldr r6, [r6] /* R6 = next ptr of struct */ ++ ldr r1, [r6] /* R1 = next struct */ ++ b unregister_loop ++ ++unregister_found: ++ ldr r1, [r1] /* R1 = next struct */ ++ str r1, [r6] /* prev->next = cur->next */ ++ pop {r6} ++ bx lr ++ ++unregister_not_found: ++ mov r0, #0 /* return NULL if not found */ ++ pop {r6} ++ bx lr ++endfunc console_unregister ++ ++ /* ----------------------------------------------- ++ * int console_is_registered(console_t *console) ++ * Function to detect if a specific console is ++ * registered or not. ++ * In: r0 - address of console_t struct to remove ++ * Out: r0 - 1 if it is registered, 0 if not. ++ * Clobber list: r0 ++ * ----------------------------------------------- ++ */ ++func console_is_registered ++#if ENABLE_ASSERTIONS ++ /* Assert that r0 isn't a NULL pointer */ ++ cmp r0, #0 ++ ASM_ASSERT(ne) ++#endif /* ENABLE_ASSERTIONS */ ++ push {r6} ++ ldr r6, =console_list ++ ldr r6, [r6] /* R6 = first console struct */ ++check_registered_loop: ++ cmp r6, #0 /* Check if end of list */ ++ beq console_not_registered ++ cmp r0, r6 /* Check if the pointers are different */ ++ beq console_registered ++ ldr r6, [r6, #CONSOLE_T_NEXT] /* Get pointer to next struct */ ++ b check_registered_loop ++console_not_registered: ++ mov r0, #0 ++ pop {r6} ++ bx lr ++console_registered: ++ mov r0, #1 ++ pop {r6} ++ bx lr ++endfunc console_is_registered ++ ++ /* ----------------------------------------------- ++ * void console_switch_state(unsigned int new_state) ++ * Function to switch the current console state. ++ * The console state determines which of the ++ * registered consoles are actually used at a time. ++ * In : r0 - global console state to move to ++ * Clobber list: r0, r1 ++ * ----------------------------------------------- ++ */ ++func console_switch_state ++ ldr r1, =console_state ++ strb r0, [r1] ++ bx lr ++endfunc console_switch_state ++ ++ /* ----------------------------------------------- ++ * void console_set_scope(console_t *console, ++ * unsigned int scope) ++ * Function to update the states that a given console ++ * may be active in. ++ * In : r0 - pointer to console_t struct ++ * : r1 - new active state mask ++ * Clobber list: r0, r1, r2 ++ * ----------------------------------------------- ++ */ ++func console_set_scope ++#if ENABLE_ASSERTIONS ++ ands r2, r1, #~CONSOLE_FLAG_SCOPE_MASK ++ ASM_ASSERT(eq) ++#endif /* ENABLE_ASSERTIONS */ ++ ldr r2, [r0, #CONSOLE_T_FLAGS] ++ and r2, r2, #~CONSOLE_FLAG_SCOPE_MASK ++ orr r2, r2, r1 ++ str r2, [r0, #CONSOLE_T_FLAGS] ++ bx lr ++endfunc console_set_scope ++ ++ /* --------------------------------------------- ++ * int console_putc(int c) ++ * Function to output a character. Calls all ++ * active console's putc() handlers in succession. ++ * In : r0 - character to be printed ++ * Out: r0 - printed character on success, or < 0 ++ if at least one console had an error ++ * Clobber list : r0, r1, r2 ++ * --------------------------------------------- ++ */ ++func console_putc ++ push {r4-r6, lr} ++ mov r5, #ERROR_NO_VALID_CONSOLE /* R5 = current return value */ ++ mov r4, r0 /* R4 = character to print */ ++ ldr r6, =console_list ++ ldr r6, [r6] /* R6 = first console struct */ ++ ++putc_loop: ++ cmp r6, #0 ++ beq putc_done ++ ldr r1, =console_state ++ ldrb r1, [r1] ++ ldr r2, [r6, #CONSOLE_T_FLAGS] ++ tst r1, r2 ++ beq putc_continue ++ ldr r2, [r6, #CONSOLE_T_PUTC] ++ cmp r2, #0 ++ beq putc_continue ++ mov r0, r4 ++ mov r1, r6 ++ blx r2 ++ cmp r5, #ERROR_NO_VALID_CONSOLE /* update R5 if it's NOVALID */ ++ cmpne r0, #0 /* else update it if R0 < 0 */ ++ movlt r5, r0 ++putc_continue: ++ ldr r6, [r6] /* R6 = next struct */ ++ b putc_loop ++ ++putc_done: ++ mov r0, r5 ++ pop {r4-r6, pc} ++endfunc console_putc ++ ++ /* --------------------------------------------- ++ * int console_getc(void) ++ * Function to get a character from any console. ++ * Keeps looping through all consoles' getc() ++ * handlers until one of them returns a ++ * character, then stops iterating and returns ++ * that character to the caller. Will stop looping ++ * if all active consoles report real errors ++ * (other than just not having a char available). ++ * Out : r0 - read character, or < 0 on error ++ * Clobber list : r0, r1 ++ * --------------------------------------------- ++ */ ++func console_getc ++ push {r5-r6, lr} ++getc_try_again: ++ mov r5, #ERROR_NO_VALID_CONSOLE /* R5 = current return value */ ++ ldr r6, =console_list ++ ldr r6, [r6] /* R6 = first console struct */ ++ cmp r6, #0 ++ bne getc_loop ++ mov r0, r5 /* If no consoles registered */ ++ pop {r5-r6, pc} /* return immediately. */ ++ ++getc_loop: ++ ldr r0, =console_state ++ ldrb r0, [r0] ++ ldr r1, [r6, #CONSOLE_T_FLAGS] ++ tst r0, r1 ++ beq getc_continue ++ ldr r1, [r6, #CONSOLE_T_GETC] ++ cmp r1, #0 ++ beq getc_continue ++ mov r0, r6 ++ blx r1 ++ cmp r0, #0 /* if R0 >= 0: return */ ++ bge getc_found ++ cmp r5, #ERROR_NO_PENDING_CHAR /* may update R5 (NOCHAR has */ ++ movne r5, r0 /* precedence vs real errors) */ ++getc_continue: ++ ldr r6, [r6] /* R6 = next struct */ ++ cmp r6, #0 ++ bne getc_loop ++ cmp r5, #ERROR_NO_PENDING_CHAR /* Keep scanning if at least */ ++ beq getc_try_again /* one console returns NOCHAR */ ++ mov r0, r5 ++ ++getc_found: ++ pop {r5-r6, pc} ++endfunc console_getc ++ ++ /* --------------------------------------------- ++ * int console_flush(void) ++ * Function to force a write of all buffered ++ * data that hasn't been output. Calls all ++ * console's flush() handlers in succession. ++ * Out: r0 - 0 on success, < 0 if at least one error ++ * Clobber list : r0, r1, r2 ++ * --------------------------------------------- ++ */ ++func console_flush ++ push {r5-r6, lr} ++ mov r5, #ERROR_NO_VALID_CONSOLE /* R5 = current return value */ ++ ldr r6, =console_list ++ ldr r6, [r6] /* R6 = first console struct */ ++ ++flush_loop: ++ cmp r6, #0 ++ beq flush_done ++ ldr r1, =console_state ++ ldrb r1, [r1] ++ ldr r2, [r6, #CONSOLE_T_FLAGS] ++ tst r1, r2 ++ beq flush_continue ++ ldr r1, [r6, #CONSOLE_T_FLUSH] ++ cmp r1, #0 ++ beq flush_continue ++ mov r0, r6 ++ blx r1 ++ cmp r5, #ERROR_NO_VALID_CONSOLE /* update R5 if it's NOVALID */ ++ cmpne r0, #0 /* else update it if R0 < 0 */ ++ movlt r5, r0 ++flush_continue: ++ ldr r6, [r6] /* R6 = next struct */ ++ b flush_loop ++ ++flush_done: ++ mov r0, r5 ++ pop {r5-r6, pc} ++endfunc console_flush +diff --git a/drivers/console/aarch64/skeleton_console.S b/drivers/console/aarch64/skeleton_console.S +index 1b5d739..3993eef 100644 +--- a/drivers/console/aarch64/skeleton_console.S ++++ b/drivers/console/aarch64/skeleton_console.S +@@ -4,6 +4,7 @@ + * SPDX-License-Identifier: BSD-3-Clause + */ + #include ++#define USE_FINISH_CONSOLE_REG_2 + #include + + /* +@@ -60,8 +61,12 @@ func console_xxx_register + * Keep console_t pointer in x0 for later. + */ + +- /* Macro to finish up registration and return (needs valid x0 + x30). */ +- finish_console_register xxx ++ /* ++ * Macro to finish up registration and return (needs valid x0 + x30). ++ * If any of the argument is unspecified, then the corresponding ++ * entry in console_t is set to 0. ++ */ ++ finish_console_register xxx putc=1, getc=1, flush=1 + + /* Jump here if hardware init fails or parameters are invalid. */ + register_fail: +diff --git a/drivers/coreboot/cbmem_console/aarch64/cbmem_console.S b/drivers/coreboot/cbmem_console/aarch64/cbmem_console.S +index 2fc0603..ae9a25b 100644 +--- a/drivers/coreboot/cbmem_console/aarch64/cbmem_console.S ++++ b/drivers/coreboot/cbmem_console/aarch64/cbmem_console.S +@@ -6,6 +6,7 @@ + + #include + #include ++#define USE_FINISH_CONSOLE_REG_2 + #include + + /* +@@ -39,7 +40,7 @@ func console_cbmc_register + ldr w2, [x0] + str w2, [x1, #CONSOLE_T_CBMC_SIZE] + mov x0, x1 +- finish_console_register cbmc ++ finish_console_register cbmc putc=1, flush=1 + endfunc console_cbmc_register + + /* ----------------------------------------------- +diff --git a/drivers/io/io_block.c b/drivers/io/io_block.c +index 8226554..3a2f403 100644 +--- a/drivers/io/io_block.c ++++ b/drivers/io/io_block.c +@@ -27,7 +27,7 @@ io_type_t device_type_block(void); + + static int block_open(io_dev_info_t *dev_info, const uintptr_t spec, + io_entity_t *entity); +-static int block_seek(io_entity_t *entity, int mode, ssize_t offset); ++static int block_seek(io_entity_t *entity, int mode, signed long long offset); + static int block_read(io_entity_t *entity, uintptr_t buffer, size_t length, + size_t *length_read); + static int block_write(io_entity_t *entity, const uintptr_t buffer, +@@ -67,8 +67,10 @@ io_type_t device_type_block(void) + static int find_first_block_state(const io_block_dev_spec_t *dev_spec, + unsigned int *index_out) + { ++ unsigned int index; + int result = -ENOENT; +- for (int index = 0; index < MAX_IO_BLOCK_DEVICES; ++index) { ++ ++ for (index = 0U; index < MAX_IO_BLOCK_DEVICES; ++index) { + /* dev_spec is used as identifier since it's unique */ + if (state_pool[index].dev_spec == dev_spec) { + result = 0; +@@ -144,7 +146,7 @@ static int block_open(io_dev_info_t *dev_info, const uintptr_t spec, + } + + /* parameter offset is relative address at here */ +-static int block_seek(io_entity_t *entity, int mode, ssize_t offset) ++static int block_seek(io_entity_t *entity, int mode, signed long long offset) + { + block_dev_state_t *cur; + +diff --git a/drivers/io/io_memmap.c b/drivers/io/io_memmap.c +index 5595e60..8add0b8 100644 +--- a/drivers/io/io_memmap.c ++++ b/drivers/io/io_memmap.c +@@ -40,7 +40,7 @@ static int memmap_dev_open(const uintptr_t dev_spec, io_dev_info_t **dev_info); + static int memmap_block_open(io_dev_info_t *dev_info, const uintptr_t spec, + io_entity_t *entity); + static int memmap_block_seek(io_entity_t *entity, int mode, +- ssize_t offset); ++ signed long long offset); + static int memmap_block_len(io_entity_t *entity, size_t *length); + static int memmap_block_read(io_entity_t *entity, uintptr_t buffer, + size_t length, size_t *length_read); +@@ -127,7 +127,8 @@ static int memmap_block_open(io_dev_info_t *dev_info, const uintptr_t spec, + + + /* Seek to a particular file offset on the memmap device */ +-static int memmap_block_seek(io_entity_t *entity, int mode, ssize_t offset) ++static int memmap_block_seek(io_entity_t *entity, int mode, ++ signed long long offset) + { + int result = -ENOENT; + file_state_t *fp; +diff --git a/drivers/io/io_semihosting.c b/drivers/io/io_semihosting.c +index 9ca0a9d..125fea9 100644 +--- a/drivers/io/io_semihosting.c ++++ b/drivers/io/io_semihosting.c +@@ -25,7 +25,7 @@ static io_type_t device_type_sh(void) + static int sh_dev_open(const uintptr_t dev_spec, io_dev_info_t **dev_info); + static int sh_file_open(io_dev_info_t *dev_info, const uintptr_t spec, + io_entity_t *entity); +-static int sh_file_seek(io_entity_t *entity, int mode, ssize_t offset); ++static int sh_file_seek(io_entity_t *entity, int mode, signed long long offset); + static int sh_file_len(io_entity_t *entity, size_t *length); + static int sh_file_read(io_entity_t *entity, uintptr_t buffer, size_t length, + size_t *length_read); +@@ -90,7 +90,7 @@ static int sh_file_open(io_dev_info_t *dev_info __unused, + + + /* Seek to a particular file offset on the semi-hosting device */ +-static int sh_file_seek(io_entity_t *entity, int mode, ssize_t offset) ++static int sh_file_seek(io_entity_t *entity, int mode, signed long long offset) + { + long file_handle, sh_result; + +diff --git a/drivers/io/io_storage.c b/drivers/io/io_storage.c +index 948f848..90282a2 100644 +--- a/drivers/io/io_storage.c ++++ b/drivers/io/io_storage.c +@@ -239,7 +239,7 @@ int io_open(uintptr_t dev_handle, const uintptr_t spec, uintptr_t *handle) + + + /* Seek to a specific position in an IO entity */ +-int io_seek(uintptr_t handle, io_seek_mode_t mode, ssize_t offset) ++int io_seek(uintptr_t handle, io_seek_mode_t mode, signed long long offset) + { + int result = -ENODEV; + assert(is_valid_entity(handle) && is_valid_seek_mode(mode)); +diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c +index 418ab11..4f9cecf 100644 +--- a/drivers/mmc/mmc.c ++++ b/drivers/mmc/mmc.c +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. ++ * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +@@ -246,6 +246,13 @@ static int mmc_fill_device_info(void) + return ret; + } + ++ do { ++ ret = mmc_device_state(); ++ if (ret < 0) { ++ return ret; ++ } ++ } while (ret != MMC_STATE_TRAN); ++ + nb_blocks = (mmc_ext_csd[CMD_EXTCSD_SEC_CNT] << 0) | + (mmc_ext_csd[CMD_EXTCSD_SEC_CNT + 1] << 8) | + (mmc_ext_csd[CMD_EXTCSD_SEC_CNT + 2] << 16) | +@@ -292,7 +299,7 @@ static int mmc_fill_device_info(void) + break; + } + +- if (ret != 0) { ++ if (ret < 0) { + return ret; + } + +@@ -379,7 +386,10 @@ static int mmc_send_op_cond(void) + int ret, n; + unsigned int resp_data[4]; + +- mmc_reset_to_idle(); ++ ret = mmc_reset_to_idle(); ++ if (ret != 0) { ++ return ret; ++ }; + + for (n = 0; n < SEND_OP_COND_MAX_RETRIES; n++) { + ret = mmc_send_cmd(MMC_CMD(1), OCR_SECTOR_MODE | +@@ -394,7 +404,7 @@ static int mmc_send_op_cond(void) + return 0; + } + +- mdelay(1); ++ mdelay(10); + } + + ERROR("CMD1 failed after %d retries\n", SEND_OP_COND_MAX_RETRIES); +@@ -409,7 +419,10 @@ static int mmc_enumerate(unsigned int clk, unsigned int bus_width) + + ops->init(); + +- mmc_reset_to_idle(); ++ ret = mmc_reset_to_idle(); ++ if (ret != 0) { ++ return ret; ++ }; + + if (mmc_dev_info->mmc_dev_type == MMC_IS_EMMC) { + ret = mmc_send_op_cond(); +diff --git a/drivers/partition/gpt.c b/drivers/partition/gpt.c +index 9cc917d..0c51e62 100644 +--- a/drivers/partition/gpt.c ++++ b/drivers/partition/gpt.c +@@ -13,10 +13,14 @@ + + static int unicode_to_ascii(unsigned short *str_in, unsigned char *str_out) + { +- uint8_t *name = (uint8_t *)str_in; ++ uint8_t *name; + int i; + +- assert((str_in != NULL) && (str_out != NULL) && (name[0] != '\0')); ++ assert((str_in != NULL) && (str_out != NULL)); ++ ++ name = (uint8_t *)str_in; ++ ++ assert(name[0] != '\0'); + + /* check whether the unicode string is valid */ + for (i = 1; i < (EFI_NAMELEN << 1); i += 2) { +@@ -36,7 +40,7 @@ int parse_gpt_entry(gpt_entry_t *gpt_entry, partition_entry_t *entry) + { + int result; + +- assert((gpt_entry != 0) && (entry != 0)); ++ assert((gpt_entry != NULL) && (entry != NULL)); + + if ((gpt_entry->first_lba == 0) && (gpt_entry->last_lba == 0)) { + return -EINVAL; +diff --git a/drivers/partition/partition.c b/drivers/partition/partition.c +index d6fb4b8..6085b86 100644 +--- a/drivers/partition/partition.c ++++ b/drivers/partition/partition.c +@@ -30,7 +30,7 @@ static void dump_entries(int num) + name[len + j] = ' '; + } + name[EFI_NAMELEN - 1] = '\0'; +- VERBOSE("%d: %s %lx-%lx\n", i + 1, name, list.list[i].start, ++ VERBOSE("%d: %s %llx-%llx\n", i + 1, name, list.list[i].start, + list.list[i].start + list.list[i].length - 4); + } + } +diff --git a/drivers/st/bsec/bsec.c b/drivers/st/bsec/bsec.c +new file mode 100644 +index 0000000..c579c41 +--- /dev/null ++++ b/drivers/st/bsec/bsec.c +@@ -0,0 +1,911 @@ ++/* ++ * Copyright (c) 2017-2018, STMicroelectronics - All Rights Reserved ++ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. ++ * ++ * SPDX-License-Identifier: BSD-3-Clause ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define BSEC_IP_VERSION_1_0 0x10 ++#define BSEC_COMPAT "st,stm32mp15-bsec" ++ ++#define OTP_ACCESS_SIZE (round_up(OTP_MAX_SIZE, __WORD_BIT) / __WORD_BIT) ++ ++static uint32_t otp_nsec_access[OTP_ACCESS_SIZE] __unused; ++ ++static uint32_t bsec_power_safmem(bool power); ++ ++/* BSEC access protection */ ++static spinlock_t bsec_spinlock; ++static uintptr_t bsec_base; ++ ++static void bsec_lock(void) ++{ ++ const uint32_t mask = SCTLR_M_BIT | SCTLR_C_BIT; ++ ++ /* Lock is currently required only when MMU and cache are enabled */ ++ if ((read_sctlr() & mask) == mask) { ++ spin_lock(&bsec_spinlock); ++ } ++} ++ ++static void bsec_unlock(void) ++{ ++ const uint32_t mask = SCTLR_M_BIT | SCTLR_C_BIT; ++ ++ /* Unlock is required only when MMU and cache are enabled */ ++ if ((read_sctlr() & mask) == mask) { ++ spin_unlock(&bsec_spinlock); ++ } ++} ++ ++static int bsec_get_dt_node(struct dt_node_info *info) ++{ ++ int node; ++ ++ node = dt_get_node(info, -1, BSEC_COMPAT); ++ if (node < 0) { ++ return -FDT_ERR_NOTFOUND; ++ } ++ ++ return node; ++} ++ ++#if defined(IMAGE_BL32) ++static void enable_non_secure_access(uint32_t otp) ++{ ++ otp_nsec_access[otp / __WORD_BIT] |= BIT(otp % __WORD_BIT); ++ ++ if (bsec_shadow_register(otp) != BSEC_OK) { ++ panic(); ++ } ++} ++ ++static bool non_secure_can_access(uint32_t otp) ++{ ++ return (otp_nsec_access[otp / __WORD_BIT] & ++ BIT(otp % __WORD_BIT)) != 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(bsec_subnode); ++ if ((status & DT_NON_SECURE) == 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 <= STM32MP1_OTP_MAX_ID); ++ ++ return ((otp & ~BSEC_OTP_MASK) >> BSEC_OTP_BANK_SHIFT) * ++ sizeof(uint32_t); ++} ++ ++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 ((mmio_read_32(bsec_base + BSEC_DISTURBED_OFF + bank) & bit) != 0U) { ++ return BSEC_DISTURBED; ++ } ++ ++ if ((mmio_read_32(bsec_base + BSEC_ERROR_OFF + bank) & bit) != 0U) { ++ return BSEC_ERROR; ++ } ++ ++ return BSEC_OK; ++} ++ ++/* ++ * bsec_probe: initialize BSEC driver. ++ * return value: BSEC_OK if no error. ++ */ ++uint32_t bsec_probe(void) ++{ ++ void *fdt; ++ int node; ++ struct dt_node_info bsec_info; ++ ++ if (fdt_get_address(&fdt) == 0) { ++ panic(); ++ } ++ ++ node = bsec_get_dt_node(&bsec_info); ++ if (node < 0) { ++ panic(); ++ } ++ ++ bsec_base = bsec_info.base; ++ ++#if defined(IMAGE_BL32) ++ bsec_dt_otp_nsec_access(fdt, node); ++#endif ++ return BSEC_OK; ++} ++ ++/* ++ * bsec_get_base: return BSEC base address. ++ */ ++uint32_t bsec_get_base(void) ++{ ++ return bsec_base; ++} ++ ++/* ++ * bsec_set_config: enable and configure BSEC. ++ * cfg: pointer to param structure used to set register. ++ * return value: BSEC_OK if no error. ++ */ ++uint32_t bsec_set_config(struct bsec_config *cfg) ++{ ++ uint32_t value; ++ int32_t result; ++ ++ value = ((((uint32_t)cfg->freq << BSEC_CONF_FRQ_SHIFT) & ++ BSEC_CONF_FRQ_MASK) | ++ (((uint32_t)cfg->pulse_width << BSEC_CONF_PRG_WIDTH_SHIFT) & ++ BSEC_CONF_PRG_WIDTH_MASK) | ++ (((uint32_t)cfg->tread << BSEC_CONF_TREAD_SHIFT) & ++ BSEC_CONF_TREAD_MASK)); ++ ++ bsec_lock(); ++ ++ mmio_write_32(bsec_base + BSEC_OTP_CONF_OFF, value); ++ ++ bsec_unlock(); ++ ++ result = bsec_power_safmem((bool)cfg->power & ++ BSEC_CONF_POWER_UP_MASK); ++ if (result != BSEC_OK) { ++ return result; ++ } ++ ++ value = ((((uint32_t)cfg->upper_otp_lock << UPPER_OTP_LOCK_SHIFT) & ++ UPPER_OTP_LOCK_MASK) | ++ (((uint32_t)cfg->den_lock << DENREG_LOCK_SHIFT) & ++ DENREG_LOCK_MASK) | ++ (((uint32_t)cfg->prog_lock << GPLOCK_LOCK_SHIFT) & ++ GPLOCK_LOCK_MASK)); ++ ++ bsec_lock(); ++ ++ mmio_write_32(bsec_base + BSEC_OTP_LOCK_OFF, value); ++ ++ bsec_unlock(); ++ ++ return BSEC_OK; ++} ++ ++/* ++ * bsec_get_config: return config parameters set in BSEC registers. ++ * cfg: config param return. ++ * return value: BSEC_OK if no error. ++ */ ++uint32_t bsec_get_config(struct bsec_config *cfg) ++{ ++ uint32_t value; ++ ++ if (cfg == NULL) { ++ return BSEC_INVALID_PARAM; ++ } ++ ++ value = mmio_read_32(bsec_base + BSEC_OTP_CONF_OFF); ++ cfg->power = (uint8_t)((value & BSEC_CONF_POWER_UP_MASK) >> ++ BSEC_CONF_POWER_UP_SHIFT); ++ cfg->freq = (uint8_t)((value & BSEC_CONF_FRQ_MASK) >> ++ BSEC_CONF_FRQ_SHIFT); ++ cfg->pulse_width = (uint8_t)((value & BSEC_CONF_PRG_WIDTH_MASK) >> ++ BSEC_CONF_PRG_WIDTH_SHIFT); ++ cfg->tread = (uint8_t)((value & BSEC_CONF_TREAD_MASK) >> ++ BSEC_CONF_TREAD_SHIFT); ++ ++ value = mmio_read_32(bsec_base + BSEC_OTP_LOCK_OFF); ++ cfg->upper_otp_lock = (uint8_t)((value & UPPER_OTP_LOCK_MASK) >> ++ UPPER_OTP_LOCK_SHIFT); ++ cfg->den_lock = (uint8_t)((value & DENREG_LOCK_MASK) >> ++ DENREG_LOCK_SHIFT); ++ cfg->prog_lock = (uint8_t)((value & GPLOCK_LOCK_MASK) >> ++ GPLOCK_LOCK_SHIFT); ++ ++ 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; ++ bool power_up = false; ++ ++ if (otp > STM32MP1_OTP_MAX_ID) { ++ return BSEC_INVALID_PARAM; ++ } ++ ++ /* Check if shadowing of OTP is locked */ ++ if (bsec_read_sr_lock(otp)) { ++ VERBOSE("BSEC: OTP %i is locked and will not be refreshed\n", ++ otp); ++ } ++ ++ if ((bsec_get_status() & BSEC_MODE_PWR_MASK) == 0U) { ++ result = bsec_power_safmem(true); ++ ++ if (result != BSEC_OK) { ++ return result; ++ } ++ ++ power_up = true; ++ } ++ ++ bsec_lock(); ++ ++ /* Set BSEC_OTP_CTRL_OFF and set ADDR with the OTP value */ ++ mmio_write_32(bsec_base + BSEC_OTP_CTRL_OFF, otp | BSEC_READ); ++ ++ while ((bsec_get_status() & BSEC_MODE_BUSY_MASK) != 0U) { ++ ; ++ } ++ ++ result = bsec_check_error(otp); ++ ++ bsec_unlock(); ++ ++ if (power_up) { ++ if (bsec_power_safmem(false) != BSEC_OK) { ++ panic(); ++ } ++ } ++ ++ 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 result; ++ ++ if (otp > STM32MP1_OTP_MAX_ID) { ++ return BSEC_INVALID_PARAM; ++ } ++ ++ bsec_lock(); ++ ++ *val = mmio_read_32(bsec_base + BSEC_OTP_DATA_OFF + ++ (otp * sizeof(uint32_t))); ++ ++ result = bsec_check_error(otp); ++ ++ bsec_unlock(); ++ ++ 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 result; ++ ++ if (otp > STM32MP1_OTP_MAX_ID) { ++ return BSEC_INVALID_PARAM; ++ } ++ ++ /* Check if programming of OTP is locked */ ++ if (bsec_read_sw_lock(otp)) { ++ VERBOSE("BSEC: OTP %i is locked and write will be ignored\n", ++ otp); ++ } ++ ++ bsec_lock(); ++ ++ mmio_write_32(bsec_base + BSEC_OTP_DATA_OFF + ++ (otp * sizeof(uint32_t)), val); ++ ++ result = bsec_check_error(otp); ++ ++ bsec_unlock(); ++ ++ 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; ++ bool power_up = false; ++ ++ if (otp > STM32MP1_OTP_MAX_ID) { ++ return BSEC_INVALID_PARAM; ++ } ++ ++ /* Check if programming of OTP is locked */ ++ if (bsec_read_sp_lock(otp)) { ++ WARN("BSEC: OTP locked, prog will be ignored\n"); ++ } ++ ++ if ((mmio_read_32(bsec_base + BSEC_OTP_LOCK_OFF) & ++ BIT(BSEC_LOCK_PROGRAM)) != 0U) { ++ WARN("BSEC: GPLOCK activated, prog will be ignored\n"); ++ } ++ ++ if ((bsec_get_status() & BSEC_MODE_PWR_MASK) == 0U) { ++ result = bsec_power_safmem(true); ++ ++ if (result != BSEC_OK) { ++ return result; ++ } ++ ++ power_up = true; ++ } ++ ++ bsec_lock(); ++ ++ /* Set value in write register */ ++ mmio_write_32(bsec_base + BSEC_OTP_WRDATA_OFF, val); ++ ++ /* Set BSEC_OTP_CTRL_OFF and set ADDR with the OTP value */ ++ mmio_write_32(bsec_base + BSEC_OTP_CTRL_OFF, otp | BSEC_WRITE); ++ ++ 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(); ++ ++ if (power_up) { ++ if (bsec_power_safmem(false) != BSEC_OK) { ++ panic(); ++ } ++ } ++ ++ 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; ++ bool power_up = false; ++ uint32_t data; ++ uint32_t addr; ++ ++ if (otp > STM32MP1_OTP_MAX_ID) { ++ return BSEC_INVALID_PARAM; ++ } ++ ++ if ((bsec_get_status() & BSEC_MODE_PWR_MASK) == 0U) { ++ result = bsec_power_safmem(true); ++ ++ if (result != BSEC_OK) { ++ return result; ++ } ++ ++ power_up = true; ++ } ++ ++ if (otp < STM32MP1_UPPER_OTP_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); ++ } ++ ++ bsec_lock(); ++ ++ /* Set value in write register */ ++ mmio_write_32(bsec_base + BSEC_OTP_WRDATA_OFF, data); ++ ++ /* Set BSEC_OTP_CTRL_OFF and set ADDR with the OTP value */ ++ mmio_write_32(bsec_base + BSEC_OTP_CTRL_OFF, ++ addr | BSEC_WRITE | BSEC_LOCK); ++ ++ 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(); ++ ++ if (power_up) { ++ if (bsec_power_safmem(false) != BSEC_OK) { ++ panic(); ++ } ++ } ++ ++ 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; ++ ++ bsec_lock(); ++ ++ mmio_write_32(bsec_base + BSEC_DEN_OFF, masked_val); ++ ++ if ((mmio_read_32(bsec_base + BSEC_DEN_OFF) ^ masked_val) == 0U) { ++ result = BSEC_OK; ++ } ++ ++ bsec_unlock(); ++ ++ return result; ++} ++ ++/* ++ * bsec_read_debug_conf: read debug configuration. ++ */ ++uint32_t bsec_read_debug_conf(void) ++{ ++ return mmio_read_32(bsec_base + BSEC_DEN_OFF); ++} ++ ++/* ++ * bsec_get_status: return status register value. ++ */ ++uint32_t bsec_get_status(void) ++{ ++ return mmio_read_32(bsec_base + BSEC_OTP_STATUS_OFF); ++} ++ ++/* ++ * bsec_get_hw_conf: return hardware configuration. ++ */ ++uint32_t bsec_get_hw_conf(void) ++{ ++ return mmio_read_32(bsec_base + BSEC_IPHW_CFG_OFF); ++} ++ ++/* ++ * bsec_get_version: return BSEC version. ++ */ ++uint32_t bsec_get_version(void) ++{ ++ return mmio_read_32(bsec_base + BSEC_IPVR_OFF); ++} ++ ++/* ++ * bsec_get_id: return BSEC ID. ++ */ ++uint32_t bsec_get_id(void) ++{ ++ return mmio_read_32(bsec_base + BSEC_IP_ID_OFF); ++} ++ ++/* ++ * bsec_get_magic_id: return BSEC magic number. ++ */ ++uint32_t bsec_get_magic_id(void) ++{ ++ return mmio_read_32(bsec_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); ++ ++ bsec_lock(); ++ ++ bank_value = mmio_read_32(bsec_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. ++ */ ++ mmio_write_32(bsec_base + BSEC_SRLOCK_OFF + bank, bank_value); ++ result = true; ++ } ++ ++ bsec_unlock(); ++ ++ 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 = mmio_read_32(bsec_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; ++ ++ bsec_lock(); ++ ++ bank_value = mmio_read_32(bsec_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. ++ */ ++ mmio_write_32(bsec_base + BSEC_SWLOCK_OFF + bank, bank_value); ++ result = true; ++ } ++ ++ bsec_unlock(); ++ ++ 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 = mmio_read_32(bsec_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); ++ ++ bsec_lock(); ++ ++ bank_value = mmio_read_32(bsec_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. ++ */ ++ mmio_write_32(bsec_base + BSEC_SPLOCK_OFF + bank, bank_value); ++ result = true; ++ } ++ ++ bsec_unlock(); ++ ++ 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 = mmio_read_32(bsec_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 ((mmio_read_32(bsec_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_base + BSEC_OTP_LOCK_OFF; ++ ++ switch (service) { ++ case BSEC_LOCK_UPPER_OTP: ++ mmio_write_32(reg, value << BSEC_LOCK_UPPER_OTP); ++ break; ++ case BSEC_LOCK_DEBUG: ++ mmio_write_32(reg, value << BSEC_LOCK_DEBUG); ++ break; ++ case BSEC_LOCK_PROGRAM: ++ mmio_write_32(reg, value << BSEC_LOCK_PROGRAM); ++ break; ++ default: ++ return BSEC_INVALID_PARAM; ++ } ++ ++ return BSEC_OK; ++} ++ ++/* ++ * 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 power) ++{ ++ uint32_t register_val; ++ uint32_t timeout = BSEC_TIMEOUT_VALUE; ++ ++ bsec_lock(); ++ ++ register_val = mmio_read_32(bsec_base + BSEC_OTP_CONF_OFF); ++ ++ if (power) { ++ register_val |= BSEC_CONF_POWER_UP_MASK; ++ } else { ++ register_val &= ~BSEC_CONF_POWER_UP_MASK; ++ } ++ ++ mmio_write_32(bsec_base + BSEC_OTP_CONF_OFF, register_val); ++ ++ /* Waiting loop */ ++ if (power) { ++ while (((bsec_get_status() & BSEC_MODE_PWR_MASK) == 0U) && ++ (timeout != 0U)) { ++ timeout--; ++ } ++ } else { ++ while (((bsec_get_status() & BSEC_MODE_PWR_MASK) != 0U) && ++ (timeout != 0U)) { ++ timeout--; ++ } ++ } ++ ++ bsec_unlock(); ++ ++ if (timeout == 0U) { ++ return BSEC_TIMEOUT; ++ } ++ ++ return BSEC_OK; ++} ++ ++/* ++ * 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) { ++ ERROR("BSEC: %u Shadowing Error %i\n", word, result); ++ return result; ++ } ++ ++ result = bsec_read_otp(otp_value, word); ++ if (result != BSEC_OK) { ++ ERROR("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 defined(IMAGE_BL32) ++ if (otp > STM32MP1_OTP_MAX_ID) { ++ return BSEC_INVALID_PARAM; ++ } ++ ++ if (otp >= STM32MP1_UPPER_OTP_START) { ++ /* Check if BSEC is in OTP-SECURED closed_device state. */ ++ if (bsec_mode_is_closed_device()) { ++ if (!non_secure_can_access(otp)) { ++ return BSEC_ERROR; ++ } ++ } ++ } ++#endif ++ ++ return BSEC_OK; ++} ++ +diff --git a/drivers/st/clk/stm32mp1_clk.c b/drivers/st/clk/stm32mp1_clk.c +index f0bf363..b304315 100644 +--- a/drivers/st/clk/stm32mp1_clk.c ++++ b/drivers/st/clk/stm32mp1_clk.c +@@ -9,26 +9,34 @@ + #include + #include + #include +-#include + #include + #include + #include + #include + #include + #include ++#include + #include + #include ++#include ++#include ++#include ++#include + #include + #include +-#include + #include + #include ++#include ++#if defined(IMAGE_BL32) ++#include ++#endif + #include + + #define MAX_HSI_HZ 64000000 ++#define USB_PHY_48_MHZ 48000000 + +-#define TIMEOUT_200MS (plat_get_syscnt_freq2() / 5U) +-#define TIMEOUT_1S plat_get_syscnt_freq2() ++#define TIMEOUT_200MS ms2tick(200) ++#define TIMEOUT_1S s2tick(1) + + #define PLLRDY_TIMEOUT TIMEOUT_200MS + #define CLKSRC_TIMEOUT TIMEOUT_200MS +@@ -36,6 +44,10 @@ + #define HSIDIV_TIMEOUT TIMEOUT_200MS + #define OSCRDY_TIMEOUT TIMEOUT_1S + ++#if defined(IMAGE_BL32) ++#define CAL_MAX_RETRY 20U ++#endif ++ + enum stm32mp1_parent_id { + /* Oscillators are defined in enum stm32mp_osc_id */ + +@@ -66,12 +78,21 @@ enum stm32mp1_parent_id { + _HCLK2, + _CK_PER, + _CK_MPU, ++ _CK_MCU, ++ _USB_PHY_48, + _PARENT_NB, + _UNKNOWN_ID = 0xff, + }; + ++/* Lists only the parent clock we are interested in */ + enum stm32mp1_parent_sel { ++ _I2C12_SEL, ++ _I2C35_SEL, ++ _STGEN_SEL, + _I2C46_SEL, ++ _SPI6_SEL, ++ _USART1_SEL, ++ _RNG1_SEL, + _UART6_SEL, + _UART24_SEL, + _UART35_SEL, +@@ -80,9 +101,10 @@ enum stm32mp1_parent_sel { + _SDMMC3_SEL, + _QSPI_SEL, + _FMC_SEL, ++ _ASS_SEL, ++ _MSS_SEL, + _USBPHY_SEL, + _USBO_SEL, +- _STGEN_SEL, + _PARENT_SEL_NB, + _UNKNOWN_SEL = 0xff, + }; +@@ -105,6 +127,7 @@ enum stm32mp1_div_id { + enum stm32mp1_clksrc_id { + CLKSRC_MPU, + CLKSRC_AXI, ++ CLKSRC_MCU, + CLKSRC_PLL12, + CLKSRC_PLL3, + CLKSRC_PLL4, +@@ -117,6 +140,7 @@ enum stm32mp1_clksrc_id { + enum stm32mp1_clkdiv_id { + CLKDIV_MPU, + CLKDIV_AXI, ++ CLKDIV_MCU, + CLKDIV_APB1, + CLKDIV_APB2, + CLKDIV_APB3, +@@ -162,9 +186,8 @@ struct stm32mp1_clk_gate { + uint8_t bit; + uint8_t index; + uint8_t set_clr; +- enum stm32mp1_parent_sel sel; +- enum stm32mp1_parent_id fixed; +- bool secure; ++ uint8_t sel; /* Relates to enum stm32mp1_parent_sel */ ++ uint8_t fixed; /* Relates to enum stm32mp1_parent_id */ + }; + + struct stm32mp1_clk_sel { +@@ -187,21 +210,34 @@ struct stm32mp1_clk_pll { + enum stm32mp_osc_id refclk[REFCLK_SIZE]; + }; + +-struct stm32mp1_clk_data { +- const struct stm32mp1_clk_gate *gate; +- const struct stm32mp1_clk_sel *sel; +- const struct stm32mp1_clk_pll *pll; +- const int nb_gate; ++#if defined(IMAGE_BL32) ++struct stm32mp1_trim_boundary_t { ++ /* Max boundary trim value around forbidden value */ ++ unsigned int x1; ++ /* Min boundary trim value around forbidden value */ ++ unsigned int x2; + }; + +-struct stm32mp1_clk_priv { +- uint32_t base; +- const struct stm32mp1_clk_data *data; +- unsigned long osc[NB_OSC]; +- uint32_t pkcs_usb_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]; + }; + +-#define STM32MP1_CLK(off, b, idx, s) \ ++/* RCC Wakeup status */ ++static bool rcc_wakeup; ++#endif ++ ++/* Clocks with selectable source and non set/clr register access */ ++#define _CLK_SELEC(off, b, idx, s) \ + { \ + .offset = (off), \ + .bit = (b), \ +@@ -209,10 +245,10 @@ struct stm32mp1_clk_priv { + .set_clr = 0, \ + .sel = (s), \ + .fixed = _UNKNOWN_ID, \ +- .secure = 0, \ + } + +-#define STM32MP1_CLK_F(off, b, idx, f) \ ++/* Clocks with fixed source and non set/clr register access */ ++#define _CLK_FIXED(off, b, idx, f) \ + { \ + .offset = (off), \ + .bit = (b), \ +@@ -220,10 +256,10 @@ struct stm32mp1_clk_priv { + .set_clr = 0, \ + .sel = _UNKNOWN_SEL, \ + .fixed = (f), \ +- .secure = 0, \ + } + +-#define STM32MP1_CLK_SET_CLR(off, b, idx, s) \ ++/* Clocks with selectable source and set/clr register access */ ++#define _CLK_SC_SELEC(off, b, idx, s) \ + { \ + .offset = (off), \ + .bit = (b), \ +@@ -231,10 +267,10 @@ struct stm32mp1_clk_priv { + .set_clr = 1, \ + .sel = (s), \ + .fixed = _UNKNOWN_ID, \ +- .secure = 0, \ + } + +-#define STM32MP1_CLK_SET_CLR_F(off, b, idx, f) \ ++/* Clocks with fixed source and set/clr register access */ ++#define _CLK_SC_FIXED(off, b, idx, f) \ + { \ + .offset = (off), \ + .bit = (b), \ +@@ -242,32 +278,20 @@ struct stm32mp1_clk_priv { + .set_clr = 1, \ + .sel = _UNKNOWN_SEL, \ + .fixed = (f), \ +- .secure = 0, \ +- } +- +-#define STM32MP1_CLK_SEC_SET_CLR(off, b, idx, s) \ +- { \ +- .offset = (off), \ +- .bit = (b), \ +- .index = (idx), \ +- .set_clr = 1, \ +- .sel = (s), \ +- .fixed = _UNKNOWN_ID, \ +- .secure = 1, \ + } + +-#define STM32MP1_CLK_PARENT(idx, off, s, m, p) \ ++#define _CLK_PARENT(idx, off, s, m, p) \ + [(idx)] = { \ + .offset = (off), \ + .src = (s), \ + .msk = (m), \ + .parent = (p), \ +- .nb_parent = ARRAY_SIZE((p)) \ ++ .nb_parent = ARRAY_SIZE(p) \ + } + +-#define STM32MP1_CLK_PLL(idx, type, off1, off2, off3, \ +- off4, off5, off6, \ +- p1, p2, p3, p4) \ ++#define _CLK_PLL(idx, type, off1, off2, off3, \ ++ off4, off5, off6, \ ++ p1, p2, p3, p4) \ + [(idx)] = { \ + .plltype = (type), \ + .rckxselr = (off1), \ +@@ -283,113 +307,180 @@ struct stm32mp1_clk_priv { + } + + static const uint8_t stm32mp1_clks[][2] = { +- {CK_PER, _CK_PER}, +- {CK_MPU, _CK_MPU}, +- {CK_AXI, _ACLK}, +- {CK_HSE, _HSE}, +- {CK_CSI, _CSI}, +- {CK_LSI, _LSI}, +- {CK_LSE, _LSE}, +- {CK_HSI, _HSI}, +- {CK_HSE_DIV2, _HSE_KER_DIV2}, ++ { 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[] = { +- STM32MP1_CLK(RCC_DDRITFCR, 0, DDRC1, _UNKNOWN_SEL), +- STM32MP1_CLK(RCC_DDRITFCR, 1, DDRC1LP, _UNKNOWN_SEL), +- STM32MP1_CLK(RCC_DDRITFCR, 2, DDRC2, _UNKNOWN_SEL), +- STM32MP1_CLK(RCC_DDRITFCR, 3, DDRC2LP, _UNKNOWN_SEL), +- STM32MP1_CLK_F(RCC_DDRITFCR, 4, DDRPHYC, _PLL2_R), +- STM32MP1_CLK(RCC_DDRITFCR, 5, DDRPHYCLP, _UNKNOWN_SEL), +- STM32MP1_CLK(RCC_DDRITFCR, 6, DDRCAPB, _UNKNOWN_SEL), +- STM32MP1_CLK(RCC_DDRITFCR, 7, DDRCAPBLP, _UNKNOWN_SEL), +- STM32MP1_CLK(RCC_DDRITFCR, 8, AXIDCG, _UNKNOWN_SEL), +- STM32MP1_CLK(RCC_DDRITFCR, 9, DDRPHYCAPB, _UNKNOWN_SEL), +- STM32MP1_CLK(RCC_DDRITFCR, 10, DDRPHYCAPBLP, _UNKNOWN_SEL), +- +- STM32MP1_CLK_SET_CLR(RCC_MP_APB1ENSETR, 14, USART2_K, _UART24_SEL), +- STM32MP1_CLK_SET_CLR(RCC_MP_APB1ENSETR, 15, USART3_K, _UART35_SEL), +- STM32MP1_CLK_SET_CLR(RCC_MP_APB1ENSETR, 16, UART4_K, _UART24_SEL), +- STM32MP1_CLK_SET_CLR(RCC_MP_APB1ENSETR, 17, UART5_K, _UART35_SEL), +- STM32MP1_CLK_SET_CLR(RCC_MP_APB1ENSETR, 18, UART7_K, _UART78_SEL), +- STM32MP1_CLK_SET_CLR(RCC_MP_APB1ENSETR, 19, UART8_K, _UART78_SEL), +- +- STM32MP1_CLK_SET_CLR(RCC_MP_APB2ENSETR, 13, USART6_K, _UART6_SEL), +- +- STM32MP1_CLK_SET_CLR(RCC_MP_APB4ENSETR, 8, DDRPERFM, _UNKNOWN_SEL), +- STM32MP1_CLK_SET_CLR(RCC_MP_APB4ENSETR, 15, IWDG2, _UNKNOWN_SEL), +- STM32MP1_CLK_SET_CLR(RCC_MP_APB4ENSETR, 16, USBPHY_K, _USBPHY_SEL), +- +- STM32MP1_CLK_SEC_SET_CLR(RCC_MP_APB5ENSETR, 2, I2C4_K, _I2C46_SEL), +- STM32MP1_CLK_SEC_SET_CLR(RCC_MP_APB5ENSETR, 8, RTCAPB, _PCLK5), +- STM32MP1_CLK_SEC_SET_CLR(RCC_MP_APB5ENSETR, 11, TZC1, _UNKNOWN_SEL), +- STM32MP1_CLK_SEC_SET_CLR(RCC_MP_APB5ENSETR, 12, TZC2, _UNKNOWN_SEL), +- STM32MP1_CLK_SEC_SET_CLR(RCC_MP_APB5ENSETR, 20, STGEN_K, _STGEN_SEL), +- +- STM32MP1_CLK_SET_CLR(RCC_MP_AHB2ENSETR, 8, USBO_K, _USBO_SEL), +- STM32MP1_CLK_SET_CLR(RCC_MP_AHB2ENSETR, 16, SDMMC3_K, _SDMMC3_SEL), +- +- STM32MP1_CLK_SET_CLR(RCC_MP_AHB4ENSETR, 0, GPIOA, _UNKNOWN_SEL), +- STM32MP1_CLK_SET_CLR(RCC_MP_AHB4ENSETR, 1, GPIOB, _UNKNOWN_SEL), +- STM32MP1_CLK_SET_CLR(RCC_MP_AHB4ENSETR, 2, GPIOC, _UNKNOWN_SEL), +- STM32MP1_CLK_SET_CLR(RCC_MP_AHB4ENSETR, 3, GPIOD, _UNKNOWN_SEL), +- STM32MP1_CLK_SET_CLR(RCC_MP_AHB4ENSETR, 4, GPIOE, _UNKNOWN_SEL), +- STM32MP1_CLK_SET_CLR(RCC_MP_AHB4ENSETR, 5, GPIOF, _UNKNOWN_SEL), +- STM32MP1_CLK_SET_CLR(RCC_MP_AHB4ENSETR, 6, GPIOG, _UNKNOWN_SEL), +- STM32MP1_CLK_SET_CLR(RCC_MP_AHB4ENSETR, 7, GPIOH, _UNKNOWN_SEL), +- STM32MP1_CLK_SET_CLR(RCC_MP_AHB4ENSETR, 8, GPIOI, _UNKNOWN_SEL), +- STM32MP1_CLK_SET_CLR(RCC_MP_AHB4ENSETR, 9, GPIOJ, _UNKNOWN_SEL), +- STM32MP1_CLK_SET_CLR(RCC_MP_AHB4ENSETR, 10, GPIOK, _UNKNOWN_SEL), +- +- STM32MP1_CLK_SEC_SET_CLR(RCC_MP_AHB5ENSETR, 0, GPIOZ, _UNKNOWN_SEL), +- STM32MP1_CLK_SEC_SET_CLR(RCC_MP_AHB5ENSETR, 5, HASH1, _UNKNOWN_SEL), +- STM32MP1_CLK_SEC_SET_CLR(RCC_MP_AHB5ENSETR, 6, RNG1_K, _CSI_KER), +- STM32MP1_CLK_SEC_SET_CLR(RCC_MP_AHB5ENSETR, 8, BKPSRAM, _UNKNOWN_SEL), +- +- STM32MP1_CLK_SET_CLR(RCC_MP_AHB6ENSETR, 12, FMC_K, _FMC_SEL), +- STM32MP1_CLK_SET_CLR(RCC_MP_AHB6ENSETR, 14, QSPI_K, _QSPI_SEL), +- STM32MP1_CLK_SET_CLR(RCC_MP_AHB6ENSETR, 16, SDMMC1_K, _SDMMC12_SEL), +- STM32MP1_CLK_SET_CLR(RCC_MP_AHB6ENSETR, 17, SDMMC2_K, _SDMMC12_SEL), +- STM32MP1_CLK_SET_CLR(RCC_MP_AHB6ENSETR, 24, USBH, _UNKNOWN_SEL), +- +- STM32MP1_CLK(RCC_DBGCFGR, 8, CK_DBG, _UNKNOWN_SEL), ++ _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_SC_FIXED(RCC_MP_APB1ENSETR, 6, TIM12_K, _PCLK1), ++ _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_APB1ENSETR, 21, I2C1_K, _I2C12_SEL), ++ _CLK_SC_SELEC(RCC_MP_APB1ENSETR, 22, I2C2_K, _I2C12_SEL), ++ _CLK_SC_SELEC(RCC_MP_APB1ENSETR, 23, I2C3_K, _I2C35_SEL), ++ _CLK_SC_SELEC(RCC_MP_APB1ENSETR, 24, I2C5_K, _I2C35_SEL), ++ _CLK_SC_FIXED(RCC_MP_APB2ENSETR, 2, TIM15_K, _PCLK2), ++ _CLK_SC_SELEC(RCC_MP_APB2ENSETR, 13, USART6_K, _UART6_SEL), ++ ++ _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_APB5ENSETR, 0, SPI6_K, _SPI6_SEL), ++ _CLK_SC_SELEC(RCC_MP_APB5ENSETR, 2, I2C4_K, _I2C46_SEL), ++ _CLK_SC_SELEC(RCC_MP_APB5ENSETR, 3, I2C6_K, _I2C46_SEL), ++ _CLK_SC_SELEC(RCC_MP_APB5ENSETR, 4, USART1_K, _USART1_SEL), ++ _CLK_SC_FIXED(RCC_MP_APB5ENSETR, 8, RTCAPB, _PCLK5), ++ _CLK_SC_FIXED(RCC_MP_APB5ENSETR, 11, TZC1, _PCLK5), ++ _CLK_SC_FIXED(RCC_MP_APB5ENSETR, 12, TZC2, _PCLK5), ++ _CLK_SC_FIXED(RCC_MP_APB5ENSETR, 13, TZPC, _PCLK5), ++ _CLK_SC_FIXED(RCC_MP_APB5ENSETR, 15, IWDG1, _PCLK5), ++ _CLK_SC_FIXED(RCC_MP_APB5ENSETR, 16, BSEC, _PCLK5), ++ _CLK_SC_SELEC(RCC_MP_APB5ENSETR, 20, STGEN_K, _STGEN_SEL), ++ ++ _CLK_SC_SELEC(RCC_MP_AHB2ENSETR, 8, USBO_K, _USBO_SEL), ++ _CLK_SC_SELEC(RCC_MP_AHB2ENSETR, 16, SDMMC3_K, _SDMMC3_SEL), ++ ++ _CLK_SC_SELEC(RCC_MP_AHB4ENSETR, 0, GPIOA, _UNKNOWN_SEL), ++ _CLK_SC_SELEC(RCC_MP_AHB4ENSETR, 1, GPIOB, _UNKNOWN_SEL), ++ _CLK_SC_SELEC(RCC_MP_AHB4ENSETR, 2, GPIOC, _UNKNOWN_SEL), ++ _CLK_SC_SELEC(RCC_MP_AHB4ENSETR, 3, GPIOD, _UNKNOWN_SEL), ++ _CLK_SC_SELEC(RCC_MP_AHB4ENSETR, 4, GPIOE, _UNKNOWN_SEL), ++ _CLK_SC_SELEC(RCC_MP_AHB4ENSETR, 5, GPIOF, _UNKNOWN_SEL), ++ _CLK_SC_SELEC(RCC_MP_AHB4ENSETR, 6, GPIOG, _UNKNOWN_SEL), ++ _CLK_SC_SELEC(RCC_MP_AHB4ENSETR, 7, GPIOH, _UNKNOWN_SEL), ++ _CLK_SC_SELEC(RCC_MP_AHB4ENSETR, 8, GPIOI, _UNKNOWN_SEL), ++ _CLK_SC_SELEC(RCC_MP_AHB4ENSETR, 9, GPIOJ, _UNKNOWN_SEL), ++ _CLK_SC_SELEC(RCC_MP_AHB4ENSETR, 10, GPIOK, _UNKNOWN_SEL), ++ ++ _CLK_SC_FIXED(RCC_MP_AHB5ENSETR, 0, GPIOZ, _PCLK5), ++ _CLK_SC_FIXED(RCC_MP_AHB5ENSETR, 4, CRYP1, _PCLK5), ++ _CLK_SC_FIXED(RCC_MP_AHB5ENSETR, 5, HASH1, _PCLK5), ++ _CLK_SC_SELEC(RCC_MP_AHB5ENSETR, 6, RNG1_K, _RNG1_SEL), ++ _CLK_SC_FIXED(RCC_MP_AHB5ENSETR, 8, BKPSRAM, _PCLK5), ++ ++ _CLK_SC_SELEC(RCC_MP_AHB6ENSETR, 12, FMC_K, _FMC_SEL), ++ _CLK_SC_SELEC(RCC_MP_AHB6ENSETR, 14, QSPI_K, _QSPI_SEL), ++ _CLK_SC_SELEC(RCC_MP_AHB6ENSETR, 16, SDMMC1_K, _SDMMC12_SEL), ++ _CLK_SC_SELEC(RCC_MP_AHB6ENSETR, 17, SDMMC2_K, _SDMMC12_SEL), ++ _CLK_SC_SELEC(RCC_MP_AHB6ENSETR, 24, USBH, _UNKNOWN_SEL), ++ ++ _CLK_SELEC(RCC_DBGCFGR, 8, CK_DBG, _UNKNOWN_SEL), ++}; ++ ++static const uint8_t i2c12_parents[] = { ++ _PCLK1, _PLL4_R, _HSI_KER, _CSI_KER ++}; ++ ++static const uint8_t i2c35_parents[] = { ++ _PCLK1, _PLL4_R, _HSI_KER, _CSI_KER ++}; ++ ++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 ++}; ++ ++static const uint8_t uart6_parents[] = { ++ _PCLK2, _PLL4_Q, _HSI_KER, _CSI_KER, _HSE_KER + }; + +-static const uint8_t i2c46_parents[] = {_PCLK5, _PLL3_Q, _HSI_KER, _CSI_KER}; +-static const uint8_t uart6_parents[] = {_PCLK2, _PLL4_Q, _HSI_KER, _CSI_KER, +- _HSE_KER}; +-static const uint8_t uart24_parents[] = {_PCLK1, _PLL4_Q, _HSI_KER, _CSI_KER, +- _HSE_KER}; +-static const uint8_t uart35_parents[] = {_PCLK1, _PLL4_Q, _HSI_KER, _CSI_KER, +- _HSE_KER}; +-static const uint8_t uart78_parents[] = {_PCLK1, _PLL4_Q, _HSI_KER, _CSI_KER, +- _HSE_KER}; +-static const uint8_t sdmmc12_parents[] = {_HCLK6, _PLL3_R, _PLL4_P, _HSI_KER}; +-static const uint8_t sdmmc3_parents[] = {_HCLK2, _PLL3_R, _PLL4_P, _HSI_KER}; +-static const uint8_t qspi_parents[] = {_ACLK, _PLL3_R, _PLL4_P, _CK_PER}; +-static const uint8_t fmc_parents[] = {_ACLK, _PLL3_R, _PLL4_P, _CK_PER}; +-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 uint8_t stgen_parents[] = {_HSI_KER, _HSE_KER}; ++static const uint8_t uart234578_parents[] = { ++ _PCLK1, _PLL4_Q, _HSI_KER, _CSI_KER, _HSE_KER ++}; ++ ++static const uint8_t sdmmc12_parents[] = { ++ _HCLK6, _PLL3_R, _PLL4_P, _HSI_KER ++}; ++ ++static const uint8_t sdmmc3_parents[] = { ++ _HCLK2, _PLL3_R, _PLL4_P, _HSI_KER ++}; ++ ++static const uint8_t qspi_parents[] = { ++ _ACLK, _PLL3_R, _PLL4_P, _CK_PER ++}; ++ ++static const uint8_t fmc_parents[] = { ++ _ACLK, _PLL3_R, _PLL4_P, _CK_PER ++}; ++ ++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] = { +- STM32MP1_CLK_PARENT(_I2C46_SEL, RCC_I2C46CKSELR, 0, 0x7, i2c46_parents), +- STM32MP1_CLK_PARENT(_UART6_SEL, RCC_UART6CKSELR, 0, 0x7, uart6_parents), +- STM32MP1_CLK_PARENT(_UART24_SEL, RCC_UART24CKSELR, 0, 0x7, +- uart24_parents), +- STM32MP1_CLK_PARENT(_UART35_SEL, RCC_UART35CKSELR, 0, 0x7, +- uart35_parents), +- STM32MP1_CLK_PARENT(_UART78_SEL, RCC_UART78CKSELR, 0, 0x7, +- uart78_parents), +- STM32MP1_CLK_PARENT(_SDMMC12_SEL, RCC_SDMMC12CKSELR, 0, 0x7, +- sdmmc12_parents), +- STM32MP1_CLK_PARENT(_SDMMC3_SEL, RCC_SDMMC3CKSELR, 0, 0x7, +- sdmmc3_parents), +- STM32MP1_CLK_PARENT(_QSPI_SEL, RCC_QSPICKSELR, 0, 0xf, qspi_parents), +- STM32MP1_CLK_PARENT(_FMC_SEL, RCC_FMCCKSELR, 0, 0xf, fmc_parents), +- STM32MP1_CLK_PARENT(_USBPHY_SEL, RCC_USBCKSELR, 0, 0x3, usbphy_parents), +- STM32MP1_CLK_PARENT(_USBO_SEL, RCC_USBCKSELR, 4, 0x1, usbo_parents), +- STM32MP1_CLK_PARENT(_STGEN_SEL, RCC_STGENCKSELR, 0, 0x3, stgen_parents), ++ _CLK_PARENT(_I2C12_SEL, RCC_I2C12CKSELR, 0, 0x7, i2c12_parents), ++ _CLK_PARENT(_I2C35_SEL, RCC_I2C35CKSELR, 0, 0x7, i2c35_parents), ++ _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), ++ _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(_SDMMC12_SEL, RCC_SDMMC12CKSELR, 0, 0x7, sdmmc12_parents), ++ _CLK_PARENT(_SDMMC3_SEL, RCC_SDMMC3CKSELR, 0, 0x7, sdmmc3_parents), ++ _CLK_PARENT(_QSPI_SEL, RCC_QSPICKSELR, 0, 0xf, qspi_parents), ++ _CLK_PARENT(_FMC_SEL, RCC_FMCCKSELR, 0, 0xf, fmc_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), + }; + + /* Define characteristic of PLL according type */ +@@ -411,29 +502,33 @@ static const struct stm32mp1_pll stm32mp1_pll[PLL_TYPE_NB] = { + 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 ++ [_DIV_R] = RCC_PLLNCFGR2_DIVR_SHIFT, + }; + + static const struct stm32mp1_clk_pll stm32mp1_clk_pll[_PLL_NB] = { +- STM32MP1_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), +- STM32MP1_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), +- STM32MP1_CLK_PLL(_PLL3, PLL_800, +- RCC_RCK3SELR, RCC_PLL3CFGR1, RCC_PLL3CFGR2, +- RCC_PLL3FRACR, RCC_PLL3CR, RCC_PLL3CSGR, +- _HSI, _HSE, _CSI, _UNKNOWN_OSC_ID), +- STM32MP1_CLK_PLL(_PLL4, PLL_800, +- RCC_RCK4SELR, RCC_PLL4CFGR1, RCC_PLL4CFGR2, +- RCC_PLL4FRACR, RCC_PLL4CR, RCC_PLL4CSGR, +- _HSI, _HSE, _CSI, _I2S_CKIN), ++ _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 +@@ -447,33 +542,210 @@ static const uint8_t stm32mp1_axi_div[8] = { + 1, 2, 3, 4, 4, 4, 4, 4 + }; + +-static const struct stm32mp1_clk_data stm32mp1_data = { +- .gate = stm32mp1_clk_gate, +- .sel = stm32mp1_clk_sel, +- .pll = stm32mp1_clk_pll, +- .nb_gate = ARRAY_SIZE(stm32mp1_clk_gate), ++#if LOG_LEVEL >= LOG_LEVEL_VERBOSE ++static const char * const stm32mp1_clk_parent_name[_PARENT_NB] __unused = { ++ [_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", ++}; ++ ++static const char * ++const stm32mp1_clk_parent_sel_name[_PARENT_SEL_NB] __unused = { ++ [_I2C12_SEL] = "I2C12", ++ [_I2C35_SEL] = "I2C35", ++ [_STGEN_SEL] = "STGEN", ++ [_I2C46_SEL] = "I2C46", ++ [_SPI6_SEL] = "SPI6", ++ [_USART1_SEL] = "USART1", ++ [_RNG1_SEL] = "RNG1", ++ [_UART6_SEL] = "UART6", ++ [_UART24_SEL] = "UART24", ++ [_UART35_SEL] = "UART35", ++ [_UART78_SEL] = "UART78", ++ [_SDMMC12_SEL] = "SDMMC12", ++ [_SDMMC3_SEL] = "SDMMC3", ++ [_QSPI_SEL] = "QSPI", ++ [_FMC_SEL] = "FMC", ++ [_ASS_SEL] = "ASS", ++ [_MSS_SEL] = "MSS", ++ [_USBPHY_SEL] = "USBPHY", ++ [_USBO_SEL] = "USBO", ++}; ++#endif ++ ++/* RCC clock device driver private */ ++static unsigned long stm32mp1_osc[NB_OSC]; ++static struct spinlock reg_lock; ++static unsigned int gate_refcounts[NB_GATES]; ++static struct spinlock refcount_lock; ++ ++static 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]; ++} ++ ++#if defined(IMAGE_BL32) ++/* List of forbiden values for hsi */ ++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 }; ++ ++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 stm32mp1_clk_cal_hsi = { ++ .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 struct stm32mp1_clk_cal stm32mp1_clk_cal_csi = { ++ .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 struct stm32mp1_clk_priv stm32mp1_clk_priv_data; ++static uint32_t timer_val; ++#endif ++ ++static int stm32mp1_lock_available(void) ++{ ++ /* The spinlocks are used only when MMU is enabled */ ++ return (read_sctlr() & SCTLR_M_BIT) && (read_sctlr() & SCTLR_C_BIT); ++} ++ ++static void stm32mp1_clk_lock(struct spinlock *lock) ++{ ++ if (stm32mp1_lock_available() == 0U) { ++ return; ++ } ++ ++ /* Assume interrupts are masked */ ++ spin_lock(lock); ++} ++ ++static void stm32mp1_clk_unlock(struct spinlock *lock) ++{ ++ if (stm32mp1_lock_available() == 0U) { ++ return; ++ } ++ ++ spin_unlock(lock); ++} ++ ++bool stm32mp1_rcc_is_secure(void) ++{ ++ uintptr_t rcc_base = stm32mp_rcc_base(); ++ ++ return (mmio_read_32(rcc_base + RCC_TZCR) & RCC_TZCR_TZEN) != 0; ++} ++ ++bool stm32mp1_rcc_is_mckprot(void) ++{ ++ uintptr_t rcc_base = stm32mp_rcc_base(); ++ ++ return (mmio_read_32(rcc_base + RCC_TZCR) & RCC_TZCR_MCKPROT) != 0; ++} ++ ++void stm32mp1_clk_rcc_regs_lock(void) ++{ ++ stm32mp1_clk_lock(®_lock); ++} ++ ++void stm32mp1_clk_rcc_regs_unlock(void) ++{ ++ stm32mp1_clk_unlock(®_lock); ++} ++ ++static unsigned int get_id_from_rcc_bit(unsigned int offset, unsigned int bit) ++{ ++ unsigned int idx; ++ ++ for (idx = 0U; idx < NB_GATES; idx++) { ++ const struct stm32mp1_clk_gate *gate = gate_ref(idx); + +-static unsigned long stm32mp1_clk_get_fixed(struct stm32mp1_clk_priv *priv, +- enum stm32mp_osc_id 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) { + return 0; + } + +- return priv->osc[idx]; ++ return stm32mp1_osc[idx]; + } + +-static int stm32mp1_clk_get_id(struct stm32mp1_clk_priv *priv, unsigned long id) ++static int stm32mp1_clk_get_gated_id(unsigned long id) + { +- const struct stm32mp1_clk_gate *gate = priv->data->gate; +- int i; +- int nb_clks = priv->data->nb_gate; ++ unsigned int i; + +- for (i = 0; i < nb_clks; i++) { +- if (gate[i].index == id) { ++ for (i = 0U; i < NB_GATES; i++) { ++ if (gate_ref(i)->index == id) { + return i; + } + } +@@ -483,77 +755,70 @@ static int stm32mp1_clk_get_id(struct stm32mp1_clk_priv *priv, unsigned long id) + return -EINVAL; + } + +-static enum stm32mp1_parent_sel +-stm32mp1_clk_get_sel(struct stm32mp1_clk_priv *priv, int i) ++static enum stm32mp1_parent_sel stm32mp1_clk_get_sel(int i) + { +- const struct stm32mp1_clk_gate *gate = priv->data->gate; +- +- return gate[i].sel; ++ return (enum stm32mp1_parent_sel)(gate_ref(i)->sel); + } + +-static enum stm32mp1_parent_id +-stm32mp1_clk_get_fixed_parent(struct stm32mp1_clk_priv *priv, int i) ++static enum stm32mp1_parent_id stm32mp1_clk_get_fixed_parent(int i) + { +- const struct stm32mp1_clk_gate *gate = priv->data->gate; +- +- return gate[i].fixed; ++ return (enum stm32mp1_parent_id)gate_ref(i)->fixed; + } + +-static int stm32mp1_clk_get_parent(struct stm32mp1_clk_priv *priv, +- unsigned long id) ++static int stm32mp1_clk_get_parent(unsigned long id) + { +- const struct stm32mp1_clk_sel *sel = priv->data->sel; ++ const struct stm32mp1_clk_sel *sel; + uint32_t j, p_sel; + int i; + enum stm32mp1_parent_id p; + enum stm32mp1_parent_sel s; ++ uintptr_t rcc_base = stm32mp_rcc_base(); + +- for (j = 0; j < ARRAY_SIZE(stm32mp1_clks); j++) { ++ 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_id(priv, id); ++ i = stm32mp1_clk_get_gated_id(id); + if (i < 0) { +- return i; ++ panic(); + } + +- p = stm32mp1_clk_get_fixed_parent(priv, i); ++ p = stm32mp1_clk_get_fixed_parent(i); + if (p < _PARENT_NB) { + return (int)p; + } + +- s = stm32mp1_clk_get_sel(priv, i); +- if (s >= _PARENT_SEL_NB) { ++ s = stm32mp1_clk_get_sel(i); ++ if (s == _UNKNOWN_SEL) { + return -EINVAL; + } +- +- p_sel = (mmio_read_32(priv->base + sel[s].offset) >> sel[s].src) & +- sel[s].msk; +- +- if (p_sel < sel[s].nb_parent) { +- return (int)sel[s].parent[p_sel]; ++ if (s >= _PARENT_SEL_NB) { ++ panic(); + } + +- ERROR("%s: no parents defined for clk id %ld\n", __func__, id); ++ sel = clk_sel_ref(s); ++ p_sel = (mmio_read_32(rcc_base + sel->offset) >> sel->src) & sel->msk; ++ if (p_sel < sel->nb_parent) { ++#if LOG_LEVEL >= LOG_LEVEL_VERBOSE ++ VERBOSE("%s: %s clock is the parent %s of clk id %ld\n", ++ __func__, ++ stm32mp1_clk_parent_name[sel->parent[p_sel]], ++ stm32mp1_clk_parent_sel_name[s], id); ++#endif ++ return (int)sel->parent[p_sel]; ++ } + + return -EINVAL; + } + +-static unsigned long stm32mp1_pll_get_fref_ck(struct stm32mp1_clk_priv *priv, +- enum stm32mp1_pll_id pll_id) ++static unsigned long stm32mp1_pll_get_fref(const struct stm32mp1_clk_pll *pll) + { +- const struct stm32mp1_clk_pll *pll = priv->data->pll; +- uint32_t selr, src; +- unsigned long refclk; +- +- selr = mmio_read_32(priv->base + pll[pll_id].rckxselr); +- src = selr & RCC_SELR_REFCLK_SRC_MASK; ++ uint32_t selr = mmio_read_32(stm32mp_rcc_base() + pll->rckxselr); ++ uint32_t src = selr & RCC_SELR_REFCLK_SRC_MASK; + +- refclk = stm32mp1_clk_get_fixed(priv, pll[pll_id].refclk[src]); +- +- return refclk; ++ return stm32mp1_clk_get_fixed(pll->refclk[src]); + } + + /* +@@ -562,20 +827,19 @@ static unsigned long stm32mp1_pll_get_fref_ck(struct stm32mp1_clk_priv *priv, + * - 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(struct stm32mp1_clk_priv *priv, +- enum stm32mp1_pll_id pll_id) ++static unsigned long stm32mp1_pll_get_fvco(const struct stm32mp1_clk_pll *pll) + { +- const struct stm32mp1_clk_pll *pll = priv->data->pll; + unsigned long refclk, fvco; + uint32_t cfgr1, fracr, divm, divn; ++ uintptr_t rcc_base = stm32mp_rcc_base(); + +- cfgr1 = mmio_read_32(priv->base + pll[pll_id].pllxcfgr1); +- fracr = mmio_read_32(priv->base + pll[pll_id].pllxfracr); ++ cfgr1 = mmio_read_32(rcc_base + pll->pllxcfgr1); ++ fracr = mmio_read_32(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_ck(priv, pll_id); ++ refclk = stm32mp1_pll_get_fref(pll); + + /* + * With FRACV : +@@ -584,13 +848,13 @@ static unsigned long stm32mp1_pll_get_fvco(struct stm32mp1_clk_priv *priv, + * Fvco = Fck_ref * ((DIVN + 1) / (DIVM + 1) + */ + if ((fracr & RCC_PLLNFRACR_FRACLE) != 0U) { +- uint32_t fracv = (fracr & RCC_PLLNFRACR_FRACV_MASK) +- >> RCC_PLLNFRACR_FRACV_SHIFT; ++ uint32_t fracv = (fracr & RCC_PLLNFRACR_FRACV_MASK) >> ++ RCC_PLLNFRACR_FRACV_SHIFT; + unsigned long long numerator, denominator; + +- numerator = ((unsigned long long)divn + 1U) << 13; +- numerator = (refclk * numerator) + fracv; +- denominator = ((unsigned long long)divm + 1U) << 13; ++ 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)); +@@ -599,11 +863,10 @@ static unsigned long stm32mp1_pll_get_fvco(struct stm32mp1_clk_priv *priv, + return fvco; + } + +-static unsigned long stm32mp1_read_pll_freq(struct stm32mp1_clk_priv *priv, +- enum stm32mp1_pll_id pll_id, ++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 = priv->data->pll; ++ const struct stm32mp1_clk_pll *pll = pll_ref(pll_id); + unsigned long dfout; + uint32_t cfgr2, divy; + +@@ -611,42 +874,43 @@ static unsigned long stm32mp1_read_pll_freq(struct stm32mp1_clk_priv *priv, + return 0; + } + +- cfgr2 = mmio_read_32(priv->base + pll[pll_id].pllxcfgr2); ++ cfgr2 = mmio_read_32(stm32mp_rcc_base() + pll->pllxcfgr2); + divy = (cfgr2 >> pllncfgr2[div_id]) & RCC_PLLNCFGR2_DIVX_MASK; + +- dfout = stm32mp1_pll_get_fvco(priv, pll_id) / (divy + 1U); ++ dfout = stm32mp1_pll_get_fvco(pll) / (divy + 1U); ++ + + return dfout; + } + +-static unsigned long stm32mp1_clk_get(struct stm32mp1_clk_priv *priv, int p) ++static unsigned long get_clock_rate(int p) + { + uint32_t reg, clkdiv; + unsigned long clock = 0; ++ uintptr_t rcc_base = stm32mp_rcc_base(); + + switch (p) { + case _CK_MPU: + /* MPU sub system */ +- reg = mmio_read_32(priv->base + RCC_MPCKSELR); ++ reg = mmio_read_32(rcc_base + RCC_MPCKSELR); + switch (reg & RCC_SELR_SRC_MASK) { + case RCC_MPCKSELR_HSI: +- clock = stm32mp1_clk_get_fixed(priv, _HSI); ++ clock = stm32mp1_clk_get_fixed(_HSI); + break; + case RCC_MPCKSELR_HSE: +- clock = stm32mp1_clk_get_fixed(priv, _HSE); ++ clock = stm32mp1_clk_get_fixed(_HSE); + break; + case RCC_MPCKSELR_PLL: +- clock = stm32mp1_read_pll_freq(priv, _PLL1, _DIV_P); ++ clock = stm32mp1_read_pll_freq(_PLL1, _DIV_P); + break; + case RCC_MPCKSELR_PLL_MPUDIV: +- clock = stm32mp1_read_pll_freq(priv, _PLL1, _DIV_P); ++ clock = stm32mp1_read_pll_freq(_PLL1, _DIV_P); + +- reg = mmio_read_32(priv->base + RCC_MPCKDIVR); ++ reg = mmio_read_32(rcc_base + RCC_MPCKDIVR); + clkdiv = reg & RCC_MPUDIV_MASK; + if (clkdiv != 0U) { + clock /= stm32mp1_mpu_div[clkdiv]; + } +- + break; + default: + break; +@@ -658,49 +922,94 @@ static unsigned long stm32mp1_clk_get(struct stm32mp1_clk_priv *priv, int p) + case _HCLK6: + case _PCLK4: + case _PCLK5: +- reg = mmio_read_32(priv->base + RCC_ASSCKSELR); ++ reg = mmio_read_32(rcc_base + RCC_ASSCKSELR); + switch (reg & RCC_SELR_SRC_MASK) { + case RCC_ASSCKSELR_HSI: +- clock = stm32mp1_clk_get_fixed(priv, _HSI); ++ clock = stm32mp1_clk_get_fixed(_HSI); + break; + case RCC_ASSCKSELR_HSE: +- clock = stm32mp1_clk_get_fixed(priv, _HSE); ++ clock = stm32mp1_clk_get_fixed(_HSE); + break; + case RCC_ASSCKSELR_PLL: +- clock = stm32mp1_read_pll_freq(priv, _PLL2, _DIV_P); ++ clock = stm32mp1_read_pll_freq(_PLL2, _DIV_P); + break; + default: + break; + } + + /* System clock divider */ +- reg = mmio_read_32(priv->base + RCC_AXIDIVR); ++ reg = mmio_read_32(rcc_base + RCC_AXIDIVR); + clock /= stm32mp1_axi_div[reg & RCC_AXIDIV_MASK]; + + switch (p) { + case _PCLK4: +- reg = mmio_read_32(priv->base + RCC_APB4DIVR); ++ reg = mmio_read_32(rcc_base + RCC_APB4DIVR); + clock >>= stm32mp1_apbx_div[reg & RCC_APBXDIV_MASK]; + break; + case _PCLK5: +- reg = mmio_read_32(priv->base + RCC_APB5DIVR); ++ 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(priv->base + RCC_CPERCKSELR); ++ reg = mmio_read_32(rcc_base + RCC_CPERCKSELR); + switch (reg & RCC_SELR_SRC_MASK) { + case RCC_CPERCKSELR_HSI: +- clock = stm32mp1_clk_get_fixed(priv, _HSI); ++ clock = stm32mp1_clk_get_fixed(_HSI); + break; + case RCC_CPERCKSELR_HSE: +- clock = stm32mp1_clk_get_fixed(priv, _HSE); ++ clock = stm32mp1_clk_get_fixed(_HSE); + break; + case RCC_CPERCKSELR_CSI: +- clock = stm32mp1_clk_get_fixed(priv, _CSI); ++ clock = stm32mp1_clk_get_fixed(_CSI); + break; + default: + break; +@@ -708,65 +1017,65 @@ static unsigned long stm32mp1_clk_get(struct stm32mp1_clk_priv *priv, int p) + break; + case _HSI: + case _HSI_KER: +- clock = stm32mp1_clk_get_fixed(priv, _HSI); ++ clock = stm32mp1_clk_get_fixed(_HSI); + break; + case _CSI: + case _CSI_KER: +- clock = stm32mp1_clk_get_fixed(priv, _CSI); ++ clock = stm32mp1_clk_get_fixed(_CSI); + break; + case _HSE: + case _HSE_KER: +- clock = stm32mp1_clk_get_fixed(priv, _HSE); ++ clock = stm32mp1_clk_get_fixed(_HSE); + break; + case _HSE_KER_DIV2: +- clock = stm32mp1_clk_get_fixed(priv, _HSE) >> 1; ++ clock = stm32mp1_clk_get_fixed(_HSE) >> 1; + break; + case _LSI: +- clock = stm32mp1_clk_get_fixed(priv, _LSI); ++ clock = stm32mp1_clk_get_fixed(_LSI); + break; + case _LSE: +- clock = stm32mp1_clk_get_fixed(priv, _LSE); ++ clock = stm32mp1_clk_get_fixed(_LSE); + break; + /* PLL */ + case _PLL1_P: +- clock = stm32mp1_read_pll_freq(priv, _PLL1, _DIV_P); ++ clock = stm32mp1_read_pll_freq(_PLL1, _DIV_P); + break; + case _PLL1_Q: +- clock = stm32mp1_read_pll_freq(priv, _PLL1, _DIV_Q); ++ clock = stm32mp1_read_pll_freq(_PLL1, _DIV_Q); + break; + case _PLL1_R: +- clock = stm32mp1_read_pll_freq(priv, _PLL1, _DIV_R); ++ clock = stm32mp1_read_pll_freq(_PLL1, _DIV_R); + break; + case _PLL2_P: +- clock = stm32mp1_read_pll_freq(priv, _PLL2, _DIV_P); ++ clock = stm32mp1_read_pll_freq(_PLL2, _DIV_P); + break; + case _PLL2_Q: +- clock = stm32mp1_read_pll_freq(priv, _PLL2, _DIV_Q); ++ clock = stm32mp1_read_pll_freq(_PLL2, _DIV_Q); + break; + case _PLL2_R: +- clock = stm32mp1_read_pll_freq(priv, _PLL2, _DIV_R); ++ clock = stm32mp1_read_pll_freq(_PLL2, _DIV_R); + break; + case _PLL3_P: +- clock = stm32mp1_read_pll_freq(priv, _PLL3, _DIV_P); ++ clock = stm32mp1_read_pll_freq(_PLL3, _DIV_P); + break; + case _PLL3_Q: +- clock = stm32mp1_read_pll_freq(priv, _PLL3, _DIV_Q); ++ clock = stm32mp1_read_pll_freq(_PLL3, _DIV_Q); + break; + case _PLL3_R: +- clock = stm32mp1_read_pll_freq(priv, _PLL3, _DIV_R); ++ clock = stm32mp1_read_pll_freq(_PLL3, _DIV_R); + break; + case _PLL4_P: +- clock = stm32mp1_read_pll_freq(priv, _PLL4, _DIV_P); ++ clock = stm32mp1_read_pll_freq(_PLL4, _DIV_P); + break; + case _PLL4_Q: +- clock = stm32mp1_read_pll_freq(priv, _PLL4, _DIV_Q); ++ clock = stm32mp1_read_pll_freq(_PLL4, _DIV_Q); + break; + case _PLL4_R: +- clock = stm32mp1_read_pll_freq(priv, _PLL4, _DIV_R); ++ clock = stm32mp1_read_pll_freq(_PLL4, _DIV_R); + break; + /* Other */ + case _USB_PHY_48: +- clock = stm32mp1_clk_get_fixed(priv, _USB_PHY_48); ++ clock = USB_PHY_48_MHZ; + break; + default: + break; +@@ -775,112 +1084,155 @@ static unsigned long stm32mp1_clk_get(struct stm32mp1_clk_priv *priv, int p) + return clock; + } + +-bool stm32mp1_clk_is_enabled(unsigned long id) ++static void __clk_enable(struct stm32mp1_clk_gate const *gate) ++{ ++ uintptr_t rcc_base = stm32mp_rcc_base(); ++ ++ if (gate->set_clr != 0U) { ++ mmio_write_32(rcc_base + gate->offset, BIT(gate->bit)); ++ } else { ++ stm32mp_mmio_setbits_32_shregs(rcc_base + gate->offset, ++ BIT(gate->bit)); ++ } ++ ++ VERBOSE("Clock %d has been enabled", gate->index); ++} ++ ++static void __clk_disable(struct stm32mp1_clk_gate const *gate) ++{ ++ uintptr_t rcc_base = stm32mp_rcc_base(); ++ ++ if (gate->set_clr != 0U) { ++ mmio_write_32(rcc_base + gate->offset + RCC_MP_ENCLRR_OFFSET, ++ BIT(gate->bit)); ++ } else { ++ stm32mp_mmio_clrbits_32_shregs(rcc_base + gate->offset, ++ BIT(gate->bit)); ++ } ++ ++ VERBOSE("Clock %d has been disabled", gate->index); ++} ++ ++static bool __clk_is_enabled(struct stm32mp1_clk_gate const *gate) ++{ ++ uintptr_t rcc_base = stm32mp_rcc_base(); ++ ++ return mmio_read_32(rcc_base + gate->offset) & BIT(gate->bit); ++} ++ ++unsigned int stm32mp1_clk_get_refcount(unsigned long id) + { +- struct stm32mp1_clk_priv *priv = &stm32mp1_clk_priv_data; +- const struct stm32mp1_clk_gate *gate = priv->data->gate; +- int i = stm32mp1_clk_get_id(priv, id); ++ int i = stm32mp1_clk_get_gated_id(id); + + if (i < 0) { +- return false; ++ panic(); + } + +- return ((mmio_read_32(priv->base + gate[i].offset) & +- BIT(gate[i].bit)) != 0U); ++ return gate_refcounts[i]; + } + +-int stm32mp1_clk_enable(unsigned long id) ++void __stm32mp1_clk_enable(unsigned long id, bool secure) + { +- struct stm32mp1_clk_priv *priv = &stm32mp1_clk_priv_data; +- const struct stm32mp1_clk_gate *gate = priv->data->gate; +- int i = stm32mp1_clk_get_id(priv, id); ++ const struct stm32mp1_clk_gate *gate; ++ int i = stm32mp1_clk_get_gated_id(id); ++ unsigned int *refcnt; + + if (i < 0) { +- return i; ++ ERROR("Clock %d can't be enabled\n", (uint32_t)id); ++ panic(); + } + +- if (gate[i].set_clr != 0U) { +- mmio_write_32(priv->base + gate[i].offset, BIT(gate[i].bit)); +- } else { +- mmio_setbits_32(priv->base + gate[i].offset, BIT(gate[i].bit)); ++ gate = gate_ref(i); ++ refcnt = &gate_refcounts[i]; ++ ++ stm32mp1_clk_lock(&refcount_lock); ++ ++ if (stm32mp_incr_shrefcnt(refcnt, secure) != 0) { ++ __clk_enable(gate); + } + +- return 0; ++ stm32mp1_clk_unlock(&refcount_lock); + } + +-int stm32mp1_clk_disable(unsigned long id) ++void __stm32mp1_clk_disable(unsigned long id, bool secure) + { +- struct stm32mp1_clk_priv *priv = &stm32mp1_clk_priv_data; +- const struct stm32mp1_clk_gate *gate = priv->data->gate; +- int i = stm32mp1_clk_get_id(priv, id); ++ const struct stm32mp1_clk_gate *gate; ++ int i = stm32mp1_clk_get_gated_id(id); ++ unsigned int *refcnt; + + if (i < 0) { +- return i; ++ ERROR("Clock %d can't be disabled\n", (uint32_t)id); ++ panic(); + } + +- if (gate[i].set_clr != 0U) { +- mmio_write_32(priv->base + gate[i].offset +- + RCC_MP_ENCLRR_OFFSET, +- BIT(gate[i].bit)); +- } else { +- mmio_clrbits_32(priv->base + gate[i].offset, BIT(gate[i].bit)); ++ gate = gate_ref(i); ++ refcnt = &gate_refcounts[i]; ++ ++ stm32mp1_clk_lock(&refcount_lock); ++ ++ if (stm32mp_decr_shrefcnt(refcnt, secure) != 0) { ++ __clk_disable(gate); + } + +- return 0; ++ stm32mp1_clk_unlock(&refcount_lock); + } + +-unsigned long stm32mp1_clk_get_rate(unsigned long id) ++bool stm32mp1_clk_is_enabled(unsigned long id) + { +- struct stm32mp1_clk_priv *priv = &stm32mp1_clk_priv_data; +- int p = stm32mp1_clk_get_parent(priv, id); +- unsigned long rate; ++ int i = stm32mp1_clk_get_gated_id(id); ++ ++ if (i < 0) { ++ panic(); ++ } ++ ++ return __clk_is_enabled(gate_ref(i)); ++} ++ ++unsigned long stm32mp_clk_get_rate(unsigned long id) ++{ ++ int p = stm32mp1_clk_get_parent(id); + + if (p < 0) { + return 0; + } + +- rate = stm32mp1_clk_get(priv, p); +- +- return rate; ++ return get_clock_rate(p); + } + +-static void stm32mp1_ls_osc_set(int enable, uint32_t rcc, uint32_t offset, +- uint32_t mask_on) ++static void stm32mp1_ls_osc_set(bool enable, uint32_t offset, uint32_t mask_on) + { +- uint32_t address = rcc + offset; ++ uint32_t address = stm32mp_rcc_base() + offset; + +- if (enable != 0) { ++ if (enable) { + mmio_setbits_32(address, mask_on); + } else { + mmio_clrbits_32(address, mask_on); + } + } + +-static void stm32mp1_hs_ocs_set(int enable, uint32_t rcc, uint32_t mask_on) ++static void stm32mp1_hs_ocs_set(bool enable, uint32_t mask_on) + { +- if (enable != 0) { +- mmio_setbits_32(rcc + RCC_OCENSETR, mask_on); +- } else { +- mmio_setbits_32(rcc + RCC_OCENCLRR, mask_on); +- } ++ uint32_t offset = enable ? RCC_OCENSETR : RCC_OCENCLRR; ++ uint32_t address = stm32mp_rcc_base() + offset; ++ ++ mmio_write_32(address, mask_on); + } + +-static int stm32mp1_osc_wait(int enable, uint32_t rcc, uint32_t offset, +- uint32_t mask_rdy) ++static int stm32mp1_osc_wait(bool enable, uint32_t offset, uint32_t mask_rdy) + { +- unsigned long start; ++ uint64_t start; + uint32_t mask_test; +- uint32_t address = rcc + offset; ++ uint32_t address = stm32mp_rcc_base() + offset; + +- if (enable != 0) { ++ if (enable) { + mask_test = mask_rdy; + } else { + mask_test = 0; + } + +- start = get_timer(0); ++ start = timeout_start(); + while ((mmio_read_32(address) & mask_rdy) != mask_test) { +- if (get_timer(start) > OSCRDY_TIMEOUT) { ++ if (timeout_elapsed(start, OSCRDY_TIMEOUT)) { + ERROR("OSC %x @ %x timeout for enable=%d : 0x%x\n", + mask_rdy, address, enable, mmio_read_32(address)); + return -ETIMEDOUT; +@@ -890,19 +1242,24 @@ static int stm32mp1_osc_wait(int enable, uint32_t rcc, uint32_t offset, + return 0; + } + +-static void stm32mp1_lse_enable(uint32_t rcc, bool bypass, uint32_t lsedrv) ++static void stm32mp1_lse_enable(bool bypass, bool digbyp, uint32_t lsedrv) + { + uint32_t value; ++ uintptr_t rcc_base = stm32mp_rcc_base(); ++ ++ if (digbyp) { ++ mmio_setbits_32(rcc_base + RCC_BDCR, RCC_BDCR_DIGBYP); ++ } + +- if (bypass) { +- mmio_setbits_32(rcc + RCC_BDCR, RCC_BDCR_LSEBYP); ++ if (bypass || digbyp) { ++ mmio_setbits_32(rcc_base + RCC_BDCR, RCC_BDCR_LSEBYP); + } + + /* + * Warning: not recommended to switch directly from "high drive" + * to "medium low drive", and vice-versa. + */ +- value = (mmio_read_32(rcc + RCC_BDCR) & RCC_BDCR_LSEDRV_MASK) >> ++ value = (mmio_read_32(rcc_base + RCC_BDCR) & RCC_BDCR_LSEDRV_MASK) >> + RCC_BDCR_LSEDRV_SHIFT; + + while (value != lsedrv) { +@@ -912,77 +1269,85 @@ static void stm32mp1_lse_enable(uint32_t rcc, bool bypass, uint32_t lsedrv) + value++; + } + +- mmio_clrsetbits_32(rcc + RCC_BDCR, ++ mmio_clrsetbits_32(rcc_base + RCC_BDCR, + RCC_BDCR_LSEDRV_MASK, + value << RCC_BDCR_LSEDRV_SHIFT); + } + +- stm32mp1_ls_osc_set(1, rcc, RCC_BDCR, RCC_BDCR_LSEON); ++ stm32mp1_ls_osc_set(true, RCC_BDCR, RCC_BDCR_LSEON); + } + +-static void stm32mp1_lse_wait(uint32_t rcc) ++static void stm32mp1_lse_wait(void) + { +- if (stm32mp1_osc_wait(1, rcc, RCC_BDCR, RCC_BDCR_LSERDY) != 0) { ++ if (stm32mp1_osc_wait(true, RCC_BDCR, RCC_BDCR_LSERDY) != 0) { + VERBOSE("%s: failed\n", __func__); + } + } + +-static void stm32mp1_lsi_set(uint32_t rcc, int enable) ++static void stm32mp1_lsi_set(bool enable) + { +- stm32mp1_ls_osc_set(enable, rcc, RCC_RDLSICR, RCC_RDLSICR_LSION); +- if (stm32mp1_osc_wait(enable, rcc, RCC_RDLSICR, RCC_RDLSICR_LSIRDY) != ++ stm32mp1_ls_osc_set(enable, RCC_RDLSICR, RCC_RDLSICR_LSION); ++ ++ if (stm32mp1_osc_wait(enable, RCC_RDLSICR, RCC_RDLSICR_LSIRDY) != + 0) { + VERBOSE("%s: failed\n", __func__); + } + } + +-static void stm32mp1_hse_enable(uint32_t rcc, bool bypass, bool css) ++static void stm32mp1_hse_enable(bool bypass, bool digbyp, bool css) + { +- if (bypass) { +- mmio_setbits_32(rcc + RCC_OCENSETR, RCC_OCENR_HSEBYP); ++ uintptr_t rcc_base = stm32mp_rcc_base(); ++ ++ if (digbyp) { ++ mmio_write_32(rcc_base + RCC_OCENSETR, RCC_OCENR_DIGBYP); ++ } ++ ++ if (bypass || digbyp) { ++ mmio_write_32(rcc_base + RCC_OCENSETR, RCC_OCENR_HSEBYP); + } + +- stm32mp1_hs_ocs_set(1, rcc, RCC_OCENR_HSEON); +- if (stm32mp1_osc_wait(1, rcc, RCC_OCRDYR, RCC_OCRDYR_HSERDY) != ++ stm32mp1_hs_ocs_set(true, RCC_OCENR_HSEON); ++ if (stm32mp1_osc_wait(true, RCC_OCRDYR, RCC_OCRDYR_HSERDY) != + 0) { + VERBOSE("%s: failed\n", __func__); + } + + if (css) { +- mmio_setbits_32(rcc + RCC_OCENSETR, RCC_OCENR_HSECSSON); ++ mmio_write_32(rcc_base + RCC_OCENSETR, RCC_OCENR_HSECSSON); + } + } + +-static void stm32mp1_csi_set(uint32_t rcc, int enable) ++static void stm32mp1_csi_set(bool enable) + { +- stm32mp1_ls_osc_set(enable, rcc, RCC_OCENSETR, RCC_OCENR_CSION); +- if (stm32mp1_osc_wait(enable, rcc, RCC_OCRDYR, RCC_OCRDYR_CSIRDY) != ++ stm32mp1_hs_ocs_set(enable, RCC_OCENR_CSION); ++ if (stm32mp1_osc_wait(enable, RCC_OCRDYR, RCC_OCRDYR_CSIRDY) != + 0) { + VERBOSE("%s: failed\n", __func__); + } + } + +-static void stm32mp1_hsi_set(uint32_t rcc, int enable) ++static void stm32mp1_hsi_set(bool enable) + { +- stm32mp1_hs_ocs_set(enable, rcc, RCC_OCENR_HSION); +- if (stm32mp1_osc_wait(enable, rcc, RCC_OCRDYR, RCC_OCRDYR_HSIRDY) != ++ stm32mp1_hs_ocs_set(enable, RCC_OCENR_HSION); ++ if (stm32mp1_osc_wait(enable, RCC_OCRDYR, RCC_OCRDYR_HSIRDY) != + 0) { + VERBOSE("%s: failed\n", __func__); + } + } + +-static int stm32mp1_set_hsidiv(uint32_t rcc, uint8_t hsidiv) ++static int stm32mp1_set_hsidiv(uint8_t hsidiv) + { +- unsigned long start; +- uint32_t address = rcc + RCC_OCRDYR; ++ uint64_t start; ++ uintptr_t rcc_base = stm32mp_rcc_base(); ++ uint32_t address = rcc_base + RCC_OCRDYR; + +- mmio_clrsetbits_32(rcc + RCC_HSICFGR, ++ mmio_clrsetbits_32(rcc_base + RCC_HSICFGR, + RCC_HSICFGR_HSIDIV_MASK, + RCC_HSICFGR_HSIDIV_MASK & (uint32_t)hsidiv); + +- start = get_timer(0); ++ start = timeout_start(); + while ((mmio_read_32(address) & RCC_OCRDYR_HSIDIVRDY) == 0U) { +- if (get_timer(start) > HSIDIV_TIMEOUT) { ++ if (timeout_elapsed(start, HSIDIV_TIMEOUT)) { + ERROR("HSIDIV failed @ 0x%x: 0x%x\n", + address, mmio_read_32(address)); + return -ETIMEDOUT; +@@ -992,7 +1357,7 @@ static int stm32mp1_set_hsidiv(uint32_t rcc, uint8_t hsidiv) + return 0; + } + +-static int stm32mp1_hsidiv(uint32_t rcc, unsigned long hsifreq) ++static int stm32mp1_hsidiv(unsigned long hsifreq) + { + uint8_t hsidiv; + uint32_t hsidivfreq = MAX_HSI_HZ; +@@ -1011,31 +1376,103 @@ static int stm32mp1_hsidiv(uint32_t rcc, unsigned long hsifreq) + } + + if (hsidiv != 0U) { +- return stm32mp1_set_hsidiv(rcc, hsidiv); ++ return stm32mp1_set_hsidiv(hsidiv); + } + + return 0; + } + +-static void stm32mp1_pll_start(struct stm32mp1_clk_priv *priv, +- enum stm32mp1_pll_id pll_id) ++static bool stm32mp1_check_pll_conf(enum stm32mp1_pll_id pll_id, ++ unsigned int clksrc, ++ uint32_t *pllcfg, int plloff) ++{ ++ const struct stm32mp1_clk_pll *pll = pll_ref(pll_id); ++ uintptr_t rcc_base = stm32mp_rcc_base(); ++ uint32_t pllxcr = rcc_base + pll->pllxcr; ++ enum stm32mp1_plltype type = pll->plltype; ++ uint32_t address = rcc_base + (clksrc >> 4); ++ unsigned long refclk; ++ uint32_t ifrge = 0U; ++ uint32_t src, value, fracv; ++ ++ /* Check PLL output */ ++ if (mmio_read_32(pllxcr) != RCC_PLLNCR_PLLON) { ++ return false; ++ } ++ ++ /* Check current clksrc */ ++ src = mmio_read_32(address) & RCC_SELR_SRC_MASK; ++ if (src != (clksrc & RCC_SELR_SRC_MASK)) { ++ return false; ++ } ++ ++ /* Check Div */ ++ src = mmio_read_32(rcc_base + pll->rckxselr) & ++ RCC_SELR_REFCLK_SRC_MASK; ++ ++ refclk = stm32mp1_clk_get_fixed(pll->refclk[src]) / ++ (pllcfg[PLLCFG_M] + 1U); ++ ++ if ((refclk < (stm32mp1_pll[type].refclk_min * 1000000U)) || ++ (refclk > (stm32mp1_pll[type].refclk_max * 1000000U))) { ++ return false; ++ } ++ ++ if ((type == PLL_800) && (refclk >= 8000000U)) { ++ ifrge = 1U; ++ } ++ ++ value = (pllcfg[PLLCFG_N] << RCC_PLLNCFGR1_DIVN_SHIFT) & ++ RCC_PLLNCFGR1_DIVN_MASK; ++ value |= (pllcfg[PLLCFG_M] << RCC_PLLNCFGR1_DIVM_SHIFT) & ++ RCC_PLLNCFGR1_DIVM_MASK; ++ value |= (ifrge << RCC_PLLNCFGR1_IFRGE_SHIFT) & ++ RCC_PLLNCFGR1_IFRGE_MASK; ++ if (mmio_read_32(rcc_base + pll->pllxcfgr1) != value) { ++ return false; ++ } ++ ++ /* Fractional configuration */ ++ fracv = fdt_read_uint32_default(plloff, "frac", 0); ++ ++ value = fracv << RCC_PLLNFRACR_FRACV_SHIFT; ++ value |= RCC_PLLNFRACR_FRACLE; ++ if (mmio_read_32(rcc_base + pll->pllxfracr) != value) { ++ return false; ++ } ++ ++ /* Output config */ ++ value = (pllcfg[PLLCFG_P] << RCC_PLLNCFGR2_DIVP_SHIFT) & ++ RCC_PLLNCFGR2_DIVP_MASK; ++ value |= (pllcfg[PLLCFG_Q] << RCC_PLLNCFGR2_DIVQ_SHIFT) & ++ RCC_PLLNCFGR2_DIVQ_MASK; ++ value |= (pllcfg[PLLCFG_R] << RCC_PLLNCFGR2_DIVR_SHIFT) & ++ RCC_PLLNCFGR2_DIVR_MASK; ++ if (mmio_read_32(rcc_base + pll->pllxcfgr2) != value) { ++ return false; ++ } ++ ++ return true; ++} ++ ++static void stm32mp1_pll_start(enum stm32mp1_pll_id pll_id) + { +- const struct stm32mp1_clk_pll *pll = priv->data->pll; ++ const struct stm32mp1_clk_pll *pll = pll_ref(pll_id); ++ uint32_t pllxcr = stm32mp_rcc_base() + pll->pllxcr; + +- mmio_write_32(priv->base + pll[pll_id].pllxcr, RCC_PLLNCR_PLLON); ++ mmio_write_32(pllxcr, RCC_PLLNCR_PLLON); + } + +-static int stm32mp1_pll_output(struct stm32mp1_clk_priv *priv, +- enum stm32mp1_pll_id pll_id, uint32_t output) ++static int stm32mp1_pll_output(enum stm32mp1_pll_id pll_id, uint32_t output) + { +- const struct stm32mp1_clk_pll *pll = priv->data->pll; +- uint32_t pllxcr = priv->base + pll[pll_id].pllxcr; +- unsigned long start; ++ const struct stm32mp1_clk_pll *pll = pll_ref(pll_id); ++ uint32_t pllxcr = stm32mp_rcc_base() + pll->pllxcr; ++ uint64_t start; + +- start = get_timer(0); ++ start = timeout_start(); + /* Wait PLL lock */ + while ((mmio_read_32(pllxcr) & RCC_PLLNCR_PLLRDY) == 0U) { +- if (get_timer(start) > PLLRDY_TIMEOUT) { ++ if (timeout_elapsed(start, PLLRDY_TIMEOUT)) { + ERROR("PLL%d start failed @ 0x%x: 0x%x\n", + pll_id, pllxcr, mmio_read_32(pllxcr)); + return -ETIMEDOUT; +@@ -1048,12 +1485,11 @@ static int stm32mp1_pll_output(struct stm32mp1_clk_priv *priv, + return 0; + } + +-static int stm32mp1_pll_stop(struct stm32mp1_clk_priv *priv, +- enum stm32mp1_pll_id pll_id) ++static int stm32mp1_pll_stop(enum stm32mp1_pll_id pll_id) + { +- const struct stm32mp1_clk_pll *pll = priv->data->pll; +- uint32_t pllxcr = priv->base + pll[pll_id].pllxcr; +- unsigned long start; ++ const struct stm32mp1_clk_pll *pll = pll_ref(pll_id); ++ uint32_t pllxcr = stm32mp_rcc_base() + pll->pllxcr; ++ uint64_t start; + + /* Stop all output */ + mmio_clrbits_32(pllxcr, RCC_PLLNCR_DIVPEN | RCC_PLLNCR_DIVQEN | +@@ -1062,10 +1498,10 @@ static int stm32mp1_pll_stop(struct stm32mp1_clk_priv *priv, + /* Stop PLL */ + mmio_clrbits_32(pllxcr, RCC_PLLNCR_PLLON); + +- start = get_timer(0); ++ start = timeout_start(); + /* Wait PLL stopped */ + while ((mmio_read_32(pllxcr) & RCC_PLLNCR_PLLRDY) != 0U) { +- if (get_timer(start) > PLLRDY_TIMEOUT) { ++ if (timeout_elapsed(start, PLLRDY_TIMEOUT)) { + ERROR("PLL%d stop failed @ 0x%x: 0x%x\n", + pll_id, pllxcr, mmio_read_32(pllxcr)); + return -ETIMEDOUT; +@@ -1075,12 +1511,11 @@ static int stm32mp1_pll_stop(struct stm32mp1_clk_priv *priv, + return 0; + } + +-static void stm32mp1_pll_config_output(struct stm32mp1_clk_priv *priv, +- enum stm32mp1_pll_id pll_id, ++static void stm32mp1_pll_config_output(enum stm32mp1_pll_id pll_id, + uint32_t *pllcfg) + { +- const struct stm32mp1_clk_pll *pll = priv->data->pll; +- uint32_t rcc = priv->base; ++ const struct stm32mp1_clk_pll *pll = pll_ref(pll_id); ++ uintptr_t rcc_base = stm32mp_rcc_base(); + uint32_t value; + + value = (pllcfg[PLLCFG_P] << RCC_PLLNCFGR2_DIVP_SHIFT) & +@@ -1089,24 +1524,23 @@ static void stm32mp1_pll_config_output(struct stm32mp1_clk_priv *priv, + RCC_PLLNCFGR2_DIVQ_MASK; + value |= (pllcfg[PLLCFG_R] << RCC_PLLNCFGR2_DIVR_SHIFT) & + RCC_PLLNCFGR2_DIVR_MASK; +- mmio_write_32(rcc + pll[pll_id].pllxcfgr2, value); ++ mmio_write_32(rcc_base + pll->pllxcfgr2, value); + } + +-static int stm32mp1_pll_config(struct stm32mp1_clk_priv *priv, +- enum stm32mp1_pll_id pll_id, ++static int stm32mp1_pll_config(enum stm32mp1_pll_id pll_id, + uint32_t *pllcfg, uint32_t fracv) + { +- const struct stm32mp1_clk_pll *pll = priv->data->pll; +- uint32_t rcc = priv->base; +- enum stm32mp1_plltype type = pll[pll_id].plltype; ++ const struct stm32mp1_clk_pll *pll = pll_ref(pll_id); ++ uint32_t rcc_base = stm32mp_rcc_base(); ++ enum stm32mp1_plltype type = pll->plltype; + unsigned long refclk; + uint32_t ifrge = 0; + uint32_t src, value; + +- src = mmio_read_32(priv->base + pll[pll_id].rckxselr) & ++ src = mmio_read_32(rcc_base + pll->rckxselr) & + RCC_SELR_REFCLK_SRC_MASK; + +- refclk = stm32mp1_clk_get_fixed(priv, pll[pll_id].refclk[src]) / ++ refclk = stm32mp1_clk_get_fixed(pll->refclk[src]) / + (pllcfg[PLLCFG_M] + 1U); + + if ((refclk < (stm32mp1_pll[type].refclk_min * 1000000U)) || +@@ -1124,28 +1558,26 @@ static int stm32mp1_pll_config(struct stm32mp1_clk_priv *priv, + RCC_PLLNCFGR1_DIVM_MASK; + value |= (ifrge << RCC_PLLNCFGR1_IFRGE_SHIFT) & + RCC_PLLNCFGR1_IFRGE_MASK; +- mmio_write_32(rcc + pll[pll_id].pllxcfgr1, value); ++ mmio_write_32(rcc_base + pll->pllxcfgr1, value); + + /* Fractional configuration */ + value = 0; +- mmio_write_32(rcc + pll[pll_id].pllxfracr, value); ++ mmio_write_32(rcc_base + pll->pllxfracr, value); + + value = fracv << RCC_PLLNFRACR_FRACV_SHIFT; +- mmio_write_32(rcc + pll[pll_id].pllxfracr, value); ++ mmio_write_32(rcc_base + pll->pllxfracr, value); + + value |= RCC_PLLNFRACR_FRACLE; +- mmio_write_32(rcc + pll[pll_id].pllxfracr, value); ++ mmio_write_32(rcc_base + pll->pllxfracr, value); + +- stm32mp1_pll_config_output(priv, pll_id, pllcfg); ++ stm32mp1_pll_config_output(pll_id, pllcfg); + + return 0; + } + +-static void stm32mp1_pll_csg(struct stm32mp1_clk_priv *priv, +- enum stm32mp1_pll_id pll_id, +- uint32_t *csg) ++static void stm32mp1_pll_csg(enum stm32mp1_pll_id pll_id, uint32_t *csg) + { +- const struct stm32mp1_clk_pll *pll = priv->data->pll; ++ const struct stm32mp1_clk_pll *pll = pll_ref(pll_id); + uint32_t pllxcsg = 0; + + pllxcsg |= (csg[PLLCSG_MOD_PER] << RCC_PLLNCSGR_MOD_PER_SHIFT) & +@@ -1157,21 +1589,20 @@ static void stm32mp1_pll_csg(struct stm32mp1_clk_priv *priv, + pllxcsg |= (csg[PLLCSG_SSCG_MODE] << RCC_PLLNCSGR_SSCG_MODE_SHIFT) & + RCC_PLLNCSGR_SSCG_MODE_MASK; + +- mmio_write_32(priv->base + pll[pll_id].pllxcsgr, pllxcsg); ++ mmio_write_32(stm32mp_rcc_base() + pll->pllxcsgr, pllxcsg); + } + +-static int stm32mp1_set_clksrc(struct stm32mp1_clk_priv *priv, +- unsigned int clksrc) ++static int stm32mp1_set_clksrc(unsigned int clksrc) + { +- uint32_t address = priv->base + (clksrc >> 4); +- unsigned long start; ++ uint32_t address = stm32mp_rcc_base() + (clksrc >> 4); ++ uint64_t start; + + mmio_clrsetbits_32(address, RCC_SELR_SRC_MASK, + clksrc & RCC_SELR_SRC_MASK); + +- start = get_timer(0); ++ start = timeout_start(); + while ((mmio_read_32(address) & RCC_SELR_SRCRDY) == 0U) { +- if (get_timer(start) > CLKSRC_TIMEOUT) { ++ if (timeout_elapsed(start, CLKSRC_TIMEOUT)) { + ERROR("CLKSRC %x start failed @ 0x%x: 0x%x\n", + clksrc, address, mmio_read_32(address)); + return -ETIMEDOUT; +@@ -1183,14 +1614,14 @@ static int stm32mp1_set_clksrc(struct stm32mp1_clk_priv *priv, + + static int stm32mp1_set_clkdiv(unsigned int clkdiv, uint32_t address) + { +- unsigned long start; ++ uint64_t start; + + mmio_clrsetbits_32(address, RCC_DIVR_DIV_MASK, + clkdiv & RCC_DIVR_DIV_MASK); + +- start = get_timer(0); ++ start = timeout_start(); + while ((mmio_read_32(address) & RCC_DIVR_DIVRDY) == 0U) { +- if (get_timer(start) > CLKDIV_TIMEOUT) { ++ if (timeout_elapsed(start, CLKDIV_TIMEOUT)) { + ERROR("CLKDIV %x start failed @ 0x%x: 0x%x\n", + clkdiv, address, mmio_read_32(address)); + return -ETIMEDOUT; +@@ -1200,10 +1631,9 @@ static int stm32mp1_set_clkdiv(unsigned int clkdiv, uint32_t address) + return 0; + } + +-static void stm32mp1_mco_csg(struct stm32mp1_clk_priv *priv, +- uint32_t clksrc, uint32_t clkdiv) ++static void stm32mp1_mco_csg(uint32_t clksrc, uint32_t clkdiv) + { +- uint32_t address = priv->base + (clksrc >> 4); ++ uint32_t address = stm32mp_rcc_base() + (clksrc >> 4); + + /* + * Binding clksrc : +@@ -1224,10 +1654,9 @@ static void stm32mp1_mco_csg(struct stm32mp1_clk_priv *priv, + } + } + +-static void stm32mp1_set_rtcsrc(struct stm32mp1_clk_priv *priv, +- unsigned int clksrc, bool lse_css) ++static void stm32mp1_set_rtcsrc(unsigned int clksrc, bool lse_css) + { +- uint32_t address = priv->base + RCC_BDCR; ++ uint32_t address = stm32mp_rcc_base() + RCC_BDCR; + + if (((mmio_read_32(address) & RCC_BDCR_RTCCKEN) == 0U) || + (clksrc != (uint32_t)CLK_RTC_DISABLED)) { +@@ -1243,52 +1672,73 @@ static void stm32mp1_set_rtcsrc(struct stm32mp1_clk_priv *priv, + } + } + +-#define CNTCVL_OFF 0x008 +-#define CNTCVU_OFF 0x00C +- +-static void stm32mp1_stgen_config(struct stm32mp1_clk_priv *priv) ++static void stm32mp1_stgen_config(void) + { + uintptr_t stgen; +- int p; + uint32_t cntfid0; + unsigned long rate; ++ unsigned long long counter; + + stgen = fdt_get_stgen_base(); +- + cntfid0 = mmio_read_32(stgen + CNTFID_OFF); +- p = stm32mp1_clk_get_parent(priv, STGEN_K); +- rate = stm32mp1_clk_get(priv, p); ++ rate = get_clock_rate(stm32mp1_clk_get_parent(STGEN_K)); + +- if (cntfid0 != rate) { +- unsigned long long counter; ++ if (cntfid0 == rate) { ++ return; ++ } + +- mmio_clrbits_32(stgen + CNTCR_OFF, CNTCR_EN); +- counter = (unsigned long long) +- mmio_read_32(stgen + CNTCVL_OFF); +- counter |= ((unsigned long long) +- (mmio_read_32(stgen + CNTCVU_OFF))) << 32; +- counter = (counter * rate / cntfid0); +- mmio_write_32(stgen + CNTCVL_OFF, (uint32_t)counter); +- mmio_write_32(stgen + CNTCVU_OFF, (uint32_t)(counter >> 32)); +- mmio_write_32(stgen + CNTFID_OFF, rate); +- mmio_setbits_32(stgen + CNTCR_OFF, CNTCR_EN); ++ mmio_clrbits_32(stgen + CNTCR_OFF, CNTCR_EN); ++ counter = (unsigned long long)mmio_read_32(stgen + CNTCVL_OFF); ++ counter |= ((unsigned long long)mmio_read_32(stgen + CNTCVU_OFF)) << 32; ++ counter = (counter * rate / cntfid0); + +- write_cntfrq((u_register_t)rate); ++ mmio_write_32(stgen + CNTCVL_OFF, (uint32_t)counter); ++ mmio_write_32(stgen + CNTCVU_OFF, (uint32_t)(counter >> 32)); ++ mmio_write_32(stgen + CNTFID_OFF, rate); ++ mmio_setbits_32(stgen + CNTCR_OFF, CNTCR_EN); + +- /* Need to update timer with new frequency */ +- generic_delay_timer_init(); +- } ++ write_cntfrq((u_register_t)rate); ++ ++ /* Need to update timer with new frequency */ ++ generic_delay_timer_init(); + } + +-void stm32mp1_stgen_increment(unsigned long long offset_in_ms) ++unsigned long stm32mp_clk_timer_get_rate(unsigned long id) + { +- uintptr_t stgen; +- unsigned long long cnt; ++ unsigned long parent_rate; ++ uint32_t prescaler, timpre; ++ uintptr_t rcc_base = stm32mp_rcc_base(); + +- stgen = fdt_get_stgen_base(); +- +- cnt = ((unsigned long long)mmio_read_32(stgen + CNTCVU_OFF) << 32) | +- mmio_read_32(stgen + CNTCVL_OFF); ++ parent_rate = stm32mp_clk_get_rate(id); ++ ++ if (id < TIM1_K) { ++ prescaler = mmio_read_32(rcc_base + RCC_APB1DIVR) & ++ RCC_APBXDIV_MASK; ++ timpre = mmio_read_32(rcc_base + RCC_TIMG1PRER) & ++ RCC_TIMGXPRER_TIMGXPRE; ++ } else { ++ prescaler = mmio_read_32(rcc_base + RCC_APB2DIVR) & ++ RCC_APBXDIV_MASK; ++ timpre = mmio_read_32(rcc_base + RCC_TIMG2PRER) & ++ RCC_TIMGXPRER_TIMGXPRE; ++ } ++ ++ if (!prescaler) { ++ return parent_rate; ++ } ++ ++ return parent_rate * (timpre + 1) * 2; ++} ++ ++void stm32mp1_stgen_increment(unsigned long long offset_in_ms) ++{ ++ uintptr_t stgen; ++ unsigned long long cnt; ++ ++ stgen = fdt_get_stgen_base(); ++ ++ cnt = ((unsigned long long)mmio_read_32(stgen + CNTCVU_OFF) << 32) | ++ mmio_read_32(stgen + CNTCVL_OFF); + + cnt += (offset_in_ms * mmio_read_32(stgen + CNTFID_OFF)) / 1000U; + +@@ -1298,9 +1748,46 @@ void stm32mp1_stgen_increment(unsigned long long offset_in_ms) + mmio_setbits_32(stgen + CNTCR_OFF, CNTCR_EN); + } + +-static void stm32mp1_pkcs_config(struct stm32mp1_clk_priv *priv, uint32_t pkcs) ++/******************************************************************************* ++ * This function determines the number of needed RTC calendar read operations ++ * to get consistent values (1 or 2 depending on clock frequencies). ++ * If APB1 frequency is lower than 7 times the RTC one, the software has to ++ * read the calendar time and date registers twice. ++ * Returns true if read twice is needed, false else. ++ ******************************************************************************/ ++bool stm32mp1_rtc_get_read_twice(void) + { +- uint32_t address = priv->base + ((pkcs >> 4) & 0xFFFU); ++ unsigned long apb1_freq; ++ uint32_t rtc_freq; ++ uint32_t apb1_div; ++ uintptr_t rcc_base = stm32mp_rcc_base(); ++ ++ switch ((mmio_read_32(rcc_base + RCC_BDCR) & ++ RCC_BDCR_RTCSRC_MASK) >> RCC_BDCR_RTCSRC_SHIFT) { ++ case 1: ++ rtc_freq = stm32mp_clk_get_rate(CK_LSE); ++ break; ++ case 2: ++ rtc_freq = stm32mp_clk_get_rate(CK_LSI); ++ break; ++ case 3: ++ rtc_freq = stm32mp_clk_get_rate(CK_HSE); ++ rtc_freq /= (mmio_read_32(rcc_base + RCC_RTCDIVR) & ++ RCC_DIVR_DIV_MASK) + 1U; ++ break; ++ default: ++ panic(); ++ } ++ ++ apb1_div = mmio_read_32(rcc_base + RCC_APB1DIVR) & RCC_APBXDIV_MASK; ++ apb1_freq = stm32mp_clk_get_rate(CK_MCU) >> apb1_div; ++ ++ return apb1_freq < (rtc_freq * 7U); ++} ++ ++static void stm32mp1_pkcs_config(uint32_t pkcs) ++{ ++ uint32_t address = stm32mp_rcc_base() + ((pkcs >> 4) & 0xFFFU); + uint32_t value = pkcs & 0xFU; + uint32_t mask = 0xFU; + +@@ -1314,8 +1801,7 @@ static void stm32mp1_pkcs_config(struct stm32mp1_clk_priv *priv, uint32_t pkcs) + + int stm32mp1_clk_init(void) + { +- struct stm32mp1_clk_priv *priv = &stm32mp1_clk_priv_data; +- uint32_t rcc = priv->base; ++ uint32_t rcc_base = stm32mp_rcc_base(); + unsigned int clksrc[CLKSRC_NB]; + unsigned int clkdiv[CLKDIV_NB]; + unsigned int pllcfg[_PLL_NB][PLLCFG_NB]; +@@ -1323,11 +1809,16 @@ int stm32mp1_clk_init(void) + int ret, len; + enum stm32mp1_pll_id i; + bool lse_css = false; +- const uint32_t *pkcs_cell; ++ bool pll3_preserve = false; ++ bool pll4_preserve = false; ++ bool pll4_bootrom = false; ++ const fdt32_t *pkcs_cell; ++ int stgen_p = stm32mp1_clk_get_parent((int)STGEN_K); ++ int usbphy_p = stm32mp1_clk_get_parent((int)USBPHY_K); + + /* Check status field to disable security */ + if (!fdt_get_rcc_secure_status()) { +- mmio_write_32(rcc + RCC_TZCR, 0); ++ mmio_write_32(rcc_base + RCC_TZCR, 0); + } + + ret = fdt_rcc_read_uint32_array("st,clksrc", clksrc, +@@ -1359,113 +1850,149 @@ int stm32mp1_clk_init(void) + } + } + +- stm32mp1_mco_csg(priv, clksrc[CLKSRC_MCO1], clkdiv[CLKDIV_MCO1]); +- stm32mp1_mco_csg(priv, clksrc[CLKSRC_MCO2], clkdiv[CLKDIV_MCO2]); ++ stm32mp1_mco_csg(clksrc[CLKSRC_MCO1], clkdiv[CLKDIV_MCO1]); ++ stm32mp1_mco_csg(clksrc[CLKSRC_MCO2], clkdiv[CLKDIV_MCO2]); + + /* + * Switch ON oscillator found in device-tree. + * Note: HSI already ON after BootROM stage. + */ +- if (priv->osc[_LSI] != 0U) { +- stm32mp1_lsi_set(rcc, 1); ++ if (stm32mp1_osc[_LSI] != 0U) { ++ stm32mp1_lsi_set(true); + } +- if (priv->osc[_LSE] != 0U) { +- bool bypass; ++ if (stm32mp1_osc[_LSE] != 0U) { ++ bool bypass, digbyp; + uint32_t lsedrv; + + bypass = fdt_osc_read_bool(_LSE, "st,bypass"); ++ digbyp = fdt_osc_read_bool(_LSE, "st,digbypass"); + lse_css = fdt_osc_read_bool(_LSE, "st,css"); + lsedrv = fdt_osc_read_uint32_default(_LSE, "st,drive", + LSEDRV_MEDIUM_HIGH); +- stm32mp1_lse_enable(rcc, bypass, lsedrv); ++ stm32mp1_lse_enable(bypass, digbyp, lsedrv); + } +- if (priv->osc[_HSE] != 0U) { +- bool bypass, css; ++ if (stm32mp1_osc[_HSE] != 0U) { ++ bool bypass, digbyp, css; + +- bypass = fdt_osc_read_bool(_LSE, "st,bypass"); +- css = fdt_osc_read_bool(_LSE, "st,css"); +- stm32mp1_hse_enable(rcc, bypass, css); ++ bypass = fdt_osc_read_bool(_HSE, "st,bypass"); ++ digbyp = fdt_osc_read_bool(_HSE, "st,digbypass"); ++ css = fdt_osc_read_bool(_HSE, "st,css"); ++ stm32mp1_hse_enable(bypass, digbyp, css); + } + /* + * CSI is mandatory for automatic I/O compensation (SYSCFG_CMPCR) + * => switch on CSI even if node is not present in device tree + */ +- stm32mp1_csi_set(rcc, 1); ++ stm32mp1_csi_set(true); + + /* Come back to HSI */ +- ret = stm32mp1_set_clksrc(priv, CLK_MPU_HSI); ++ ret = stm32mp1_set_clksrc(CLK_MPU_HSI); ++ if (ret != 0) { ++ return ret; ++ } ++ ret = stm32mp1_set_clksrc(CLK_AXI_HSI); + if (ret != 0) { + return ret; + } +- ret = stm32mp1_set_clksrc(priv, CLK_AXI_HSI); ++ ret = stm32mp1_set_clksrc(CLK_MCU_HSI); + if (ret != 0) { + return ret; + } + ++ if ((mmio_read_32(rcc_base + RCC_MP_RSTSCLRR) & ++ RCC_MP_RSTSCLRR_MPUP0RSTF) != 0) { ++ pll3_preserve = stm32mp1_check_pll_conf(_PLL3, ++ clksrc[CLKSRC_PLL3], ++ pllcfg[_PLL3], ++ plloff[_PLL3]); ++ pll4_preserve = stm32mp1_check_pll_conf(_PLL4, ++ clksrc[CLKSRC_PLL4], ++ pllcfg[_PLL4], ++ plloff[_PLL4]); ++ } ++ /* Don't initialize PLL4, when used by BOOTROM */ ++ if ((get_boot_device() == BOOT_DEVICE_USB) && ++ ((stgen_p == (int)_PLL4_R) || (usbphy_p == (int)_PLL4_R))) { ++ pll4_bootrom = true; ++ pll4_preserve = true; ++ } ++ + for (i = (enum stm32mp1_pll_id)0; i < _PLL_NB; i++) { +- if (i == _PLL4) ++ if (((i == _PLL3) && pll3_preserve) || ++ ((i == _PLL4) && pll4_preserve)) { + continue; +- ret = stm32mp1_pll_stop(priv, i); ++ } ++ ++ ret = stm32mp1_pll_stop(i); + if (ret != 0) { + return ret; + } + } + + /* Configure HSIDIV */ +- if (priv->osc[_HSI] != 0U) { +- ret = stm32mp1_hsidiv(rcc, priv->osc[_HSI]); ++ if (stm32mp1_osc[_HSI] != 0U) { ++ ret = stm32mp1_hsidiv(stm32mp1_osc[_HSI]); + if (ret != 0) { + return ret; + } +- stm32mp1_stgen_config(priv); ++ stm32mp1_stgen_config(); + } + + /* Select DIV */ + /* No ready bit when MPUSRC != CLK_MPU_PLL1P_DIV, MPUDIV is disabled */ +- mmio_write_32(rcc + RCC_MPCKDIVR, ++ mmio_write_32(rcc_base + RCC_MPCKDIVR, + clkdiv[CLKDIV_MPU] & RCC_DIVR_DIV_MASK); +- ret = stm32mp1_set_clkdiv(clkdiv[CLKDIV_AXI], rcc + RCC_AXIDIVR); ++ ret = stm32mp1_set_clkdiv(clkdiv[CLKDIV_AXI], rcc_base + RCC_AXIDIVR); ++ if (ret != 0) { ++ return ret; ++ } ++ ret = stm32mp1_set_clkdiv(clkdiv[CLKDIV_APB4], rcc_base + RCC_APB4DIVR); + if (ret != 0) { + return ret; + } +- ret = stm32mp1_set_clkdiv(clkdiv[CLKDIV_APB4], rcc + RCC_APB4DIVR); ++ ret = stm32mp1_set_clkdiv(clkdiv[CLKDIV_APB5], rcc_base + RCC_APB5DIVR); + if (ret != 0) { + return ret; + } +- ret = stm32mp1_set_clkdiv(clkdiv[CLKDIV_APB5], rcc + RCC_APB5DIVR); ++ ret = stm32mp1_set_clkdiv(clkdiv[CLKDIV_MCU], rcc_base + RCC_MCUDIVR); + if (ret != 0) { + return ret; + } +- ret = stm32mp1_set_clkdiv(clkdiv[CLKDIV_APB1], rcc + RCC_APB1DIVR); ++ ret = stm32mp1_set_clkdiv(clkdiv[CLKDIV_APB1], rcc_base + RCC_APB1DIVR); + if (ret != 0) { + return ret; + } +- ret = stm32mp1_set_clkdiv(clkdiv[CLKDIV_APB2], rcc + RCC_APB2DIVR); ++ ret = stm32mp1_set_clkdiv(clkdiv[CLKDIV_APB2], rcc_base + RCC_APB2DIVR); + if (ret != 0) { + return ret; + } +- ret = stm32mp1_set_clkdiv(clkdiv[CLKDIV_APB3], rcc + RCC_APB3DIVR); ++ ret = stm32mp1_set_clkdiv(clkdiv[CLKDIV_APB3], rcc_base + RCC_APB3DIVR); + if (ret != 0) { + return ret; + } + + /* No ready bit for RTC */ +- mmio_write_32(rcc + RCC_RTCDIVR, ++ mmio_write_32(rcc_base + RCC_RTCDIVR, + clkdiv[CLKDIV_RTC] & RCC_DIVR_DIV_MASK); + + /* Configure PLLs source */ +- ret = stm32mp1_set_clksrc(priv, clksrc[CLKSRC_PLL12]); ++ ret = stm32mp1_set_clksrc(clksrc[CLKSRC_PLL12]); + if (ret != 0) { + return ret; + } +- ret = stm32mp1_set_clksrc(priv, clksrc[CLKSRC_PLL3]); +- if (ret != 0) { +- return ret; ++ ++ if (!pll3_preserve) { ++ ret = stm32mp1_set_clksrc(clksrc[CLKSRC_PLL3]); ++ if (ret != 0) { ++ return ret; ++ } + } + +- ret = stm32mp1_set_clksrc(priv, clksrc[CLKSRC_PLL4]); +- if (ret != 0) { +- return ret; ++ if (!pll4_preserve) { ++ ret = stm32mp1_set_clksrc(clksrc[CLKSRC_PLL4]); ++ if (ret != 0) { ++ return ret; ++ } + } + + /* Configure and start PLLs */ +@@ -1473,25 +2000,36 @@ int stm32mp1_clk_init(void) + uint32_t fracv; + uint32_t csg[PLLCSG_NB]; + ++ if (((i == _PLL3) && pll3_preserve) || ++ ((i == _PLL4) && pll4_preserve && !pll4_bootrom)) { ++ continue; ++ } ++ + if (!fdt_check_node(plloff[i])) { + continue; + } + ++ if ((i == _PLL4) && pll4_bootrom) { ++ /* Set output divider if not done by the Bootrom */ ++ stm32mp1_pll_config_output(i, pllcfg[i]); ++ continue; ++ } ++ + fracv = fdt_read_uint32_default(plloff[i], "frac", 0); + +- ret = stm32mp1_pll_config(priv, i, pllcfg[i], fracv); ++ ret = stm32mp1_pll_config(i, pllcfg[i], fracv); + if (ret != 0) { + return ret; + } + ret = fdt_read_uint32_array(plloff[i], "csg", csg, + (uint32_t)PLLCSG_NB); + if (ret == 0) { +- stm32mp1_pll_csg(priv, i, csg); ++ stm32mp1_pll_csg(i, csg); + } else if (ret != -FDT_ERR_NOTFOUND) { + return ret; + } + +- stm32mp1_pll_start(priv, i); ++ stm32mp1_pll_start(i); + } + /* Wait and start PLLs ouptut when ready */ + for (i = (enum stm32mp1_pll_id)0; i < _PLL_NB; i++) { +@@ -1499,43 +2037,50 @@ int stm32mp1_clk_init(void) + continue; + } + +- ret = stm32mp1_pll_output(priv, i, pllcfg[i][PLLCFG_O]); ++ ret = stm32mp1_pll_output(i, pllcfg[i][PLLCFG_O]); + if (ret != 0) { + return ret; + } + } + /* Wait LSE ready before to use it */ +- if (priv->osc[_LSE] != 0U) { +- stm32mp1_lse_wait(rcc); ++ if (stm32mp1_osc[_LSE] != 0U) { ++ stm32mp1_lse_wait(); + } + + /* Configure with expected clock source */ +- ret = stm32mp1_set_clksrc(priv, clksrc[CLKSRC_MPU]); ++ ret = stm32mp1_set_clksrc(clksrc[CLKSRC_MPU]); + if (ret != 0) { + return ret; + } +- ret = stm32mp1_set_clksrc(priv, clksrc[CLKSRC_AXI]); ++ ret = stm32mp1_set_clksrc(clksrc[CLKSRC_AXI]); + if (ret != 0) { + return ret; + } +- stm32mp1_set_rtcsrc(priv, clksrc[CLKSRC_RTC], lse_css); ++ ret = stm32mp1_set_clksrc(clksrc[CLKSRC_MCU]); ++ if (ret != 0) { ++ return ret; ++ } ++ stm32mp1_set_rtcsrc(clksrc[CLKSRC_RTC], lse_css); + + /* Configure PKCK */ + pkcs_cell = fdt_rcc_read_prop("st,pkcs", &len); + if (pkcs_cell != NULL) { + bool ckper_disabled = false; + uint32_t j; ++ uint32_t usbreg_bootrom = 0U; + +- priv->pkcs_usb_value = 0; ++ if (pll4_bootrom) { ++ usbreg_bootrom = mmio_read_32(rcc_base + RCC_USBCKSELR); ++ } + + for (j = 0; j < ((uint32_t)len / sizeof(uint32_t)); j++) { +- uint32_t pkcs = (uint32_t)fdt32_to_cpu(pkcs_cell[j]); ++ uint32_t pkcs = fdt32_to_cpu(pkcs_cell[j]); + + if (pkcs == (uint32_t)CLK_CKPER_DISABLED) { + ckper_disabled = true; + continue; + } +- stm32mp1_pkcs_config(priv, pkcs); ++ stm32mp1_pkcs_config(pkcs); + } + + /* +@@ -1545,18 +2090,37 @@ int stm32mp1_clk_init(void) + * => deactivated CKPER only after switching clock + */ + if (ckper_disabled) { +- stm32mp1_pkcs_config(priv, CLK_CKPER_DISABLED); ++ stm32mp1_pkcs_config(CLK_CKPER_DISABLED); ++ } ++ ++ if (pll4_bootrom) { ++ uint32_t usbreg_value, usbreg_mask; ++ const struct stm32mp1_clk_sel *sel; ++ ++ sel = clk_sel_ref(_USBPHY_SEL); ++ usbreg_mask = (uint32_t)sel->msk << sel->src; ++ sel = clk_sel_ref(_USBO_SEL); ++ usbreg_mask |= (uint32_t)sel->msk << sel->src; ++ ++ usbreg_value = mmio_read_32(rcc_base + RCC_USBCKSELR) & ++ usbreg_mask; ++ usbreg_bootrom &= usbreg_mask; ++ if (usbreg_bootrom != usbreg_value) { ++ VERBOSE("forbidden new USB clk path\n"); ++ VERBOSE("vs bootrom on USB boot\n"); ++ return -FDT_ERR_BADVALUE; ++ } + } + } + + /* Switch OFF HSI if not found in device-tree */ +- if (priv->osc[_HSI] == 0U) { +- stm32mp1_hsi_set(rcc, 0); ++ if (stm32mp1_osc[_HSI] == 0U) { ++ stm32mp1_hsi_set(false); + } +- stm32mp1_stgen_config(priv); ++ stm32mp1_stgen_config(); + + /* Software Self-Refresh mode (SSR) during DDR initilialization */ +- mmio_clrsetbits_32(priv->base + RCC_DDRITFCR, ++ mmio_clrsetbits_32(rcc_base + RCC_DDRITFCR, + RCC_DDRITFCR_DDRCKMOD_MASK, + RCC_DDRITFCR_DDRCKMOD_SSR << + RCC_DDRITFCR_DDRCKMOD_SHIFT); +@@ -1565,48 +2129,711 @@ int stm32mp1_clk_init(void) + } + + static void stm32mp1_osc_clk_init(const char *name, +- struct stm32mp1_clk_priv *priv, + enum stm32mp_osc_id index) + { + uint32_t frequency; + +- priv->osc[index] = 0; ++ if (fdt_osc_read_freq(name, &frequency) == 0) { ++ stm32mp1_osc[index] = frequency; ++ } ++} ++ ++#if defined(IMAGE_BL32) ++/* ++ * HSI Calibration part ++ */ ++static void hsi_set_trim(unsigned int cal) ++{ ++ int clk_trim = (int)cal - (int)stm32mp1_clk_cal_hsi.cal_ref; ++ uint32_t trim = ((uint32_t)clk_trim << RCC_HSICFGR_HSITRIM_SHIFT) & ++ RCC_HSICFGR_HSITRIM_MASK; ++ ++ mmio_clrsetbits_32(stm32mp_rcc_base() + RCC_HSICFGR, ++ RCC_HSICFGR_HSITRIM_MASK, trim); ++} ++ ++static unsigned int hsi_get_trimed_cal(void) ++{ ++ uint32_t utrim = (mmio_read_32(stm32mp_rcc_base() + RCC_HSICFGR) & ++ RCC_HSICFGR_HSITRIM_MASK) >> ++ RCC_HSICFGR_HSITRIM_SHIFT; ++ int trim = (int)utrim - stm32mp1_clk_cal_hsi.trim_max; ++ ++ if (trim + (int)stm32mp1_clk_cal_hsi.cal_ref < 0) { ++ return 0; ++ } ++ ++ return stm32mp1_clk_cal_hsi.cal_ref + trim; ++} ++ ++static void csi_set_trim(unsigned int cal) ++{ ++ int clk_trim = (int)cal - (int)stm32mp1_clk_cal_csi.cal_ref + ++ stm32mp1_clk_cal_csi.trim_max + 1; ++ uint32_t trim = ((uint32_t)clk_trim << RCC_CSICFGR_CSITRIM_SHIFT) & ++ RCC_CSICFGR_CSITRIM_MASK; + +- if (fdt_osc_read_freq(name, &frequency) != 0) { +- ERROR("%s frequency request failed\n", name); ++ mmio_clrsetbits_32(stm32mp_rcc_base() + RCC_CSICFGR, ++ RCC_CSICFGR_CSITRIM_MASK, trim); ++} ++ ++static unsigned int csi_get_trimed_cal(void) ++{ ++ uint32_t trim = (mmio_read_32(stm32mp_rcc_base() + RCC_CSICFGR) & ++ RCC_CSICFGR_CSITRIM_MASK) >> ++ RCC_CSICFGR_CSITRIM_SHIFT; ++ ++ return (int)trim - stm32mp1_clk_cal_csi.trim_max + ++ (int)stm32mp1_clk_cal_csi.cal_ref - 1; ++} ++ ++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 stm32mp1_rcc_calibration(struct stm32mp1_clk_cal *clk_cal) ++{ ++ unsigned long freq = clk_cal->get_freq(); ++ unsigned long min = clk_cal->ref_freq - ++ ((clk_cal->ref_freq * clk_cal->freq_margin) / 100); ++ unsigned long max = clk_cal->ref_freq + ++ ((clk_cal->ref_freq * clk_cal->freq_margin) / 100); ++ unsigned int nb_retries = CAL_MAX_RETRY; ++ int cal = clk_cal->get_trim(); ++ ++ VERBOSE("Freq is %lu min %lu max %lu\n", freq, min, max); ++ ++ while (((freq < min) || (freq > max)) && (nb_retries != 0U)) { ++ ++ 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(); ++ ++ nb_retries--; ++ } ++ ++ if (nb_retries == 0U) { ++ ERROR("Calibration Failed\n"); + panic(); +- } else { +- priv->osc[index] = frequency; + } + } + ++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; ++} ++ ++bool stm32mp1_rcc_get_wakeup(void) ++{ ++ return rcc_wakeup; ++} ++ ++void stm32mp1_rcc_set_wakeup(bool state) ++{ ++ rcc_wakeup = state; ++} ++ ++void stm32mp1_rcc_it_handler(uint32_t id) ++{ ++ uintptr_t rcc_base = stm32mp_rcc_base(); ++ ++ switch (id) { ++ case STM32MP1_IRQ_RCC_WAKEUP: ++ plat_ic_set_priority_mask(GIC_HIGHEST_NS_PRIORITY); ++ mmio_setbits_32(rcc_base + RCC_MP_CIFR, RCC_MP_CIFR_WKUPF); ++ stm32mp1_rcc_set_wakeup(true); ++ return; ++ ++ case STM32MP1_IRQ_MCU_SEV: ++ stm32mp1_rcc_set_wakeup(false); ++ if ((mmio_read_32(EXTI_BASE + EXTI_RPR3) & ++ EXTI_RPR3_RPIF65) != 0U) { ++ mmio_setbits_32(EXTI_BASE + EXTI_RPR3, ++ EXTI_RPR3_RPIF65); ++ } ++ ++ if ((mmio_read_32(EXTI_BASE + EXTI_FPR3) & ++ EXTI_FPR3_FPIF65) != 0U) { ++ mmio_setbits_32(EXTI_BASE + EXTI_FPR3, ++ EXTI_FPR3_FPIF65); ++ } ++ ++ break; ++ ++ case ARM_IRQ_SEC_PHY_TIMER: ++ default: ++ break; ++ } ++ ++ if (stm32mp1_clk_cal_hsi.ref_freq != 0U) { ++ stm32mp1_rcc_calibration(&stm32mp1_clk_cal_hsi); ++ } ++ ++ if (stm32mp1_clk_cal_csi.ref_freq != 0U) { ++ stm32mp1_rcc_calibration(&stm32mp1_clk_cal_csi); ++ } ++ ++ if (timer_val != 0U) { ++ write_cntptval(timer_val); ++ } ++} ++ ++int stm32mp1_rcc_start_hsi_cal(void) ++{ ++ if (stm32mp1_clk_cal_hsi.ref_freq == 0U) { ++ return -ENOENT; ++ } ++ ++ stm32mp1_rcc_calibration(&stm32mp1_clk_cal_hsi); ++ return 0; ++} ++ ++int stm32mp1_rcc_start_csi_cal(void) ++{ ++ if (stm32mp1_clk_cal_csi.ref_freq == 0U) { ++ return -ENOENT; ++ } ++ ++ stm32mp1_rcc_calibration(&stm32mp1_clk_cal_csi); ++ return 0; ++} ++ ++static void init_hsi_cal(void) ++{ ++ int len; ++ ++ if (fdt_rcc_read_prop("st,hsi-cal", &len) == NULL) { ++ return; ++ } ++ ++ stm32_timer_freq_func(&stm32mp1_clk_cal_hsi.get_freq, HSI_CAL); ++ assert(stm32mp1_clk_cal_hsi.get_freq); ++ ++ stm32mp1_clk_cal_hsi.ref_freq = stm32mp_clk_get_rate(CK_HSI); ++ ++ /* Read initial value */ ++ stm32mp1_clk_cal_hsi.cal_ref = ++ ((mmio_read_32(stm32mp_rcc_base() + RCC_HSICFGR) ++ & RCC_HSICFGR_HSICAL_MASK) >> RCC_HSICFGR_HSICAL_SHIFT); ++ ++ trim_table_init(&stm32mp1_clk_cal_hsi); ++ ++ stm32mp1_clk_cal_hsi.set_trim(stm32mp1_clk_cal_hsi.cal_ref); ++ ++ stm32mp1_rcc_calibration(&stm32mp1_clk_cal_hsi); ++} ++ ++static void init_csi_cal(void) ++{ ++ int len; ++ ++ if (fdt_rcc_read_prop("st,csi-cal", &len) == NULL) { ++ return; ++ } ++ ++ stm32_timer_freq_func(&stm32mp1_clk_cal_csi.get_freq, CSI_CAL); ++ assert(stm32mp1_clk_cal_csi.get_freq); ++ ++ stm32mp1_clk_cal_csi.ref_freq = stm32mp_clk_get_rate(CK_CSI); ++ ++ /* Read initial value */ ++ stm32mp1_clk_cal_csi.cal_ref = ++ ((mmio_read_32(stm32mp_rcc_base() + RCC_CSICFGR) & ++ RCC_CSICFGR_CSICAL_MASK) >> RCC_CSICFGR_CSICAL_SHIFT); ++ ++ trim_table_init(&stm32mp1_clk_cal_csi); ++ ++ stm32mp1_clk_cal_csi.set_trim(stm32mp1_clk_cal_csi.cal_ref); ++ ++ stm32mp1_rcc_calibration(&stm32mp1_clk_cal_csi); ++} ++ ++void stm32mp1_cal_init(void) ++{ ++ init_hsi_cal(); ++ init_csi_cal(); ++ ++ timer_val = fdt_rcc_read_uint32_default("st,cal-sec", 0) * ++ plat_get_syscnt_freq2(); ++ ++ if (timer_val != 0U) { ++ /* Load & enable timer */ ++ write_cntptval(timer_val); ++ write_cntpctl(BIT(0)); ++ }; ++ ++ if (fdt_rcc_enable_it("mcu_sev") < 0) { ++ VERBOSE("No MCU calibration\n"); ++ } ++} ++#endif ++ + static void stm32mp1_osc_init(void) + { +- struct stm32mp1_clk_priv *priv = &stm32mp1_clk_priv_data; + enum stm32mp_osc_id i; + + for (i = (enum stm32mp_osc_id)0 ; i < NB_OSC; i++) { +- stm32mp1_osc_clk_init(stm32mp_osc_node_label[i], priv, i); ++ stm32mp1_osc_clk_init(stm32mp_osc_node_label[i], i); + } + } + +-int stm32mp1_clk_probe(void) ++/* ++ * 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(unsigned int offset, unsigned int bit) + { +- struct stm32mp1_clk_priv *priv = &stm32mp1_clk_priv_data; ++ return get_id_from_rcc_bit(offset, bit); ++} + +- priv->base = fdt_rcc_read_addr(); +- if (priv->base == 0U) { +- return -EINVAL; ++/* ++ * 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; + } + +- priv->data = &stm32mp1_data; ++ if (s != _UNKNOWN_SEL) { ++ const struct stm32mp1_clk_sel *sel = clk_sel_ref(s); ++ uintptr_t rcc_base = stm32mp_rcc_base(); + +- if ((priv->data->gate == NULL) || (priv->data->sel == NULL) || +- (priv->data->pll == NULL)) { +- return -EINVAL; ++ 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); ++ uintptr_t rcc_base = stm32mp_rcc_base(); ++ ++ p_sel = mmio_read_32(rcc_base + pll->rckxselr) & ++ RCC_SELR_REFCLK_SRC_MASK; ++ ++ if (pll->refclk[p_sel] != _UNKNOWN_OSC_ID) { ++ return (int)pll->refclk[p_sel]; ++ } + } + ++#if LOG_LEVEL >= LOG_LEVEL_VERBOSE ++ VERBOSE("No parent selected for %s", ++ stm32mp1_clk_parent_name[parent_id]); ++#endif ++ ++ 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: ++ stm32mp1_register_secure_periph(STM32MP1_SHRES_PLL1_P); ++ break; ++ case _PLL1_Q: ++ stm32mp1_register_secure_periph(STM32MP1_SHRES_PLL1_Q); ++ break; ++ case _PLL1_R: ++ stm32mp1_register_secure_periph(STM32MP1_SHRES_PLL1_R); ++ break; ++ ++ case _PLL2_P: ++ stm32mp1_register_secure_periph(STM32MP1_SHRES_PLL2_P); ++ break; ++ case _PLL2_Q: ++ stm32mp1_register_secure_periph(STM32MP1_SHRES_PLL2_Q); ++ break; ++ case _PLL2_R: ++ stm32mp1_register_secure_periph(STM32MP1_SHRES_PLL2_R); ++ break; ++ ++ case _PLL3_P: ++ stm32mp1_register_secure_periph(STM32MP1_SHRES_PLL3_P); ++ break; ++ case _PLL3_Q: ++ stm32mp1_register_secure_periph(STM32MP1_SHRES_PLL3_Q); ++ break; ++ case _PLL3_R: ++ stm32mp1_register_secure_periph(STM32MP1_SHRES_PLL3_R); ++ break; ++ ++ /* Source clocks */ ++ case _HSI: ++ case _HSI_KER: ++ stm32mp1_register_secure_periph(STM32MP1_SHRES_HSI); ++ break; ++ case _LSI: ++ stm32mp1_register_secure_periph(STM32MP1_SHRES_LSI); ++ break; ++ case _CSI: ++ case _CSI_KER: ++ stm32mp1_register_secure_periph(STM32MP1_SHRES_CSI); ++ break; ++ case _HSE: ++ case _HSE_KER: ++ case _HSE_KER_DIV2: ++ stm32mp1_register_secure_periph(STM32MP1_SHRES_HSE); ++ break; ++ case _LSE: ++ stm32mp1_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 stm32mp1_register_clock_parents_secure(unsigned long clock_id) ++{ ++ int parent_id; ++ ++ if (!stm32mp1_rcc_is_secure()) { ++ return; ++ } ++ ++ 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: ++ ERROR("PLL4 cannot be secured\n"); ++ panic(); ++ break; ++ default: ++ /* Others are expected gateable clock */ ++ parent_id = stm32mp1_clk_get_parent(clock_id); ++ break; ++ } ++ ++ if (parent_id < 0) { ++ ERROR("No parent for clock %lu", clock_id); ++ panic(); ++ } ++ ++ secure_parent_clocks(parent_id); ++} ++ ++/* Sync secure clock refcount after all drivers probe/inits, */ ++void stm32mp1_update_earlyboot_clocks_state(void) ++{ ++ unsigned int idx; ++ ++ for (idx = 0U; idx < NB_GATES; idx++) { ++ const struct stm32mp1_clk_gate *gate = gate_ref(idx); ++ unsigned long clock_id = gate_ref(idx)->index; ++ ++ /* Drop non secure refcnt on non shared shareable clocks */ ++ if (__clk_is_enabled(gate) && ++ stm32mp1_clock_is_shareable(clock_id) && ++ !stm32mp1_clock_is_shared(clock_id)) { ++ stm32mp1_clk_disable_non_secure(clock_id); ++ } ++ } ++ ++#if LOG_LEVEL >= LOG_LEVEL_VERBOSE ++ /* Dump clocks state */ ++ for (idx = 0U; idx < NB_GATES; idx++) { ++ const struct stm32mp1_clk_gate *gate = gate_ref(idx); ++ unsigned long __unused clock_id = gate->index; ++ unsigned int __unused refcnt = gate_refcounts[idx]; ++ int __unused p = stm32mp1_clk_get_parent(clock_id); ++ ++ VERBOSE("stm32mp1 clk %lu %sabled (refcnt %d) (parent %d %s)\n", ++ clock_id, __clk_is_enabled(gate) ? "en" : "dis", ++ refcnt, p, ++ p < 0 ? "n.a" : stm32mp1_clk_parent_sel_name[p]); ++ } ++#endif ++} ++ ++static void sync_earlyboot_clocks_state(void) ++{ ++ unsigned int idx; ++ int res; ++ ++ for (idx = 0U; idx < NB_GATES; idx++) { ++ assert(gate_refcounts[idx] == 0); ++ } ++ ++ /* Set a non secure refcnt for shareable clocks enabled from boot */ ++ for (idx = 0U; idx < NB_GATES; idx++) { ++ struct stm32mp1_clk_gate const *gate = gate_ref(idx); ++ ++ if (__clk_is_enabled(gate) && ++ stm32mp1_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 ++ */ ++ stm32mp1_register_clock_parents_secure(DDRC1); ++ stm32mp1_clk_enable_secure(DDRC1); ++ stm32mp1_register_clock_parents_secure(DDRC1LP); ++ stm32mp1_clk_enable_secure(DDRC1LP); ++ stm32mp1_register_clock_parents_secure(DDRC2); ++ stm32mp1_clk_enable_secure(DDRC2); ++ stm32mp1_register_clock_parents_secure(DDRC2LP); ++ stm32mp1_clk_enable_secure(DDRC2LP); ++ stm32mp1_register_clock_parents_secure(DDRPHYC); ++ stm32mp1_clk_enable_secure(DDRPHYC); ++ stm32mp1_register_clock_parents_secure(DDRPHYCLP); ++ stm32mp1_clk_enable_secure(DDRPHYCLP); ++ stm32mp1_register_clock_parents_secure(DDRCAPB); ++ stm32mp1_clk_enable_secure(DDRCAPB); ++ stm32mp1_register_clock_parents_secure(AXIDCG); ++ stm32mp1_clk_enable_secure(AXIDCG); ++ stm32mp1_register_clock_parents_secure(DDRPHYCAPB); ++ stm32mp1_clk_enable_secure(DDRPHYCAPB); ++ stm32mp1_register_clock_parents_secure(DDRPHYCAPBLP); ++ stm32mp1_clk_enable_secure(DDRPHYCAPBLP); ++ ++ stm32mp1_register_clock_parents_secure(TZPC); ++ stm32mp1_clk_enable_secure(TZPC); ++ stm32mp1_register_clock_parents_secure(TZC1); ++ stm32mp1_clk_enable_secure(TZC1); ++ stm32mp1_register_clock_parents_secure(TZC2); ++ stm32mp1_clk_enable_secure(TZC2); ++ stm32mp1_register_clock_parents_secure(STGEN_K); ++ stm32mp1_clk_enable_secure(STGEN_K); ++ ++ stm32mp1_register_clock_parents_secure(BSEC); ++ stm32mp1_register_clock_parents_secure(BKPSRAM); ++ ++ stm32mp1_register_clock_parents_secure(RTCAPB); ++ ++ res = stm32mp_is_single_core(); ++ if (res < 0) { ++ panic(); ++ } ++ ++ if (res == 0) { ++ stm32mp1_clk_enable_secure(RTCAPB); ++ } ++} ++ ++void stm32mp1_rcc_init_late(void) ++{ ++#if defined(IMAGE_BL32) ++ int irq_num; ++ ++ if (!stm32mp1_rcc_is_secure()) { ++ return; ++ } ++ ++ irq_num = fdt_rcc_enable_it("wakeup"); ++ if (irq_num < 0) { ++ panic(); ++ } ++ ++ plat_ic_set_interrupt_priority(irq_num, STM32MP1_IRQ_RCC_SEC_PRIO); ++#endif ++} ++ ++int stm32mp1_clk_probe(void) ++{ + stm32mp1_osc_init(); + ++ sync_earlyboot_clocks_state(); ++ + return 0; + } +diff --git a/drivers/st/clk/stm32mp1_clkfunc.c b/drivers/st/clk/stm32mp1_clkfunc.c +index d4c69cb..99a7360 100644 +--- a/drivers/st/clk/stm32mp1_clkfunc.c ++++ b/drivers/st/clk/stm32mp1_clkfunc.c +@@ -7,16 +7,13 @@ + #include + #include + #include ++#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" +-#define DT_USART_COMPAT "st,stm32h7-usart" + + const char *stm32mp_osc_node_label[NB_OSC] = { + [_LSI] = "clk-lsi", +@@ -24,15 +21,14 @@ const char *stm32mp_osc_node_label[NB_OSC] = { + [_HSI] = "clk-hsi", + [_HSE] = "clk-hse", + [_CSI] = "clk-csi", +- [_I2S_CKIN] = "i2s_ckin", +- [_USB_PHY_48] = "ck_usbo_48m" ++ [_I2S_CKIN] = "i2s_ckin" + }; + + /******************************************************************************* + * This function reads the frequency of an oscillator from its name. + * It reads the value indicated inside the device tree. +- * Returns 0 if success, and a negative value else. +- * If success, value is stored in the second parameter. ++ * 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(const char *name, uint32_t *freq) + { +@@ -124,7 +120,7 @@ bool fdt_osc_read_bool(enum stm32mp_osc_id osc_id, const char *prop_name) + + /******************************************************************************* + * This function reads a value of a oscillator property from its id. +- * Returns value if success, and a default value if property not found. ++ * 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(enum stm32mp_osc_id osc_id, +@@ -166,200 +162,19 @@ uint32_t fdt_osc_read_uint32_default(enum stm32mp_osc_id osc_id, + return dflt_value; + } + +-/******************************************************************************* +- * This function reads the rcc base address. +- * It reads the value indicated inside the device tree. +- * Returns address if success, and 0 value else. +- ******************************************************************************/ +-uint32_t fdt_rcc_read_addr(void) +-{ +- int node, subnode; +- void *fdt; +- +- if (fdt_get_address(&fdt) == 0) { +- return 0; +- } +- +- 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 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. ++ * This function get interrupt name. ++ * It reads the values indicated the enabling status. + * Returns 0 if success, and a negative value else. +- * If success, values are stored at the second parameter address. +- ******************************************************************************/ +-int fdt_rcc_read_uint32_array(const char *prop_name, +- uint32_t *array, uint32_t count) +-{ +- int node; +- void *fdt; +- +- if (fdt_get_address(&fdt) == 0) { +- return -ENOENT; +- } +- +- node = fdt_node_offset_by_compatible(fdt, -1, DT_RCC_CLK_COMPAT); +- if (node < 0) { +- return -FDT_ERR_NOTFOUND; +- } +- +- return fdt_read_uint32_array(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 if success, and a negative value else. +- ******************************************************************************/ +-int fdt_rcc_subnode_offset(const char *name) +-{ +- int node, subnode; +- void *fdt; +- +- if (fdt_get_address(&fdt) == 0) { +- return -ENOENT; +- } +- +- node = fdt_node_offset_by_compatible(fdt, -1, DT_RCC_CLK_COMPAT); +- 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 if success, and NULL value else. +- ******************************************************************************/ +-const uint32_t *fdt_rcc_read_prop(const char *prop_name, int *lenp) +-{ +- const uint32_t *cuint; +- int node, len; +- void *fdt; +- +- if (fdt_get_address(&fdt) == 0) { +- return NULL; +- } +- +- node = fdt_node_offset_by_compatible(fdt, -1, DT_RCC_CLK_COMPAT); +- if (node < 0) { +- return NULL; +- } +- +- cuint = fdt_getprop(fdt, node, prop_name, &len); +- if (cuint == NULL) { +- return NULL; +- } +- +- *lenp = len; +- return cuint; +-} +- +-/******************************************************************************* +- * This function gets the secure status for rcc node. +- * It reads secure-status in device tree. +- * Returns 1 if rcc is available from secure world, 0 else. + ******************************************************************************/ +-bool fdt_get_rcc_secure_status(void) ++int fdt_rcc_enable_it(const char *name) + { +- int node; +- void *fdt; +- +- if (fdt_get_address(&fdt) == 0) { +- return false; +- } +- +- node = fdt_node_offset_by_compatible(fdt, -1, DT_RCC_COMPAT); +- if (node < 0) { +- return false; +- } +- +- return fdt_check_secure_status(node); +-} +- +-/******************************************************************************* +- * This function reads the stgen base address. +- * It reads the value indicated inside the device tree. +- * Returns address if success, and NULL value else. +- ******************************************************************************/ +-uintptr_t fdt_get_stgen_base(void) +-{ +- int node; +- const fdt32_t *cuint; +- void *fdt; +- +- if (fdt_get_address(&fdt) == 0) { +- return 0; +- } +- +- node = fdt_node_offset_by_compatible(fdt, -1, DT_STGEN_COMPAT); +- if (node < 0) { +- return 0; +- } +- +- cuint = fdt_getprop(fdt, node, "reg", NULL); +- if (cuint == NULL) { +- return 0; +- } +- +- return fdt32_to_cpu(*cuint); +-} +- +-/******************************************************************************* +- * This function gets the clock ID of the given node. +- * It reads the value indicated inside the device tree. +- * Returns ID if success, and a negative value else. +- ******************************************************************************/ +-int fdt_get_clock_id(int node) +-{ +- const fdt32_t *cuint; + void *fdt; + + if (fdt_get_address(&fdt) == 0) { + return -ENOENT; + } + +- cuint = fdt_getprop(fdt, node, "clocks", NULL); +- if (cuint == NULL) { +- return -FDT_ERR_NOTFOUND; +- } +- +- cuint++; +- return (int)fdt32_to_cpu(*cuint); ++ return stm32_gic_enable_spi(fdt_get_rcc_node(fdt), name); + } +diff --git a/drivers/st/clk/stm32mp_clkfunc.c b/drivers/st/clk/stm32mp_clkfunc.c +new file mode 100644 +index 0000000..5c7e202 +--- /dev/null ++++ b/drivers/st/clk/stm32mp_clkfunc.c +@@ -0,0 +1,307 @@ ++/* ++ * Copyright (c) 2017-2018, STMicroelectronics - All Rights Reserved ++ * ++ * SPDX-License-Identifier: BSD-3-Clause ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define DT_STGEN_COMPAT "st,stm32-stgen" ++#define DT_UART_COMPAT "st,stm32h7-uart" ++ ++/******************************************************************************* ++ * 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 the rcc base address. ++ * It reads the value indicated inside the device tree. ++ * Returns address on success, and 0 on failure. ++ ******************************************************************************/ ++uint32_t fdt_rcc_read_addr(void) ++{ ++ int node; ++ void *fdt; ++ const fdt32_t *cuint; ++ ++ if (fdt_get_address(&fdt) == 0) { ++ return 0; ++ } ++ ++ node = fdt_get_rcc_node(fdt); ++ if (node < 0) { ++ return 0; ++ } ++ ++ cuint = fdt_getprop(fdt, node, "reg", NULL); ++ if (cuint == NULL) { ++ return 0; ++ } ++ ++ return fdt32_to_cpu(*cuint); ++} ++ ++/******************************************************************************* ++ * 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(const char *prop_name, ++ uint32_t *array, uint32_t count) ++{ ++ int node; ++ void *fdt; ++ ++ if (fdt_get_address(&fdt) == 0) { ++ return -ENOENT; ++ } ++ ++ node = fdt_get_rcc_node(fdt); ++ if (node < 0) { ++ return -FDT_ERR_NOTFOUND; ++ } ++ ++ return fdt_read_uint32_array(node, prop_name, array, count); ++} ++ ++/******************************************************************************* ++ * This function reads a property rcc-clk section. ++ * It reads the values indicated inside the device tree, from property name. ++ * Returns dflt_value if property is not found, and a property value on ++ * success. ++ ******************************************************************************/ ++uint32_t fdt_rcc_read_uint32_default(const char *prop_name, uint32_t dflt_value) ++{ ++ int node; ++ void *fdt; ++ ++ if (fdt_get_address(&fdt) == 0) { ++ return dflt_value; ++ } ++ ++ node = fdt_node_offset_by_compatible(fdt, -1, DT_RCC_CLK_COMPAT); ++ if (node < 0) { ++ return dflt_value; ++ } ++ ++ return fdt_read_uint32_default(node, prop_name, dflt_value); ++} ++ ++/******************************************************************************* ++ * 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(const char *name) ++{ ++ int node, subnode; ++ void *fdt; ++ ++ if (fdt_get_address(&fdt) == 0) { ++ return -ENOENT; ++ } ++ ++ 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(const char *prop_name, int *lenp) ++{ ++ const fdt32_t *cuint; ++ int node, len; ++ void *fdt; ++ ++ if (fdt_get_address(&fdt) == 0) { ++ return NULL; ++ } ++ ++ 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 gets the secure status for rcc node. ++ * It reads secure-status in device tree. ++ * Returns true if rcc is available from secure world, false if not. ++ ******************************************************************************/ ++bool fdt_get_rcc_secure_status(void) ++{ ++ int node; ++ void *fdt; ++ ++ if (fdt_get_address(&fdt) == 0) { ++ return false; ++ } ++ ++ node = fdt_get_rcc_node(fdt); ++ if (node < 0) { ++ return false; ++ } ++ ++ return !!(fdt_get_status(node) & DT_SECURE); ++} ++ ++/******************************************************************************* ++ * 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 fdt_get_stgen_base(void) ++{ ++ int node; ++ const fdt32_t *cuint; ++ void *fdt; ++ ++ if (fdt_get_address(&fdt) == 0) { ++ return 0; ++ } ++ ++ node = fdt_node_offset_by_compatible(fdt, -1, DT_STGEN_COMPAT); ++ if (node < 0) { ++ return 0; ++ } ++ ++ cuint = fdt_getprop(fdt, node, "reg", NULL); ++ if (cuint == NULL) { ++ return 0; ++ } ++ ++ return fdt32_to_cpu(*cuint); ++} ++ ++/******************************************************************************* ++ * 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/ERRNO error code on failure. ++ ******************************************************************************/ ++int fdt_get_clock_id(int node) ++{ ++ const fdt32_t *cuint; ++ void *fdt; ++ ++ if (fdt_get_address(&fdt) == 0) { ++ return -ENOENT; ++ } ++ ++ 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/ERRNO error code on failure. ++ ******************************************************************************/ ++int fdt_get_clock_id_by_name(int node, const char *name) ++{ ++ const fdt32_t *cuint; ++ void *fdt; ++ int index, len; ++ ++ if (fdt_get_address(&fdt) == 0) { ++ return -ENOENT; ++ } ++ ++ 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 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 fdt_get_uart_clock_freq(uintptr_t instance) ++{ ++ int node; ++ void *fdt; ++ ++ if (fdt_get_address(&fdt) == 0) { ++ return 0; ++ } ++ ++ /* Check for UART nodes */ ++ node = fdt_node_offset_by_compatible(fdt, -1, DT_UART_COMPAT); ++ while (node != -FDT_ERR_NOTFOUND) { ++ const fdt32_t *cuint; ++ ++ cuint = fdt_getprop(fdt, node, "reg", NULL); ++ if (cuint == NULL) ++ goto next; ++ ++ if ((uintptr_t)fdt32_to_cpu(*cuint) == instance) { ++ unsigned long clk_id; ++ ++ cuint = fdt_getprop(fdt, node, "clocks", NULL); ++ if (cuint == NULL) ++ goto next; ++ ++ cuint++; ++ clk_id = (unsigned long)(fdt32_to_cpu(*cuint)); ++ ++ return stm32mp_clk_get_rate(clk_id); ++ } ++next: ++ node = fdt_node_offset_by_compatible(fdt, node, DT_UART_COMPAT); ++ } ++ ++ return 0; ++} +diff --git a/drivers/st/ddr/stm32mp1_ddr.c b/drivers/st/ddr/stm32mp1_ddr.c +index eed1d76..ae5668a 100644 +--- a/drivers/st/ddr/stm32mp1_ddr.c ++++ b/drivers/st/ddr/stm32mp1_ddr.c +@@ -8,18 +8,14 @@ + #include + #include + #include +-#include ++#include + #include + #include ++#include + #include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include ++#include ++#include ++#include + + struct reg_desc { + const char *name; +@@ -29,7 +25,8 @@ struct reg_desc { + + #define INVALID_OFFSET 0xFFU + +-#define TIMESLOT_1US (plat_get_syscnt_freq2() / 1000000U) ++#define TIMESLOT_1US us2tick(1) ++#define TIMEOUT_1S s2tick(1) + + #define DDRCTL_REG(x, y) \ + { \ +@@ -231,40 +228,67 @@ struct ddr_reg_info { + + static const struct ddr_reg_info ddr_registers[REG_TYPE_NB] = { + [REG_REG] = { +- "static", ddr_reg, ARRAY_SIZE(ddr_reg), DDR_BASE ++ .name = "static", ++ .desc = ddr_reg, ++ .size = ARRAY_SIZE(ddr_reg), ++ .base = DDR_BASE + }, + [REG_TIMING] = { +- "timing", ddr_timing, ARRAY_SIZE(ddr_timing), DDR_BASE ++ .name = "timing", ++ .desc = ddr_timing, ++ .size = ARRAY_SIZE(ddr_timing), ++ .base = DDR_BASE + }, + [REG_PERF] = { +- "perf", ddr_perf, ARRAY_SIZE(ddr_perf), DDR_BASE ++ .name = "perf", ++ .desc = ddr_perf, ++ .size = ARRAY_SIZE(ddr_perf), ++ .base = DDR_BASE + }, + [REG_MAP] = { +- "map", ddr_map, ARRAY_SIZE(ddr_map), DDR_BASE ++ .name = "map", ++ .desc = ddr_map, ++ .size = ARRAY_SIZE(ddr_map), ++ .base = DDR_BASE + }, + [REGPHY_REG] = { +- "static", ddrphy_reg, ARRAY_SIZE(ddrphy_reg), DDRPHY_BASE ++ .name = "static", ++ .desc = ddrphy_reg, ++ .size = ARRAY_SIZE(ddrphy_reg), ++ .base = DDRPHY_BASE + }, + [REGPHY_TIMING] = { +- "timing", ddrphy_timing, ARRAY_SIZE(ddrphy_timing), DDRPHY_BASE ++ .name = "timing", ++ .desc = ddrphy_timing, ++ .size = ARRAY_SIZE(ddrphy_timing), ++ .base = DDRPHY_BASE + }, + [REGPHY_CAL] = { +- "cal", ddrphy_cal, ARRAY_SIZE(ddrphy_cal), DDRPHY_BASE ++ .name = "cal", ++ .desc = ddrphy_cal, ++ .size = ARRAY_SIZE(ddrphy_cal), ++ .base = DDRPHY_BASE + }, + [REG_DYN] = { +- "dyn", ddr_dyn, ARRAY_SIZE(ddr_dyn), DDR_BASE ++ .name = "dyn", ++ .desc = ddr_dyn, ++ .size = ARRAY_SIZE(ddr_dyn), ++ .base = DDR_BASE + }, + [REGPHY_DYN] = { +- "dyn", ddrphy_dyn, ARRAY_SIZE(ddrphy_dyn), DDRPHY_BASE ++ .name = "dyn", ++ .desc = ddrphy_dyn, ++ .size = ARRAY_SIZE(ddrphy_dyn), ++ .base = DDRPHY_BASE + }, + }; + +-static uint32_t get_base_addr(const struct ddr_info *priv, enum base_type base) ++static uintptr_t get_base_addr(const struct ddr_info *priv, enum base_type base) + { + if (base == DDRPHY_BASE) { +- return (uint32_t)priv->phy; ++ return (uintptr_t)priv->phy; + } else { +- return (uint32_t)priv->ctl; ++ return (uintptr_t)priv->ctl; + } + } + +@@ -273,21 +297,22 @@ static void set_reg(const struct ddr_info *priv, + const void *param) + { + unsigned int i; +- unsigned int *ptr, value; ++ unsigned int value; + enum base_type base = ddr_registers[type].base; +- uint32_t base_addr = get_base_addr(priv, base); ++ uintptr_t base_addr = get_base_addr(priv, base); + const struct reg_desc *desc = ddr_registers[type].desc; + + VERBOSE("init %s\n", ddr_registers[type].name); + for (i = 0; i < ddr_registers[type].size; i++) { +- ptr = (unsigned int *)(base_addr + desc[i].offset); ++ uintptr_t ptr = base_addr + desc[i].offset; ++ + if (desc[i].par_offset == INVALID_OFFSET) { + ERROR("invalid parameter offset for %s", desc[i].name); + panic(); + } else { +- value = *((uint32_t *)((uint32_t)param + ++ value = *((uint32_t *)((uintptr_t)param + + desc[i].par_offset)); +- mmio_write_32((uint32_t)ptr, value); ++ mmio_write_32(ptr, value); + } + } + } +@@ -296,26 +321,27 @@ static void stm32mp1_ddrphy_idone_wait(struct stm32mp1_ddrphy *phy) + { + uint32_t pgsr; + int error = 0; +- unsigned long start; +- unsigned long time0, time; ++ uint64_t start, time0; + +- start = get_timer(0); ++ start = timeout_start(); + time0 = start; + + do { +- pgsr = mmio_read_32((uint32_t)&phy->pgsr); +- time = get_timer(start); ++ uint64_t time; ++ ++ pgsr = mmio_read_32((uintptr_t)&phy->pgsr); ++ time = timeout_start() - start; + if (time != time0) { +- VERBOSE(" > [0x%x] pgsr = 0x%x &\n", +- (uint32_t)&phy->pgsr, pgsr); +- VERBOSE(" [0x%x] pir = 0x%x (time=%x)\n", +- (uint32_t)&phy->pir, +- mmio_read_32((uint32_t)&phy->pir), +- (uint32_t)time); ++ VERBOSE(" > [0x%lx] pgsr = 0x%x &\n", ++ (uintptr_t)&phy->pgsr, pgsr); ++ VERBOSE(" [0x%lx] pir = 0x%x (time=%llx)\n", ++ (uintptr_t)&phy->pir, ++ mmio_read_32((uintptr_t)&phy->pir), ++ time); + } + + time0 = time; +- if (time > plat_get_syscnt_freq2()) { ++ if (time > TIMEOUT_1S) { + panic(); + } + if ((pgsr & DDRPHYC_PGSR_DTERR) != 0U) { +@@ -339,18 +365,18 @@ static void stm32mp1_ddrphy_idone_wait(struct stm32mp1_ddrphy *phy) + error++; + } + } while ((pgsr & DDRPHYC_PGSR_IDONE) == 0U && error == 0); +- VERBOSE("\n[0x%x] pgsr = 0x%x\n", +- (uint32_t)&phy->pgsr, pgsr); ++ VERBOSE("\n[0x%lx] pgsr = 0x%x\n", ++ (uintptr_t)&phy->pgsr, pgsr); + } + + static void stm32mp1_ddrphy_init(struct stm32mp1_ddrphy *phy, uint32_t pir) + { + uint32_t pir_init = pir | DDRPHYC_PIR_INIT; + +- mmio_write_32((uint32_t)&phy->pir, pir_init); +- VERBOSE("[0x%x] pir = 0x%x -> 0x%x\n", +- (uint32_t)&phy->pir, pir_init, +- mmio_read_32((uint32_t)&phy->pir)); ++ mmio_write_32((uintptr_t)&phy->pir, pir_init); ++ VERBOSE("[0x%lx] pir = 0x%x -> 0x%x\n", ++ (uintptr_t)&phy->pir, pir_init, ++ mmio_read_32((uintptr_t)&phy->pir)); + + /* Need to wait 10 configuration clock before start polling */ + udelay(10); +@@ -362,56 +388,57 @@ static void stm32mp1_ddrphy_init(struct stm32mp1_ddrphy *phy, uint32_t pir) + /* Start quasi dynamic register update */ + static void stm32mp1_start_sw_done(struct stm32mp1_ddrctl *ctl) + { +- mmio_clrbits_32((uint32_t)&ctl->swctl, DDRCTRL_SWCTL_SW_DONE); +- VERBOSE("[0x%x] swctl = 0x%x\n", +- (uint32_t)&ctl->swctl, mmio_read_32((uint32_t)&ctl->swctl)); ++ mmio_clrbits_32((uintptr_t)&ctl->swctl, DDRCTRL_SWCTL_SW_DONE); ++ VERBOSE("[0x%lx] swctl = 0x%x\n", ++ (uintptr_t)&ctl->swctl, mmio_read_32((uintptr_t)&ctl->swctl)); + } + + /* Wait quasi dynamic register update */ + static void stm32mp1_wait_sw_done_ack(struct stm32mp1_ddrctl *ctl) + { +- unsigned long start; ++ uint64_t start; + uint32_t swstat; + +- mmio_setbits_32((uint32_t)&ctl->swctl, DDRCTRL_SWCTL_SW_DONE); +- VERBOSE("[0x%x] swctl = 0x%x\n", +- (uint32_t)&ctl->swctl, mmio_read_32((uint32_t)&ctl->swctl)); ++ mmio_setbits_32((uintptr_t)&ctl->swctl, DDRCTRL_SWCTL_SW_DONE); ++ VERBOSE("[0x%lx] swctl = 0x%x\n", ++ (uintptr_t)&ctl->swctl, mmio_read_32((uintptr_t)&ctl->swctl)); + +- start = get_timer(0); ++ start = timeout_start(); + do { +- swstat = mmio_read_32((uint32_t)&ctl->swstat); +- VERBOSE("[0x%x] swstat = 0x%x ", +- (uint32_t)&ctl->swstat, swstat); +- VERBOSE("timer in ms 0x%x = start 0x%lx\r", +- get_timer(0), start); +- if (get_timer(start) > plat_get_syscnt_freq2()) { ++ swstat = mmio_read_32((uintptr_t)&ctl->swstat); ++ VERBOSE("[0x%lx] swstat = 0x%x ", ++ (uintptr_t)&ctl->swstat, swstat); ++ VERBOSE("timer in ms 0x%llx = start 0x%llx\r", ++ timeout_start(), start); ++ if (timeout_elapsed(start, TIMEOUT_1S)) { + panic(); + } + } while ((swstat & DDRCTRL_SWSTAT_SW_DONE_ACK) == 0U); + +- VERBOSE("[0x%x] swstat = 0x%x\n", +- (uint32_t)&ctl->swstat, swstat); ++ VERBOSE("[0x%lx] swstat = 0x%x\n", ++ (uintptr_t)&ctl->swstat, swstat); + } + + /* Wait quasi dynamic register update */ + static void stm32mp1_wait_operating_mode(struct ddr_info *priv, uint32_t mode) + { +- unsigned long start; ++ uint64_t start; + uint32_t stat; +- uint32_t operating_mode; +- uint32_t selref_type; + int break_loop = 0; + +- start = get_timer(0); ++ start = timeout_start(); + for ( ; ; ) { +- stat = mmio_read_32((uint32_t)&priv->ctl->stat); ++ uint32_t operating_mode; ++ uint32_t selref_type; ++ ++ stat = mmio_read_32((uintptr_t)&priv->ctl->stat); + operating_mode = stat & DDRCTRL_STAT_OPERATING_MODE_MASK; + selref_type = stat & DDRCTRL_STAT_SELFREF_TYPE_MASK; +- VERBOSE("[0x%x] stat = 0x%x\n", +- (uint32_t)&priv->ctl->stat, stat); +- VERBOSE("timer in ms 0x%x = start 0x%lx\r", +- get_timer(0), start); +- if (get_timer(start) > plat_get_syscnt_freq2()) { ++ VERBOSE("[0x%lx] stat = 0x%x\n", ++ (uintptr_t)&priv->ctl->stat, stat); ++ VERBOSE("timer in ms 0x%llx = start 0x%llx\r", ++ timeout_start(), start); ++ if (timeout_elapsed(start, TIMEOUT_1S)) { + panic(); + } + +@@ -439,8 +466,8 @@ static void stm32mp1_wait_operating_mode(struct ddr_info *priv, uint32_t mode) + } + } + +- VERBOSE("[0x%x] stat = 0x%x\n", +- (uint32_t)&priv->ctl->stat, stat); ++ VERBOSE("[0x%lx] stat = 0x%x\n", ++ (uintptr_t)&priv->ctl->stat, stat); + } + + /* Mode Register Writes (MRW or MRS) */ +@@ -457,7 +484,7 @@ static void stm32mp1_mode_register_write(struct ddr_info *priv, uint8_t addr, + * No write should be performed to MRCTRL0 and MRCTRL1 + * if MRSTAT.mr_wr_busy = 1. + */ +- while ((mmio_read_32((uint32_t)&priv->ctl->mrstat) & ++ while ((mmio_read_32((uintptr_t)&priv->ctl->mrstat) & + DDRCTRL_MRSTAT_MR_WR_BUSY) != 0U) { + ; + } +@@ -470,14 +497,14 @@ static void stm32mp1_mode_register_write(struct ddr_info *priv, uint8_t addr, + DDRCTRL_MRCTRL0_MR_RANK_ALL | + (((uint32_t)addr << DDRCTRL_MRCTRL0_MR_ADDR_SHIFT) & + DDRCTRL_MRCTRL0_MR_ADDR_MASK); +- mmio_write_32((uint32_t)&priv->ctl->mrctrl0, mrctrl0); +- VERBOSE("[0x%x] mrctrl0 = 0x%x (0x%x)\n", +- (uint32_t)&priv->ctl->mrctrl0, +- mmio_read_32((uint32_t)&priv->ctl->mrctrl0), mrctrl0); +- mmio_write_32((uint32_t)&priv->ctl->mrctrl1, data); +- VERBOSE("[0x%x] mrctrl1 = 0x%x\n", +- (uint32_t)&priv->ctl->mrctrl1, +- mmio_read_32((uint32_t)&priv->ctl->mrctrl1)); ++ mmio_write_32((uintptr_t)&priv->ctl->mrctrl0, mrctrl0); ++ VERBOSE("[0x%lx] mrctrl0 = 0x%x (0x%x)\n", ++ (uintptr_t)&priv->ctl->mrctrl0, ++ mmio_read_32((uintptr_t)&priv->ctl->mrctrl0), mrctrl0); ++ mmio_write_32((uintptr_t)&priv->ctl->mrctrl1, data); ++ VERBOSE("[0x%lx] mrctrl1 = 0x%x\n", ++ (uintptr_t)&priv->ctl->mrctrl1, ++ mmio_read_32((uintptr_t)&priv->ctl->mrctrl1)); + + /* + * 3. In a separate APB transaction, write the MRCTRL0.mr_wr to 1. This +@@ -487,22 +514,22 @@ static void stm32mp1_mode_register_write(struct ddr_info *priv, uint8_t addr, + * initiated until it is deasserted. + */ + mrctrl0 |= DDRCTRL_MRCTRL0_MR_WR; +- mmio_write_32((uint32_t)&priv->ctl->mrctrl0, mrctrl0); ++ mmio_write_32((uintptr_t)&priv->ctl->mrctrl0, mrctrl0); + +- while ((mmio_read_32((uint32_t)&priv->ctl->mrstat) & ++ while ((mmio_read_32((uintptr_t)&priv->ctl->mrstat) & + DDRCTRL_MRSTAT_MR_WR_BUSY) != 0U) { + ; + } + +- VERBOSE("[0x%x] mrctrl0 = 0x%x\n", +- (uint32_t)&priv->ctl->mrctrl0, mrctrl0); ++ VERBOSE("[0x%lx] mrctrl0 = 0x%x\n", ++ (uintptr_t)&priv->ctl->mrctrl0, mrctrl0); + } + + /* Switch DDR3 from DLL-on to DLL-off */ + static void stm32mp1_ddr3_dll_off(struct ddr_info *priv) + { +- uint32_t mr1 = mmio_read_32((uint32_t)&priv->phy->mr1); +- uint32_t mr2 = mmio_read_32((uint32_t)&priv->phy->mr2); ++ uint32_t mr1 = mmio_read_32((uintptr_t)&priv->phy->mr1); ++ uint32_t mr2 = mmio_read_32((uintptr_t)&priv->phy->mr2); + uint32_t dbgcam; + + VERBOSE("mr1: 0x%x\n", mr1); +@@ -512,10 +539,10 @@ static void stm32mp1_ddr3_dll_off(struct ddr_info *priv) + * 1. Set the DBG1.dis_hif = 1. + * This prevents further reads/writes being received on the HIF. + */ +- mmio_setbits_32((uint32_t)&priv->ctl->dbg1, DDRCTRL_DBG1_DIS_HIF); +- VERBOSE("[0x%x] dbg1 = 0x%x\n", +- (uint32_t)&priv->ctl->dbg1, +- mmio_read_32((uint32_t)&priv->ctl->dbg1)); ++ mmio_setbits_32((uintptr_t)&priv->ctl->dbg1, DDRCTRL_DBG1_DIS_HIF); ++ VERBOSE("[0x%lx] dbg1 = 0x%x\n", ++ (uintptr_t)&priv->ctl->dbg1, ++ mmio_read_32((uintptr_t)&priv->ctl->dbg1)); + + /* + * 2. Ensure all commands have been flushed from the uMCTL2 by polling +@@ -526,9 +553,9 @@ static void stm32mp1_ddr3_dll_off(struct ddr_info *priv) + * DBGCAM.dbg_hpr_q_depth = 0. + */ + do { +- dbgcam = mmio_read_32((uint32_t)&priv->ctl->dbgcam); +- VERBOSE("[0x%x] dbgcam = 0x%x\n", +- (uint32_t)&priv->ctl->dbgcam, dbgcam); ++ dbgcam = mmio_read_32((uintptr_t)&priv->ctl->dbgcam); ++ VERBOSE("[0x%lx] dbgcam = 0x%x\n", ++ (uintptr_t)&priv->ctl->dbgcam, dbgcam); + } while ((((dbgcam & DDRCTRL_DBGCAM_DATA_PIPELINE_EMPTY) == + DDRCTRL_DBGCAM_DATA_PIPELINE_EMPTY)) && + ((dbgcam & DDRCTRL_DBGCAM_DBG_Q_DEPTH) == 0U)); +@@ -572,11 +599,11 @@ static void stm32mp1_ddr3_dll_off(struct ddr_info *priv) + * PWRCTL.selfref_sw = 1, and polling STAT.operating_mode to ensure + * the DDRC has entered self-refresh. + */ +- mmio_setbits_32((uint32_t)&priv->ctl->pwrctl, ++ mmio_setbits_32((uintptr_t)&priv->ctl->pwrctl, + DDRCTRL_PWRCTL_SELFREF_SW); +- VERBOSE("[0x%x] pwrctl = 0x%x\n", +- (uint32_t)&priv->ctl->pwrctl, +- mmio_read_32((uint32_t)&priv->ctl->pwrctl)); ++ VERBOSE("[0x%lx] pwrctl = 0x%x\n", ++ (uintptr_t)&priv->ctl->pwrctl, ++ mmio_read_32((uintptr_t)&priv->ctl->pwrctl)); + + /* + * 8. Wait until STAT.operating_mode[1:0]==11 indicating that the +@@ -592,10 +619,10 @@ static void stm32mp1_ddr3_dll_off(struct ddr_info *priv) + */ + stm32mp1_start_sw_done(priv->ctl); + +- mmio_setbits_32((uint32_t)&priv->ctl->mstr, DDRCTRL_MSTR_DLL_OFF_MODE); +- VERBOSE("[0x%x] mstr = 0x%x\n", +- (uint32_t)&priv->ctl->mstr, +- mmio_read_32((uint32_t)&priv->ctl->mstr)); ++ mmio_setbits_32((uintptr_t)&priv->ctl->mstr, DDRCTRL_MSTR_DLL_OFF_MODE); ++ VERBOSE("[0x%lx] mstr = 0x%x\n", ++ (uintptr_t)&priv->ctl->mstr, ++ mmio_read_32((uintptr_t)&priv->ctl->mstr)); + + stm32mp1_wait_sw_done_ack(priv->ctl); + +@@ -608,27 +635,27 @@ static void stm32mp1_ddr3_dll_off(struct ddr_info *priv) + */ + + /* Change Bypass Mode Frequency Range */ +- if (stm32mp1_clk_get_rate(DDRPHYC) < 100000000U) { +- mmio_clrbits_32((uint32_t)&priv->phy->dllgcr, ++ if (stm32mp_clk_get_rate(DDRPHYC) < 100000000U) { ++ mmio_clrbits_32((uintptr_t)&priv->phy->dllgcr, + DDRPHYC_DLLGCR_BPS200); + } else { +- mmio_setbits_32((uint32_t)&priv->phy->dllgcr, ++ mmio_setbits_32((uintptr_t)&priv->phy->dllgcr, + DDRPHYC_DLLGCR_BPS200); + } + +- mmio_setbits_32((uint32_t)&priv->phy->acdllcr, DDRPHYC_ACDLLCR_DLLDIS); ++ mmio_setbits_32((uintptr_t)&priv->phy->acdllcr, DDRPHYC_ACDLLCR_DLLDIS); + +- mmio_setbits_32((uint32_t)&priv->phy->dx0dllcr, ++ mmio_setbits_32((uintptr_t)&priv->phy->dx0dllcr, + DDRPHYC_DXNDLLCR_DLLDIS); +- mmio_setbits_32((uint32_t)&priv->phy->dx1dllcr, ++ mmio_setbits_32((uintptr_t)&priv->phy->dx1dllcr, + DDRPHYC_DXNDLLCR_DLLDIS); +- mmio_setbits_32((uint32_t)&priv->phy->dx2dllcr, ++ mmio_setbits_32((uintptr_t)&priv->phy->dx2dllcr, + DDRPHYC_DXNDLLCR_DLLDIS); +- mmio_setbits_32((uint32_t)&priv->phy->dx3dllcr, ++ mmio_setbits_32((uintptr_t)&priv->phy->dx3dllcr, + DDRPHYC_DXNDLLCR_DLLDIS); + + /* 12. Exit the self-refresh state by setting PWRCTL.selfref_sw = 0. */ +- mmio_clrbits_32((uint32_t)&priv->ctl->pwrctl, ++ mmio_clrbits_32((uintptr_t)&priv->ctl->pwrctl, + DDRCTRL_PWRCTL_SELFREF_SW); + stm32mp1_wait_operating_mode(priv, DDRCTRL_STAT_OPERATING_MODE_NORMAL); + +@@ -644,20 +671,20 @@ static void stm32mp1_ddr3_dll_off(struct ddr_info *priv) + */ + + /* 15. Write DBG1.dis_hif = 0 to re-enable reads and writes. */ +- mmio_clrbits_32((uint32_t)&priv->ctl->dbg1, DDRCTRL_DBG1_DIS_HIF); +- VERBOSE("[0x%x] dbg1 = 0x%x\n", +- (uint32_t)&priv->ctl->dbg1, +- mmio_read_32((uint32_t)&priv->ctl->dbg1)); ++ mmio_clrbits_32((uintptr_t)&priv->ctl->dbg1, DDRCTRL_DBG1_DIS_HIF); ++ VERBOSE("[0x%lx] dbg1 = 0x%x\n", ++ (uintptr_t)&priv->ctl->dbg1, ++ mmio_read_32((uintptr_t)&priv->ctl->dbg1)); + } + + static void stm32mp1_refresh_disable(struct stm32mp1_ddrctl *ctl) + { + stm32mp1_start_sw_done(ctl); + /* Quasi-dynamic register update*/ +- mmio_setbits_32((uint32_t)&ctl->rfshctl3, ++ mmio_setbits_32((uintptr_t)&ctl->rfshctl3, + DDRCTRL_RFSHCTL3_DIS_AUTO_REFRESH); +- mmio_clrbits_32((uint32_t)&ctl->pwrctl, DDRCTRL_PWRCTL_POWERDOWN_EN); +- mmio_clrbits_32((uint32_t)&ctl->dfimisc, ++ mmio_clrbits_32((uintptr_t)&ctl->pwrctl, DDRCTRL_PWRCTL_POWERDOWN_EN); ++ mmio_clrbits_32((uintptr_t)&ctl->dfimisc, + DDRCTRL_DFIMISC_DFI_INIT_COMPLETE_EN); + stm32mp1_wait_sw_done_ack(ctl); + } +@@ -667,21 +694,99 @@ static void stm32mp1_refresh_restore(struct stm32mp1_ddrctl *ctl, + { + stm32mp1_start_sw_done(ctl); + if ((rfshctl3 & DDRCTRL_RFSHCTL3_DIS_AUTO_REFRESH) == 0U) { +- mmio_clrbits_32((uint32_t)&ctl->rfshctl3, ++ mmio_clrbits_32((uintptr_t)&ctl->rfshctl3, + DDRCTRL_RFSHCTL3_DIS_AUTO_REFRESH); + } + if ((pwrctl & DDRCTRL_PWRCTL_POWERDOWN_EN) != 0U) { +- mmio_setbits_32((uint32_t)&ctl->pwrctl, ++ mmio_setbits_32((uintptr_t)&ctl->pwrctl, + DDRCTRL_PWRCTL_POWERDOWN_EN); + } +- mmio_setbits_32((uint32_t)&ctl->dfimisc, ++ mmio_setbits_32((uintptr_t)&ctl->dfimisc, + DDRCTRL_DFIMISC_DFI_INIT_COMPLETE_EN); + stm32mp1_wait_sw_done_ack(ctl); + } + ++static void stm32mp1_refresh_cmd(struct stm32mp1_ddrctl *ctl) ++{ ++ uint32_t dbgstat; ++ ++ do { ++ dbgstat = mmio_read_32((uintptr_t)&ctl->dbgstat); ++ } while ((dbgstat & DDRCTRL_DBGSTAT_RANK0_REFRESH_BUSY) != 0U); ++ ++ mmio_setbits_32((uintptr_t)&ctl->dbgcmd, DDRCTRL_DBGCMD_RANK0_REFRESH); ++} ++ ++/* Refresh compensation by forcing refresh command ++ * Rule1: Tref should be always < tREFW ? R x tREBW/8 ++ * Rule2: refcomp = RU(Tref/tREFI) = RU(RxTref/tREFW) ++ */ ++static ++void stm32mp1_refresh_compensation(const struct stm32mp1_ddr_config *config, ++ struct stm32mp1_ddrctl *ctl, ++ uint64_t start) ++{ ++ uint32_t tck_ps; ++ uint64_t time, time_us, tref, trefi, refcomp, i; ++ ++ time = timeout_start() - start; ++ time_us = time / TIMESLOT_1US; ++ tck_ps = 1000000000U / config->info.speed; ++ if (tck_ps == 0U) { ++ return; ++ } ++ /* ref = refresh time in tck */ ++ tref = time_us * 1000000U / tck_ps; ++ trefi = ((mmio_read_32((uintptr_t)&ctl->rfshtmg) & ++ DDRCTRL_RFSHTMG_T_RFC_NOM_X1_X32_MASK) ++ >> DDRCTRL_RFSHTMG_T_RFC_NOM_X1_X32_SHIFT) * 32U; ++ if (trefi == 0U) { ++ return; ++ } ++ ++ /* div round up : number of refresh to compensate */ ++ refcomp = (tref + trefi - 1U) / trefi; ++ ++ for (i = 0; i < refcomp; i++) { ++ stm32mp1_refresh_cmd(ctl); ++ } ++} ++ ++static void stm32mp1_self_refresh_zcal(struct ddr_info *priv, uint32_t zdata) ++{ ++ /* sequence for PUBL I/O Data Retention during Power-Down */ ++ ++ /* 10. Override ZQ calibration with previously (pre-retention) ++ * calibrated values. This is done by writing 1 to ZQ0CRN.ZDEN ++ * and the override data to ZQ0CRN.ZDATA. ++ */ ++ mmio_setbits_32((uintptr_t)&priv->phy->zq0cr0, DDRPHYC_ZQ0CRN_ZDEN); ++ ++ mmio_clrsetbits_32((uintptr_t)&priv->phy->zq0cr0, ++ DDRPHYC_ZQ0CRN_ZDATA_MASK, ++ zdata << DDRPHYC_ZQ0CRN_ZDATA_SHIFT); ++ ++ /* 11. De-assert the PHY_top data retention enable signals ++ * (ret_en or ret_en_i/ret_en_n_i). ++ */ ++ mmio_setbits_32((uintptr_t)(priv->pwr) + PWR_CR3, PWR_CR3_DDRSRDIS); ++ mmio_clrbits_32((uintptr_t)(priv->pwr) + PWR_CR3, PWR_CR3_DDRRETEN); ++ ++ /* 12. Remove ZQ calibration override by writing 0 to ZQ0CRN.ZDEN. */ ++ mmio_clrbits_32((uintptr_t)&priv->phy->zq0cr0, DDRPHYC_ZQ0CRN_ZDEN); ++ ++ /* 13. Trigger ZQ calibration by writing 1 to PIR.INIT ++ * and '1' to PIR.ZCAL ++ */ ++ /* 14. Wait for ZQ calibration to finish by polling a 1 status ++ * on PGSR.IDONE. ++ */ ++ stm32mp1_ddrphy_init(priv->phy, DDRPHYC_PIR_ZCAL); ++} ++ + static int board_ddr_power_init(enum ddr_type ddr_type) + { +- if (dt_check_pmic()) { ++ if (dt_pmic_status() > 0) { + return pmic_ddr_power_init(ddr_type); + } + +@@ -691,13 +796,18 @@ static int board_ddr_power_init(enum ddr_type ddr_type) + void stm32mp1_ddr_init(struct ddr_info *priv, + struct stm32mp1_ddr_config *config) + { +- uint32_t pir; +- int ret; ++ uint32_t pir, ddr_reten; ++ int ret = -EINVAL; ++ uint64_t time; + + if ((config->c_reg.mstr & DDRCTRL_MSTR_DDR3) != 0U) { + ret = board_ddr_power_init(STM32MP_DDR3); +- } else { ++ } else if ((config->c_reg.mstr & DDRCTRL_MSTR_LPDDR2) != 0U) { + ret = board_ddr_power_init(STM32MP_LPDDR2); ++ } else if ((config->c_reg.mstr & DDRCTRL_MSTR_LPDDR3) != 0U) { ++ ret = board_ddr_power_init(STM32MP_LPDDR3); ++ } else { ++ ERROR("DDR type not supported\n"); + } + + if (ret != 0) { +@@ -705,8 +815,29 @@ void stm32mp1_ddr_init(struct ddr_info *priv, + } + + VERBOSE("name = %s\n", config->info.name); +- VERBOSE("speed = %d MHz\n", config->info.speed); ++ VERBOSE("speed = %d kHz\n", config->info.speed); + VERBOSE("size = 0x%x\n", config->info.size); ++ if (config->self_refresh) { ++ VERBOSE("sel-refresh exit (zdata = 0x%x)\n", config->zdata); ++ } ++ ++ /* Check DDR PHY pads retention */ ++ ddr_reten = mmio_read_32((uint32_t)(priv->pwr) + PWR_CR3) & ++ PWR_CR3_DDRRETEN; ++ if (config->self_refresh) { ++ if (ddr_reten == 0U) { ++ VERBOSE("self-refresh aborted: no retention\n"); ++ config->self_refresh = false; ++ } ++ } else { ++ if (ddr_reten != 0U) { ++ VERBOSE("disable DDR PHY retention\n"); ++ mmio_setbits_32((uint32_t)(priv->pwr) + PWR_CR3, ++ PWR_CR3_DDRSRDIS); ++ mmio_clrbits_32((uint32_t)(priv->pwr) + PWR_CR3, ++ PWR_CR3_DDRRETEN); ++ } ++ } + + /* DDR INIT SEQUENCE */ + +@@ -744,11 +875,11 @@ void stm32mp1_ddr_init(struct ddr_info *priv, + + /* 1.5. initialize registers ddr_umctl2 */ + /* Stop uMCTL2 before PHY is ready */ +- mmio_clrbits_32((uint32_t)&priv->ctl->dfimisc, ++ mmio_clrbits_32((uintptr_t)&priv->ctl->dfimisc, + DDRCTRL_DFIMISC_DFI_INIT_COMPLETE_EN); +- VERBOSE("[0x%x] dfimisc = 0x%x\n", +- (uint32_t)&priv->ctl->dfimisc, +- mmio_read_32((uint32_t)&priv->ctl->dfimisc)); ++ VERBOSE("[0x%lx] dfimisc = 0x%x\n", ++ (uintptr_t)&priv->ctl->dfimisc, ++ mmio_read_32((uintptr_t)&priv->ctl->dfimisc)); + + set_reg(priv, REG_REG, &config->c_reg); + +@@ -757,23 +888,31 @@ void stm32mp1_ddr_init(struct ddr_info *priv, + (DDRCTRL_MSTR_DDR3 | DDRCTRL_MSTR_DLL_OFF_MODE)) + == (DDRCTRL_MSTR_DDR3 | DDRCTRL_MSTR_DLL_OFF_MODE)) { + VERBOSE("deactivate DLL OFF in mstr\n"); +- mmio_clrbits_32((uint32_t)&priv->ctl->mstr, ++ mmio_clrbits_32((uintptr_t)&priv->ctl->mstr, + DDRCTRL_MSTR_DLL_OFF_MODE); +- VERBOSE("[0x%x] mstr = 0x%x\n", +- (uint32_t)&priv->ctl->mstr, +- mmio_read_32((uint32_t)&priv->ctl->mstr)); ++ VERBOSE("[0x%lx] mstr = 0x%x\n", ++ (uintptr_t)&priv->ctl->mstr, ++ mmio_read_32((uintptr_t)&priv->ctl->mstr)); + } + + set_reg(priv, REG_TIMING, &config->c_timing); + set_reg(priv, REG_MAP, &config->c_map); + +- /* Skip CTRL init, SDRAM init is done by PHY PUBL */ +- mmio_clrsetbits_32((uint32_t)&priv->ctl->init0, +- DDRCTRL_INIT0_SKIP_DRAM_INIT_MASK, +- DDRCTRL_INIT0_SKIP_DRAM_INIT_NORMAL); +- VERBOSE("[0x%x] init0 = 0x%x\n", +- (uint32_t)&priv->ctl->init0, +- mmio_read_32((uint32_t)&priv->ctl->init0)); ++ /* Keep the controller in self-refresh mode */ ++ if (config->self_refresh) { ++ mmio_setbits_32((uintptr_t)&priv->ctl->pwrctl, ++ DDRCTRL_PWRCTL_SELFREF_SW); ++ } ++ ++ { ++ /* Skip CTRL init, SDRAM init is done by PHY PUBL */ ++ mmio_clrsetbits_32((uintptr_t)&priv->ctl->init0, ++ DDRCTRL_INIT0_SKIP_DRAM_INIT_MASK, ++ DDRCTRL_INIT0_SKIP_DRAM_INIT_NORMAL); ++ VERBOSE("[0x%lx] init0 = 0x%x\n", ++ (uintptr_t)&priv->ctl->init0, ++ mmio_read_32((uintptr_t)&priv->ctl->init0)); ++ } + + set_reg(priv, REG_PERF, &config->c_perf); + +@@ -786,6 +925,7 @@ void stm32mp1_ddr_init(struct ddr_info *priv, + * 3. start PHY init by accessing relevant PUBL registers + * (DXGCR, DCR, PTR*, MR*, DTPR*) + */ ++ + set_reg(priv, REGPHY_REG, &config->p_reg); + set_reg(priv, REGPHY_TIMING, &config->p_timing); + set_reg(priv, REGPHY_CAL, &config->p_cal); +@@ -795,10 +935,10 @@ void stm32mp1_ddr_init(struct ddr_info *priv, + (DDRCTRL_MSTR_DDR3 | DDRCTRL_MSTR_DLL_OFF_MODE)) + == (DDRCTRL_MSTR_DDR3 | DDRCTRL_MSTR_DLL_OFF_MODE)) { + VERBOSE("deactivate DLL OFF in mr1\n"); +- mmio_clrbits_32((uint32_t)&priv->phy->mr1, BIT(0)); +- VERBOSE("[0x%x] mr1 = 0x%x\n", +- (uint32_t)&priv->phy->mr1, +- mmio_read_32((uint32_t)&priv->phy->mr1)); ++ mmio_clrbits_32((uintptr_t)&priv->phy->mr1, BIT(0)); ++ VERBOSE("[0x%lx] mr1 = 0x%x\n", ++ (uintptr_t)&priv->phy->mr1, ++ mmio_read_32((uintptr_t)&priv->phy->mr1)); + } + + /* +@@ -820,19 +960,31 @@ void stm32mp1_ddr_init(struct ddr_info *priv, + pir |= DDRPHYC_PIR_DRAMRST; /* Only for DDR3 */ + } + ++ /* Treat self-refresh exit : hot boot */ ++ if (config->self_refresh) { ++ /* DDR in self refresh mode, remove zcal & reset & init */ ++ pir &= ~(DDRPHYC_PIR_ZCAL & DDRPHYC_PIR_DRAMRST ++ & DDRPHYC_PIR_DRAMINIT); ++ pir |= DDRPHYC_PIR_ZCALBYP; ++ } ++ + stm32mp1_ddrphy_init(priv->phy, pir); + ++ if (config->self_refresh) { ++ stm32mp1_self_refresh_zcal(priv, config->zdata); ++ } ++ + /* + * 6. SET DFIMISC.dfi_init_complete_en to 1 + * Enable quasi-dynamic register programming. + */ + stm32mp1_start_sw_done(priv->ctl); + +- mmio_setbits_32((uint32_t)&priv->ctl->dfimisc, ++ mmio_setbits_32((uintptr_t)&priv->ctl->dfimisc, + DDRCTRL_DFIMISC_DFI_INIT_COMPLETE_EN); +- VERBOSE("[0x%x] dfimisc = 0x%x\n", +- (uint32_t)&priv->ctl->dfimisc, +- mmio_read_32((uint32_t)&priv->ctl->dfimisc)); ++ VERBOSE("[0x%lx] dfimisc = 0x%x\n", ++ (uintptr_t)&priv->ctl->dfimisc, ++ mmio_read_32((uintptr_t)&priv->ctl->dfimisc)); + + stm32mp1_wait_sw_done_ack(priv->ctl); + +@@ -842,6 +994,13 @@ void stm32mp1_ddr_init(struct ddr_info *priv, + */ + + /* Wait uMCTL2 ready */ ++ ++ /* Trigger self-refresh exit */ ++ if (config->self_refresh) { ++ mmio_clrbits_32((uintptr_t)&priv->ctl->pwrctl, ++ DDRCTRL_PWRCTL_SELFREF_SW); ++ } ++ + stm32mp1_wait_operating_mode(priv, DDRCTRL_STAT_OPERATING_MODE_NORMAL); + + /* Switch to DLL OFF mode */ +@@ -851,6 +1010,8 @@ void stm32mp1_ddr_init(struct ddr_info *priv, + + VERBOSE("DDR DQS training : "); + ++ time = timeout_start(); ++ + /* + * 8. Disable Auto refresh and power down by setting + * - RFSHCTL3.dis_au_refresh = 1 +@@ -875,6 +1036,11 @@ void stm32mp1_ddr_init(struct ddr_info *priv, + /* 11. monitor PUB PGSR.IDONE to poll cpmpletion of training sequence */ + stm32mp1_ddrphy_idone_wait(priv->phy); + ++ /* Refresh compensation: forcing refresh command */ ++ if (config->self_refresh) { ++ stm32mp1_refresh_compensation(config, priv->ctl, time); ++ } ++ + /* + * 12. set back registers in step 8 to the orginal values if desidered + */ +@@ -882,14 +1048,16 @@ void stm32mp1_ddr_init(struct ddr_info *priv, + config->c_reg.pwrctl); + + /* Enable uMCTL2 AXI port 0 */ +- mmio_setbits_32((uint32_t)&priv->ctl->pctrl_0, DDRCTRL_PCTRL_N_PORT_EN); +- VERBOSE("[0x%x] pctrl_0 = 0x%x\n", +- (uint32_t)&priv->ctl->pctrl_0, +- mmio_read_32((uint32_t)&priv->ctl->pctrl_0)); ++ mmio_setbits_32((uintptr_t)&priv->ctl->pctrl_0, ++ DDRCTRL_PCTRL_N_PORT_EN); ++ VERBOSE("[0x%lx] pctrl_0 = 0x%x\n", ++ (uintptr_t)&priv->ctl->pctrl_0, ++ mmio_read_32((uintptr_t)&priv->ctl->pctrl_0)); + + /* Enable uMCTL2 AXI port 1 */ +- mmio_setbits_32((uint32_t)&priv->ctl->pctrl_1, DDRCTRL_PCTRL_N_PORT_EN); +- VERBOSE("[0x%x] pctrl_1 = 0x%x\n", +- (uint32_t)&priv->ctl->pctrl_1, +- mmio_read_32((uint32_t)&priv->ctl->pctrl_1)); ++ mmio_setbits_32((uintptr_t)&priv->ctl->pctrl_1, ++ DDRCTRL_PCTRL_N_PORT_EN); ++ VERBOSE("[0x%lx] pctrl_1 = 0x%x\n", ++ (uintptr_t)&priv->ctl->pctrl_1, ++ mmio_read_32((uintptr_t)&priv->ctl->pctrl_1)); + } +diff --git a/drivers/st/ddr/stm32mp1_ddr_helpers.c b/drivers/st/ddr/stm32mp1_ddr_helpers.c +index 325c0b8..63f254f 100644 +--- a/drivers/st/ddr/stm32mp1_ddr_helpers.c ++++ b/drivers/st/ddr/stm32mp1_ddr_helpers.c +@@ -4,17 +4,521 @@ + * SPDX-License-Identifier: BSD-3-Clause + */ + ++#include ++#include ++#include + #include ++#include + #include +-#include +-#include ++#include ++ ++#define TIMEOUT_500US us2tick(500) + + void ddr_enable_clock(void) + { +- mmio_setbits_32(RCC_BASE + RCC_DDRITFCR, ++ stm32mp1_clk_rcc_regs_lock(); ++ ++ mmio_setbits_32(stm32mp_rcc_base() + RCC_DDRITFCR, + RCC_DDRITFCR_DDRC1EN | + RCC_DDRITFCR_DDRC2EN | + RCC_DDRITFCR_DDRPHYCEN | + RCC_DDRITFCR_DDRPHYCAPBEN | + RCC_DDRITFCR_DDRCAPBEN); ++ ++ stm32mp1_clk_rcc_regs_unlock(); ++} ++ ++static void do_sw_handshake(void) ++{ ++ uintptr_t ddrctrl_base = stm32mp_ddrctrl_base(); ++ ++ mmio_clrbits_32(ddrctrl_base + DDRCTRL_SWCTL, DDRCTRL_SWCTL_SW_DONE); ++} ++ ++static void do_sw_ack(void) ++{ ++ uint64_t start; ++ uintptr_t ddrctrl_base = stm32mp_ddrctrl_base(); ++ ++ mmio_setbits_32(ddrctrl_base + DDRCTRL_SWCTL, DDRCTRL_SWCTL_SW_DONE); ++ ++ start = timeout_start(); ++ while ((mmio_read_32(ddrctrl_base + DDRCTRL_SWSTAT) & ++ DDRCTRL_SWSTAT_SW_DONE_ACK) == 0U) { ++ if (timeout_elapsed(start, TIMEOUT_500US)) { ++ panic(); ++ } ++ } ++} ++ ++static int ddr_sw_self_refresh_in(void) ++{ ++ uint64_t start; ++ uint32_t stat; ++ uint32_t operating_mode; ++ uint32_t selref_type; ++ uint8_t op_mode_changed = 0; ++ uintptr_t rcc_base = stm32mp_rcc_base(); ++ uintptr_t pwr_base = stm32mp_pwr_base(); ++ uintptr_t ddrctrl_base = stm32mp_ddrctrl_base(); ++ uintptr_t ddrphyc_base = stm32mp_ddrphyc_base(); ++ ++ stm32mp1_clk_rcc_regs_lock(); ++ ++ mmio_clrbits_32(rcc_base + RCC_DDRITFCR, RCC_DDRITFCR_AXIDCGEN); ++ ++ stm32mp1_clk_rcc_regs_unlock(); ++ ++ /* 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 ++ */ ++ start = timeout_start(); ++ while (mmio_read_32(ddrctrl_base + DDRCTRL_PSTAT)) { ++ if (timeout_elapsed(start, TIMEOUT_500US)) { ++ 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. ++ */ ++ start = timeout_start(); ++ while (!timeout_elapsed(start, TIMEOUT_500US)) { ++ 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(ddrphyc_base + DDRPHYC_ACIOCR, DDRPHYC_ACIOCR_ACPDD); ++ ++ mmio_setbits_32(ddrphyc_base + DDRPHYC_ACIOCR, DDRPHYC_ACIOCR_ACPDR); ++ ++ mmio_clrsetbits_32(ddrphyc_base + DDRPHYC_ACIOCR, ++ DDRPHYC_ACIOCR_CKPDD_MASK, ++ DDRPHYC_ACIOCR_CKPDD_0); ++ ++ mmio_clrsetbits_32(ddrphyc_base + DDRPHYC_ACIOCR, ++ DDRPHYC_ACIOCR_CKPDR_MASK, ++ DDRPHYC_ACIOCR_CKPDR_0); ++ ++ mmio_clrsetbits_32(ddrphyc_base + DDRPHYC_ACIOCR, ++ DDRPHYC_ACIOCR_CSPDD_MASK, ++ DDRPHYC_ACIOCR_CSPDD_0); ++ ++ mmio_setbits_32(ddrphyc_base + DDRPHYC_DXCCR, DDRPHYC_DXCCR_DXPDD); ++ ++ mmio_setbits_32(ddrphyc_base + DDRPHYC_DXCCR, DDRPHYC_DXCCR_DXPDR); ++ ++ mmio_clrsetbits_32(ddrphyc_base + DDRPHYC_DSGCR, ++ DDRPHYC_DSGCR_ODTPDD_MASK, ++ DDRPHYC_DSGCR_ODTPDD_0); ++ ++ mmio_setbits_32(ddrphyc_base + DDRPHYC_DSGCR, DDRPHYC_DSGCR_NL2PD); ++ ++ mmio_clrsetbits_32(ddrphyc_base + DDRPHYC_DSGCR, ++ DDRPHYC_DSGCR_CKEPDD_MASK, ++ DDRPHYC_DSGCR_CKEPDD_0); ++ ++ /* Disable PZQ cell (PUBL register) */ ++ mmio_setbits_32(ddrphyc_base + DDRPHYC_ZQ0CR0, DDRPHYC_ZQ0CRN_ZQPD); ++ ++ /* Activate sw retention in PWRCTRL */ ++ pwr_regs_lock(); ++ mmio_setbits_32(pwr_base + PWR_CR3, PWR_CR3_DDRRETEN); ++ pwr_regs_unlock(); ++ ++ /* Switch controller clocks (uMCTL2/PUBL) to DLL ref clock */ ++ stm32mp1_clk_rcc_regs_lock(); ++ mmio_setbits_32(rcc_base + RCC_DDRITFCR, RCC_DDRITFCR_GSKPCTRL); ++ stm32mp1_clk_rcc_regs_unlock(); ++ ++ /* Disable all DLLs: GLITCH window */ ++ mmio_setbits_32(ddrphyc_base + DDRPHYC_ACDLLCR, ++ DDRPHYC_ACDLLCR_DLLDIS); ++ ++ mmio_setbits_32(ddrphyc_base + DDRPHYC_DX0DLLCR, ++ DDRPHYC_DXNDLLCR_DLLDIS); ++ ++ mmio_setbits_32(ddrphyc_base + DDRPHYC_DX1DLLCR, ++ DDRPHYC_DXNDLLCR_DLLDIS); ++ ++ mmio_setbits_32(ddrphyc_base + DDRPHYC_DX2DLLCR, ++ DDRPHYC_DXNDLLCR_DLLDIS); ++ ++ mmio_setbits_32(ddrphyc_base + DDRPHYC_DX3DLLCR, ++ DDRPHYC_DXNDLLCR_DLLDIS); ++ ++ stm32mp1_clk_rcc_regs_lock(); ++ ++ /* Switch controller clocks (uMCTL2/PUBL) to DLL output clock */ ++ mmio_clrbits_32(rcc_base + RCC_DDRITFCR, RCC_DDRITFCR_GSKPCTRL); ++ ++ /* Deactivate all DDR clocks */ ++ mmio_clrbits_32(rcc_base + RCC_DDRITFCR, ++ RCC_DDRITFCR_DDRC1EN | ++ RCC_DDRITFCR_DDRC2EN | ++ RCC_DDRITFCR_DDRCAPBEN | ++ RCC_DDRITFCR_DDRPHYCAPBEN); ++ ++ stm32mp1_clk_rcc_regs_unlock(); ++ ++ 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 start; ++ uintptr_t rcc_base = stm32mp_rcc_base(); ++ uintptr_t pwr_base = stm32mp_pwr_base(); ++ uintptr_t ddrctrl_base = stm32mp_ddrctrl_base(); ++ uintptr_t ddrphyc_base = stm32mp_ddrphyc_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 */ ++ stm32mp1_clk_rcc_regs_lock(); ++ mmio_setbits_32(rcc_base + RCC_DDRITFCR, RCC_DDRITFCR_GSKPCTRL); ++ stm32mp1_clk_rcc_regs_unlock(); ++ ++ /* Enable all DLLs: GLITCH window */ ++ mmio_clrbits_32(ddrphyc_base + DDRPHYC_ACDLLCR, ++ DDRPHYC_ACDLLCR_DLLDIS); ++ ++ mmio_clrbits_32(ddrphyc_base + DDRPHYC_DX0DLLCR, ++ DDRPHYC_DXNDLLCR_DLLDIS); ++ ++ mmio_clrbits_32(ddrphyc_base + DDRPHYC_DX1DLLCR, ++ DDRPHYC_DXNDLLCR_DLLDIS); ++ ++ mmio_clrbits_32(ddrphyc_base + DDRPHYC_DX2DLLCR, ++ DDRPHYC_DXNDLLCR_DLLDIS); ++ ++ mmio_clrbits_32(ddrphyc_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 */ ++ stm32mp1_clk_rcc_regs_lock(); ++ mmio_clrbits_32(rcc_base + RCC_DDRITFCR, RCC_DDRITFCR_GSKPCTRL); ++ stm32mp1_clk_rcc_regs_unlock(); ++ ++ mmio_clrbits_32(ddrphyc_base + DDRPHYC_ACDLLCR, ++ DDRPHYC_ACDLLCR_DLLSRST); ++ ++ udelay(10); ++ ++ mmio_setbits_32(ddrphyc_base + DDRPHYC_ACDLLCR, ++ DDRPHYC_ACDLLCR_DLLSRST); ++ ++ /* PHY partial init: (DLL lock and ITM reset) */ ++ mmio_write_32(ddrphyc_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); ++ ++ /* Pool end of init */ ++ start = timeout_start(); ++ ++ while ((mmio_read_32(ddrphyc_base + DDRPHYC_PGSR) & ++ DDRPHYC_PGSR_IDONE) == 0U) { ++ if (timeout_elapsed(start, TIMEOUT_500US)) { ++ 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 */ ++ pwr_regs_lock(); ++ mmio_clrbits_32(pwr_base + PWR_CR3, PWR_CR3_DDRRETEN); ++ pwr_regs_unlock(); ++ ++ /* Enable PZQ cell (PUBL register) */ ++ mmio_clrbits_32(ddrphyc_base + DDRPHYC_ZQ0CR0, DDRPHYC_ZQ0CRN_ZQPD); ++ ++ /* Enable pad drivers */ ++ mmio_clrbits_32(ddrphyc_base + DDRPHYC_ACIOCR, DDRPHYC_ACIOCR_ACPDD); ++ ++ mmio_clrbits_32(ddrphyc_base + DDRPHYC_ACIOCR, ++ DDRPHYC_ACIOCR_CKPDD_MASK); ++ ++ mmio_clrbits_32(ddrphyc_base + DDRPHYC_ACIOCR, ++ DDRPHYC_ACIOCR_CSPDD_MASK); ++ ++ mmio_clrbits_32(ddrphyc_base + DDRPHYC_DXCCR, DDRPHYC_DXCCR_DXPDD); ++ ++ mmio_clrbits_32(ddrphyc_base + DDRPHYC_DXCCR, DDRPHYC_DXCCR_DXPDR); ++ ++ mmio_clrbits_32(ddrphyc_base + DDRPHYC_DSGCR, ++ DDRPHYC_DSGCR_ODTPDD_MASK); ++ ++ mmio_clrbits_32(ddrphyc_base + DDRPHYC_DSGCR, DDRPHYC_DSGCR_NL2PD); ++ ++ mmio_clrbits_32(ddrphyc_base + DDRPHYC_DSGCR, ++ DDRPHYC_DSGCR_CKEPDD_MASK); ++ ++ /* Remove selfrefresh */ ++ mmio_clrbits_32(ddrctrl_base + DDRCTRL_PWRCTL, ++ DDRCTRL_PWRCTL_SELFREF_SW); ++ ++ /* Wait operating_mode == normal */ ++ start = timeout_start(); ++ while ((mmio_read_32(ddrctrl_base + DDRCTRL_STAT) & ++ DDRCTRL_STAT_OPERATING_MODE_MASK) != ++ DDRCTRL_STAT_OPERATING_MODE_NORMAL) { ++ if (timeout_elapsed(start, TIMEOUT_500US)) { ++ 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); ++ ++ stm32mp1_clk_rcc_regs_lock(); ++ ++ mmio_setbits_32(rcc_base + RCC_DDRITFCR, RCC_DDRITFCR_AXIDCGEN); ++ ++ stm32mp1_clk_rcc_regs_unlock(); ++ ++ return 0; ++} ++ ++int ddr_standby_sr_entry(uint32_t *zq0cr0_zdata) ++{ ++ uintptr_t pwr_base = stm32mp_pwr_base(); ++ uintptr_t ddrphyc_base = stm32mp_ddrphyc_base(); ++ ++ /* Save IOs calibration values */ ++ if (zq0cr0_zdata != NULL) { ++ *zq0cr0_zdata = mmio_read_32(ddrphyc_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 */ ++ pwr_regs_lock(); ++ mmio_setbits_32(pwr_base + PWR_CR3, PWR_CR3_DDRSREN); ++ pwr_regs_unlock(); ++ ++ return 0; ++} ++ ++void ddr_sr_mode_ssr(void) ++{ ++ uintptr_t rcc_ddritfcr = stm32mp_rcc_base() + RCC_DDRITFCR; ++ uintptr_t ddrctrl_base = stm32mp_ddrctrl_base(); ++ ++ stm32mp1_clk_rcc_regs_lock(); ++ ++ 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); ++ ++ stm32mp1_clk_rcc_regs_unlock(); ++ ++ /* 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 = stm32mp_rcc_base() + RCC_DDRITFCR; ++ uintptr_t ddrctrl_base = stm32mp_ddrctrl_base(); ++ ++ stm32mp1_clk_rcc_regs_lock(); ++ ++ 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); ++ ++ stm32mp1_clk_rcc_regs_unlock(); ++ ++ /* 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 = stm32mp_rcc_base() + RCC_DDRITFCR; ++ uintptr_t ddrctrl_base = stm32mp_ddrctrl_base(); ++ ++ stm32mp1_clk_rcc_regs_lock(); ++ ++ 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); ++ ++ stm32mp1_clk_rcc_regs_unlock(); ++ ++ /* 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); ++} ++ ++bool ddr_is_nonsecured_area(uintptr_t address, uint32_t length) ++{ ++ uint64_t pa; ++ ++ write_ats1cpw(address); ++ ++ isb(); ++ ++ pa = read64_par(); ++ ++ if ((((pa >> PAR_NS_SHIFT) & PAR_NS_MASK) != PAR_NS_MASK) || ++ (((pa >> PAR_F_SHIFT) & PAR_F_MASK) == PAR_F_MASK)) { ++ return false; ++ } ++ ++ write_ats1cpw(address + length - 1U); ++ ++ isb(); ++ ++ pa = read64_par(); ++ ++ if ((((pa >> PAR_NS_SHIFT) & PAR_NS_MASK) == PAR_NS_MASK) && ++ (((pa >> PAR_F_SHIFT) & PAR_F_MASK) != PAR_F_MASK)) { ++ return true; ++ } ++ ++ return false; + } +diff --git a/drivers/st/ddr/stm32mp1_ram.c b/drivers/st/ddr/stm32mp1_ram.c +index 6d515ec..82b8fda 100644 +--- a/drivers/st/ddr/stm32mp1_ram.c ++++ b/drivers/st/ddr/stm32mp1_ram.c +@@ -7,36 +7,30 @@ + #include + #include + #include +-#include + #include + #include + #include + #include +-#include +-#include +-#include +-#include +-#include +-#include +-#include ++#include ++#include + + #define DDR_PATTERN 0xAAAAAAAAU + #define DDR_ANTIPATTERN 0x55555555U + + static struct ddr_info ddr_priv_data; + +-int stm32mp1_ddr_clk_enable(struct ddr_info *priv, uint16_t mem_speed) ++int stm32mp1_ddr_clk_enable(struct ddr_info *priv, uint32_t mem_speed) + { + unsigned long ddrphy_clk, ddr_clk, mem_speed_hz; + + ddr_enable_clock(); + +- ddrphy_clk = stm32mp1_clk_get_rate(DDRPHYC); ++ ddrphy_clk = stm32mp_clk_get_rate(DDRPHYC); + +- VERBOSE("DDR: mem_speed (%d MHz), RCC %ld MHz\n", +- mem_speed, ddrphy_clk / 1000U / 1000U); ++ VERBOSE("DDR: mem_speed (%d kHz), RCC %ld kHz\n", ++ mem_speed, ddrphy_clk / 1000U); + +- mem_speed_hz = (uint32_t)mem_speed * 1000U * 1000U; ++ mem_speed_hz = mem_speed * 1000U; + + /* Max 10% frequency delta */ + if (ddrphy_clk > mem_speed_hz) { +@@ -44,15 +38,35 @@ int stm32mp1_ddr_clk_enable(struct ddr_info *priv, uint16_t mem_speed) + } else { + ddr_clk = mem_speed_hz - ddrphy_clk; + } +- if (ddr_clk > mem_speed_hz) { +- ERROR("DDR expected freq %d MHz, current is %ld MHz\n", +- mem_speed, ddrphy_clk / 1000U / 1000U); ++ if (ddr_clk > (mem_speed_hz / 10)) { ++ ERROR("DDR expected freq %d kHz, current is %ld kHz\n", ++ mem_speed, ddrphy_clk / 1000U); + return -1; + } + return 0; + } + + /******************************************************************************* ++ * This function tests a simple read/write access to the DDR. ++ * Note that the previous content is restored after test. ++ * Returns 0 if success, and address value else. ++ ******************************************************************************/ ++static uint32_t ddr_test_rw_access(void) ++{ ++ uint32_t saved_value = mmio_read_32(STM32MP_DDR_BASE); ++ ++ mmio_write_32(STM32MP_DDR_BASE, DDR_PATTERN); ++ ++ if (mmio_read_32(STM32MP_DDR_BASE) != DDR_PATTERN) { ++ return (uint32_t)STM32MP_DDR_BASE; ++ } ++ ++ mmio_write_32(STM32MP_DDR_BASE, saved_value); ++ ++ return 0; ++} ++ ++/******************************************************************************* + * This function tests the DDR data bus wiring. + * This is inspired from the Data Bus Test algorithm written by Michael Barr + * in "Programming Embedded Systems in C and C++" book. +@@ -65,10 +79,10 @@ static uint32_t ddr_test_data_bus(void) + uint32_t pattern; + + for (pattern = 1U; pattern != 0U; pattern <<= 1) { +- mmio_write_32(STM32MP1_DDR_BASE, pattern); ++ mmio_write_32(STM32MP_DDR_BASE, pattern); + +- if (mmio_read_32(STM32MP1_DDR_BASE) != pattern) { +- return (uint32_t)STM32MP1_DDR_BASE; ++ if (mmio_read_32(STM32MP_DDR_BASE) != pattern) { ++ return (uint32_t)STM32MP_DDR_BASE; + } + } + +@@ -92,44 +106,44 @@ static uint32_t ddr_test_addr_bus(void) + /* Write the default pattern at each of the power-of-two offsets. */ + for (offset = sizeof(uint32_t); (offset & addressmask) != 0U; + offset <<= 1) { +- mmio_write_32(STM32MP1_DDR_BASE + (uint32_t)offset, ++ mmio_write_32(STM32MP_DDR_BASE + (uint32_t)offset, + DDR_PATTERN); + } + + /* Check for address bits stuck high. */ +- mmio_write_32(STM32MP1_DDR_BASE + (uint32_t)testoffset, ++ mmio_write_32(STM32MP_DDR_BASE + (uint32_t)testoffset, + DDR_ANTIPATTERN); + + for (offset = sizeof(uint32_t); (offset & addressmask) != 0U; + offset <<= 1) { +- if (mmio_read_32(STM32MP1_DDR_BASE + (uint32_t)offset) != ++ if (mmio_read_32(STM32MP_DDR_BASE + (uint32_t)offset) != + DDR_PATTERN) { +- return (uint32_t)(STM32MP1_DDR_BASE + offset); ++ return (uint32_t)(STM32MP_DDR_BASE + offset); + } + } + +- mmio_write_32(STM32MP1_DDR_BASE + (uint32_t)testoffset, DDR_PATTERN); ++ mmio_write_32(STM32MP_DDR_BASE + (uint32_t)testoffset, DDR_PATTERN); + + /* Check for address bits stuck low or shorted. */ + for (testoffset = sizeof(uint32_t); (testoffset & addressmask) != 0U; + testoffset <<= 1) { +- mmio_write_32(STM32MP1_DDR_BASE + (uint32_t)testoffset, ++ mmio_write_32(STM32MP_DDR_BASE + (uint32_t)testoffset, + DDR_ANTIPATTERN); + +- if (mmio_read_32(STM32MP1_DDR_BASE) != DDR_PATTERN) { +- return STM32MP1_DDR_BASE; ++ if (mmio_read_32(STM32MP_DDR_BASE) != DDR_PATTERN) { ++ return STM32MP_DDR_BASE; + } + + for (offset = sizeof(uint32_t); (offset & addressmask) != 0U; + offset <<= 1) { +- if ((mmio_read_32(STM32MP1_DDR_BASE + ++ if ((mmio_read_32(STM32MP_DDR_BASE + + (uint32_t)offset) != DDR_PATTERN) && + (offset != testoffset)) { +- return (uint32_t)(STM32MP1_DDR_BASE + offset); ++ return (uint32_t)(STM32MP_DDR_BASE + offset); + } + } + +- mmio_write_32(STM32MP1_DDR_BASE + (uint32_t)testoffset, ++ mmio_write_32(STM32MP_DDR_BASE + (uint32_t)testoffset, + DDR_PATTERN); + } + +@@ -147,13 +161,13 @@ static uint32_t ddr_check_size(void) + { + uint32_t offset = sizeof(uint32_t); + +- mmio_write_32(STM32MP1_DDR_BASE, DDR_PATTERN); ++ mmio_write_32(STM32MP_DDR_BASE, DDR_PATTERN); + +- while (offset < STM32MP1_DDR_MAX_SIZE) { +- mmio_write_32(STM32MP1_DDR_BASE + offset, DDR_ANTIPATTERN); ++ while (offset < STM32MP_DDR_MAX_SIZE) { ++ mmio_write_32(STM32MP_DDR_BASE + offset, DDR_ANTIPATTERN); + dsb(); + +- if (mmio_read_32(STM32MP1_DDR_BASE) != DDR_PATTERN) { ++ if (mmio_read_32(STM32MP_DDR_BASE) != DDR_PATTERN) { + break; + } + +@@ -171,8 +185,12 @@ static int stm32mp1_ddr_setup(void) + int ret; + struct stm32mp1_ddr_config config; + int node, len; +- uint32_t tamp_clk_off = 0, uret, idx; ++ uint32_t magic, uret, idx; + void *fdt; ++ uint32_t bkpr_core1_addr = ++ tamp_bkpr(BOOT_API_CORE1_BRANCH_ADDRESS_TAMP_BCK_REG_IDX); ++ uint32_t bkpr_core1_magic = ++ tamp_bkpr(BOOT_API_CORE1_MAGIC_NUMBER_TAMP_BCK_REG_IDX); + + #define PARAM(x, y) \ + { \ +@@ -208,11 +226,16 @@ static int stm32mp1_ddr_setup(void) + return -EINVAL; + } + +- config.info.speed = +- (uint16_t)fdt_read_uint32_default(node, "st,mem-speed", +- STM32MP1_DDR_SPEED_DFLT); +- config.info.size = fdt_read_uint32_default(node, "st,mem-size", +- STM32MP1_DDR_SIZE_DFLT); ++ config.info.speed = fdt_read_uint32_default(node, "st,mem-speed", 0); ++ if (!config.info.speed) { ++ VERBOSE("%s: no st,mem-speed\n", __func__); ++ return -EINVAL; ++ } ++ config.info.size = fdt_read_uint32_default(node, "st,mem-size", 0); ++ if (!config.info.size) { ++ VERBOSE("%s: no st,mem-size\n", __func__); ++ return -EINVAL; ++ } + config.info.name = fdt_getprop(fdt, node, "st,mem-name", &len); + if (config.info.name == NULL) { + VERBOSE("%s: no st,mem-name\n", __func__); +@@ -222,7 +245,7 @@ static int stm32mp1_ddr_setup(void) + + for (idx = 0; idx < ARRAY_SIZE(param); idx++) { + ret = fdt_read_uint32_array(node, param[idx].name, +- (void *)((uint32_t)&config + ++ (void *)((uintptr_t)&config + + param[idx].offset), + param[idx].size); + +@@ -235,19 +258,18 @@ static int stm32mp1_ddr_setup(void) + } + } + +- if (!stm32mp1_clk_is_enabled(RTCAPB)) { +- tamp_clk_off = 1; +- if (stm32mp1_clk_enable(RTCAPB) != 0) { +- return -EINVAL; +- } +- } ++ config.self_refresh = false; + +- if (tamp_clk_off != 0U) { +- if (stm32mp1_clk_disable(RTCAPB) != 0) { +- return -EINVAL; +- } ++ stm32mp_clk_enable(RTCAPB); ++ ++ magic = mmio_read_32(bkpr_core1_magic); ++ if (magic == BOOT_API_A7_CORE0_MAGIC_NUMBER) { ++ config.self_refresh = true; ++ config.zdata = stm32_get_zdata_from_context(); + } + ++ stm32mp_clk_disable(RTCAPB); ++ + /* Disable axidcg clock gating during init */ + mmio_clrbits_32(priv->rcc + RCC_DDRITFCR, RCC_DDRITFCR_AXIDCGEN); + +@@ -256,36 +278,60 @@ static int stm32mp1_ddr_setup(void) + /* Enable axidcg clock gating */ + mmio_setbits_32(priv->rcc + RCC_DDRITFCR, RCC_DDRITFCR_AXIDCGEN); + ++ /* check if DDR content is lost (self-refresh aborted) */ ++ if ((magic == BOOT_API_A7_CORE0_MAGIC_NUMBER) && !config.self_refresh) { ++ /* clear Backup register */ ++ mmio_write_32(bkpr_core1_addr, 0); ++ /* clear magic number */ ++ mmio_write_32(bkpr_core1_magic, 0); ++ } ++ + priv->info.size = config.info.size; + + VERBOSE("%s : ram size(%x, %x)\n", __func__, + (uint32_t)priv->info.base, (uint32_t)priv->info.size); + +- dcsw_op_all(DC_OP_CISW); ++#ifndef DCACHE_OFF + write_sctlr(read_sctlr() & ~SCTLR_C_BIT); ++ dcsw_op_all(DC_OP_CISW); ++#endif ++ ++ if (config.self_refresh) { ++ uret = ddr_test_rw_access(); ++ if (uret != 0U) { ++ ERROR("DDR rw test: Can't access memory @ 0x%x\n", ++ uret); ++ panic(); ++ } + +- uret = ddr_test_data_bus(); +- if (uret != 0U) { +- ERROR("DDR data bus test: can't access memory @ 0x%x\n", +- uret); +- panic(); +- } ++ /* Restore area overwritten by training */ ++ stm32_restore_ddr_training_area(); ++ } else { ++ uret = ddr_test_data_bus(); ++ if (uret != 0U) { ++ ERROR("DDR data bus test: can't access memory @ 0x%x\n", ++ uret); ++ panic(); ++ } + +- uret = ddr_test_addr_bus(); +- if (uret != 0U) { +- ERROR("DDR addr bus test: can't access memory @ 0x%x\n", +- uret); +- panic(); +- } ++ uret = ddr_test_addr_bus(); ++ if (uret != 0U) { ++ ERROR("DDR addr bus test: can't access memory @ 0x%x\n", ++ uret); ++ panic(); ++ } + +- uret = ddr_check_size(); +- if (uret < config.info.size) { +- ERROR("DDR size: 0x%x does not match DT config: 0x%x\n", +- uret, config.info.size); +- panic(); ++ uret = ddr_check_size(); ++ if (uret < config.info.size) { ++ ERROR("DDR size: 0x%x does not match DT config: 0x%x\n", ++ uret, config.info.size); ++ panic(); ++ } + } + ++#ifndef DCACHE_OFF + write_sctlr(read_sctlr() | SCTLR_C_BIT); ++#endif + + return 0; + } +@@ -296,12 +342,12 @@ int stm32mp1_ddr_probe(void) + + VERBOSE("STM32MP DDR probe\n"); + +- priv->ctl = (struct stm32mp1_ddrctl *)DDRCTRL_BASE; +- priv->phy = (struct stm32mp1_ddrphy *)DDRPHYC_BASE; +- priv->pwr = PWR_BASE; +- priv->rcc = RCC_BASE; ++ priv->ctl = (struct stm32mp1_ddrctl *)stm32mp_ddrctrl_base(); ++ priv->phy = (struct stm32mp1_ddrphy *)stm32mp_ddrphyc_base(); ++ priv->pwr = stm32mp_pwr_base(); ++ priv->rcc = stm32mp_rcc_base(); + +- priv->info.base = STM32MP1_DDR_BASE; ++ priv->info.base = STM32MP_DDR_BASE; + priv->info.size = 0; + + return stm32mp1_ddr_setup(); +diff --git a/drivers/st/etzpc/etzpc.c b/drivers/st/etzpc/etzpc.c +new file mode 100644 +index 0000000..06c3282 +--- /dev/null ++++ b/drivers/st/etzpc/etzpc.c +@@ -0,0 +1,310 @@ ++/* ++ * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved. ++ * Copyright (c) 2017-2018, STMicroelectronics ++ * ++ * SPDX-License-Identifier: BSD-3-Clause ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* Device Tree related definitions */ ++#define ETZPC_COMPAT "st,stm32-etzpc" ++#define ETZPC_LOCK_MASK 0x1U ++#define ETZPC_MODE_SHIFT 8 ++#define ETZPC_MODE_MASK GENMASK(1, 0) ++#define ETZPC_ID_SHIFT 16 ++#define ETZPC_ID_MASK GENMASK(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(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 ++ ++/* ++ * etzpc_instance. ++ * base : register 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 ++ */ ++struct etzpc_instance { ++ uintptr_t base; ++ uint8_t chunck_size; ++ uint8_t num_tzma; ++ uint8_t num_per_sec; ++ uint8_t num_ahb_sec; ++ uint8_t revision; ++}; ++ ++/* Only 1 instance of the ETZPC is expected per platform */ ++static struct etzpc_instance etzpc_dev; ++ ++struct dt_id_attr { ++ fdt32_t id_attr[STM32MP1_ETZPC_MAX_ID]; ++}; ++ ++/* ++ * 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(2, 0) ++ ++static bool valid_decprot_id(unsigned int id) ++{ ++ return id < (unsigned int)etzpc_dev.num_per_sec; ++} ++ ++#if ENABLE_ASSERTIONS ++static bool valid_tzma_id(unsigned int id) ++{ ++ return id < (unsigned int)etzpc_dev.num_tzma; ++} ++#endif ++ ++static int etzpc_dt_conf_decprot(int node) ++{ ++ const struct dt_id_attr *conf_list; ++ void *fdt; ++ unsigned int i; ++ int len = 0; ++ ++ if (fdt_get_address(&fdt) == 0) { ++ return -ENOENT; ++ } ++ ++ conf_list = (const struct dt_id_attr *)fdt_getprop(fdt, node, ++ "st,decprot", &len); ++ if (conf_list == NULL) { ++ INFO("No ETZPC configuration in DT, use default\n"); ++ return 0; ++ } ++ ++ for (i = 0U; i < (unsigned int)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)) { ++ ERROR("Invalid DECPROT %d", id); ++ return -1; ++ } ++ ++ mode = (value >> ETZPC_MODE_SHIFT) & ETZPC_MODE_MASK; ++ attr = stm32mp_etzpc_binding2decprot(mode); ++ ++ stm32mp1_register_etzpc_decprot(id, attr); ++ ++ etzpc_configure_decprot(id, attr); ++ ++ if ((value & ETZPC_LOCK_MASK) != 0U) { ++ etzpc_lock_decprot(id); ++ } ++ } ++ ++ return 0; ++} ++ ++/* ++ * etzpc_configure_decprot : Load a DECPROT configuration ++ * decprot_id : ID of the IP ++ * decprot_attr : Restriction access attribute ++ */ ++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; ++ ++ assert(valid_decprot_id(decprot_id)); ++ ++ mmio_clrsetbits_32(etzpc_dev.base + ETZPC_DECPROT0 + offset, ++ (uint32_t)ETZPC_DECPROT0_MASK << shift, ++ masked_decprot << shift); ++} ++ ++/* ++ * 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) ++{ ++ 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_dev.base + offset; ++ uint32_t value; ++ ++ assert(valid_decprot_id(decprot_id)); ++ ++ value = (mmio_read_32(base_decprot + ETZPC_DECPROT0) >> shift) & ++ ETZPC_DECPROT0_MASK; ++ ++ return (enum etzpc_decprot_attributes)value; ++} ++ ++/* ++ * etzpc_lock_decprot : Lock access to the DECPROT attribute ++ * decprot_id : ID of the IP ++ */ ++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_dev.base + offset; ++ ++ assert(valid_decprot_id(decprot_id)); ++ ++ mmio_write_32(base_decprot + ETZPC_DECPROT_LOCK0, shift); ++} ++ ++/* ++ * 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) ++{ ++ assert(valid_tzma_id(tzma_id)); ++ ++ mmio_write_32(etzpc_dev.base + ETZPC_TZMA0_SIZE + ++ (sizeof(uint32_t) * tzma_id), 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) ++{ ++ assert(valid_tzma_id(tzma_id)); ++ ++ return (uint16_t)mmio_read_32(etzpc_dev.base + ETZPC_TZMA0_SIZE + ++ (sizeof(uint32_t) * tzma_id)); ++} ++ ++/* ++ * etzpc_lock_tzma : Lock the target TZMA ++ * tzma_id : TZMA ID ++ */ ++void etzpc_lock_tzma(uint32_t tzma_id) ++{ ++ assert(valid_tzma_id(tzma_id)); ++ ++ mmio_setbits_32(etzpc_dev.base + ETZPC_TZMA0_SIZE + ++ (sizeof(uint32_t) * tzma_id), ETZPC_TZMA0_SIZE_LOCK); ++} ++ ++/* ++ * 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) ++{ ++ uint32_t tzma_size; ++ ++ assert(valid_tzma_id(tzma_id)); ++ ++ tzma_size = mmio_read_32(etzpc_dev.base + ETZPC_TZMA0_SIZE + ++ (sizeof(uint32_t) * tzma_id)); ++ ++ return (tzma_size & ETZPC_TZMA0_SIZE_LOCK) != 0; ++} ++ ++/* ++ * etzpc_get_num_per_sec : Return the DECPROT ID limit value ++ */ ++uint8_t etzpc_get_num_per_sec(void) ++{ ++ return etzpc_dev.num_per_sec; ++} ++ ++/* ++ * etzpc_get_revision : Return the ETZPC IP revision ++ */ ++uint8_t etzpc_get_revision(void) ++{ ++ return etzpc_dev.revision; ++} ++ ++/* ++ * etzpc_get_base_address : Return the ETZPC IP base address ++ */ ++uintptr_t etzpc_get_base_address(void) ++{ ++ return etzpc_dev.base; ++} ++ ++/* ++ * etzpc_init : Initialize the ETZPC driver ++ * Return 0 on success else a non zero value ++ */ ++int etzpc_init(void) ++{ ++ uint32_t hwcfg; ++ int node; ++ struct dt_node_info etzpc_info; ++ ++ node = dt_get_node(&etzpc_info, -1, ETZPC_COMPAT); ++ if (node < 0) { ++ return -EIO; ++ } ++ ++ /* Check ETZPC is secure only */ ++ if (etzpc_info.status != DT_SECURE) { ++ return -EACCES; ++ } ++ ++ etzpc_dev.base = etzpc_info.base; ++ ++ hwcfg = mmio_read_32(etzpc_dev.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 = mmio_read_8(etzpc_dev.base + ETZPC_VERR); ++ ++ VERBOSE("ETZPC version 0x%x", etzpc_dev.revision); ++ ++ return etzpc_dt_conf_decprot(node); ++} +diff --git a/drivers/st/gpio/stm32_gpio.c b/drivers/st/gpio/stm32_gpio.c +index 200b473..fc0dce8 100644 +--- a/drivers/st/gpio/stm32_gpio.c ++++ b/drivers/st/gpio/stm32_gpio.c +@@ -4,83 +4,280 @@ + * SPDX-License-Identifier: BSD-3-Clause + */ + ++#include + #include + #include ++#include ++#include + #include ++#include + #include + #include ++#include ++#include ++#include + +-static bool check_gpio(uint32_t bank, uint32_t pin) ++#define DT_GPIO_BANK_SHIFT 12 ++#define DT_GPIO_BANK_MASK 0x1F000U ++#define DT_GPIO_PIN_SHIFT 8 ++#define DT_GPIO_PIN_MASK 0xF00U ++#define DT_GPIO_MODE_MASK 0xFFU ++ ++/******************************************************************************* ++ * This function gets GPIO bank node in DT. ++ * Returns node offset if status is okay in DT, else return 0 ++ ******************************************************************************/ ++static int ckeck_gpio_bank(void *fdt, uint32_t bank, int pinctrl_node) + { +- if (pin > GPIO_PIN_MAX) { +- ERROR("%s: wrong pin number (%d)\n", __func__, pin); +- return false; +- } ++ 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; ++ } + +- if ((bank > GPIO_BANK_K) && (bank != GPIO_BANK_Z)) { +- ERROR("%s: wrong GPIO bank number (%d)\n", __func__, bank); +- return false; ++ 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(pinctrl_subnode) != DT_DISABLED)) { ++ return pinctrl_subnode; ++ } + } + +- return true; ++ return 0; + } + +-void set_gpio(uint32_t bank, uint32_t pin, uint32_t mode, uint32_t speed, +- uint32_t pull, uint32_t alternate) ++/******************************************************************************* ++ * This function gets the pin settings from DT information. ++ * When analyze and parsing is done, set the GPIO registers. ++ * Returns 0 on success and a negative FDT error code on failure. ++ ******************************************************************************/ ++static int dt_set_gpio_config(void *fdt, int node, uint8_t status) + { +- volatile uint32_t bank_address; ++ const fdt32_t *cuint, *slewrate; ++ int len; ++ int pinctrl_node; ++ uint32_t i; ++ uint32_t speed = GPIO_SPEED_LOW; ++ uint32_t pull = GPIO_NO_PULL; ++ ++ 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; ++ } + +- if (!check_gpio(bank, pin)) { +- return; ++ slewrate = fdt_getprop(fdt, node, "slew-rate", NULL); ++ if (slewrate != NULL) { ++ speed = fdt32_to_cpu(*slewrate); + } + +- if (bank == GPIO_BANK_Z) { +- bank_address = STM32_GPIOZ_BANK; ++ 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 { +- bank_address = STM32_GPIOA_BANK + +- (bank * STM32_GPIO_BANK_OFFSET); ++ VERBOSE("No bias configured in node %d\n", node); ++ } ++ ++ for (i = 0U; 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); ++ int bank_node; ++ int clk; ++ ++ 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 ... 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) { ++ ERROR("PINCTRL inconsistent in DT\n"); ++ panic(); ++ } ++ ++ clk = fdt_get_clock_id(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)); ++ ++ set_gpio(bank, pin, mode, speed, pull, alternate, status); ++ } ++ ++ return 0; ++} ++ ++/******************************************************************************* ++ * This function gets the pin settings from DT information. ++ * When analyze and parsing is done, set the GPIO registers. ++ * Returns 0 on success and a negative FDT/ERRNO error code on failure. ++ ******************************************************************************/ ++int dt_set_pinctrl_config(int node) ++{ ++ const fdt32_t *cuint; ++ int lenp = 0; ++ uint32_t i; ++ uint8_t status = fdt_get_status(node); ++ void *fdt; ++ ++ if (fdt_get_address(&fdt) == 0) { ++ return -ENOENT; ++ } ++ ++ if (status == DT_DISABLED) { ++ return -FDT_ERR_NOTFOUND; + } + +- mmio_clrbits_32(bank_address + GPIO_MODE_OFFSET, ++ cuint = fdt_getprop(fdt, node, "pinctrl-0", &lenp); ++ if (cuint == NULL) { ++ return -FDT_ERR_NOTFOUND; ++ } ++ ++ for (i = 0; i < ((uint32_t)lenp / 4U); i++) { ++ int p_node, p_subnode; ++ ++ p_node = fdt_node_offset_by_phandle(fdt, fdt32_to_cpu(*cuint)); ++ if (p_node < 0) { ++ return -FDT_ERR_NOTFOUND; ++ } ++ ++ fdt_for_each_subnode(p_subnode, fdt, p_node) { ++ int ret = dt_set_gpio_config(fdt, p_subnode, status); ++ ++ if (ret < 0) { ++ return ret; ++ } ++ } ++ ++ cuint++; ++ } ++ ++ return 0; ++} ++ ++void set_gpio(uint32_t bank, uint32_t pin, uint32_t mode, uint32_t speed, ++ uint32_t pull, uint32_t alternate, uint8_t status) ++{ ++ uintptr_t base = stm32_get_gpio_bank_base(bank); ++ int clock = stm32_get_gpio_bank_clock(bank); ++ ++ assert(pin <= GPIO_PIN_MAX); ++ ++ stm32mp_clk_enable((unsigned long)clock); ++ ++ mmio_clrbits_32(base + GPIO_MODE_OFFSET, + ((uint32_t)GPIO_MODE_MASK << (pin << 1))); +- mmio_setbits_32(bank_address + GPIO_MODE_OFFSET, ++ mmio_setbits_32(base + GPIO_MODE_OFFSET, + (mode & ~GPIO_OPEN_DRAIN) << (pin << 1)); + + if ((mode & GPIO_OPEN_DRAIN) != 0U) { +- mmio_setbits_32(bank_address + GPIO_TYPE_OFFSET, +- BIT(pin)); ++ mmio_setbits_32(base + GPIO_TYPE_OFFSET, BIT(pin)); ++ } else { ++ mmio_clrbits_32(base + GPIO_TYPE_OFFSET, BIT(pin)); + } + +- mmio_clrbits_32(bank_address + GPIO_SPEED_OFFSET, ++ mmio_clrbits_32(base + GPIO_SPEED_OFFSET, + ((uint32_t)GPIO_SPEED_MASK << (pin << 1))); +- mmio_setbits_32(bank_address + GPIO_SPEED_OFFSET, speed << (pin << 1)); ++ mmio_setbits_32(base + GPIO_SPEED_OFFSET, speed << (pin << 1)); + +- mmio_clrbits_32(bank_address + GPIO_PUPD_OFFSET, ++ mmio_clrbits_32(base + GPIO_PUPD_OFFSET, + ((uint32_t)GPIO_PULL_MASK << (pin << 1))); +- mmio_setbits_32(bank_address + GPIO_PUPD_OFFSET, pull << (pin << 1)); ++ mmio_setbits_32(base + GPIO_PUPD_OFFSET, pull << (pin << 1)); + + if (pin < GPIO_ALT_LOWER_LIMIT) { +- mmio_clrbits_32(bank_address + GPIO_AFRL_OFFSET, ++ mmio_clrbits_32(base + GPIO_AFRL_OFFSET, + ((uint32_t)GPIO_ALTERNATE_MASK << (pin << 2))); +- mmio_setbits_32(bank_address + GPIO_AFRL_OFFSET, ++ mmio_setbits_32(base + GPIO_AFRL_OFFSET, + alternate << (pin << 2)); + } else { +- mmio_clrbits_32(bank_address + GPIO_AFRH_OFFSET, ++ mmio_clrbits_32(base + GPIO_AFRH_OFFSET, + ((uint32_t)GPIO_ALTERNATE_MASK << + ((pin - GPIO_ALT_LOWER_LIMIT) << 2))); +- mmio_setbits_32(bank_address + GPIO_AFRH_OFFSET, ++ mmio_setbits_32(base + GPIO_AFRH_OFFSET, + alternate << ((pin - GPIO_ALT_LOWER_LIMIT) << + 2)); + } + + VERBOSE("GPIO %u mode set to 0x%x\n", bank, +- mmio_read_32(bank_address + GPIO_MODE_OFFSET)); ++ mmio_read_32(base + GPIO_MODE_OFFSET)); + VERBOSE("GPIO %u speed set to 0x%x\n", bank, +- mmio_read_32(bank_address + GPIO_SPEED_OFFSET)); ++ mmio_read_32(base + GPIO_SPEED_OFFSET)); + VERBOSE("GPIO %u mode pull to 0x%x\n", bank, +- mmio_read_32(bank_address + GPIO_PUPD_OFFSET)); ++ mmio_read_32(base + GPIO_PUPD_OFFSET)); + VERBOSE("GPIO %u mode alternate low to 0x%x\n", bank, +- mmio_read_32(bank_address + GPIO_AFRL_OFFSET)); ++ mmio_read_32(base + GPIO_AFRL_OFFSET)); + VERBOSE("GPIO %u mode alternate high to 0x%x\n", bank, +- mmio_read_32(bank_address + GPIO_AFRH_OFFSET)); ++ mmio_read_32(base + GPIO_AFRH_OFFSET)); ++ ++ stm32mp_clk_disable((unsigned long)clock); ++ ++ if (status == DT_SECURE) { ++ stm32mp_register_secure_gpio(bank, pin); ++ } else { ++ stm32mp_register_non_secure_gpio(bank, pin); ++ } ++} ++ ++void set_gpio_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))); ++ ++ stm32mp_clk_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)); ++ } ++ ++ stm32mp_clk_disable((unsigned long)clock); + } +diff --git a/drivers/st/hash/hash_sec.c b/drivers/st/hash/hash_sec.c +new file mode 100644 +index 0000000..a3c588a +--- /dev/null ++++ b/drivers/st/hash/hash_sec.c +@@ -0,0 +1,369 @@ ++/* ++ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. ++ * ++ * SPDX-License-Identifier: BSD-3-Clause ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define RESET 0 ++ ++#define timer_GetTimeSec() (uint32_t)read_cntpct_el0() ++ ++static void HASH_WriteData(HASH_HandleTypeDef *hHash, const uint8_t *pInBuffer, ++ uint32_t SizeInBytes); ++static void HASH_GetDigest(HASH_HandleTypeDef *hHash, uint8_t *pMsgDigest); ++static uint32_t HASH_WaitBusyClearWithTimeout(HASH_HandleTypeDef *hHash, ++ uint32_t timeout); ++static uint32_t HASH_WaitDcisClearWithTimeout(HASH_HandleTypeDef *hHash, ++ uint32_t timeout); ++ ++/***************************************************************************** ++ * ++ * Function: HASH_SHA256_Init ++ * ++ * Description: Initializes the HASH peripheral ++ * ++ * Parameters: hHash : pointer to a HASH_HandleTypeDef structure that contains ++ * the configuration information for HASH module ++ * ++ * Return: none ++ * ++ *****************************************************************************/ ++Std_ReturnType HASH_SHA256_Init(HASH_HandleTypeDef *hHash) ++{ ++ /* Check the hash handle allocation */ ++ if (!hHash) { ++ return STD_NOT_OK; ++ } ++ ++ hHash->Instance = (HASH_TypeDef *)HASH_BASE; ++ ++ /* Enable HASH1 clock */ ++ stm32mp_clk_enable(HASH1); ++ ++ hHash->Error = HASH_INIT_NOT_DONE; ++ ++ hHash->pHashInBuffPtr = NULL; ++ ++ hHash->pHashOutBuffPtr = NULL; ++ ++ /* Set the data type to 8 bits */ ++ hHash->Instance->CR |= HASH_DATATYPE_8B; ++ ++ /* Select the SHA256 mode and reset the HASH processor core, ++ * so that the HASH will be ready to compute the message digest ++ * of a new message ++ */ ++ hHash->Instance->CR |= HASH_AlgoSelection_SHA256 | HASH_CR_INIT; ++ ++ /* Return function status */ ++ hHash->Error = HASH_INIT_DONE; ++ ++ return STD_OK; ++} ++ ++/***************************************************************************** ++ * ++ * Function: HASH_SHA256_Start ++ * ++ * Description: Initializes the HASH peripheral in SHA256 mode ++ * then processes pInBuffer. ++ * The digest is available in pOutBuffer. ++ * ++ * Parameters: hHash : pointer to a HASH_HandleTypeDef structure that contains ++ * the configuration information for HASH module ++ * ++ * pInBuffer: Pointer to the input buffer (buffer to be hashed). ++ * ++ * sizeInBytes: Length of the input buffer in bytes. ++ * If the Size is not multiple of 64 bytes, ++ * the padding is managed by hardware. ++ * ++ * pOutBuffer: Pointer to the computed digest. ++ * Its size must be 32 bytes. ++ * ++ * Timeout: Specify Timeout value ++ * ++ * Return: none ++ * ++ *****************************************************************************/ ++Std_ReturnType HASH_SHA256_Start(HASH_HandleTypeDef *hHash, ++ const uint8_t *pInBuffer, uint32_t sizeInBytes, ++ uint8_t *pOutBuffer, uint32_t Timeout) ++{ ++ uint32_t timeoutDetected = 0; ++ ++ /* Check the hash handle allocation */ ++ if (!hHash) { ++ return STD_NOT_OK; ++ } ++ ++ hHash->pHashInBuffPtr = pInBuffer; ++ hHash->pHashOutBuffPtr = pOutBuffer; ++ ++ /* Configure the number of valid bits in last word 32 bits ++ * of the bit stream ++ */ ++ __HAL_HASH_SET_NBVALIDBITSINLAST32BITSWORD(sizeInBytes); ++ ++ /* Fill in entire input buffer to be hashed in HASH DIN register ++ * Note : intermediate digest is computed each time 64 bytes are written ++ * in HASH_DIN register ++ */ ++ HASH_WriteData(hHash, pInBuffer, sizeInBytes); ++ ++ /* Start the Final Digest calculation */ ++ hHash->Instance->STR |= HASH_STR_DCAL; ++ ++ /* Check for timeout */ ++ timeoutDetected = HASH_WaitBusyClearWithTimeout(hHash, Timeout); ++ if (timeoutDetected != 0) { ++ hHash->Error = HASH_TIMEOUT; ++ return STD_NOT_OK; ++ } ++ ++ /* Read the message digest in output buffer */ ++ HASH_GetDigest(hHash, pOutBuffer); ++ ++ hHash->Error = HASH_DIGEST_DONE; ++ ++ return STD_OK; ++} ++ ++/***************************************************************************** ++ * ++ * Function: HASH_SHA256_Accumulate ++ * ++ * Description: Initializes the HASH peripheral in SHA256 mode then processes ++ * pInBuffer. ++ * ++ * Parameters: hHash: pointer to a HASH_HandleTypeDef structure that contains ++ * the configuration information for HASH module ++ * ++ * pInBuffer: Pointer to the input buffer (buffer to be hashed). ++ * ++ * sizeInBytes: Length of the input buffer in bytes. ++ * If the Size is not multiple of 64 bytes, the padding is managed ++ * by hardware. ++ * ++ * Return: none ++ * ++ *****************************************************************************/ ++Std_ReturnType HASH_SHA256_Accumulate(HASH_HandleTypeDef *hHash, ++ const uint8_t *pInBuffer, ++ uint32_t sizeInBytes) ++{ ++ /* Check the hash handle allocation */ ++ if (!hHash) { ++ return STD_NOT_OK; ++ } ++ ++ hHash->pHashInBuffPtr = pInBuffer; ++ ++ /* Configure the number of valid bits in last 32 bits word ++ * of the message ++ */ ++ __HAL_HASH_SET_NBVALIDBITSINLAST32BITSWORD(sizeInBytes); ++ ++ /* Write input buffer in data register */ ++ HASH_WriteData(hHash, pInBuffer, sizeInBytes); ++ ++ /* Return function status */ ++ hHash->Error = HASH_ACCU_DONE; ++ ++ return STD_OK; ++} ++ ++/***************************************************************************** ++ * ++ * Function: HASH_SHA256_Finish ++ * ++ * Description: Returns the computed digest in SHA256. ++ * ++ * Parameters: hHash: pointer to a HASH_HandleTypeDef structure that contains ++ * the configuration information for HASH module ++ * ++ * pOutBuffer: Pointer to the computed digest. ++ * Its size must be 32 bytes. ++ * ++ * Timeout: Timeout value ++ * ++ * Return: none ++ * ++ *****************************************************************************/ ++Std_ReturnType HASH_SHA256_Finish(HASH_HandleTypeDef *hHash, ++ uint8_t *pOutBuffer, uint32_t Timeout) ++{ ++ uint32_t timeoutDetected = 0; ++ ++ /* Check the hash handle allocation */ ++ if (!hHash) { ++ return STD_NOT_OK; ++ } ++ ++ hHash->pHashOutBuffPtr = pOutBuffer; ++ ++ /* Check for the Timeout */ ++ timeoutDetected = HASH_WaitDcisClearWithTimeout(hHash, Timeout); ++ if (timeoutDetected != 0) { ++ hHash->Error = HASH_TIMEOUT; ++ return STD_NOT_OK; ++ } ++ ++ /* Read the message digest */ ++ HASH_GetDigest(hHash, pOutBuffer); ++ ++ /* Return function status */ ++ hHash->Error = HASH_FINISHED; ++ ++ return STD_OK; ++} ++ ++/* Static functions ----------------------------------------------------------*/ ++ ++/** ++ * @brief Writes the input buffer in HASH_DIN register. ++ * @param pInBuffer: Pointer to input buffer ++ * @param SizeInBytes : The size of input buffer (in bytes) ++ * @retval None ++ */ ++static void HASH_WriteData(HASH_HandleTypeDef *hHash, const uint8_t *pInBuffer, ++ uint32_t SizeInBytes) ++{ ++ uint32_t *pInWord32 = (uint32_t *)pInBuffer; ++ uint32_t nbBlocks = (SizeInBytes / HASH_BLOCK_SIZE_NB_BYTES); ++ uint32_t remainingBytesInLastBlock = (SizeInBytes % ++ HASH_BLOCK_SIZE_NB_BYTES); ++ uint32_t remainingBytesInLastWord = (SizeInBytes % 4); ++ uint32_t idxBlock = 0; ++ uint32_t idxWord32; ++ ++ /* For all blocks */ ++ for (idxBlock = 0; idxBlock < nbBlocks; idxBlock++) { ++ for (idxWord32 = 0; idxWord32 < (HASH_BLOCK_SIZE_NB_BYTES / 4); ++ idxWord32++) { ++ hHash->Instance->DIN = *pInWord32; ++ pInWord32++; ++ } ++ ++ /* Wait until end of computation of intermediate digest */ ++ while ((hHash->Instance->SR & HASH_SR_DINIS) == HASH_SR_DINIS) { ++ ; ++ } ++ } ++ ++ if (remainingBytesInLastBlock != 0) { ++ uint32_t nbWords32Remaining = (remainingBytesInLastBlock / 4); ++ ++ for (idxWord32 = 0; idxWord32 < nbWords32Remaining; ++ idxWord32++) { ++ hHash->Instance->DIN = *pInWord32; ++ pInWord32++; ++ } ++ } ++ ++ if (remainingBytesInLastWord != 0) { ++ hHash->Instance->DIN = *pInWord32; ++ } ++} ++ ++#ifndef __CC_ARM ++/* __rev is a builtin command in ARM compiler ++ * it needs to be remapped on __builtin_bswap32 for GCC ++ */ ++#define __rev __builtin_bswap32 ++#endif ++ ++/** ++ * @brief Provides the message digest result. ++ * @param hHash: Hash handle ++ * @param pMsgDigest: Pointer to the message digest ++ * @retval None ++ */ ++static void HASH_GetDigest(HASH_HandleTypeDef *hHash, uint8_t *pMsgDigest) ++{ ++ uintptr_t msgdigest = (uintptr_t)pMsgDigest; ++ ++ /* Read the message digest */ ++ *(uintptr_t *)(msgdigest) = __rev(hHash->Instance->HR[0]); ++ msgdigest += 4; ++ *(uintptr_t *)(msgdigest) = __rev(hHash->Instance->HR[1]); ++ msgdigest += 4; ++ *(uintptr_t *)(msgdigest) = __rev(hHash->Instance->HR[2]); ++ msgdigest += 4; ++ *(uintptr_t *)(msgdigest) = __rev(hHash->Instance->HR[3]); ++ msgdigest += 4; ++ *(uintptr_t *)(msgdigest) = __rev(hHash->Instance->HR[4]); ++ msgdigest += 4; ++ *(uintptr_t *)(msgdigest) = __rev(HASH_DIGEST->HR[5]); ++ msgdigest += 4; ++ *(uintptr_t *)(msgdigest) = __rev(HASH_DIGEST->HR[6]); ++ msgdigest += 4; ++ *(uintptr_t *)(msgdigest) = __rev(HASH_DIGEST->HR[7]); ++} ++ ++/** ++ * @brief This function waits until bit HASH_SR_BUSY is 1b0' before a timeout. ++ * @param [in] hHash : hash handle ++ * @param [in] timeout : timeout value ++ * ++ * @retval timeoutDetected : value 0x1 if timeout was detected while ++ * waiting for bit BUSY to be cleared. ++ ****************************************************************************** ++ */ ++ ++static uint32_t HASH_WaitBusyClearWithTimeout(HASH_HandleTypeDef *hHash, ++ uint32_t timeout) ++{ ++ uint32_t timerValInit = 0; ++ uint32_t timeoutDetected = 0; ++ ++ /* Get timer current value at start of loop */ ++ timerValInit = timer_GetTimeSec(); ++ ++ while (((hHash->Instance->SR & HASH_SR_BUSY) == HASH_SR_BUSY) && ++ (timeoutDetected == 0)) { ++ /* Sense timeout occurrence */ ++ if ((timer_GetTimeSec() - timerValInit) >= timeout) { ++ timeoutDetected = 1; ++ } ++ } ++ ++ return timeoutDetected; ++} ++ ++/** ++ * @brief This function waits until bit HASH_SR_DCIS is 1b0' before a timeout. ++ * @param [in] hHash : hash handle ++ * @param [in] timeout : timeout value ++ * ++ * @retval timeoutDetected : value 0x1 if timeout was detected while ++ * waiting for bit DCIS to be cleared. ++ ****************************************************************************** ++ */ ++ ++static uint32_t HASH_WaitDcisClearWithTimeout(HASH_HandleTypeDef *hHash, ++ uint32_t timeout) ++{ ++ uint32_t timerValInit = 0; ++ uint32_t timeoutDetected = 0; ++ ++ /* Get timer current value at start of loop */ ++ timerValInit = timer_GetTimeSec(); ++ ++ while ((HAL_IS_BIT_CLR(hHash->Instance->SR, HASH_SR_DCIS)) && ++ (timeoutDetected == 0)) { ++ /* Sense timeout occurrence */ ++ if ((timer_GetTimeSec() - timerValInit) >= timeout) { ++ timeoutDetected = 1; ++ } ++ } ++ ++ return timeoutDetected; ++} +diff --git a/drivers/st/i2c/stm32_i2c.c b/drivers/st/i2c/stm32_i2c.c +new file mode 100644 +index 0000000..694a76a +--- /dev/null ++++ b/drivers/st/i2c/stm32_i2c.c +@@ -0,0 +1,1371 @@ ++/* ++ * Copyright (c) 2016-2018, STMicroelectronics - All Rights Reserved ++ * ++ * SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause ++ */ ++ ++#include ++#include ++#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 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; ++} ++ ++/* ++ * @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; ++ int sdadel_min; ++ int sdadel_max; ++ uint32_t sdadel_min_u; ++ uint32_t sdadel_max_u; ++ uint32_t scldel_min; ++ int s = -1; ++ struct i2c_timing_s solutions[I2C_TIMINGR_PRESC_MAX]; ++ ++ switch (mode) { ++ case I2C_SPEED_STANDARD ... I2C_SPEED_FAST_PLUS: ++ break; ++ default: ++ ERROR("I2C speed out of bound {%d/%d}\n", ++ mode, I2C_SPEED_FAST_PLUS); ++ return -EINVAL; ++ } ++ ++ 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)) { ++ ERROR(" I2C timings out of bound Rise{%d>%d}/Fall{%d>%d}\n", ++ init->rise_time, i2c_specs[mode].rise_max, ++ init->fall_time, i2c_specs[mode].fall_max); ++ return -EINVAL; ++ } ++ ++ if (init->digital_filter_coef > STM32_I2C_DIGITAL_FILTER_MAX) { ++ ERROR("DNF out of bound %d/%d\n", ++ init->digital_filter_coef, STM32_I2C_DIGITAL_FILTER_MAX); ++ return -EINVAL; ++ } ++ ++ /* 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 - ++ af_delay_min - ((init->digital_filter_coef + 3) * i2cclk); ++ ++ sdadel_max = i2c_specs[mode].vddat_max - init->rise_time - ++ af_delay_max - ((init->digital_filter_coef + 4) * i2cclk); ++ ++ scldel_min = init->rise_time + i2c_specs[mode].sudat_min; ++ ++ if (sdadel_min < 0) { ++ sdadel_min_u = 0; ++ } else { ++ sdadel_min_u = (uint32_t)sdadel_min; ++ } ++ ++ if (sdadel_max < 0) { ++ sdadel_max_u = 0; ++ } else { ++ sdadel_max_u = (uint32_t)sdadel_max; ++ } ++ ++ VERBOSE("I2C SDADEL(min/max): %u/%u, SCLDEL(Min): %u\n", ++ sdadel_min_u, sdadel_max_u, scldel_min); ++ ++ zeromem(&solutions, 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_u) && ++ (sdadel <= sdadel_max_u) && ++ (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) { ++ ERROR(" I2C no Prescaler solution\n"); ++ return -EPERM; ++ } ++ ++ 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) { ++ ERROR(" I2C no solution at all\n"); ++ return -EPERM; ++ } ++ ++ /* 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); ++ ++ VERBOSE("I2C TIMINGR (PRESC/SCLDEL/SDADEL): %i/%i/%i\n", ++ s, solutions[s].scldel, solutions[s].sdadel); ++ VERBOSE("I2C TIMINGR (SCLH/SCLL): %i/%i\n", ++ solutions[s].sclh, solutions[s].scll); ++ VERBOSE("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 = stm32mp_clk_get_rate(hi2c->clock); ++ if (clock_src == 0U) { ++ ERROR("I2C clock rate is 0\n"); ++ return -EINVAL; ++ } ++ ++ do { ++ rc = i2c_compute_timing(init, clock_src, timing); ++ if (rc != 0) { ++ ERROR("Failed to compute I2C timings\n"); ++ if (init->speed_mode > I2C_SPEED_STANDARD) { ++ init->speed_mode--; ++ WARN("Downgrade I2C speed to %uHz)\n", ++ i2c_specs[init->speed_mode].rate); ++ } else { ++ break; ++ } ++ } ++ } while (rc != 0); ++ ++ if (rc != 0) { ++ ERROR("Impossible to compute I2C timings\n"); ++ return rc; ++ } ++ ++ VERBOSE("I2C Speed Mode(%i), Freq(%i), Clk Source(%i)\n", ++ init->speed_mode, i2c_specs[init->speed_mode].rate, clock_src); ++ VERBOSE("I2C Rise(%i) and Fall(%i) Time\n", ++ init->rise_time, init->fall_time); ++ VERBOSE("I2C Analog Filter(%s), DNF(%i)\n", ++ (init->analog_filter ? "On" : "Off"), ++ init->digital_filter_coef); ++ ++ 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) ++{ ++ if ((hi2c->i2c_state != I2C_STATE_READY) || (hi2c->lock != 0U)) { ++ return -EBUSY; ++ } ++ ++ hi2c->lock = 1; ++ ++ hi2c->i2c_state = I2C_STATE_BUSY; ++ ++ /* Disable the selected I2C peripheral */ ++ mmio_clrbits_32(hi2c->i2c_base_addr + I2C_CR1, I2C_CR1_PE); ++ ++ /* Reset I2Cx ANOFF bit */ ++ mmio_clrbits_32(hi2c->i2c_base_addr + I2C_CR1, I2C_CR1_ANFOFF); ++ ++ /* Set analog filter bit*/ ++ mmio_setbits_32(hi2c->i2c_base_addr + I2C_CR1, analog_filter); ++ ++ /* Enable the selected I2C peripheral */ ++ mmio_setbits_32(hi2c->i2c_base_addr + 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) ++{ ++ const fdt32_t *cuint; ++ ++ cuint = fdt_getprop(fdt, node, "i2c-scl-rising-time-ns", NULL); ++ if (cuint == NULL) { ++ init->rise_time = STM32_I2C_RISE_TIME_DEFAULT; ++ } else { ++ init->rise_time = fdt32_to_cpu(*cuint); ++ } ++ ++ cuint = fdt_getprop(fdt, node, "i2c-scl-falling-time-ns", NULL); ++ if (cuint == NULL) { ++ init->fall_time = STM32_I2C_FALL_TIME_DEFAULT; ++ } else { ++ init->fall_time = fdt32_to_cpu(*cuint); ++ } ++ ++ cuint = fdt_getprop(fdt, node, "clock-frequency", NULL); ++ if (cuint == NULL) { ++ init->speed_mode = STM32_I2C_SPEED_DEFAULT; ++ } else { ++ switch (fdt32_to_cpu(*cuint)) { ++ case STANDARD_RATE: ++ init->speed_mode = I2C_SPEED_STANDARD; ++ break; ++ case FAST_RATE: ++ init->speed_mode = I2C_SPEED_FAST; ++ break; ++ case FAST_PLUS_RATE: ++ init->speed_mode = I2C_SPEED_FAST_PLUS; ++ break; ++ default: ++ init->speed_mode = STM32_I2C_SPEED_DEFAULT; ++ break; ++ } ++ } ++ ++ return dt_set_pinctrl_config(node); ++} ++ ++/* ++ * @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: 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; ++ ++ if (hi2c == NULL) { ++ return -ENOENT; ++ } ++ ++ 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; ++ } ++ ++ stm32mp_clk_enable(hi2c->clock); ++ ++ /* Disable the selected I2C peripheral */ ++ mmio_clrbits_32(hi2c->i2c_base_addr + I2C_CR1, I2C_CR1_PE); ++ ++ /* Configure I2Cx: Frequency range */ ++ mmio_write_32(hi2c->i2c_base_addr + I2C_TIMINGR, ++ timing & TIMINGR_CLEAR_MASK); ++ ++ /* Disable Own Address1 before set the Own Address1 configuration */ ++ mmio_clrbits_32(hi2c->i2c_base_addr + 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(hi2c->i2c_base_addr + I2C_OAR1, ++ I2C_OAR1_OA1EN | init_data->own_address1); ++ } else { /* I2C_ADDRESSINGMODE_10BIT */ ++ mmio_write_32(hi2c->i2c_base_addr + I2C_OAR1, ++ I2C_OAR1_OA1EN | I2C_OAR1_OA1MODE | ++ init_data->own_address1); ++ } ++ ++ mmio_write_32(hi2c->i2c_base_addr + I2C_CR2, 0); ++ ++ /* Configure I2Cx: Addressing Master mode */ ++ if (init_data->addressing_mode == I2C_ADDRESSINGMODE_10BIT) { ++ mmio_setbits_32(hi2c->i2c_base_addr + I2C_CR2, I2C_CR2_ADD10); ++ } ++ ++ /* ++ * Enable the AUTOEND by default, and enable NACK ++ * (should be disabled only during Slave process). ++ */ ++ mmio_setbits_32(hi2c->i2c_base_addr + I2C_CR2, ++ I2C_CR2_AUTOEND | I2C_CR2_NACK); ++ ++ /* Disable Own Address2 before set the Own Address2 configuration */ ++ mmio_clrbits_32(hi2c->i2c_base_addr + I2C_OAR2, I2C_DUALADDRESS_ENABLE); ++ ++ /* Configure I2Cx: Dual mode and Own Address2 */ ++ mmio_write_32(hi2c->i2c_base_addr + 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(hi2c->i2c_base_addr + I2C_CR1, ++ init_data->general_call_mode | ++ init_data->no_stretch_mode); ++ ++ /* Enable the selected I2C peripheral */ ++ mmio_setbits_32(hi2c->i2c_base_addr + 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) { ++ ERROR("Cannot initialize I2C analog filter (%d)\n", rc); ++ stm32mp_clk_disable(hi2c->clock); ++ return rc; ++ } ++ ++ stm32mp_clk_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; ++ uint64_t tick_to = ms2tick(timeout_ms); ++ int rc = -EIO; ++ uint8_t *p_buff = p_data; ++ uint32_t xfer_size; ++ uint32_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 -EBUSY; ++ } ++ ++ if ((p_data == NULL) || (size == 0U)) { ++ return -EINVAL; ++ } ++ ++ stm32mp_clk_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(hi2c->i2c_base_addr + 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(hi2c->i2c_base_addr + I2C_ICR, I2C_FLAG_STOPF); ++ ++ mmio_clrbits_32(hi2c->i2c_base_addr + I2C_CR2, I2C_RESET_CR2); ++ ++ hi2c->i2c_state = I2C_STATE_READY; ++ hi2c->i2c_mode = I2C_MODE_NONE; ++ ++ rc = 0; ++ ++bail: ++ hi2c->lock = 0; ++ stm32mp_clk_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); ++} ++ ++/* ++ * @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) ++{ ++ uint64_t tick_start; ++ uint64_t tick_to = ms2tick(timeout_ms); ++ int rc = -EIO; ++ uint8_t *p_buff = p_data; ++ uint32_t xfer_count = size; ++ uint32_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 -EBUSY; ++ } ++ ++ if ((p_data == NULL) || (size == 0U)) { ++ return -EINVAL; ++ } ++ ++ stm32mp_clk_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(hi2c->i2c_base_addr + 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(hi2c->i2c_base_addr + I2C_ICR, I2C_FLAG_STOPF); ++ ++ mmio_clrbits_32(hi2c->i2c_base_addr + I2C_CR2, I2C_RESET_CR2); ++ ++ hi2c->i2c_state = I2C_STATE_READY; ++ hi2c->i2c_mode = I2C_MODE_NONE; ++ ++ rc = 0; ++ ++bail: ++ hi2c->lock = 0; ++ stm32mp_clk_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) ++{ ++ 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; ++ } ++ ++ stm32mp_clk_enable(hi2c->clock); ++ ++ hi2c->lock = 1; ++ hi2c->i2c_mode = I2C_MODE_NONE; ++ ++ if ((mmio_read_32(hi2c->i2c_base_addr + 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; ++ ++ /* Generate Start */ ++ if ((mmio_read_32(hi2c->i2c_base_addr + I2C_OAR1) & ++ I2C_OAR1_OA1MODE) == 0) { ++ mmio_write_32(hi2c->i2c_base_addr + I2C_CR2, ++ (((uint32_t)dev_addr & I2C_CR2_SADD) | ++ I2C_CR2_START | I2C_CR2_AUTOEND) & ++ ~I2C_CR2_RD_WRN); ++ } else { ++ mmio_write_32(hi2c->i2c_base_addr + 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 ((mmio_read_32(hi2c->i2c_base_addr + I2C_ISR) & ++ (I2C_FLAG_STOPF | I2C_FLAG_AF)) != 0U) { ++ break; ++ } ++ ++ if (timeout_elapsed(tick_start, tick_to)) { ++ notif_i2c_timeout(hi2c); ++ goto bail; ++ } ++ } while (true); ++ ++ if ((mmio_read_32(hi2c->i2c_base_addr + 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(hi2c->i2c_base_addr + 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(hi2c->i2c_base_addr + I2C_ICR, I2C_FLAG_AF); ++ ++ mmio_write_32(hi2c->i2c_base_addr + I2C_ICR, I2C_FLAG_STOPF); ++ ++ if (i2c_trials == trials) { ++ mmio_setbits_32(hi2c->i2c_base_addr + I2C_CR2, ++ I2C_CR2_STOP); ++ ++ if (i2c_wait_flag(hi2c, I2C_FLAG_STOPF, 0, tick_to, ++ tick_start) != 0) { ++ goto bail; ++ } ++ ++ mmio_write_32(hi2c->i2c_base_addr + I2C_ICR, ++ I2C_FLAG_STOPF); ++ } ++ ++ i2c_trials++; ++ } while (i2c_trials < trials); ++ ++ notif_i2c_timeout(hi2c); ++ ++bail: ++ hi2c->lock = 0; ++ stm32mp_clk_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) ++{ ++ 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 -EIO; ++ } ++ ++ if (mem_add_size == I2C_MEMADD_SIZE_8BIT) { ++ /* Send Memory Address */ ++ mmio_write_8(hi2c->i2c_base_addr + I2C_TXDR, ++ (uint8_t)(mem_addr & 0x00FFU)); ++ } else { ++ /* Send MSB of Memory Address */ ++ mmio_write_8(hi2c->i2c_base_addr + I2C_TXDR, ++ (uint8_t)((mem_addr & 0xFF00U) >> 8)); ++ ++ if (i2c_wait_txis(hi2c, tick_to, tick_start) != 0) { ++ return -EIO; ++ } ++ ++ /* Send LSB of Memory Address */ ++ mmio_write_8(hi2c->i2c_base_addr + I2C_TXDR, ++ (uint8_t)(mem_addr & 0x00FFU)); ++ } ++ ++ if (i2c_wait_flag(hi2c, I2C_FLAG_TCR, 0, tick_to, tick_start) != 0) { ++ return -EIO; ++ } ++ ++ 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) ++{ ++ 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 -EIO; ++ } ++ ++ if (mem_add_size == I2C_MEMADD_SIZE_8BIT) { ++ /* Send Memory Address */ ++ mmio_write_8(hi2c->i2c_base_addr + I2C_TXDR, ++ (uint8_t)(mem_addr & 0x00FFU)); ++ } else { ++ /* Send MSB of Memory Address */ ++ mmio_write_8(hi2c->i2c_base_addr + I2C_TXDR, ++ (uint8_t)((mem_addr & 0xFF00U) >> 8)); ++ ++ if (i2c_wait_txis(hi2c, tick_to, tick_start) != 0) { ++ return -EIO; ++ } ++ ++ /* Send LSB of Memory Address */ ++ mmio_write_8(hi2c->i2c_base_addr + I2C_TXDR, ++ (uint8_t)(mem_addr & 0x00FFU)); ++ } ++ ++ if (i2c_wait_flag(hi2c, I2C_FLAG_TC, 0, tick_to, tick_start) != 0) { ++ return -EIO; ++ } ++ ++ 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) ++{ ++ /* ++ * If a pending TXIS flag is set, ++ * write a dummy data in TXDR to clear it. ++ */ ++ if ((mmio_read_32(hi2c->i2c_base_addr + I2C_ISR) & I2C_FLAG_TXIS) != ++ 0U) { ++ mmio_write_32(hi2c->i2c_base_addr + I2C_TXDR, 0); ++ } ++ ++ /* Flush TX register if not empty */ ++ if ((mmio_read_32(hi2c->i2c_base_addr + I2C_ISR) & I2C_FLAG_TXE) == ++ 0U) { ++ mmio_setbits_32(hi2c->i2c_base_addr + 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 = mmio_read_32(hi2c->i2c_base_addr + I2C_ISR); ++ ++ if (!!(isr & flag) != !!awaited_value) { ++ return 0; ++ } ++ ++ if (timeout_elapsed(tick_start, tick_to)) { ++ notif_i2c_timeout(hi2c); ++ hi2c->lock = 0; ++ ++ return -EIO; ++ } ++ } ++} ++ ++/* ++ * @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 ((mmio_read_32(hi2c->i2c_base_addr + I2C_ISR) & ++ I2C_FLAG_TXIS) == 0U) { ++ if (i2c_ack_failed(hi2c, tick_to, tick_start) != 0) { ++ return -EIO; ++ } ++ ++ if (timeout_elapsed(tick_start, tick_to)) { ++ notif_i2c_timeout(hi2c); ++ hi2c->lock = 0; ++ ++ return -EIO; ++ } ++ } ++ ++ 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 ((mmio_read_32(hi2c->i2c_base_addr + I2C_ISR) & ++ I2C_FLAG_STOPF) == 0U) { ++ if (i2c_ack_failed(hi2c, tick_to, tick_start) != 0) { ++ return -EIO; ++ } ++ ++ if (timeout_elapsed(tick_start, tick_to)) { ++ notif_i2c_timeout(hi2c); ++ hi2c->lock = 0; ++ ++ return -EIO; ++ } ++ } ++ ++ 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) ++{ ++ if ((mmio_read_32(hi2c->i2c_base_addr + I2C_ISR) & I2C_FLAG_AF) == 0U) { ++ return 0; ++ } ++ ++ /* ++ * Wait until STOP Flag is reset. ++ * AutoEnd should be initiate after AF. ++ */ ++ while ((mmio_read_32(hi2c->i2c_base_addr + I2C_ISR) & ++ I2C_FLAG_STOPF) == 0U) { ++ if (timeout_elapsed(tick_start, tick_to)) { ++ notif_i2c_timeout(hi2c); ++ hi2c->lock = 0; ++ ++ return -EIO; ++ } ++ } ++ ++ mmio_write_32(hi2c->i2c_base_addr + I2C_ICR, I2C_FLAG_AF); ++ ++ mmio_write_32(hi2c->i2c_base_addr + I2C_ICR, I2C_FLAG_STOPF); ++ ++ i2c_flush_txdr(hi2c); ++ ++ mmio_clrbits_32(hi2c->i2c_base_addr + 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 -EIO; ++} ++ ++/* ++ * @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(hi2c->i2c_base_addr + I2C_CR2, clr_value, set_value); ++} +diff --git a/drivers/st/io/io_mmc.c b/drivers/st/io/io_mmc.c +new file mode 100644 +index 0000000..bc9a91a +--- /dev/null ++++ b/drivers/st/io/io_mmc.c +@@ -0,0 +1,134 @@ ++/* ++ * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved. ++ * ++ * SPDX-License-Identifier: BSD-3-Clause ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* SDMMC device functions */ ++static int mmc_dev_open(const uintptr_t init_params, io_dev_info_t **dev_info); ++static int mmc_block_open(io_dev_info_t *dev_info, const uintptr_t spec, ++ io_entity_t *entity); ++static int mmc_dev_init(io_dev_info_t *dev_info, const uintptr_t init_params); ++static int mmc_block_seek(io_entity_t *entity, int mode, ++ signed long long offset); ++static int mmc_block_read(io_entity_t *entity, uintptr_t buffer, size_t length, ++ size_t *length_read); ++static int mmc_block_close(io_entity_t *entity); ++static int mmc_dev_close(io_dev_info_t *dev_info); ++static io_type_t device_type_mmc(void); ++ ++static int64_t seek_offset; ++ ++static const io_dev_connector_t mmc_dev_connector = { ++ .dev_open = mmc_dev_open ++}; ++ ++static const io_dev_funcs_t mmc_dev_funcs = { ++ .type = device_type_mmc, ++ .open = mmc_block_open, ++ .seek = mmc_block_seek, ++ .size = NULL, ++ .read = mmc_block_read, ++ .write = NULL, ++ .close = mmc_block_close, ++ .dev_init = mmc_dev_init, ++ .dev_close = mmc_dev_close, ++}; ++ ++static const io_dev_info_t mmc_dev_info = { ++ .funcs = &mmc_dev_funcs, ++ .info = 0, ++}; ++ ++/* Identify the device type as mmc device */ ++static io_type_t device_type_mmc(void) ++{ ++ return IO_TYPE_MMC; ++} ++ ++/* Open a connection to the mmc device */ ++static int mmc_dev_open(const uintptr_t init_params, io_dev_info_t **dev_info) ++{ ++ assert(dev_info != NULL); ++ *dev_info = (io_dev_info_t *)&mmc_dev_info; ++ ++ return 0; ++} ++ ++static int mmc_dev_init(io_dev_info_t *dev_info, const uintptr_t init_params) ++{ ++ return 0; ++} ++ ++/* Close a connection to the mmc device */ ++static int mmc_dev_close(io_dev_info_t *dev_info) ++{ ++ return 0; ++} ++ ++/* Open a file on the mmc device */ ++static int mmc_block_open(io_dev_info_t *dev_info, const uintptr_t spec, ++ io_entity_t *entity) ++{ ++ seek_offset = 0; ++ return 0; ++} ++ ++/* Seek to a particular file offset on the mmc device */ ++static int mmc_block_seek(io_entity_t *entity, int mode, ++ signed long long offset) ++{ ++ seek_offset = offset; ++ return 0; ++} ++ ++/* Read data from a file on the mmc device */ ++static int mmc_block_read(io_entity_t *entity, uintptr_t buffer, ++ size_t length, size_t *length_read) ++{ ++ uint8_t retries = 3U; ++ ++ do { ++ retries--; ++ if (retries == 0U) { ++ return -EIO; ++ } ++ ++ *length_read = mmc_read_blocks(seek_offset / MMC_BLOCK_SIZE, ++ buffer, length); ++ ++ } while (*length_read != length); ++ ++ return 0; ++} ++ ++/* Close a file on the mmc device */ ++static int mmc_block_close(io_entity_t *entity) ++{ ++ return 0; ++} ++ ++/* Register the mmc driver with the IO abstraction */ ++int register_io_dev_mmc(const io_dev_connector_t **dev_con) ++{ ++ int result; ++ ++ assert(dev_con != NULL); ++ ++ result = io_register_device(&mmc_dev_info); ++ if (result == 0) { ++ *dev_con = &mmc_dev_connector; ++ } ++ ++ return result; ++} +diff --git a/drivers/st/io/io_programmer_st_usb.c b/drivers/st/io/io_programmer_st_usb.c +new file mode 100644 +index 0000000..a0871f6 +--- /dev/null ++++ b/drivers/st/io/io_programmer_st_usb.c +@@ -0,0 +1,379 @@ ++/* ++ * Copyright (c) 2017, STMicroelectronics - All Rights Reserved ++ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. ++ * ++ * SPDX-License-Identifier: BSD-3-Clause ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static uint8_t first_usb_buffer[USB_DFU_MAX_XFER_SIZE + 1] __aligned(4); ++static usb_dfu_media_t usb_dfu_fops; ++static uint8_t checksum_is_wrong; ++static uint8_t usb_status; ++ ++#define USB_STATE_READY 0 ++#define USB_STATE_WRITTEN 1 ++ ++/* usb device functions */ ++static int usb_dev_open(const uintptr_t init_params, ++ io_dev_info_t **dev_info); ++static int usb_block_open(io_dev_info_t *dev_info, const uintptr_t spec, ++ io_entity_t *entity); ++static int usb_dev_init(io_dev_info_t *dev_info, ++ const uintptr_t init_params); ++static int usb_partition_size(io_entity_t *entity, size_t *length); ++static int usb_block_seek(io_entity_t *entity, int mode, ++ signed long long offset); ++static int usb_block_read(io_entity_t *entity, uintptr_t buffer, ++ size_t length, size_t *length_read); ++static int usb_block_close(io_entity_t *entity); ++static int usb_dev_close(io_dev_info_t *dev_info); ++static io_type_t device_type_usb(void); ++ ++static const io_dev_connector_t usb_dev_connector = { ++ .dev_open = usb_dev_open ++}; ++ ++static const io_dev_funcs_t usb_dev_funcs = { ++ .type = device_type_usb, ++ .open = usb_block_open, ++ .seek = usb_block_seek, ++ .size = usb_partition_size, ++ .read = usb_block_read, ++ .write = NULL, ++ .close = usb_block_close, ++ .dev_init = usb_dev_init, ++ .dev_close = usb_dev_close, ++}; ++ ++static io_dev_info_t usb_dev_info = { ++ .funcs = &usb_dev_funcs, ++ .info = (uintptr_t)0, ++}; ++ ++/* Identify the device type as usb */ ++static io_type_t device_type_usb(void) ++{ ++ return IO_TYPE_USB; ++} ++ ++/* Callback to notify that data has been written in memory ++ * ( set by USBD_DFU_SetDownloadAddr) ++ */ ++static uint16_t usb_callback_write_done(uint32_t *written_in, uint32_t len) ++{ ++ VERBOSE("%s Written_in 0x%lx len %i\n", __func__, (uintptr_t)written_in, ++ len); ++ ++ /* Update SRAM state machine when block writing is finished */ ++ usb_status = USB_STATE_WRITTEN; ++ ++ return 0; ++} ++ ++/* Call back to notify that a read memory is requested */ ++static uint8_t *usb_callback_read(uint8_t *src, uint8_t *dest, uint32_t len) ++{ ++ ERROR("%s read is not supported src 0x%lx dest 0x%lx len %i\n", ++ __func__, (uintptr_t)src, (uintptr_t)dest, len); ++ ++ /* Return a valid address to avoid HardFault */ ++ return (uint8_t *)(dest); ++} ++ ++/* Get the status to know if written operation has been checked */ ++static uint16_t usb_callback_get_status(void) ++{ ++ uint16_t status; ++ ++ /* According to SRAM state machine */ ++ switch (usb_status) { ++ case USB_STATE_WRITTEN: ++ /* The SRAM bloc writing has been done, change state machine ++ * to set SRAM in SRAM_STATE_READY ++ */ ++ usb_status = USB_STATE_READY; ++ ++ /* Notice caller that SRAM block writing is finished */ ++ status = DFU_MEDIA_STATE_WRITTEN; ++ ++ /* Checks checksum calculation result */ ++ if (checksum_is_wrong == 1) { ++ status = DFU_MEDIA_STATE_ERROR; ++ checksum_is_wrong = 0; ++ } ++ break; ++ ++ case USB_STATE_READY: ++ /* Notice caller that SRAM is ready to be written */ ++ status = DFU_MEDIA_STATE_READY; ++ break; ++ ++ default: ++ status = DFU_MEDIA_STATE_ERROR; ++ ERROR("USB unknown state\n"); ++ break; ++ } ++ VERBOSE("usb_callback_GetStatus status : %i\n", status); ++ return status; ++} ++ ++/* Open a connection to the usb device */ ++static int usb_dev_open(const uintptr_t init_params, ++ io_dev_info_t **dev_info) ++{ ++ usb_handle_t *usb_core_handle = (usb_handle_t *)init_params; ++ ++ assert(dev_info); ++ *dev_info = &usb_dev_info; ++ ++ usb_dfu_fops.write_done = usb_callback_write_done; ++ usb_dfu_fops.read = usb_callback_read; ++ usb_dfu_fops.get_status = usb_callback_get_status; ++ usb_status = USB_STATE_READY; ++ checksum_is_wrong = 0; ++ ++ usb_core_handle->user_data = &usb_dfu_fops; ++ ++ usb_dev_info.info = (uintptr_t)usb_core_handle; ++ ++ return 0; ++} ++ ++static int usb_dev_init(io_dev_info_t *dev_info, const uintptr_t init_params) ++{ ++ return 0; ++} ++ ++/* Close a connection to the usb device */ ++static int usb_dev_close(io_dev_info_t *dev_info) ++{ ++ return 0; ++} ++ ++/* Open a file on the usb device */ ++static int usb_block_open(io_dev_info_t *dev_info, const uintptr_t spec, ++ io_entity_t *entity) ++{ ++ int result; ++ uint32_t length = 0; ++ boot_api_image_header_t *header = ++ (boot_api_image_header_t *)first_usb_buffer; ++ ++ const struct stm32image_part_info *partition_spec = ++ (struct stm32image_part_info *)spec; ++ ++ /* Use PHASE_FSBL1 like init value*/ ++ if (current_phase.phase_id == PHASE_FSBL1) { ++ assert(partition_spec); ++ assert(entity); ++ ++ current_phase.current_packet = 0; ++ ++ if (!strcmp(partition_spec->name, BL33_IMAGE_NAME)) { ++ /* read flash layout first for U-boot */ ++ current_phase.phase_id = PHASE_FLASHLAYOUT; ++ current_phase.keep_header = 1; ++ ++ usb_dfu_set_phase_id(PHASE_FLASHLAYOUT); ++ usb_dfu_set_download_addr((uintptr_t) ++ &first_usb_buffer[0]); ++ ++ header->magic = 0; ++ ++ while (((header->magic != ++ BOOT_API_IMAGE_HEADER_MAGIC_NB) || ++ usb_dfu_get_current_req() == DFU_DNLOAD)) { ++ usb_core_handle_it((usb_handle_t *) ++ usb_dev_info.info); ++ } ++ result = usb_block_read(NULL, ++ FLASHLAYOUT_BASE, ++ 0, ++ &length); ++ if (result != 0) { ++ return result; ++ } ++ ++ flush_dcache_range((unsigned long)FLASHLAYOUT_BASE, ++ header->image_length + ++ sizeof(boot_api_image_header_t)); ++ ++ current_phase.current_packet = 0; ++ current_phase.keep_header = 0; ++ current_phase.phase_id = PHASE_SSBL; ++ current_phase.max_size = dt_get_ddr_size(); ++ } ++ entity->info = (uintptr_t)¤t_phase; ++ result = 0; ++ } else { ++ WARN("A UART device is already active. Close first.\n"); ++ result = -EIO; ++ } ++ ++ return result; ++} ++ ++/* Return the size of a partition */ ++static int usb_partition_size(io_entity_t *entity, size_t *length) ++{ ++ boot_api_image_header_t *header = ++ (boot_api_image_header_t *)first_usb_buffer; ++ int result = 0; ++ ++ usb_dfu_set_phase_id(current_phase.phase_id); ++ usb_dfu_set_download_addr((uintptr_t)&first_usb_buffer[0]); ++ ++ header->magic = 0; ++ ++ while ((header->magic != BOOT_API_IMAGE_HEADER_MAGIC_NB) || ++ (usb_dfu_get_current_req() == DFU_DNLOAD)) { ++ usb_core_handle_it((usb_handle_t *)usb_dev_info.info); ++ } ++ ++ if (header->image_length > current_phase.max_size) ++ result = -EIO; ++ else ++ *length = header->image_length; ++ ++ INFO("%s: partition size : 0x%x\n", __func__, ++ header->image_length); ++ ++ return result; ++} ++ ++/* Seek to a particular file offset on the usb device */ ++static int usb_block_seek(io_entity_t *entity, int mode, ++ signed long long offset) ++{ ++ return 0; ++} ++ ++/* Read data from a file on the usb device */ ++static int usb_block_read(io_entity_t *entity, uintptr_t buffer, ++ size_t length, size_t *length_read) ++{ ++ uint8_t *local_ptr = (uint8_t *)buffer; ++ int result = 0; ++ boot_api_image_header_t *header = ++ (boot_api_image_header_t *)first_usb_buffer; ++ ++ INFO("Start Download partition %i to address 0x%lx length %i\n", ++ current_phase.phase_id, buffer, length); ++ ++ if (current_phase.keep_header) { ++ memcpy((uint8_t *)local_ptr, ++ (uint8_t *)&first_usb_buffer[0], ++ USB_DFU_MAX_XFER_SIZE); ++ ++ usb_dfu_set_download_addr((uintptr_t) ++ &local_ptr[USB_DFU_MAX_XFER_SIZE]); ++ } else { ++ memcpy((uint8_t *)local_ptr, ++ (uint8_t *) ++ &first_usb_buffer[sizeof(boot_api_image_header_t)], ++ USB_DFU_MAX_XFER_SIZE - ++ sizeof(boot_api_image_header_t)); ++ ++ usb_dfu_set_download_addr((uintptr_t) ++ &local_ptr[USB_DFU_MAX_XFER_SIZE - ++ sizeof(boot_api_image_header_t)]); ++ } ++ ++ while (!usb_dfu_download_is_completed()) { ++ /* Reload watchdog */ ++ stm32_iwdg_refresh(IWDG2_INST); ++ ++ usb_core_handle_it((usb_handle_t *)usb_dev_info.info); ++ } ++ ++ usb_core_handle_it((usb_handle_t *)usb_dev_info.info); ++ usb_core_handle_it((usb_handle_t *)usb_dev_info.info); ++ ++ if (current_phase.keep_header) ++ local_ptr += sizeof(boot_api_image_header_t); ++ ++ /* Verify header and checksum payload */ ++ result = check_header(header, (uintptr_t)local_ptr); ++ if (result) { ++ ERROR("Header check failed\n"); ++ return result; ++ } ++ ++#if defined(AUTHENTICATE_BL33) ++ if (current_phase.phase_id != PHASE_FLASHLAYOUT) { ++ result = check_authentication(header, (uintptr_t)local_ptr); ++ if (result != 0) { ++ ERROR("Authentication failed\n"); ++ return result; ++ } ++ } ++#else ++ NOTICE("Authentication disabled: No signature check\n"); ++#endif ++ ++ /* Wait Detach in case of bl33 */ ++ if (current_phase.phase_id == PHASE_SSBL) { ++ uint32_t timeout = IO_USB_TIMEOUT; ++ uint32_t detach_timeout = DETACH_TIMEOUT; ++ ++ usb_dfu_set_phase_id(0x0); ++ usb_dfu_set_download_addr(UNDEFINE_DOWN_ADDR); ++ usb_dfu_request_detach(); ++ while (timeout && detach_timeout) { ++ usb_core_handle_it((usb_handle_t *) ++ usb_dev_info.info); ++ if (!usb_dfu_detach_req()) ++ detach_timeout--; ++ timeout--; ++ } ++ if (!timeout) ++ return -EIO; ++ /* STOP the USB Handler */ ++ usb_core_stop((usb_handle_t *)usb_dev_info.info); ++ } ++ ++ *length_read = length; ++ ++ return 0; ++} ++ ++/* Close a file on the usb device */ ++static int usb_block_close(io_entity_t *entity) ++{ ++ current_phase.phase_id = PHASE_FSBL1; ++ ++ return 0; ++} ++ ++/* Exported functions */ ++ ++/* Register the usb driver with the IO abstraction */ ++int register_io_dev_usb(const io_dev_connector_t **dev_con) ++{ ++ int result; ++ ++ assert(dev_con); ++ ++ result = io_register_device(&usb_dev_info); ++ if (!result) ++ *dev_con = &usb_dev_connector; ++ ++ return result; ++} +diff --git a/drivers/st/io/io_stm32image.c b/drivers/st/io/io_stm32image.c +new file mode 100644 +index 0000000..fde6269 +--- /dev/null ++++ b/drivers/st/io/io_stm32image.c +@@ -0,0 +1,381 @@ ++/* ++ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. ++ * ++ * SPDX-License-Identifier: BSD-3-Clause ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static uintptr_t backend_dev_handle; ++static uintptr_t backend_image_spec; ++static uint32_t *stm32_img; ++static uint8_t first_lba_buffer[MAX_LBA_SIZE] __aligned(4); ++static struct stm32image_part_info *current_part; ++ ++/* STM32 Image driver functions */ ++static int stm32image_dev_open(const uintptr_t init_params, ++ io_dev_info_t **dev_info); ++static int stm32image_partition_open(io_dev_info_t *dev_info, ++ const uintptr_t spec, io_entity_t *entity); ++static int stm32image_partition_size(io_entity_t *entity, size_t *length); ++static int stm32image_partition_read(io_entity_t *entity, uintptr_t buffer, ++ size_t length, size_t *length_read); ++static int stm32image_partition_close(io_entity_t *entity); ++static int stm32image_dev_init(io_dev_info_t *dev_info, ++ const uintptr_t init_params); ++static int stm32image_dev_close(io_dev_info_t *dev_info); ++ ++/* Identify the device type as a virtual driver */ ++static io_type_t device_type_stm32image(void) ++{ ++ return IO_TYPE_STM32IMAGE; ++} ++ ++static const io_dev_connector_t stm32image_dev_connector = { ++ .dev_open = stm32image_dev_open ++}; ++ ++static const io_dev_funcs_t stm32image_dev_funcs = { ++ .type = device_type_stm32image, ++ .open = stm32image_partition_open, ++ .size = stm32image_partition_size, ++ .read = stm32image_partition_read, ++ .close = stm32image_partition_close, ++ .dev_init = stm32image_dev_init, ++ .dev_close = stm32image_dev_close, ++}; ++ ++static io_dev_info_t stm32image_dev_info = { ++ .funcs = &stm32image_dev_funcs, ++ .info = (uintptr_t)0, ++}; ++ ++static struct stm32image_device_info stm32image_dev; ++ ++static int get_part_idx_by_binary_type(uint32_t binary_type) ++{ ++ int i; ++ ++ for (i = 0; i < STM32_PART_NUM; i++) { ++ if (stm32image_dev.part_info[i].binary_type == binary_type) { ++ return i; ++ } ++ } ++ ++ return -EINVAL; ++} ++ ++/* Open a connection to the STM32IMAGE device */ ++static int stm32image_dev_open(const uintptr_t init_params, ++ io_dev_info_t **dev_info) ++{ ++ int i; ++ struct stm32image_device_info *device_info = ++ (struct stm32image_device_info *)init_params; ++ ++ assert(dev_info != NULL); ++ *dev_info = (io_dev_info_t *)&stm32image_dev_info; ++ ++ stm32image_dev.device_size = device_info->device_size; ++ stm32image_dev.lba_size = device_info->lba_size; ++ ++ for (i = 0; i < STM32_PART_NUM; i++) { ++ memcpy(stm32image_dev.part_info[i].name, ++ device_info->part_info[i].name, MAX_PART_NAME_SIZE); ++ stm32image_dev.part_info[i].binary_type = ++ device_info->part_info[i].binary_type; ++ stm32image_dev.part_info[i].part_offset = ++ device_info->part_info[i].part_offset; ++ stm32image_dev.part_info[i].bkp_offset = ++ device_info->part_info[i].bkp_offset; ++ } ++ ++ return 0; ++} ++ ++/* Do some basic package checks */ ++static int stm32image_dev_init(io_dev_info_t *dev_info, ++ const uintptr_t init_params) ++{ ++ int result; ++ ++ if ((backend_dev_handle != 0U) || (backend_image_spec != 0U)) { ++ ERROR("STM32 Image io supports only one session\n"); ++ return -ENOMEM; ++ } ++ ++ /* Obtain a reference to the image by querying the platform layer */ ++ result = plat_get_image_source(STM32_IMAGE_ID, &backend_dev_handle, ++ &backend_image_spec); ++ if (result != 0) { ++ ERROR("STM32 image error (%i)\n", result); ++ return -EINVAL; ++ } ++ ++ return result; ++} ++ ++/* Close a connection to the STM32 Image device */ ++static int stm32image_dev_close(io_dev_info_t *dev_info) ++{ ++ backend_dev_handle = 0U; ++ backend_image_spec = 0U; ++ stm32_img = NULL; ++ ++ return 0; ++} ++ ++/* Open a partition */ ++static int stm32image_partition_open(io_dev_info_t *dev_info, ++ const uintptr_t spec, io_entity_t *entity) ++{ ++ const struct stm32image_part_info *partition_spec; ++ int idx; ++ ++ assert(entity != NULL); ++ ++ partition_spec = (struct stm32image_part_info *)spec; ++ assert(partition_spec != NULL); ++ ++ idx = get_part_idx_by_binary_type(partition_spec->binary_type); ++ if ((idx < 0) || (idx > STM32_PART_NUM)) { ++ ERROR("Wrong partition index (%d)\n", idx); ++ return -EINVAL; ++ } ++ ++ current_part = &stm32image_dev.part_info[idx]; ++ stm32_img = (uint32_t *)¤t_part->part_offset; ++ ++ return 0; ++} ++ ++/* Return the size of a partition */ ++static int stm32image_partition_size(io_entity_t *entity, size_t *length) ++{ ++ int result; ++ uintptr_t backend_handle; ++ size_t bytes_read; ++ boot_api_image_header_t *header = ++ (boot_api_image_header_t *)first_lba_buffer; ++ ++ assert(entity != NULL); ++ assert(length != NULL); ++ ++ /* Attempt to access the image */ ++ result = io_open(backend_dev_handle, backend_image_spec, ++ &backend_handle); ++ ++ if (result < 0) { ++ ERROR("%s: io_open (%i)\n", __func__, result); ++ return result; ++ } ++ ++ /* Reset magic header value */ ++ header->magic = 0; ++ ++ while (header->magic == 0U) { ++ result = io_seek(backend_handle, IO_SEEK_SET, *stm32_img); ++ if (result != 0) { ++ ERROR("%s: io_seek (%i)\n", __func__, result); ++ break; ++ } ++ ++ result = io_read(backend_handle, (uintptr_t)header, ++ MAX_LBA_SIZE, (size_t *)&bytes_read); ++ if (result != 0) { ++ if (current_part->bkp_offset == 0U) { ++ ERROR("%s: io_read (%i)\n", __func__, result); ++ } ++ header->magic = 0; ++ } ++ ++ if ((header->magic != BOOT_API_IMAGE_HEADER_MAGIC_NB) || ++ (header->binary_type != current_part->binary_type) || ++ (header->image_length >= stm32image_dev.device_size)) { ++ VERBOSE("%s: partition %s not found at %x\n", ++ __func__, current_part->name, *stm32_img); ++ ++ if (current_part->bkp_offset == 0U) { ++ result = -ENOMEM; ++ break; ++ } ++ ++ /* Header not correct, check next offset for backup */ ++ *stm32_img += current_part->bkp_offset; ++ if (*stm32_img > stm32image_dev.device_size) { ++ /* No backup found, end of device reached */ ++ WARN("%s : partition %s not found\n", ++ __func__, current_part->name); ++ result = -ENOMEM; ++ break; ++ } ++ header->magic = 0; ++ } ++ } ++ ++ io_close(backend_handle); ++ ++ if (result != 0) { ++ return result; ++ } ++ ++ if (header->image_length < stm32image_dev.lba_size) { ++ *length = stm32image_dev.lba_size; ++ } else { ++ *length = header->image_length; ++ } ++ ++ INFO("STM32 Image size : %lu\n", (unsigned long)*length); ++ ++ return 0; ++} ++ ++/* Read data from a partition */ ++static int stm32image_partition_read(io_entity_t *entity, uintptr_t buffer, ++ size_t length, size_t *length_read) ++{ ++ int result = 0; ++ uint8_t *local_buffer = (uint8_t *)buffer; ++ boot_api_image_header_t *header = ++ (boot_api_image_header_t *)first_lba_buffer; ++ ++ assert(entity != NULL); ++ assert(buffer != 0U); ++ assert(length_read != NULL); ++ ++ *length_read = 0U; ++ ++ while (*length_read == 0U) { ++ int offset; ++ int local_length; ++ uintptr_t backend_handle; ++ ++ if (header->magic != BOOT_API_IMAGE_HEADER_MAGIC_NB) { ++ /* Check for backup as image is corrupted */ ++ if (current_part->bkp_offset == 0U) { ++ result = -ENOMEM; ++ break; ++ } ++ ++ *stm32_img += current_part->bkp_offset; ++ if (*stm32_img >= stm32image_dev.device_size) { ++ /* End of device reached */ ++ result = -ENOMEM; ++ break; ++ } ++ ++ local_buffer = (uint8_t *)buffer; ++ ++ result = stm32image_partition_size(entity, &length); ++ if (result != 0) { ++ break; ++ } ++ } ++ ++ /* Part of image already loaded with the header */ ++ memcpy(local_buffer, (uint8_t *)first_lba_buffer + ++ sizeof(boot_api_image_header_t), ++ MAX_LBA_SIZE - sizeof(boot_api_image_header_t)); ++ local_buffer += MAX_LBA_SIZE - sizeof(boot_api_image_header_t); ++ offset = MAX_LBA_SIZE; ++ ++ /* New image length to be read */ ++ local_length = round_up(length - ++ ((MAX_LBA_SIZE) - ++ sizeof(boot_api_image_header_t)), ++ stm32image_dev.lba_size); ++ ++ if ((header->load_address != 0U) && ++ (header->load_address != buffer)) { ++ ERROR("Wrong load address\n"); ++ panic(); ++ } ++ ++ result = io_open(backend_dev_handle, backend_image_spec, ++ &backend_handle); ++ ++ if (result != 0) { ++ ERROR("%s: io_open (%i)\n", __func__, result); ++ break; ++ } ++ ++ result = io_seek(backend_handle, IO_SEEK_SET, ++ *stm32_img + offset); ++ ++ if (result != 0) { ++ ERROR("%s: io_seek (%i)\n", __func__, result); ++ *length_read = 0; ++ io_close(backend_handle); ++ break; ++ } ++ ++ result = io_read(backend_handle, (uintptr_t)local_buffer, ++ local_length, length_read); ++ ++ /* Adding part of size already read from header */ ++ *length_read += MAX_LBA_SIZE - sizeof(boot_api_image_header_t); ++ ++ if (result != 0) { ++ ERROR("%s: io_read (%i)\n", __func__, result); ++ *length_read = 0; ++ header->magic = 0; ++ continue; ++ } ++ ++ result = check_header(header, buffer); ++ if (result != 0) { ++ ERROR("Header check failed\n"); ++ *length_read = 0; ++ header->magic = 0; ++ } ++ ++#ifdef AUTHENTICATE_BL33 ++ result = check_authentication(header, buffer); ++ if (result != 0) { ++ ERROR("Authentication Failed\n"); ++ return result; ++ } ++#else ++ NOTICE("Authentication disabled: No signature check\n"); ++#endif ++ ++ io_close(backend_handle); ++ } ++ ++ return result; ++} ++ ++/* Close a partition */ ++static int stm32image_partition_close(io_entity_t *entity) ++{ ++ current_part = NULL; ++ ++ return 0; ++} ++ ++/* Register the stm32image driver with the IO abstraction */ ++int register_io_dev_stm32image(const io_dev_connector_t **dev_con) ++{ ++ int result; ++ ++ assert(dev_con != NULL); ++ ++ result = io_register_device(&stm32image_dev_info); ++ if (result == 0) { ++ *dev_con = &stm32image_dev_connector; ++ } ++ ++ return result; ++} +diff --git a/drivers/st/iwdg/stm32_iwdg.c b/drivers/st/iwdg/stm32_iwdg.c +new file mode 100644 +index 0000000..6d91a9f +--- /dev/null ++++ b/drivers/st/iwdg/stm32_iwdg.c +@@ -0,0 +1,289 @@ ++/* ++ * Copyright (c) 2017-2018, STMicroelectronics - All Rights Reserved ++ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. ++ * ++ * SPDX-License-Identifier: BSD-3-Clause ++ */ ++ ++#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_MS U(100) ++ ++/* 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(11, 0) ++ ++struct stm32_iwdg_instance { ++ uintptr_t base; ++ unsigned long clock; ++ uint8_t flags; ++ int num_irq; ++}; ++ ++static struct stm32_iwdg_instance stm32_iwdg[IWDG_MAX_INSTANCE]; ++ ++static int stm32_iwdg_get_dt_node(struct dt_node_info *info, int offset) ++{ ++ int node; ++ ++ node = dt_get_node(info, offset, IWDG_COMPAT); ++ if (node < 0) { ++ if (offset == -1) { ++ VERBOSE("%s: No IDWG found\n", __func__); ++ } ++ return -FDT_ERR_NOTFOUND; ++ } ++ ++ return node; ++} ++ ++#if defined(IMAGE_BL32) ++void __dead2 stm32_iwdg_it_handler(int id) ++{ ++ unsigned int cpu = plat_my_core_pos(); ++ struct stm32_iwdg_instance *iwdg; ++ unsigned int instance; ++ ++ for (instance = 0; instance < IWDG_MAX_INSTANCE; instance++) { ++ if (stm32_iwdg[instance].num_irq == id) { ++ break; ++ } ++ } ++ ++ if (instance == IWDG_MAX_INSTANCE) { ++ panic(); ++ } ++ ++ iwdg = &stm32_iwdg[instance]; ++ ++ VERBOSE("CPU %x IT Watchdog %d\n", cpu, instance + 1); ++ ++ stm32_iwdg_refresh(instance); ++ ++ stm32mp_clk_enable(iwdg->clock); ++ ++ mmio_setbits_32(iwdg->base + IWDG_EWCR_OFFSET, IWDG_EWCR_EWIC); ++ ++ stm32mp_clk_disable(iwdg->clock); ++ ++ /* Ack interrupt as we do not return from next call */ ++ gicv2_end_of_interrupt(id); ++ ++ stm32mp_plat_reset(cpu); ++} ++ ++static int stm32_iwdg_get_secure_timeout(int node) ++{ ++ void *fdt; ++ const fdt32_t *cuint; ++ ++ if (fdt_get_address(&fdt) == 0) { ++ return -1; ++ } ++ ++ 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(int node, struct stm32_iwdg_instance *iwdg) ++{ ++ int id_lsi; ++ int dt_secure_timeout = stm32_iwdg_get_secure_timeout(node); ++ uint32_t reload, status; ++ unsigned int timeout = IWDG_TIMEOUT_MS; ++ unsigned long long reload_ll; ++ ++ if (dt_secure_timeout < 0) { ++ return 0; ++ } ++ ++ if (dt_secure_timeout == 0) { ++ return -EINVAL; ++ } ++ ++ id_lsi = fdt_get_clock_id_by_name(node, "lsi"); ++ if (id_lsi < 0) { ++ return -EINVAL; ++ } ++ ++ /* Prescaler fix to 256 */ ++ reload_ll = (unsigned long long)dt_secure_timeout * ++ stm32mp_clk_get_rate(id_lsi); ++ reload = ((uint32_t)(reload_ll >> 8) - 1U) & IWDG_EWCR_EWIT_MASK; ++ ++ stm32mp_clk_enable(iwdg->clock); ++ ++ mmio_write_32(iwdg->base + IWDG_KR_OFFSET, IWDG_KR_START_KEY); ++ mmio_write_32(iwdg->base + IWDG_KR_OFFSET, IWDG_KR_ACCESS_KEY); ++ mmio_write_32(iwdg->base + IWDG_PR_OFFSET, IWDG_PR_DIV_256); ++ mmio_write_32(iwdg->base + IWDG_EWCR_OFFSET, IWDG_EWCR_EWIE | reload); ++ ++ do { ++ status = mmio_read_32(iwdg->base + IWDG_SR_OFFSET) & ++ IWDG_SR_EWU; ++ timeout--; ++ mdelay(1); ++ } while ((status != 0U) && (timeout != 0U)); ++ ++ iwdg->num_irq = stm32_gic_enable_spi(node, NULL); ++ if (iwdg->num_irq < 0) { ++ panic(); ++ } ++ ++ stm32mp_clk_disable(iwdg->clock); ++ ++ return (timeout == 0U) ? -ETIMEDOUT : 0; ++} ++#endif ++ ++void stm32_iwdg_refresh(uint32_t instance) ++{ ++ struct stm32_iwdg_instance *iwdg = &stm32_iwdg[instance]; ++ ++ assert(iwdg); ++ ++ stm32mp_clk_enable(iwdg->clock); ++ ++ mmio_write_32(iwdg->base + IWDG_KR_OFFSET, IWDG_KR_RELOAD_KEY); ++ ++ stm32mp_clk_disable(iwdg->clock); ++} ++ ++int stm32_iwdg_init(void) ++{ ++ int node = -1; ++ int __unused res; ++ struct dt_node_info dt_info; ++ void *fdt; ++ uint32_t __unused count = 0; ++ uint32_t idx; ++ uint32_t __unused otp_value; ++ ++ if (fdt_get_address(&fdt) == 0) { ++ panic(); ++ } ++ ++ for (node = stm32_iwdg_get_dt_node(&dt_info, node); ++ node != -FDT_ERR_NOTFOUND; ++ node = stm32_iwdg_get_dt_node(&dt_info, node)) { ++ struct stm32_iwdg_instance *iwdg; ++ uint32_t hw_init; ++ ++ idx = stm32_iwdg_get_instance(dt_info.base); ++ iwdg = &stm32_iwdg[idx]; ++ iwdg->base = dt_info.base; ++ iwdg->clock = (unsigned long)dt_info.clock; ++ ++ /* 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; ++ } ++ ++ /* Explicit list of supported bit flags */ ++ hw_init = stm32_iwdg_get_otp_config(iwdg->base); ++ ++ if ((hw_init & IWDG_HW_ENABLED) != 0) { ++ if (dt_info.status == DT_DISABLED) { ++ ERROR("OTP enabled but iwdg%d DT-disabled\n", ++ idx + 1); ++ panic(); ++ } ++ iwdg->flags |= IWDG_HW_ENABLED; ++ } ++ ++ if (dt_info.status == DT_DISABLED) { ++ zeromem((void *)iwdg, ++ sizeof(struct stm32_iwdg_instance)); ++ goto next; ++ } ++ ++ 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; ++ } ++ ++ VERBOSE("IWDG%u found, %ssecure\n", idx + 1, ++ ((dt_info.status & DT_NON_SECURE) != 0) ? ++ "non " : ""); ++ ++ if ((dt_info.status & DT_NON_SECURE) != 0) { ++ stm32mp_register_non_secure_periph_iomem(iwdg->base); ++ } else { ++ stm32mp_register_secure_periph_iomem(iwdg->base); ++ } ++ ++ stm32mp_clk_enable(iwdg->clock); ++ stm32mp_clk_disable(iwdg->clock); ++ ++#if defined(IMAGE_BL32) ++ res = stm32_iwdg_conf_etimeout(node, iwdg); ++ if (res != 0) { ++ ERROR("IWDG%x early timeout config failed (%d)\n", ++ idx + 1, res); ++ return res; ++ } ++#endif ++#if defined(IMAGE_BL2) ++ if (stm32_iwdg_shadow_update(iwdg->base, iwdg->flags) != ++ BSEC_OK) { ++ return -1; ++ } ++#endif ++ ++next: ++ count++; ++ } ++ ++ VERBOSE("%u IWDG instance%s found\n", count, count > 1 ? "s" : ""); ++ ++ return 0; ++} +diff --git a/drivers/st/mmc/stm32_sdmmc2.c b/drivers/st/mmc/stm32_sdmmc2.c +new file mode 100644 +index 0000000..620087e +--- /dev/null ++++ b/drivers/st/mmc/stm32_sdmmc2.c +@@ -0,0 +1,752 @@ ++/* ++ * Copyright (c) 2018-2019, STMicroelectronics - All Rights Reserved ++ * ++ * SPDX-License-Identifier: BSD-3-Clause ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* Registers offsets */ ++#define SDMMC_POWER 0x00U ++#define SDMMC_CLKCR 0x04U ++#define SDMMC_ARGR 0x08U ++#define SDMMC_CMDR 0x0CU ++#define SDMMC_RESPCMDR 0x10U ++#define SDMMC_RESP1R 0x14U ++#define SDMMC_RESP2R 0x18U ++#define SDMMC_RESP3R 0x1CU ++#define SDMMC_RESP4R 0x20U ++#define SDMMC_DTIMER 0x24U ++#define SDMMC_DLENR 0x28U ++#define SDMMC_DCTRLR 0x2CU ++#define SDMMC_DCNTR 0x30U ++#define SDMMC_STAR 0x34U ++#define SDMMC_ICR 0x38U ++#define SDMMC_MASKR 0x3CU ++#define SDMMC_ACKTIMER 0x40U ++#define SDMMC_IDMACTRLR 0x50U ++#define SDMMC_IDMABSIZER 0x54U ++#define SDMMC_IDMABASE0R 0x58U ++#define SDMMC_IDMABASE1R 0x5CU ++#define SDMMC_FIFOR 0x80U ++ ++/* SDMMC power control register */ ++#define SDMMC_POWER_PWRCTRL GENMASK(1, 0) ++#define SDMMC_POWER_DIRPOL BIT(4) ++ ++/* SDMMC clock control register */ ++#define SDMMC_CLKCR_WIDBUS_4 BIT(14) ++#define SDMMC_CLKCR_WIDBUS_8 BIT(15) ++#define SDMMC_CLKCR_NEGEDGE BIT(16) ++#define SDMMC_CLKCR_HWFC_EN BIT(17) ++#define SDMMC_CLKCR_SELCLKRX_0 BIT(20) ++ ++/* SDMMC command register */ ++#define SDMMC_CMDR_CMDTRANS BIT(6) ++#define SDMMC_CMDR_CMDSTOP BIT(7) ++#define SDMMC_CMDR_WAITRESP GENMASK(9, 8) ++#define SDMMC_CMDR_WAITRESP_SHORT BIT(8) ++#define SDMMC_CMDR_WAITRESP_SHORT_NOCRC BIT(9) ++#define SDMMC_CMDR_CPSMEN BIT(12) ++ ++/* SDMMC data control register */ ++#define SDMMC_DCTRLR_DTEN BIT(0) ++#define SDMMC_DCTRLR_DTDIR BIT(1) ++#define SDMMC_DCTRLR_DTMODE GENMASK(3, 2) ++#define SDMMC_DCTRLR_DBLOCKSIZE_0 BIT(4) ++#define SDMMC_DCTRLR_DBLOCKSIZE_1 BIT(5) ++#define SDMMC_DCTRLR_DBLOCKSIZE_3 BIT(7) ++#define SDMMC_DCTRLR_DBLOCKSIZE GENMASK(7, 4) ++#define SDMMC_DCTRLR_FIFORST BIT(13) ++ ++#define SDMMC_DCTRLR_CLEAR_MASK (SDMMC_DCTRLR_DTEN | \ ++ SDMMC_DCTRLR_DTDIR | \ ++ SDMMC_DCTRLR_DTMODE | \ ++ SDMMC_DCTRLR_DBLOCKSIZE) ++#define SDMMC_DBLOCKSIZE_8 (SDMMC_DCTRLR_DBLOCKSIZE_0 | \ ++ SDMMC_DCTRLR_DBLOCKSIZE_1) ++#define SDMMC_DBLOCKSIZE_512 (SDMMC_DCTRLR_DBLOCKSIZE_0 | \ ++ SDMMC_DCTRLR_DBLOCKSIZE_3) ++ ++/* SDMMC status register */ ++#define SDMMC_STAR_CCRCFAIL BIT(0) ++#define SDMMC_STAR_DCRCFAIL BIT(1) ++#define SDMMC_STAR_CTIMEOUT BIT(2) ++#define SDMMC_STAR_DTIMEOUT BIT(3) ++#define SDMMC_STAR_TXUNDERR BIT(4) ++#define SDMMC_STAR_RXOVERR BIT(5) ++#define SDMMC_STAR_CMDREND BIT(6) ++#define SDMMC_STAR_CMDSENT BIT(7) ++#define SDMMC_STAR_DATAEND BIT(8) ++#define SDMMC_STAR_DBCKEND BIT(10) ++#define SDMMC_STAR_DPSMACT BIT(12) ++#define SDMMC_STAR_RXFIFOHF BIT(15) ++#define SDMMC_STAR_RXFIFOE BIT(19) ++#define SDMMC_STAR_IDMATE BIT(27) ++#define SDMMC_STAR_IDMABTC BIT(28) ++ ++/* SDMMC DMA control register */ ++#define SDMMC_IDMACTRLR_IDMAEN BIT(0) ++ ++#define SDMMC_STATIC_FLAGS (SDMMC_STAR_CCRCFAIL | \ ++ SDMMC_STAR_DCRCFAIL | \ ++ SDMMC_STAR_CTIMEOUT | \ ++ SDMMC_STAR_DTIMEOUT | \ ++ SDMMC_STAR_TXUNDERR | \ ++ SDMMC_STAR_RXOVERR | \ ++ SDMMC_STAR_CMDREND | \ ++ SDMMC_STAR_CMDSENT | \ ++ SDMMC_STAR_DATAEND | \ ++ SDMMC_STAR_DBCKEND | \ ++ SDMMC_STAR_IDMATE | \ ++ SDMMC_STAR_IDMABTC) ++ ++#define TIMEOUT_10_MS ms2tick(10) ++#define TIMEOUT_1_S s2tick(1) ++ ++#define DT_SDMMC2_COMPAT "st,stm32-sdmmc2" ++ ++static void stm32_sdmmc2_init(void); ++static int stm32_sdmmc2_send_cmd_req(struct mmc_cmd *cmd); ++static int stm32_sdmmc2_send_cmd(struct mmc_cmd *cmd); ++static int stm32_sdmmc2_set_ios(unsigned int clk, unsigned int width); ++static int stm32_sdmmc2_prepare(int lba, uintptr_t buf, size_t size); ++static int stm32_sdmmc2_read(int lba, uintptr_t buf, size_t size); ++static int stm32_sdmmc2_write(int lba, uintptr_t buf, size_t size); ++ ++static const struct mmc_ops stm32_sdmmc2_ops = { ++ .init = stm32_sdmmc2_init, ++ .send_cmd = stm32_sdmmc2_send_cmd, ++ .set_ios = stm32_sdmmc2_set_ios, ++ .prepare = stm32_sdmmc2_prepare, ++ .read = stm32_sdmmc2_read, ++ .write = stm32_sdmmc2_write, ++}; ++ ++static struct stm32_sdmmc2_params sdmmc2_params; ++ ++#pragma weak plat_sdmmc2_use_dma ++bool plat_sdmmc2_use_dma(unsigned int instance, unsigned int memory) ++{ ++ return false; ++} ++ ++static void dump_registers(void) ++{ ++ uintptr_t base = sdmmc2_params.reg_base; ++ ++ INFO("SDMMC_POWER = 0x%x\n", mmio_read_32(base + SDMMC_POWER)); ++ INFO("SDMMC_CLKCR = 0x%x\n", mmio_read_32(base + SDMMC_CLKCR)); ++ INFO("SDMMC_ARGR = 0x%x\n", mmio_read_32(base + SDMMC_ARGR)); ++ INFO("SDMMC_CMDR = 0x%x\n", mmio_read_32(base + SDMMC_CMDR)); ++ INFO("SDMMC_RESPCMDR = 0x%x\n", mmio_read_32(base + SDMMC_RESPCMDR)); ++ INFO("SDMMC_RESP1R = 0x%x\n", mmio_read_32(base + SDMMC_RESP1R)); ++ INFO("SDMMC_RESP2R = 0x%x\n", mmio_read_32(base + SDMMC_RESP2R)); ++ INFO("SDMMC_RESP3R = 0x%x\n", mmio_read_32(base + SDMMC_RESP3R)); ++ INFO("SDMMC_RESP4R = 0x%x\n", mmio_read_32(base + SDMMC_RESP4R)); ++ INFO("SDMMC_DTIMER = 0x%x\n", mmio_read_32(base + SDMMC_DTIMER)); ++ INFO("SDMMC_DLENR = 0x%x\n", mmio_read_32(base + SDMMC_DLENR)); ++ INFO("SDMMC_DCTRLR = 0x%x\n", mmio_read_32(base + SDMMC_DCTRLR)); ++ INFO("SDMMC_DCNTR = 0x%x\n", mmio_read_32(base + SDMMC_DCNTR)); ++ INFO("SDMMC_MASKR = 0x%x\n", mmio_read_32(base + SDMMC_MASKR)); ++ INFO("SDMMC_ACKTIMER = 0x%x\n", mmio_read_32(base + SDMMC_ACKTIMER)); ++} ++ ++static void stm32_sdmmc2_init(void) ++{ ++ uint32_t clock_div; ++ uintptr_t base = sdmmc2_params.reg_base; ++ ++ clock_div = div_round_up(sdmmc2_params.clk_rate, ++ STM32MP_MMC_INIT_FREQ * 2); ++ ++ mmio_write_32(base + SDMMC_CLKCR, SDMMC_CLKCR_HWFC_EN | clock_div | ++ sdmmc2_params.negedge | ++ sdmmc2_params.pin_ckin); ++ ++ mmio_write_32(base + SDMMC_POWER, ++ SDMMC_POWER_PWRCTRL | sdmmc2_params.dirpol); ++ ++ mdelay(1); ++} ++ ++static int stm32_sdmmc2_stop_transfer(void) ++{ ++ struct mmc_cmd cmd_stop; ++ ++ zeromem(&cmd_stop, sizeof(struct mmc_cmd)); ++ ++ cmd_stop.cmd_idx = MMC_CMD(12); ++ cmd_stop.resp_type = MMC_RESPONSE_R1B; ++ ++ return stm32_sdmmc2_send_cmd(&cmd_stop); ++} ++ ++static int stm32_sdmmc2_send_cmd_req(struct mmc_cmd *cmd) ++{ ++ uint64_t start; ++ uint32_t flags_cmd, status; ++ uint32_t flags_data = 0; ++ int err = 0; ++ uintptr_t base = sdmmc2_params.reg_base; ++ unsigned int cmd_reg, arg_reg; ++ ++ if (cmd == NULL) { ++ return -EINVAL; ++ } ++ ++ flags_cmd = SDMMC_STAR_CTIMEOUT; ++ arg_reg = cmd->cmd_arg; ++ ++ if ((mmio_read_32(base + SDMMC_CMDR) & SDMMC_CMDR_CPSMEN) != 0U) { ++ mmio_write_32(base + SDMMC_CMDR, 0); ++ } ++ ++ cmd_reg = cmd->cmd_idx | SDMMC_CMDR_CPSMEN; ++ ++ if (cmd->resp_type == 0U) { ++ flags_cmd |= SDMMC_STAR_CMDSENT; ++ } ++ ++ if ((cmd->resp_type & MMC_RSP_48) != 0U) { ++ if ((cmd->resp_type & MMC_RSP_136) != 0U) { ++ flags_cmd |= SDMMC_STAR_CMDREND; ++ cmd_reg |= SDMMC_CMDR_WAITRESP; ++ } else if ((cmd->resp_type & MMC_RSP_CRC) != 0U) { ++ flags_cmd |= SDMMC_STAR_CMDREND | SDMMC_STAR_CCRCFAIL; ++ cmd_reg |= SDMMC_CMDR_WAITRESP_SHORT; ++ } else { ++ flags_cmd |= SDMMC_STAR_CMDREND; ++ cmd_reg |= SDMMC_CMDR_WAITRESP_SHORT_NOCRC; ++ } ++ } ++ ++ switch (cmd->cmd_idx) { ++ case MMC_CMD(1): ++ arg_reg |= OCR_POWERUP; ++ break; ++ case MMC_CMD(8): ++ if (sdmmc2_params.device_info->mmc_dev_type == MMC_IS_EMMC) { ++ cmd_reg |= SDMMC_CMDR_CMDTRANS; ++ } ++ break; ++ case MMC_CMD(12): ++ cmd_reg |= SDMMC_CMDR_CMDSTOP; ++ break; ++ case MMC_CMD(17): ++ case MMC_CMD(18): ++ cmd_reg |= SDMMC_CMDR_CMDTRANS; ++ if (sdmmc2_params.use_dma) { ++ flags_data |= SDMMC_STAR_DCRCFAIL | ++ SDMMC_STAR_DTIMEOUT | ++ SDMMC_STAR_DATAEND | ++ SDMMC_STAR_RXOVERR | ++ SDMMC_STAR_IDMATE; ++ } ++ break; ++ case MMC_ACMD(41): ++ arg_reg |= OCR_3_2_3_3 | OCR_3_3_3_4; ++ break; ++ case MMC_ACMD(51): ++ cmd_reg |= SDMMC_CMDR_CMDTRANS; ++ if (sdmmc2_params.use_dma) { ++ flags_data |= SDMMC_STAR_DCRCFAIL | ++ SDMMC_STAR_DTIMEOUT | ++ SDMMC_STAR_DATAEND | ++ SDMMC_STAR_RXOVERR | ++ SDMMC_STAR_IDMATE | ++ SDMMC_STAR_DBCKEND; ++ } ++ break; ++ default: ++ break; ++ } ++ ++ if ((cmd->resp_type & MMC_RSP_BUSY) != 0U) { ++ mmio_write_32(base + SDMMC_DTIMER, UINT32_MAX); ++ } ++ ++ mmio_write_32(base + SDMMC_ARGR, arg_reg); ++ ++ mmio_write_32(base + SDMMC_CMDR, cmd_reg); ++ ++ status = mmio_read_32(base + SDMMC_STAR); ++ ++ start = timeout_start(); ++ ++ while ((status & flags_cmd) == 0U) { ++ if (timeout_elapsed(start, TIMEOUT_10_MS)) { ++ err = -ETIMEDOUT; ++ ERROR("%s: timeout 10ms (cmd = %d,status = %x)\n", ++ __func__, cmd->cmd_idx, status); ++ goto err_exit; ++ } ++ ++ status = mmio_read_32(base + SDMMC_STAR); ++ } ++ ++ if ((status & (SDMMC_STAR_CTIMEOUT | SDMMC_STAR_CCRCFAIL)) != 0U) { ++ if ((status & SDMMC_STAR_CTIMEOUT) != 0U) { ++ err = -ETIMEDOUT; ++ /* ++ * Those timeouts can occur, and framework will handle ++ * the retries. CMD8 is expected to return this timeout ++ * for eMMC ++ */ ++ if (!((cmd->cmd_idx == MMC_CMD(1)) || ++ (cmd->cmd_idx == MMC_CMD(13)) || ++ ((cmd->cmd_idx == MMC_CMD(8)) && ++ (cmd->resp_type == MMC_RESPONSE_R7)))) { ++ ERROR("%s: CTIMEOUT (cmd = %d,status = %x)\n", ++ __func__, cmd->cmd_idx, status); ++ } ++ } else { ++ err = -EIO; ++ ERROR("%s: CRCFAIL (cmd = %d,status = %x)\n", ++ __func__, cmd->cmd_idx, status); ++ } ++ ++ goto err_exit; ++ } ++ ++ if ((cmd_reg & SDMMC_CMDR_WAITRESP) != 0U) { ++ if ((cmd->cmd_idx == MMC_CMD(9)) && ++ ((cmd_reg & SDMMC_CMDR_WAITRESP) == SDMMC_CMDR_WAITRESP)) { ++ /* Need to invert response to match CSD structure */ ++ cmd->resp_data[0] = mmio_read_32(base + SDMMC_RESP4R); ++ cmd->resp_data[1] = mmio_read_32(base + SDMMC_RESP3R); ++ cmd->resp_data[2] = mmio_read_32(base + SDMMC_RESP2R); ++ cmd->resp_data[3] = mmio_read_32(base + SDMMC_RESP1R); ++ } else { ++ cmd->resp_data[0] = mmio_read_32(base + SDMMC_RESP1R); ++ if ((cmd_reg & SDMMC_CMDR_WAITRESP) == ++ SDMMC_CMDR_WAITRESP) { ++ cmd->resp_data[1] = mmio_read_32(base + ++ SDMMC_RESP2R); ++ cmd->resp_data[2] = mmio_read_32(base + ++ SDMMC_RESP3R); ++ cmd->resp_data[3] = mmio_read_32(base + ++ SDMMC_RESP4R); ++ } ++ } ++ } ++ ++ if (flags_data == 0U) { ++ mmio_write_32(base + SDMMC_ICR, SDMMC_STATIC_FLAGS); ++ ++ return 0; ++ } ++ ++ status = mmio_read_32(base + SDMMC_STAR); ++ ++ start = timeout_start(); ++ ++ while ((status & flags_data) == 0U) { ++ if (timeout_elapsed(start, TIMEOUT_10_MS)) { ++ ERROR("%s: timeout 10ms (cmd = %d,status = %x)\n", ++ __func__, cmd->cmd_idx, status); ++ err = -ETIMEDOUT; ++ goto err_exit; ++ } ++ ++ status = mmio_read_32(base + SDMMC_STAR); ++ }; ++ ++ if ((status & (SDMMC_STAR_DTIMEOUT | SDMMC_STAR_DCRCFAIL | ++ SDMMC_STAR_TXUNDERR | SDMMC_STAR_RXOVERR | ++ SDMMC_STAR_IDMATE)) != 0U) { ++ ERROR("%s: Error flag (cmd = %d,status = %x)\n", __func__, ++ cmd->cmd_idx, status); ++ err = -EIO; ++ } ++ ++err_exit: ++ mmio_write_32(base + SDMMC_ICR, SDMMC_STATIC_FLAGS); ++ mmio_clrbits_32(base + SDMMC_CMDR, SDMMC_CMDR_CMDTRANS); ++ ++ if ((err != 0) && ((status & SDMMC_STAR_DPSMACT) != 0U)) { ++ int ret_stop = stm32_sdmmc2_stop_transfer(); ++ ++ if (ret_stop != 0) { ++ return ret_stop; ++ } ++ } ++ ++ return err; ++} ++ ++static int stm32_sdmmc2_send_cmd(struct mmc_cmd *cmd) ++{ ++ int8_t retry; ++ int err = 0; ++ ++ assert(cmd != NULL); ++ ++ for (retry = 0; retry <= 3; retry++) { ++ err = stm32_sdmmc2_send_cmd_req(cmd); ++ if (err == 0) { ++ return err; ++ } ++ ++ if ((cmd->cmd_idx == MMC_CMD(1)) || ++ (cmd->cmd_idx == MMC_CMD(13))) { ++ return 0; /* Retry managed by framework */ ++ } ++ ++ /* Command 8 is expected to fail for eMMC */ ++ if (!(cmd->cmd_idx == MMC_CMD(8))) { ++ WARN(" CMD%d, Retry: %d, Error: %d\n", ++ cmd->cmd_idx, retry, err); ++ } ++ ++ udelay(10); ++ } ++ ++ return err; ++} ++ ++static int stm32_sdmmc2_set_ios(unsigned int clk, unsigned int width) ++{ ++ uintptr_t base = sdmmc2_params.reg_base; ++ uint32_t bus_cfg = 0; ++ uint32_t clock_div, max_freq; ++ uint32_t clk_rate = sdmmc2_params.clk_rate; ++ uint32_t max_bus_freq = sdmmc2_params.device_info->max_bus_freq; ++ ++ switch (width) { ++ case MMC_BUS_WIDTH_1: ++ break; ++ case MMC_BUS_WIDTH_4: ++ bus_cfg |= SDMMC_CLKCR_WIDBUS_4; ++ break; ++ case MMC_BUS_WIDTH_8: ++ bus_cfg |= SDMMC_CLKCR_WIDBUS_8; ++ break; ++ default: ++ panic(); ++ break; ++ } ++ ++ if (sdmmc2_params.device_info->mmc_dev_type == MMC_IS_EMMC) { ++ if (max_bus_freq >= 52000000U) { ++ max_freq = STM32MP_EMMC_HIGH_SPEED_MAX_FREQ; ++ } else { ++ max_freq = STM32MP_EMMC_NORMAL_SPEED_MAX_FREQ; ++ } ++ } else { ++ if (max_bus_freq >= 50000000U) { ++ max_freq = STM32MP_SD_HIGH_SPEED_MAX_FREQ; ++ } else { ++ max_freq = STM32MP_SD_NORMAL_SPEED_MAX_FREQ; ++ } ++ } ++ ++ clock_div = div_round_up(clk_rate, max_freq * 2); ++ ++ mmio_write_32(base + SDMMC_CLKCR, ++ SDMMC_CLKCR_HWFC_EN | clock_div | bus_cfg | ++ sdmmc2_params.negedge | ++ sdmmc2_params.pin_ckin); ++ ++ return 0; ++} ++ ++static int stm32_sdmmc2_prepare(int lba, uintptr_t buf, size_t size) ++{ ++ struct mmc_cmd cmd; ++ int ret; ++ uintptr_t base = sdmmc2_params.reg_base; ++ uint32_t data_ctrl = SDMMC_DCTRLR_DTDIR; ++ ++ if (size == 8U) { ++ data_ctrl |= SDMMC_DBLOCKSIZE_8; ++ } else { ++ data_ctrl |= SDMMC_DBLOCKSIZE_512; ++ } ++ ++ sdmmc2_params.use_dma = plat_sdmmc2_use_dma(base, buf); ++ ++ if (sdmmc2_params.use_dma) { ++ inv_dcache_range(buf, size); ++ } ++ ++ /* Prepare CMD 16*/ ++ mmio_write_32(base + SDMMC_DTIMER, 0); ++ ++ mmio_write_32(base + SDMMC_DLENR, 0); ++ ++ mmio_write_32(base + SDMMC_DCTRLR, 0); ++ ++ zeromem(&cmd, sizeof(struct mmc_cmd)); ++ ++ cmd.cmd_idx = MMC_CMD(16); ++ if (size > MMC_BLOCK_SIZE) { ++ cmd.cmd_arg = MMC_BLOCK_SIZE; ++ } else { ++ cmd.cmd_arg = size; ++ } ++ ++ cmd.resp_type = MMC_RESPONSE_R1; ++ ++ ret = stm32_sdmmc2_send_cmd(&cmd); ++ if (ret != 0) { ++ ERROR("CMD16 failed\n"); ++ return ret; ++ } ++ ++ /* Prepare data command */ ++ mmio_write_32(base + SDMMC_DTIMER, UINT32_MAX); ++ ++ mmio_write_32(base + SDMMC_DLENR, size); ++ ++ if (sdmmc2_params.use_dma) { ++ mmio_write_32(base + SDMMC_IDMACTRLR, ++ SDMMC_IDMACTRLR_IDMAEN); ++ mmio_write_32(base + SDMMC_IDMABASE0R, buf); ++ ++ flush_dcache_range(buf, size); ++ } ++ ++ mmio_clrsetbits_32(base + SDMMC_DCTRLR, ++ SDMMC_DCTRLR_CLEAR_MASK, ++ data_ctrl); ++ ++ return 0; ++} ++ ++static int stm32_sdmmc2_read(int lba, uintptr_t buf, size_t size) ++{ ++ uint32_t error_flags = SDMMC_STAR_RXOVERR | SDMMC_STAR_DCRCFAIL | ++ SDMMC_STAR_DTIMEOUT; ++ uint32_t flags = error_flags | SDMMC_STAR_DATAEND; ++ uint32_t status; ++ uint32_t *buffer; ++ uintptr_t base = sdmmc2_params.reg_base; ++ uintptr_t fifo_reg = base + SDMMC_FIFOR; ++ unsigned int start; ++ int ret; ++ ++ /* Assert buf is 4 bytes aligned */ ++ assert((buf & GENMASK(1, 0)) == 0U); ++ ++ buffer = (uint32_t *)buf; ++ ++ if (sdmmc2_params.use_dma) { ++ inv_dcache_range(buf, size); ++ ++ return 0; ++ } ++ ++ if (size <= MMC_BLOCK_SIZE) { ++ flags |= SDMMC_STAR_DBCKEND; ++ } ++ ++ start = timeout_start(); ++ ++ do { ++ status = mmio_read_32(base + SDMMC_STAR); ++ ++ if ((status & error_flags) != 0U) { ++ ERROR("%s: Read error (status = %x)\n", __func__, ++ status); ++ dump_registers(); ++ mmio_write_32(base + SDMMC_DCTRLR, ++ SDMMC_DCTRLR_FIFORST); ++ ++ mmio_write_32(base + SDMMC_ICR, ++ SDMMC_STATIC_FLAGS); ++ ++ ret = stm32_sdmmc2_stop_transfer(); ++ if (ret != 0) { ++ return ret; ++ } ++ ++ return -EIO; ++ } ++ ++ if (timeout_elapsed(start, TIMEOUT_1_S)) { ++ ERROR("%s: timeout 1s (status = %x)\n", ++ __func__, status); ++ dump_registers(); ++ mmio_write_32(base + SDMMC_ICR, ++ SDMMC_STATIC_FLAGS); ++ ++ ret = stm32_sdmmc2_stop_transfer(); ++ if (ret != 0) { ++ return ret; ++ } ++ ++ return -ETIMEDOUT; ++ } ++ ++ if (size < (8U * sizeof(uint32_t))) { ++ if ((mmio_read_32(base + SDMMC_DCNTR) > 0U) && ++ ((status & SDMMC_STAR_RXFIFOE) == 0U)) { ++ *buffer = mmio_read_32(fifo_reg); ++ buffer++; ++ } ++ } else if ((status & SDMMC_STAR_RXFIFOHF) != 0U) { ++ uint32_t count; ++ ++ /* Read data from SDMMC Rx FIFO */ ++ for (count = 0; count < 8U; count++) { ++ *buffer = mmio_read_32(fifo_reg); ++ buffer++; ++ } ++ } ++ } while ((status & flags) == 0U); ++ ++ mmio_write_32(base + SDMMC_ICR, SDMMC_STATIC_FLAGS); ++ ++ if ((status & SDMMC_STAR_DPSMACT) != 0U) { ++ WARN("%s: DPSMACT=1, send stop\n", __func__); ++ return stm32_sdmmc2_stop_transfer(); ++ } ++ ++ return 0; ++} ++ ++static int stm32_sdmmc2_write(int lba, uintptr_t buf, size_t size) ++{ ++ return 0; ++} ++ ++static int stm32_sdmmc2_dt_get_config(void) ++{ ++ int sdmmc_node; ++ void *fdt = NULL; ++ const fdt32_t *cuint; ++ ++ if (fdt_get_address(&fdt) == 0) { ++ return -FDT_ERR_NOTFOUND; ++ } ++ ++ if (fdt == NULL) { ++ return -FDT_ERR_NOTFOUND; ++ } ++ ++ sdmmc_node = fdt_node_offset_by_compatible(fdt, -1, DT_SDMMC2_COMPAT); ++ ++ while (sdmmc_node != -FDT_ERR_NOTFOUND) { ++ cuint = fdt_getprop(fdt, sdmmc_node, "reg", NULL); ++ if (cuint == NULL) { ++ continue; ++ } ++ ++ if (fdt32_to_cpu(*cuint) == sdmmc2_params.reg_base) { ++ break; ++ } ++ ++ sdmmc_node = fdt_node_offset_by_compatible(fdt, sdmmc_node, ++ DT_SDMMC2_COMPAT); ++ } ++ ++ if (sdmmc_node == -FDT_ERR_NOTFOUND) { ++ return -FDT_ERR_NOTFOUND; ++ } ++ ++ if (fdt_get_status(sdmmc_node) == DT_DISABLED) { ++ return -FDT_ERR_NOTFOUND; ++ } ++ ++ if (dt_set_pinctrl_config(sdmmc_node) != 0) { ++ return -FDT_ERR_BADVALUE; ++ } ++ ++ cuint = fdt_getprop(fdt, sdmmc_node, "clocks", NULL); ++ if (cuint == NULL) { ++ return -FDT_ERR_NOTFOUND; ++ } ++ ++ cuint++; ++ sdmmc2_params.clock_id = fdt32_to_cpu(*cuint); ++ ++ cuint = fdt_getprop(fdt, sdmmc_node, "resets", NULL); ++ if (cuint == NULL) { ++ return -FDT_ERR_NOTFOUND; ++ } ++ ++ cuint++; ++ sdmmc2_params.reset_id = fdt32_to_cpu(*cuint); ++ ++ if ((fdt_getprop(fdt, sdmmc_node, "st,use-ckin", NULL)) != NULL) { ++ sdmmc2_params.pin_ckin = SDMMC_CLKCR_SELCLKRX_0; ++ } ++ ++ if ((fdt_getprop(fdt, sdmmc_node, "st,sig-dir", NULL)) != NULL) { ++ sdmmc2_params.dirpol = SDMMC_POWER_DIRPOL; ++ } ++ ++ if ((fdt_getprop(fdt, sdmmc_node, "st,neg-edge", NULL)) != NULL) { ++ sdmmc2_params.negedge = SDMMC_CLKCR_NEGEDGE; ++ } ++ ++ cuint = fdt_getprop(fdt, sdmmc_node, "bus-width", NULL); ++ if (cuint != NULL) { ++ switch (fdt32_to_cpu(*cuint)) { ++ case 4: ++ sdmmc2_params.bus_width = MMC_BUS_WIDTH_4; ++ break; ++ ++ case 8: ++ sdmmc2_params.bus_width = MMC_BUS_WIDTH_8; ++ break; ++ ++ default: ++ break; ++ } ++ } ++ ++ return 0; ++} ++ ++unsigned long long stm32_sdmmc2_mmc_get_device_size(void) ++{ ++ return sdmmc2_params.device_info->device_size; ++} ++ ++int stm32_sdmmc2_mmc_init(struct stm32_sdmmc2_params *params) ++{ ++ assert((params != NULL) && ++ ((params->reg_base & MMC_BLOCK_MASK) == 0U) && ++ ((params->bus_width == MMC_BUS_WIDTH_1) || ++ (params->bus_width == MMC_BUS_WIDTH_4) || ++ (params->bus_width == MMC_BUS_WIDTH_8))); ++ ++ memcpy(&sdmmc2_params, params, sizeof(struct stm32_sdmmc2_params)); ++ ++ if (stm32_sdmmc2_dt_get_config() != 0) { ++ ERROR("%s: DT error\n", __func__); ++ return -ENOMEM; ++ } ++ ++ stm32mp_clk_enable(sdmmc2_params.clock_id); ++ ++ stm32mp_reset_assert(sdmmc2_params.reset_id); ++ udelay(2); ++ stm32mp_reset_deassert(sdmmc2_params.reset_id); ++ mdelay(1); ++ ++ sdmmc2_params.clk_rate = stm32mp_clk_get_rate(sdmmc2_params.clock_id); ++ ++ return mmc_init(&stm32_sdmmc2_ops, sdmmc2_params.clk_rate, ++ sdmmc2_params.bus_width, sdmmc2_params.flags, ++ sdmmc2_params.device_info); ++} +diff --git a/drivers/st/nand/io_nand.c b/drivers/st/nand/io_nand.c +new file mode 100644 +index 0000000..54ac8fb +--- /dev/null ++++ b/drivers/st/nand/io_nand.c +@@ -0,0 +1,228 @@ ++/* ++ * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved. ++ * ++ * SPDX-License-Identifier: BSD-3-Clause ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* NAND device functions */ ++static int nand_dev_open(const uintptr_t init_params, io_dev_info_t **dev_info); ++static int nand_block_open(io_dev_info_t *dev_info, const uintptr_t spec, ++ io_entity_t *entity); ++static int nand_dev_init(io_dev_info_t *dev_info, const uintptr_t init_params); ++static int nand_block_seek(io_entity_t *entity, int mode, ++ signed long long offset); ++static int nand_block_read(io_entity_t *entity, uintptr_t buffer, ++ size_t length, size_t *length_read); ++static int nand_block_close(io_entity_t *entity); ++static int nand_dev_close(io_dev_info_t *dev_info); ++static io_type_t device_type_nand(void); ++ ++static NAND_HandleTypeDef *hnand; ++static uint64_t seek_offset; ++ ++static const io_dev_connector_t nand_dev_connector = { ++ .dev_open = nand_dev_open ++}; ++ ++static const io_dev_funcs_t nand_dev_funcs = { ++ .type = device_type_nand, ++ .open = nand_block_open, ++ .seek = nand_block_seek, ++ .size = NULL, ++ .read = nand_block_read, ++ .write = NULL, ++ .close = nand_block_close, ++ .dev_init = nand_dev_init, ++ .dev_close = nand_dev_close, ++}; ++ ++static const io_dev_info_t nand_dev_info = { ++ .funcs = &nand_dev_funcs, ++ .info = (uintptr_t)0, ++}; ++ ++/* Identify the device type as memmap */ ++static io_type_t device_type_nand(void) ++{ ++ return IO_TYPE_NAND; ++} ++ ++/* Open a connection to the nand device */ ++static int nand_dev_open(const uintptr_t init_params, io_dev_info_t **dev_info) ++{ ++ uint32_t nb_page_per_block, page_size; ++ ++ assert(dev_info); ++ *dev_info = (io_dev_info_t *)&nand_dev_info; ++ ++ hnand = (NAND_HandleTypeDef *)init_params; ++ ++ if (nand_initialize(hnand) != STD_OK) ++ return -EIO; ++ ++ hnand->Info.page_size_shift = 0; ++ ++ page_size = hnand->Info.PageSize; ++ if (!IS_POWER_OF_TWO(page_size)) ++ return -EINVAL; ++ ++ while (page_size >>= 1) ++ hnand->Info.page_size_shift++; ++ ++ nb_page_per_block = hnand->Info.BlockSize; ++ if (!IS_POWER_OF_TWO(nb_page_per_block)) ++ return -EINVAL; ++ ++ /* Block size is (page_size * number of pages per blocks) */ ++ hnand->Info.block_size_shift = hnand->Info.page_size_shift; ++ while (nb_page_per_block >>= 1) ++ hnand->Info.block_size_shift++; ++ ++ return 0; ++} ++ ++static int nand_dev_init(io_dev_info_t *dev_info, const uintptr_t init_params) ++{ ++ return 0; ++} ++ ++/* Close a connection to the nand device */ ++static int nand_dev_close(io_dev_info_t *dev_info) ++{ ++ return 0; ++} ++ ++/* Open a file on the nand device */ ++static int nand_block_open(io_dev_info_t *dev_info, const uintptr_t spec, ++ io_entity_t *entity) ++{ ++ seek_offset = 0; ++ return 0; ++} ++ ++/* Seek to a particular file offset on the nand device */ ++static int nand_block_seek(io_entity_t *entity, int mode, ++ signed long long offset) ++{ ++ seek_offset = offset; ++ return 0; ++} ++ ++/* Read data from a file on the nand device */ ++static int nand_block_read(io_entity_t *entity, uintptr_t buffer, ++ size_t length, size_t *length_read) ++{ ++ uint32_t block_size_shift = hnand->Info.block_size_shift; ++ uint32_t page_size_shift = hnand->Info.page_size_shift; ++ uint32_t buffer_index = 0; ++ uint32_t num_sectors_read = seek_offset / BCH_PAGE_SECTOR; ++ uint64_t number_sectors_to_read = length / BCH_PAGE_SECTOR; ++ uint64_t nand_address_block, nand_address_page; ++ NAND_AddressTypeDef nand_address; ++ ++ *length_read = 0; ++ ++ nand_address_block = seek_offset; ++ while (block_size_shift) { ++ nand_address_block >>= 1; ++ if (!nand_address_block) ++ break; ++ block_size_shift--; ++ } ++ ++ nand_address.Block = (uint16_t)nand_address_block; ++ ++ nand_address_page = seek_offset & ((1 << hnand->Info.block_size_shift) ++ - 1); ++ while (page_size_shift) { ++ nand_address_page >>= 1; ++ if (!nand_address_page) ++ break; ++ page_size_shift--; ++ } ++ ++ nand_address.Page = (uint16_t)nand_address_page; ++ ++ while (NAND_Check_Bad_Block(hnand, &nand_address) == BAD_BLOCK) { ++ nand_address.Block++; ++ if (nand_address.Block >= hnand->Info.BlockNb) { ++ ERROR("Cannot find valid block\n"); ++ return -EIO; ++ } ++ } ++ ++ if ((length % BCH_PAGE_SECTOR) != 0) { ++ /* ++ * yes, remainder required, ++ * adjust total number of sectors required ++ * one more page needed to read, ++ * data will not fill all page ++ */ ++ number_sectors_to_read += 1; ++ } ++ ++ /* ++ * Proceed here with reading/copying of ++ * (number_of_pages_remaining_to_read * BCH_PAGE_SECTOR) ++ * from NAND memory to SYSRAM download area ++ */ ++ while (number_sectors_to_read != 0) { ++ uint32_t bch_sector_nb = num_sectors_read % ++ (hnand->Info.PageSize / BCH_PAGE_SECTOR); ++ ++ if (NAND_Read_Logical_Page(hnand, &nand_address, ++ (uint8_t *)(buffer + ++ (buffer_index * ++ BCH_PAGE_SECTOR)), ++ bch_sector_nb) != STD_OK) { ++ VERBOSE("Page read failed or end of NAND reached\n"); ++ return -EIO; ++ } ++ ++ /* Increment read sectors number */ ++ num_sectors_read++; ++ buffer_index++; ++ ++ /* Decrement sectors to read */ ++ number_sectors_to_read--; ++ ++ /* Increment the NAND address */ ++ NAND_Address_Inc(hnand, &nand_address, num_sectors_read); ++ } ++ ++ *length_read = ((num_sectors_read - (seek_offset / BCH_PAGE_SECTOR)) * ++ BCH_PAGE_SECTOR); ++ ++ return 0; ++} ++ ++/* Close a file on the nand device */ ++static int nand_block_close(io_entity_t *entity) ++{ ++ return 0; ++} ++ ++/* Exported functions */ ++ ++/* Register the nand driver with the IO abstraction */ ++int register_io_dev_nand(const io_dev_connector_t **dev_con) ++{ ++ int result; ++ ++ assert(dev_con); ++ ++ result = io_register_device(&nand_dev_info); ++ if (!result) ++ *dev_con = &nand_dev_connector; ++ ++ return result; ++} +diff --git a/drivers/st/nand/nand.c b/drivers/st/nand/nand.c +new file mode 100644 +index 0000000..7f435cc +--- /dev/null ++++ b/drivers/st/nand/nand.c +@@ -0,0 +1,1548 @@ ++/* ++ ****************************************************************************** ++ * @file nand.c ++ * @author mgentilini - MCD IntroPack team - MPU AP v1 bootROM project ++ * @version V0.1 ++ * @date 28-April-2016 ++ * @brief Nand FMC driver module for STM32MP1. ++ ****************************************************************************** ++ * @attention ++ * ++ *

© COPYRIGHT(c) STMicroelectronics

++ * ++ * SPDX-License-Identifier: BSD-3-Clause ++ * ++ ****************************************************************************** ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* Other internal NAND driver definitions */ ++#define CMD_SECTION ((uint32_t)(1 << 16)) /* A16 high */ ++#define ADDR_SECTION ((uint32_t)(1 << 17)) /* A17 high */ ++#define DATA_SECTION (0) /* A16 and A17 low */ ++ ++#define EIGHT_BIT_ACCESS 0x0 ++#define SIXTEEN_BIT_ACCESS 0x1 ++ ++#define ONFI_SIG_VALUE 0x49464E4F /* "ONFI" */ ++#define EXT_PAGE_SIG_VALUE 0x53505045 /* "EPPS" */ ++ ++/* NAND instance number */ ++#define NAND_INSTANCE_NB 1 ++/* Wait Time following NAND_RESET command sent (30us) */ ++#define NAND_RST_TIMEOUT 30 ++#define NAND_READY_WAIT_TIMEOUT_VAL_250MS_AT_64MHz 16000000 ++ ++/* NAND ECC Calculation wait timeout */ ++#define NAND_ECC_CALCULATION_TIMEOUT_VAL_250MS ms2tick(250) ++ ++#define NAND_ECC_PAGE_SECTOR 512 ++#define NAND_ECC_HAMMING1 1 ++#define NAND_ECC_BCH4 4 ++#define NAND_ECC_BCH8 8 ++#define NAND_ECC_HAMMING1_BYTES_NB_8b 3 ++#define NAND_ECC_BCH4_BYTES_NB_8b 7 ++#define NAND_ECC_BCH8_BYTES_NB_8b 13 ++#define NAND_ECC_HAMMING1_BYTES_NB_16b 4 ++#define NAND_ECC_BCH4_BYTES_NB_16b 8 ++#define NAND_ECC_BCH8_BYTES_NB_16b 14 ++#define PARAM_PAGE_SIZE 256 ++ ++/* NAND memory status */ ++#define NAND_BUSY ((uint32_t)0x00000000U) ++#define NAND_ERROR ((uint32_t)0x00000001U) ++#define NAND_READY ((uint32_t)0x00000040U) ++ ++/* NAND ONFI commands */ ++#define NAND_CMD_RESET ((uint8_t)0xFFU) ++#define NAND_CMD_READID ((uint8_t)0x90U) ++#define NAND_CMD_READID_SIG_ADDR ((uint8_t)0x20U) ++#define NAND_CMD_READ_PARAM_PAGE ((uint8_t)0xECU) ++#define NAND_CMD_READ_1ST ((uint8_t)0x00U) ++#define NAND_CMD_READ_2ND ((uint8_t)0x30U) ++#define NAND_CMD_STATUS ((uint8_t)0x70U) ++#define NAND_CMD_CHANGE_1ST ((uint8_t)0x05U) ++#define NAND_CMD_CHANGE_2ND ((uint8_t)0xE0U) ++ ++/* CRC calculation */ ++#define CRC_POLYNOM 0x8005 ++#define CRC_INIT_VALUE 0x4F4E ++ ++static void nand_calc_timing(NAND_HandleTypeDef *hNand) ++{ ++ nand_timings *tims = &hNand->Info.timings; ++ unsigned long hclk = stm32mp_clk_get_rate(FMC_K); ++ unsigned long hclkp = FMC_NSEC_PER_SEC / (hclk / 1000); ++ int tar, tclr, thiz, twait, tset_mem, tset_att, thold_mem, thold_att; ++ ++ tar = hclkp; ++ if (tar < FMC_TAR_MIN) ++ tar = FMC_TAR_MIN; ++ tims->tar = div_round_up(tar, hclkp) - 1; ++ if (tims->tar > FMC_PCR_TIMING_MASK) ++ tims->tar = FMC_PCR_TIMING_MASK; ++ ++ tclr = hclkp; ++ if (tclr < FMC_TCLR_MIN) ++ tclr = FMC_TCLR_MIN; ++ tims->tclr = div_round_up(tclr, hclkp) - 1; ++ if (tims->tclr > FMC_PCR_TIMING_MASK) ++ tims->tclr = FMC_PCR_TIMING_MASK; ++ ++ tims->thiz = FMC_THIZ; ++ thiz = (tims->thiz + 1) * hclkp; ++ ++ /* ++ * tWAIT > tRP ++ * tWAIT > tWP ++ * tWAIT > tREA + tIO ++ */ ++ twait = hclkp; ++ if (twait < FMC_TRP_MIN) ++ twait = FMC_TRP_MIN; ++ if (twait < FMC_TWP_MIN) ++ twait = FMC_TWP_MIN; ++ if (twait < FMC_TREA_MAX + FMC_TIO) ++ twait = FMC_TREA_MAX + FMC_TIO; ++ tims->twait = div_round_up(twait, hclkp); ++ if (tims->twait == 0) ++ tims->twait = 1; ++ ++ /* ++ * tSETUP_MEM > tCS - tWAIT ++ * tSETUP_MEM > tALS - tWAIT ++ * tSETUP_MEM > tDS - (tWAIT - tHIZ) ++ */ ++ tset_mem = hclkp; ++ if (twait < FMC_TCS_MIN && (tset_mem < FMC_TCS_MIN - twait)) ++ tset_mem = FMC_TCS_MIN - twait; ++ if (twait < FMC_TALS_MIN && (tset_mem < FMC_TALS_MIN - twait)) ++ tset_mem = FMC_TALS_MIN - twait; ++ if (twait > thiz && (twait - thiz < FMC_TDS_MIN) && ++ (tset_mem < FMC_TDS_MIN - (twait - thiz))) ++ tset_mem = FMC_TDS_MIN - (twait - thiz); ++ tims->tset_mem = div_round_up(tset_mem, hclkp); ++ if (tims->tset_mem == 0) ++ tims->tset_mem = 1; ++ ++ /* ++ * tHOLD_MEM > tCH ++ * tHOLD_MEM > tREH - tSETUP_MEM ++ * tHOLD_MEM > max(tRC, tWC) - (tSETUP_MEM + tWAIT) ++ */ ++ thold_mem = hclkp; ++ if (thold_mem < FMC_TCH_MIN) ++ thold_mem = FMC_TCH_MIN; ++ if (tset_mem < FMC_TREH_MIN && ++ (thold_mem < FMC_TREH_MIN - tset_mem)) ++ thold_mem = FMC_TREH_MIN - tset_mem; ++ if ((tset_mem + twait < FMC_TRC_MIN) && ++ (thold_mem < FMC_TRC_MIN - (tset_mem + twait))) ++ thold_mem = FMC_TRC_MIN - (tset_mem + twait); ++ if ((tset_mem + twait < FMC_TWC_MIN) && ++ (thold_mem < FMC_TWC_MIN - (tset_mem + twait))) ++ thold_mem = FMC_TWC_MIN - (tset_mem + twait); ++ tims->thold_mem = div_round_up(thold_mem, hclkp); ++ if (tims->thold_mem == 0) ++ tims->thold_mem = 1; ++ ++ /* ++ * tSETUP_ATT > tCS - tWAIT ++ * tSETUP_ATT > tCLS - tWAIT ++ * tSETUP_ATT > tALS - tWAIT ++ * tSETUP_ATT > tRHW - tHOLD_MEM ++ * tSETUP_ATT > tDS - (tWAIT - tHIZ) ++ */ ++ tset_att = hclkp; ++ if (twait < FMC_TCS_MIN && (tset_att < FMC_TCS_MIN - twait)) ++ tset_att = FMC_TCS_MIN - twait; ++ if (twait < FMC_TCLS_MIN && (tset_att < FMC_TCLS_MIN - twait)) ++ tset_att = FMC_TCLS_MIN - twait; ++ if (twait < FMC_TALS_MIN && (tset_att < FMC_TALS_MIN - twait)) ++ tset_att = FMC_TALS_MIN - twait; ++ if (thold_mem < FMC_TRHW_MIN && ++ (tset_att < FMC_TRHW_MIN - thold_mem)) ++ tset_att = FMC_TRHW_MIN - thold_mem; ++ if (twait > thiz && (twait - thiz < FMC_TDS_MIN) && ++ (tset_att < FMC_TDS_MIN - (twait - thiz))) ++ tset_att = FMC_TDS_MIN - (twait - thiz); ++ tims->tset_att = div_round_up(tset_att, hclkp); ++ if (tims->tset_att == 0) ++ tims->tset_att = 1; ++ ++ /* ++ * tHOLD_ATT > tALH ++ * tHOLD_ATT > tCH ++ * tHOLD_ATT > tCLH ++ * tHOLD_ATT > tCOH ++ * tHOLD_ATT > tDH ++ * tHOLD_ATT > tWB + tIO + tSYNC - tSETUP_MEM ++ * tHOLD_ATT > tADL - tSETUP_MEM ++ * tHOLD_ATT > tWH - tSETUP_MEM ++ * tHOLD_ATT > tWHR - tSETUP_MEM ++ * tHOLD_ATT > tRC - (tSETUP_ATT + tWAIT) ++ * tHOLD_ATT > tWC - (tSETUP_ATT + tWAIT) ++ */ ++ thold_att = hclkp; ++ if (thold_att < FMC_TALH_MIN) ++ thold_att = FMC_TALH_MIN; ++ if (thold_att < FMC_TCH_MIN) ++ thold_att = FMC_TCH_MIN; ++ if (thold_att < FMC_TCLH_MIN) ++ thold_att = FMC_TCLH_MIN; ++ if (thold_att < FMC_TCOH_MIN) ++ thold_att = FMC_TCOH_MIN; ++ if (thold_att < FMC_TDH_MIN) ++ thold_att = FMC_TDH_MIN; ++ if ((FMC_TWB_MAX + FMC_TIO + FMC_TSYNC > tset_mem) && ++ (thold_att < FMC_TWB_MAX + FMC_TIO + FMC_TSYNC - tset_mem)) ++ thold_att = FMC_TWB_MAX + FMC_TIO + FMC_TSYNC - tset_mem; ++ if (tset_mem < FMC_TADL_MIN && ++ (thold_att < FMC_TADL_MIN - tset_mem)) ++ thold_att = FMC_TADL_MIN - tset_mem; ++ if (tset_mem < FMC_TWH_MIN && ++ (thold_att < FMC_TWH_MIN - tset_mem)) ++ thold_att = FMC_TWH_MIN - tset_mem; ++ if (tset_mem < FMC_TWHR_MIN && ++ (thold_att < FMC_TWHR_MIN - tset_mem)) ++ thold_att = FMC_TWHR_MIN - tset_mem; ++ if (tset_att + twait < FMC_TRC_MIN && ++ (thold_att < FMC_TRC_MIN - (tset_att + twait))) ++ thold_att = FMC_TRC_MIN - (tset_att + twait); ++ if (tset_att + twait < FMC_TWC_MIN && ++ (thold_att < FMC_TWC_MIN - (tset_att + twait))) ++ thold_att = FMC_TWC_MIN - (tset_att + twait); ++ tims->thold_att = div_round_up(thold_att, hclkp); ++ if (tims->thold_att == 0) ++ tims->thold_att = 1; ++} ++ ++/***************************************************************************** ++ * ++ * Function: Nand_Init ++ * ++ * Description: This function initializes the Nand FMC driver. ++ * ++ * Input parameters: NAND_HandleTypeDef * hNand ++ * uint32_t bus_width ++ * ++ * Output parameters: none ++ * ++ * Return: None ++ * ++ *****************************************************************************/ ++static void Nand_Init(NAND_HandleTypeDef *hNand, uint32_t bus_width, ++ uint32_t bch_algo) ++{ ++ assert(hNand); ++ ++ /* ++ * Initialize NAND control Interface ++ * Wait feature disabled, memory bank disabled, ECC logic disabled, ++ * BCH is selected, TCLR and TAR to max values, ECC sector size to 512B, ++ * BCH 8-bit is selected, enabled read access ++ * ++ * Be careful to not set ECCEN bit before Read Parameter Page command ++ * ECC logic must be enabled just before Read Logical Page ++ * Note: with PWAITEN feature, NAND controller temporizes next accesses, ++ * so no need to wait for ready/not busy after each command ++ */ ++ ++ /* ++ * Parameters should be given by boot_context ++ * Try to retrieve them with Nand_DetectAndInit ++ */ ++ if (!hNand->Info.PageSize) { ++ hNand->Instance->PCReg |= FMC_PCR_ECCALG | /* Select BCH */ ++ FMC_PCR_ECCSS_0 | /* ECCSS: Sector Size=512 bytes */ ++ FMC_PCR_BCHECC | ++ FMC_PCR_PWAITEN; ++ ++ hNand->Instance->PCReg &= ~FMC_PCR_PBKEN & ++ ~FMC_PCR_WE & ++ ~FMC_PCR_ECCSS_1 & /* ECCSS: Sector Size=512 bytes */ ++ ~FMC_PCR_ECCSS_2; /* ECCSS: Sector Size=512 bytes */ ++ ++ if (bus_width == SIXTEEN_BIT_ACCESS) { ++ hNand->Instance->PCReg |= FMC_PCR_PWID_0; ++ hNand->Instance->PCReg &= ~FMC_PCR_PWID_1; ++ } else { ++ hNand->Instance->PCReg &= ~FMC_PCR_PWID_0; ++ hNand->Instance->PCReg &= ~FMC_PCR_PWID_1; ++ } ++ ++ if (bch_algo == NAND_ECC_BCH4) { ++ /* BCH selected */ ++ hNand->Instance->PCReg |= FMC_PCR_ECCALG; ++ /* BCH4 selected */ ++ hNand->Instance->PCReg &= ~FMC_PCR_BCHECC; ++ } else if (bch_algo == NAND_ECC_BCH8) { ++ /* BCH selected */ ++ hNand->Instance->PCReg |= FMC_PCR_ECCALG; ++ /* BCH8 selected */ ++ hNand->Instance->PCReg |= FMC_PCR_BCHECC; ++ } else { ++ /* Hamming code selected */ ++ hNand->Instance->PCReg &= ~FMC_PCR_ECCALG; ++ } ++ } ++ ++ nand_calc_timing(hNand); ++ ++ /* Set tclr/tar timings */ ++ hNand->Instance->PCReg &= ++ ~FMC_PCR_TCLR_0 & /* tCLR: forced to value 0 */ ++ ~FMC_PCR_TCLR_1 & /* tCLR: forced to value 0 */ ++ ~FMC_PCR_TCLR_2 & /* tCLR: forced to value 0 */ ++ ~FMC_PCR_TCLR_3 & /* tCLR: forced to value 0 */ ++ ~FMC_PCR_TAR_0 & /* tAR: forced to value 0 */ ++ ~FMC_PCR_TAR_1 & /* tAR: forced to value 0 */ ++ ~FMC_PCR_TAR_2 & /* tAR: forced to value 0 */ ++ ~FMC_PCR_TAR_3; /* tAR: forced to value 0 */ ++ ++ hNand->Instance->PCReg |= FMC_PCR_TCLR(hNand->Info.timings.tclr); ++ hNand->Instance->PCReg |= FMC_PCR_TAR(hNand->Info.timings.tar); ++ ++ /* Set tset/twait/thold/thiz timings in common bank */ ++ hNand->Instance->PMEM = FMC_PMEM_MEMSET(hNand->Info.timings.tset_mem); ++ hNand->Instance->PMEM |= FMC_PMEM_MEMWAIT(hNand->Info.timings.twait); ++ hNand->Instance->PMEM |= ++ FMC_PMEM_MEMHOLD(hNand->Info.timings.thold_mem); ++ hNand->Instance->PMEM |= FMC_PMEM_MEMHIZ(hNand->Info.timings.thiz); ++ ++ /* Set tset/twait/thold/thiz timings in attribut bank */ ++ hNand->Instance->PATT = FMC_PATT_ATTSET(hNand->Info.timings.tset_att); ++ hNand->Instance->PATT |= FMC_PATT_ATTWAIT(hNand->Info.timings.twait); ++ hNand->Instance->PATT |= ++ FMC_PATT_ATTHOLD(hNand->Info.timings.thold_att); ++ hNand->Instance->PATT |= FMC_PATT_ATTHIZ(hNand->Info.timings.thiz); ++ ++ /* Enable the NAND device */ ++ hNand->Instance->PCReg |= FMC_PCR_PBKEN; ++ ++ /* Enable FMC Controller IP */ ++ hNand->Instance->BCR1 |= FMC_BCR1_FMCEN; ++} ++ ++/* ++ * @brief NAND memory read status ++ * @param hNand: pointer to a NAND_HandleTypeDef structure that contains ++ * the configuration information for NAND module. ++ * @retval NAND status ++ */ ++static uint32_t NAND_ReadStatus(NAND_HandleTypeDef *hNand) ++{ ++ uint32_t data; ++ uintptr_t deviceComMemAddr; ++ uintptr_t deviceAttrMemAddr; ++ ++ assert(hNand); ++ ++ /* Identify the device address */ ++ deviceComMemAddr = FLASH_COMMON_MEM_BASE; ++ deviceAttrMemAddr = FLASH_ATTRIB_MEM_BASE; ++ ++ /* Send Read status operation command */ ++ *(__IO uint8_t *)(deviceAttrMemAddr | CMD_SECTION) = ++ NAND_CMD_STATUS; ++ ++ /* Read status register data */ ++ data = *(__IO uint8_t *)deviceComMemAddr; ++ ++ /* Return the status */ ++ if ((data & NAND_ERROR) == NAND_ERROR) ++ return NAND_ERROR; ++ else if ((data & NAND_READY) == NAND_READY) ++ return NAND_READY; ++ ++ return NAND_BUSY; ++} ++ ++/***************************************************************************** ++ * ++ * Function: NAND_WaitReadyWithTimeout ++ * ++ * Description: This function wait with timeout of 250 ms until ++ * NAND Ready bit is set. ++ * Nand detection and initialization. ++ * ++ * Input parameters: NAND_HandleTypeDef * hNand ++ * ++ * Return: value 0 is no timeout occurred, value 1 if 250 ms ++ * wait timeout elapsed while waiting for NAND Ready ++ * flag to raise. ++ * ++ *****************************************************************************/ ++static uint32_t NAND_WaitReadyWithTimeout(NAND_HandleTypeDef *hNand) ++{ ++ uint32_t timerValInit = 0; ++ uint32_t timeoutDetected = 0; ++ ++ /* Is Nand handle NULL ? */ ++ assert(hNand); ++ ++ /* Get timer current value at start of loop */ ++ timerValInit = (uint32_t)read_cntpct_el0(); ++ ++ /* Wait NAND Ready by a read status command until response or */ ++ /* NAND Ready timeout elapses */ ++ /* timeout = 250ms @ 64 MHz of gentimer */ ++ while ((NAND_ReadStatus(hNand) != NAND_READY) && ++ (timeoutDetected == 0)) { ++ /* Check if timeout occurred */ ++ if (((uint32_t)read_cntpct_el0() - timerValInit) >= ++ NAND_READY_WAIT_TIMEOUT_VAL_250MS_AT_64MHz) ++ timeoutDetected = 1; ++ } ++ ++ return(timeoutDetected); ++} ++ ++/***************************************************************************** ++ * ++ * Function: Nand_Reset ++ * ++ * Description: Resets NAND Flash memory. ++ * ++ * Input parameters: NAND_HandleTypeDef * hNand ++ * ++ * Output parameters: none ++ * ++ * Return: Std_ReturnType ++ * ++ *****************************************************************************/ ++static Std_ReturnType Nand_Reset(NAND_HandleTypeDef *hNand) ++{ ++ Std_ReturnType retVal = STD_NOT_OK; ++ uintptr_t deviceAddress; ++ uint32_t timeoutDetected = 0; ++ ++ /* Is Nand handle NULL ? */ ++ assert(hNand); ++ ++ /* Identify the device address */ ++ deviceAddress = FLASH_COMMON_MEM_BASE; ++ ++ /* Send NAND reset command */ ++ /* Writes the command value in command section */ ++ *(uint8_t *)(deviceAddress | CMD_SECTION) = NAND_CMD_RESET; ++ ++ /* Wait the fixed 30 us time : after the NAND Reset command sent */ ++ /* 30us @ 64 MHz of gentimer */ ++ udelay(NAND_RST_TIMEOUT); ++ ++ /* Wait NANDReady with timeout 250 ms */ ++ timeoutDetected = NAND_WaitReadyWithTimeout(hNand); ++ ++ /* If no timeout occurred : the NAND Reset phase was successful */ ++ if (timeoutDetected == 0) ++ /* Set good status on exit */ ++ retVal = STD_OK; ++ ++ return retVal; ++} ++ ++/***************************************************************************** ++ * ++ * Function: Nand_ReadIDCode ++ * ++ * Description: This function reads the NAND ID code ++ * ++ * Input parameters: NAND_HandleTypeDef * hNand: NAND handle ++ * NAND_IDTypeDef * pNAND_ID: NAND ID structure ++ * ++ * Output parameters: none ++ * ++ * Return: None ++ * ++ *****************************************************************************/ ++static void Nand_ReadIDCode(NAND_HandleTypeDef *hNand, NAND_IDTypeDef *pNAND_ID) ++{ ++ uint32_t data; ++ uintptr_t deviceComMemAddr; ++ uintptr_t deviceAttrMemAddr; ++ ++ assert(hNand); ++ ++ /* Identify the device addresses */ ++ deviceComMemAddr = FLASH_COMMON_MEM_BASE; ++ deviceAttrMemAddr = FLASH_ATTRIB_MEM_BASE; ++ ++ /* Send Read ID command sequence */ ++ *(__IO uint8_t *)(deviceComMemAddr | CMD_SECTION) = NAND_CMD_READID; ++ *(__IO uint8_t *)(deviceAttrMemAddr | ADDR_SECTION) = 0x00; ++ ++ udelay(NAND_RST_TIMEOUT); ++ ++ /* Read the electronic signature from NAND flash */ ++ data = *(__IO uint16_t *)deviceComMemAddr; ++ ++ /* Return the data read */ ++ pNAND_ID->Maker_Id = (uint8_t)(data); ++ pNAND_ID->Device_Id = (uint8_t)(data >> 8); ++} ++ ++/** ++ * @brief NAND check CRC16 ++ * @param crc: initial CRC value ++ * @param data_in: pointer to buffer ++ * @param data_len: length of data ++ * @retval CRC 16 bits ++ */ ++static uint16_t NAND_CheckCrc16(uint16_t crc, uint8_t *data_in, ++ uint32_t data_len) ++{ ++ /* Algorithm from ONFI standard */ ++ ++ uint32_t i, j, bit; ++ ++ for (i = 0; i < data_len; i++) { ++ uint8_t curParam = *data_in++; ++ ++ for (j = 0x80; j != 0; j >>= 1) { ++ bit = crc & 0x8000; ++ crc <<= 1; ++ ++ if (curParam & j) ++ bit ^= 0x8000; ++ ++ if (bit) ++ crc ^= CRC_POLYNOM; ++ } ++ crc &= 0xFFFF; ++ } ++ ++ return crc; ++} ++ ++/***************************************************************************** ++ * ++ * Function: Nand_ReadParameterPage ++ * ++ * Description: This function reads the NAND parameter page ++ * (command 0xEC) ++ * The Read Parameter Page command retrieves ++ * the data structure that describes ++ * the targets organization, features, timings ++ * and other behavioral parameters. ++ * There may also be additional information ++ * provided in an extended parameter page. ++ * ++ * Input parameters: NAND_HandleTypeDef * hNand ++ * ++ * Output parameters: none ++ * ++ * Return: Std_ReturnType ++ * ++ *****************************************************************************/ ++static Std_ReturnType Nand_ReadParameterPage(NAND_HandleTypeDef *hNand) ++{ ++ uint32_t index; ++ uint8_t buffer[PARAM_PAGE_SIZE]; ++ uintptr_t deviceComMemAddr; ++ uintptr_t deviceAttrMemAddr; ++ int i; ++ uint16_t crc16; ++ ++ assert(hNand); ++ ++ /* Identify the device address */ ++ deviceComMemAddr = FLASH_COMMON_MEM_BASE; ++ deviceAttrMemAddr = FLASH_ATTRIB_MEM_BASE; ++ ++ /* Send ONFI Parameter Page Read sequence */ ++ *(uint8_t *)(deviceComMemAddr | CMD_SECTION) = NAND_CMD_READ_PARAM_PAGE; ++ *(uint8_t *)(deviceAttrMemAddr | ADDR_SECTION) = 0x00; ++ ++ udelay(NAND_RST_TIMEOUT); ++ ++ /* ++ * Read Parameter Page ++ * Note: There are three consecutive redondant copies ++ * of parameter page ++ */ ++ for (i = 0; i < 3; i++) { ++ /* Read parameter page from NAND flash */ ++ /* Get data */ ++ for (index = 0; index < PARAM_PAGE_SIZE; index++) ++ buffer[index] = *(uint8_t *)deviceComMemAddr; ++ ++ /* ++ * Bytes 0-4: Parameter page signature ++ * This field contains the parameter page signature. ++ * When two or more bytes of the signature are valid, ++ * then it denotes that a valid copy ++ * of the parameter page is present ++ */ ++ hNand->Info.Signature = (buffer[3] << 24) | (buffer[2] << 16) | ++ (buffer[1] << 8) | buffer[0]; ++ crc16 = (buffer[254] | buffer[255] << 8); ++ ++ if ((hNand->Info.Signature == ONFI_SIG_VALUE) && ++ (NAND_CheckCrc16(CRC_INIT_VALUE, buffer, ++ PARAM_PAGE_SIZE - 2) == crc16)) ++ break; ++ } ++ ++ if (i == 3) { ++ /* Could not find ONFI parameter page */ ++ INFO("%s: No Onfi Parameter Page\n", __func__); ++ return STD_NOT_OK; ++ } ++ ++ /* Byte 6, bit 0: data bus width (8 or 16) */ ++ hNand->Info.BusWidth = buffer[6] & 0x1; ++ ++ /* Bytes 80-83: Page size */ ++ hNand->Info.PageSize = (buffer[83] << 24) | (buffer[82] << 16) | ++ (buffer[81] << 8) | buffer[80]; ++ ++ /* Bytes 92-95 : Block size in number of pages */ ++ hNand->Info.BlockSize = (buffer[95] << 24) | (buffer[94] << 16) | ++ (buffer[93] << 8) | buffer[92]; ++ ++ /* Byte 96-99: Number of blocks per logical unit */ ++ hNand->Info.BlockNb = (buffer[99] << 24) | (buffer[98] << 16) | ++ (buffer[97] << 8) | buffer[96]; ++ ++ /* ++ * Byte 112: Number of bits ECC correctability ++ * This field indicates the number of bits that the host ++ * should be able to correct per 512 bytes of data ++ */ ++ if (buffer[112] != 0xFF) { ++ hNand->Info.ECCcorrectability = buffer[112]; ++ } else if ((buffer[4] != 1) && (buffer[4] != 2) && ++ buffer[6] & (1 << 7)) { ++ /* NAND ONFI, version > 2.1, with extended parameter page */ ++ uint32_t ext_page_size = ((buffer[13] << 8) | buffer[12]); ++ uint32_t ext_page_offset = buffer[14] * PARAM_PAGE_SIZE; ++ uint32_t ecc_block_offset = 32; ++ ++ /* Send ONFI Parameter Page Read sequence */ ++ *(uint8_t *)(deviceComMemAddr | CMD_SECTION) = ++ NAND_CMD_READ_PARAM_PAGE; ++ *(uint8_t *)(deviceAttrMemAddr | ADDR_SECTION) = 0x00; ++ ++ /* Skip ONFI parameter pages to read Extended parameter page */ ++ *(uint8_t *)(deviceComMemAddr | CMD_SECTION) = ++ NAND_CMD_CHANGE_1ST; ++ ++ *(uint8_t *)(deviceComMemAddr | ADDR_SECTION) = ++ ADDR_1ST_CYCLE(ext_page_offset); ++ ++ *(uint8_t *)(deviceAttrMemAddr | ADDR_SECTION) = ++ ADDR_2ND_CYCLE(ext_page_offset); ++ ++ *(uint8_t *)(deviceAttrMemAddr | CMD_SECTION) = ++ NAND_CMD_CHANGE_2ND; ++ ++ udelay(NAND_RST_TIMEOUT); ++ ++ /* Copy Extended parameter page */ ++ for (index = 0; index < PARAM_PAGE_SIZE; index++) ++ buffer[index] = *(uint8_t *)deviceComMemAddr; ++ ++ if (((buffer[5] << 24) | (buffer[4] << 16) | ++ (buffer[3] << 8) | buffer[2]) != EXT_PAGE_SIG_VALUE) { ++ WARN("Extended parameter page signature is wrong\n"); ++ return STD_NOT_OK; ++ } ++ ++ /* ++ * Extended parameter page can fit in buffer ++ * we can try to calculate its CRC ++ */ ++ if (ext_page_size <= PARAM_PAGE_SIZE) { ++ crc16 = (buffer[1] << 8) | buffer[0]; ++ ++ if (NAND_CheckCrc16(CRC_INIT_VALUE, buffer, ++ ext_page_size) != crc16) { ++ WARN("Extended page CRC failed\n"); ++ return STD_NOT_OK; ++ } ++ } ++ ++ /* ++ * Check the 8 sections of extended parameter page ++ * for an extended ECC information block (type = 2) ++ */ ++ for (i = 0; i < 8; i++) { ++ if (buffer[16 + 2 * i] == 2) ++ break; ++ ++ ecc_block_offset += buffer[17 + 2 * i]; ++ } ++ ++ if (i == 8) { ++ WARN("ECC extended block could not be found\n"); ++ return STD_NOT_OK; ++ } ++ ++ if (ext_page_size <= PARAM_PAGE_SIZE) { ++ /* ++ * ECC correctcatbility is the first byte ++ * of the ECC block ++ */ ++ hNand->Info.ECCcorrectability = ++ buffer[ecc_block_offset]; ++ } else { ++ /* Send ONFI Parameter Page Read sequence */ ++ *(uint8_t *)(deviceComMemAddr | CMD_SECTION) = ++ NAND_CMD_READ_PARAM_PAGE; ++ *(uint8_t *)(deviceAttrMemAddr | ADDR_SECTION) = 0x00; ++ ++ /* ++ * Skip ONFI parameter pages to read ++ * Extended parameter page ++ */ ++ *(uint8_t *)(deviceComMemAddr | CMD_SECTION) = ++ NAND_CMD_CHANGE_1ST; ++ *(uint8_t *)(deviceComMemAddr | ADDR_SECTION) = ++ ADDR_1ST_CYCLE(ext_page_offset + ++ ecc_block_offset); ++ ++ *(uint8_t *)(deviceAttrMemAddr | ADDR_SECTION) = ++ ADDR_2ND_CYCLE(ext_page_offset + ++ ecc_block_offset); ++ ++ *(uint8_t *)(deviceAttrMemAddr | CMD_SECTION) = ++ NAND_CMD_CHANGE_2ND; ++ ++ udelay(NAND_RST_TIMEOUT); ++ ++ hNand->Info.ECCcorrectability = ++ *(uint8_t *)deviceComMemAddr; ++ } ++ } else { ++ WARN("ECC correctability could not be found\n"); ++ return STD_NOT_OK; ++ } ++ ++ return STD_OK; ++} ++ ++/***************************************************************************** ++ * ++ * Function: Nand_DetectAndInit ++ * ++ * Description: This function initializes the Nand FMC driver. ++ * Nand detection and initialization. ++ * ++ * Input parameters: NAND_HandleTypeDef * hNand ++ * ++ * Output parameters: none ++ * ++ * Return: Std_ReturnType ++ * ++ *****************************************************************************/ ++static Std_ReturnType Nand_DetectAndInit(NAND_HandleTypeDef *hNand) ++{ ++ NAND_IDTypeDef pNAND_ID; ++ uint32_t nand_param_in_otp, result; ++ ++ assert(hNand); ++ ++ /* Remark : ReadID and ReadParameterPage are commands on 8-bit */ ++ ++ /* ReadID code */ ++ Nand_ReadIDCode(hNand, &pNAND_ID); ++ ++ /* Check if NAND parameters are stored in OTP */ ++ result = bsec_shadow_read_otp(&nand_param_in_otp, NAND_OTP); ++ if (result != BSEC_OK) { ++ ERROR("BSEC: NAND_OTP Error %i\n", result); ++ return STD_NOT_OK; ++ } ++ ++ if (nand_param_in_otp & NAND_PARAM_STORED_IN_OTP) { ++ /* ++ * NAND parameter shall be read from OTP ++ */ ++ hNand->Info.BusWidth = (nand_param_in_otp & NAND_WIDTH_MASK) >> ++ NAND_WIDTH_OFFSET; ++ ++ switch ((nand_param_in_otp & NAND_PAGE_SIZE_MASK) >> ++ NAND_PAGE_SIZE_OFFSET) { ++ case NAND_PAGE_SIZE_2K: ++ hNand->Info.PageSize = 2048; ++ break; ++ ++ case NAND_PAGE_SIZE_4K: ++ hNand->Info.PageSize = 4096; ++ break; ++ ++ case NAND_PAGE_SIZE_8K: ++ hNand->Info.PageSize = 8192; ++ break; ++ ++ default: ++ hNand->Info.PageSize = 0; ++ ERROR("Cannot read NAND page size\n"); ++ return STD_NOT_OK; ++ } ++ ++ switch ((nand_param_in_otp & NAND_BLOCK_SIZE_MASK) >> ++ NAND_BLOCK_SIZE_OFFSET) { ++ case NAND_BLOCK_SIZE_64_PAGES: ++ hNand->Info.BlockSize = 64; ++ break; ++ ++ case NAND_BLOCK_SIZE_128_PAGES: ++ hNand->Info.BlockSize = 128; ++ break; ++ ++ case NAND_BLOCK_SIZE_256_PAGES: ++ hNand->Info.BlockSize = 256; ++ break; ++ ++ default: ++ hNand->Info.BlockSize = 0; ++ ERROR("Cannot read NAND block size\n"); ++ return STD_NOT_OK; ++ } ++ ++ hNand->Info.BlockNb = ((nand_param_in_otp & ++ NAND_BLOCK_NB_MASK) >> ++ NAND_BLOCK_NB_OFFSET) * ++ NAND_BLOCK_NB_UNIT; ++ ++ switch ((nand_param_in_otp & NAND_ECC_BIT_NB_MASK) >> ++ NAND_ECC_BIT_NB_OFFSET) { ++ case NAND_ECC_BIT_NB_UNSET: ++ hNand->Info.ECCcorrectability = 0; ++ break; ++ ++ case NAND_ECC_BIT_NB_1_BITS: ++ hNand->Info.ECCcorrectability = 1; ++ break; ++ ++ case NAND_ECC_BIT_NB_4_BITS: ++ hNand->Info.ECCcorrectability = 4; ++ break; ++ ++ case NAND_ECC_BIT_NB_8_BITS: ++ hNand->Info.ECCcorrectability = 8; ++ break; ++ ++ default: ++ hNand->Info.ECCcorrectability = 0; ++ ERROR("Cannot read ECCbit number\n"); ++ return STD_NOT_OK; ++ } ++ } else { ++ /* ++ * ONFI or 'ONFI compliant' NAND ++ * 'ONFI compliant' means that parameters used by bootrom are ++ * available in parameter table at same offsets as in a ++ * ONFI parameter table. ++ * NAND parameter shall be read from Parameter table. ++ */ ++ ++ uint32_t onfi_ecc; ++ ++ /* Read Nand parameter page */ ++ if (Nand_ReadParameterPage(hNand) != STD_OK) { ++ ERROR("%s: NAND not initialized\n", __func__); ++ return STD_NOT_OK; ++ } ++ ++ onfi_ecc = hNand->Info.ECCcorrectability; ++ ++ /* ++ * For ONFI nand, ECC number of bits may be overridden by a ++ * value from OTP configuration. ++ */ ++ switch ((nand_param_in_otp & NAND_ECC_BIT_NB_MASK) >> ++ NAND_ECC_BIT_NB_OFFSET) { ++ case NAND_ECC_BIT_NB_UNSET: ++ hNand->Info.ECCcorrectability = 0; ++ break; ++ ++ case NAND_ECC_BIT_NB_1_BITS: ++ hNand->Info.ECCcorrectability = 1; ++ break; ++ ++ case NAND_ECC_BIT_NB_4_BITS: ++ hNand->Info.ECCcorrectability = 4; ++ break; ++ ++ case NAND_ECC_BIT_NB_8_BITS: ++ hNand->Info.ECCcorrectability = 8; ++ break; ++ ++ default: ++ hNand->Info.ECCcorrectability = 0; ++ break; ++ } ++ ++ /* ++ * if OTP info is wrong, fall back to parameter read in ONFI ++ * parameter page ++ */ ++ if (hNand->Info.ECCcorrectability == 0) ++ hNand->Info.ECCcorrectability = onfi_ecc; ++ } ++ ++ Nand_Init(hNand, hNand->Info.BusWidth, hNand->Info.ECCcorrectability); ++ ++ /* Now NAND Flash is detected and initialized */ ++ return STD_OK; ++} ++ ++/** ++ * @brief NAND read page command sequence ++ * @param hNand: pointer to a NAND_HandleTypeDef structure that contains ++ * the configuration information for NAND module. ++ * @param colAddr: column address ++ * @param rowAddr: row address ++ * @retval Std_ReturnType ++ */ ++static void NAND_Read_Page_Cmd(NAND_HandleTypeDef *hNand, uint32_t colAddr, ++ uint32_t rowAddr) ++{ ++ uintptr_t deviceComMemAddr; ++ uintptr_t deviceAttrMemAddr; ++ ++ assert(hNand); ++ ++ /* Identify the device address */ ++ deviceComMemAddr = FLASH_COMMON_MEM_BASE; ++ deviceAttrMemAddr = FLASH_ATTRIB_MEM_BASE; ++ ++ /* If NAND 8bit */ ++ if (hNand->Info.BusWidth == EIGHT_BIT_ACCESS) { ++ *(__IO uint8_t *)(deviceComMemAddr | CMD_SECTION) = ++ NAND_CMD_READ_1ST; ++ ++ /* C1 */ ++ *(__IO uint8_t *)(deviceComMemAddr | ADDR_SECTION) = ++ ADDR_1ST_CYCLE(colAddr); ++ /* C2 */ ++ *(__IO uint8_t *)(deviceComMemAddr | ADDR_SECTION) = ++ ADDR_2ND_CYCLE(colAddr); ++ /* R1 */ ++ *(__IO uint8_t *)(deviceComMemAddr | ADDR_SECTION) = ++ ADDR_1ST_CYCLE(rowAddr); ++ /* R2 */ ++ *(__IO uint8_t *)(deviceComMemAddr | ADDR_SECTION) = ++ ADDR_2ND_CYCLE(rowAddr); ++ ++ /* R3 */ ++ *(__IO uint8_t *)(deviceAttrMemAddr | ADDR_SECTION) = ++ ADDR_3RD_CYCLE(rowAddr); ++ ++ *(__IO uint8_t *)(deviceAttrMemAddr | CMD_SECTION) = ++ NAND_CMD_READ_2ND; ++ } else { ++ /* NAND 16bit */ ++ *(__IO uint16_t *)(deviceComMemAddr | CMD_SECTION) = ++ NAND_CMD_READ_1ST; ++ ++ /* C1 */ ++ *(__IO uint16_t *)(deviceComMemAddr | ADDR_SECTION) = ++ ADDR_1ST_CYCLE(colAddr); ++ /* C2 */ ++ *(__IO uint16_t *)(deviceComMemAddr | ADDR_SECTION) = ++ ADDR_2ND_CYCLE(colAddr); ++ /* R1 */ ++ *(__IO uint16_t *)(deviceComMemAddr | ADDR_SECTION) = ++ ADDR_1ST_CYCLE(rowAddr); ++ /* R2 */ ++ *(__IO uint16_t *)(deviceComMemAddr | ADDR_SECTION) = ++ ADDR_2ND_CYCLE(rowAddr); ++ ++ /* R3 */ ++ *(__IO uint16_t *)(deviceAttrMemAddr | ADDR_SECTION) = ++ ADDR_3RD_CYCLE(rowAddr); ++ ++ *(__IO uint16_t *)(deviceAttrMemAddr | CMD_SECTION) = ++ NAND_CMD_READ_2ND; ++ } ++} ++ ++/***************************************************************************** ++ * ++ * Function: _bit_count ++ * ++ * Description: Return the number of bits set to one in a 32bit word ++ * ++ * Input parameters: v 32 bit word ++ * ++ * Return: number of bits set to one in v. ++ * ++ *****************************************************************************/ ++static uint32_t _bit_count(uint32_t v) ++{ ++ uint32_t c = 0; ++ ++ for (uint32_t i = 0; i < CHAR_BIT * sizeof(typeof(v)); i++) ++ if (v & (BIT(i))) ++ c++; ++ ++ return c; ++} ++ ++/***************************************************************************** ++ * ++ * Function: NAND_Hamming_Correction ++ * ++ * Description: Consider Hamming correction code, and apply correction ++ * if needed and possible. ++ * ++ * Input parameters: Buffer : pointer to buffer containing data read. ++ * EccBuffer : pointer to buffer containing ecc code read ++ * from out of band area. ++ * EccCalculated : ECC calculated by FMC during reading of ++ * data. ++ * ++ * Return: 0 no error detected ++ * 1 one error detected and correted ++ * > 1 unrecoverable error ++ * -1 ecc error ++ * ++ *****************************************************************************/ ++static int NAND_Hamming_Correction(uint8_t *Buffer, uint8_t *EccBuffer, ++ uint32_t EccCalculated) ++{ ++ uint8_t xor_ecc_ones; ++ uint16_t xor_ecc_1b, xor_ecc_2b, xor_ecc_3b; ++ union { ++ uint32_t val; ++ uint8_t bytes[4]; ++ } xor_ecc; ++ ++ /* Page size--------ECC_Code Size ++ * 256---------------22 bits LSB (ECC_CODE & 0x003FFFFF) ++ * 512---------------24 bits (ECC_CODE & 0x00FFFFFF) ++ * 1024--------------26 bits (ECC_CODE & 0x03FFFFFF) ++ * 2048--------------28 bits (ECC_CODE & 0x0FFFFFFF) ++ * 4096--------------30 bits (ECC_CODE & 0x3FFFFFFF) ++ * 8192--------------32 bits (ECC_CODE & 0xFFFFFFFF) ++ */ ++ ++ /* For Page size 512, ECC_Code size 24 bits */ ++ xor_ecc_1b = (EccCalculated & 0x000000FF) ^ EccBuffer[0]; ++ xor_ecc_2b = ((EccCalculated & 0x0000FF00) >> 8) ^ EccBuffer[1]; ++ xor_ecc_3b = ((EccCalculated & 0x00FF0000) >> 16) ^ EccBuffer[2]; ++ ++ xor_ecc.val = 0L; ++ xor_ecc.bytes[2] = xor_ecc_3b; ++ xor_ecc.bytes[1] = xor_ecc_2b; ++ xor_ecc.bytes[0] = xor_ecc_1b; ++ ++ if (xor_ecc.val == 0) ++ return 0; /* No Error */ ++ ++ xor_ecc_ones = _bit_count(xor_ecc.val); ++ if (xor_ecc_ones < 23) { ++ if (xor_ecc_ones == 12) { ++ uint16_t bit_address, byte_address; ++ ++ /* Correctable ERROR */ ++ bit_address = ((xor_ecc_1b >> 1) & 0x01) | ++ ((xor_ecc_1b >> 2) & 0x02) | ++ ((xor_ecc_1b >> 3) & 0x04); ++ ++ byte_address = ((xor_ecc_1b >> 7) & 0x01) | ++ ((xor_ecc_2b) & 0x02) | ++ ((xor_ecc_2b >> 1) & 0x04) | ++ ((xor_ecc_2b >> 2) & 0x08) | ++ ((xor_ecc_2b >> 3) & 0x10) | ++ ((xor_ecc_3b << 4) & 0x20) | ++ ((xor_ecc_3b << 3) & 0x40) | ++ ((xor_ecc_3b << 2) & 0x80) | ++ ((xor_ecc_3b << 1) & 0x100); ++ ++ /* Correct bit error in the data */ ++ Buffer[byte_address] = (Buffer[byte_address]) ^ ++ ((uint8_t)(1 << bit_address)); ++ INFO("Hamming: 1 ECC error corrected\n"); ++ return 1; ++ } ++ ++ /* Non Correctable ERROR */ ++ ERROR("%s: Uncorrectable ECC Errors\n", __func__); ++ return 2; ++ } ++ ++ /* ECC ERROR */ ++ ERROR("%s: Hamming correction error\n", __func__); ++ return -1; ++} ++ ++/***************************************************************************** ++ * ++ * Function: NAND_Read_Logical_Page ++ * ++ * Description: Read 512B sector from NAND memory page ++ * ++ * Input parameters: hNand: pointer to a NAND_HandleTypeDef structure ++ * that contains the configuration information ++ * for NAND module. ++ * Address : pointer to NAND address structure ++ * Buffer : pointer to destination read buffer ++ * bch_sector_nb : 512B sector number in the page ++ * ++ * ++ * Return: Std_ReturnType ++ * ++ *****************************************************************************/ ++Std_ReturnType NAND_Read_Logical_Page(NAND_HandleTypeDef *hNand, ++ NAND_AddressTypeDef *Address, ++ uint8_t *Buffer, uint32_t bch_sector_nb) ++{ ++ uintptr_t deviceComMemAddr; ++ uintptr_t deviceAttrMemAddr; ++ uint32_t size = 0; ++ uint32_t index, bloc_nb, nb_pages_per_block, offset; ++ uint32_t ecc_size = 0; ++ uint32_t rowAddr = 0, colAddr = 0; ++ uint8_t EccBuffer[NAND_ECC_BCH8_BYTES_NB_16b]; ++ uint32_t heccr = 0; ++ ++ assert(hNand); ++ ++ /* Identify the device address */ ++ deviceComMemAddr = FLASH_COMMON_MEM_BASE; ++ deviceAttrMemAddr = FLASH_ATTRIB_MEM_BASE; ++ ++ bloc_nb = Address->Block; ++ nb_pages_per_block = hNand->Info.BlockSize; ++ ++ /* Page and block to be read */ ++ rowAddr = (bloc_nb * nb_pages_per_block) + Address->Page; ++ ++ /* If NAND 8bit */ ++ if (hNand->Info.BusWidth == EIGHT_BIT_ACCESS) { ++ /* Byte or word in page to be read */ ++ colAddr = bch_sector_nb * NAND_ECC_PAGE_SECTOR; ++ ++ size = NAND_ECC_PAGE_SECTOR; ++ } else { ++ /* If NAND 16bit */ ++ /* Byte or word in page to be read */ ++ colAddr = (bch_sector_nb * NAND_ECC_PAGE_SECTOR) / 2; ++ ++ size = NAND_ECC_PAGE_SECTOR / 2; ++ } ++ ++ /* Reset ECC enabling */ ++ hNand->Instance->PCReg &= ~FMC_PCR_ECCEN; ++ hNand->Instance->PCReg &= ~FMC_PCR_WE; ++ hNand->Instance->PCReg |= FMC_PCR_ECCEN; ++ ++ /* Clear status */ ++ hNand->Instance->BCHICR = 0x1F; ++ ++ /* Send read page command sequence */ ++ NAND_Read_Page_Cmd(hNand, colAddr, rowAddr); ++ ++ /* Get data into destination buffer */ ++ /* If NAND 8bit */ ++ if (hNand->Info.BusWidth == EIGHT_BIT_ACCESS) { ++ uint8_t *Buffer8b = (uint8_t *)Buffer; ++ ++ for (index = 0; index < size; index++) ++ *Buffer8b++ = *(uint8_t *)deviceComMemAddr; ++ } else { ++ /* If NAND 16bit */ ++ uint16_t *Buffer16b = (uint16_t *)Buffer; ++ ++ for (index = 0; index < size; index++) ++ *Buffer16b++ = *(uint16_t *)deviceComMemAddr; ++ } ++ ++ if (hNand->Info.ECCcorrectability == NAND_ECC_HAMMING1) { ++ /* During read of data , syndrome is calculated */ ++ /* Wait until decoding error is ready */ ++ uint32_t timerValInit = read_cntpct_el0(); ++ ++ while ((hNand->Instance->SR & FMC_SR_NWRF) != FMC_SR_NWRF) { ++ if ((read_cntpct_el0() - timerValInit) > ++ NAND_ECC_CALCULATION_TIMEOUT_VAL_250MS) { ++ ERROR("%s: syndrome calculation timeout\n", ++ __func__); ++ return STD_NOT_OK; ++ } ++ } ++ ++ heccr = hNand->Instance->HECCR; ++ } ++ ++ /* Read now corresponding ECC bytes (7 or 13) in spare area */ ++ /* Page and block to be read */ ++ ++ if (hNand->Info.ECCcorrectability == NAND_ECC_BCH4) { ++ if (hNand->Info.BusWidth == EIGHT_BIT_ACCESS) ++ ecc_size = NAND_ECC_BCH4_BYTES_NB_8b; ++ else ++ ecc_size = NAND_ECC_BCH4_BYTES_NB_16b; ++ } else if (hNand->Info.ECCcorrectability == NAND_ECC_BCH8) { ++ if (hNand->Info.BusWidth == EIGHT_BIT_ACCESS) ++ ecc_size = NAND_ECC_BCH8_BYTES_NB_8b; ++ else ++ ecc_size = NAND_ECC_BCH8_BYTES_NB_16b; ++ } else { ++ if (hNand->Info.BusWidth == EIGHT_BIT_ACCESS) ++ ecc_size = NAND_ECC_HAMMING1_BYTES_NB_8b; ++ else ++ ecc_size = NAND_ECC_HAMMING1_BYTES_NB_16b; ++ } ++ ++ offset = 2; ++ ++ /* If NAND 8bit */ ++ if (hNand->Info.BusWidth == EIGHT_BIT_ACCESS) { ++ /* Byte or word in page to be read */ ++ /* See SRS mapping */ ++ colAddr = hNand->Info.PageSize + offset + ++ (bch_sector_nb * ecc_size); ++ } else { ++ /* If NAND 16bit */ ++ /* Byte or word in page to be read */ ++ /* See SRS mapping */ ++ colAddr = (hNand->Info.PageSize + offset + ++ (bch_sector_nb * ecc_size)) / 2; ++ } ++ ++ /* Send change read column command */ ++ if (hNand->Info.BusWidth == EIGHT_BIT_ACCESS) { ++ *(__IO uint8_t *)(deviceComMemAddr | CMD_SECTION) = ++ NAND_CMD_CHANGE_1ST; ++ ++ /* C1 */ ++ *(__IO uint8_t *)(deviceComMemAddr | ADDR_SECTION) = ++ ADDR_1ST_CYCLE(colAddr); ++ /* C2 */ ++ *(__IO uint8_t *)(deviceAttrMemAddr | ADDR_SECTION) = ++ ADDR_2ND_CYCLE(colAddr); ++ ++ *(__IO uint8_t *)(deviceAttrMemAddr | CMD_SECTION) = ++ NAND_CMD_CHANGE_2ND; ++ } else { ++ *(__IO uint16_t *)(deviceComMemAddr | CMD_SECTION) = ++ NAND_CMD_CHANGE_1ST; ++ ++ /* C1 */ ++ *(__IO uint16_t *)(deviceComMemAddr | ADDR_SECTION) = ++ ADDR_1ST_CYCLE(colAddr); ++ /* C2 */ ++ *(__IO uint16_t *)(deviceAttrMemAddr | ADDR_SECTION) = ++ ADDR_2ND_CYCLE(colAddr); ++ ++ *(__IO uint16_t *)(deviceAttrMemAddr | CMD_SECTION) = ++ NAND_CMD_CHANGE_2ND; ++ } ++ ++ /* Get data into destination EccBuffer */ ++ ++ /* If NAND 8bit */ ++ if (hNand->Info.BusWidth == EIGHT_BIT_ACCESS) { ++ uint8_t *pEccBuffer = EccBuffer; ++ ++ for (index = 0; index < ecc_size; index++) ++ *(uint8_t *)pEccBuffer++ = *(uint8_t *)deviceComMemAddr; ++ } else { ++ /* If NAND 16bit */ ++ uint16_t *pEccBuffer16b = (uint16_t *)(EccBuffer); ++ ++ for (index = 0; index < ecc_size / 2; index++) { ++ *(uint16_t *)pEccBuffer16b++ = ++ *(uint16_t *)deviceComMemAddr; ++ } ++ } ++ ++ if (hNand->Info.ECCcorrectability == NAND_ECC_HAMMING1) { ++ int nb_errors; ++ ++ nb_errors = NAND_Hamming_Correction(Buffer, EccBuffer, ++ heccr); ++ if ((nb_errors != 0) && (nb_errors != 1)) ++ return STD_NOT_OK; ++ ++ } else /* BCH error correction */ { ++ uint32_t ecc_errors_nb; ++ uint32_t i; ++ uint32_t errorPosition[8]; ++ ++ /* ++ * During read of data and parity bits, syndrome is calculated, ++ * then error location is launched ++ * Wait until decoding error is ready ++ */ ++ uint32_t timerValInit = (uint32_t)read_cntpct_el0(); ++ ++ while ((hNand->Instance->BCHISR & FMC_BCHISR_DERF) != ++ FMC_BCHISR_DERF) { ++ if (((uint32_t)read_cntpct_el0() - timerValInit) > ++ NAND_ECC_CALCULATION_TIMEOUT_VAL_250MS) ++ return STD_NOT_OK; ++ } ++ ++ /* Read decoding results */ ++ /* Check if there were uncorrectable errors */ ++ if (hNand->Instance->BCHISR & FMC_BCHISR_DUEF) { ++ VERBOSE("%s: Uncorrectable ECC Error\n", __func__); ++ return STD_NOT_OK; ++ } ++ ++ /* Check if there were errors */ ++ if (!(hNand->Instance->BCHISR & FMC_BCHISR_DEFF)) ++ return STD_OK; ++ ++ /* Read number of errors */ ++ ecc_errors_nb = hNand->Instance->BCHSR & FMC_BCHSR_DEN; ++ ++ VERBOSE("%s: ECC Errors detected: %d\n", __func__, ++ ecc_errors_nb); ++ ++ /* Retrieve the error position corresponding to the error ++ * number ++ */ ++ /* Error 1 position : FMC_BCHDSR1.EBP1 */ ++ errorPosition[0] = hNand->Instance->BCHDSR1 & FMC_BCHDSR1_EBP1; ++ /* Error 2 position : FMC_BCHDSR1.EBP2 */ ++ errorPosition[1] = (hNand->Instance->BCHDSR1 & FMC_BCHDSR1_EBP2) ++ >> FMC_EBP2_MASK; ++ /* Error 3 position : FMC_BCHDSR2.EBP1 */ ++ errorPosition[2] = hNand->Instance->BCHDSR2 & FMC_BCHDSR2_EBP1; ++ /* Error 4 position : FMC_BCHDSR2.EBP2 */ ++ errorPosition[3] = (hNand->Instance->BCHDSR2 & FMC_BCHDSR2_EBP2) ++ >> FMC_EBP2_MASK; ++ /* Error 5 position : FMC_BCHDSR3.EBP1 */ ++ errorPosition[4] = hNand->Instance->BCHDSR3 & FMC_BCHDSR3_EBP1; ++ /* Error 6 position : FMC_BCHDSR3.EBP2 */ ++ errorPosition[5] = (hNand->Instance->BCHDSR3 & FMC_BCHDSR3_EBP2) ++ >> FMC_EBP2_MASK; ++ /* Error 7 position : FMC_BCHDSR4.EBP1 */ ++ errorPosition[6] = hNand->Instance->BCHDSR4 & FMC_BCHDSR4_EBP1; ++ /* Error 8 position : FMC_BCHDSR4.EBP2 */ ++ errorPosition[7] = (hNand->Instance->BCHDSR4 & FMC_BCHDSR4_EBP2) ++ >> FMC_EBP2_MASK; ++ ++ /* Error position indicates error bit number in binary */ ++ /* Retrieve the mask of the wrong bit to correct */ ++ for (i = 0; i < ecc_errors_nb; i++) { ++ VERBOSE("%s: ECC Error position: %d\n", __func__, ++ errorPosition[i]); ++ /* Correct only if error is in data area */ ++ if (errorPosition[i] < 0x1000) { ++ /* ++ * Retrieve the mask of the wrong bit ++ * to correct ++ */ ++ uint32_t bitMask = BIT(errorPosition[i] & 0x07); ++ ++ /* ++ * Remove bit postion in the error position ++ * (to have byte to correct) ++ */ ++ errorPosition[i] >>= 0x03; ++ VERBOSE("%s: ECC Error in data area\n", ++ __func__); ++ ++ /* Fix the error : invert the wrong bit */ ++ *(Buffer + errorPosition[i]) ^= bitMask; ++ } else { ++ VERBOSE("%s: ECC Error not in data area\n", ++ __func__); ++ } ++ } ++ } ++ ++ return STD_OK; ++} ++ ++/** ++ * @brief NAND check bad blck ++ * @param hNand: pointer to a NAND_HandleTypeDef structure that contains ++ * the configuration information for NAND module. ++ * Address: pointer to NAND address structure ++ * @retval BAD_BLOCK or GOOD_BLOCK ++ */ ++uint32_t NAND_Check_Bad_Block(NAND_HandleTypeDef *hNand, ++ NAND_AddressTypeDef *Address) ++{ ++ uintptr_t deviceComMemAddr = 0; ++ uint32_t bloc_nb = 0; ++ uint32_t nb_pages_per_block = 0; ++ uint32_t page_nb; ++ uint32_t block_status = BAD_BLOCK; ++ uint32_t rowAddr = 0, colAddr = 0; ++ uint8_t bbm_marker, bbm_marker_2; ++ uint16_t bbm_marker16b; ++ ++ assert(hNand); ++ ++ /* Identify the device address */ ++ deviceComMemAddr = FLASH_COMMON_MEM_BASE; ++ ++ /* ++ * Bad block indication is is the 2 first bytes of the 1st ++ * or 2nd page of the block (depends on manufacturer) ++ */ ++ ++ /* ++ * Read the 2 first bytes of the spare area ++ * of the 1st page of the block ++ */ ++ bloc_nb = Address->Block; ++ nb_pages_per_block = hNand->Info.BlockSize; ++ ++ /* Page and block to be read */ ++ page_nb = 0; ++ rowAddr = (bloc_nb * nb_pages_per_block) + page_nb; ++ ++ /* If NAND 8bit */ ++ if (hNand->Info.BusWidth == EIGHT_BIT_ACCESS) { ++ /* Byte or word in page to be read */ ++ colAddr = hNand->Info.PageSize; ++ } else { ++ /* If NAND 16bit */ ++ /* Byte or word in page to be read */ ++ colAddr = hNand->Info.PageSize / 2; ++ } ++ ++ /* Send read page command sequence */ ++ NAND_Read_Page_Cmd(hNand, colAddr, rowAddr); ++ ++ udelay(NAND_RST_TIMEOUT); ++ ++ /* Get data into destination buffer */ ++ /* If NAND 8bit */ ++ if (hNand->Info.BusWidth == EIGHT_BIT_ACCESS) { ++ bbm_marker = *(uint8_t *)deviceComMemAddr; ++ bbm_marker_2 = *(uint8_t *)deviceComMemAddr; ++ ++ if ((bbm_marker != 0xFF) || (bbm_marker_2 != 0xFF)) ++ block_status = BAD_BLOCK; ++ else ++ block_status = GOOD_BLOCK; ++ ++ } else { ++ /* If NAND 16bit */ ++ bbm_marker16b = *(uint16_t *)deviceComMemAddr; ++ ++ if (bbm_marker16b != 0xFFFF) ++ block_status = BAD_BLOCK; ++ else ++ block_status = GOOD_BLOCK; ++ } ++ ++ if (block_status == BAD_BLOCK) ++ return block_status; ++ ++ /* ++ * Read the 2 first bytes of the spare area of the 2nd page ++ * of the block ++ * Page and block to be read ++ */ ++ page_nb = 1; ++ rowAddr = (bloc_nb * nb_pages_per_block) + page_nb; ++ ++ /* Send read page command sequence */ ++ NAND_Read_Page_Cmd(hNand, colAddr, rowAddr); ++ ++ udelay(NAND_RST_TIMEOUT); ++ ++ /* Get data into destination buffer */ ++ /* If NAND 8bit */ ++ if (hNand->Info.BusWidth == EIGHT_BIT_ACCESS) { ++ bbm_marker = *(uint8_t *)deviceComMemAddr; ++ bbm_marker_2 = *(uint8_t *)deviceComMemAddr; ++ ++ if ((bbm_marker == 0xFF) && (bbm_marker_2 == 0xFF)) ++ block_status = GOOD_BLOCK; ++ else ++ block_status = BAD_BLOCK; ++ } else { ++ /* If NAND 16bit */ ++ bbm_marker16b = *(uint16_t *)deviceComMemAddr; ++ ++ if (bbm_marker16b == 0xFFFF) ++ block_status = GOOD_BLOCK; ++ else ++ block_status = BAD_BLOCK; ++ } ++ ++ return block_status; ++} ++ ++/** ++ * @brief Increment the NAND memory address ++ * @param hNand: pointer to a NAND_HandleTypeDef structure that contains ++ * the configuration information for NAND module. ++ * @param Address: pointer to NAND address structure ++ * @retval Std_ReturnType ++ */ ++Std_ReturnType NAND_Address_Inc(NAND_HandleTypeDef *hNand, ++ NAND_AddressTypeDef *Address, ++ uint32_t numPagesRead) ++{ ++ assert(hNand); ++ ++ /* Increment page address */ ++ if ((numPagesRead % (hNand->Info.PageSize / BCH_PAGE_SECTOR)) == 0) ++ Address->Page++; ++ ++ /* Check NAND address is valid */ ++ if (Address->Page == hNand->Info.BlockSize) { ++ Address->Page = 0; ++ /* Search for next valid block */ ++ Address->Block++; ++ while (Address->Block < hNand->Info.BlockNb && ++ NAND_Check_Bad_Block(hNand, Address) == BAD_BLOCK) ++ Address->Block++; ++ ++ if (Address->Block == hNand->Info.BlockNb) ++ return STD_NOT_OK; ++ } ++ ++ return STD_OK; ++} ++ ++/** ++ * @brief Initialize driver only if needed: ++ * bootrom must have initialize NAND and bootcontext ++ * must contains correct value. ++ * @param hNand: pointer to a NAND_HandleTypeDef structure that contains ++ * the configuration information for NAND module. ++ * @retval Std_ReturnType ++ */ ++Std_ReturnType nand_initialize(NAND_HandleTypeDef *hnand) ++{ ++ if (!hnand->Info.PageSize) { ++ INFO("Reconfigure NAND\n"); ++ /* Not properly initialized by bootrom */ ++ Nand_Init(hnand, EIGHT_BIT_ACCESS, NAND_ECC_BCH8); ++ ++ if (Nand_Reset(hnand) != STD_OK) { ++ ERROR("nand: Reset error (IP base::0x%lx)\n", ++ (uintptr_t)hnand->Instance); ++ return STD_NOT_OK; ++ } ++ ++ if (Nand_DetectAndInit(hnand) != STD_OK) { ++ ERROR("nand: DetectAndInit error (IP base:0x%lx)\n", ++ (uintptr_t)hnand->Instance); ++ return STD_NOT_OK; ++ } ++ } else { ++ /* Initialization done, just need to set correct timing */ ++ Nand_Init(hnand, hnand->Info.BusWidth, ++ hnand->Info.ECCcorrectability); ++ } ++ return STD_OK; ++} ++ +diff --git a/drivers/st/pmic/stm32_i2c.c b/drivers/st/pmic/stm32_i2c.c +deleted file mode 100644 +index 0980139..0000000 +--- a/drivers/st/pmic/stm32_i2c.c ++++ /dev/null +@@ -1,851 +0,0 @@ +-/* +- * Copyright (c) 2016-2018, STMicroelectronics - All Rights Reserved +- * +- * SPDX-License-Identifier: BSD-3-Clause +- */ +- +-#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 MAX_DELAY 0xFFFFFFFFU +- +-/* I2C TIMING clear register Mask */ +-#define TIMING_CLEAR_MASK 0xF0FFFFFFU +-/* Timeout 25 ms */ +-#define I2C_TIMEOUT_BUSY 25U +- +-#define MAX_NBYTE_SIZE 255U +- +-static int i2c_request_memory_write(struct i2c_handle_s *hi2c, +- uint16_t dev_addr, uint16_t mem_addr, +- uint16_t mem_add_size, uint32_t timeout, +- uint32_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, +- uint32_t timeout, uint32_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, uint32_t timeout, +- uint32_t tick_start); +-static int i2c_wait_txis(struct i2c_handle_s *hi2c, uint32_t timeout, +- uint32_t tick_start); +-static int i2c_wait_stop(struct i2c_handle_s *hi2c, uint32_t timeout, +- uint32_t tick_start); +-static int i2c_ack_failed(struct i2c_handle_s *hi2c, uint32_t timeout, +- uint32_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); +- +-/* +- * @brief Initialize the I2C device. +- * @param hi2c: Pointer to a struct i2c_handle_s structure that contains +- * the configuration information for the specified I2C. +- * @retval 0 if OK, negative value else +- */ +-int stm32_i2c_init(struct i2c_handle_s *hi2c) +-{ +- if (hi2c == NULL) { +- return -ENOENT; +- } +- +- if (hi2c->i2c_state == I2C_STATE_RESET) { +- hi2c->lock = 0; +- } +- +- hi2c->i2c_state = I2C_STATE_BUSY; +- +- /* Disable the selected I2C peripheral */ +- mmio_clrbits_32(hi2c->i2c_base_addr + I2C_CR1, I2C_CR1_PE); +- +- /* Configure I2Cx: Frequency range */ +- mmio_write_32(hi2c->i2c_base_addr + I2C_TIMINGR, +- hi2c->i2c_init.timing & TIMING_CLEAR_MASK); +- +- /* Disable Own Address1 before set the Own Address1 configuration */ +- mmio_clrbits_32(hi2c->i2c_base_addr + I2C_OAR1, I2C_OAR1_OA1EN); +- +- /* Configure I2Cx: Own Address1 and ack own address1 mode */ +- if (hi2c->i2c_init.addressing_mode == I2C_ADDRESSINGMODE_7BIT) { +- mmio_write_32(hi2c->i2c_base_addr + I2C_OAR1, +- I2C_OAR1_OA1EN | hi2c->i2c_init.own_address1); +- } else { /* I2C_ADDRESSINGMODE_10BIT */ +- mmio_write_32(hi2c->i2c_base_addr + I2C_OAR1, +- I2C_OAR1_OA1EN | I2C_OAR1_OA1MODE | +- hi2c->i2c_init.own_address1); +- } +- +- /* Configure I2Cx: Addressing Master mode */ +- if (hi2c->i2c_init.addressing_mode == I2C_ADDRESSINGMODE_10BIT) { +- mmio_write_32(hi2c->i2c_base_addr + I2C_CR2, I2C_CR2_ADD10); +- } +- +- /* +- * Enable the AUTOEND by default, and enable NACK +- * (should be disable only during Slave process) +- */ +- mmio_setbits_32(hi2c->i2c_base_addr + I2C_CR2, +- I2C_CR2_AUTOEND | I2C_CR2_NACK); +- +- /* Disable Own Address2 before set the Own Address2 configuration */ +- mmio_clrbits_32(hi2c->i2c_base_addr + I2C_OAR2, I2C_DUALADDRESS_ENABLE); +- +- /* Configure I2Cx: Dual mode and Own Address2 */ +- mmio_write_32(hi2c->i2c_base_addr + I2C_OAR2, +- hi2c->i2c_init.dual_address_mode | +- hi2c->i2c_init.own_address2 | +- (hi2c->i2c_init.own_address2_masks << 8)); +- +- /* Configure I2Cx: Generalcall and NoStretch mode */ +- mmio_write_32(hi2c->i2c_base_addr + I2C_CR1, +- hi2c->i2c_init.general_call_mode | +- hi2c->i2c_init.no_stretch_mode); +- +- /* Enable the selected I2C peripheral */ +- mmio_setbits_32(hi2c->i2c_base_addr + I2C_CR1, I2C_CR1_PE); +- +- hi2c->i2c_err = I2C_ERROR_NONE; +- hi2c->i2c_state = I2C_STATE_READY; +- hi2c->i2c_mode = I2C_MODE_NONE; +- +- return 0; +-} +- +-/* +- * @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: timeout duration +- * @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) +-{ +- uint32_t tickstart; +- +- if ((hi2c->i2c_state != I2C_STATE_READY) || (hi2c->lock != 0U)) { +- return -EBUSY; +- } +- +- if ((p_data == NULL) || (size == 0U)) { +- return -EINVAL; +- } +- +- hi2c->lock = 1; +- +- tickstart = (uint32_t)read_cntpct_el0(); +- +- if (i2c_wait_flag(hi2c, I2C_FLAG_BUSY, 1, I2C_TIMEOUT_BUSY, +- tickstart) != 0) { +- return -EIO; +- } +- +- hi2c->i2c_state = I2C_STATE_BUSY_TX; +- hi2c->i2c_mode = I2C_MODE_MEM; +- hi2c->i2c_err = I2C_ERROR_NONE; +- +- hi2c->p_buff = p_data; +- hi2c->xfer_count = size; +- +- /* Send Slave Address and Memory Address */ +- if (i2c_request_memory_write(hi2c, dev_addr, mem_addr, mem_add_size, +- timeout, tickstart) != 0) { +- hi2c->lock = 0; +- return -EIO; +- } +- +- /* +- * Set NBYTES to write and reload +- * if hi2c->xfer_count > MAX_NBYTE_SIZE +- */ +- if (hi2c->xfer_count > MAX_NBYTE_SIZE) { +- hi2c->xfer_size = MAX_NBYTE_SIZE; +- i2c_transfer_config(hi2c, dev_addr, hi2c->xfer_size, +- I2C_RELOAD_MODE, I2C_NO_STARTSTOP); +- } else { +- hi2c->xfer_size = hi2c->xfer_count; +- i2c_transfer_config(hi2c, dev_addr, hi2c->xfer_size, +- I2C_AUTOEND_MODE, I2C_NO_STARTSTOP); +- } +- +- do { +- if (i2c_wait_txis(hi2c, timeout, tickstart) != 0) { +- return -EIO; +- } +- +- mmio_write_8(hi2c->i2c_base_addr + I2C_TXDR, *hi2c->p_buff); +- hi2c->p_buff++; +- hi2c->xfer_count--; +- hi2c->xfer_size--; +- +- if ((hi2c->xfer_count != 0U) && (hi2c->xfer_size == 0U)) { +- /* Wait until TCR flag is set */ +- if (i2c_wait_flag(hi2c, I2C_FLAG_TCR, 0, timeout, +- tickstart) != 0) { +- return -EIO; +- } +- +- if (hi2c->xfer_count > MAX_NBYTE_SIZE) { +- hi2c->xfer_size = MAX_NBYTE_SIZE; +- i2c_transfer_config(hi2c, dev_addr, +- hi2c->xfer_size, +- I2C_RELOAD_MODE, +- I2C_NO_STARTSTOP); +- } else { +- hi2c->xfer_size = hi2c->xfer_count; +- i2c_transfer_config(hi2c, dev_addr, +- hi2c->xfer_size, +- I2C_AUTOEND_MODE, +- I2C_NO_STARTSTOP); +- } +- } +- +- } while (hi2c->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, timeout, tickstart) != 0) { +- return -EIO; +- } +- +- mmio_write_32(hi2c->i2c_base_addr + I2C_ICR, I2C_FLAG_STOPF); +- +- mmio_clrbits_32(hi2c->i2c_base_addr + I2C_CR2, I2C_RESET_CR2); +- +- hi2c->i2c_state = I2C_STATE_READY; +- hi2c->i2c_mode = I2C_MODE_NONE; +- +- hi2c->lock = 0; +- +- return 0; +-} +- +-/* +- * @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: timeout duration +- * @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) +-{ +- uint32_t tickstart; +- +- if ((hi2c->i2c_state != I2C_STATE_READY) || (hi2c->lock != 0U)) { +- return -EBUSY; +- } +- +- if ((p_data == NULL) || (size == 0U)) { +- return -EINVAL; +- } +- +- hi2c->lock = 1; +- +- tickstart = (uint32_t)read_cntpct_el0(); +- +- if (i2c_wait_flag(hi2c, I2C_FLAG_BUSY, 1, I2C_TIMEOUT_BUSY, +- tickstart) != 0) { +- return -EIO; +- } +- +- hi2c->i2c_state = I2C_STATE_BUSY_RX; +- hi2c->i2c_mode = I2C_MODE_MEM; +- hi2c->i2c_err = I2C_ERROR_NONE; +- +- hi2c->p_buff = p_data; +- hi2c->xfer_count = size; +- +- /* Send Slave Address and Memory Address */ +- if (i2c_request_memory_read(hi2c, dev_addr, mem_addr, mem_add_size, +- timeout, tickstart) != 0) { +- hi2c->lock = 0; +- return -EIO; +- } +- +- /* +- * Send Slave Address. +- * Set NBYTES to write and reload if hi2c->xfer_count > MAX_NBYTE_SIZE +- * and generate RESTART. +- */ +- if (hi2c->xfer_count > MAX_NBYTE_SIZE) { +- hi2c->xfer_size = MAX_NBYTE_SIZE; +- i2c_transfer_config(hi2c, dev_addr, hi2c->xfer_size, +- I2C_RELOAD_MODE, I2C_GENERATE_START_READ); +- } else { +- hi2c->xfer_size = hi2c->xfer_count; +- i2c_transfer_config(hi2c, dev_addr, hi2c->xfer_size, +- I2C_AUTOEND_MODE, I2C_GENERATE_START_READ); +- } +- +- do { +- if (i2c_wait_flag(hi2c, I2C_FLAG_RXNE, 0, timeout, +- tickstart) != 0) { +- return -EIO; +- } +- +- *hi2c->p_buff = mmio_read_8(hi2c->i2c_base_addr + I2C_RXDR); +- hi2c->p_buff++; +- hi2c->xfer_size--; +- hi2c->xfer_count--; +- +- if ((hi2c->xfer_count != 0U) && (hi2c->xfer_size == 0U)) { +- if (i2c_wait_flag(hi2c, I2C_FLAG_TCR, 0, timeout, +- tickstart) != 0) { +- return -EIO; +- } +- +- if (hi2c->xfer_count > MAX_NBYTE_SIZE) { +- hi2c->xfer_size = MAX_NBYTE_SIZE; +- i2c_transfer_config(hi2c, dev_addr, +- hi2c->xfer_size, +- I2C_RELOAD_MODE, +- I2C_NO_STARTSTOP); +- } else { +- hi2c->xfer_size = hi2c->xfer_count; +- i2c_transfer_config(hi2c, dev_addr, +- hi2c->xfer_size, +- I2C_AUTOEND_MODE, +- I2C_NO_STARTSTOP); +- } +- } +- } while (hi2c->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, timeout, tickstart) != 0) { +- return -EIO; +- } +- +- mmio_write_32(hi2c->i2c_base_addr + I2C_ICR, I2C_FLAG_STOPF); +- +- mmio_clrbits_32(hi2c->i2c_base_addr + I2C_CR2, I2C_RESET_CR2); +- +- hi2c->i2c_state = I2C_STATE_READY; +- hi2c->i2c_mode = I2C_MODE_NONE; +- +- hi2c->lock = 0; +- +- return 0; +-} +- +-/* +- * @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: timeout duration +- * @retval 0 if OK, negative value else +- */ +-int stm32_i2c_is_device_ready(struct i2c_handle_s *hi2c, +- uint16_t dev_addr, uint32_t trials, +- uint32_t timeout) +-{ +- uint32_t i2c_trials = 0U; +- +- if ((hi2c->i2c_state != I2C_STATE_READY) || (hi2c->lock != 0U)) { +- return -EBUSY; +- } +- +- if ((mmio_read_32(hi2c->i2c_base_addr + I2C_ISR) & I2C_FLAG_BUSY) != +- 0U) { +- return -EBUSY; +- } +- +- hi2c->lock = 1; +- +- hi2c->i2c_state = I2C_STATE_BUSY; +- hi2c->i2c_err = I2C_ERROR_NONE; +- +- do { +- uint32_t tickstart; +- +- /* Generate Start */ +- if (hi2c->i2c_init.addressing_mode == I2C_ADDRESSINGMODE_7BIT) { +- mmio_write_32(hi2c->i2c_base_addr + I2C_CR2, +- (((uint32_t)dev_addr & I2C_CR2_SADD) | +- I2C_CR2_START | I2C_CR2_AUTOEND) & +- ~I2C_CR2_RD_WRN); +- } else { +- mmio_write_32(hi2c->i2c_base_addr + 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 +- */ +- tickstart = (uint32_t)read_cntpct_el0(); +- while (((mmio_read_32(hi2c->i2c_base_addr + I2C_ISR) & +- (I2C_FLAG_STOPF | I2C_FLAG_AF)) == 0U) && +- (hi2c->i2c_state != I2C_STATE_TIMEOUT)) { +- if (timeout != MAX_DELAY) { +- if ((((uint32_t)read_cntpct_el0() - tickstart) > +- timeout) || (timeout == 0U)) { +- hi2c->i2c_state = I2C_STATE_READY; +- +- hi2c->i2c_err |= +- I2C_ERROR_TIMEOUT; +- +- hi2c->lock = 0; +- +- return -EIO; +- } +- } +- } +- +- /* Check if the NACKF flag has not been set */ +- if ((mmio_read_32(hi2c->i2c_base_addr + I2C_ISR) & +- I2C_FLAG_AF) == 0U) { +- if (i2c_wait_flag(hi2c, I2C_FLAG_STOPF, 0, timeout, +- tickstart) != 0) { +- return -EIO; +- } +- +- mmio_write_32(hi2c->i2c_base_addr + I2C_ICR, +- I2C_FLAG_STOPF); +- +- hi2c->i2c_state = I2C_STATE_READY; +- +- hi2c->lock = 0; +- +- return 0; +- } +- +- if (i2c_wait_flag(hi2c, I2C_FLAG_STOPF, 0, timeout, +- tickstart) != 0) { +- return -EIO; +- } +- +- mmio_write_32(hi2c->i2c_base_addr + I2C_ICR, I2C_FLAG_AF); +- +- mmio_write_32(hi2c->i2c_base_addr + I2C_ICR, I2C_FLAG_STOPF); +- +- if (i2c_trials == trials) { +- mmio_setbits_32(hi2c->i2c_base_addr + I2C_CR2, +- I2C_CR2_STOP); +- +- if (i2c_wait_flag(hi2c, I2C_FLAG_STOPF, 0, timeout, +- tickstart) != 0) { +- return -EIO; +- } +- +- mmio_write_32(hi2c->i2c_base_addr + I2C_ICR, +- I2C_FLAG_STOPF); +- } +- +- i2c_trials++; +- } while (i2c_trials < trials); +- +- hi2c->i2c_state = I2C_STATE_READY; +- +- hi2c->i2c_err |= I2C_ERROR_TIMEOUT; +- +- hi2c->lock = 0; +- +- return -EIO; +-} +- +-/* +- * @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 timeout: 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, uint32_t timeout, +- uint32_t tick_start) +-{ +- i2c_transfer_config(hi2c, dev_addr, mem_add_size, I2C_RELOAD_MODE, +- I2C_GENERATE_START_WRITE); +- +- if (i2c_wait_txis(hi2c, timeout, tick_start) != 0) { +- return -EIO; +- } +- +- if (mem_add_size == I2C_MEMADD_SIZE_8BIT) { +- /* Send Memory Address */ +- mmio_write_8(hi2c->i2c_base_addr + I2C_TXDR, +- (uint8_t)(mem_addr & 0x00FFU)); +- } else { +- /* Send MSB of Memory Address */ +- mmio_write_8(hi2c->i2c_base_addr + I2C_TXDR, +- (uint8_t)((mem_addr & 0xFF00U) >> 8)); +- +- /* Wait until TXIS flag is set */ +- if (i2c_wait_txis(hi2c, timeout, tick_start) != 0) { +- return -EIO; +- } +- +- /* Send LSB of Memory Address */ +- mmio_write_8(hi2c->i2c_base_addr + I2C_TXDR, +- (uint8_t)(mem_addr & 0x00FFU)); +- } +- +- if (i2c_wait_flag(hi2c, I2C_FLAG_TCR, 0, timeout, tick_start) != +- 0) { +- return -EIO; +- } +- +- 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 timeout: 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, +- uint32_t timeout, uint32_t tick_start) +-{ +- i2c_transfer_config(hi2c, dev_addr, mem_add_size, I2C_SOFTEND_MODE, +- I2C_GENERATE_START_WRITE); +- +- if (i2c_wait_txis(hi2c, timeout, tick_start) != 0) { +- return -EIO; +- } +- +- if (mem_add_size == I2C_MEMADD_SIZE_8BIT) { +- /* Send Memory Address */ +- mmio_write_8(hi2c->i2c_base_addr + I2C_TXDR, +- (uint8_t)(mem_addr & 0x00FFU)); +- } else { +- /* Send MSB of Memory Address */ +- mmio_write_8(hi2c->i2c_base_addr + I2C_TXDR, +- (uint8_t)((mem_addr & 0xFF00U) >> 8)); +- +- /* Wait until TXIS flag is set */ +- if (i2c_wait_txis(hi2c, timeout, tick_start) != 0) { +- return -EIO; +- } +- +- /* Send LSB of Memory Address */ +- mmio_write_8(hi2c->i2c_base_addr + I2C_TXDR, +- (uint8_t)(mem_addr & 0x00FFU)); +- } +- +- if (i2c_wait_flag(hi2c, I2C_FLAG_TC, 0, timeout, tick_start) != 0) { +- return -EIO; +- } +- +- 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) +-{ +- /* +- * If a pending TXIS flag is set, +- * write a dummy data in TXDR to clear it. +- */ +- if ((mmio_read_32(hi2c->i2c_base_addr + I2C_ISR) & I2C_FLAG_TXIS) != +- 0U) { +- mmio_write_32(hi2c->i2c_base_addr + I2C_TXDR, 0); +- } +- +- /* Flush TX register if not empty */ +- if ((mmio_read_32(hi2c->i2c_base_addr + I2C_ISR) & I2C_FLAG_TXE) == +- 0U) { +- mmio_setbits_32(hi2c->i2c_base_addr + 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 timeout: 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, uint32_t timeout, +- uint32_t tick_start) +-{ +- uint8_t flag_check; +- +- do { +- flag_check = ((mmio_read_32(hi2c->i2c_base_addr + I2C_ISR) & +- flag) == flag) ? 1U : 0U; +- +- if (timeout != MAX_DELAY) { +- if ((((uint32_t)read_cntpct_el0() - tick_start) > +- timeout) || (timeout == 0U)) { +- hi2c->i2c_err |= I2C_ERROR_TIMEOUT; +- hi2c->i2c_state = I2C_STATE_READY; +- hi2c->i2c_mode = I2C_MODE_NONE; +- +- hi2c->lock = 0; +- return -EIO; +- } +- } +- } while (flag_check == awaited_value); +- +- return 0; +-} +- +-/* +- * @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 timeout: 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, uint32_t timeout, +- uint32_t tick_start) +-{ +- while ((mmio_read_32(hi2c->i2c_base_addr + I2C_ISR) & +- I2C_FLAG_TXIS) == 0U) { +- if (i2c_ack_failed(hi2c, timeout, tick_start) != 0) { +- return -EIO; +- } +- +- if (timeout != MAX_DELAY) { +- if ((((uint32_t)read_cntpct_el0() - tick_start) > +- timeout) || (timeout == 0U)) { +- hi2c->i2c_err |= I2C_ERROR_TIMEOUT; +- hi2c->i2c_state = I2C_STATE_READY; +- hi2c->i2c_mode = I2C_MODE_NONE; +- +- hi2c->lock = 0; +- +- return -EIO; +- } +- } +- } +- +- 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 timeout: 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, uint32_t timeout, +- uint32_t tick_start) +-{ +- while ((mmio_read_32(hi2c->i2c_base_addr + I2C_ISR) & +- I2C_FLAG_STOPF) == 0U) { +- if (i2c_ack_failed(hi2c, timeout, tick_start) != 0) { +- return -EIO; +- } +- +- if ((((uint32_t)read_cntpct_el0() - tick_start) > timeout) || +- (timeout == 0U)) { +- hi2c->i2c_err |= I2C_ERROR_TIMEOUT; +- hi2c->i2c_state = I2C_STATE_READY; +- hi2c->i2c_mode = I2C_MODE_NONE; +- +- hi2c->lock = 0; +- +- return -EIO; +- } +- } +- +- 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 timeout: 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, uint32_t timeout, +- uint32_t tick_start) +-{ +- if ((mmio_read_32(hi2c->i2c_base_addr + I2C_ISR) & I2C_FLAG_AF) == 0U) { +- return 0; +- } +- +- /* +- * Wait until STOP Flag is reset. +- * AutoEnd should be initiate after AF. +- */ +- while ((mmio_read_32(hi2c->i2c_base_addr + I2C_ISR) & +- I2C_FLAG_STOPF) == 0U) { +- if (timeout != MAX_DELAY) { +- if ((((uint32_t)read_cntpct_el0() - tick_start) > +- timeout) || (timeout == 0U)) { +- hi2c->i2c_err |= I2C_ERROR_TIMEOUT; +- hi2c->i2c_state = I2C_STATE_READY; +- hi2c->i2c_mode = I2C_MODE_NONE; +- +- hi2c->lock = 0; +- +- return -EIO; +- } +- } +- } +- +- mmio_write_32(hi2c->i2c_base_addr + I2C_ICR, I2C_FLAG_AF); +- +- mmio_write_32(hi2c->i2c_base_addr + I2C_ICR, I2C_FLAG_STOPF); +- +- i2c_flush_txdr(hi2c); +- +- mmio_clrbits_32(hi2c->i2c_base_addr + 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 -EIO; +-} +- +-/* +- * @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(hi2c->i2c_base_addr + I2C_CR2, clr_value, set_value); +-} +- +-/* +- * @brief Configure I2C Analog noise filter. +- * @param hi2c: Pointer to a struct i2c_handle_s structure that contains +- * the configuration information for the specified I2Cx peripheral +- * @param analog_filter: New state of the Analog filter. +- * @retval 0 if OK, negative value else +- */ +-int stm32_i2c_config_analog_filter(struct i2c_handle_s *hi2c, +- uint32_t analog_filter) +-{ +- if ((hi2c->i2c_state != I2C_STATE_READY) || (hi2c->lock != 0U)) { +- return -EBUSY; +- } +- +- hi2c->lock = 1; +- +- hi2c->i2c_state = I2C_STATE_BUSY; +- +- /* Disable the selected I2C peripheral */ +- mmio_clrbits_32(hi2c->i2c_base_addr + I2C_CR1, I2C_CR1_PE); +- +- /* Reset I2Cx ANOFF bit */ +- mmio_clrbits_32(hi2c->i2c_base_addr + I2C_CR1, I2C_CR1_ANFOFF); +- +- /* Set analog filter bit*/ +- mmio_setbits_32(hi2c->i2c_base_addr + I2C_CR1, analog_filter); +- +- /* Enable the selected I2C peripheral */ +- mmio_setbits_32(hi2c->i2c_base_addr + I2C_CR1, I2C_CR1_PE); +- +- hi2c->i2c_state = I2C_STATE_READY; +- +- hi2c->lock = 0; +- +- return 0; +-} +diff --git a/drivers/st/pmic/stm32mp1_pmic.c b/drivers/st/pmic/stm32mp1_pmic.c +deleted file mode 100644 +index 958de08..0000000 +--- a/drivers/st/pmic/stm32mp1_pmic.c ++++ /dev/null +@@ -1,346 +0,0 @@ +-/* +- * Copyright (c) 2017-2018, STMicroelectronics - All Rights Reserved +- * +- * SPDX-License-Identifier: BSD-3-Clause +- */ +- +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +- +-/* I2C Timing hard-coded value, for I2C clock source is HSI at 64MHz */ +-#define I2C_TIMING 0x10D07DB5 +- +-#define I2C_TIMEOUT 0xFFFFF +- +-#define MASK_RESET_BUCK3 BIT(2) +- +-#define STPMU1_LDO12356_OUTPUT_MASK (uint8_t)(GENMASK(6, 2)) +-#define STPMU1_LDO12356_OUTPUT_SHIFT 2 +-#define STPMU1_LDO3_MODE (uint8_t)(BIT(7)) +-#define STPMU1_LDO3_DDR_SEL 31U +-#define STPMU1_LDO3_1800000 (9U << STPMU1_LDO12356_OUTPUT_SHIFT) +- +-#define STPMU1_BUCK_OUTPUT_SHIFT 2 +-#define STPMU1_BUCK3_1V8 (39U << STPMU1_BUCK_OUTPUT_SHIFT) +- +-#define STPMU1_DEFAULT_START_UP_DELAY_MS 1 +- +-static struct i2c_handle_s i2c_handle; +-static uint32_t pmic_i2c_addr; +- +-static int dt_get_pmic_node(void *fdt) +-{ +- return fdt_node_offset_by_compatible(fdt, -1, "st,stpmu1"); +-} +- +-bool dt_check_pmic(void) +-{ +- int node; +- void *fdt; +- +- if (fdt_get_address(&fdt) == 0) { +- return false; +- } +- +- node = dt_get_pmic_node(fdt); +- if (node < 0) { +- VERBOSE("%s: No PMIC node found in DT\n", __func__); +- return false; +- } +- +- return fdt_check_status(node); +-} +- +-static int dt_pmic_i2c_config(struct dt_node_info *i2c_info) +-{ +- int pmic_node, i2c_node; +- void *fdt; +- const fdt32_t *cuint; +- +- if (fdt_get_address(&fdt) == 0) { +- return -ENOENT; +- } +- +- pmic_node = dt_get_pmic_node(fdt); +- if (pmic_node < 0) { +- return -FDT_ERR_NOTFOUND; +- } +- +- 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 -EINVAL; +- } +- +- i2c_node = fdt_parent_offset(fdt, pmic_node); +- if (i2c_node < 0) { +- return -FDT_ERR_NOTFOUND; +- } +- +- dt_fill_device_info(i2c_info, i2c_node); +- if (i2c_info->base == 0U) { +- return -FDT_ERR_NOTFOUND; +- } +- +- return dt_set_pinctrl_config(i2c_node); +-} +- +-int dt_pmic_enable_boot_on_regulators(void) +-{ +- int pmic_node, regulators_node, regulator_node; +- void *fdt; +- +- if (fdt_get_address(&fdt) == 0) { +- return -ENOENT; +- } +- +- 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 *node_name; +- uint16_t voltage; +- +- if (fdt_getprop(fdt, regulator_node, "regulator-boot-on", +- NULL) == NULL) { +- continue; +- } +- +- cuint = fdt_getprop(fdt, regulator_node, +- "regulator-min-microvolt", NULL); +- if (cuint == NULL) { +- continue; +- } +- +- /* DT uses microvolts, whereas driver awaits millivolts */ +- voltage = (uint16_t)(fdt32_to_cpu(*cuint) / 1000U); +- node_name = fdt_get_name(fdt, regulator_node, NULL); +- +- if (stpmu1_is_regulator_enabled(node_name) == 0U) { +- int status; +- +- status = stpmu1_regulator_voltage_set(node_name, +- voltage); +- if (status != 0) { +- return status; +- } +- +- status = stpmu1_regulator_enable(node_name); +- if (status != 0) { +- return status; +- } +- } +- } +- +- return 0; +-} +- +-void initialize_pmic_i2c(void) +-{ +- int ret; +- struct dt_node_info i2c_info; +- +- if (dt_pmic_i2c_config(&i2c_info) != 0) { +- ERROR("I2C configuration failed\n"); +- panic(); +- } +- +- if (stm32mp1_clk_enable((uint32_t)i2c_info.clock) < 0) { +- ERROR("I2C clock enable failed\n"); +- panic(); +- } +- +- /* Initialize PMIC I2C */ +- i2c_handle.i2c_base_addr = i2c_info.base; +- i2c_handle.i2c_init.timing = I2C_TIMING; +- i2c_handle.i2c_init.own_address1 = pmic_i2c_addr; +- i2c_handle.i2c_init.addressing_mode = I2C_ADDRESSINGMODE_7BIT; +- i2c_handle.i2c_init.dual_address_mode = I2C_DUALADDRESS_DISABLE; +- i2c_handle.i2c_init.own_address2 = 0; +- i2c_handle.i2c_init.own_address2_masks = I2C_OAR2_OA2NOMASK; +- i2c_handle.i2c_init.general_call_mode = I2C_GENERALCALL_DISABLE; +- i2c_handle.i2c_init.no_stretch_mode = I2C_NOSTRETCH_DISABLE; +- +- ret = stm32_i2c_init(&i2c_handle); +- if (ret != 0) { +- ERROR("Cannot initialize I2C %x (%d)\n", +- i2c_handle.i2c_base_addr, ret); +- panic(); +- } +- +- ret = stm32_i2c_config_analog_filter(&i2c_handle, +- I2C_ANALOGFILTER_ENABLE); +- if (ret != 0) { +- ERROR("Cannot initialize I2C analog filter (%d)\n", ret); +- panic(); +- } +- +- ret = stm32_i2c_is_device_ready(&i2c_handle, (uint16_t)pmic_i2c_addr, 1, +- I2C_TIMEOUT); +- if (ret != 0) { +- ERROR("I2C device not ready (%d)\n", ret); +- panic(); +- } +- +- stpmu1_bind_i2c(&i2c_handle, (uint16_t)pmic_i2c_addr); +-} +- +-void initialize_pmic(void) +-{ +- int status; +- uint8_t read_val; +- +- initialize_pmic_i2c(); +- +- status = stpmu1_register_read(VERSION_STATUS_REG, &read_val); +- if (status != 0) { +- panic(); +- } +- +- INFO("PMIC version = 0x%x\n", read_val); +- +- /* Keep VDD on during the reset cycle */ +- status = stpmu1_register_update(MASK_RESET_BUCK_REG, +- MASK_RESET_BUCK3, +- MASK_RESET_BUCK3); +- if (status != 0) { +- panic(); +- } +-} +- +-int pmic_ddr_power_init(enum ddr_type ddr_type) +-{ +- bool buck3_at_1v8 = false; +- uint8_t read_val; +- int status; +- +- switch (ddr_type) { +- case STM32MP_DDR3: +- /* Set LDO3 to sync mode */ +- status = stpmu1_register_read(LDO3_CONTROL_REG, &read_val); +- if (status != 0) { +- return status; +- } +- +- read_val &= ~STPMU1_LDO3_MODE; +- read_val &= ~STPMU1_LDO12356_OUTPUT_MASK; +- read_val |= STPMU1_LDO3_DDR_SEL << STPMU1_LDO12356_OUTPUT_SHIFT; +- +- status = stpmu1_register_write(LDO3_CONTROL_REG, read_val); +- if (status != 0) { +- return status; +- } +- +- status = stpmu1_regulator_voltage_set("buck2", 1350); +- if (status != 0) { +- return status; +- } +- +- status = stpmu1_regulator_enable("buck2"); +- if (status != 0) { +- return status; +- } +- +- mdelay(STPMU1_DEFAULT_START_UP_DELAY_MS); +- +- status = stpmu1_regulator_enable("vref_ddr"); +- if (status != 0) { +- return status; +- } +- +- mdelay(STPMU1_DEFAULT_START_UP_DELAY_MS); +- +- status = stpmu1_regulator_enable("ldo3"); +- if (status != 0) { +- return status; +- } +- +- mdelay(STPMU1_DEFAULT_START_UP_DELAY_MS); +- break; +- +- case STM32MP_LPDDR2: +- /* +- * Set LDO3 to 1.8V +- * Set LDO3 to bypass mode if BUCK3 = 1.8V +- * Set LDO3 to normal mode if BUCK3 != 1.8V +- */ +- status = stpmu1_register_read(BUCK3_CONTROL_REG, &read_val); +- if (status != 0) { +- return status; +- } +- +- if ((read_val & STPMU1_BUCK3_1V8) == STPMU1_BUCK3_1V8) { +- buck3_at_1v8 = true; +- } +- +- status = stpmu1_register_read(LDO3_CONTROL_REG, &read_val); +- if (status != 0) { +- return status; +- } +- +- read_val &= ~STPMU1_LDO3_MODE; +- read_val &= ~STPMU1_LDO12356_OUTPUT_MASK; +- read_val |= STPMU1_LDO3_1800000; +- if (buck3_at_1v8) { +- read_val |= STPMU1_LDO3_MODE; +- } +- +- status = stpmu1_register_write(LDO3_CONTROL_REG, read_val); +- if (status != 0) { +- return status; +- } +- +- status = stpmu1_regulator_voltage_set("buck2", 1200); +- if (status != 0) { +- return status; +- } +- +- status = stpmu1_regulator_enable("ldo3"); +- if (status != 0) { +- return status; +- } +- +- mdelay(STPMU1_DEFAULT_START_UP_DELAY_MS); +- +- status = stpmu1_regulator_enable("buck2"); +- if (status != 0) { +- return status; +- } +- +- mdelay(STPMU1_DEFAULT_START_UP_DELAY_MS); +- +- status = stpmu1_regulator_enable("vref_ddr"); +- if (status != 0) { +- return status; +- } +- +- mdelay(STPMU1_DEFAULT_START_UP_DELAY_MS); +- break; +- +- default: +- break; +- }; +- +- return 0; +-} +diff --git a/drivers/st/pmic/stm32mp_pmic.c b/drivers/st/pmic/stm32mp_pmic.c +new file mode 100644 +index 0000000..c8d70db +--- /dev/null ++++ b/drivers/st/pmic/stm32mp_pmic.c +@@ -0,0 +1,522 @@ ++/* ++ * Copyright (c) 2017-2018, STMicroelectronics - All Rights Reserved ++ * ++ * SPDX-License-Identifier: BSD-3-Clause ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define STPMIC1_LDO12356_OUTPUT_MASK (uint8_t)(GENMASK(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 REGULATOR_MODE_STANDBY 8U ++ ++#define STPMIC1_DEFAULT_START_UP_DELAY_MS 1 ++ ++static struct i2c_handle_s i2c_handle; ++static uint32_t pmic_i2c_addr; ++ ++static int dt_get_pmic_node(void *fdt) ++{ ++ return fdt_node_offset_by_compatible(fdt, -1, "st,stpmic1"); ++} ++ ++int dt_pmic_status(void) ++{ ++ int node; ++ void *fdt; ++ ++ if (fdt_get_address(&fdt) == 0) { ++ return -ENOENT; ++ } ++ ++ node = dt_get_pmic_node(fdt); ++ if (node <= 0) { ++ return -FDT_ERR_NOTFOUND; ++ } ++ ++ return fdt_get_status(node); ++} ++ ++static bool dt_pmic_is_secure(void) ++{ ++ int status = dt_pmic_status(); ++ ++ return (status >= 0) && ++ (status == DT_SECURE) && ++ (i2c_handle.dt_status == DT_SECURE); ++} ++ ++/* ++ * Get PMIC and its I2C bus configuration from the device tree. ++ * Return 0 on success, negative on error, 1 if no PMIC node is defined. ++ */ ++static int dt_pmic_i2c_config(struct dt_node_info *i2c_info, ++ struct stm32_i2c_init_s *init) ++{ ++ int pmic_node, i2c_node; ++ void *fdt; ++ const fdt32_t *cuint; ++ ++ if (fdt_get_address(&fdt) == 0) { ++ return -ENOENT; ++ } ++ ++ 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 -EINVAL; ++ } ++ ++ i2c_node = fdt_parent_offset(fdt, pmic_node); ++ if (i2c_node < 0) { ++ return -FDT_ERR_NOTFOUND; ++ } ++ ++ dt_fill_device_info(i2c_info, i2c_node); ++ if (i2c_info->base == 0U) { ++ return -FDT_ERR_NOTFOUND; ++ } ++ ++ return stm32_i2c_get_setup_from_fdt(fdt, i2c_node, init); ++} ++ ++int dt_pmic_configure_boot_on_regulators(void) ++{ ++ int pmic_node, regulators_node, regulator_node; ++ void *fdt; ++ ++ if (fdt_get_address(&fdt) == 0) { ++ return -ENOENT; ++ } ++ ++ 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 *node_name = fdt_get_name(fdt, regulator_node, NULL); ++ uint16_t voltage; ++ int status; ++ ++#if defined(IMAGE_BL2) ++ if ((fdt_getprop(fdt, regulator_node, "regulator-boot-on", ++ NULL) == NULL) && ++ (fdt_getprop(fdt, regulator_node, "regulator-always-on", ++ NULL) == NULL)) { ++#else ++ if (fdt_getprop(fdt, regulator_node, "regulator-boot-on", ++ NULL) == NULL) { ++#endif ++ continue; ++ } ++ ++ if (fdt_getprop(fdt, regulator_node, "regulator-pull-down", ++ NULL) != NULL) { ++ int status; ++ ++ status = stpmic1_regulator_pull_down_set(node_name); ++ if (status != 0) { ++ return status; ++ } ++ } ++ ++ if (fdt_getprop(fdt, regulator_node, "st,mask-reset", ++ NULL) != NULL) { ++ int status; ++ ++ status = stpmic1_regulator_mask_reset_set(node_name); ++ if (status != 0) { ++ return status; ++ } ++ } ++ ++ cuint = fdt_getprop(fdt, regulator_node, ++ "regulator-min-microvolt", NULL); ++ if (cuint == NULL) { ++ continue; ++ } ++ ++ /* DT uses microvolts, whereas driver awaits millivolts */ ++ voltage = (uint16_t)(fdt32_to_cpu(*cuint) / 1000U); ++ ++ status = stpmic1_regulator_voltage_set(node_name, voltage); ++ if (status != 0) { ++ return status; ++ } ++ ++ if (stpmic1_is_regulator_enabled(node_name) == 0U) { ++ status = stpmic1_regulator_enable(node_name); ++ if (status != 0) { ++ return status; ++ } ++ } ++ } ++ ++ return 0; ++} ++ ++int dt_pmic_set_lp_config(const char *node_name) ++{ ++ int pmic_node, regulators_node, regulator_node; ++ int status; ++ void *fdt; ++ ++ if (node_name == NULL) { ++ return 0; ++ } ++ ++ if (fdt_get_address(&fdt) == 0) { ++ return -ENOENT; ++ } ++ ++ pmic_node = dt_get_pmic_node(fdt); ++ if (pmic_node < 0) { ++ return -FDT_ERR_NOTFOUND; ++ } ++ ++ status = stpmic1_powerctrl_on(); ++ if (status != 0) { ++ return status; ++ }; ++ ++ regulators_node = fdt_subnode_offset(fdt, pmic_node, "regulators"); ++ ++ fdt_for_each_subnode(regulator_node, fdt, regulators_node) { ++ const fdt32_t *cuint; ++ const char *reg_name; ++ int regulator_state_node; ++ ++ /* ++ * First, copy active configuration (Control register) to ++ * PWRCTRL Control register, even if regulator_state_node ++ * does not exist. ++ */ ++ reg_name = fdt_get_name(fdt, regulator_node, NULL); ++ status = stpmic1_lp_copy_reg(reg_name); ++ if (status != 0) { ++ return status; ++ } ++ ++ /* Then apply configs from regulator_state_node */ ++ regulator_state_node = fdt_subnode_offset(fdt, ++ regulator_node, ++ node_name); ++ if (regulator_state_node <= 0) { ++ continue; ++ } ++ ++ if (fdt_getprop(fdt, regulator_state_node, ++ "regulator-on-in-suspend", NULL) != NULL) { ++ status = stpmic1_lp_reg_on_off(reg_name, 1); ++ if (status != 0) { ++ return status; ++ } ++ } ++ ++ if (fdt_getprop(fdt, regulator_state_node, ++ "regulator-off-in-suspend", NULL) != NULL) { ++ status = stpmic1_lp_reg_on_off(reg_name, 0); ++ if (status != 0) { ++ return status; ++ } ++ } ++ ++ cuint = fdt_getprop(fdt, regulator_state_node, ++ "regulator-suspend-microvolt", NULL); ++ if (cuint != NULL) { ++ uint16_t voltage = (uint16_t)(fdt32_to_cpu(*cuint) / ++ 1000U); ++ ++ status = stpmic1_lp_set_voltage(reg_name, voltage); ++ if (status != 0) { ++ return status; ++ } ++ } ++ ++ cuint = fdt_getprop(fdt, regulator_state_node, ++ "regulator-mode", NULL); ++ if (cuint != NULL) { ++ if (fdt32_to_cpu(*cuint) == REGULATOR_MODE_STANDBY) { ++ status = stpmic1_lp_set_mode(reg_name, 1); ++ if (status != 0) { ++ return status; ++ } ++ } ++ } ++ } ++ ++ return 0; ++} ++ ++/* ++ * initialize_pmic_i2c - Initialize I2C for the PMIC control ++ * ++ * Return true if PMIC is available, false if not found, panics on errors ++ */ ++bool initialize_pmic_i2c(void) ++{ ++ int ret; ++ struct dt_node_info i2c_info; ++ struct i2c_handle_s *i2c = &i2c_handle; ++ struct stm32_i2c_init_s i2c_init; ++ ++ ret = dt_pmic_i2c_config(&i2c_info, &i2c_init); ++ if (ret < 0) { ++ ERROR("I2C configuration failed %d\n", ret); ++ panic(); ++ } ++ if (ret != 0) { ++ return false; ++ } ++ ++ /* Initialize PMIC I2C */ ++ i2c->i2c_base_addr = i2c_info.base; ++ 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; ++ ++ ret = stm32_i2c_init(i2c, &i2c_init); ++ if (ret != 0) { ++ ERROR("Cannot initialize I2C %x (%d)\n", ++ i2c->i2c_base_addr, ret); ++ panic(); ++ } ++ ++ if (!stm32_i2c_is_device_ready(i2c, pmic_i2c_addr, 1, ++ I2C_TIMEOUT_BUSY_MS)) { ++ ERROR("I2C device not ready\n"); ++ panic(); ++ } ++ ++ stpmic1_bind_i2c(i2c, (uint16_t)pmic_i2c_addr); ++ ++ return true; ++} ++ ++#if STM32MP1_DEBUG_ENABLE ++int pmic_keep_debug_unit(void) ++{ ++ unsigned int i; ++ static const char * const regus[] = { ++ "buck1", ++ "buck3", ++ }; ++ ++ for (i = 0; i < ARRAY_SIZE(regus); i++) { ++ int res; ++ ++ WARN("Mask %s\n", regus[i]); ++ res = stpmic1_regulator_mask_reset_set(regus[i]); ++ if (res != 0) { ++ return res; ++ } ++ } ++ ++ return 0; ++} ++#endif ++ ++static void register_non_secure_pmic(void) ++{ ++ if (i2c_handle.i2c_base_addr == 0U) { ++ return; ++ } ++ ++ stm32mp_register_non_secure_periph_iomem(i2c_handle.i2c_base_addr); ++ ++ if (stm32mp1_rcc_is_secure()) { ++ stm32mp1_register_clock_parents_secure(i2c_handle.clock); ++ } ++} ++ ++static void register_secure_pmic(void) ++{ ++ stm32mp_register_secure_periph_iomem(i2c_handle.i2c_base_addr); ++} ++ ++void initialize_pmic(void) ++{ ++ unsigned long pmic_version; ++ ++ if (!initialize_pmic_i2c()) { ++ VERBOSE("No PMIC\n"); ++ register_non_secure_pmic(); ++ return; ++ } ++ ++ if (stpmic1_get_version(&pmic_version) != 0) { ++ ERROR("Failed to access PMIC\n"); ++ panic(); ++ } ++ ++ INFO("PMIC version = 0x%02lx\n", pmic_version); ++ stpmic1_dump_regulators(); ++ ++ if (dt_pmic_is_secure()) { ++ register_secure_pmic(); ++ } else { ++ VERBOSE("PMIC is not secure-only hence assumed non secure\n"); ++ register_non_secure_pmic(); ++ } ++ ++#if defined(IMAGE_BL2) ++ if (dt_pmic_configure_boot_on_regulators() != 0) { ++ panic(); ++ }; ++#endif ++} ++ ++int pmic_ddr_power_init(enum ddr_type ddr_type) ++{ ++ bool buck3_at_1v8 = false; ++ uint8_t read_val; ++ int status; ++ ++ switch (ddr_type) { ++ case STM32MP_DDR3: ++ /* Set LDO3 to sync mode */ ++ status = stpmic1_register_read(LDO3_CONTROL_REG, &read_val); ++ if (status != 0) { ++ return status; ++ } ++ ++ read_val &= ~STPMIC1_LDO3_MODE; ++ read_val &= ~STPMIC1_LDO12356_OUTPUT_MASK; ++ read_val |= STPMIC1_LDO3_DDR_SEL << ++ STPMIC1_LDO12356_OUTPUT_SHIFT; ++ ++ status = stpmic1_register_write(LDO3_CONTROL_REG, read_val); ++ if (status != 0) { ++ return status; ++ } ++ ++ status = stpmic1_regulator_voltage_set("buck2", 1350); ++ if (status != 0) { ++ return status; ++ } ++ ++ status = stpmic1_regulator_enable("buck2"); ++ if (status != 0) { ++ return status; ++ } ++ ++ mdelay(STPMIC1_DEFAULT_START_UP_DELAY_MS); ++ ++ status = stpmic1_regulator_enable("vref_ddr"); ++ if (status != 0) { ++ return status; ++ } ++ ++ mdelay(STPMIC1_DEFAULT_START_UP_DELAY_MS); ++ ++ status = stpmic1_regulator_enable("ldo3"); ++ if (status != 0) { ++ return status; ++ } ++ ++ mdelay(STPMIC1_DEFAULT_START_UP_DELAY_MS); ++ break; ++ ++ case STM32MP_LPDDR2: ++ case STM32MP_LPDDR3: ++ /* ++ * Set LDO3 to 1.8V ++ * Set LDO3 to bypass mode if BUCK3 = 1.8V ++ * Set LDO3 to normal mode if BUCK3 != 1.8V ++ */ ++ status = stpmic1_register_read(BUCK3_CONTROL_REG, &read_val); ++ if (status != 0) { ++ return status; ++ } ++ ++ if ((read_val & STPMIC1_BUCK3_1V8) == STPMIC1_BUCK3_1V8) { ++ buck3_at_1v8 = true; ++ } ++ ++ status = stpmic1_register_read(LDO3_CONTROL_REG, &read_val); ++ if (status != 0) { ++ return status; ++ } ++ ++ read_val &= ~STPMIC1_LDO3_MODE; ++ read_val &= ~STPMIC1_LDO12356_OUTPUT_MASK; ++ read_val |= STPMIC1_LDO3_1800000; ++ if (buck3_at_1v8) { ++ read_val |= STPMIC1_LDO3_MODE; ++ } ++ ++ status = stpmic1_register_write(LDO3_CONTROL_REG, read_val); ++ if (status != 0) { ++ return status; ++ } ++ ++ status = stpmic1_regulator_voltage_set("buck2", 1200); ++ if (status != 0) { ++ return status; ++ } ++ ++ status = stpmic1_regulator_enable("ldo3"); ++ if (status != 0) { ++ return status; ++ } ++ ++ mdelay(STPMIC1_DEFAULT_START_UP_DELAY_MS); ++ ++ status = stpmic1_regulator_enable("buck2"); ++ if (status != 0) { ++ return status; ++ } ++ ++ mdelay(STPMIC1_DEFAULT_START_UP_DELAY_MS); ++ ++ status = stpmic1_regulator_enable("vref_ddr"); ++ if (status != 0) { ++ return status; ++ } ++ ++ mdelay(STPMIC1_DEFAULT_START_UP_DELAY_MS); ++ break; ++ ++ default: ++ break; ++ }; ++ ++ return 0; ++} +diff --git a/drivers/st/pmic/stpmic1.c b/drivers/st/pmic/stpmic1.c +new file mode 100644 +index 0000000..2bd2b60 +--- /dev/null ++++ b/drivers/st/pmic/stpmic1.c +@@ -0,0 +1,817 @@ ++/* ++ * Copyright (c) 2016-2018, STMicroelectronics - All Rights Reserved ++ * ++ * SPDX-License-Identifier: BSD-3-Clause ++ */ ++ ++#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, ++ 500, ++ 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, ++ }, ++ { ++ .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, ++ }, ++ { ++ .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, ++ }, ++ { ++ .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, ++ }, ++ { ++ .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, ++ }, ++ { ++ .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, ++ }, ++ { ++ .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, ++ }, ++ { ++ .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, ++ }, ++ { ++ .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, ++ }, ++ { ++ .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, ++ }, ++ { ++ .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, ++ }, ++}; ++ ++#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); ++} ++ ++/* Low-power functions */ ++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_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_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_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); ++} ++ ++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_register_read(uint8_t register_id, uint8_t *value) ++{ ++ return stm32_i2c_mem_read(pmic_i2c_handle, pmic_i2c_addr, ++ (uint16_t)register_id, ++ I2C_MEMADD_SIZE_8BIT, value, ++ 1, I2C_TIMEOUT_MS); ++} ++ ++int stpmic1_register_write(uint8_t register_id, uint8_t value) ++{ ++ int status; ++ ++ status = stm32_i2c_mem_write(pmic_i2c_handle, pmic_i2c_addr, ++ (uint16_t)register_id, ++ I2C_MEMADD_SIZE_8BIT, &value, ++ 1, I2C_TIMEOUT_MS); ++ ++#if ENABLE_ASSERTIONS ++ 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) ++{ ++ uint32_t i; ++ ++ for (i = 0U; i < MAX_REGUL; i++) { ++ const char *name __unused = regulators_table[i].dt_node_name; ++ ++ VERBOSE("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/drivers/st/pmic/stpmu1.c b/drivers/st/pmic/stpmu1.c +deleted file mode 100644 +index 5951899..0000000 +--- a/drivers/st/pmic/stpmu1.c ++++ /dev/null +@@ -1,600 +0,0 @@ +-/* +- * Copyright (c) 2016-2018, STMicroelectronics - All Rights Reserved +- * +- * SPDX-License-Identifier: BSD-3-Clause +- */ +- +-#include +-#include +-#include +-#include +- +-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; +-}; +- +-static struct i2c_handle_s *stpmu_i2c_handle; +-static uint16_t stpmu_i2c_addr; +- +-/* Voltage tables in mV */ +-static const uint16_t buck1_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, +- 1325, +- 1350, +- 1350, +-}; +- +-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, +- }, +- { +- .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, +- }, +- { +- .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, +- }, +- { +- .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, +- }, +- { +- .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, +- }, +- { +- .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, +- }, +- { +- .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, +- }, +- { +- .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, +- }, +- { +- .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, +- }, +- { +- .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, +- }, +- { +- .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, +- }, +-}; +- +-#define MAX_REGUL ARRAY_SIZE(regulators_table) +- +-static const struct regul_struct *stpmu1_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 stpmu1_voltage_find_index(const char *name, +- uint16_t millivolts) +-{ +- const struct regul_struct *regul = stpmu1_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 stpmu1_switch_off(void) +-{ +- return stpmu1_register_update(MAIN_CONTROL_REG, 1, +- SOFTWARE_SWITCH_OFF_ENABLED); +-} +- +-int stpmu1_regulator_enable(const char *name) +-{ +- const struct regul_struct *regul = stpmu1_get_regulator_data(name); +- +- return stpmu1_register_update(regul->control_reg, BIT(0), BIT(0)); +-} +- +-int stpmu1_regulator_disable(const char *name) +-{ +- const struct regul_struct *regul = stpmu1_get_regulator_data(name); +- +- return stpmu1_register_update(regul->control_reg, 0, BIT(0)); +-} +- +-uint8_t stpmu1_is_regulator_enabled(const char *name) +-{ +- uint8_t val; +- const struct regul_struct *regul = stpmu1_get_regulator_data(name); +- +- if (stpmu1_register_read(regul->control_reg, &val) != 0) { +- panic(); +- } +- +- return (val & 0x1U); +-} +- +-int stpmu1_regulator_voltage_set(const char *name, uint16_t millivolts) +-{ +- uint8_t voltage_index = stpmu1_voltage_find_index(name, millivolts); +- const struct regul_struct *regul = stpmu1_get_regulator_data(name); +- +- return stpmu1_register_update(regul->control_reg, voltage_index << 2, +- 0xFC); +-} +- +-int stpmu1_register_read(uint8_t register_id, uint8_t *value) +-{ +- return stm32_i2c_mem_read(stpmu_i2c_handle, stpmu_i2c_addr, +- (uint16_t)register_id, I2C_MEMADD_SIZE_8BIT, +- value, 1, 100000); +-} +- +-int stpmu1_register_write(uint8_t register_id, uint8_t value) +-{ +- int status; +- +- status = stm32_i2c_mem_write(stpmu_i2c_handle, stpmu_i2c_addr, +- (uint16_t)register_id, +- I2C_MEMADD_SIZE_8BIT, &value, 1, 100000); +- +- if (status != 0) { +- return status; +- } +- +- if ((register_id != WATCHDOG_CONTROL_REG) && (register_id <= 0x40U)) { +- uint8_t readval; +- +- status = stpmu1_register_read(register_id, &readval); +- if (status != 0) { +- return status; +- } +- +- if (readval != value) { +- return -1; +- } +- } +- +- return 0; +-} +- +-int stpmu1_register_update(uint8_t register_id, uint8_t value, uint8_t mask) +-{ +- int status; +- uint8_t val; +- +- status = stpmu1_register_read(register_id, &val); +- if (status != 0) { +- return status; +- } +- +- /* Clear bits to update */ +- val &= ~mask; +- +- /* Update appropriate bits*/ +- val |= (value & mask); +- +- /* Send new value on I2C Bus */ +- return stpmu1_register_write(register_id, val); +-} +- +-void stpmu1_bind_i2c(struct i2c_handle_s *i2c_handle, uint16_t i2c_addr) +-{ +- stpmu_i2c_handle = i2c_handle; +- stpmu_i2c_addr = i2c_addr; +-} +diff --git a/drivers/st/qspi/io_qspi.c b/drivers/st/qspi/io_qspi.c +new file mode 100644 +index 0000000..b00b7d6 +--- /dev/null ++++ b/drivers/st/qspi/io_qspi.c +@@ -0,0 +1,349 @@ ++/* ++ * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved. ++ * ++ * SPDX-License-Identifier: BSD-3-Clause ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define QSPI_COMPAT "st,stm32f469-qspi" ++ ++#define TIMEOUT_100_US us2tick(100) ++ ++/* QSPI device functions */ ++static int qspi_dev_open(const uintptr_t init_params, ++ io_dev_info_t **dev_info); ++static int qspi_block_open(io_dev_info_t *dev_info, const uintptr_t spec, ++ io_entity_t *entity); ++static int qspi_dev_init(io_dev_info_t *dev_info, const uintptr_t init_params); ++static int qspi_block_seek(io_entity_t *entity, int mode, ++ signed long long offset); ++static int qspi_block_read(io_entity_t *entity, uintptr_t buffer, ++ size_t length, size_t *length_read); ++static int qspi_block_close(io_entity_t *entity); ++static int qspi_dev_close(io_dev_info_t *dev_info); ++static io_type_t device_type_qspi(void); ++ ++static QSPI_HandleTypeDef *hsd; ++static uint64_t seek_offset; ++ ++static struct dt_node_info qspi_node_info; ++static uintptr_t qspi_mm_base; ++static size_t qspi_mm_size; ++static bool qspi_memory_map; ++ ++static const io_dev_connector_t qspi_dev_connector = { ++ .dev_open = qspi_dev_open ++}; ++ ++static const io_dev_funcs_t qspi_dev_funcs = { ++ .type = device_type_qspi, ++ .open = qspi_block_open, ++ .seek = qspi_block_seek, ++ .size = NULL, ++ .read = qspi_block_read, ++ .write = NULL, ++ .close = qspi_block_close, ++ .dev_init = qspi_dev_init, ++ .dev_close = qspi_dev_close, ++}; ++ ++static const io_dev_info_t qspi_dev_info = { ++ .funcs = &qspi_dev_funcs, ++ .info = (uintptr_t)0, ++}; ++ ++/* Identify the device type as memmap */ ++static io_type_t device_type_qspi(void) ++{ ++ return IO_TYPE_QSPI; ++} ++ ++/* Open a connection to the qspi device */ ++static int qspi_dev_open(const uintptr_t init_params, io_dev_info_t **dev_info) ++{ ++ int qspi_node; ++ int qspi_subnode = 0; ++ int ret; ++ uint32_t fsize; ++ uint32_t flash_max_freq = 0; ++ uint32_t div = 8U; /* Default clock divider */ ++ uint32_t presc; ++ void *fdt; ++ const fdt32_t *cuint = NULL; ++ ++ assert(dev_info); ++ ++ if (fdt_get_address(&fdt) == 0) { ++ panic(); ++ } ++ ++ hsd = (QSPI_HandleTypeDef *)init_params; ++ ++ qspi_node = dt_get_node(&qspi_node_info, -1, QSPI_COMPAT); ++ assert(qspi_node_info.base == (uintptr_t)hsd->instance); ++ ++ *dev_info = (io_dev_info_t *)&qspi_dev_info; ++ ++ ret = fdt_get_reg_props_by_name(qspi_node, "qspi_mm", &qspi_mm_base, ++ &qspi_mm_size); ++ if (ret != 0) { ++ INFO("NOR: Indirect mode\n"); ++ qspi_memory_map = false; ++ ++ /* ++ * Indirect mode is already initialized by bootrom: ++ * no configuration to be done. ++ */ ++ return 0; ++ } ++ ++ /* Size of NOR is 2^(fsise + 1) */ ++ fsize = ((__builtin_ctz(qspi_mm_size) - 1) << QSPI_DCR_FSIZE_SHIFT) & ++ QSPI_DCR_FSIZE_MASK; ++ ++ /* switch to memory mapped mode */ ++ INFO("NOR: Memory mapped mode\n"); ++ qspi_memory_map = true; ++ ++ fdt_for_each_subnode(qspi_subnode, fdt, qspi_node) { ++ cuint = fdt_getprop(fdt, qspi_subnode, "reg", NULL); ++ ++ if ((cuint != NULL) && (fdt32_to_cpu(*cuint) == 0U)) { ++ /* Flash node found */ ++ cuint = fdt_getprop(fdt, qspi_subnode, ++ "spi-max-frequency", NULL); ++ if (cuint != NULL) { ++ flash_max_freq = fdt32_to_cpu(*cuint); ++ } ++ ++ break; ++ } ++ } ++ ++ if (flash_max_freq != 0) { ++ div = div_round_up(stm32mp_clk_get_rate(qspi_node_info.clock), ++ flash_max_freq); ++ } ++ ++ presc = div - 1U; ++ ++ if (presc > UINT8_MAX) { ++ presc = UINT8_MAX; ++ } ++ ++ presc <<= QSPI_CR_PRESCALER_SHIFT; ++ ++ /* Check if QuadSPI was configured in dual flash mode */ ++ if ((hsd->instance->CR & QSPI_CR_DFM) != 0U) { ++ hsd->instance->CR = QSPI_CR_EN | presc | QSPI_CR_DFM; ++ if (hsd->is_dual == 0U) { ++ WARN("Dual NOR configured in IP\n"); ++ WARN(" but set as single in boot context\n"); ++ WARN(" -> Try Dual NOR boot\n"); ++ } ++ } else { ++ hsd->instance->CR = QSPI_CR_EN | presc; ++ if (hsd->is_dual != 0U) { ++ WARN("Single NOR configured in IP\n"); ++ WARN(" but set as dual in boot context\n"); ++ WARN(" -> Try Single NOR boot\n"); ++ } ++ } ++ ++ hsd->instance->DCR = fsize | QSPI_DCR_CSHT; ++ hsd->instance->CCR = QSPI_DFLT_READ_FLAGS | QSPI_CCR_FMODE_MM; ++ ++ return 0; ++} ++ ++static int qspi_dev_init(io_dev_info_t *dev_info, const uintptr_t init_params) ++{ ++ return 0; ++} ++ ++/* Close a connection to the qspi device */ ++static int qspi_dev_close(io_dev_info_t *dev_info) ++{ ++ uint64_t start; ++ ++ /* Send Abort command to end all transfers */ ++ hsd->instance->CR |= QSPI_CR_ABORT; ++ ++ start = timeout_start(); ++ while ((hsd->instance->CR & QSPI_CR_ABORT) != 0U) { ++ if (timeout_elapsed(start, TIMEOUT_100_US)) { ++ return -ETIMEDOUT; ++ } ++ } ++ ++ return 0; ++} ++ ++/* Open a file on the qspi device */ ++static int qspi_block_open(io_dev_info_t *dev_info, const uintptr_t spec, ++ io_entity_t *entity) ++{ ++ seek_offset = 0; ++ return 0; ++} ++ ++/* Seek to a particular file offset on the qspi device */ ++static int qspi_block_seek(io_entity_t *entity, int mode, ++ signed long long offset) ++{ ++ seek_offset = offset; ++ return 0; ++} ++ ++/* Read blocks in indirect mode */ ++static int qspi_block_read_indr(io_entity_t *entity, uintptr_t buffer, ++ size_t length, size_t *length_read) ++{ ++ uint32_t local_length = (uint32_t)length; ++ uint8_t *data = (uint8_t *)buffer; ++ uint8_t *qspi_dr_u8; ++ uint64_t start; ++ int ret = 0; ++ ++ assert(hsd); ++ ++ qspi_dr_u8 = (uint8_t *)&hsd->instance->DR; ++ ++ /* Clear all flags */ ++ hsd->instance->FCR = QSPI_SR_TCF | QSPI_SR_FTF | ++ QSPI_FCR_CTOF | QSPI_FCR_CSMF; ++ hsd->instance->DLR = local_length - 1; ++ hsd->instance->CCR = QSPI_DFLT_READ_FLAGS | QSPI_CCR_FMODE; ++ hsd->instance->AR = seek_offset; ++ ++ while (local_length != 0U) { ++ *data++ = *qspi_dr_u8; ++ local_length--; ++ } ++ ++ *length_read = length; ++ ++ start = timeout_start(); ++ while ((hsd->instance->SR & QSPI_SR_BUSY) != 0U) { ++ if (timeout_elapsed(start, TIMEOUT_100_US)) { ++ ret = -ETIMEDOUT; ++ break; ++ } ++ } ++ ++ return ret; ++} ++ ++static int qspi_block_read_mm_part(io_entity_t *entity, uintptr_t buffer, ++ size_t length, size_t *length_read) ++{ ++ uint64_t start; ++ int ret = 0; ++ ++ assert(hsd); ++ ++ memcpy((uint8_t *)buffer, (uint8_t *)qspi_mm_base + seek_offset, ++ length); ++ ++ *length_read = length; ++ ++ start = timeout_start(); ++ while ((hsd->instance->SR & QSPI_SR_BUSY) != 0U) { ++ if (timeout_elapsed(start, TIMEOUT_100_US)) { ++ ret = -ETIMEDOUT; ++ break; ++ } ++ } ++ ++ /* Send abort to avoid prefetch issues */ ++ hsd->instance->CR |= QSPI_CR_ABORT; ++ ++ start = timeout_start(); ++ while ((hsd->instance->CR & QSPI_CR_ABORT) != 0U) { ++ if (timeout_elapsed(start, TIMEOUT_100_US)) { ++ ret = -ETIMEDOUT; ++ break; ++ } ++ } ++ ++ return ret; ++ ++} ++ ++/* Read blocks in memory map mode */ ++static int qspi_block_read_mm(io_entity_t *entity, uintptr_t buffer, ++ size_t length, size_t *length_read) ++{ ++ if (seek_offset + length + 1 >= qspi_mm_size) { ++ if (length > QSPI_NOR_LBA_SIZE) { ++ size_t length_read_mm, length_read_indr; ++ ++ qspi_block_read_mm_part(entity, buffer, ++ length - QSPI_NOR_LBA_SIZE, ++ &length_read_mm); ++ ++ seek_offset += length - QSPI_NOR_LBA_SIZE; ++ ++ qspi_block_read_indr(entity, buffer + length - ++ QSPI_NOR_LBA_SIZE, ++ QSPI_NOR_LBA_SIZE, ++ &length_read_indr); ++ ++ *length_read = length_read_mm + length_read_indr; ++ } else { ++ qspi_block_read_indr(entity, buffer, length, ++ length_read); ++ } ++ } else { ++ qspi_block_read_mm_part(entity, buffer, length, length_read); ++ } ++ ++ return 0; ++ ++} ++ ++/* Read data from a file on the qspi device */ ++static int qspi_block_read(io_entity_t *entity, uintptr_t buffer, ++ size_t length, size_t *length_read) ++{ ++ if (qspi_memory_map) { ++ return qspi_block_read_mm(entity, buffer, length, length_read); ++ } ++ ++ return qspi_block_read_indr(entity, buffer, length, length_read); ++} ++ ++/* Close a file on the qspi device */ ++static int qspi_block_close(io_entity_t *entity) ++{ ++ return 0; ++} ++ ++/* Exported functions */ ++ ++/* Register the qspi driver with the IO abstraction */ ++int register_io_dev_qspi(const io_dev_connector_t **dev_con) ++{ ++ int result; ++ ++ assert(dev_con); ++ ++ result = io_register_device(&qspi_dev_info); ++ if (result == 0) { ++ *dev_con = &qspi_dev_connector; ++ } ++ ++ return result; ++} +diff --git a/drivers/st/reset/stm32mp1_reset.c b/drivers/st/reset/stm32mp1_reset.c +index 106bbfe..2e19ef0 100644 +--- a/drivers/st/reset/stm32mp1_reset.c ++++ b/drivers/st/reset/stm32mp1_reset.c +@@ -6,34 +6,66 @@ + + #include + #include ++#include + #include + #include + #include +-#include +-#include ++#include ++#include + #include + +-#define RST_CLR_OFFSET 4U ++#define RST_CLR_OFFSET 4U ++#define RESET_TIMEOUT_1MS_IN_US 1000 ++#define RESET_TIMEOUT_STEP_US 10 + +-void stm32mp1_reset_assert(uint32_t id) ++static uint32_t id2reg_offset(unsigned int reset_id) + { +- uint32_t offset = (id / (uint32_t)__LONG_BIT) * sizeof(uintptr_t); +- uint32_t bit = id % (uint32_t)__LONG_BIT; ++ return ((reset_id & GENMASK(31, 5)) >> 5) * sizeof(uint32_t); ++} ++ ++static uint8_t id2reg_bit_pos(unsigned int reset_id) ++{ ++ return (uint8_t)(reset_id & GENMASK(4, 0)); ++} ++ ++void stm32mp_reset_assert(uint32_t id) ++{ ++ uint32_t offset = id2reg_offset(id); ++ uint32_t bitmsk = BIT(id2reg_bit_pos(id)); ++ int nb_tries = RESET_TIMEOUT_1MS_IN_US / RESET_TIMEOUT_STEP_US; ++ uintptr_t rcc_base = stm32mp_rcc_base(); + +- mmio_write_32(RCC_BASE + offset, BIT(bit)); +- while ((mmio_read_32(RCC_BASE + offset) & BIT(bit)) == 0U) { +- ; ++ mmio_write_32(rcc_base + offset, bitmsk); ++ ++ while (((mmio_read_32(rcc_base + offset) & bitmsk) == 0U) && ++ (nb_tries != 0)) { ++ udelay(RESET_TIMEOUT_STEP_US); ++ nb_tries--; ++ } ++ ++ if (nb_tries == 0) { ++ ERROR("Reset timeout\n"); ++ panic(); + } + } + +-void stm32mp1_reset_deassert(uint32_t id) ++void stm32mp_reset_deassert(uint32_t id) + { +- uint32_t offset = ((id / (uint32_t)__LONG_BIT) * sizeof(uintptr_t)) + +- RST_CLR_OFFSET; +- uint32_t bit = id % (uint32_t)__LONG_BIT; ++ uint32_t offset = id2reg_offset(id) + RST_CLR_OFFSET; ++ uint32_t bitmsk = BIT(id2reg_bit_pos(id)); ++ int nb_tries = RESET_TIMEOUT_1MS_IN_US / RESET_TIMEOUT_STEP_US; ++ uintptr_t rcc_base = stm32mp_rcc_base(); ++ ++ mmio_write_32(rcc_base + offset, bitmsk); ++ ++ while (((mmio_read_32(rcc_base + offset) & bitmsk) != 0U) && ++ (nb_tries != 0)) { ++ udelay(RESET_TIMEOUT_STEP_US); ++ nb_tries--; ++ } + +- mmio_write_32(RCC_BASE + offset, BIT(bit)); +- while ((mmio_read_32(RCC_BASE + offset) & BIT(bit)) != 0U) { +- ; ++ if (nb_tries == 0) { ++ ERROR("Reset timeout\n"); ++ panic(); + } + } +diff --git a/drivers/st/rng/stm32_rng.c b/drivers/st/rng/stm32_rng.c +new file mode 100644 +index 0000000..eec75b2 +--- /dev/null ++++ b/drivers/st/rng/stm32_rng.c +@@ -0,0 +1,191 @@ ++/* ++ * Copyright (c) 2018, STMicroelectronics - All Rights Reserved ++ * ++ * SPDX-License-Identifier: BSD-3-Clause ++ */ ++ ++#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 ++#define RNG_TIMEOUT_STEP_US 10 ++ ++struct stm32_rng_instance { ++ uintptr_t base; ++ unsigned long clock; ++}; ++ ++static struct stm32_rng_instance stm32_rng; ++ ++/* ++ * stm32_rng_read - Read a number of random bytes from RNG ++ * out: pointer to the output buffer ++ * size: number of bytes to be read ++ * Return 0 on success, non-0 on failure ++ */ ++int stm32_rng_read(uint8_t *out, uint32_t size) ++{ ++ uint8_t *buf = out; ++ uint32_t len = size; ++ int nb_tries; ++ uint32_t data32; ++ int rc = 0; ++ int count; ++ ++ if (stm32_rng.base == 0U) { ++ return -EPERM; ++ } ++ ++ stm32mp_clk_enable(stm32_rng.clock); ++ ++ if ((mmio_read_32(stm32_rng.base + RNG_CR) & RNG_CR_RNGEN) == 0U) { ++ mmio_write_32(stm32_rng.base + RNG_CR, ++ RNG_CR_RNGEN | RNG_CR_CED); ++ } ++ ++ while (len != 0U) { ++ nb_tries = RNG_TIMEOUT_US / RNG_TIMEOUT_STEP_US; ++ do { ++ uint32_t status = mmio_read_32(stm32_rng.base + RNG_SR); ++ ++ if ((status & (RNG_SR_SECS | RNG_SR_SEIS)) != 0U) { ++ uint8_t i; ++ ++ /* Recommended by the SoC reference manual */ ++ mmio_clrbits_32(stm32_rng.base + RNG_SR, ++ RNG_SR_SEIS); ++ dmb(); ++ for (i = 12; i != 0; i--) { ++ (void)mmio_read_32(stm32_rng.base + ++ RNG_DR); ++ } ++ dmb(); ++ ++ if ((mmio_read_32(stm32_rng.base + RNG_SR) & ++ RNG_SR_SEIS) != 0U) { ++ ERROR("RNG noise\n"); ++ panic(); ++ } ++ } ++ ++ udelay(RNG_TIMEOUT_STEP_US); ++ nb_tries--; ++ if (nb_tries == 0) { ++ rc = -ETIMEDOUT; ++ goto bail; ++ } ++ } while ((mmio_read_32(stm32_rng.base + RNG_SR) & ++ RNG_SR_DRDY) == 0U); ++ ++ count = 4; ++ while (len != 0U) { ++ data32 = mmio_read_32(stm32_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: ++ stm32mp_clk_disable(stm32_rng.clock); ++ ++ if (rc != 0) { ++ memset(out, 0, buf - out); ++ } ++ ++ return rc; ++} ++ ++/* ++ * stm32_rng_init: Initialize rng from DT ++ * return 0 on success, negative value on failure ++ */ ++int stm32_rng_init(void) ++{ ++ void *fdt; ++ struct dt_node_info dt_rng; ++ int node; ++ uint8_t __unused test[43]; ++ ++ if (fdt_get_address(&fdt) == 0) { ++ panic(); ++ } ++ ++ node = dt_get_node(&dt_rng, -1, DT_RNG_COMPAT); ++ if (node < 0) { ++ return 0; ++ } ++ ++ if ((dt_rng.status & DT_SECURE) == 0) { ++ return 0; ++ } ++ ++ assert(dt_rng.base == RNG1_BASE); ++ ++ stm32_rng.base = dt_rng.base; ++ ++ if ((dt_rng.status & DT_NON_SECURE) == DT_NON_SECURE) { ++ stm32mp_register_non_secure_periph_iomem(stm32_rng.base); ++ } else { ++ stm32mp_register_secure_periph_iomem(stm32_rng.base); ++ } ++ ++ if (dt_rng.clock < 0) { ++ panic(); ++ } ++ stm32_rng.clock = (unsigned long)dt_rng.clock; ++ ++ stm32mp_clk_enable(stm32_rng.clock); ++ stm32mp_clk_disable(stm32_rng.clock); ++ ++ if (dt_rng.reset >= 0) { ++ stm32mp_reset_assert((unsigned long)dt_rng.reset); ++ udelay(20); ++ stm32mp_reset_deassert((unsigned long)dt_rng.reset); ++ } ++ ++ VERBOSE("Init RNG done\n"); ++ ++#if STM32MP1_DEBUG_ENABLE ++ memset(test, 0xa5, sizeof(test)); ++ if (stm32_rng_read(test, sizeof(test))) { ++ ERROR("RNG test\n"); ++ panic(); ++ } ++ ++ VERBOSE("RNG test:\n"); ++ VERBOSE_HEXDUMP8(test, sizeof(test)); ++#endif ++ ++ return 0; ++} +diff --git a/drivers/st/rtc/stm32_rtc.c b/drivers/st/rtc/stm32_rtc.c +new file mode 100644 +index 0000000..017c46d +--- /dev/null ++++ b/drivers/st/rtc/stm32_rtc.c +@@ -0,0 +1,499 @@ ++/* ++ * 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 GENMASK(3, 0) ++#define RTC_TR_ST_MASK GENMASK(6, 4) ++#define RTC_TR_ST_SHIFT 4 ++#define RTC_TR_MNU_MASK GENMASK(11, 8) ++#define RTC_TR_MNU_SHIFT 8 ++#define RTC_TR_MNT_MASK GENMASK(14, 12) ++#define RTC_TR_MNT_SHIFT 12 ++#define RTC_TR_HU_MASK GENMASK(19, 16) ++#define RTC_TR_HU_SHIFT 16 ++#define RTC_TR_HT_MASK GENMASK(21, 20) ++#define RTC_TR_HT_SHIFT 20 ++#define RTC_TR_PM BIT(22) ++ ++#define RTC_DR_DU_MASK GENMASK(3, 0) ++#define RTC_DR_DT_MASK GENMASK(5, 4) ++#define RTC_DR_DT_SHIFT 4 ++#define RTC_DR_MU_MASK GENMASK(11, 8) ++#define RTC_DR_MU_SHIFT 8 ++#define RTC_DR_MT BIT(12) ++#define RTC_DR_MT_SHIFT 12 ++#define RTC_DR_WDU_MASK GENMASK(15, 13) ++#define RTC_DR_WDU_SHIFT 13 ++#define RTC_DR_YU_MASK GENMASK(19, 16) ++#define RTC_DR_YU_SHIFT 16 ++#define RTC_DR_YT_MASK GENMASK(23, 20) ++#define RTC_DR_YT_SHIFT 20 ++ ++#define RTC_SSR_SS_MASK GENMASK(15, 0) ++ ++#define RTC_ICSR_ALRAWF BIT(0) ++#define RTC_ICSR_RSF BIT(5) ++ ++#define RTC_PRER_PREDIV_S_MASK GENMASK(14, 0) ++ ++#define RTC_CR_BYPSHAD BIT(5) ++#define RTC_CR_BYPSHAD_SHIFT 5 ++#define RTC_CR_ALRAE BIT(8) ++#define RTC_CR_ALRAIE BIT(12) ++#define RTC_CR_TAMPTS BIT(25) ++ ++#define RTC_SMCR_TS_DPROT BIT(3) ++ ++#define RTC_TSDR_DU_MASK GENMASK(3, 0) ++#define RTC_TSDR_DU_SHIFT 0 ++#define RTC_TSDR_DT_MASK GENMASK(5, 4) ++#define RTC_TSDR_DT_SHIFT 4 ++#define RTC_TSDR_MU_MASK GENMASK(11, 8) ++#define RTC_TSDR_MU_SHIFT 8 ++ ++#define RTC_ALRMAR_DU_SHIFT 24 ++ ++#define RTC_SR_TSF BIT(3) ++#define RTC_SR_TSOVF BIT(4) ++ ++#define RTC_SCR_CTSF BIT(3) ++#define RTC_SCR_CTSOVF BIT(4) ++ ++#define RTC_WPR_KEY1 0xCA ++#define RTC_WPR_KEY2 0x53 ++#define RTC_WPR_KEY_LOCK 0xFF ++ ++static struct dt_node_info rtc_dev; ++ ++static struct spinlock lock; ++ ++void stm32_rtc_regs_lock(void) ++{ ++ const uint32_t mask = SCTLR_M_BIT | SCTLR_C_BIT; ++ ++ /* Lock is currently required only when MMU and cache are enabled */ ++ if ((read_sctlr() & mask) == mask) { ++ spin_lock(&lock); ++ } ++} ++ ++void stm32_rtc_regs_unlock(void) ++{ ++ const uint32_t mask = SCTLR_M_BIT | SCTLR_C_BIT; ++ ++ /* Unlock is required only when MMU and cache are enabled */ ++ if ((read_sctlr() & mask) == mask) { ++ spin_unlock(&lock); ++ } ++} ++ ++static void stm32_rtc_write_unprotect(void) ++{ ++ mmio_write_32(rtc_dev.base + RTC_WPR, RTC_WPR_KEY1); ++ mmio_write_32(rtc_dev.base + RTC_WPR, RTC_WPR_KEY2); ++} ++ ++static void stm32_rtc_write_protect(void) ++{ ++ mmio_write_32(rtc_dev.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(rtc_dev.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) ++{ ++ bool bypshad = stm32_rtc_get_bypshad(); ++ ++ if (!bypshad) { ++ mmio_clrbits_32((uint32_t)(rtc_dev.base + RTC_ICSR), ++ RTC_ICSR_RSF); ++ while ((mmio_read_32(rtc_dev.base + RTC_ICSR) & RTC_ICSR_RSF) != ++ RTC_ICSR_RSF) { ++ ; ++ } ++ } ++ ++ calendar->ssr = mmio_read_32(rtc_dev.base + RTC_SSR); ++ calendar->tr = mmio_read_32(rtc_dev.base + RTC_TR); ++ calendar->dr = mmio_read_32(rtc_dev.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) ++{ ++ assert(cal != NULL); ++ assert(tm != NULL); ++ ++ 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) ++{ ++ assert(cal != NULL); ++ assert(tm != NULL); ++ ++ 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) ++{ ++ assert(time != NULL); ++ ++ struct stm32_rtc_calendar cal_tamp; ++ ++ cal_tamp.tr = mmio_read_32(rtc_dev.base + RTC_TSTR); ++ cal_tamp.dr = mmio_read_32(rtc_dev.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) ++{ ++ bool read_twice = stm32mp1_rtc_get_read_twice(); ++ ++ stm32_rtc_regs_lock(); ++ stm32mp_clk_enable(rtc_dev.clock); ++ ++ stm32_rtc_read_calendar(calendar); ++ ++ if (read_twice) { ++ uint32_t tr_save = calendar->tr; ++ ++ stm32_rtc_read_calendar(calendar); ++ ++ if (calendar->tr != tr_save) { ++ stm32_rtc_read_calendar(calendar); ++ } ++ } ++ ++ stm32mp_clk_disable(rtc_dev.clock); ++ stm32_rtc_regs_unlock(); ++} ++ ++/******************************************************************************* ++ * 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(rtc_dev.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; ++ ++ stm32mp_clk_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); ++ ++ stm32mp_clk_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) ++{ ++ stm32_rtc_regs_lock(); ++ stm32mp_clk_enable(rtc_dev.clock); ++ ++ if ((mmio_read_32(rtc_dev.base + RTC_SR) & RTC_SR_TSF) != 0U) { ++ /* Print timestamp for tamper event */ ++ stm32_rtc_read_timestamp(tamp_ts); ++ mmio_setbits_32(rtc_dev.base + RTC_SCR, RTC_SCR_CTSF); ++ if ((mmio_read_32(rtc_dev.base + RTC_SR) & RTC_SR_TSOVF) != ++ 0U) { ++ /* Overflow detected */ ++ mmio_setbits_32(rtc_dev.base + RTC_SCR, RTC_SCR_CTSOVF); ++ } ++ } ++ ++ stm32mp_clk_disable(rtc_dev.clock); ++ stm32_rtc_regs_unlock(); ++} ++ ++/******************************************************************************* ++ * This function enable the timestamp bit for tamper and secure timestamp ++ * access. ++ ******************************************************************************/ ++void stm32_rtc_set_tamper_timestamp(void) ++{ ++ stm32_rtc_regs_lock(); ++ stm32mp_clk_enable(rtc_dev.clock); ++ ++ stm32_rtc_write_unprotect(); ++ ++ /* Enable tamper timestamper */ ++ mmio_setbits_32(rtc_dev.base + RTC_CR, RTC_CR_TAMPTS); ++ ++ /* Secure Timestamp bit */ ++ mmio_clrbits_32(rtc_dev.base + RTC_SMCR, RTC_SMCR_TS_DPROT); ++ ++ stm32_rtc_write_protect(); ++ ++ stm32mp_clk_disable(rtc_dev.clock); ++ stm32_rtc_regs_unlock(); ++} ++ ++/******************************************************************************* ++ * This function return state of tamper timestamp. ++ ******************************************************************************/ ++bool stm32_rtc_is_timestamp_enable(void) ++{ ++ bool ret; ++ ++ stm32mp_clk_enable(rtc_dev.clock); ++ ++ ret = (mmio_read_32(rtc_dev.base + RTC_CR) & RTC_CR_TAMPTS) != 0U; ++ ++ stm32mp_clk_disable(rtc_dev.clock); ++ ++ return ret; ++} ++ ++/******************************************************************************* ++ * RTC initialisation function. ++ ******************************************************************************/ ++int stm32_rtc_init(void) ++{ ++ int node; ++ ++ node = dt_get_node(&rtc_dev, -1, RTC_COMPAT); ++ if (node < 0) { ++ return node; ++ } ++ ++ if (rtc_dev.status == DT_SECURE) { ++ stm32mp_register_secure_periph_iomem(rtc_dev.base); ++ } else { ++ stm32mp_register_non_secure_periph_iomem(rtc_dev.base); ++ } ++ ++ return 0; ++} +diff --git a/drivers/st/tamper/stm32_tamp.c b/drivers/st/tamper/stm32_tamp.c +new file mode 100644 +index 0000000..0bfa177 +--- /dev/null ++++ b/drivers/st/tamper/stm32_tamp.c +@@ -0,0 +1,375 @@ ++/* ++ * Copyright (c) 2018, STMicroelectronics - All Rights Reserved ++ * ++ * SPDX-License-Identifier: BSD-3-Clause ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define DT_TAMP_COMPAT "st,stm32-tamp" ++/* STM32 Registers */ ++#define STM32_TAMP_CR1 0x00U ++#define STM32_TAMP_CR2 0x04U ++#define STM32_TAMP_FLTCR 0x0CU ++#define STM32_TAMP_ATCR 0x10U ++#define STM32_TAMP_ATSEEDR 0x14U ++#define STM32_TAMP_ATOR 0x18U ++#define STM32_TAMP_SMCR 0x20U ++#define STM32_TAMP_IER 0x2CU ++#define STM32_TAMP_SR 0x30U ++#define STM32_TAMP_SCR 0x3CU ++#define STM32_TAMP_COUNTR 0x40U ++#define STM32_TAMP_OR 0x50U ++#define STM32_TAMP_HWCFGR2 0x3ECU ++#define STM32_TAMP_HWCFGR1 0x3F0U ++#define STM32_TAMP_VERR 0x3F4U ++#define STM32_TAMP_IPIDR 0x3F8U ++#define STM32_TAMP_SIDR 0x3FCU ++ ++/* STM32_TAMP_FLTCR bit fields */ ++#define STM32_TAMP_FLTCR_TAMPFREQ GENMASK(2, 0) ++#define STM32_TAMP_FLTCR_TAMPFLT GENMASK(4, 3) ++#define STM32_TAMP_FLTCR_TAMPPRCH GENMASK(6, 5) ++#define STM32_TAMP_FLTCR_TAMPPUDIS BIT(7) ++ ++/* STM32_TAMP_ATCR bit fields */ ++#define STM32_TAMP_ATCR_ATCKSEL GENMASK(18, 16) ++#define STM32_TAMP_ATCR_ATPER GENMASK(26, 24) ++#define STM32_TAMP_ATCR_ATOSHARE BIT(30) ++#define STM32_TAMP_ATCR_FLTEN BIT(31) ++ ++/* STM32_TAMP_ATOR bit fields */ ++#define STM32_TAMP_PRNG GENMASK(7, 0) ++#define STM32_TAMP_SEEDF BIT(14) ++#define STM32_TAMP_INITS BIT(15) ++ ++/* STM32_TAMP_IER bit fields */ ++#define STM32_TAMP_IER_TAMPXIE_ALL GENMASK(7, 0) ++#define STM32_TAMP_IER_ITAMPXIE_ALL GENMASK(31, 16) ++ ++/* STM32_TAMP_SR bit fields */ ++#define STM32_TAMP_SR_TAMPXF_MASK GENMASK(7, 0) ++#define STM32_TAMP_SR_ITAMPXF_MASK GENMASK(31, 16) ++ ++/* STM32_TAMP_SMCR but fields */ ++#define STM32_TAMP_SMCR_DPROT BIT(31) ++ ++/* STM32_TAMP_CFGR bit fields */ ++#define STM32_TAMP_OR_OUT3RMP BIT(0) ++ ++/* STM32_TAMP_HWCFGR2 bit fields */ ++#define STM32_TAMP_HWCFGR2_TZ GENMASK(11, 8) ++#define STM32_TAMP_HWCFGR2_OR GENMASK(7, 0) ++ ++/* STM32_TAMP_HWCFGR1 bit fields */ ++#define STM32_TAMP_HWCFGR1_BKPREG GENMASK(7, 0) ++#define STM32_TAMP_HWCFGR1_TAMPER GENMASK(11, 8) ++#define STM32_TAMP_HWCFGR1_ACTIVE GENMASK(15, 12) ++#define STM32_TAMP_HWCFGR1_INTERN GENMASK(31, 16) ++ ++/* STM32_TAMP_VERR bit fields */ ++#define STM32_TAMP_VERR_MINREV GENMASK(3, 0) ++#define STM32_TAMP_VERR_MAJREV GENMASK(7, 4) ++ ++#define STM32_TAMP_MAX_INTERNAL 16U ++#define STM32_TAMP_MAX_EXTERNAL 8U ++ ++struct stm32_tamp_instance { ++ uintptr_t base; ++ uint32_t clock; ++ uint32_t hwconf1; ++ uint32_t hwconf2; ++ uint16_t int_nbtamp; ++ uint8_t ext_nbtamp; ++ struct stm32_tamp_int *int_tamp; ++ struct stm32_tamp_ext *ext_tamp; ++}; ++ ++static struct stm32_tamp_instance stm32_tamp; ++ ++static void stm32_tamp_set_secured(unsigned long base) ++{ ++ mmio_clrbits_32(base + STM32_TAMP_SMCR, STM32_TAMP_SMCR_DPROT); ++} ++ ++static void stm32_tamp_configure_or(unsigned long base, uint32_t out3) ++{ ++ mmio_setbits_32(base + STM32_TAMP_OR, out3); ++} ++ ++static int stm32_tamp_seed_init(unsigned long base) ++{ ++ /* Need RNG access */ ++ uint32_t timeout = 100; ++ uint8_t idx; ++ ++ for (idx = 0; idx < 4U; idx++) { ++ uint32_t rnd; ++ ++ if (stm32_rng_read((uint8_t *)&rnd, sizeof(uint32_t)) != 0) { ++ return -1; ++ } ++ ++ VERBOSE("Seed init %u\n", rnd); ++ mmio_write_32(base + STM32_TAMP_ATSEEDR, rnd); ++ } ++ ++ while (((mmio_read_32(base + STM32_TAMP_ATOR) & ++ STM32_TAMP_SEEDF) != 0U) && ++ (timeout != 0U)) { ++ timeout--; ++ } ++ ++ if (timeout == 0U) { ++ return -1; ++ } ++ ++ return 0; ++} ++ ++static void stm32_tamp_reset_register(unsigned long base) ++{ ++ /* Disable all internal tamper */ ++ mmio_write_32(base + STM32_TAMP_CR1, 0U); ++ ++ /* Disable all external tamper */ ++ mmio_write_32(base + STM32_TAMP_CR2, 0U); ++ ++ /* Clean configuration registers */ ++ mmio_write_32(base + STM32_TAMP_FLTCR, 0U); ++ mmio_write_32(base + STM32_TAMP_ATCR, 0U); ++ mmio_clrbits_32(base + STM32_TAMP_SMCR, STM32_TAMP_SMCR_DPROT); ++ ++ /* Clean Tamper IT */ ++ mmio_write_32(base + STM32_TAMP_IER, 0U); ++ mmio_write_32(base + STM32_TAMP_SCR, ~0U); ++ ++ mmio_clrbits_32(base + STM32_TAMP_OR, STM32_TAMP_OR_OUT3RMP); ++} ++ ++void stm32_tamp_write_mcounter(void) ++{ ++ mmio_write_32(stm32_tamp.base + STM32_TAMP_COUNTR, 1U); ++} ++ ++void stm32_tamp_configure_internal(struct stm32_tamp_int *tamper_list, ++ uint16_t nb_tamper) ++{ ++ uint16_t i; ++ ++ assert(nb_tamper < STM32_TAMP_MAX_INTERNAL); ++ ++ for (i = 0; i < nb_tamper; i++) { ++ int id = tamper_list[i].id; ++ uint32_t u_id; ++ ++ if (id == -1) { ++ continue; ++ } ++ ++ u_id = (uint32_t)id; ++ ++ if ((stm32_tamp.hwconf1 & BIT(u_id + 16U)) != 0U) { ++ mmio_setbits_32(stm32_tamp.base + STM32_TAMP_CR1, ++ BIT(u_id + 16U)); ++ mmio_setbits_32(stm32_tamp.base + STM32_TAMP_IER, ++ BIT(u_id + 16U)); ++ } ++ } ++ ++ stm32_tamp.int_tamp = tamper_list; ++ stm32_tamp.int_nbtamp = nb_tamper; ++} ++ ++void stm32_tamp_configure_external(struct stm32_tamp_ext *ext_tamper_list, ++ uint8_t nb_tamper, uint32_t passive_conf, ++ uint32_t active_conf) ++{ ++ /* External configuration */ ++ uint8_t i, active_tamp = 0; ++ ++ assert(nb_tamper < STM32_TAMP_MAX_EXTERNAL); ++ ++ /* Enable external Tamp */ ++ for (i = 0; i < nb_tamper; i++) { ++ int id = ext_tamper_list[i].id; ++ uint32_t reg = 0, u_id; ++ ++ if (id == -1) { ++ continue; ++ } ++ ++ u_id = (uint32_t)id; ++ ++ mmio_setbits_32(stm32_tamp.base + STM32_TAMP_CR1, ++ BIT(u_id)); ++ ++ if (ext_tamper_list[i].mode == TAMP_TRIG_ON) { ++ reg |= BIT(u_id + 24U); ++ } ++ ++ if (ext_tamper_list[i].mode == TAMP_ACTIVE) { ++ active_tamp |= BIT(u_id); ++ } ++ ++ if (ext_tamper_list[i].erase != 0U) { ++ reg |= BIT(u_id); ++ } ++ ++ if (ext_tamper_list[i].evt_mask != 0U) { ++ reg |= BIT(u_id + 16U); ++ } else { ++ mmio_setbits_32(stm32_tamp.base + STM32_TAMP_IER, ++ BIT(u_id)); ++ } ++ ++ mmio_setbits_32(stm32_tamp.base + STM32_TAMP_CR2, reg); ++ } ++ ++ /* Filter mode register set */ ++ mmio_write_32(stm32_tamp.base + STM32_TAMP_FLTCR, passive_conf); ++ ++ /* Active mode configuration */ ++ if (active_tamp != 0U) { ++ mmio_write_32(stm32_tamp.base + STM32_TAMP_ATCR, ++ active_conf | active_tamp); ++ if (stm32_tamp_seed_init(stm32_tamp.base) != 0) { ++ ERROR("Active tamper: SEED not initialized\n"); ++ panic(); ++ } ++ } ++ ++ stm32_tamp.ext_tamp = ext_tamper_list; ++ stm32_tamp.ext_nbtamp = nb_tamper; ++} ++ ++void stm32_tamp_it_handler(void) ++{ ++ uint32_t it = mmio_read_32(stm32_tamp.base + STM32_TAMP_SR); ++ uint8_t tamp = 0; ++ struct stm32_rtc_time tamp_ts; ++ struct stm32_tamp_int *int_list = stm32_tamp.int_tamp; ++ struct stm32_tamp_ext *ext_list = stm32_tamp.ext_tamp; ++ ++ if (stm32_rtc_is_timestamp_enable()) { ++ stm32_rtc_get_timestamp(&tamp_ts); ++ INFO("Tamper Event Occurred\n"); ++ INFO("Date : %u/%u\n \t Time : %u:%u:%u\n", ++ tamp_ts.day, tamp_ts.month, tamp_ts.hour, ++ tamp_ts.min, tamp_ts.sec); ++ } ++ ++ /* Internal tamper interrupt */ ++ if ((it & STM32_TAMP_IER_ITAMPXIE_ALL) == 0U) { ++ goto tamp_ext; ++ } ++ ++ while ((it != 0U) && (tamp < stm32_tamp.int_nbtamp)) { ++ uint32_t int_id = (uint32_t)int_list[tamp].id; ++ ++ if ((it & BIT(int_id + 16U)) != 0U) { ++ if (int_list[tamp].it_handler != NULL) { ++ int_list[tamp].it_handler(); ++ } ++ ++ mmio_setbits_32(stm32_tamp.base + STM32_TAMP_SCR, ++ BIT(int_id + 16U)); ++ it &= ~BIT(int_id + 16U); ++ } ++ tamp++; ++ } ++ ++tamp_ext: ++ tamp = 0; ++ /* External tamper interrupt */ ++ if ((it == 0U) || ((it & STM32_TAMP_IER_TAMPXIE_ALL) == 0U)) { ++ return; ++ } ++ ++ while ((it != 0U) && (tamp < stm32_tamp.ext_nbtamp)) { ++ uint32_t ext_id = (uint32_t)ext_list[tamp].id; ++ ++ if ((it & BIT(ext_id)) != 0U) { ++ if (ext_list[tamp].it_handler != NULL) { ++ ext_list[tamp].it_handler(); ++ } ++ ++ mmio_setbits_32(stm32_tamp.base + STM32_TAMP_SCR, ++ BIT(ext_id)); ++ it &= ~BIT(ext_id); ++ } ++ tamp++; ++ } ++} ++ ++int stm32_tamp_init(void) ++{ ++ int node; ++ struct dt_node_info dt_tamp; ++ void *fdt; ++ uint32_t rev __unused; ++ ++ if (fdt_get_address(&fdt) == 0) { ++ return -EPERM; ++ } ++ ++ node = dt_get_node(&dt_tamp, -1, DT_TAMP_COMPAT); ++ if (node < 0) { ++ return -FDT_ERR_NOTFOUND; ++ } ++ ++ assert(dt_tamp.base != 0U); ++ assert(dt_tamp.clock != -1); ++ ++ stm32_tamp.base = dt_tamp.base; ++ stm32_tamp.clock = (uint32_t)dt_tamp.clock; ++ ++ /* Init Tamp clock */ ++ stm32mp_clk_enable(stm32_tamp.clock); ++ ++ /* Reset Tamp register without modifying backup registers conf */ ++ stm32_tamp_reset_register(stm32_tamp.base); ++ ++ /* Check if tamper are secured */ ++ if (dt_tamp.status != DT_SECURE) { ++ return 0; ++ } ++ ++ stm32_tamp.hwconf1 = mmio_read_32(stm32_tamp.base + STM32_TAMP_HWCFGR1); ++ stm32_tamp.hwconf2 = mmio_read_32(stm32_tamp.base + STM32_TAMP_HWCFGR2); ++ ++ rev = mmio_read_32(stm32_tamp.base + STM32_TAMP_VERR); ++ VERBOSE("STM32 TAMPER V%u.%u\n", (rev & STM32_TAMP_VERR_MAJREV) >> 4, ++ rev & STM32_TAMP_VERR_MINREV); ++ ++ if ((stm32_tamp.hwconf2 & STM32_TAMP_HWCFGR2_TZ) == 0U) { ++ ERROR("Tamper IP doesn't support trustzone"); ++ return -EPERM; ++ } ++ ++ stm32_tamp_set_secured(stm32_tamp.base); ++ ++ if (fdt_getprop(fdt, node, "st,out3-pc13", NULL) != NULL) { ++ stm32_tamp_configure_or(stm32_tamp.base, 1); ++ } ++ ++ if (stm32_gic_enable_spi(node, NULL) != 0) { ++ panic(); ++ } ++ ++ if (fdt_getprop(fdt, node, "wakeup-source", NULL) != NULL) { ++ mmio_setbits_32(EXTI_BASE + EXTI_TZENR1, EXTI_TZENR1_TZEN18); ++ mmio_setbits_32(EXTI_BASE + EXTI_C1IMR1, EXTI_IMR1_IM18); ++ } ++ ++ return 1; ++} +diff --git a/drivers/st/timer/stm32_timer.c b/drivers/st/timer/stm32_timer.c +new file mode 100644 +index 0000000..6d36e31 +--- /dev/null ++++ b/drivers/st/timer/stm32_timer.c +@@ -0,0 +1,297 @@ ++/* ++ * Copyright (c) 2018, STMicroelectronics - All Rights Reserved ++ * ++ * SPDX-License-Identifier: BSD-3-Clause ++ */ ++ ++#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(2, 0) /* Slave mode selection */ ++#define TIM_SMCR_TS GENMASK(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(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 { ++ uintptr_t base; ++ unsigned long clk; ++ unsigned long freq; ++ uint8_t cal_input; ++}; ++ ++static struct stm32_timer_instance stm32_timer[TIM_MAX_INSTANCE]; ++ ++static int stm32_timer_get_dt_node(struct dt_node_info *info, int offset) ++{ ++ int node; ++ ++ node = dt_get_node(info, offset, TIM_COMPAT); ++ if (node < 0) { ++ if (offset == -1) { ++ WARN("%s: No TIMER found\n", __func__); ++ } ++ return -FDT_ERR_NOTFOUND; ++ } ++ ++ return node; ++} ++ ++static void stm32_timer_config(struct stm32_timer_instance *timer) ++{ ++ stm32mp_clk_enable(timer->clk); ++ ++ timer->freq = stm32mp_clk_timer_get_rate(timer->clk); ++ ++ if ((mmio_read_32(timer->base + TIM_TISEL) & TIM_TISEL_TI1SEL_MASK) != ++ timer->cal_input) { ++ mmio_clrsetbits_32(timer->base + TIM_CCMR1, ++ TIM_CCMR_CC1S_TI1 | TIM_CCMR_CC1S_TI2, ++ TIM_CCMR_CC1S_TI1); ++ ++ mmio_clrbits_32(timer->base + TIM_CCER, ++ TIM_CCER_CC1P | TIM_CCER_CC1NP); ++ ++ mmio_clrsetbits_32(timer->base + TIM_SMCR, ++ TIM_SMCR_TS | TIM_SMCR_SMS, ++ (TIM_SMCR_TS_TI1FP1 << TIM_SMCR_TS_SHIFT) | ++ TIM_SMCR_SMS_RESET); ++ ++ mmio_write_32(timer->base + TIM_TISEL, timer->cal_input); ++ mmio_setbits_32(timer->base + TIM_CR1, TIM_CR1_CEN); ++ mmio_setbits_32(timer->base + TIM_CCER, TIM_CCER_CC1E); ++ } ++ ++ stm32mp_clk_disable(timer->clk); ++} ++ ++static uint32_t stm32_timer_start_capture(struct stm32_timer_instance *timer) ++{ ++ uint32_t timeout = TIM_TIMEOUT_US / TIM_TIMEOUT_STEP_US; ++ uint32_t counter = 0U; ++ uint32_t old_counter = 0U; ++ int twice = 0; ++ ++ stm32_timer_config(timer); ++ ++ stm32mp_clk_enable(timer->clk); ++ ++ mmio_write_32(timer->base + TIM_SR, 0U); ++ while (((mmio_read_32(timer->base + TIM_SR) & ++ TIM_SR_UIF) == 0U) && (timeout != 0U)) { ++ udelay(TIM_TIMEOUT_STEP_US); ++ timeout--; ++ } ++ ++ if (timeout == 0U) { ++ goto out; ++ } ++ ++ mmio_write_32(timer->base + TIM_SR, 0U); ++ ++ while ((twice < 2) || (old_counter != counter)) { ++ timeout = TIM_TIMEOUT_US / TIM_TIMEOUT_STEP_US; ++ ++ while (((mmio_read_32(timer->base + TIM_SR) & ++ TIM_SR_CC1IF) == 0U) && (timeout != 0U)) { ++ udelay(TIM_TIMEOUT_STEP_US); ++ timeout--; ++ } ++ if (timeout == 0U) { ++ goto out; ++ } ++ ++ old_counter = counter; ++ counter = mmio_read_32(timer->base + TIM_CCR1); ++ twice++; ++ } ++ ++out: ++ stm32mp_clk_disable(timer->clk); ++ ++ if (timeout == 0U) { ++ return 0U; ++ } ++ ++ return counter; ++} ++ ++unsigned long stm32_timer_hsi_freq(void) ++{ ++ struct stm32_timer_instance *timer = &stm32_timer[HSI_CAL]; ++ unsigned long hsi_freq; ++ uint32_t counter; ++ ++ if (timer->base == 0) { ++ return 0; ++ } ++ ++ counter = stm32_timer_start_capture(timer); ++ VERBOSE("Counter value %i\n", counter); ++ ++ if (counter == 0U) { ++ return 0; ++ } ++ ++ hsi_freq = (timer->freq / counter) << TIM_PRESCAL_HSI; ++ ++ return hsi_freq; ++} ++ ++unsigned long stm32_timer_csi_freq(void) ++{ ++ struct stm32_timer_instance *timer = &stm32_timer[CSI_CAL]; ++ unsigned long csi_freq; ++ uint32_t counter; ++ ++ if (timer->base == 0) { ++ return 0; ++ } ++ ++ counter = stm32_timer_start_capture(timer); ++ VERBOSE("Counter value %i\n", counter); ++ ++ if (counter == 0U) { ++ return 0; ++ } ++ ++ csi_freq = (timer->freq / counter) << TIM_PRESCAL_CSI; ++ ++ return csi_freq; ++} ++ ++/* ++ * 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) ++{ ++ switch (type) { ++ case HSI_CAL: ++ if (stm32_timer[HSI_CAL].base != 0) { ++ *timer_freq_cb = stm32_timer_hsi_freq; ++ } ++ break; ++ ++ case CSI_CAL: ++ if (stm32_timer[CSI_CAL].base != 0) { ++ *timer_freq_cb = stm32_timer_csi_freq; ++ } ++ break; ++ ++ default: ++ panic(); ++ } ++} ++ ++/* ++ * Initialize timer from DT ++ * return 0 if disabled, 1 if enabled, else < 0 ++ */ ++int stm32_timer_init(void) ++{ ++ void *fdt; ++ struct dt_node_info dt_timer; ++ int node = -1; ++ uint8_t nb_timer = 0; ++ ++ if (fdt_get_address(&fdt) == 0) { ++ return -EPERM; ++ } ++ ++ for (node = stm32_timer_get_dt_node(&dt_timer, node); ++ node != -FDT_ERR_NOTFOUND; ++ node = stm32_timer_get_dt_node(&dt_timer, node)) { ++ ++ if (dt_timer.status == DT_SECURE) { ++ struct stm32_timer_instance *timer; ++ const fdt32_t *cuint; ++ ++ nb_timer++; ++ ++ cuint = fdt_getprop(fdt, node, "st,hsi-cal-input", ++ NULL); ++ if (cuint != NULL) { ++ timer = &stm32_timer[HSI_CAL]; ++ timer->base = dt_timer.base; ++ timer->clk = dt_timer.clock; ++ timer->freq = ++ stm32mp_clk_timer_get_rate(timer->clk); ++ timer->cal_input = ++ (uint8_t)fdt32_to_cpu(*cuint); ++ stm32_timer_config(timer); ++ } ++ ++ cuint = fdt_getprop(fdt, node, "st,csi_cal-input", ++ NULL); ++ if (cuint != NULL) { ++ timer = &stm32_timer[CSI_CAL]; ++ timer->base = dt_timer.base; ++ timer->clk = dt_timer.clock; ++ timer->freq = ++ stm32mp_clk_timer_get_rate(timer->clk); ++ timer->cal_input = ++ (uint8_t)fdt32_to_cpu(*cuint); ++ stm32_timer_config(timer); ++ } ++ } ++ } ++ ++ VERBOSE("%u TIMER instance%s found\n", nb_timer, ++ nb_timer > 1 ? "s" : ""); ++ ++ if (nb_timer == 0U) { ++ return -FDT_ERR_NOTFOUND; ++ } ++ ++ return 0; ++} +diff --git a/drivers/st/uart/aarch32/stm32_console.S b/drivers/st/uart/aarch32/stm32_console.S +index 792703a..823e38b 100644 +--- a/drivers/st/uart/aarch32/stm32_console.S ++++ b/drivers/st/uart/aarch32/stm32_console.S +@@ -4,30 +4,27 @@ + * SPDX-License-Identifier: BSD-3-Clause + */ + #include ++#include ++#define USE_FINISH_CONSOLE_REG_2 ++#include ++#include ++#include + + #define USART_TIMEOUT 0x1000 + +-#define USART_CR1 0x00 +-#define USART_CR1_UE 0x00000001 +-#define USART_CR1_TE 0x00000008 +-#define USART_CR1_FIFOEN 0x20000000 +- +-#define USART_CR2 0x04 +-#define USART_CR2_STOP 0x00003000 +- +-#define USART_BRR 0x0C ++ /* ++ * "core" functions are low-level implementations that don't require ++ * writeable memory and are thus safe to call in BL1 crash context. ++ */ ++ .globl console_stm32_core_init ++ .globl console_stm32_core_putc ++ .globl console_stm32_core_getc ++ .globl console_stm32_core_flush + +-#define USART_ISR 0x1C +-#define USART_ISR_TC 0x00000040 +-#define USART_ISR_TXE 0x00000080 +-#define USART_ISR_TEACK 0x00200000 ++ .globl console_stm32_putc ++ .globl console_stm32_flush + +-#define USART_TDR 0x28 + +- .globl console_core_init +- .globl console_core_putc +- .globl console_core_getc +- .globl console_core_flush + + /* ----------------------------------------------------------------- + * int console_core_init(uintptr_t base_addr, +@@ -45,7 +42,7 @@ + * Clobber list : r1, r2, r3 + * ----------------------------------------------------------------- + */ +-func console_core_init ++func console_stm32_core_init + /* Check the input base address */ + cmp r0, #0 + beq core_init_fail +@@ -88,21 +85,55 @@ teack_loop: + core_init_fail: + mov r0, #0 + bx lr +-endfunc console_core_init ++endfunc console_stm32_core_init + +- /* --------------------------------------------------------------- ++ .globl console_stm32_register ++ ++ /* ------------------------------------------------------- ++ * int console_stm32_register(uintptr_t baseaddr, ++ * uint32_t clock, uint32_t baud, ++ * struct console_stm32 *console); ++ * Function to initialize and register a new STM32 ++ * console. Storage passed in for the console struct ++ * *must* be persistent (i.e. not from the stack). ++ * In: r0 - UART register base address ++ * r1 - UART clock in Hz ++ * r2 - Baud rate ++ * r3 - pointer to empty console_stm32 struct ++ * Out: return 1 on success, 0 on error ++ * Clobber list : r0, r1, r2 ++ * ------------------------------------------------------- ++ */ ++func console_stm32_register ++ push {r4, lr} ++ mov r4, r3 ++ cmp r4, #0 ++ beq register_fail ++ str r0, [r4, #CONSOLE_T_STM32_BASE] ++ ++ bl console_stm32_core_init ++ cmp r0, #0 ++ beq register_fail ++ ++ mov r0, r4 ++ pop {r4, lr} ++ finish_console_register stm32 putc=1, getc=0, flush=1 ++ ++register_fail: ++ pop {r4, pc} ++endfunc console_stm32_register ++ ++ /* -------------------------------------------------------- + * int console_core_putc(int c, uintptr_t base_addr) +- * +- * Function to output a character over the console. It returns the +- * character printed on success or -1 on error. +- * ++ * Function to output a character over the console. It ++ * returns the character printed on success or -1 on error. + * In : r0 - character to be printed + * r1 - console base address + * Out : return -1 on error else return character. +- * Clobber list : r2 +- * --------------------------------------------------------------- ++ * Clobber list : r2, r3 ++ * -------------------------------------------------------- + */ +-func console_core_putc ++func console_stm32_core_putc + /* Check the input parameter */ + cmp r1, #0 + beq putc_error +@@ -111,26 +142,38 @@ func console_core_putc + bne 2f + 1: + /* Check Transmit Data Register Empty */ ++ mov r3, #USART_TIMEOUT + txe_loop_1: ++ subs r3, r3, #1 ++ beq putc_error + ldr r2, [r1, #USART_ISR] + tst r2, #USART_ISR_TXE + beq txe_loop_1 + mov r2, #0xD + str r2, [r1, #USART_TDR] + /* Check transmit complete flag */ ++ mov r3, #USART_TIMEOUT + tc_loop_1: ++ subs r3, r3, #1 ++ beq putc_error + ldr r2, [r1, #USART_ISR] + tst r2, #USART_ISR_TC + beq tc_loop_1 + 2: + /* Check Transmit Data Register Empty */ ++ mov r3, #USART_TIMEOUT + txe_loop_2: ++ subs r3, r3, #1 ++ beq putc_error + ldr r2, [r1, #USART_ISR] + tst r2, #USART_ISR_TXE + beq txe_loop_2 + str r0, [r1, #USART_TDR] + /* Check transmit complete flag */ ++ mov r3, #USART_TIMEOUT + tc_loop_2: ++ subs r3, r3, #1 ++ beq putc_error + ldr r2, [r1, #USART_ISR] + tst r2, #USART_ISR_TC + beq tc_loop_2 +@@ -138,7 +181,26 @@ tc_loop_2: + putc_error: + mov r0, #-1 + bx lr +-endfunc console_core_putc ++endfunc console_stm32_core_putc ++ ++ /* ------------------------------------------------------------ ++ * int console_stm32_putc(int c, struct console_stm32 *console) ++ * Function to output a character over the console. It ++ * returns the character printed on success or -1 on error. ++ * In: r0 - character to be printed ++ * r1 - pointer to console_t structure ++ * Out : return -1 on error else return character. ++ * Clobber list: r2 ++ * ------------------------------------------------------------ ++ */ ++func console_stm32_putc ++#if ENABLE_ASSERTIONS ++ cmp r1, #0 ++ ASM_ASSERT(ne) ++#endif /* ENABLE_ASSERTIONS */ ++ ldr r1, [r1, #CONSOLE_T_STM32_BASE] ++ b console_stm32_core_putc ++endfunc console_stm32_putc + + /* ----------------------------------------------------------- + * int console_core_getc(uintptr_t base_addr) +@@ -151,11 +213,11 @@ endfunc console_core_putc + * Clobber list : r0, r1 + * ----------------------------------------------------------- + */ +-func console_core_getc ++func console_stm32_core_getc + /* Not supported */ + mov r0, #-1 + bx lr +-endfunc console_core_getc ++endfunc console_stm32_core_getc + + /* --------------------------------------------------------------- + * int console_core_flush(uintptr_t base_addr) +@@ -165,14 +227,17 @@ endfunc console_core_getc + * + * In : r0 - console base address + * Out : return -1 on error else return 0. +- * Clobber list : r0, r1 ++ * Clobber list : r0, r1, r2 + * --------------------------------------------------------------- + */ +-func console_core_flush ++func console_stm32_core_flush + cmp r0, #0 + beq flush_error + /* Check Transmit Data Register Empty */ ++ mov r2, #USART_TIMEOUT + txe_loop_3: ++ subs r2, r2, #1 ++ beq flush_error + ldr r1, [r0, #USART_ISR] + tst r1, #USART_ISR_TXE + beq txe_loop_3 +@@ -181,4 +246,22 @@ txe_loop_3: + flush_error: + mov r0, #-1 + bx lr +-endfunc console_core_flush ++endfunc console_stm32_core_flush ++ ++ /* ------------------------------------------------------ ++ * int console_stm32_flush(struct console_stm32 *console) ++ * Function to force a write of all buffered ++ * data that hasn't been output. ++ * In : r0 - pointer to console_t structure ++ * Out : return -1 on error else return 0. ++ * Clobber list: r0, r1 ++ * ------------------------------------------------------ ++ */ ++func console_stm32_flush ++#if ENABLE_ASSERTIONS ++ cmp r0, #0 ++ ASM_ASSERT(ne) ++#endif /* ENABLE_ASSERTIONS */ ++ ldr r0, [r0, #CONSOLE_T_STM32_BASE] ++ b console_stm32_core_flush ++endfunc console_stm32_flush +diff --git a/drivers/st/uart/io_programmer_uart.c b/drivers/st/uart/io_programmer_uart.c +new file mode 100644 +index 0000000..34a7cbb +--- /dev/null ++++ b/drivers/st/uart/io_programmer_uart.c +@@ -0,0 +1,597 @@ ++/* ++ * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved. ++ * ++ * SPDX-License-Identifier: BSD-3-Clause ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* USART bootloader protocol version V4.0*/ ++#define USART_BL_VERSION 0x40 ++ ++#define UART_ISR_ERRORS (USART_ISR_ORE | USART_ISR_NE | \ ++ USART_ISR_FE | USART_ISR_PE) ++ ++/* array of supported command */ ++static const uint8_t command_tab[] = { ++ GET_CMD_COMMAND, ++ GET_VER_COMMAND, ++ GET_ID_COMMAND, ++ PHASE_COMMAND, ++ START_COMMAND, ++ DOWNLOAD_COMMAND ++}; ++ ++static uint8_t header_buffer[512] __aligned(4); ++static int32_t header_length_read; ++ ++/* UART device functions */ ++static int uart_dev_open(const uintptr_t init_params, io_dev_info_t **dev_info); ++static int uart_block_open(io_dev_info_t *dev_info, const uintptr_t spec, ++ io_entity_t *entity); ++static int uart_dev_init(io_dev_info_t *dev_info, const uintptr_t init_params); ++static int uart_block_read(io_entity_t *entity, uintptr_t buffer, ++ size_t length, size_t *length_read); ++static int uart_block_close(io_entity_t *entity); ++static int uart_dev_close(io_dev_info_t *dev_info); ++static int uart_block_len(io_entity_t *entity, size_t *length); ++static io_type_t device_type_uart(void); ++ ++/* variables */ ++static const io_dev_connector_t uart_dev_connector = { ++ .dev_open = uart_dev_open ++}; ++ ++static const io_dev_funcs_t uart_dev_funcs = { ++ .type = device_type_uart, ++ .open = uart_block_open, ++ .seek = NULL, ++ .size = uart_block_len, ++ .read = uart_block_read, ++ .write = NULL, ++ .close = uart_block_close, ++ .dev_init = uart_dev_init, ++ .dev_close = uart_dev_close, ++}; ++ ++static const io_dev_info_t uart_dev_info = { ++ .funcs = &uart_dev_funcs, ++ .info = (uintptr_t)0, ++}; ++ ++static UART_HandleTypeDef *uart_handle_programmer; ++ ++/* Identify the device type as memmap */ ++static io_type_t device_type_uart(void) ++{ ++ return IO_TYPE_UART; ++} ++ ++static int uart_write_byte(uint8_t byte) ++{ ++ if (HAL_UART_GetState(uart_handle_programmer) == HAL_UART_STATE_RESET) ++ uart_handle_programmer->gState = HAL_UART_STATE_READY; ++ return HAL_UART_Transmit(uart_handle_programmer, (uint8_t *)&byte, 1, ++ PROGRAMMER_TIMEOUT); ++} ++ ++static int uart_write_uint32(uint32_t value) ++{ ++ if (HAL_UART_GetState(uart_handle_programmer) == HAL_UART_STATE_RESET) ++ uart_handle_programmer->gState = HAL_UART_STATE_READY; ++ return HAL_UART_Transmit(uart_handle_programmer, (uint8_t *)&value, 4, ++ PROGRAMMER_TIMEOUT); ++} ++ ++static int uart_read_byte(uint8_t *byte) ++{ ++ HAL_StatusTypeDef ret; ++ ++ if (HAL_UART_GetState(uart_handle_programmer) == HAL_UART_STATE_RESET) ++ uart_handle_programmer->RxState = HAL_UART_STATE_READY; ++ ++ ret = HAL_UART_Receive(uart_handle_programmer, byte, 1, ++ PROGRAMMER_TIMEOUT); ++ ++ if (ret || (uart_handle_programmer->Instance->ISReg & UART_ISR_ERRORS)) ++ return -EIO; ++ ++ return 0; ++} ++ ++static void uart_flush_rx_fifo(uint32_t timeout) ++{ ++ uint8_t byte = 0; ++ ++ /* Clear all errors */ ++ __HAL_UART_CLEAR_FLAG(uart_handle_programmer, UART_ISR_ERRORS); ++ ++ while ((__HAL_UART_GET_FLAG(uart_handle_programmer, UART_FLAG_RXNE) != ++ RESET) && timeout) { ++ timeout--; ++ uart_read_byte(&byte); ++ } ++} ++ ++/* Open a connection to the uart device */ ++static int uart_dev_open(const uintptr_t init_params, io_dev_info_t **dev_info) ++{ ++ int result = 0; ++ ++ assert(dev_info); ++ *dev_info = (io_dev_info_t *)&uart_dev_info; ++ ++ uart_handle_programmer = (UART_HandleTypeDef *)init_params; ++ ++ /* Init UART to enable FIFO mode */ ++ if (HAL_UART_Init(uart_handle_programmer) != HAL_OK) { ++ return -EIO; ++ } ++ ++ uart_flush_rx_fifo(PROGRAMMER_TIMEOUT); ++ ++ uart_write_byte(NACK_BYTE); ++ ++ return result; ++} ++ ++static int uart_dev_init(io_dev_info_t *dev_info, const uintptr_t init_params) ++{ ++ return 0; ++} ++ ++/* Close a connection to the uart device */ ++static int uart_dev_close(io_dev_info_t *dev_info) ++{ ++ return 0; ++} ++ ++/* Return the size of a file on the uart device */ ++static int uart_block_len(io_entity_t *entity, size_t *length) ++{ ++ boot_api_image_header_t *header = ++ (boot_api_image_header_t *)&header_buffer[0]; ++ ++ assert(entity); ++ assert(length); ++ ++ header_length_read = 0; ++ header->magic = 0; ++ ++ uart_block_read(entity, (uintptr_t)&header_buffer[0], ++ sizeof(boot_api_image_header_t), ++ (size_t *)&header_length_read); ++ ++ if (header->magic != BOOT_API_IMAGE_HEADER_MAGIC_NB) ++ return -EIO; ++ ++ if (header->image_length > current_phase.max_size) ++ return -EIO; ++ ++ *length = header->image_length; ++ ++ INFO("binary size 0x%x\n", header->image_length); ++ ++ return 0; ++} ++ ++/* Open a file on the uart device */ ++static int uart_block_open(io_dev_info_t *dev_info, const uintptr_t spec, ++ io_entity_t *entity) ++{ ++ int result = -EIO; ++ const struct stm32image_part_info *partition_spec = ++ (struct stm32image_part_info *)spec; ++ uint32_t length = 0; ++ uint32_t layout_length = 0; ++ ++ /* Use PHASE_FSBL1 like init value*/ ++ if (current_phase.phase_id == PHASE_FSBL1) { ++ assert(partition_spec); ++ assert(entity); ++ ++ current_phase.current_packet = 0; ++ ++ if (!strcmp(partition_spec->name, BL33_IMAGE_NAME)) { ++ /* read flashlayout first for U-boot */ ++ current_phase.phase_id = PHASE_FLASHLAYOUT; ++ current_phase.max_size = FLASHLAYOUT_LIMIT; ++ current_phase.keep_header = 1; ++ uart_block_len(entity, &layout_length); ++ uart_block_read(entity, FLASHLAYOUT_BASE, ++ layout_length, ++ &length); ++ ++ flush_dcache_range((unsigned long)FLASHLAYOUT_BASE, ++ layout_length + ++ sizeof(boot_api_image_header_t)); ++ ++ current_phase.current_packet = 0; ++ current_phase.phase_id = PHASE_SSBL; ++ current_phase.max_size = dt_get_ddr_size(); ++ current_phase.keep_header = 0; ++ } ++ entity->info = (uintptr_t)¤t_phase; ++ result = 0; ++ } else { ++ WARN("A UART device is already active. Close first.\n"); ++ result = -EIO; ++ } ++ return result; ++} ++ ++static int uart_receive_command(uint8_t *command) ++{ ++ uint8_t byte = 0; ++ uint8_t xor = 0; ++ uint8_t counter = 0, found = 0; ++ int ret; ++ ++ /* check command */ ++ ret = uart_read_byte(&byte); ++ if (ret) ++ return ret; ++ ++ for (counter = 0; counter < sizeof(command_tab); counter++) { ++ if (command_tab[counter] == byte) { ++ found = 1; ++ break; ++ } ++ } ++ ++ if (found) { ++ ret = uart_read_byte(&xor); ++ if (ret) ++ return ret; ++ if ((byte ^ xor) != 0xFF) { ++ WARN("UART: Command XOR check fail (byte=0x%x, xor=0x%x)\n", ++ byte, xor); ++ return -EPROTO; ++ } ++ } else { ++ if (byte != INIT_BYTE) { ++ WARN("UART: Command unknown (byte=0x%x)\n", byte); ++ return -EPROTO; ++ } ++ } ++ ++ *command = byte; ++ ++ return 0; ++} ++ ++static int get_cmd_command(void) ++{ ++ uint8_t counter = 0x0; ++ ++ uart_write_byte(sizeof(command_tab)); ++ uart_write_byte(USART_BL_VERSION); ++ ++ for (counter = 0; counter < sizeof(command_tab); counter++) ++ uart_write_byte(command_tab[counter]); ++ ++ return 0; ++} ++ ++static int get_version_command(void) ++{ ++ uart_write_byte(STM32_TF_VERSION); ++ ++ return 0; ++} ++ ++static int get_id_command(void) ++{ ++ /* Send Device IDCode */ ++ uart_write_byte(0x1); ++ uart_write_byte(DEVICE_ID_BYTE1); ++ uart_write_byte(DEVICE_ID_BYTE2); ++ ++ return 0; ++} ++ ++static int uart_send_phase(uint32_t address) ++{ ++ uart_write_byte(0x05); /* length of data - 1 */ ++ /* Send the ID of next partition */ ++ uart_write_byte(current_phase.phase_id); /* partition ID */ ++ ++ uart_write_uint32(address); /* destination address */ ++ uart_write_byte(0x00); /* length of extra data */ ++ ++ return 0; ++} ++ ++static int uart_download_part(uint8_t *buffer, uint32_t *length_read) ++{ ++ uint8_t byte = 0; ++ uint8_t xor = 0; ++ uint8_t operation = 0; ++ uint32_t packet_number = 0; ++ uint8_t packet_size = 0; ++ int i = 0; ++ volatile uint8_t *ptr = (uint8_t *)buffer; ++ ++ /* get operation number */ ++ if (uart_read_byte(&operation)) ++ return -EIO; ++ xor = operation; ++ ++ /* get packet Number */ ++ for (i = 3, byte = 0; i > 0; i--) { ++ if (uart_read_byte(&byte)) ++ return -EIO; ++ xor ^= byte; ++ packet_number = (packet_number << 8) | byte; ++ } ++ ++ if (packet_number != current_phase.current_packet) { ++ WARN("UART: Bad packet number receive: %i\n", packet_number); ++ return -EPROTO; ++ } ++ ++ /* checksum */ ++ if (uart_read_byte(&byte)) ++ return -EIO; ++ ++ if (xor != byte) { ++ WARN("UART: Download Command header checksum fail: calculated xor: %i, received xor:%i\n", ++ xor, byte); ++ return -EPROTO; ++ } ++ ++ uart_write_byte(ACK_BYTE); ++ ++ if (uart_read_byte(&packet_size)) ++ return -EIO; ++ ++ xor = packet_size; ++ ++ for (i = packet_size; i >= 0; i--) { ++ /* Reload watchdog, once every 8 loops */ ++ if (i % 8) ++ stm32_iwdg_refresh(IWDG2_INST); ++ ++ if (uart_read_byte(&byte)) ++ return -EIO; ++ *(volatile uint8_t *)ptr = byte; ++ xor ^= byte; ++ ptr++; ++ } ++ ++ /* checksum */ ++ if (uart_read_byte(&byte)) ++ return -EIO; ++ ++ if (xor != byte) { ++ WARN("UART: Download Command data checksum fail: calculated xor: 0x%x, received xor:0x%x\n", ++ xor, byte); ++ return -EPROTO; ++ } ++ ++ current_phase.current_packet++; ++ *length_read = (uint32_t)packet_size + 1; ++ ++ return 0; ++} ++ ++static int uart_start_cmd(boot_api_image_header_t *header, uintptr_t buffer) ++{ ++ uint8_t byte = 0; ++ uint8_t xor = 0; ++ int i = 0; ++ uint32_t start_address = 0; ++ int result = 0; ++ ++ /* get address */ ++ for (i = 4; i > 0; i--) { ++ if (uart_read_byte(&byte)) ++ return -EIO; ++ xor ^= byte; ++ start_address = (start_address << 8) | byte; ++ } ++ ++ /* checksum */ ++ if (uart_read_byte(&byte)) ++ return -EIO; ++ ++ if (xor != byte) { ++ WARN("UART: Start command checksum fail: calculated xor: %i, received xor:%i\n", ++ xor, byte); ++ return -EPROTO; ++ } ++ ++ switch (current_phase.phase_id) { ++ case PHASE_FLASHLAYOUT: ++ result = check_header(header, buffer + ++ sizeof(boot_api_image_header_t)); ++ if (result) ++ return result; ++ break; ++ ++ case PHASE_SSBL: ++ if (start_address != BL33_BASE) { ++ VERBOSE("BL33 address provided: 0x%x, using: 0x%x\n", ++ start_address, BL33_BASE); ++ } ++ ++ result = check_header(header, buffer); ++ if (result) ++ return result; ++ ++#ifdef AUTHENTICATE_BL33 ++ result = check_authentication(header, buffer); ++ if (result != 0) { ++ return result; ++ } ++#else ++ NOTICE("Authentication disabled: No signature check\n"); ++#endif ++ break; ++ ++ default: ++ ERROR("Invalid phase ID : %i\n", current_phase.phase_id); ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++/* Read data from the uart device */ ++static int uart_block_read(io_entity_t *entity, uintptr_t buffer, ++ size_t length, size_t *length_read) ++{ ++ uint32_t read_length = 0; ++ uint32_t total_length = 0; ++ uint32_t ptr_offset = 0; ++ uint8_t command = 0; ++ uint8_t all_commands_done = 0; ++ boot_api_image_header_t *header = ++ (boot_api_image_header_t *)&header_buffer[0]; ++ ++ if (header_length_read && current_phase.keep_header) { ++ memcpy((uint8_t *)buffer, (uint8_t *)&header_buffer[0], ++ header_length_read); ++ ptr_offset += header_length_read; ++ } else if (header_length_read && ++ ((header_length_read - ++ sizeof(boot_api_image_header_t)) > 0)) { ++ memcpy((uint8_t *)buffer, ++ (uint8_t *) ++ &header_buffer[sizeof(boot_api_image_header_t)], ++ header_length_read - ++ sizeof(boot_api_image_header_t)); ++ ptr_offset += header_length_read - ++ sizeof(boot_api_image_header_t); ++ } ++ ++ while (!all_commands_done) { ++ int result; ++ ++ /* Reload watchdog */ ++ stm32_iwdg_refresh(IWDG2_INST); ++ ++ result = uart_receive_command(&command); ++ if (result) { ++ if (result == -EIO) { ++ WARN("UART: device error on command receive\n"); ++ } ++ ++ mdelay(2); ++ ++ uart_flush_rx_fifo(PROGRAMMER_TIMEOUT); ++ uart_write_byte(NACK_BYTE); ++ continue; ++ } ++ ++ /* Send ack */ ++ uart_write_byte(ACK_BYTE); ++ ++ switch (command) { ++ case INIT_BYTE: ++ /* Nothing to do */ ++ continue; ++ case GET_CMD_COMMAND: ++ result = get_cmd_command(); ++ break; ++ ++ case GET_VER_COMMAND: ++ result = get_version_command(); ++ break; ++ ++ case GET_ID_COMMAND: ++ result = get_id_command(); ++ break; ++ ++ case PHASE_COMMAND: ++ result = uart_send_phase((uint32_t)buffer); ++ break; ++ ++ case DOWNLOAD_COMMAND: ++ result = uart_download_part((uint8_t *)(buffer + ++ ptr_offset), ++ &read_length); ++ if (!result) { ++ ptr_offset += read_length; ++ total_length += read_length; ++ if ((total_length >= length) && ++ !header_length_read) { ++ /* read header only go out*/ ++ all_commands_done = 1; ++ } ++ } ++ ++ break; ++ ++ case START_COMMAND: ++ result = uart_start_cmd(header, buffer); ++ if (!result) ++ all_commands_done = 1; ++ ++ break; ++ ++ default: ++ /* Not supported command */ ++ WARN("UART: Unknown command\n"); ++ uart_flush_rx_fifo(PROGRAMMER_TIMEOUT); ++ uart_write_byte(NACK_BYTE); ++ continue; ++ } ++ if (!result) { ++ /* Send ack */ ++ uart_write_byte(ACK_BYTE); ++ } else if (result == -EPROTO) { ++ uart_flush_rx_fifo(0xFFFF); ++ uart_write_byte(NACK_BYTE); ++ } else { ++ uart_flush_rx_fifo(PROGRAMMER_TIMEOUT); ++ uart_write_byte(NACK_BYTE); ++ continue; ++ } ++ } ++ ++ *length_read = total_length; ++ ++ INFO("Read block in buffer 0x%lx size 0x%x phase ID %i\n", ++ buffer, length, current_phase.phase_id); ++ ++ return 0; ++} ++ ++/* Close a file on the uart device */ ++static int uart_block_close(io_entity_t *entity) ++{ ++ current_phase.phase_id = PHASE_FSBL1; ++ ++ return 0; ++} ++ ++/* Exported functions */ ++ ++/* Register the uart driver with the IO abstraction */ ++int register_io_dev_uart(const io_dev_connector_t **dev_con) ++{ ++ int result; ++ ++ assert(dev_con); ++ ++ result = io_register_device(&uart_dev_info); ++ if (!result) ++ *dev_con = &uart_dev_connector; ++ ++ return result; ++} +diff --git a/drivers/st/uart/stm32mp1xx_hal_uart.c b/drivers/st/uart/stm32mp1xx_hal_uart.c +new file mode 100644 +index 0000000..c8e5860 +--- /dev/null ++++ b/drivers/st/uart/stm32mp1xx_hal_uart.c +@@ -0,0 +1,799 @@ ++/** ++ ****************************************************************************** ++ * @file stm32mp1xx_hal_uart.c ++ * @author MCD Application Team ++ * @version $VERSION$ ++ * @date $DATE$ ++ * @brief UART HAL module driver. ++ * This file provides firmware functions to manage the following ++ * functionalities of the Universal Asynchronous Receiver Transmitter Peripheral (UART). ++ * + Initialization and de-initialization functions ++ * + IO operation functions ++ * + Peripheral Control functions ++ * ++ * ++ * @verbatim ++ * =============================================================================== ++ * ##### How to use this driver ##### ++ * =============================================================================== ++ * [..] ++ * The UART HAL driver can be used as follows: ++ * ++ * (#) Declare a UART_HandleTypeDef handle structure (eg. UART_HandleTypeDef huart). ++ * (#) Initialize the UART low level resources by implementing the HAL_UART_MspInit() API: ++ * (++) Enable the USARTx interface clock. ++ * (++) UART pins configuration: ++ * (+++) Enable the clock for the UART GPIOs. ++ * (+++) Configure these UART pins as alternate function pull-up. ++ * (++) NVIC configuration if you need to use interrupt process (HAL_UART_Transmit_IT() ++ * and HAL_UART_Receive_IT() APIs): ++ * (+++) Configure the USARTx interrupt priority. ++ * (+++) Enable the NVIC USART IRQ handle. ++ * (++) UART interrupts handling: ++ * -@@- The specific UART interrupts (Transmission complete interrupt, ++ * RXNE interrupt and Error Interrupts) are managed using the macros ++ * __HAL_UART_ENABLE_IT() and __HAL_UART_DISABLE_IT() inside the transmit and receive processes. ++ * (++) DMA Configuration if you need to use DMA process (HAL_UART_Transmit_DMA() ++ * and HAL_UART_Receive_DMA() APIs): ++ * (+++) Declare a DMA handle structure for the Tx/Rx channel. ++ * (+++) Enable the DMAx interface clock. ++ * (+++) Configure the declared DMA handle structure with the required Tx/Rx parameters. ++ * (+++) Configure the DMA Tx/Rx channel. ++ * (+++) Associate the initialized DMA handle to the UART DMA Tx/Rx handle. ++ * (+++) Configure the priority and enable the NVIC for the transfer complete interrupt on the DMA Tx/Rx channel. ++ * ++ * (#) Program the Baud Rate, Word Length, Stop Bit, Parity, Hardware ++ * flow control and Mode (Receiver/Transmitter) in the huart handle Init structure. ++ * ++ * (#) If required, program UART advanced features (TX/RX pins swap, auto Baud rate detection,...) ++ * in the huart handle AdvancedInit structure. ++ * ++ * (#) For the UART asynchronous mode, initialize the UART registers by calling ++ * the HAL_UART_Init() API. ++ * ++ * (#) For the UART Half duplex mode, initialize the UART registers by calling ++ * the HAL_HalfDuplex_Init() API. ++ * ++ * (#) For the UART LIN (Local Interconnection Network) mode, initialize the UART registers ++ * by calling the HAL_LIN_Init() API. ++ * ++ * (#) For the UART Multiprocessor mode, initialize the UART registers ++ * by calling the HAL_MultiProcessor_Init() API. ++ * ++ * (#) For the UART RS485 Driver Enabled mode, initialize the UART registers ++ * by calling the HAL_RS485Ex_Init() API. ++ * ++ * [..] ++ * (@) These API's (HAL_UART_Init(), HAL_HalfDuplex_Init(), HAL_LIN_Init(), HAL_MultiProcessor_Init(), ++ * also configure the low level Hardware GPIO, CLOCK, CORTEX...etc) by ++ * calling the customized HAL_UART_MspInit() API. ++ * ++ * @endverbatim ++ ****************************************************************************** ++ * @attention ++ * ++ *

© COPYRIGHT(c) 2015-2017 STMicroelectronics

++ * ++ * SPDX-License-Identifier: BSD-3-Clause ++ * ++ ****************************************************************************** ++ */ ++ ++/* Includes ------------------------------------------------------------------*/ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/** @addtogroup STM32MP1xx_HAL_Driver ++ * @{ ++ */ ++ ++/** @defgroup UART UART ++ * @brief HAL UART module driver ++ * @{ ++ */ ++ ++#ifdef HAL_UART_MODULE_ENABLED ++ ++/* Private typedef -----------------------------------------------------------*/ ++/* Private define ------------------------------------------------------------*/ ++/** @defgroup UART_Private_Constants UART Private Constants ++ * @{ ++ */ ++#define UART_CR1_FIELDS \ ++ ((uint32_t)(USART_CR1_M | USART_CR1_PCE | USART_CR1_PS | \ ++ USART_CR1_TE | USART_CR1_RE | USART_CR1_OVER8 | \ ++ USART_CR1_FIFOEN)) ++ ++#define USART_CR3_FIELDS \ ++ ((uint32_t)(USART_CR3_RTSE | USART_CR3_CTSE | USART_CR3_ONEBIT | \ ++ USART_CR3_TXFTCFG | USART_CR3_RXFTCFG)) ++ ++ ++/** ++ * @} ++ */ ++ ++/* Exported functions --------------------------------------------------------*/ ++ ++/** @defgroup UART_Exported_Functions UART Exported Functions ++ * @{ ++ */ ++ ++/** @defgroup UART_Exported_Functions_Group1 Initialization and de-initialization functions ++ * @brief Initialization and Configuration functions ++ * ++ * @verbatim ++ * =============================================================================== ++ * ##### Initialization and Configuration functions ##### ++ * =============================================================================== ++ * [..] ++ * This subsection provides a set of functions allowing to initialize the USARTx or the UARTy ++ * in asynchronous mode. ++ * (+) For the asynchronous mode the parameters below can be configured: ++ * (++) Baud Rate ++ * (++) Word Length ++ * (++) Stop Bit ++ * (++) Parity: If the parity is enabled, then the MSB bit of the data written ++ * in the data register is transmitted but is changed by the parity bit. ++ * (++) Hardware flow control ++ * (++) Receiver/transmitter modes ++ * (++) Over Sampling Method ++ * (++) One-Bit Sampling Method ++ * (+) For the asynchronous mode, the following advanced features can be configured as well: ++ * (++) TX and/or RX pin level inversion ++ * (++) data logical level inversion ++ * (++) RX and TX pins swap ++ * (++) RX overrun detection disabling ++ * (++) DMA disabling on RX error ++ * (++) MSB first on communication line ++ * (++) auto Baud rate detection ++ * [..] ++ * The HAL_UART_Init(), HAL_HalfDuplex_Init(), HAL_LIN_Init()and HAL_MultiProcessor_Init()API ++ * follow respectively the UART asynchronous, UART Half duplex, UART LIN mode ++ * and UART multiprocessor mode configuration procedures (details for the procedures ++ * are available in reference manual). ++ * ++ * @endverbatim ++ * ++ * Depending on the frame length defined by the M1 and M0 bits (7-bit, ++ * 8-bit or 9-bit), the possible UART formats are listed in the ++ * following table. ++ * ++ * Table 1. UART frame format. ++ * +-----------------------------------------------------------------------+ ++ * | M1 bit | M0 bit | PCE bit | UART frame | ++ * |---------|---------|-----------|---------------------------------------| ++ * | 0 | 0 | 0 | | SB | 8 bit data | STB | | ++ * |---------|---------|-----------|---------------------------------------| ++ * | 0 | 0 | 1 | | SB | 7 bit data | PB | STB | | ++ * |---------|---------|-----------|---------------------------------------| ++ * | 0 | 1 | 0 | | SB | 9 bit data | STB | | ++ * |---------|---------|-----------|---------------------------------------| ++ * | 0 | 1 | 1 | | SB | 8 bit data | PB | STB | | ++ * |---------|---------|-----------|---------------------------------------| ++ * | 1 | 0 | 0 | | SB | 7 bit data | STB | | ++ * |---------|---------|-----------|---------------------------------------| ++ * | 1 | 0 | 1 | | SB | 6 bit data | PB | STB | | ++ * +-----------------------------------------------------------------------+ ++ * ++ * @{ ++ */ ++ ++/** ++ * @brief Initialize the UART mode according to the specified ++ * parameters in the UART_InitTypeDef and initialize the associated handle. ++ * @param huart: UART handle. ++ * @retval HAL status ++ */ ++HAL_StatusTypeDef HAL_UART_Init(UART_HandleTypeDef *huart) ++{ ++ /* Check the UART handle allocation */ ++ if (!huart) ++ return HAL_ERROR; ++ ++ /* Check the parameters */ ++ if (huart->Init.HwFlowCtl != UART_HWCONTROL_NONE) ++ assert_param(IS_UART_HWFLOW_INSTANCE(huart->Instance)); ++ else ++ assert_param(IS_UART_INSTANCE(huart->Instance)); ++ ++ /* Allocate lock resource and initialize it */ ++ if (huart->gState == HAL_UART_STATE_RESET) ++ huart->Lock = HAL_UNLOCKED; ++ ++ huart->gState = HAL_UART_STATE_BUSY; ++ ++ /* Disable the Peripheral */ ++ __HAL_UART_DISABLE(huart); ++ ++ /* Set the UART Communication parameters */ ++ if (UART_SetConfig(huart) == HAL_ERROR) ++ return HAL_ERROR; ++ ++ if (huart->AdvancedInit.AdvFeatureInit != UART_ADVFEATURE_NO_INIT) ++ UART_AdvFeatureConfig(huart); ++ ++ /* In asynchronous mode, the following bits must be kept cleared: ++ - LINEN and CLKEN bits in the USART_CR2 register, ++ - SCEN, HDSEL and IREN bits in the USART_CR3 register.*/ ++ CLEAR_BIT(huart->Instance->CR2, (USART_CR2_LINEN | USART_CR2_CLKEN)); ++ CLEAR_BIT(huart->Instance->CR3, (USART_CR3_SCEN | USART_CR3_HDSEL | ++ USART_CR3_IREN)); ++ ++ /* Enable the Peripheral */ ++ __HAL_UART_ENABLE(huart); ++ ++ /* TEACK and/or REACK to check before moving huart->gState and huart->RxState to Ready */ ++ return UART_CheckIdleState(huart); ++} ++ ++ ++/** ++ * @} ++ */ ++ ++/** @defgroup UART_Exported_Functions_Group2 IO operation functions ++ * @brief UART Transmit/Receive functions ++ * ++ * @verbatim ++ * =============================================================================== ++ * ##### IO operation functions ##### ++ * =============================================================================== ++ * This subsection provides a set of functions allowing to manage the UART asynchronous ++ * and Half duplex data transfers. ++ * ++ * (#) There are two mode of transfer: ++ * (+) Blocking mode: The communication is performed in polling mode. ++ * The HAL status of all data processing is returned by the same function ++ * after finishing transfer. ++ * (+) Non-Blocking mode: The communication is performed using Interrupts ++ * or DMA, These API's return the HAL status. ++ * The end of the data processing will be indicated through the ++ * dedicated UART IRQ when using Interrupt mode or the DMA IRQ when ++ * using DMA mode. ++ * The HAL_UART_TxCpltCallback(), HAL_UART_RxCpltCallback() user callbacks ++ * will be executed respectively at the end of the transmit or Receive process ++ * The HAL_UART_ErrorCallback()user callback will be executed when a communication error is detected ++ * ++ * (#) Blocking mode API's are : ++ * (+) HAL_UART_Transmit() ++ * (+) HAL_UART_Receive() ++ * ++ * (#) Non-Blocking mode API's with Interrupt are : ++ * (+) HAL_UART_Transmit_IT() ++ * (+) HAL_UART_Receive_IT() ++ * (+) HAL_UART_IRQHandler() ++ * ++ * (#) Non-Blocking mode API's with DMA are : ++ * (+) HAL_UART_Transmit_DMA() ++ * (+) HAL_UART_Receive_DMA() ++ * (+) HAL_UART_DMAPause() ++ * (+) HAL_UART_DMAResume() ++ * (+) HAL_UART_DMAStop() ++ * ++ * (#) A set of Transfer Complete Callbacks are provided in Non_Blocking mode: ++ * (+) HAL_UART_TxHalfCpltCallback() ++ * (+) HAL_UART_TxCpltCallback() ++ * (+) HAL_UART_RxHalfCpltCallback() ++ * (+) HAL_UART_RxCpltCallback() ++ * (+) HAL_UART_ErrorCallback() ++ * ++ * -@- In the Half duplex communication, it is forbidden to run the transmit ++ * and receive process in parallel, the UART state HAL_UART_STATE_BUSY_TX_RX can't be useful. ++ * ++ * @endverbatim ++ * @{ ++ */ ++ ++/** ++ * @brief Send an amount of data in blocking mode. ++ * @param huart: UART handle. ++ * @param pData: Pointer to data buffer. ++ * @param Size: Amount of data to be sent. ++ * @param Timeout: Timeout duration. ++ * @retval HAL status ++ */ ++HAL_StatusTypeDef HAL_UART_Transmit(UART_HandleTypeDef *huart, uint8_t *pData, ++ uint16_t Size, uint32_t Timeout) ++{ ++ uint16_t *tmp; ++ uint32_t tickstart = 0U; ++ HAL_StatusTypeDef ret = HAL_OK; ++ ++ /* Check that a Tx process is not already ongoing */ ++ if (huart->gState != HAL_UART_STATE_READY) ++ return HAL_BUSY; ++ ++ if ((!pData) || (Size == 0U)) ++ return HAL_ERROR; ++ ++ /* Process Locked */ ++ __HAL_LOCK(huart); ++ ++ huart->ErrorCode = HAL_UART_ERROR_NONE; ++ huart->gState = HAL_UART_STATE_BUSY_TX; ++ ++ /* Init tickstart for timeout management*/ ++ tickstart = HAL_GetTick(); ++ ++ huart->TxXferSize = Size; ++ huart->TxXferCount = Size; ++ while (huart->TxXferCount > 0U) { ++ huart->TxXferCount--; ++ if (UART_WaitOnFlagUntilTimeout(huart, UART_FLAG_TXE, RESET, ++ tickstart, Timeout) != HAL_OK) { ++ ret = HAL_TIMEOUT; ++ goto end; ++ } ++ ++ if ((huart->Init.WordLength == UART_WORDLENGTH_9B) && ++ (huart->Init.Parity == UART_PARITY_NONE)) { ++ tmp = (uint16_t *)pData; ++ huart->Instance->TDR = (*tmp & (uint16_t)0x01FFU); ++ pData += 2U; ++ } else { ++ huart->Instance->TDR = (*pData++ & (uint8_t)0xFFU); ++ } ++ } ++ ++ if (UART_WaitOnFlagUntilTimeout(huart, UART_FLAG_TC, RESET, tickstart, ++ Timeout) != HAL_OK) { ++ ret = HAL_TIMEOUT; ++ goto end; ++ } ++ ++end: ++ /* At end of Tx process, restore huart->gState to Ready */ ++ huart->gState = HAL_UART_STATE_READY; ++ ++ /* Process Unlocked */ ++ __HAL_UNLOCK(huart); ++ ++ return ret; ++} ++ ++/** ++ * @brief Receive an amount of data in blocking mode. ++ * @param huart: UART handle. ++ * @param pData: pointer to data buffer. ++ * @param Size: amount of data to be received. ++ * @param Timeout: Timeout duration. ++ * @retval HAL status ++ */ ++HAL_StatusTypeDef HAL_UART_Receive(UART_HandleTypeDef *huart, uint8_t *pData, ++ uint16_t Size, uint32_t Timeout) ++{ ++ uint16_t *tmp; ++ uint16_t uhMask; ++ uint32_t tickstart = 0; ++ HAL_StatusTypeDef ret = HAL_OK; ++ ++ /* Check that a Rx process is not already ongoing */ ++ if (huart->RxState != HAL_UART_STATE_READY) ++ return HAL_BUSY; ++ ++ if ((!pData) || (Size == 0U)) ++ return HAL_ERROR; ++ ++ /* Process Locked */ ++ __HAL_LOCK(huart); ++ ++ huart->ErrorCode = HAL_UART_ERROR_NONE; ++ huart->RxState = HAL_UART_STATE_BUSY_RX; ++ ++ /* Init tickstart for timeout management*/ ++ tickstart = HAL_GetTick(); ++ ++ huart->RxXferSize = Size; ++ huart->RxXferCount = Size; ++ ++ /* Computation of UART mask to apply to RDR register */ ++ UART_MASK_COMPUTATION(huart); ++ uhMask = huart->Mask; ++ ++ /* as long as data have to be received */ ++ while (huart->RxXferCount > 0U) { ++ huart->RxXferCount--; ++ if (UART_WaitOnFlagUntilTimeout(huart, UART_FLAG_RXNE, RESET, ++ tickstart, Timeout) != HAL_OK) { ++ ret = HAL_TIMEOUT; ++ goto end; ++ } ++ ++ if ((huart->Init.WordLength == UART_WORDLENGTH_9B) && ++ (huart->Init.Parity == UART_PARITY_NONE)) { ++ tmp = (uint16_t *)pData; ++ *tmp = (uint16_t)(huart->Instance->RDR & uhMask); ++ pData += 2U; ++ } else { ++ *pData++ = (uint8_t)(huart->Instance->RDR & ++ (uint8_t)uhMask); ++ } ++ } ++ ++end: ++ /* At end of Rx process, restore huart->RxState to Ready */ ++ huart->RxState = HAL_UART_STATE_READY; ++ ++ /* Process Unlocked */ ++ __HAL_UNLOCK(huart); ++ ++ return ret; ++} ++ ++ ++/** ++ * @} ++ */ ++ ++/** @defgroup UART_Exported_Functions_Group3 Peripheral Control functions ++ * @brief UART control functions ++ * ++@verbatim ++ =============================================================================== ++ ##### Peripheral Control functions ##### ++ =============================================================================== ++ [..] ++ This subsection provides a set of functions allowing to control the UART. ++ (+) HAL_MultiProcessor_EnableMuteMode() API enables mute mode ++ (+) HAL_MultiProcessor_DisableMuteMode() API disables mute mode ++ (+) HAL_MultiProcessor_EnterMuteMode() API enters mute mode ++ (+) HAL_MultiProcessor_EnableMuteMode() API enables mute mode ++ (+) UART_SetConfig() API configures the UART peripheral ++ (+) UART_AdvFeatureConfig() API optionally configures the UART advanced features ++ (+) UART_CheckIdleState() API ensures that TEACK and/or REACK are set after initialization ++ (+) UART_Wakeup_AddressConfig() API configures the wake-up from stop mode parameters ++ (+) HAL_HalfDuplex_EnableTransmitter() API disables receiver and enables transmitter ++ (+) HAL_HalfDuplex_EnableReceiver() API disables transmitter and enables receiver ++ (+) HAL_LIN_SendBreak() API transmits the break characters ++@endverbatim ++ * @{ ++ */ ++ ++ ++ ++/** ++ * @} ++ */ ++ ++/** @defgroup UART_Exported_Functions_Group4 Peripheral State and Error functions ++ * @brief UART Peripheral State functions ++ * ++@verbatim ++ ============================================================================== ++ ##### Peripheral State and Error functions ##### ++ ============================================================================== ++ [..] ++ This subsection provides functions allowing to : ++ (+) Return the UART handle state. ++ (+) Return the UART handle error code ++ ++@endverbatim ++ * @{ ++ */ ++ ++/** ++ * @brief Return the UART handle state. ++ * @param huart Pointer to a UART_HandleTypeDef structure that contains ++ * the configuration information for the specified UART. ++ * @retval HAL state ++ */ ++HAL_UART_StateTypeDef HAL_UART_GetState(UART_HandleTypeDef *huart) ++{ ++ uint32_t temp1 = huart->gState; ++ uint32_t temp2 = huart->RxState; ++ ++ return (HAL_UART_StateTypeDef)(temp1 | temp2); ++} ++ ++/** ++ * @brief Return the UART handle error code. ++ * @param huart Pointer to a UART_HandleTypeDef structure that contains ++ * the configuration information for the specified UART. ++ * @retval UART Error Code ++*/ ++uint32_t HAL_UART_GetError(UART_HandleTypeDef *huart) ++{ ++ return huart->ErrorCode; ++} ++ ++/** ++ * @} ++ */ ++ ++/** ++ * @} ++ */ ++ ++/** @defgroup UART_Private_Functions UART Private Functions ++ * @{ ++ */ ++ ++static unsigned long uart_get_clock_freq(UART_HandleTypeDef *huart) ++{ ++ return fdt_get_uart_clock_freq((uintptr_t)huart->Instance); ++} ++ ++/** ++ * @brief Configure the UART peripheral. ++ * @param huart: UART handle. ++ * @retval HAL status ++ */ ++HAL_StatusTypeDef UART_SetConfig(UART_HandleTypeDef *huart) ++{ ++ uint32_t tmpreg; ++ unsigned long clockfreq; ++ ++ /*---------------------- USART CR1 Configuration -------------------- ++ * Clear M, PCE, PS, TE, RE and OVER8 bits and configure ++ * the UART Word Length, Parity, Mode and oversampling: ++ * set the M bits according to huart->Init.WordLength value ++ * set PCE and PS bits according to huart->Init.Parity value ++ * set TE and RE bits according to huart->Init.Mode value ++ * set OVER8 bit according to huart->Init.OverSampling value ++ */ ++ tmpreg = (uint32_t)(huart->Init.WordLength | ++ huart->Init.Parity | ++ huart->Init.Mode | ++ huart->Init.OverSampling); ++ tmpreg |= (uint32_t)huart->Init.FIFOMode; ++ MODIFY_REG(huart->Instance->CR1, UART_CR1_FIELDS, tmpreg); ++ ++ /*--------------------- USART CR2 Configuration --------------------- ++ * Configure the UART Stop Bits: Set STOP[13:12] bits according ++ * to huart->Init.StopBits value ++ */ ++ MODIFY_REG(huart->Instance->CR2, USART_CR2_STOP, huart->Init.StopBits); ++ ++ /*--------------------- USART CR3 Configuration --------------------- ++ * Configure ++ * - UART HardWare Flow Control: set CTSE and RTSE bits according ++ * to huart->Init.HwFlowCtl value ++ * - one-bit sampling method versus three samples' majority rule ++ * according to huart->Init.OneBitSampling (not applicable to LPUART) ++ * - set TXFTCFG bit according to husart->Init.TXFIFOThreshold value ++ * - set RXFTCFG bit according to husart->Init.RXFIFOThreshold value ++ */ ++ tmpreg = (uint32_t)huart->Init.HwFlowCtl; ++ ++ tmpreg |= huart->Init.OneBitSampling; ++ ++ if (huart->Init.FIFOMode == UART_FIFOMODE_ENABLE) ++ tmpreg |= ((uint32_t)huart->Init.TXFIFOThreshold | ++ (uint32_t)huart->Init.RXFIFOThreshold); ++ ++ MODIFY_REG(huart->Instance->CR3, USART_CR3_FIELDS, tmpreg); ++ ++ /*--------------------- USART PRESC Configuration ------------------- ++ * Configure ++ * - UART Clock Prescaler : set PRESCALER according to ++ * huart->Init.Prescaler value ++ */ ++ MODIFY_REG(huart->Instance->PRESC, USART_PRESC_PRESCALER, ++ huart->Init.Prescaler); ++ ++ /*-------------------------- USART BRR Configuration -----------------------*/ ++ ++ clockfreq = uart_get_clock_freq(huart); ++ if (!clockfreq) ++ return HAL_ERROR; ++ ++ if (huart->Init.OverSampling == UART_OVERSAMPLING_8) { ++ uint16_t usartdiv = ++ (uint16_t)uart_div_sampling8(clockfreq, ++ huart->Init.BaudRate, ++ huart->Init.Prescaler); ++ ++ uint16_t brrtemp = usartdiv & 0xFFF0U; ++ ++ brrtemp |= (uint16_t)((usartdiv & (uint16_t)0x000FU) >> 1U); ++ huart->Instance->BRR = brrtemp; ++ } else { ++ huart->Instance->BRR = ++ (uint16_t)uart_div_sampling16(clockfreq, ++ huart->Init.BaudRate, ++ huart->Init.Prescaler); ++ } ++ ++ return HAL_OK; ++} ++ ++/** ++ * @brief Configure the UART peripheral advanced features. ++ * @param huart: UART handle. ++ * @retval None ++ */ ++void UART_AdvFeatureConfig(UART_HandleTypeDef *huart) ++{ ++ /* Check whether the set of advanced features to configure is properly set */ ++ assert_param( ++ IS_UART_ADVFEATURE_INIT(huart->AdvancedInit.AdvFeatureInit)); ++ ++ /* if required, configure TX pin active level inversion */ ++ if (HAL_IS_BIT_SET(huart->AdvancedInit.AdvFeatureInit, ++ UART_ADVFEATURE_TXINVERT_INIT)) { ++ assert_param( ++ IS_UART_ADVFEATURE_TXINV( ++ huart->AdvancedInit.TxPinLevelInvert)); ++ MODIFY_REG(huart->Instance->CR2, USART_CR2_TXINV, ++ huart->AdvancedInit.TxPinLevelInvert); ++ } ++ ++ /* if required, configure RX pin active level inversion */ ++ if (HAL_IS_BIT_SET(huart->AdvancedInit.AdvFeatureInit, ++ UART_ADVFEATURE_RXINVERT_INIT)) { ++ assert_param( ++ IS_UART_ADVFEATURE_RXINV( ++ huart->AdvancedInit.RxPinLevelInvert)); ++ MODIFY_REG(huart->Instance->CR2, USART_CR2_RXINV, ++ huart->AdvancedInit.RxPinLevelInvert); ++ } ++ ++ /* if required, configure data inversion */ ++ if (HAL_IS_BIT_SET(huart->AdvancedInit.AdvFeatureInit, ++ UART_ADVFEATURE_DATAINVERT_INIT)) { ++ assert_param( ++ IS_UART_ADVFEATURE_DATAINV( ++ huart->AdvancedInit.DataInvert)); ++ MODIFY_REG(huart->Instance->CR2, USART_CR2_DATAINV, ++ huart->AdvancedInit.DataInvert); ++ } ++ ++ /* if required, configure RX/TX pins swap */ ++ if (HAL_IS_BIT_SET(huart->AdvancedInit.AdvFeatureInit, ++ UART_ADVFEATURE_SWAP_INIT)) { ++ assert_param(IS_UART_ADVFEATURE_SWAP(huart->AdvancedInit.Swap)); ++ MODIFY_REG(huart->Instance->CR2, USART_CR2_SWAP, ++ huart->AdvancedInit.Swap); ++ } ++ ++ /* if required, configure RX overrun detection disabling */ ++ if (HAL_IS_BIT_SET(huart->AdvancedInit.AdvFeatureInit, ++ UART_ADVFEATURE_RXOVERRUNDISABLE_INIT)) { ++ assert_param(IS_UART_OVERRUN( ++ huart->AdvancedInit.OverrunDisable)); ++ MODIFY_REG(huart->Instance->CR3, USART_CR3_OVRDIS, ++ huart->AdvancedInit.OverrunDisable); ++ } ++ ++ /* if required, configure DMA disabling on reception error */ ++ if (HAL_IS_BIT_SET(huart->AdvancedInit.AdvFeatureInit, ++ UART_ADVFEATURE_DMADISABLEONERROR_INIT)) { ++ assert_param( ++ IS_UART_ADVFEATURE_DMAONRXERROR( ++ huart->AdvancedInit.DMADisableonRxError)); ++ MODIFY_REG(huart->Instance->CR3, USART_CR3_DDRE, ++ huart->AdvancedInit.DMADisableonRxError); ++ } ++ ++ /* if required, configure auto Baud rate detection scheme */ ++ if (HAL_IS_BIT_SET(huart->AdvancedInit.AdvFeatureInit, ++ UART_ADVFEATURE_AUTOBAUDRATE_INIT)) { ++ assert_param( ++ IS_USART_AUTOBAUDRATE_DETECTION_INSTANCE( ++ huart->Instance)); ++ assert_param( ++ IS_UART_ADVFEATURE_AUTOBAUDRATE( ++ huart->AdvancedInit.AutoBaudRateEnable)); ++ MODIFY_REG(huart->Instance->CR2, USART_CR2_ABREN, ++ huart->AdvancedInit.AutoBaudRateEnable); ++ /* set auto Baudrate detection parameters if detection is enabled */ ++ if (huart->AdvancedInit.AutoBaudRateEnable == ++ UART_ADVFEATURE_AUTOBAUDRATE_ENABLE) { ++ assert_param( ++ IS_UART_ADVFEATURE_AUTOBAUDRATEMODE( ++ huart->AdvancedInit.AutoBaudRateMode)); ++ MODIFY_REG(huart->Instance->CR2, USART_CR2_ABRMODE, ++ huart->AdvancedInit.AutoBaudRateMode); ++ } ++ } ++ ++ /* if required, configure MSB first on communication line */ ++ if (HAL_IS_BIT_SET(huart->AdvancedInit.AdvFeatureInit, ++ UART_ADVFEATURE_MSBFIRST_INIT)) { ++ assert_param( ++ IS_UART_ADVFEATURE_MSBFIRST( ++ huart->AdvancedInit.MSBFirst)); ++ MODIFY_REG(huart->Instance->CR2, USART_CR2_MSBFIRST, ++ huart->AdvancedInit.MSBFirst); ++ } ++} ++ ++/** ++ * @brief Check the UART Idle State. ++ * @param huart: UART handle. ++ * @retval HAL status ++ */ ++HAL_StatusTypeDef UART_CheckIdleState(UART_HandleTypeDef *huart) ++{ ++ uint32_t tickstart; ++ ++ /* Initialize the UART ErrorCode */ ++ huart->ErrorCode = HAL_UART_ERROR_NONE; ++ ++ /* Init tickstart for timeout management*/ ++ tickstart = HAL_GetTick(); ++ ++ /* Check if the Transmitter is enabled */ ++ if ((huart->Instance->CR1 & USART_CR1_TE) == USART_CR1_TE) { ++ /* Wait until TEACK flag is set */ ++ if (UART_WaitOnFlagUntilTimeout(huart, USART_ISR_TEACK, ++ RESET, tickstart, ++ HAL_UART_TIMEOUT_VALUE) != ++ HAL_OK) { ++ /* Timeout occurred */ ++ return HAL_TIMEOUT; ++ } ++ } ++ /* Check if the Receiver is enabled */ ++ if ((huart->Instance->CR1 & USART_CR1_RE) == USART_CR1_RE) { ++ /* Wait until REACK flag is set */ ++ if (UART_WaitOnFlagUntilTimeout(huart, USART_ISR_REACK, RESET, ++ tickstart, ++ HAL_UART_TIMEOUT_VALUE) != ++ HAL_OK) { ++ /* Timeout occurred */ ++ return HAL_TIMEOUT; ++ } ++ } ++ ++ /* Initialize the UART State */ ++ huart->gState = HAL_UART_STATE_READY; ++ huart->RxState = HAL_UART_STATE_READY; ++ ++ /* Process Unlocked */ ++ __HAL_UNLOCK(huart); ++ ++ return HAL_OK; ++} ++ ++/** ++ * @brief Handle UART Communication Timeout. ++ * @param huart: UART handle. ++ * @param Flag Specifies the UART flag to check ++ * @param Status Flag status (SET or RESET) ++ * @param Tickstart Tick start value ++ * @param Timeout Timeout duration ++ * @retval HAL status ++ */ ++HAL_StatusTypeDef UART_WaitOnFlagUntilTimeout(UART_HandleTypeDef *huart, ++ uint32_t Flag, FlagStatus Status, ++ uint32_t Tickstart, ++ uint32_t Timeout) ++{ ++ /* Wait until flag is set */ ++ while ((__HAL_UART_GET_FLAG(huart, Flag) ? SET : RESET) == Status) { ++ /* Check for the Timeout */ ++ if (Timeout != HAL_MAX_DELAY) { ++ if ((Timeout == 0U) || ++ ((HAL_GetTick() - Tickstart) > Timeout)) { ++ /* ++ * Disable TXE, RXNE, PE and ERR (Frame error, noise error, overrun error) ++ * interrupts for the interrupt process ++ */ ++ CLEAR_BIT(huart->Instance->CR1, ++ (USART_CR1_RXNEIE | USART_CR1_PEIE | ++ USART_CR1_TXEIE)); ++ CLEAR_BIT(huart->Instance->CR3, USART_CR3_EIE); ++ ++ huart->gState = HAL_UART_STATE_READY; ++ huart->RxState = HAL_UART_STATE_READY; ++ ++ /* Process Unlocked */ ++ __HAL_UNLOCK(huart); ++ ++ return HAL_TIMEOUT; ++ } ++ } ++ } ++ return HAL_OK; ++} ++ ++#endif /* HAL_UART_MODULE_ENABLED */ ++ ++ ++/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ +diff --git a/drivers/st/usb_dwc2/usb_dwc2.c b/drivers/st/usb_dwc2/usb_dwc2.c +new file mode 100644 +index 0000000..a920553 +--- /dev/null ++++ b/drivers/st/usb_dwc2/usb_dwc2.c +@@ -0,0 +1,858 @@ ++/* ++ * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved. ++ * ++ * SPDX-License-Identifier: BSD-3-Clause ++ */ ++ ++#include ++#include ++#include ++#include ++ ++static usb_dwc2_t dwc2_handle; ++ ++static const usb_driver_t usb_dwc2driver = { ++ .disable_int = usb_dwc2_disable_int, ++ .ep0_out_start = usb_dwc2_ep0_out_start, ++ .ep_start_xfer = usb_dwc2_ep_start_xfer, ++ .ep0_start_xfer = usb_dwc2_ep0_start_xfer, ++ .write_packet = usb_dwc2_write_packet, ++ .read_packet = usb_dwc2_read_packet, ++ .ep_set_stall = usb_dwc2_ep_set_stall, ++ .stop_device = usb_dwc2_stop_device, ++ .set_address = usb_dwc2_set_address, ++ .dev_disconnect = usb_dwc2_dev_disconnect, ++ .write_empty_tx_fifo = usb_dwc2_write_empty_tx_fifo, ++ .it_handler = usb_dwc2_it_handler ++}; ++ ++/* ++ * USB_OTG_FlushTxFifo : Flush a Tx FIFO ++ * USBx : Selected device ++ * num : FIFO number ++ * This parameter can be a value from 1 to 15 ++ * 15 means Flush all Tx FIFOs ++ * return : status ++ */ ++static usb_status_t usb_dwc2_flush_tx_fifo(usb_dwc2_global_t *usbx, ++ uint32_t num) ++{ ++ uint32_t count = 0; ++ ++ usbx->grstctl = (USB_OTG_GRSTCTL_TXFFLSH | (uint32_t)(num << 6)); ++ ++ do { ++ if (++count > 200000) ++ return USBD_TIMEOUT; ++ } while ((usbx->grstctl & USB_OTG_GRSTCTL_TXFFLSH) == ++ USB_OTG_GRSTCTL_TXFFLSH); ++ ++ return USBD_OK; ++} ++ ++/* ++ * USB_FlushRxFifo : Flush Rx FIFO ++ * param : USBx : Selected device ++ * return : status ++ */ ++static usb_status_t usb_dwc2_flush_rx_fifo(usb_dwc2_global_t *usbx) ++{ ++ uint32_t count = 0; ++ ++ usbx->grstctl = USB_OTG_GRSTCTL_RXFFLSH; ++ ++ do { ++ if (++count > 200000) ++ return USBD_TIMEOUT; ++ } while ((usbx->grstctl & USB_OTG_GRSTCTL_RXFFLSH) == ++ USB_OTG_GRSTCTL_RXFFLSH); ++ ++ return USBD_OK; ++} ++ ++/* ++ * USB_ReadInterrupts: return the global USB interrupt status ++ * param USBx : Selected device ++ * return : interrupt register value ++ */ ++static uint32_t usb_dwc2_read_int(usb_dwc2_global_t *usbx) ++{ ++ uint32_t v = 0; ++ ++ v = usbx->gintsts; ++ v &= usbx->gintmsk; ++ ++ return v; ++} ++ ++/* ++ * usb_dwc2_all_out_ep_int : return the USB device OUT endpoints interrupt ++ * param : USBx : Selected device ++ * return : device OUT endpoint interrupts ++ */ ++static uint32_t usb_dwc2_all_out_ep_int(usb_dwc2_global_t *usbx) ++{ ++ uint32_t v = 0; ++ ++ v = dwc2_handle.usb_device->daint; ++ v &= dwc2_handle.usb_device->daintmsk; ++ ++ return ((v & 0xffff0000) >> 16); ++} ++ ++/* ++ * usb_dwc2_all_in_ep_int: return the USB device IN endpoints interrupt ++ * param : USBx : Selected device ++ * return : device IN endpoint interrupts ++ */ ++static uint32_t usb_dwc2_all_in_ep_int(usb_dwc2_global_t *usbx) ++{ ++ uint32_t v = 0; ++ ++ v = dwc2_handle.usb_device->daint; ++ v &= dwc2_handle.usb_device->daintmsk; ++ ++ return ((v & 0xFFFF)); ++} ++ ++/* ++ * usb_dwc2_out_ep_int : returns Device OUT EP Interrupt register ++ * USBx : Selected device ++ * epnum : endpoint number ++ * This parameter can be a value from 0 to 15 ++ * return : Device OUT EP Interrupt register ++ */ ++static uint32_t usb_dwc2_out_ep_int(usb_dwc2_global_t *usbx, uint8_t epnum) ++{ ++ uint32_t v = 0; ++ ++ v = dwc2_handle.usb_out_endpoint[epnum]->epint; ++ v &= dwc2_handle.usb_device->doepmsk; ++ ++ return v; ++} ++ ++/* ++ * usb_dwc2_in_ep_int : Returns Device IN EP Interrupt register ++ * param : USBx : Selected device ++ * param : epnum : endpoint number ++ * This parameter can be a value from 0 to 15 ++ * return : Device IN EP Interrupt register ++ */ ++static uint32_t usb_dwc2_in_ep_int(usb_dwc2_global_t *usbx, uint8_t epnum) ++{ ++ uint32_t msk, emp; ++ ++ msk = dwc2_handle.usb_device->diepmsk; ++ emp = dwc2_handle.usb_device->diepempmsk; ++ msk |= ((emp >> epnum) & 0x1) << 7; ++ ++ return (dwc2_handle.usb_in_endpoint[epnum]->epint & msk); ++} ++ ++/* ++ * usb_dwc2_get_mode : Returns USB core mode ++ * param : USBx : Selected device ++ * return : core mode : Host or Device ++ * This parameter can be one of the these values: ++ * 0 : Host ++ * 1 : Device ++ */ ++static uint32_t usb_dwc2_get_mode(usb_dwc2_global_t *usbx) ++{ ++ return ((usbx->gintsts) & 0x1); ++} ++ ++/* ++ * usb_dwc2_activate_setup : Activate EP0 for Setup transactions ++ * param : USBx : Selected device ++ * return : status ++ */ ++static usb_status_t usb_dwc2_activate_setup(usb_dwc2_global_t *usbx) ++{ ++ /* Set the MPS of the IN EP based on the enumeration speed */ ++ dwc2_handle.usb_in_endpoint[0]->epctl &= ~USB_OTG_DIEPCTL_MPSIZ; ++ ++ if ((dwc2_handle.usb_device->dsts & USB_OTG_DSTS_ENUMSPD) == ++ DSTS_ENUMSPD_LS_PHY_6MHZ) ++ dwc2_handle.usb_in_endpoint[0]->epctl |= 3; ++ ++ dwc2_handle.usb_device->dctl |= USB_OTG_DCTL_CGINAK; ++ ++ return USBD_OK; ++} ++ ++/* ++ * usb_dwc2_disable_int : ++ * Disable the controller's Global Int in the AHB Config reg ++ * param : handle : Selected device ++ * return : status ++ */ ++usb_status_t usb_dwc2_disable_int(void *handle) ++{ ++ usb_dwc2_global_t *usbx = ((usb_dwc2_t *)handle)->usb_global; ++ ++ usbx->gahbcfg &= ~USB_OTG_GAHBCFG_GINT; ++ return USBD_OK; ++} ++ ++/* ++ * usb_dwc2_ep0_out_start : Prepare the EP0 to start the first control setup ++ * param : handle : Selected device ++ * return : status ++ */ ++usb_status_t usb_dwc2_ep0_out_start(void *handle) ++{ ++ /*usb_dwc2_global_t *USBx = (usb_dwc2_global_t *)handle;*/ ++ ++ dwc2_handle.usb_out_endpoint[0]->eptsiz = 0; ++ dwc2_handle.usb_out_endpoint[0]->eptsiz |= (USB_OTG_DOEPTSIZ_PKTCNT & ++ (1 << 19)); ++ dwc2_handle.usb_out_endpoint[0]->eptsiz |= (3 * 8); ++ dwc2_handle.usb_out_endpoint[0]->eptsiz |= USB_OTG_DOEPTSIZ_STUPCNT; ++ ++ return USBD_OK; ++} ++ ++/* ++ * usb_dwc2_ep_start_xfer : setup and starts a transfer over an EP ++ * param : handle : Selected device ++ * param : ep: pointer to endpoint structure ++ * return : status ++ */ ++usb_status_t usb_dwc2_ep_start_xfer(void *handle, usb_otg_ep_t *ep) ++{ ++ usb_dwc2_global_t *usbx = ((usb_dwc2_t *)handle)->usb_global; ++ ++ /* IN endpoint */ ++ if (ep->is_in == 1) { ++ /* Zero Length Packet? */ ++ if (ep->xfer_len == 0) { ++ dwc2_handle.usb_in_endpoint[ep->num]->eptsiz &= ++ ~(USB_OTG_DIEPTSIZ_PKTCNT); ++ dwc2_handle.usb_in_endpoint[ep->num]->eptsiz |= ++ (USB_OTG_DIEPTSIZ_PKTCNT & (1 << 19)); ++ dwc2_handle.usb_in_endpoint[ep->num]->eptsiz &= ++ ~(USB_OTG_DIEPTSIZ_XFRSIZ); ++ } else { ++ /* Program the transfer size and packet count ++ * as follows: xfersize = N * maxpacket + ++ * short_packet pktcnt = N + (short_packet ++ * exist ? 1 : 0) ++ */ ++ dwc2_handle.usb_in_endpoint[ep->num]->eptsiz &= ++ ~(USB_OTG_DIEPTSIZ_XFRSIZ); ++ dwc2_handle.usb_in_endpoint[ep->num]->eptsiz &= ++ ~(USB_OTG_DIEPTSIZ_PKTCNT); ++ dwc2_handle.usb_in_endpoint[ep->num]->eptsiz |= ++ (USB_OTG_DIEPTSIZ_PKTCNT & ++ (((ep->xfer_len + ep->maxpacket - 1) / ++ ep->maxpacket) << 19)); ++ dwc2_handle.usb_in_endpoint[ep->num]->eptsiz |= ++ (USB_OTG_DIEPTSIZ_XFRSIZ & ++ ep->xfer_len); ++ ++ if (ep->type == EP_TYPE_ISOC) { ++ dwc2_handle.usb_in_endpoint[ep->num]->eptsiz &= ++ ~(USB_OTG_DIEPTSIZ_MULCNT); ++ dwc2_handle.usb_in_endpoint[ep->num]->eptsiz |= ++ (USB_OTG_DIEPTSIZ_MULCNT & ++ (1 << 29)); ++ } ++ } ++ ++ if (ep->type != EP_TYPE_ISOC) { ++ /* Enable the Tx FIFO Empty Interrupt for this EP */ ++ if (ep->xfer_len > 0) ++ dwc2_handle.usb_device->diepempmsk |= ++ 1 << ep->num; ++ } ++ ++ if (ep->type == EP_TYPE_ISOC) { ++ if ((dwc2_handle.usb_device->dsts & (1 << 8)) == 0) { ++ dwc2_handle.usb_in_endpoint[ep->num]->epctl |= ++ USB_OTG_DIEPCTL_SODDFRM; ++ } else { ++ dwc2_handle.usb_in_endpoint[ep->num]->epctl |= ++ USB_OTG_DIEPCTL_SD0PID_SEVNFRM; ++ } ++ } ++ ++ /* EP enable, IN data in FIFO */ ++ dwc2_handle.usb_in_endpoint[ep->num]->epctl |= ++ (USB_OTG_DIEPCTL_CNAK | ++ USB_OTG_DIEPCTL_EPENA); ++ ++ if (ep->type == EP_TYPE_ISOC) ++ usb_dwc2_write_packet(usbx, ep->xfer_buff, ++ ep->num, ep->xfer_len); ++ } else { ++ /* Program the transfer size and packet count as follows: ++ * pktcnt = N ++ * xfersize = N * maxpacket ++ */ ++ dwc2_handle.usb_out_endpoint[ep->num]->eptsiz &= ++ ~(USB_OTG_DOEPTSIZ_XFRSIZ); ++ dwc2_handle.usb_out_endpoint[ep->num]->eptsiz &= ++ ~(USB_OTG_DOEPTSIZ_PKTCNT); ++ ++ if (ep->xfer_len == 0) { ++ dwc2_handle.usb_out_endpoint[ep->num]->eptsiz |= ++ (USB_OTG_DOEPTSIZ_XFRSIZ & ++ ep->maxpacket); ++ dwc2_handle.usb_out_endpoint[ep->num]->eptsiz |= ++ (USB_OTG_DOEPTSIZ_PKTCNT & (1 << 19)); ++ } else { ++ uint16_t pktcnt = (ep->xfer_len + ep->maxpacket - 1) / ++ ep->maxpacket; ++ ++ dwc2_handle.usb_out_endpoint[ep->num]->eptsiz |= ++ (USB_OTG_DOEPTSIZ_PKTCNT & ++ (pktcnt << 19)); ++ dwc2_handle.usb_out_endpoint[ep->num]->eptsiz |= ++ (USB_OTG_DOEPTSIZ_XFRSIZ & ++ (ep->maxpacket * pktcnt)); ++ } ++ ++ if (ep->type == EP_TYPE_ISOC) { ++ if ((dwc2_handle.usb_device->dsts & (1 << 8)) == 0) ++ dwc2_handle.usb_out_endpoint[ep->num]->epctl |= ++ USB_OTG_DOEPCTL_SODDFRM; ++ else ++ dwc2_handle.usb_out_endpoint[ep->num]->epctl |= ++ USB_OTG_DOEPCTL_SD0PID_SEVNFRM; ++ } ++ /* EP enable */ ++ dwc2_handle.usb_out_endpoint[ep->num]->epctl |= ++ (USB_OTG_DOEPCTL_CNAK | USB_OTG_DOEPCTL_EPENA); ++ } ++ return USBD_OK; ++} ++ ++/* ++ * usb_dwc2_ep0_start_xfer : setup and starts a transfer over the EP 0 ++ * param : handle : Selected device ++ * param : ep: pointer to endpoint structure ++ * return : status ++ */ ++usb_status_t usb_dwc2_ep0_start_xfer(void *handle, usb_otg_ep_t *ep) ++{ ++ /*usb_dwc2_global_t *USBx = (usb_dwc2_global_t *)handle;*/ ++ ++ /* IN endpoint */ ++ if (ep->is_in == 1) { ++ /* Zero Length Packet? */ ++ if (ep->xfer_len == 0) { ++ dwc2_handle.usb_in_endpoint[ep->num]->eptsiz &= ++ ~(USB_OTG_DIEPTSIZ_PKTCNT); ++ dwc2_handle.usb_in_endpoint[ep->num]->eptsiz |= ++ (USB_OTG_DIEPTSIZ_PKTCNT & (1 << 19)); ++ dwc2_handle.usb_in_endpoint[ep->num]->eptsiz &= ++ ~(USB_OTG_DIEPTSIZ_XFRSIZ); ++ } else { ++ /* Program the transfer size and packet count ++ * as follows: xfersize = N * maxpacket + ++ * short_packet pktcnt = N + (short_packet ++ * exist ? 1 : 0) ++ */ ++ dwc2_handle.usb_in_endpoint[ep->num]->eptsiz &= ++ ~(USB_OTG_DIEPTSIZ_XFRSIZ); ++ dwc2_handle.usb_in_endpoint[ep->num]->eptsiz &= ++ ~(USB_OTG_DIEPTSIZ_PKTCNT); ++ ++ if (ep->xfer_len > ep->maxpacket) ++ ep->xfer_len = ep->maxpacket; ++ ++ dwc2_handle.usb_in_endpoint[ep->num]->eptsiz |= ++ (USB_OTG_DIEPTSIZ_PKTCNT & (1 << 19)); ++ dwc2_handle.usb_in_endpoint[ep->num]->eptsiz |= ++ (USB_OTG_DIEPTSIZ_XFRSIZ & ++ ep->xfer_len); ++ } ++ ++ /* Enable the Tx FIFO Empty Interrupt for this EP */ ++ if (ep->xfer_len > 0) ++ dwc2_handle.usb_device->diepempmsk |= 1 << (ep->num); ++ ++ /* EP enable, IN data in FIFO */ ++ dwc2_handle.usb_in_endpoint[ep->num]->epctl |= ++ (USB_OTG_DIEPCTL_CNAK | USB_OTG_DIEPCTL_EPENA); ++ } else { ++ /* Program the transfer size and packet count as follows: ++ * pktcnt = N ++ * xfersize = N * maxpacket ++ */ ++ dwc2_handle.usb_out_endpoint[ep->num]->eptsiz &= ++ ~(USB_OTG_DOEPTSIZ_XFRSIZ); ++ dwc2_handle.usb_out_endpoint[ep->num]->eptsiz &= ++ ~(USB_OTG_DOEPTSIZ_PKTCNT); ++ ++ if (ep->xfer_len > 0) ++ ep->xfer_len = ep->maxpacket; ++ ++ dwc2_handle.usb_out_endpoint[ep->num]->eptsiz |= ++ (USB_OTG_DOEPTSIZ_PKTCNT & ++ (1 << 19)); ++ dwc2_handle.usb_out_endpoint[ep->num]->eptsiz |= ++ (USB_OTG_DOEPTSIZ_XFRSIZ & ++ (ep->maxpacket)); ++ ++ /* EP enable */ ++ dwc2_handle.usb_out_endpoint[ep->num]->epctl |= ++ (USB_OTG_DOEPCTL_CNAK | ++ USB_OTG_DOEPCTL_EPENA); ++ } ++ return USBD_OK; ++} ++ ++/* ++ * usb_dwc2_write_packet : Writes a packet into the Tx FIFO associated ++ * with the EP/channel ++ * param : handle : Selected device ++ * param : src : pointer to source buffer ++ * param : ch_ep_num : endpoint or host channel number ++ * param : len : Number of bytes to write ++ * return : status ++ */ ++usb_status_t usb_dwc2_write_packet(void *handle, uint8_t *src, ++ uint8_t ch_ep_num, uint16_t len) ++{ ++ uint32_t count32b, i, j; ++ /*usb_dwc2_global_t *USBx = (usb_dwc2_global_t *)handle;*/ ++ ++ count32b = (len + 3) / 4; ++ for (i = 0; i < count32b; i++, src += 4) { ++ uint32_t src_copy = 0; ++ ++ /* Data written to fifo need to be 4 bytes aligned */ ++ for (j = 0; j < 4; j++) ++ src_copy += (*(src + j)) << (8 * j); ++ ++ *dwc2_handle.usb_fifo[ch_ep_num] = src_copy; ++ } ++ ++ return USBD_OK; ++} ++ ++/* ++ * usb_dwc2_read_packet : read a packet from the Tx FIFO associated ++ * with the EP/channel ++ * param : handle : Selected device ++ * param : src : source pointer ++ * param : ch_ep_num : endpoint or host channel number ++ * param : len : Number of bytes to read ++ * return : pointer to destination buffer ++ */ ++void *usb_dwc2_read_packet(void *handle, uint8_t *dest, uint16_t len) ++{ ++ uint32_t i = 0; ++ uint32_t count32b = (len + 3) / 4; ++ /*usb_dwc2_global_t *USBx = (usb_dwc2_global_t *)handle;*/ ++ ++ VERBOSE("read packet length %i to 0x%lx\n", len, (uintptr_t)dest); ++ ++ for (i = 0; i < count32b; i++, dest += 4) { ++ *(uint32_t *)dest = *dwc2_handle.usb_fifo[0]; ++ dsb(); ++ } ++ ++ return ((void *)dest); ++} ++ ++/* ++ * usb_dwc2_EPSetStall : set a stall condition over an EP ++ * param : handle : Selected device ++ * param : ep: pointer to endpoint structure ++ * return : status ++ */ ++usb_status_t usb_dwc2_ep_set_stall(void *handle, usb_otg_ep_t *ep) ++{ ++ /*usb_dwc2_global_t *USBx = (usb_dwc2_global_t *)handle;*/ ++ if (ep->is_in == 1) { ++ if ((dwc2_handle.usb_in_endpoint[ep->num]->epctl & ++ USB_OTG_DIEPCTL_EPENA) == 0) ++ dwc2_handle.usb_in_endpoint[ep->num]->epctl &= ++ ~(USB_OTG_DIEPCTL_EPDIS); ++ dwc2_handle.usb_in_endpoint[ep->num]->epctl |= ++ USB_OTG_DIEPCTL_STALL; ++ } else { ++ if ((dwc2_handle.usb_out_endpoint[ep->num]->epctl & ++ USB_OTG_DOEPCTL_EPENA) == 0) ++ dwc2_handle.usb_out_endpoint[ep->num]->epctl &= ++ ~(USB_OTG_DOEPCTL_EPDIS); ++ dwc2_handle.usb_out_endpoint[ep->num]->epctl |= ++ USB_OTG_DOEPCTL_STALL; ++ } ++ return USBD_OK; ++} ++ ++/* ++ * usb_dwc2_stop_device : Stop the usb device mode ++ * param : handle : Selected device ++ * return : status ++ */ ++usb_status_t usb_dwc2_stop_device(void *handle) ++{ ++ uint32_t i = 0; ++ usb_dwc2_global_t *usbx = ((usb_dwc2_t *)handle)->usb_global; ++ ++ /* Clear Pending interrupt */ ++ for (i = 0; i < 15 ; i++) { ++ dwc2_handle.usb_in_endpoint[i]->epint = 0xFF; ++ dwc2_handle.usb_out_endpoint[i]->epint = 0xFF; ++ } ++ dwc2_handle.usb_device->daint = 0xFFFFFFFF; ++ ++ /* Clear interrupt masks */ ++ dwc2_handle.usb_device->diepmsk = 0; ++ dwc2_handle.usb_device->doepmsk = 0; ++ dwc2_handle.usb_device->daintmsk = 0; ++ ++ /* Flush the FIFO */ ++ usb_dwc2_flush_rx_fifo(usbx); ++ usb_dwc2_flush_tx_fifo(usbx, 0x10); ++ ++ return USBD_OK; ++} ++ ++/* ++ * usb_dwc2_set_address : Stop the usb device mode ++ * param : handle : Selected device ++ * param : address : new device address to be assigned ++ * This parameter can be a value from 0 to 255 ++ * return : status ++ */ ++usb_status_t usb_dwc2_set_address(void *handle, uint8_t address) ++{ ++ /*usb_dwc2_global_t *USBx = (usb_dwc2_global_t *)handle;*/ ++ ++ dwc2_handle.usb_device->dcfg &= ~(USB_OTG_DCFG_DAD); ++ dwc2_handle.usb_device->dcfg |= (address << 4) & USB_OTG_DCFG_DAD; ++ ++ return USBD_OK; ++} ++ ++/* ++ * usb_dwc2_dev_disconnect : ++ * Disconnect the USB device by disabling the pull-up/pull-down ++ * param : handle : Selected device ++ * return : status ++ */ ++usb_status_t usb_dwc2_dev_disconnect(void *handle) ++{ ++ /*usb_dwc2_global_t *USBx = (usb_dwc2_global_t *)handle;*/ ++ ++ dwc2_handle.usb_device->dctl |= USB_OTG_DCTL_SDIS; ++ ++ return USBD_OK; ++} ++ ++/* ++ * usb_dwc2_write_empty_tx_fifo ++ * check FIFO for the next packet to be loaded ++ * param : handle : Selected device ++ * param : epnum : endpoint number ++ * param : xfer_len : block length ++ * param : xfer_count : number of block ++ * param : maxpacket : max packet length ++ * param : xfer_buff : buffer pointer ++ * retval : status ++ */ ++usb_status_t usb_dwc2_write_empty_tx_fifo(void *handle, ++ uint32_t epnum, uint32_t xfer_len, ++ uint32_t *xfer_count, ++ uint32_t maxpacket, ++ uint8_t **xfer_buff) ++{ ++ int32_t len = 0; ++ uint32_t len32b; ++ usb_dwc2_global_t *usbx = ((usb_dwc2_t *)handle)->usb_global; ++ ++ len = xfer_len - *xfer_count; ++ ++ if ((len > 0) && ((uint32_t)len > maxpacket)) ++ len = maxpacket; ++ ++ len32b = (len + 3) / 4; ++ ++ while ((dwc2_handle.usb_in_endpoint[epnum]->txfsts & ++ USB_OTG_DTXFSTS_INEPTFSAV) > len32b && ++ (*xfer_count < xfer_len) && (xfer_len != 0)) { ++ /* Write the FIFO */ ++ len = xfer_len - *xfer_count; ++ ++ if ((len > 0) && ((uint32_t)len > maxpacket)) ++ len = maxpacket; ++ ++ len32b = (len + 3) / 4; ++ ++ usb_dwc2_write_packet(usbx, *xfer_buff, epnum, len); ++ ++ *xfer_buff += len; ++ *xfer_count += len; ++ } ++ ++ if (len <= 0) { ++ uint32_t fifoemptymsk = 0x1 << epnum; ++ ++ dwc2_handle.usb_device->diepempmsk &= ~fifoemptymsk; ++ } ++ ++ return USBD_OK; ++} ++ ++/* ++ * @brief This function handles PCD interrupt request. ++ * @param hpcd: PCD handle ++ * @retval HAL status ++ */ ++usb_action_t usb_dwc2_it_handler(void *handle, uint32_t *param) ++{ ++ usb_dwc2_global_t *usbx = ((usb_dwc2_t *)handle)->usb_global; ++ uint32_t ep_intr, epint, epnum = 0; ++ uint32_t temp; ++ ++ /* ensure that we are in device mode */ ++ if (usb_dwc2_get_mode(usbx) != USB_OTG_MODE_DEVICE) ++ return USB_NOTHING; ++ ++ /* avoid spurious interrupt */ ++ if (!usb_dwc2_read_int(usbx)) ++ return USB_NOTHING; ++ ++ if (usb_dwc2_read_int(usbx) & USB_OTG_GINTSTS_MMIS) ++ /* incorrect mode, acknowledge the interrupt */ ++ usbx->gintsts = USB_OTG_GINTSTS_MMIS; ++ ++ if (usb_dwc2_read_int(usbx) & USB_OTG_GINTSTS_OEPINT) { ++ /* Read in the device interrupt bits */ ++ ep_intr = usb_dwc2_all_out_ep_int(usbx); ++ ++ while (!(ep_intr & 1)) { ++ epnum++; ++ ep_intr >>= 1; ++ } ++ ++ if (ep_intr & 1) { ++ epint = usb_dwc2_out_ep_int(usbx, epnum); ++ ++ if ((epint & USB_OTG_DOEPINT_XFRC) == ++ USB_OTG_DOEPINT_XFRC) { ++ dwc2_handle.usb_out_endpoint[epnum]->epint = ++ USB_OTG_DOEPINT_XFRC; ++ *param = epnum; ++ return USB_DATA_OUT; ++ } ++ if ((epint & USB_OTG_DOEPINT_STUP) == ++ USB_OTG_DOEPINT_STUP) { ++ /* Inform the upper layer that a setup packet ++ * is available ++ */ ++ dwc2_handle.usb_out_endpoint[epnum]->epint = ++ USB_OTG_DOEPINT_STUP; ++ return USB_SETUP; ++ } ++ if ((epint & USB_OTG_DOEPINT_OTEPDIS) == ++ USB_OTG_DOEPINT_OTEPDIS) ++ dwc2_handle.usb_out_endpoint[epnum]->epint = ++ USB_OTG_DOEPINT_OTEPDIS; ++ } ++ } ++ if (usb_dwc2_read_int(usbx) & USB_OTG_GINTSTS_IEPINT) { ++ /* Read in the device interrupt bits */ ++ ep_intr = usb_dwc2_all_in_ep_int(usbx); ++ ++ while (!(ep_intr & 1)) { ++ epnum++; ++ ep_intr >>= 1; ++ } ++ /* In ITR */ ++ if (ep_intr & 0x1) { ++ epint = usb_dwc2_in_ep_int(usbx, epnum); ++ ++ if ((epint & USB_OTG_DIEPINT_XFRC) == ++ USB_OTG_DIEPINT_XFRC) { ++ uint32_t fifoemptymsk = 0x1 << epnum; ++ ++ dwc2_handle.usb_device->diepempmsk &= ++ ~fifoemptymsk; ++ ++ dwc2_handle.usb_in_endpoint[epnum]->epint = ++ USB_OTG_DIEPINT_XFRC; ++ ++ *param = epnum; ++ return USB_DATA_IN; ++ } ++ if ((epint & USB_OTG_DIEPINT_TOC) == ++ USB_OTG_DIEPINT_TOC) ++ dwc2_handle.usb_in_endpoint[epnum]->epint = ++ USB_OTG_DIEPINT_TOC; ++ ++ if ((epint & USB_OTG_DIEPINT_ITTXFE) == ++ USB_OTG_DIEPINT_ITTXFE) ++ dwc2_handle.usb_in_endpoint[epnum]->epint = ++ USB_OTG_DIEPINT_ITTXFE; ++ ++ if ((epint & USB_OTG_DIEPINT_INEPNE) == ++ USB_OTG_DIEPINT_INEPNE) ++ dwc2_handle.usb_in_endpoint[epnum]->epint = ++ USB_OTG_DIEPINT_INEPNE; ++ ++ if ((epint & USB_OTG_DIEPINT_EPDISD) == ++ USB_OTG_DIEPINT_EPDISD) ++ dwc2_handle.usb_in_endpoint[epnum]->epint = ++ USB_OTG_DIEPINT_EPDISD; ++ ++ if ((epint & USB_OTG_DIEPINT_TXFE) == ++ USB_OTG_DIEPINT_TXFE) { ++ *param = epnum; ++ return USB_WRITE_EMPTY; ++ } ++ } ++ } ++ ++ /* Handle Resume Interrupt */ ++ if (usb_dwc2_read_int(usbx) & USB_OTG_GINTSTS_WKUINT) { ++ INFO("handle USB : Resume\n"); ++ /* Clear the Remote Wake-up Signaling */ ++ dwc2_handle.usb_device->dctl &= ~USB_OTG_DCTL_RWUSIG; ++ usbx->gintsts = USB_OTG_GINTSTS_WKUINT; ++ return USB_RESUME; ++ } ++ ++ /* Handle Suspend Interrupt */ ++ if (usb_dwc2_read_int(usbx) & USB_OTG_GINTSTS_USBSUSP) { ++ INFO("handle USB : Suspend int\n"); ++ usbx->gintsts = USB_OTG_GINTSTS_USBSUSP; ++ if ((dwc2_handle.usb_device->dsts & USB_OTG_DSTS_SUSPSTS) == ++ USB_OTG_DSTS_SUSPSTS){ ++ return USB_SUSPEND; ++ } ++ } ++ ++ /* Handle LPM Interrupt */ ++ if (usb_dwc2_read_int(usbx) & USB_OTG_GINTSTS_LPMINT) { ++ INFO("handle USB : LPM int enter in suspend\n"); ++ usbx->gintsts = USB_OTG_GINTSTS_LPMINT; ++ *param = (usbx->glpmcfg & USB_OTG_GLPMCFG_BESL) >> 2; ++ return USB_LPM; ++ } ++ ++ /* Handle Reset Interrupt */ ++ if (usb_dwc2_read_int(usbx) & USB_OTG_GINTSTS_USBRST) { ++ INFO("handle USB : Reset\n"); ++ dwc2_handle.usb_device->dctl &= ~USB_OTG_DCTL_RWUSIG; ++ usb_dwc2_flush_tx_fifo(usbx, 0); ++ ++ dwc2_handle.usb_device->daint = 0xFFFFFFFF; ++ dwc2_handle.usb_device->daintmsk |= 0x10001; ++ ++ dwc2_handle.usb_device->doepmsk |= (USB_OTG_DOEPMSK_STUPM | ++ USB_OTG_DOEPMSK_XFRCM | ++ USB_OTG_DOEPMSK_EPDM); ++ dwc2_handle.usb_device->diepmsk |= (USB_OTG_DIEPMSK_TOM | ++ USB_OTG_DIEPMSK_XFRCM | ++ USB_OTG_DIEPMSK_EPDM); ++ ++ /* Set Default Address to 0 */ ++ dwc2_handle.usb_device->dcfg &= ~USB_OTG_DCFG_DAD; ++ ++ /* setup EP0 to receive SETUP packets */ ++ usb_dwc2_ep0_out_start(usbx); ++ ++ usbx->gintsts = USB_OTG_GINTSTS_USBRST; ++ } ++ ++ /* Handle Enumeration done Interrupt */ ++ if (usb_dwc2_read_int(usbx) & USB_OTG_GINTSTS_ENUMDNE) { ++ usb_dwc2_activate_setup(usbx); ++ usbx->gusbcfg &= ~USB_OTG_GUSBCFG_TRDT; ++ ++ usbx->gusbcfg |= (uint32_t)((USBD_HS_TRDT_VALUE << 10) & ++ USB_OTG_GUSBCFG_TRDT); ++ ++ usbx->gintsts = USB_OTG_GINTSTS_ENUMDNE; ++ return USB_ENUM_DONE; ++ } ++ ++ /* Handle RxQLevel Interrupt */ ++ if (usb_dwc2_read_int(usbx) & USB_OTG_GINTSTS_RXFLVL) { ++ usbx->gintmsk &= ~USB_OTG_GINTSTS_RXFLVL; ++ temp = usbx->grxstsp; ++ *param = (temp & USB_OTG_GRXSTSP_EPNUM); ++ *param |= ((temp & USB_OTG_GRXSTSP_BCNT) << 0xC); ++ ++ if (((temp & USB_OTG_GRXSTSP_PKTSTS) >> 17) == STS_DATA_UPDT) { ++ if ((temp & USB_OTG_GRXSTSP_BCNT) != 0) { ++ usbx->gintmsk |= USB_OTG_GINTSTS_RXFLVL; ++ return USB_READ_DATA_PACKET; ++ } ++ } else if (((temp & USB_OTG_GRXSTSP_PKTSTS) >> 17) == ++ STS_SETUP_UPDT) { ++ usbx->gintmsk |= USB_OTG_GINTSTS_RXFLVL; ++ return USB_READ_SETUP_PACKET; ++ } ++ usbx->gintmsk |= USB_OTG_GINTSTS_RXFLVL; ++ } ++ ++ /* Handle SOF Interrupt */ ++ if (usb_dwc2_read_int(usbx) & USB_OTG_GINTSTS_SOF) { ++ INFO("handle USB : SOF\n"); ++ usbx->gintsts = USB_OTG_GINTSTS_SOF; ++ return USB_SOF; ++ } ++ ++ /* Handle Incomplete ISO IN Interrupt */ ++ if (usb_dwc2_read_int(usbx) & USB_OTG_GINTSTS_IISOIXFR) { ++ INFO("handle USB : ISO IN\n"); ++ usbx->gintsts = USB_OTG_GINTSTS_IISOIXFR; ++ } ++ ++ /* Handle Incomplete ISO OUT Interrupt */ ++ if (usb_dwc2_read_int(usbx) & USB_OTG_GINTSTS_PXFR_INCOMPISOOUT) { ++ INFO("handle USB : ISO OUT\n"); ++ usbx->gintsts = USB_OTG_GINTSTS_PXFR_INCOMPISOOUT; ++ } ++ ++ /* Handle Connection event Interrupt */ ++ if (usb_dwc2_read_int(usbx) & USB_OTG_GINTSTS_SRQINT) { ++ INFO("handle USB : Connect\n"); ++ usbx->gintsts = USB_OTG_GINTSTS_SRQINT; ++ } ++ ++ /* Handle Disconnection event Interrupt */ ++ if (usb_dwc2_read_int(usbx) & USB_OTG_GINTSTS_OTGINT) { ++ INFO("handle USB : Disconnect\n"); ++ temp = usbx->gotgint; ++ if ((temp & USB_OTG_GOTGINT_SEDET) == USB_OTG_GOTGINT_SEDET) ++ return USB_DISCONNECT; ++ } ++ return USB_NOTHING; ++} ++ ++void usb_dwc2_init_driver(usb_handle_t *usb_core_handle, ++ uint32_t *base_register) ++{ ++ uint32_t i = 0; ++ uintptr_t base = (uintptr_t)base_register; ++ ++ dwc2_handle.usb_global = (usb_dwc2_global_t *)base; ++ ++ dwc2_handle.usb_device = (usb_dwc2_device_t *) ++ (base + USB_OTG_DEVICE_BASE); ++ ++ for (i = 0; i < USB_MAX_ENDPOINT_NB; i++) { ++ dwc2_handle.usb_in_endpoint[i] = (usb_dwc2_endpoint_t *) ++ (base + USB_OTG_IN_ENDPOINT_BASE + ++ (i * sizeof(usb_dwc2_endpoint_t))); ++ dwc2_handle.usb_out_endpoint[i] = (usb_dwc2_endpoint_t *) ++ (base + USB_OTG_OUT_ENDPOINT_BASE + ++ (i * sizeof(usb_dwc2_endpoint_t))); ++ dwc2_handle.usb_fifo[i] = (uint32_t *)(base + ++ USB_OTG_FIFO_BASE + ++ (i * USB_OTG_FIFO_SIZE)); ++ } ++ ++ register_usb_driver(usb_core_handle, &usb_dwc2driver, ++ (void *)&dwc2_handle); ++} +diff --git a/drivers/ti/uart/aarch64/16550_console.S b/drivers/ti/uart/aarch64/16550_console.S +index d46fa61..34cce95 100644 +--- a/drivers/ti/uart/aarch64/16550_console.S ++++ b/drivers/ti/uart/aarch64/16550_console.S +@@ -7,6 +7,7 @@ + #include + #include + #include ++#define USE_FINISH_CONSOLE_REG_2 + #include + #include + +@@ -111,7 +112,7 @@ func console_16550_register + + mov x0, x6 + mov x30, x7 +- finish_console_register 16550 ++ finish_console_register 16550 putc=1, getc=1, flush=1 + + register_fail: + ret x7 +diff --git a/fdts/stm32mp15-ddr.dtsi b/fdts/stm32mp15-ddr.dtsi +index be4e2c3..1a5c51c 100644 +--- a/fdts/stm32mp15-ddr.dtsi ++++ b/fdts/stm32mp15-ddr.dtsi +@@ -5,7 +5,7 @@ + + / { + soc { +- ddr: ddr@0x5A003000{ ++ ddr: ddr@5A003000{ + + compatible = "st,stm32mp1-ddr"; + +diff --git a/fdts/stm32mp15-ddr3-1x4Gb-1066-binG.dtsi b/fdts/stm32mp15-ddr3-1x4Gb-1066-binG.dtsi +new file mode 100644 +index 0000000..16b8cf6 +--- /dev/null ++++ b/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/fdts/stm32mp15-ddr3-2x4Gb-1066-binG.dtsi b/fdts/stm32mp15-ddr3-2x4Gb-1066-binG.dtsi +index 58a4cdc..82e7104 100644 +--- a/fdts/stm32mp15-ddr3-2x4Gb-1066-binG.dtsi ++++ b/fdts/stm32mp15-ddr3-2x4Gb-1066-binG.dtsi +@@ -3,7 +3,7 @@ + * Copyright (C) 2018, STMicroelectronics - All Rights Reserved + */ + +-/* STM32MP157C ED1 and ED2 BOARD configuration ++/* STM32MP157C ED1 BOARD configuration + * 2x DDR3L 4Gb each, 16-bit, 533MHz, Single Die Package in flyby topology. + * Reference used NT5CC256M16DP-DI from NANYA + * +@@ -15,10 +15,11 @@ + * timing mode optimized + * Scheduling/QoS options : type = 2 + * address mapping : RBC ++ * Tc > + 85C : N + */ + +-#define DDR_MEM_NAME "DDR3-1066 bin G 2x4Gb 533MHz v1.39" +-#define DDR_MEM_SPEED 533 ++#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 +@@ -62,7 +63,7 @@ + #define DDR_ADDRMAP11 0x00000000 + #define DDR_ODTCFG 0x06000600 + #define DDR_ODTMAP 0x00000001 +-#define DDR_SCHED 0x00001201 ++#define DDR_SCHED 0x00000C01 + #define DDR_SCHED1 0x00000000 + #define DDR_PERFHPR1 0x01000001 + #define DDR_PERFLPR1 0x08000200 +@@ -74,15 +75,15 @@ + #define DDR_PCCFG 0x00000010 + #define DDR_PCFGR_0 0x00010000 + #define DDR_PCFGW_0 0x00000000 +-#define DDR_PCFGQOS0_0 0x02100B03 ++#define DDR_PCFGQOS0_0 0x02100C03 + #define DDR_PCFGQOS1_0 0x00800100 +-#define DDR_PCFGWQOS0_0 0x01100B03 ++#define DDR_PCFGWQOS0_0 0x01100C03 + #define DDR_PCFGWQOS1_0 0x01000200 + #define DDR_PCFGR_1 0x00010000 + #define DDR_PCFGW_1 0x00000000 +-#define DDR_PCFGQOS0_1 0x02100B03 +-#define DDR_PCFGQOS1_1 0x00800000 +-#define DDR_PCFGWQOS0_1 0x01100B03 ++#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 +diff --git a/fdts/stm32mp157-pinctrl.dtsi b/fdts/stm32mp157-pinctrl.dtsi +index 21bd34e..8037e4f 100644 +--- a/fdts/stm32mp157-pinctrl.dtsi ++++ b/fdts/stm32mp157-pinctrl.dtsi +@@ -3,13 +3,14 @@ + * Copyright (C) STMicroelectronics 2017 - All Rights Reserved + * Author: Ludovic Barre for STMicroelectronics. + */ +- + #include ++ + / { + soc { +- pinctrl: pin-controller { ++ pinctrl: pin-controller@50002000 { + #address-cells = <1>; + #size-cells = <1>; ++ compatible = "st,stm32mp157-pinctrl"; + ranges = <0 0x50002000 0xa400>; + pins-are-numbered; + +@@ -134,54 +135,76 @@ + status = "disabled"; + }; + +- uart4_pins_a: uart4@0 { ++ qspi_bk1_pins_a: qspi-bk1-0 { + pins1 { +- pinmux = ; /* UART4_TX */ ++ pinmux = , /* QSPI_BK1_IO0 */ ++ , /* QSPI_BK1_IO1 */ ++ , /* QSPI_BK1_IO2 */ ++ ; /* QSPI_BK1_IO3 */ + bias-disable; + drive-push-pull; +- slew-rate = <0>; ++ slew-rate = <1>; + }; + pins2 { +- pinmux = ; /* UART4_RX */ +- bias-disable; ++ pinmux = ; /* QSPI_BK1_NCS */ ++ bias-pull-up; ++ drive-push-pull; ++ slew-rate = <1>; + }; + }; + +- usart3_pins_a: usart3@0 { ++ qspi_bk2_pins_a: qspi-bk2-0 { + pins1 { +- pinmux = , /* USART3_TX */ +- ; /* USART3_RTS */ ++ pinmux = , /* QSPI_BK2_IO0 */ ++ , /* QSPI_BK2_IO1 */ ++ , /* QSPI_BK2_IO2 */ ++ ; /* QSPI_BK2_IO3 */ + bias-disable; + drive-push-pull; +- slew-rate = <0>; ++ slew-rate = <1>; + }; + pins2 { +- pinmux = , /* USART3_RX */ +- ; /* USART3_CTS_NSS */ +- bias-disable; ++ pinmux = ; /* QSPI_BK2_NCS */ ++ bias-pull-up; ++ drive-push-pull; ++ slew-rate = <1>; + }; + }; + +- sdmmc1_b4_pins_a: sdmmc1-b4@0 { ++ 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_CK */ + ; /* SDMMC1_CMD */ +- slew-rate = <3>; ++ 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 { ++ sdmmc1_dir_pins_a: sdmmc1-dir-0 { + pins1 { + pinmux = , /* SDMMC1_D0DIR */ + , /* SDMMC1_D123DIR */ + ; /* SDMMC1_CDIR */ +- slew-rate = <3>; ++ slew-rate = <1>; + drive-push-pull; + bias-pull-up; + }; +@@ -191,36 +214,113 @@ + }; + }; + +- sdmmc2_b4_pins_a: sdmmc2-b4@0 { +- pins { ++ 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_CK */ + ; /* SDMMC2_CMD */ +- slew-rate = <3>; ++ 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 { ++ sdmmc2_d47_pins_a: sdmmc2-d47-0 { + pins { + pinmux = , /* SDMMC2_D4 */ + , /* SDMMC2_D5 */ + , /* SDMMC2_D6 */ + ; /* SDMMC2_D7 */ +- slew-rate = <3>; ++ 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 { ++ pinctrl_z: pin-controller-z@54004000 { + #address-cells = <1>; + #size-cells = <1>; ++ compatible = "st,stm32mp157-z-pinctrl"; + ranges = <0 0x54004000 0x400>; + pins-are-numbered; + +@@ -236,7 +336,7 @@ + status = "disabled"; + }; + +- i2c4_pins_a: i2c4@0 { ++ i2c4_pins_a: i2c4-0 { + pins { + pinmux = , /* I2C4_SCL */ + ; /* I2C4_SDA */ +diff --git a/fdts/stm32mp157a-dk1.dts b/fdts/stm32mp157a-dk1.dts +new file mode 100644 +index 0000000..fadb442 +--- /dev/null ++++ b/fdts/stm32mp157a-dk1.dts +@@ -0,0 +1,464 @@ ++// 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 { ++ 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 init */ ++&rcc { ++ secure-status = "okay"; ++ st,hsi-cal; ++ st,csi-cal; ++ st,cal-sec = <60>; ++ st,clksrc = < ++ CLK_MPU_PLL1P ++ CLK_AXI_PLL2P ++ CLK_MCU_PLL3P ++ CLK_PLL12_HSE ++ CLK_PLL3_HSE ++ CLK_PLL4_HSE ++ CLK_RTC_LSE ++ CLK_MCO1_DISABLED ++ CLK_MCO2_DISABLED ++ >; ++ ++ st,clkdiv = < ++ 1 /*MPU*/ ++ 0 /*AXI*/ ++ 0 /*MCU*/ ++ 1 /*APB1*/ ++ 1 /*APB2*/ ++ 1 /*APB3*/ ++ 1 /*APB4*/ ++ 2 /*APB5*/ ++ 23 /*RTC*/ ++ 0 /*MCO1*/ ++ 0 /*MCO2*/ ++ >; ++ ++ st,pkcs = < ++ CLK_CKPER_HSE ++ CLK_FMC_ACLK ++ CLK_QSPI_ACLK ++ CLK_ETH_DISABLED ++ CLK_SDMMC12_PLL4P ++ CLK_DSI_DSIPLL ++ CLK_STGEN_HSE ++ CLK_USBPHY_HSE ++ CLK_SPI2S1_PLL3Q ++ CLK_SPI2S23_PLL3Q ++ CLK_SPI45_HSI ++ CLK_SPI6_HSI ++ CLK_I2C46_HSI ++ CLK_SDMMC3_PLL4P ++ CLK_USBO_USBPHY ++ CLK_ADC_CKPER ++ CLK_CEC_LSE ++ CLK_I2C12_HSI ++ CLK_I2C35_HSI ++ CLK_UART1_HSI ++ CLK_UART24_HSI ++ CLK_UART35_HSI ++ CLK_UART6_HSI ++ CLK_UART78_HSI ++ CLK_SPDIF_PLL4P ++ CLK_FDCAN_PLL4Q ++ CLK_SAI1_PLL3Q ++ CLK_SAI2_PLL3Q ++ CLK_SAI3_PLL3Q ++ CLK_SAI4_PLL3Q ++ CLK_RNG1_LSI ++ CLK_RNG2_LSI ++ CLK_LPTIM1_PCLK1 ++ CLK_LPTIM23_PCLK3 ++ CLK_LPTIM45_LSE ++ >; ++ ++ /* VCO = 1300.0 MHz => P = 650 (CPU) */ ++ pll1: st,pll@0 { ++ cfg = < 2 80 0 0 0 PQR(1,0,0) >; ++ frac = < 0x800 >; ++ }; ++ ++ /* VCO = 1066.0 MHz => P = 266 (AXI), Q = 533 (GPU), R = 533 (DDR) */ ++ pll2: st,pll@1 { ++ cfg = < 2 65 1 0 0 PQR(1,1,1) >; ++ frac = < 0x1400 >; ++ }; ++ ++ /* VCO = 417.8 MHz => P = 209, Q = 24, R = 11 */ ++ pll3: st,pll@2 { ++ cfg = < 1 33 1 16 36 PQR(1,1,1) >; ++ frac = < 0x1a04 >; ++ }; ++ ++ /* VCO = 594.0 MHz => P = 99, Q = 74, R = 74 */ ++ pll4: st,pll@3 { ++ cfg = < 3 98 5 7 7 PQR(1,1,1) >; ++ }; ++}; ++ ++/* 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/fdts/stm32mp157c-dk2.dts b/fdts/stm32mp157c-dk2.dts +new file mode 100644 +index 0000000..fdcf4c8 +--- /dev/null ++++ b/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/fdts/stm32mp157c-ed1.dts b/fdts/stm32mp157c-ed1.dts +index e3dabe8..0daf4be 100644 +--- a/fdts/stm32mp157c-ed1.dts ++++ b/fdts/stm32mp157c-ed1.dts +@@ -1,24 +1,30 @@ + // SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) + /* +- * Copyright (C) STMicroelectronics 2017 - All Rights Reserved ++ * Copyright (C) STMicroelectronics 2017-2019 - All Rights Reserved + * Author: Ludovic Barre for STMicroelectronics. + */ +- + /dts-v1/; + + #include "stm32mp157c.dtsi" + #include "stm32mp157caa-pinctrl.dtsi" + + / { +- model = "STMicroelectronics STM32MP157C-ED1 pmic eval daughter"; ++ model = "STMicroelectronics STM32MP157C eval daughter"; + compatible = "st,stm32mp157c-ed1", "st,stm32mp157"; + + chosen { +- bootargs = "earlyprintk console=ttyS3,115200 root=/dev/ram"; +- stdout-path = "serial3:115200n8"; ++ stdout-path = "serial0:115200n8"; ++ }; ++ ++ aliases { ++ serial0 = &uart4; + }; + }; + ++&clk_hse { ++ st,digbypass; ++}; ++ + &i2c4 { + pinctrl-names = "default"; + pinctrl-0 = <&i2c4_pins_a>; +@@ -26,37 +32,88 @@ + i2c-scl-falling-time-ns = <20>; + status = "okay"; + +- pmic: stpmu1@33 { +- compatible = "st,stpmu1"; ++ 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 = <0x30>; ++ st,main-control-register = <0x04>; ++ st,vin-control-register = <0xc0>; ++ st,usb-control-register = <0x20>; + + regulators { +- compatible = "st,stpmu1-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-boot-on; ++ 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; +- regulator-initial-mode = <8>; +- +- regulator-state-standby { +- regulator-suspend-microvolt = <3300000>; +- regulator-unchanged-in-suspend; +- regulator-mode = <8>; +- }; +- regulator-state-mem { +- regulator-off-in-suspend; +- }; +- regulator-state-disk { +- regulator-off-in-suspend; +- }; ++ }; ++ ++ vdd_usb: ldo4 { ++ regulator-name = "vdd_usb"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; + }; + + vdd_sd: ldo5 { +@@ -64,40 +121,49 @@ + regulator-min-microvolt = <2900000>; + regulator-max-microvolt = <2900000>; + regulator-boot-on; ++ }; + +- regulator-state-standby { +- regulator-suspend-microvolt = <2900000>; +- regulator-unchanged-in-suspend; +- }; +- regulator-state-mem { +- regulator-off-in-suspend; +- }; +- regulator-state-disk { +- regulator-off-in-suspend; +- }; ++ 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 { +- instance = <2>; + timeout-sec = <32>; + status = "okay"; + }; + ++&pwr { ++ pwr-supply = <&vdd>; ++}; ++ + &rng1 { + status = "okay"; + }; + ++&rtc { ++ status = "okay"; ++}; ++ + &sdmmc1 { + pinctrl-names = "default"; + pinctrl-0 = <&sdmmc1_b4_pins_a &sdmmc1_dir_pins_a>; + broken-cd; +- st,dirpol; +- st,negedge; +- st,pin-ckin; ++ 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; +@@ -112,22 +178,25 @@ + non-removable; + no-sd; + no-sdio; +- st,dirpol; +- st,negedge; ++ 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>; +- resets = <&rcc UART4_R>; + status = "okay"; + }; + + /* ATF Specific */ + #include ++#include + #include "stm32mp15-ddr3-2x4Gb-1066-binG.dtsi" ++#include "stm32mp157c-security.dtsi" + + / { + aliases { +@@ -145,21 +214,18 @@ + gpio25 = &gpioz; + i2c3 = &i2c4; + }; +- +- soc { +- stgen: stgen@5C008000 { +- compatible = "st,stm32-stgen"; +- reg = <0x5C008000 0x1000>; +- status = "okay"; +- }; +- }; + }; + + /* CLOCK init */ + &rcc { ++ secure-status = "okay"; ++ st,hsi-cal; ++ st,csi-cal; ++ st,cal-sec = <60>; + st,clksrc = < + CLK_MPU_PLL1P + CLK_AXI_PLL2P ++ CLK_MCU_PLL3P + CLK_PLL12_HSE + CLK_PLL3_HSE + CLK_PLL4_HSE +@@ -171,6 +237,7 @@ + st,clkdiv = < + 1 /*MPU*/ + 0 /*AXI*/ ++ 0 /*MCU*/ + 1 /*APB1*/ + 1 /*APB2*/ + 1 /*APB3*/ +@@ -186,7 +253,7 @@ + CLK_FMC_ACLK + CLK_QSPI_ACLK + CLK_ETH_DISABLED +- CLK_SDMMC12_PLL3R ++ CLK_SDMMC12_PLL4P + CLK_DSI_DSIPLL + CLK_STGEN_HSE + CLK_USBPHY_HSE +@@ -195,7 +262,7 @@ + CLK_SPI45_HSI + CLK_SPI6_HSI + CLK_I2C46_HSI +- CLK_SDMMC3_PLL3R ++ CLK_SDMMC3_PLL4P + CLK_USBO_USBPHY + CLK_ADC_CKPER + CLK_CEC_LSE +@@ -206,17 +273,17 @@ + CLK_UART35_HSI + CLK_UART6_HSI + CLK_UART78_HSI +- CLK_SPDIF_PLL3Q ++ CLK_SPDIF_PLL4P + CLK_FDCAN_PLL4Q + CLK_SAI1_PLL3Q + CLK_SAI2_PLL3Q + CLK_SAI3_PLL3Q + CLK_SAI4_PLL3Q +- CLK_RNG1_CSI +- CLK_RNG2_CSI ++ CLK_RNG1_LSI ++ CLK_RNG2_LSI + CLK_LPTIM1_PCLK1 + CLK_LPTIM23_PCLK3 +- CLK_LPTIM45_PCLK3 ++ CLK_LPTIM45_LSE + >; + + /* VCO = 1300.0 MHz => P = 650 (CPU) */ +@@ -231,16 +298,167 @@ + frac = < 0x1400 >; + }; + +- /* VCO = 786.4 MHz => P = 197, Q = 49, R = 98 */ ++ /* VCO = 417.8 MHz => P = 209, Q = 24, R = 11 */ + pll3: st,pll@2 { +- cfg = < 2 97 3 15 7 PQR(1,1,1) >; +- frac = < 0x9ba >; ++ cfg = < 1 33 1 16 36 PQR(1,1,1) >; ++ frac = < 0x1a04 >; + }; + +- /* VCO = 508.0 MHz => P = 56, Q = 56, R = 56 */ ++ /* VCO = 594.0 MHz => P = 99, Q = 74, R = 74 */ + pll4: st,pll@3 { +- cfg = < 5 126 8 8 8 PQR(1,1,1) >; ++ cfg = < 3 98 5 7 7 PQR(1,1,1) >; + }; + }; + +-/delete-node/ &clk_csi; ++/* 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/fdts/stm32mp157c-ev1.dts b/fdts/stm32mp157c-ev1.dts +index 98a9d35..cfde8ed 100644 +--- a/fdts/stm32mp157c-ev1.dts ++++ b/fdts/stm32mp157c-ev1.dts +@@ -3,23 +3,65 @@ + * Copyright (C) STMicroelectronics 2017 - All Rights Reserved + * Author: Ludovic Barre for STMicroelectronics. + */ +- + /dts-v1/; ++ + #include "stm32mp157c-ed1.dts" + + / { +- model = "STMicroelectronics STM32MP157C-EV1 pmic eval daughter on eval mother"; ++ model = "STMicroelectronics STM32MP157C eval daughter on eval mother"; + compatible = "st,stm32mp157c-ev1", "st,stm32mp157c-ed1", "st,stm32mp157"; + + chosen { +- bootargs = "earlyprintk console=ttyS3,115200 root=/dev/ram"; +- stdout-path = "serial3:115200n8"; ++ 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>; +- resets = <&rcc USART3_R>; + status = "disabled"; + }; +diff --git a/fdts/stm32mp157c-security.dtsi b/fdts/stm32mp157c-security.dtsi +new file mode 100644 +index 0000000..8d45a33 +--- /dev/null ++++ b/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/fdts/stm32mp157c.dtsi b/fdts/stm32mp157c.dtsi +index 8b13c0e..06c2cf1 100644 +--- a/fdts/stm32mp157c.dtsi ++++ b/fdts/stm32mp157c.dtsi +@@ -1,9 +1,9 @@ + // SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) + /* +- * Copyright (C) STMicroelectronics 2017 - All Rights Reserved ++ * Copyright (C) STMicroelectronics 2017-2019 - All Rights Reserved + * Author: Ludovic Barre for STMicroelectronics. + */ +- ++#include + #include + #include + +@@ -11,15 +11,12 @@ + #address-cells = <1>; + #size-cells = <1>; + +- aliases { +- serial0 = &usart1; +- serial1 = &usart2; +- serial2 = &usart3; +- serial3 = &uart4; +- serial4 = &uart5; +- serial5 = &usart6; +- serial6 = &uart7; +- serial7 = &uart8; ++ intc: interrupt-controller@a0021000 { ++ compatible = "arm,cortex-a7-gic"; ++ #interrupt-cells = <3>; ++ interrupt-controller; ++ reg = <0xa0021000 0x1000>, ++ <0xa0022000 0x2000>; + }; + + clocks { +@@ -56,7 +53,7 @@ + clk_i2s_ckin: i2s_ckin { + #clock-cells = <0>; + compatible = "fixed-clock"; +- clock-frequency = <64000000>; ++ clock-frequency = <0>; + }; + + clk_dsi_phy: ck_dsi_phy { +@@ -64,31 +61,38 @@ + compatible = "fixed-clock"; + clock-frequency = <0>; + }; +- +- clk_usbo_48m: ck_usbo_48m { +- #clock-cells = <0>; +- compatible = "fixed-clock"; +- clock-frequency = <48000000>; +- }; + }; + + 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-usart"; ++ compatible = "st,stm32h7-uart"; + reg = <0x4000e000 0x400>; + clocks = <&rcc USART2_K>; ++ resets = <&rcc USART2_R>; + status = "disabled"; + }; + + usart3: serial@4000f000 { +- compatible = "st,stm32h7-usart"; ++ compatible = "st,stm32h7-uart"; + reg = <0x4000f000 0x400>; + clocks = <&rcc USART3_K>; ++ resets = <&rcc USART3_R>; + status = "disabled"; + }; + +@@ -96,6 +100,7 @@ + compatible = "st,stm32h7-uart"; + reg = <0x40010000 0x400>; + clocks = <&rcc UART4_K>; ++ resets = <&rcc UART4_R>; + status = "disabled"; + }; + +@@ -103,6 +108,7 @@ + compatible = "st,stm32h7-uart"; + reg = <0x40011000 0x400>; + clocks = <&rcc UART5_K>; ++ resets = <&rcc UART5_R>; + status = "disabled"; + }; + +@@ -111,6 +117,7 @@ + compatible = "st,stm32h7-uart"; + reg = <0x40018000 0x400>; + clocks = <&rcc UART7_K>; ++ resets = <&rcc UART7_R>; + status = "disabled"; + }; + +@@ -118,21 +125,34 @@ + compatible = "st,stm32h7-uart"; + reg = <0x40019000 0x400>; + clocks = <&rcc UART8_K>; ++ resets = <&rcc UART8_R>; + status = "disabled"; + }; + + usart6: serial@44003000 { +- compatible = "st,stm32h7-usart"; ++ 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 = "st,stm32-sdmmc2"; ++ compatible = "arm,pl18x", "arm,primecell"; ++ arm,primecell-periphid = <0x00253180>; + reg = <0x48004000 0x400>, <0x48005000 0x400>; +- reg-names = "sdmmc", "delay"; + clocks = <&rcc SDMMC3_K>; ++ clock-names = "apb_pclk"; + resets = <&rcc SDMMC3_R>; + cap-sd-highspeed; + cap-mmc-highspeed; +@@ -140,18 +160,69 @@ + 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 = "syscon", "st,stm32mp1-rcc"; ++ compatible = "st,stm32mp1-rcc", "syscon"; ++ reg = <0x50000000 0x1000>; + #clock-cells = <1>; + #reset-cells = <1>; +- reg = <0x50000000 0x1000>; ++ interrupts = ; ++ }; ++ ++ pwr: pwr@50001000 { ++ compatible = "st,stm32mp1-pwr", "syscon", "simple-mfd"; ++ reg = <0x50001000 0x400>; + }; + +- rcc_reboot: rcc-reboot@50000000 { +- compatible = "syscon-reboot"; +- regmap = <&rcc>; +- offset = <0x404>; +- mask = <0x1>; ++ 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 { +@@ -162,13 +233,15 @@ + status = "disabled"; + }; + +- fmc_nand: fmc_nand@58002000 { +- compatible = "st,stm32mp1-fmc"; ++ fmc: nand-controller@58002000 { ++ compatible = "st,stm32mp15-fmc2"; + reg = <0x58002000 0x1000>, +- <0x80000000 0x40000>, +- <0x81000000 0x40000>, +- <0x88000000 0x40000>, +- <0x89000000 0x40000>; ++ <0x80000000 0x1000>, ++ <0x88010000 0x1000>, ++ <0x88020000 0x1000>, ++ <0x81000000 0x1000>, ++ <0x89010000 0x1000>, ++ <0x89020000 0x1000>; + clocks = <&rcc FMC_K>; + resets = <&rcc FMC_R>; + status = "disabled"; +@@ -177,15 +250,18 @@ + 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 = "st,stm32-sdmmc2"; ++ compatible = "arm,pl18x", "arm,primecell"; ++ arm,primecell-periphid = <0x00253180>; + reg = <0x58005000 0x1000>, <0x58006000 0x1000>; +- reg-names = "sdmmc", "delay"; + clocks = <&rcc SDMMC1_K>; ++ clock-names = "apb_pclk"; + resets = <&rcc SDMMC1_R>; + cap-sd-highspeed; + cap-mmc-highspeed; +@@ -194,10 +270,11 @@ + }; + + sdmmc2: sdmmc@58007000 { +- compatible = "st,stm32-sdmmc2"; ++ compatible = "arm,pl18x", "arm,primecell"; ++ arm,primecell-periphid = <0x00253180>; + reg = <0x58007000 0x1000>, <0x58008000 0x1000>; +- reg-names = "sdmmc", "delay"; + clocks = <&rcc SDMMC2_K>; ++ clock-names = "apb_pclk"; + resets = <&rcc SDMMC2_R>; + cap-sd-highspeed; + cap-mmc-highspeed; +@@ -205,7 +282,7 @@ + status = "disabled"; + }; + +- iwdg2: iwdg@5a002000 { ++ iwdg2: watchdog@5a002000 { + compatible = "st,stm32mp1-iwdg"; + reg = <0x5a002000 0x400>; + clocks = <&rcc IWDG2>, <&rcc CK_LSI>; +@@ -214,15 +291,34 @@ + }; + + usart1: serial@5c000000 { +- compatible = "st,stm32h7-usart"; ++ 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>; +@@ -235,6 +331,41 @@ + 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/fdts/stm32mp157caa-pinctrl.dtsi b/fdts/stm32mp157caa-pinctrl.dtsi +index 774561a..9b9cd08 100644 +--- a/fdts/stm32mp157caa-pinctrl.dtsi ++++ b/fdts/stm32mp157caa-pinctrl.dtsi +@@ -7,8 +7,8 @@ + #include "stm32mp157-pinctrl.dtsi" + / { + soc { +- pinctrl: pin-controller { +- compatible = "st,stm32mp157caa-pinctrl"; ++ pinctrl: pin-controller@50002000 { ++ st,package = ; + + gpioa: gpio@50002000 { + status = "okay"; +@@ -77,8 +77,8 @@ + }; + }; + +- pinctrl_z: pin-controller-z { +- compatible = "st,stm32mp157caa-z-pinctrl"; ++ pinctrl_z: pin-controller-z@54004000 { ++ st,package = ; + + gpioz: gpio@54004000 { + status = "okay"; +diff --git a/fdts/stm32mp157cab-pinctrl.dtsi b/fdts/stm32mp157cab-pinctrl.dtsi +new file mode 100644 +index 0000000..c570cf9 +--- /dev/null ++++ b/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/fdts/stm32mp157cac-pinctrl.dtsi b/fdts/stm32mp157cac-pinctrl.dtsi +new file mode 100644 +index 0000000..777f991 +--- /dev/null ++++ b/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/fdts/stm32mp157cad-pinctrl.dtsi b/fdts/stm32mp157cad-pinctrl.dtsi +new file mode 100644 +index 0000000..c4c303a +--- /dev/null ++++ b/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/include/common/aarch32/console_macros.S b/include/common/aarch32/console_macros.S +new file mode 100644 +index 0000000..7c30688 +--- /dev/null ++++ b/include/common/aarch32/console_macros.S +@@ -0,0 +1,84 @@ ++/* ++ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. ++ * ++ * SPDX-License-Identifier: BSD-3-Clause ++ */ ++#ifndef __CONSOLE_MACROS_S__ ++#define __CONSOLE_MACROS_S__ ++ ++#include ++ ++/* ++ * This macro encapsulates the common setup that has to be done at the end of ++ * a console driver's register function. It will register all of the driver's ++ * callbacks in the console_t structure and initialize the flags field (by ++ * default consoles are enabled for the "boot" and "crash" states, this can be ++ * changed after registration with the console_set_scope() function). It ends ++ * with a tail call that will include return to the caller. ++ * REQUIRES console_t pointer in x0 and a valid return address in x30. ++ */ ++/* ++ * The USE_FINISH_CONSOLE_REG_2 guard is introduced to allow selection between ++ * the 2 variants of the finish_console_register macro and will be removed ++ * once the deprecated variant is removed. ++ */ ++#ifndef USE_FINISH_CONSOLE_REG_2 ++#if !ERROR_DEPRECATED ++ /* This version of the macro is deprecated. Use the new version */ ++ .macro finish_console_register _driver ++ /* ++ * Add these weak definitions so we will automatically write a 0 if the ++ * function doesn't exist. I'd rather use .ifdef but that only works if ++ * the function was defined (not just declared .global) above this point ++ * in the file, which we can't guarantee. ++ */ ++ .weak console_\_driver\()_putc ++ .weak console_\_driver\()_getc ++ .weak console_\_driver\()_flush ++ ++ /* Don't use adrp on weak funcs! See GNU ld bugzilla issue 22589. */ ++ ldr r1, =console_\_driver\()_putc ++ str r1, [r0, #CONSOLE_T_PUTC] ++ ldr r1, =console_\_driver\()_getc ++ str r1, [r0, #CONSOLE_T_GETC] ++ ldr r1, =console_\_driver\()_flush ++ str r1, [r0, #CONSOLE_T_FLUSH] ++ mov r1, #(CONSOLE_FLAG_BOOT | CONSOLE_FLAG_CRASH) ++ str r1, [r0, #CONSOLE_T_FLAGS] ++ b console_register ++ .endm ++#endif /* ERROR_DEPRECATED */ ++#else /* USE_FINISH_CONSOLE_REG_2 */ ++ /* The new version of the macro not using weak references */ ++ .macro finish_console_register _driver, putc=0, getc=0, flush=0 ++ /* ++ * If any of the callback is not specified or set as 0, then the ++ * corresponding callback entry in console_t is set to 0. ++ */ ++ .ifne \putc ++ ldr r1, =console_\_driver\()_putc ++ .else ++ mov r1, #0 ++ .endif ++ str r1, [r0, #CONSOLE_T_PUTC] ++ ++ .ifne \getc ++ ldr r1, =console_\_driver\()_getc ++ .else ++ mov r1, #0 ++ .endif ++ str r1, [r0, #CONSOLE_T_GETC] ++ ++ .ifne \flush ++ ldr r1, =console_\_driver\()_flush ++ .else ++ mov r1, #0 ++ .endif ++ str r1, [r0, #CONSOLE_T_FLUSH] ++ ++ mov r1, #(CONSOLE_FLAG_BOOT | CONSOLE_FLAG_CRASH) ++ str r1, [r0, #CONSOLE_T_FLAGS] ++ b console_register ++ .endm ++#endif /* USE_FINISH_CONSOLE_REG_2 */ ++#endif /* __CONSOLE_MACROS_S__ */ +diff --git a/include/common/aarch64/console_macros.S b/include/common/aarch64/console_macros.S +index 0ebea2c..b285ecc 100644 +--- a/include/common/aarch64/console_macros.S ++++ b/include/common/aarch64/console_macros.S +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. ++ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +@@ -17,6 +17,14 @@ + * with a tail call that will include return to the caller. + * REQUIRES console_t pointer in x0 and a valid return address in x30. + */ ++/* ++ * The USE_FINISH_CONSOLE_REG_2 guard is introduced to allow selection between ++ * the 2 variants of the finish_console_register macro and will be removed ++ * once the deprecated variant is removed. ++ */ ++#ifndef USE_FINISH_CONSOLE_REG_2 ++#if !ERROR_DEPRECATED ++ /* This version of the macro is deprecated. Use the new version */ + .macro finish_console_register _driver + /* + * Add these weak definitions so we will automatically write a 0 if the +@@ -39,5 +47,41 @@ + str x1, [x0, #CONSOLE_T_FLAGS] + b console_register + .endm ++#endif /* ERROR_DEPRECATED */ ++#else /* USE_FINISH_CONSOLE_REG_2 */ ++ /* The new version of the macro not using weak references */ ++ .macro finish_console_register _driver, putc=0, getc=0, flush=0 ++ /* ++ * If any of the callback is not specified or set as 0, then the ++ * corresponding callback entry in console_t is set to 0. ++ */ ++ .ifne \putc ++ adrp x1, console_\_driver\()_putc ++ add x1, x1, :lo12:console_\_driver\()_putc ++ str x1, [x0, #CONSOLE_T_PUTC] ++ .else ++ str xzr, [x0, #CONSOLE_T_PUTC] ++ .endif ++ ++ .ifne \getc ++ adrp x1, console_\_driver\()_getc ++ add x1, x1, :lo12:console_\_driver\()_getc ++ str x1, [x0, #CONSOLE_T_GETC] ++ .else ++ str xzr, [x0, #CONSOLE_T_GETC] ++ .endif + ++ .ifne \flush ++ adrp x1, console_\_driver\()_flush ++ add x1, x1, :lo12:console_\_driver\()_flush ++ str x1, [x0, #CONSOLE_T_FLUSH] ++ .else ++ str xzr, [x0, #CONSOLE_T_FLUSH] ++ .endif ++ ++ mov x1, #(CONSOLE_FLAG_BOOT | CONSOLE_FLAG_CRASH) ++ str x1, [x0, #CONSOLE_T_FLAGS] ++ b console_register ++ .endm ++#endif /* USE_FINISH_CONSOLE_REG_2 */ + #endif /* __CONSOLE_MACROS_S__ */ +diff --git a/include/common/tbbr/tbbr_img_def.h b/include/common/tbbr/tbbr_img_def.h +index a97914d..96bfb53 100644 +--- a/include/common/tbbr/tbbr_img_def.h ++++ b/include/common/tbbr/tbbr_img_def.h +@@ -77,7 +77,13 @@ + /* NT_FW_CONFIG */ + #define NT_FW_CONFIG_ID U(27) + ++/* GPT Partition */ ++#define GPT_IMAGE_ID U(28) ++ ++/* Binary with STM32 header */ ++#define STM32_IMAGE_ID U(29) ++ + /* Define size of the array */ +-#define MAX_NUMBER_IDS U(28) ++#define MAX_NUMBER_IDS U(30) + + #endif /* __TBBR_IMG_DEF_H__ */ +diff --git a/include/drivers/arm/tzc400.h b/include/drivers/arm/tzc400.h +index 095099c..a0c7542 100644 +--- a/include/drivers/arm/tzc400.h ++++ b/include/drivers/arm/tzc400.h +@@ -32,6 +32,7 @@ + #define BUILD_CONFIG_NR_SHIFT 0 + #define BUILD_CONFIG_NR_MASK 0x1f + ++#define FILTER_OFFSET 0x10 + /* + * Number of gate keepers is implementation defined. But we know the max for + * this device is 4. Get implementation details from BUILD_CONFIG. +@@ -112,6 +113,9 @@ void tzc400_configure_region(unsigned int filters, + void tzc400_set_action(tzc_action_t action); + void tzc400_enable_filters(void); + void tzc400_disable_filters(void); ++void tzc400_clear_all_interrupts(void); ++int tzc400_is_pending_interrupt(void); ++void tzc400_it_handler(void); + + static inline void tzc_init(uintptr_t base) + { +diff --git a/include/drivers/io/io_driver.h b/include/drivers/io/io_driver.h +index 8306407..3d2c3ab 100644 +--- a/include/drivers/io/io_driver.h ++++ b/include/drivers/io/io_driver.h +@@ -39,7 +39,7 @@ typedef struct io_dev_funcs { + io_type_t (*type)(void); + int (*open)(io_dev_info_t *dev_info, const uintptr_t spec, + io_entity_t *entity); +- int (*seek)(io_entity_t *entity, int mode, ssize_t offset); ++ int (*seek)(io_entity_t *entity, int mode, signed long long offset); + int (*size)(io_entity_t *entity, size_t *length); + int (*read)(io_entity_t *entity, uintptr_t buffer, size_t length, + size_t *length_read); +diff --git a/include/drivers/io/io_storage.h b/include/drivers/io/io_storage.h +index 485ed8c..2bf7721 100644 +--- a/include/drivers/io/io_storage.h ++++ b/include/drivers/io/io_storage.h +@@ -22,6 +22,12 @@ typedef enum { + IO_TYPE_DUMMY, + IO_TYPE_FIRMWARE_IMAGE_PACKAGE, + IO_TYPE_BLOCK, ++ IO_TYPE_MMC, ++ IO_TYPE_STM32IMAGE, ++ IO_TYPE_UART, ++ IO_TYPE_QSPI, ++ IO_TYPE_NAND, ++ IO_TYPE_USB, + IO_TYPE_MAX + } io_type_t; + +@@ -86,7 +92,7 @@ int io_dev_close(uintptr_t dev_handle); + /* Synchronous operations */ + int io_open(uintptr_t dev_handle, const uintptr_t spec, uintptr_t *handle); + +-int io_seek(uintptr_t handle, io_seek_mode_t mode, ssize_t offset); ++int io_seek(uintptr_t handle, io_seek_mode_t mode, signed long long offset); + + int io_size(uintptr_t handle, size_t *length); + +diff --git a/include/drivers/st/bsec.h b/include/drivers/st/bsec.h +new file mode 100644 +index 0000000..b21bde8 +--- /dev/null ++++ b/include/drivers/st/bsec.h +@@ -0,0 +1,205 @@ ++/* ++ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. ++ * ++ * SPDX-License-Identifier: BSD-3-Clause ++ */ ++ ++#ifndef __BSEC_H__ ++#define __BSEC_H__ ++ ++#include ++#include ++#include ++ ++/* ++ * IP configuration ++ */ ++#define BSEC_OTP_MASK GENMASK(4, 0) ++#define BSEC_OTP_BANK_SHIFT 5 ++#define BSEC_TIMEOUT_VALUE 0xFFFF ++ ++#define ADDR_LOWER_OTP_PERLOCK_SHIFT 0x03 ++#define DATA_LOWER_OTP_PERLOCK_BIT 0x03U /* 2 significants bits are used */ ++#define DATA_LOWER_OTP_PERLOCK_MASK GENMASK(2, 0) ++#define ADDR_UPPER_OTP_PERLOCK_SHIFT 0x04 ++#define DATA_UPPER_OTP_PERLOCK_BIT 0x01U /* 1 significants bits are used */ ++#define DATA_UPPER_OTP_PERLOCK_MASK GENMASK(3, 0) ++ ++/* ++ * Return status ++ */ ++#define BSEC_OK 0U ++#define BSEC_ERROR 0xFFFFFFFFU ++#define BSEC_DISTURBED 0xFFFFFFFEU ++#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_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 /* Safmem permanent lock */ ++#define BSEC_WRLOCK1_OFF 0x050U ++#define BSEC_WRLOCK2_OFF 0x054U ++#define BSEC_SPLOCK_OFF 0x064U /* Program safmem sticky lock */ ++#define BSEC_SPLOCK1_OFF 0x068U ++#define BSEC_SPLOCK2_OFF 0x06CU ++#define BSEC_SWLOCK_OFF 0x07CU /* Write in OTP sticky lock */ ++#define BSEC_SWLOCK1_OFF 0x080U ++#define BSEC_SWLOCK2_OFF 0x084U ++#define BSEC_SRLOCK_OFF 0x094U /* Shadowing sticky lock */ ++#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(2, 1) ++#define BSEC_CONF_FRQ_SHIFT 1 ++#define BSEC_CONF_PRG_WIDTH_MASK GENMASK(6, 3) ++#define BSEC_CONF_PRG_WIDTH_SHIFT 3 ++#define BSEC_CONF_TREAD_MASK GENMASK(8, 7) ++#define BSEC_CONF_TREAD_SHIFT 7 ++ ++/* ++ * BSEC_CONTROL Register ++ */ ++#define BSEC_READ 0x000U ++#define BSEC_WRITE 0x100U ++#define BSEC_LOCK 0x200U ++ ++/* ++ * BSEC_OTP_LOCK register ++ */ ++#define UPPER_OTP_LOCK_MASK BIT(0) ++#define UPPER_OTP_LOCK_SHIFT 0 ++#define DENREG_LOCK_MASK BIT(2) ++#define DENREG_LOCK_SHIFT 2 ++#define GPLOCK_LOCK_MASK BIT(4) ++#define GPLOCK_LOCK_SHIFT 4 ++ ++/* ++ * BSEC_OTP_STATUS Register ++ */ ++#define BSEC_MODE_STATUS_MASK GENMASK(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) ++ ++/* OTP MODE*/ ++#define BSEC_MODE_OPEN1 0x00 ++#define BSEC_MODE_SECURED 0x01 ++#define BSEC_MODE_OPEN2 0x02 ++#define BSEC_MODE_INVALID 0x04 ++ ++/* BSEC_DENABLE Register */ ++#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(10, 0) ++ ++/* BSEC_FENABLE Register */ ++#define BSEC_FEN_ALL_MSK GENMASK(14, 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 ++ ++/* ++ * Device info structure, providing device-specific functions and a means of ++ * adding driver-specific state ++ */ ++struct bsec_config { ++ uint8_t tread; /* SAFMEM Reading current level default 0 */ ++ uint8_t pulse_width; /* SAFMEM Programming pulse width default 1 */ ++ uint8_t freq; /* SAFMEM CLOCK see freq value define ++ * default FREQ_45_67_MHZ ++ */ ++ uint8_t power; /* Power up SAFMEM. 1 power up, 0 power off */ ++ uint8_t prog_lock; /* Programming Sticky lock ++ * 1 programming is locked until next reset ++ */ ++ uint8_t den_lock; /* Debug enable is sticky lock ++ * 1 debug enable is locked until next reset ++ */ ++ uint8_t upper_otp_lock; /* Shadowing of upper OTP is sticky lock ++ * 1 shadowing of upper OTP is locked ++ * until next reset ++ */ ++}; ++ ++uint32_t bsec_probe(void); ++uint32_t bsec_get_base(void); ++ ++uint32_t bsec_set_config(struct bsec_config *cfg); ++uint32_t bsec_get_config(struct bsec_config *cfg); ++ ++uint32_t bsec_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_write_feature_conf(uint32_t val); ++uint32_t bsec_read_feature_conf(uint32_t *val); ++ ++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 /*__BSEC_H__*/ +diff --git a/include/drivers/st/etzpc.h b/include/drivers/st/etzpc.h +new file mode 100644 +index 0000000..c31d996 +--- /dev/null ++++ b/include/drivers/st/etzpc.h +@@ -0,0 +1,32 @@ ++/* ++ * Copyright (c) 2017-2018, STMicroelectronics ++ * ++ * SPDX-License-Identifier: BSD-3-Clause ++ */ ++ ++#ifndef __ETZPC_H__ ++#define __ETZPC_H__ ++ ++/* 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, ++}; ++ ++void etzpc_configure_decprot(uint32_t decprot_id, ++ enum etzpc_decprot_attributes decprot_attr); ++enum etzpc_decprot_attributes etzpc_get_decprot(uint32_t decprot_id); ++void etzpc_lock_decprot(uint32_t decprot_id); ++void etzpc_configure_tzma(uint32_t tzma_id, uint16_t tzma_value); ++uint16_t etzpc_get_tzma(uint32_t tzma_id); ++void etzpc_lock_tzma(uint32_t tzma_id); ++bool etzpc_get_lock_tzma(uint32_t tzma_id); ++uint8_t etzpc_get_num_per_sec(void); ++uint8_t etzpc_get_revision(void); ++uintptr_t etzpc_get_base_address(void); ++int etzpc_init(void); ++ ++#endif /* __ETZPC_H__ */ +diff --git a/include/drivers/st/hash_sec.h b/include/drivers/st/hash_sec.h +new file mode 100644 +index 0000000..a8d8b9b +--- /dev/null ++++ b/include/drivers/st/hash_sec.h +@@ -0,0 +1,113 @@ ++/** ++ ****************************************************************************** ++ * @file hash_sec.h ++ * @author mgentilini - MCD IntroPack team - MPU AP v1 bootROM project ++ * @version V0.1 ++ * @date 22-Sept-2015 ++ * @brief Header file for STM32MP1 HASH driver module. ++ ****************************************************************************** ++ * @attention ++ * ++ *

© COPYRIGHT(c) 2015 STMicroelectronics

++ * ++ * SPDX-License-Identifier: BSD-3-Clause ++ * ++ ****************************************************************************** ++ */ ++ ++/* Define to prevent recursive inclusion -------------------------------------*/ ++#ifndef __HASH_SEC_H ++#define __HASH_SEC_H ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++#include ++#include ++ ++/* Definitions----------------------------------------------------------------*/ ++#define HASH ((HASH_TypeDef *)HASH_BASE) ++#define HASH_DIGEST ((HASH_DIGEST_TypeDef *)(HASH_BASE + 0x310)) ++ ++#define HASH_TIMEOUT_VALUE 0x500000 ++ ++/* ++ * HASH IP uses 512 bits : ie 64 bytes block in order to start computation of ++ * Hash intermediate Digest ++ * The digest intermediate computation starts only after 64 bytes are entered ++ */ ++#define HASH_BLOCK_SIZE_NB_BYTES 64 ++ ++/** ++ * @brief Set the number of valid bits in last word 32 bits written in Data ++ * register ++ * @param SIZE: size in byte of last data written in Data register. ++ * @retval None ++ */ ++ ++#define __HAL_HASH_SET_NBVALIDBITSINLAST32BITSWORD(SIZE) \ ++ do { \ ++ HASH->STR &= ~(HASH_STR_NBW); \ ++ HASH->STR |= 8 * ((SIZE) % 4); \ ++ } while (0) ++ ++/** ++ * @brief HASH Handle Structure definition ++ */ ++typedef struct { ++ HASH_TypeDef *Instance; /*!< HASH Registers base address */ ++ uint32_t State; ++ uint32_t Error; ++ const uint8_t *pHashInBuffPtr; /*!< Pointer to input buffer */ ++ const uint8_t *pHashOutBuffPtr; /*!< Pointer to output buffer */ ++} HASH_HandleTypeDef; ++ ++#define HASH_DIGEST_DONE 0x0 ++#define HASH_TIMEOUT 0x1 ++#define HASH_INIT_DONE 0x2 ++#define HASH_ACCU_DONE 0x3 ++#define HASH_FINISHED 0x4 ++#define HASH_INIT_NOT_DONE 0x5 ++ ++/** @defgroup HASH_Algo_Selection ++ * @{ ++ */ ++#define HASH_AlgoSelection_SHA256 HASH_CR_ALGO /*!< HASH function is SHA256 */ ++ ++/** ++ * @} ++ */ ++ ++/** @defgroup HASH_Data_Type ++ * @{ ++ */ ++#define HASH_DATATYPE_8B HASH_CR_DATATYPE_1 /*!< 8-bit data. All bytes are ++ * swapped ++ */ ++ ++/* Exported functions --------------------------------------------------------*/ ++ ++/* HASH processing using polling *********************************************/ ++Std_ReturnType HASH_SHA256_Init(HASH_HandleTypeDef *hHash); ++ ++Std_ReturnType HASH_SHA256_Start(HASH_HandleTypeDef *hHash, ++ const uint8_t *pInBuffer, ++ uint32_t sizeInBytes, ++ uint8_t *pOutBuffer, uint32_t Timeout); ++ ++Std_ReturnType HASH_SHA256_Accumulate(HASH_HandleTypeDef *hHash, ++ const uint8_t *pInBuffer, ++ uint32_t sizeInBytes); ++ ++Std_ReturnType HASH_SHA256_Finish(HASH_HandleTypeDef *hHash, ++ uint8_t *pOutBuffer, uint32_t Timeout); ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif /* __HASH_SEC_H */ ++ ++/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ ++ +diff --git a/include/drivers/st/io_mmc.h b/include/drivers/st/io_mmc.h +new file mode 100644 +index 0000000..de71e7d +--- /dev/null ++++ b/include/drivers/st/io_mmc.h +@@ -0,0 +1,14 @@ ++/* ++ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. ++ * ++ * SPDX-License-Identifier: BSD-3-Clause ++ */ ++ ++#ifndef IO_MMC_H ++#define IO_MMC_H ++ ++#include ++ ++int register_io_dev_mmc(const io_dev_connector_t **dev_con); ++ ++#endif /* IO_MMC_H */ +diff --git a/include/drivers/st/io_nand.h b/include/drivers/st/io_nand.h +new file mode 100644 +index 0000000..13c8fbf +--- /dev/null ++++ b/include/drivers/st/io_nand.h +@@ -0,0 +1,19 @@ ++/* ++ * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved. ++ * ++ * SPDX-License-Identifier: BSD-3-Clause ++ */ ++ ++#ifndef __IO_NAND_H__ ++#define __IO_NAND_H__ ++ ++#define STM32_NAND_MAX_BLOCK_SIZE 512 ++ ++typedef struct nand_device_info { ++ uint64_t device_size; /* Size of device in bytes */ ++ uint32_t block_size; /* block size in bytes */ ++} nand_device_info_t; ++ ++int register_io_dev_nand(const io_dev_connector_t **dev_con); ++ ++#endif /* __IO_NAND_H__ */ +diff --git a/include/drivers/st/io_programmer.h b/include/drivers/st/io_programmer.h +new file mode 100644 +index 0000000..454aa68 +--- /dev/null ++++ b/include/drivers/st/io_programmer.h +@@ -0,0 +1,51 @@ ++/* ++ * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved. ++ * ++ * SPDX-License-Identifier: BSD-3-Clause ++ */ ++ ++#ifndef __IO_PROGRAMMER_H__ ++#define __IO_PROGRAMMER_H__ ++ ++/* Phase definition */ ++#define PHASE_FLASHLAYOUT 0 ++#define PHASE_FSBL1 1 ++#define PHASE_FSBL2 2 ++#define PHASE_SSBL 3 ++ ++/* Command definition */ ++#define GET_CMD_COMMAND 0x00 ++#define GET_VER_COMMAND 0x01 ++#define GET_ID_COMMAND 0x02 ++#define PHASE_COMMAND 0x03 ++#define START_COMMAND 0x21 ++#define DOWNLOAD_COMMAND 0x31 ++ ++/* Answer defines */ ++#define INIT_BYTE 0x7F ++#define ACK_BYTE 0x79 ++#define NACK_BYTE 0x1F ++#define ABORT 0x5F ++ ++#define PROGRAMMER_TIMEOUT 0xFFFFFFFE ++ ++#define DEVICE_ID_BYTE1 0x05 ++#define DEVICE_ID_BYTE2 0x00 ++ ++/* phase structure */ ++struct phase_struct { ++ uint32_t keep_header; ++ uint32_t current_packet; ++ size_t max_size; ++ uint8_t phase_id; ++}; ++ ++/* current phase struct variable */ ++static struct phase_struct current_phase = { ++ .phase_id = PHASE_FSBL1, ++ .max_size = 0, ++ .keep_header = 0, ++ .current_packet = 0, ++}; ++ ++#endif /* __IO_PROGRAMMER_H__ */ +diff --git a/include/drivers/st/io_programmer_st_usb.h b/include/drivers/st/io_programmer_st_usb.h +new file mode 100644 +index 0000000..f6ad9c7 +--- /dev/null ++++ b/include/drivers/st/io_programmer_st_usb.h +@@ -0,0 +1,20 @@ ++/* ++ * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved. ++ * ++ * SPDX-License-Identifier: BSD-3-Clause ++ */ ++ ++#ifndef __IO_USB_H__ ++#define __IO_USB_H__ ++ ++#define IO_USB_TIMEOUT 0xFFFFF ++/* need to call the USB Handler 4 times after to have ++ * received the detach request ++ */ ++#define DETACH_TIMEOUT 0x100 ++ ++#define USB_DFU_MAX_XFER_SIZE 1024 ++ ++int register_io_dev_usb(const io_dev_connector_t **dev_con); ++ ++#endif /* __IO_USB_H__ */ +diff --git a/include/drivers/st/io_qspi.h b/include/drivers/st/io_qspi.h +new file mode 100644 +index 0000000..fc03faf +--- /dev/null ++++ b/include/drivers/st/io_qspi.h +@@ -0,0 +1,92 @@ ++/* ++ * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved. ++ * ++ * SPDX-License-Identifier: BSD-3-Clause ++ */ ++ ++#ifndef __IO_QSPI_H__ ++#define __IO_QSPI_H__ ++ ++#define QSPI_FMODE_MASK 0x0C000000 ++#define QSPI_FMODE_MEMORY_MAPPED 0x0C000000 ++ ++#define QSPI_NOR_MAX_SIZE 0x10000000 /* 256 MB*/ ++#define QSPI_NOR_LBA_SIZE 0x00000200 /* 512 B*/ ++#define QSPI_NOR_BLK_SIZE 0x00040000 /* 256 KB*/ ++ ++#define QSPI_CR_EN 0x00000001 ++#define QSPI_CR_ABORT 0x00000002 ++#define QSPI_CR_TCEN 0x00000008 ++#define QSPI_CR_SSHIFT 0x00000010 ++#define QSPI_CR_DFM 0x00000040 ++#define QSPI_CR_PRESCALER_SHIFT 24 ++ ++#define QSPI_DCR_CSHT 0x00000100 ++#define QSPI_DCR_FSIZE_MASK 0x001F0000 ++#define QSPI_DCR_FSIZE_SHIFT 16 ++ ++#define QSPI_CCR_INST 0x0000000B ++#define QSPI_CCR_IMODE 0x00000100 ++#define QSPI_CCR_ADMODE 0x00000400 ++#define QSPI_CCR_ADSIZE 0x00002000 ++#define QSPI_CCR_ABMODE 0x00000000 ++#define QSPI_CCR_ABSIZE 0x00000000 ++#define QSPI_CCR_DCYC 0x00200000 ++#define QSPI_CCR_DMODE 0x01000000 ++#define QSPI_CCR_FMODE_MM 0x0C000000 ++#define QSPI_CCR_FMODE 0x04000000 ++#define QSPI_CCR_SIOO 0x00000000 ++#define QSPI_CCR_DDRM 0x00000000 ++#define QSPI_CCR_DHHC 0x00000000 ++ ++#define QSPI_SR_FLEVEL 0x1F00 ++#define QSPI_SR_BUSY 0x0020 ++#define QSPI_SR_TOF 0x0010 ++#define QSPI_SR_SMF 0x0008 ++#define QSPI_SR_FTF 0x0004 ++#define QSPI_SR_TCF 0x0002 ++#define QSPI_SR_TEF 0x0001 ++ ++#define QSPI_FCR_CTOF 0x0008 ++#define QSPI_FCR_CSMF 0x0004 ++#define QSPI_FCR_CTCF 0x0002 ++#define QSPI_FCR_CTEF 0x0001 ++ ++#define QSPI_DFLT_READ_FLAGS (QSPI_CCR_INST | QSPI_CCR_IMODE | \ ++ QSPI_CCR_ADMODE | QSPI_CCR_ADSIZE | \ ++ QSPI_CCR_ABMODE | QSPI_CCR_ABSIZE | \ ++ QSPI_CCR_DCYC | QSPI_CCR_DMODE | \ ++ QSPI_CCR_SIOO | QSPI_CCR_DDRM | \ ++ QSPI_CCR_DHHC) ++ ++/* ++ * QUAD Serial Peripheral Interface ++ */ ++ ++typedef struct { ++ volatile uint32_t CR; /* Control register */ ++ volatile uint32_t DCR; /* Device Configuration register */ ++ volatile uint32_t SR; /* Status register */ ++ volatile uint32_t FCR; /* Flag Clear register */ ++ volatile uint32_t DLR; /* Data Length register */ ++ volatile uint32_t CCR; /* Communication Configuration register */ ++ volatile uint32_t AR; /* Address register */ ++ volatile uint32_t ABR; /* Alternate Bytes register */ ++ volatile uint32_t DR; /* Data register */ ++ volatile uint32_t PSMKR; /* Polling Status Mask register */ ++ volatile uint32_t PSMAR; /* Polling Status Match register */ ++ volatile uint32_t PIR; /* Polling Interval register */ ++ volatile uint32_t LPTR; /* Low Power Timeout register */ ++} QUADSPI_TypeDef; ++ ++/* ++ * QSPI Handle Structure definition ++ */ ++typedef struct { ++ QUADSPI_TypeDef *instance; /* QSPI registers base address */ ++ uint32_t is_dual; ++} QSPI_HandleTypeDef; ++ ++int register_io_dev_qspi(const io_dev_connector_t **dev_con); ++ ++#endif /* __IO_QSPI_H__ */ +diff --git a/include/drivers/st/io_stm32image.h b/include/drivers/st/io_stm32image.h +new file mode 100644 +index 0000000..b668219 +--- /dev/null ++++ b/include/drivers/st/io_stm32image.h +@@ -0,0 +1,32 @@ ++/* ++ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. ++ * ++ * SPDX-License-Identifier: BSD-3-Clause ++ */ ++ ++#ifndef IO_STM32IMAGE_H ++#define IO_STM32IMAGE_H ++ ++#include ++#include ++ ++#define MAX_LBA_SIZE 512 ++#define MAX_PART_NAME_SIZE (EFI_NAMELEN + 1) ++#define STM32_PART_NUM (PLAT_PARTITION_MAX_ENTRIES - STM32_TF_A_COPIES) ++ ++struct stm32image_part_info { ++ char name[MAX_PART_NAME_SIZE]; ++ uint32_t binary_type; ++ uintptr_t part_offset; ++ uint32_t bkp_offset; ++}; ++ ++struct stm32image_device_info { ++ struct stm32image_part_info part_info[STM32_PART_NUM]; ++ uint32_t device_size; ++ uint32_t lba_size; ++}; ++ ++int register_io_dev_stm32image(const io_dev_connector_t **dev_con); ++ ++#endif /* IO_STM32IMAGE_H */ +diff --git a/include/drivers/st/io_uart.h b/include/drivers/st/io_uart.h +new file mode 100644 +index 0000000..2f9ecb3 +--- /dev/null ++++ b/include/drivers/st/io_uart.h +@@ -0,0 +1,12 @@ ++/* ++ * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved. ++ * ++ * SPDX-License-Identifier: BSD-3-Clause ++ */ ++ ++#ifndef __IO_UART_H__ ++#define __IO_UART_H__ ++ ++int register_io_dev_uart(const io_dev_connector_t **dev_con); ++ ++#endif /* __IO_UART_H__ */ +diff --git a/include/drivers/st/nand.h b/include/drivers/st/nand.h +new file mode 100644 +index 0000000..f92511d +--- /dev/null ++++ b/include/drivers/st/nand.h +@@ -0,0 +1,252 @@ ++/* ++ ****************************************************************************** ++ * @file nand.h ++ * @author mgentilini - MCD IntroPack team - MPU AP v1 bootROM project ++ * @version V0.1 ++ * @date 28-April-2016 ++ * @brief Header file for STM32MP1 Nand driver module. ++ ****************************************************************************** ++ * @attention ++ * ++ *

© COPYRIGHT(c) STMicroelectronics

++ * ++ * SPDX-License-Identifier: BSD-3-Clause ++ * ++ ****************************************************************************** ++ */ ++ ++#ifndef __NAND_H ++#define __NAND_H ++ ++#include ++ ++/* FMC NAND Flash 'common memory' data area */ ++#define FLASH_COMMON_MEM_BASE 0x80000000 ++/* FMC NAND Flash 'attribute memory' data area */ ++#define FLASH_ATTRIB_MEM_BASE 0x88000000 ++ ++#define BCH_PAGE_SECTOR 512 ++ ++/* BBM */ ++#define GOOD_BLOCK 0 ++#define BAD_BLOCK 1 ++ ++/**************** Bit definition for FMC_PCR register *******************/ ++/* Wait feature enable bit */ ++#define FMC_PCR_PWAITEN ((uint32_t)0x00000002) ++/* PC Card/NAND Flash memory bank enable bit */ ++#define FMC_PCR_PBKEN ((uint32_t)0x00000004) ++ ++/* PWID[1:0] bits (NAND Flash databus width) */ ++#define FMC_PCR_PWID ((uint32_t)0x00000030) ++#define FMC_PCR_PWID_0 ((uint32_t)0x00000010) /* Bit 0 */ ++#define FMC_PCR_PWID_1 ((uint32_t)0x00000020) /* Bit 1 */ ++ ++/* ECC computation logic enable bit */ ++#define FMC_PCR_ECCEN ((uint32_t)0x00000040) ++ ++/* ECC algorithm */ ++#define FMC_PCR_ECCALG ((uint32_t)0x00000100) ++ ++/* TCLR[3:0] bits (CLE to RE delay) */ ++#define FMC_PCR_TCLR_0 ((uint32_t)0x00000200) /* Bit 0 */ ++#define FMC_PCR_TCLR_1 ((uint32_t)0x00000400) /* Bit 1 */ ++#define FMC_PCR_TCLR_2 ((uint32_t)0x00000800) /* Bit 2 */ ++#define FMC_PCR_TCLR_3 ((uint32_t)0x00001000) /* Bit 3 */ ++ ++/* TAR[3:0] bits (ALE to RE delay) */ ++#define FMC_PCR_TAR_0 ((uint32_t)0x00002000) /* Bit 0 */ ++#define FMC_PCR_TAR_1 ((uint32_t)0x00004000) /* Bit 1 */ ++#define FMC_PCR_TAR_2 ((uint32_t)0x00008000) /* Bit 2 */ ++#define FMC_PCR_TAR_3 ((uint32_t)0x00010000) /* Bit 3 */ ++ ++/* ECCSS[1:0] bits (ECC sector size) */ ++#define FMC_PCR_ECCSS ((uint32_t)0x000E0000) ++#define FMC_PCR_ECCSS_0 ((uint32_t)0x00020000) /* Bit 0 */ ++#define FMC_PCR_ECCSS_1 ((uint32_t)0x00040000) /* Bit 1 */ ++#define FMC_PCR_ECCSS_2 ((uint32_t)0x00080000) /* Bit 2 */ ++ ++/* BCH Error correction capability */ ++#define FMC_PCR_BCHECC ((uint32_t)0x01000000) ++ ++/* Write enable */ ++#define FMC_PCR_WE ((uint32_t)0x02000000) ++ ++/**************** Bit definition for FMC_BCR1 register *******************/ ++/* FMC controller enable */ ++#define FMC_BCR1_FMCEN ((uint32_t)0x80000000) ++ ++/**************** Bit definition for FMC_BCHISR register *******************/ ++/* Decoder Error Ready Flag */ ++#define FMC_BCHISR_DERF ((uint32_t)0x00000002) ++/* Decoder Uncorrectable Error Flag */ ++#define FMC_BCHISR_DUEF ((uint32_t)0x00000001) ++/* Decoder Error Found Flag */ ++#define FMC_BCHISR_DEFF ((uint32_t)0x00000004) ++ ++/**************** Bit definition for FMC_BCHSR register *******************/ ++/* Decoder Error Number */ ++#define FMC_BCHSR_DEN ((uint32_t)0x0000000F) ++ ++/**************** Bit definition for FMC_BCHDSR0 register *******************/ ++/* Decoder Uncorrectable Error */ ++#define FMC_BCHDSR0_DUE ((uint32_t)0x00000001) ++/* Decoder Error Number */ ++#define FMC_BCHDSR0_DEN ((uint32_t)0x000000F0) ++ ++/**************** Bit definition for FMC_BCHDSR1 register *******************/ ++#define FMC_BCHDSR1_EBP1 ((uint32_t)0x00001FFF) ++#define FMC_BCHDSR1_EBP2 ((uint32_t)0x1FFF0000) ++ ++/**************** Bit definition for FMC_BCHDSR2 register *******************/ ++#define FMC_BCHDSR2_EBP1 ((uint32_t)0x00001FFF) ++#define FMC_BCHDSR2_EBP2 ((uint32_t)0x1FFF0000) ++ ++/**************** Bit definition for FMC_BCHDSR3 register *******************/ ++#define FMC_BCHDSR3_EBP1 ((uint32_t)0x00001FFF) ++#define FMC_BCHDSR3_EBP2 ((uint32_t)0x1FFF0000) ++ ++/**************** Bit definition for FMC_BCHDSR4 register *******************/ ++#define FMC_BCHDSR4_EBP1 ((uint32_t)0x00001FFF) ++#define FMC_BCHDSR4_EBP2 ((uint32_t)0x1FFF0000) ++ ++/**************** Bit definition for FMC_SR register **********************/ ++#define FMC_SR_NWRF ((uint32_t)0x00000040) ++#define FMC_SR_PF ((uint32_t)0x00000010) ++ ++#define FMC_NSEC_PER_SEC 1000000000L ++ ++/* Timings */ ++#define FMC_THIZ 1 ++#define FMC_TIO 8000 ++#define FMC_TSYNC 3000 ++#define FMC_PCR_TIMING_MASK 0xf ++#define FMC_PMEM_PATT_TIMING_MASK 0xff ++ ++/* Register: FMC_PCR */ ++#define FMC_PCR_TCLR(x) (((x) & 0xf) << 9) ++#define FMC_PCR_TAR(x) (((x) & 0xf) << 13) ++ ++/* Register: FMC_PMEM */ ++#define FMC_PMEM_MEMSET(x) (((x) & 0xff) << 0) ++#define FMC_PMEM_MEMWAIT(x) (((x) & 0xff) << 8) ++#define FMC_PMEM_MEMHOLD(x) (((x) & 0xff) << 16) ++#define FMC_PMEM_MEMHIZ(x) (((x) & 0xff) << 24) ++ ++/* Register: FMC_PATT */ ++#define FMC_PATT_ATTSET(x) (((x) & 0xff) << 0) ++#define FMC_PATT_ATTWAIT(x) (((x) & 0xff) << 8) ++#define FMC_PATT_ATTHOLD(x) (((x) & 0xff) << 16) ++#define FMC_PATT_ATTHIZ(x) (((x) & 0xff) << 24) ++ ++/* NAND ONFI Default Value Mode 0 */ ++#define FMC_TADL_MIN 200000 ++#define FMC_TALH_MIN 20000 ++#define FMC_TALS_MIN 50000 ++#define FMC_TAR_MIN 25000 ++#define FMC_TCH_MIN 20000 ++#define FMC_TCLH_MIN 20000 ++#define FMC_TCLR_MIN 20000 ++#define FMC_TCLS_MIN 50000 ++#define FMC_TCOH_MIN 0 ++#define FMC_TCS_MIN 70000 ++#define FMC_TDH_MIN 20000 ++#define FMC_TDS_MIN 40000 ++#define FMC_TRC_MIN 100000 ++#define FMC_TREA_MAX 40000 ++#define FMC_TREH_MIN 30000 ++#define FMC_TRHW_MIN 200000 ++#define FMC_TRP_MIN 50000 ++#define FMC_TWB_MAX 200000 ++#define FMC_TWC_MIN 100000 ++#define FMC_TWH_MIN 30000 ++#define FMC_TWHR_MIN 120000 ++#define FMC_TWP_MIN 50000 ++ ++ ++#define FMC_EBP2_MASK 16 ++ ++/* 1st addressing cycle */ ++#define ADDR_1ST_CYCLE(__ADDRESS__) (uint8_t)(__ADDRESS__) ++/* 2nd addressing cycle */ ++#define ADDR_2ND_CYCLE(__ADDRESS__) (uint8_t)((__ADDRESS__) >> 8) ++/* 3rd addressing cycle */ ++#define ADDR_3RD_CYCLE(__ADDRESS__) (uint8_t)((__ADDRESS__) >> 16) ++/* 4th addressing cycle */ ++#define ADDR_4TH_CYCLE(__ADDRESS__) (uint8_t)((__ADDRESS__) >> 24) ++ ++typedef struct { ++ uint8_t tclr; ++ uint8_t tar; ++ uint8_t thiz; ++ uint8_t twait; ++ uint8_t thold_mem; ++ uint8_t tset_mem; ++ uint8_t thold_att; ++ uint8_t tset_att; ++} nand_timings; ++ ++typedef struct { ++ uint32_t Signature; /* NAND Parameter page signature */ ++ ++ uint32_t PageSize; /* NAND memory page (without spare area) size ++ * measured in B ++ */ ++ ++ uint32_t BlockSize; /* NAND memory block size in number ++ * of pages ++ */ ++ ++ uint32_t BlockNb; /* NAND memory number of blocks */ ++ ++ uint32_t ZoneSize; /* NAND memory zone size measured in number ++ * of blocks ++ */ ++ ++ uint32_t BusWidth; /* NAND memory bus width in bytes */ ++ ++ uint32_t ECCcorrectability; /* NAND number of bits ECC correctability */ ++ ++ uint32_t page_size_shift; ++ uint32_t block_size_shift; ++ ++ nand_timings timings; ++ ++} NAND_InfoTypeDef; ++ ++/* NAND Memory address Structure definition */ ++typedef struct { ++ uint16_t Page; /* NAND memory Page address */ ++ ++ uint16_t Zone; /* NAND memory Zone address */ ++ ++ uint16_t Block; /* NAND memory Block address */ ++} NAND_AddressTypeDef; ++ ++/* NAND Memory electronic signature Structure definition */ ++typedef struct { ++ uint8_t Maker_Id; ++ ++ uint8_t Device_Id; ++} NAND_IDTypeDef; ++ ++/* NAND handle Structure definition */ ++typedef struct { ++ FMC_TypeDef *Instance; /* Register base address */ ++ ++ NAND_InfoTypeDef Info; /* NAND characteristic information structure */ ++} NAND_HandleTypeDef; ++ ++/* Exported functions */ ++Std_ReturnType nand_initialize(NAND_HandleTypeDef *hnand); ++Std_ReturnType NAND_Read_Logical_Page(NAND_HandleTypeDef *hNand, ++ NAND_AddressTypeDef *Address, ++ uint8_t *Buffer, uint32_t bch_sector_nb); ++uint32_t NAND_Check_Bad_Block(NAND_HandleTypeDef *hNand, ++ NAND_AddressTypeDef *Address); ++Std_ReturnType NAND_Address_Inc(NAND_HandleTypeDef *hNand, ++ NAND_AddressTypeDef *Address, ++ uint32_t numPagesRead); ++ ++#endif /* __NAND_H */ ++ +diff --git a/include/drivers/st/stm32_console.h b/include/drivers/st/stm32_console.h +new file mode 100644 +index 0000000..57e6d74 +--- /dev/null ++++ b/include/drivers/st/stm32_console.h +@@ -0,0 +1,34 @@ ++/* ++ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. ++ * ++ * SPDX-License-Identifier: BSD-3-Clause ++ */ ++ ++#ifndef STM32_CONSOLE_H ++#define STM32_CONSOLE_H ++ ++#include ++ ++#define CONSOLE_T_STM32_BASE CONSOLE_T_DRVDATA ++ ++#ifndef __ASSEMBLY__ ++ ++#include ++ ++struct console_stm32 { ++ console_t console; ++ uintptr_t base; ++}; ++ ++/* ++ * Initialize a new STM32 console instance and register it with the console ++ * framework. The |console| pointer must point to storage that will be valid ++ * for the lifetime of the console, such as a global or static local variable. ++ * Its contents will be reinitialized from scratch. ++ */ ++int console_stm32_register(uintptr_t baseaddr, uint32_t clock, uint32_t baud, ++ struct console_stm32 *console); ++ ++#endif /*__ASSEMBLY__*/ ++ ++#endif /* STM32_CONSOLE_H */ +diff --git a/include/drivers/st/stm32_gpio.h b/include/drivers/st/stm32_gpio.h +index 7a5ccd3..33cef04 100644 +--- a/include/drivers/st/stm32_gpio.h ++++ b/include/drivers/st/stm32_gpio.h +@@ -4,15 +4,11 @@ + * SPDX-License-Identifier: BSD-3-Clause + */ + +-#ifndef __PLAT_GPIO_H__ +-#define __PLAT_GPIO_H__ ++#ifndef STM32_GPIO_H ++#define STM32_GPIO_H + + #include + +-#define STM32_GPIOA_BANK U(0x50002000) +-#define STM32_GPIOZ_BANK U(0x54004000) +-#define STM32_GPIO_BANK_OFFSET U(0x1000) +- + #define GPIO_MODE_OFFSET U(0x00) + #define GPIO_TYPE_OFFSET U(0x04) + #define GPIO_SPEED_OFFSET U(0x08) +@@ -20,56 +16,14 @@ + #define GPIO_BSRR_OFFSET U(0x18) + #define GPIO_AFRL_OFFSET U(0x20) + #define GPIO_AFRH_OFFSET U(0x24) ++#define GPIO_SECR_OFFSET U(0x30) + + #define GPIO_ALT_LOWER_LIMIT U(0x08) + +-#define GPIO_BANK_A U(0x00) +-#define GPIO_BANK_B U(0x01) +-#define GPIO_BANK_C U(0x02) +-#define GPIO_BANK_D U(0x03) +-#define GPIO_BANK_E U(0x04) +-#define GPIO_BANK_F U(0x05) +-#define GPIO_BANK_G U(0x06) +-#define GPIO_BANK_H U(0x07) +-#define GPIO_BANK_I U(0x08) +-#define GPIO_BANK_J U(0x09) +-#define GPIO_BANK_K U(0x0A) +-#define GPIO_BANK_Z U(0x19) +- +-#define GPIO_PIN_0 U(0x00) +-#define GPIO_PIN_1 U(0x01) +-#define GPIO_PIN_2 U(0x02) +-#define GPIO_PIN_3 U(0x03) +-#define GPIO_PIN_4 U(0x04) +-#define GPIO_PIN_5 U(0x05) +-#define GPIO_PIN_6 U(0x06) +-#define GPIO_PIN_7 U(0x07) +-#define GPIO_PIN_8 U(0x08) +-#define GPIO_PIN_9 U(0x09) +-#define GPIO_PIN_10 U(0x0A) +-#define GPIO_PIN_11 U(0x0B) +-#define GPIO_PIN_12 U(0x0C) +-#define GPIO_PIN_13 U(0x0D) +-#define GPIO_PIN_14 U(0x0E) +-#define GPIO_PIN_15 U(0x0F) +-#define GPIO_PIN_MAX GPIO_PIN_15 ++#define GPIO_PIN_(_x) U(_x) ++#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_(_x) U(_x) + #define GPIO_ALTERNATE_MASK U(0x0F) + + #define GPIO_MODE_INPUT 0x00 +@@ -82,8 +36,8 @@ + + #define GPIO_SPEED_LOW 0x00 + #define GPIO_SPEED_MEDIUM 0x01 +-#define GPIO_SPEED_FAST 0x02 +-#define GPIO_SPEED_HIGH 0x03 ++#define GPIO_SPEED_HIGH 0x02 ++#define GPIO_SPEED_VERY_HIGH 0x03 + #define GPIO_SPEED_MASK U(0x03) + + #define GPIO_NO_PULL 0x00 +@@ -94,8 +48,10 @@ + #ifndef __ASSEMBLY__ + #include + ++int dt_set_pinctrl_config(int node); + void set_gpio(uint32_t bank, uint32_t pin, uint32_t mode, uint32_t speed, +- uint32_t pull, uint32_t alternate); ++ uint32_t pull, uint32_t alternate, uint8_t status); ++void set_gpio_secure_cfg(uint32_t bank, uint32_t pin, bool secure); + #endif /*__ASSEMBLY__*/ + +-#endif /*__PLAT_GPIO_H__*/ ++#endif /* STM32_GPIO_H */ +diff --git a/include/drivers/st/stm32_hal_hash_reg.h b/include/drivers/st/stm32_hal_hash_reg.h +new file mode 100644 +index 0000000..e7a589b +--- /dev/null ++++ b/include/drivers/st/stm32_hal_hash_reg.h +@@ -0,0 +1,136 @@ ++/** ++ ****************************************************************************** ++ * @file stm32_hal_hash_reg.h ++ * @author MCD Intropack Team - MPU AP v1 bootROM project ++ * @date 22 September 2015 ++ * @brief STM32 Device Peripheral Access Layer Header File. ++ * ++ * This file contains: ++ * - Data structures and the address mapping for all peripherals ++ * - Peripheral's registers declarations and bits definition ++ * - Macros to access peripherals registers hardware ++ * ++ ****************************************************************************** ++ * @attention ++ * ++ *

© COPYRIGHT(c) 2015 STMicroelectronics

++ * ++ * SPDX-License-Identifier: BSD-3-Clause ++ * ++ ****************************************************************************** ++ */ ++ ++#ifndef _STM32_HAL_HASH_REG_H_ ++#define _STM32_HAL_HASH_REG_H_ ++ ++#ifdef __cplusplus ++ extern "C" { ++#endif /* __cplusplus */ ++ ++ ++/** @addtogroup Peripheral_registers_structures ++ * @{ ++ */ ++ ++/** ++ * @brief Secure digital input/output Interface ++ */ ++#ifndef __ASM_INCLUDE__ ++/** ++ * @brief HASH ++ */ ++ ++typedef struct ++{ ++ __IO uint32_t CR; /*!< HASH control register, Address offset: 0x00 */ ++ __IO uint32_t DIN; /*!< HASH data input register, Address offset: 0x04 */ ++ __IO uint32_t STR; /*!< HASH start register, Address offset: 0x08 */ ++ __IO uint32_t HR[5]; /*!< HASH digest registers, Address offset: 0x0C-0x1C */ ++ __IO uint32_t IMR; /*!< HASH interrupt enable register, Address offset: 0x20 */ ++ __IO uint32_t SR; /*!< HASH status register, Address offset: 0x24 */ ++ uint32_t RESERVED[52]; /*!< Reserved, 0x28-0xF4 */ ++ __IO uint32_t CSR[54]; /*!< HASH context swap registers, Address offset: 0x0F8-0x1CC */ ++} HASH_TypeDef; ++#endif /* __ASM_INCLUDE__ */ ++ ++#ifndef __ASM_INCLUDE__ ++/** ++ * @brief HASH_DIGEST ++ */ ++ ++typedef struct ++{ ++ __IO uint32_t HR[8]; /*!< HASH digest registers, Address offset: 0x310-0x32C */ ++} HASH_DIGEST_TypeDef; ++#endif /* __ASM_INCLUDE__ */ ++ ++ ++ ++ ++ ++/** @addtogroup Exported_constants ++ * @{ ++ */ ++ ++ /** @addtogroup Peripheral_Registers_Bits_Definition ++ * @{ ++ */ ++ ++/****************** Bits definition for HASH_CR register ********************/ ++#define HASH_CR_INIT ((uint32_t)0x00000004) ++#define HASH_CR_DMAE ((uint32_t)0x00000008) ++#define HASH_CR_DATATYPE ((uint32_t)0x00000030) ++#define HASH_CR_DATATYPE_0 ((uint32_t)0x00000010) ++#define HASH_CR_DATATYPE_1 ((uint32_t)0x00000020) ++#define HASH_CR_MODE ((uint32_t)0x00000040) ++#define HASH_CR_ALGO ((uint32_t)0x00040080) ++#define HASH_CR_ALGO_0 ((uint32_t)0x00000080) ++#define HASH_CR_ALGO_1 ((uint32_t)0x00040000) ++#define HASH_CR_NBW ((uint32_t)0x00000F00) ++#define HASH_CR_NBW_0 ((uint32_t)0x00000100) ++#define HASH_CR_NBW_1 ((uint32_t)0x00000200) ++#define HASH_CR_NBW_2 ((uint32_t)0x00000400) ++#define HASH_CR_NBW_3 ((uint32_t)0x00000800) ++#define HASH_CR_DINNE ((uint32_t)0x00001000) ++#define HASH_CR_MDMAT ((uint32_t)0x00002000) ++#define HASH_CR_LKEY ((uint32_t)0x00010000) ++ ++/****************** Bits definition for HASH_STR register *******************/ ++#define HASH_STR_NBW ((uint32_t)0x0000001F) ++#define HASH_STR_NBW_0 ((uint32_t)0x00000001) ++#define HASH_STR_NBW_1 ((uint32_t)0x00000002) ++#define HASH_STR_NBW_2 ((uint32_t)0x00000004) ++#define HASH_STR_NBW_3 ((uint32_t)0x00000008) ++#define HASH_STR_NBW_4 ((uint32_t)0x00000010) ++#define HASH_STR_DCAL ((uint32_t)0x00000100) ++ ++/****************** Bits definition for HASH_IMR register *******************/ ++#define HASH_IMR_DINIM ((uint32_t)0x00000001) ++#define HASH_IMR_DCIM ((uint32_t)0x00000002) ++ ++/****************** Bits definition for HASH_SR register ********************/ ++#define HASH_SR_DINIS ((uint32_t)0x00000001) ++#define HASH_SR_DCIS ((uint32_t)0x00000002) ++#define HASH_SR_DMAS ((uint32_t)0x00000004) ++#define HASH_SR_BUSY ((uint32_t)0x00000008) ++ ++/** ++ * @} ++ */ ++ ++/** ++ * @} ++ */ ++ ++ ++/** ++ * @} ++ */ ++ ++#ifdef __cplusplus ++} ++#endif /* __cplusplus */ ++ ++#endif /* _STM32_HAL_HASH_REG_H_ */ ++ ++/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ +diff --git a/include/drivers/st/stm32_i2c.h b/include/drivers/st/stm32_i2c.h +index 29b9d34..4d5e302 100644 +--- a/include/drivers/st/stm32_i2c.h ++++ b/include/drivers/st/stm32_i2c.h +@@ -1,11 +1,11 @@ + /* + * Copyright (c) 2016-2018, STMicroelectronics - All Rights Reserved + * +- * SPDX-License-Identifier: BSD-3-Clause ++ * SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause + */ + +-#ifndef __STM32MP1_I2C_H +-#define __STM32MP1_I2C_H ++#ifndef STM32_I2C_H ++#define STM32_I2C_H + + #include + #include +@@ -72,6 +72,21 @@ + #define I2C_TIMINGR_SDADEL GENMASK(19, 16) + #define I2C_TIMINGR_SCLDEL GENMASK(23, 20) + #define I2C_TIMINGR_PRESC GENMASK(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(11, 0) +@@ -110,94 +125,113 @@ + #define I2C_ICR_TIMOUTCF BIT(12) + #define I2C_ICR_ALERTCF BIT(13) + +-struct stm32_i2c_init_s { +- uint32_t timing; /* Specifies the I2C_TIMINGR_register value +- * This parameter is calculated by referring +- * to I2C initialization section in Reference +- * manual. +- */ +- +- 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. +- */ ++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, /* Peripheral is not yet +- * initialized. +- */ +- I2C_STATE_READY = 0x20U, /* Peripheral Initialized +- * and ready for use. +- */ +- I2C_STATE_BUSY = 0x24U, /* An internal process is +- * ongoing. +- */ +- I2C_STATE_BUSY_TX = 0x21U, /* Data Transmission process +- * is ongoing. +- */ +- I2C_STATE_BUSY_RX = 0x22U, /* Data Reception process +- * is ongoing. +- */ +- I2C_STATE_LISTEN = 0x28U, /* Address Listen Mode is +- * ongoing. +- */ +- I2C_STATE_BUSY_TX_LISTEN = 0x29U, /* Address Listen Mode +- * and Data Transmission +- * process is ongoing. +- */ +- I2C_STATE_BUSY_RX_LISTEN = 0x2AU, /* Address Listen Mode +- * and Data Reception +- * process is ongoing. +- */ +- I2C_STATE_ABORT = 0x60U, /* Abort user request ongoing. */ +- I2C_STATE_TIMEOUT = 0xA0U, /* Timeout state. */ +- I2C_STATE_ERROR = 0xE0U /* Error. */ +- ++ 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 */ + }; + + enum i2c_mode_e { +- I2C_MODE_NONE = 0x00U, /* No I2C communication on going. */ +- I2C_MODE_MASTER = 0x10U, /* I2C communication is in Master Mode. */ +- I2C_MODE_SLAVE = 0x20U, /* I2C communication is in Slave Mode. */ +- I2C_MODE_MEM = 0x40U /* I2C communication is in Memory Mode. */ ++ 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 */ + + }; + +@@ -212,52 +246,38 @@ enum i2c_mode_e { + + struct i2c_handle_s { + uint32_t i2c_base_addr; /* Registers base address */ +- +- struct stm32_i2c_init_s i2c_init; /* Communication parameters */ +- +- uint8_t *p_buff; /* Pointer to transfer buffer */ +- +- uint16_t xfer_size; /* Transfer size */ +- +- uint16_t xfer_count; /* Transfer counter */ +- +- uint32_t prev_state; /* Communication previous +- * state +- */ +- +- uint8_t lock; /* Locking object */ +- +- enum i2c_state_e i2c_state; /* Communication state */ +- +- enum i2c_mode_e i2c_mode; /* Communication mode */ +- +- uint32_t i2c_err; /* Error code */ ++ unsigned int dt_status; /* DT nsec/sec status */ ++ unsigned int clock; /* Clock reference */ ++ uint8_t lock; /* Locking object */ ++ enum i2c_state_e i2c_state; /* Communication state */ ++ enum i2c_mode_e i2c_mode; /* Communication mode */ ++ uint32_t i2c_err; /* Error code */ + }; + +-#define I2C_ADDRESSINGMODE_7BIT 0x00000001U +-#define I2C_ADDRESSINGMODE_10BIT 0x00000002U ++#define I2C_ADDRESSINGMODE_7BIT 0x00000001U ++#define I2C_ADDRESSINGMODE_10BIT 0x00000002U + +-#define I2C_DUALADDRESS_DISABLE 0x00000000U +-#define I2C_DUALADDRESS_ENABLE I2C_OAR2_OA2EN ++#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_GENERALCALL_DISABLE 0x00000000U ++#define I2C_GENERALCALL_ENABLE I2C_CR1_GCEN + +-#define I2C_NOSTRETCH_DISABLE 0x00000000U +-#define I2C_NOSTRETCH_ENABLE I2C_CR1_NOSTRETCH ++#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_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_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_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 +@@ -280,21 +300,36 @@ struct i2c_handle_s { + I2C_CR2_NBYTES | I2C_CR2_RELOAD | \ + I2C_CR2_RD_WRN) + +-#define I2C_ANALOGFILTER_ENABLE ((uint32_t)0x00000000U) +-#define I2C_ANALOGFILTER_DISABLE I2C_CR1_ANFOFF ++#define I2C_TIMEOUT_BUSY_MS 25U + +-int stm32_i2c_init(struct i2c_handle_s *hi2c); ++#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); ++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); ++ 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); +-int stm32_i2c_is_device_ready(struct i2c_handle_s *hi2c, uint16_t dev_addr, +- uint32_t trials, uint32_t timeout); +- +-int stm32_i2c_config_analog_filter(struct i2c_handle_s *hi2c, +- uint32_t analog_filter); +- +-#endif /* __STM32MP1_I2C_H */ ++ 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); ++ ++#endif /* STM32_I2C_H */ +diff --git a/include/drivers/st/stm32_iwdg.h b/include/drivers/st/stm32_iwdg.h +new file mode 100644 +index 0000000..b6d4769 +--- /dev/null ++++ b/include/drivers/st/stm32_iwdg.h +@@ -0,0 +1,20 @@ ++/* ++ * Copyright (c) 2018, STMicroelectronics - All Rights Reserved ++ * ++ * SPDX-License-Identifier: BSD-3-Clause ++ */ ++ ++#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) ++ ++int stm32_iwdg_init(void); ++void stm32_iwdg_refresh(uint32_t instance); ++void __dead2 stm32_iwdg_it_handler(int id); ++ ++#endif /* __STM32_IWDG_H__ */ +diff --git a/include/drivers/st/stm32_rng.h b/include/drivers/st/stm32_rng.h +new file mode 100644 +index 0000000..a644118 +--- /dev/null ++++ b/include/drivers/st/stm32_rng.h +@@ -0,0 +1,13 @@ ++/* ++ * Copyright (c) 2018, STMicroelectronics - All Rights Reserved ++ * ++ * SPDX-License-Identifier: BSD-3-Clause ++ */ ++ ++#ifndef STM32_RNG_H ++#define STM32_RNG_H ++ ++int stm32_rng_read(uint8_t *out, uint32_t size); ++int stm32_rng_init(void); ++ ++#endif /* STM32_RNG_H */ +diff --git a/include/drivers/st/stm32_rtc.h b/include/drivers/st/stm32_rtc.h +new file mode 100644 +index 0000000..bc9e61e +--- /dev/null ++++ b/include/drivers/st/stm32_rtc.h +@@ -0,0 +1,79 @@ ++/* ++ * Copyright (c) 2017-2018, STMicroelectronics - All Rights Reserved ++ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. ++ * ++ * SPDX-License-Identifier: BSD-3-Clause ++ */ ++ ++#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); ++int stm32_rtc_init(void); ++ ++/* SMP protection on RTC registers access */ ++void stm32_rtc_regs_lock(void); ++void stm32_rtc_regs_unlock(void); ++ ++#endif /* __PLAT_RTC_H__ */ +diff --git a/include/drivers/st/stm32_sdmmc2.h b/include/drivers/st/stm32_sdmmc2.h +new file mode 100644 +index 0000000..b172659 +--- /dev/null ++++ b/include/drivers/st/stm32_sdmmc2.h +@@ -0,0 +1,31 @@ ++/* ++ * Copyright (c) 2017-2018, STMicroelectronics - All Rights Reserved ++ * ++ * SPDX-License-Identifier: BSD-3-Clause ++ */ ++ ++#ifndef STM32_SDMMC2_H ++#define STM32_SDMMC2_H ++ ++#include ++#include ++ ++struct stm32_sdmmc2_params { ++ uintptr_t reg_base; ++ unsigned int clk_rate; ++ unsigned int bus_width; ++ unsigned int flags; ++ struct mmc_device_info *device_info; ++ unsigned int pin_ckin; ++ unsigned int negedge; ++ unsigned int dirpol; ++ unsigned int clock_id; ++ unsigned int reset_id; ++ bool use_dma; ++}; ++ ++unsigned long long stm32_sdmmc2_mmc_get_device_size(void); ++int stm32_sdmmc2_mmc_init(struct stm32_sdmmc2_params *params); ++bool plat_sdmmc2_use_dma(unsigned int instance, unsigned int memory); ++ ++#endif /* STM32_SDMMC2_H */ +diff --git a/include/drivers/st/stm32_tamp.h b/include/drivers/st/stm32_tamp.h +new file mode 100644 +index 0000000..3933c26 +--- /dev/null ++++ b/include/drivers/st/stm32_tamp.h +@@ -0,0 +1,163 @@ ++/* ++ * Copyright (c) 2014, ARM Limited and Contributors. All rights reserved. ++ * ++ * SPDX-License-Identifier: BSD-3-Clause ++ */ ++ ++#ifndef __TAMPER_H__ ++#define __TAMPER_H__ ++ ++/* Internal Tamper */ ++enum stm32_tamp_int_id { ++ ITAMP1 = 0, ++ ITAMP2, ++ ITAMP3, ++ ITAMP4, ++ ITAMP5, ++ ITAMP6, ++ ITAMP7, ++ ITAMP8, ++ ITAMP9, ++ ITAMP10, ++ ITAMP11, ++ ITAMP12, ++ ITAMP13, ++ ITAMP14, ++ ITAMP15, ++ ITAMP16 ++}; ++ ++/* External Tamper */ ++enum stm32_tamp_ext_id { ++ EXT_TAMP1 = 0, ++ EXT_TAMP2, ++ EXT_TAMP3, ++ EXT_TAMP4, ++ EXT_TAMP5, ++ EXT_TAMP6, ++ EXT_TAMP7, ++ EXT_TAMP8 ++}; ++ ++enum stm32_tamp_state { ++ TAMP_DISABLE = 0, ++ TAMP_ENABLE ++}; ++ ++#define TAMP_UNUSED {.id = -1} ++ ++/* define TAMPER modes */ ++#define TAMP_TRIG_OFF 0x0U ++#define TAMP_TRIG_ON 0x1U ++#define TAMP_ACTIVE 0x2U ++#define TAMP_ERASE 0x0U ++#define TAMP_NOERASE 0x1U ++#define TAMP_NO_EVT_MASK 0x0U ++#define TAMP_EVT_MASK 0x1U ++ ++/* define Passive FILTER mode */ ++#define TAMP_FILTER_PRECHARGE 0x0U ++#define TAMP_FILTER_PULL_UP_DISABLE 0x1U ++#define TAMP_FILTER_DURATION_1_CYCLE 0x0U ++#define TAMP_FILTER_DURATION_2_CYCLES 0x1U ++#define TAMP_FILTER_DURATION_3_CYCLES 0x2U ++#define TAMP_FILTER_DURATION_4_CYCLES 0x3U ++#define TAMP_FILTER_COUNT_1 0x0U ++#define TAMP_FILTER_COUNT_2 0x1U ++#define TAMP_FILTER_COUNT_4 0x2U ++#define TAMP_FILTER_COUNT_8 0x3U ++#define TAMP_FILTER_SAMPLING_32768 0x0U ++#define TAMP_FILTER_SAMPLING_16384 0x1U ++#define TAMP_FILTER_SAMPLING_8192 0x2U ++#define TAMP_FILTER_SAMPLING_4096 0x3U ++#define TAMP_FILTER_SAMPLING_2048 0x4U ++#define TAMP_FILTER_SAMPLING_1024 0x5U ++#define TAMP_FILTER_SAMPLING_512 0x6U ++#define TAMP_FILTER_SAMPLING_256 0x7U ++ ++/* define active filter */ ++#define TAMP_ACTIVE_FILTER_OFF 0x0U ++#define TAMP_ACTIVE_FILTER_ON 0x1U ++#define TAMP_ACTIVE_ATO_DEDICTED 0x0U ++#define TAMP_ACTIVE_ATO_TAMPOUTSEL 0x1U ++#define TAMP_ACTIVE_APER_1_OUTPUT 0x0U ++#define TAMP_ACTIVE_APER_2_OUTPUTS 0x1U ++#define TAMP_ACTIVE_APER_3_4_OUTPUTS 0x2U ++#define TAMP_ACTIVE_APER_5_OUTPUTS 0x3U ++#define TAMP_ACTIVE_CKSEL_DIV_0 0x0U ++#define TAMP_ACTIVE_CKSEL_DIV_2 0x1U ++#define TAMP_ACTIVE_CKSEL_DIV_4 0x2U ++#define TAMP_ACTIVE_CKSEL_DIV_8 0x3U ++#define TAMP_ACTIVE_CKSEL_DIV_16 0x4U ++#define TAMP_ACTIVE_CKSEL_DIV_32 0x5U ++#define TAMP_ACTIVE_CKSEL_DIV_64 0x6U ++#define TAMP_ACTIVE_CKSEL_DIV_128 0x7U ++#define TAMP_ACTIVE_ATOSEL_OUT1_(X) (0x0U << (X * 2)) ++#define TAMP_ACTIVE_ATOSEL_OUT2_(X) (0x1U << (X * 2)) ++#define TAMP_ACTIVE_ATOSEL_OUT3_(X) (0x2U << (X * 2)) ++#define TAMP_ACTIVE_ATOSEL_OUT4_(X) (0x3U << (X * 2)) ++ ++#define TAMP_EXT(tamp_id, trig, erase, mask) (((tamp_id) << 3) | ((trig) << 2)\ ++ | ((erase) << 1) | (mask)) ++ ++#define TAMP_FLTCR(precharge, duration, count, sample) (((precharge) << 7) |\ ++ ((duration) << 5) |\ ++ ((count) << 3) |\ ++ (sample)) ++ ++#define TAMP_ACT(filter, ato, aper, atcksel, atosel) (((filter) << 31) |\ ++ ((ato) << 30) |\ ++ ((aper) << 24) |\ ++ ((atcksel) << 16) |\ ++ (atosel) << 8) ++ ++struct stm32_tamp_int { ++ int id; ++ void (*it_handler)(void); ++}; ++ ++struct stm32_tamp_ext { ++ int id; ++ uint8_t mode; ++ uint8_t erase; ++ uint8_t evt_mask; ++ void (*it_handler)(void); ++}; ++ ++/* ++ * stm32_tamp_write_mcounter : Increase monotonic counter ++ */ ++void stm32_tamp_write_mcounter(void); ++ ++/* ++ * stm32_tamp_it_handler : Interrupt handler ++ */ ++void stm32_tamp_it_handler(void); ++ ++/* ++ * stm32_tamp_configure_internal: Configure internal tamper ++ * tamper_list: List of tamper to enable ++ * nb_tamper: Number of tamper in list ++ */ ++void stm32_tamp_configure_internal(struct stm32_tamp_int *tamper_list, ++ uint16_t nb_tamper); ++ ++/* ++ * stm32_tamp_configure_external: Configure external tamper and associated ++ * configuration for filtering ++ * ext_tamp_list: List of external tamper to configure ++ * nb_tamper: Number of tamper in list ++ * passive_conf: Filter configuration ++ * active_conf: Configuration for active tamper ++ */ ++void stm32_tamp_configure_external(struct stm32_tamp_ext *ext_tamper_list, ++ uint8_t nb_tamper, uint32_t passive_conf, ++ uint32_t active_conf); ++ ++/* ++ * stm32_tamp_init: Initialize tamper from DT ++ * return 0 if disabled, 1 if enabled, else < 0 ++ */ ++int stm32_tamp_init(void); ++ ++#endif /* __TAMPER__ */ +diff --git a/include/drivers/st/stm32_timer.h b/include/drivers/st/stm32_timer.h +new file mode 100644 +index 0000000..e62f3df +--- /dev/null ++++ b/include/drivers/st/stm32_timer.h +@@ -0,0 +1,21 @@ ++/* ++ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. ++ * ++ * SPDX-License-Identifier: BSD-3-Clause ++ */ ++ ++#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); ++void stm32_timer_freq_func(unsigned long (**timer_freq_cb)(void), ++ enum timer_cal type); ++int stm32_timer_init(void); ++ ++#endif /* STM32_TIMER_H */ +diff --git a/include/drivers/st/stm32_uart_regs.h b/include/drivers/st/stm32_uart_regs.h +new file mode 100644 +index 0000000..e78d3d4 +--- /dev/null ++++ b/include/drivers/st/stm32_uart_regs.h +@@ -0,0 +1,199 @@ ++/* ++ * Copyright (C) 2018, STMicroelectronics - All Rights Reserved ++ * ++ * SPDX-License-Identifier: BSD-3-Clause ++ */ ++ ++#ifndef STM32_UART_REGS_H ++#define STM32_UART_REGS_H ++ ++#include ++ ++#define USART_CR1 U(0x00) ++#define USART_CR2 U(0x04) ++#define USART_CR3 U(0x08) ++#define USART_BRR U(0x0C) ++#define USART_GTPR U(0x10) ++#define USART_RTOR U(0x14) ++#define USART_RQR U(0x18) ++#define USART_ISR U(0x1C) ++#define USART_ICR U(0x20) ++#define USART_RDR U(0x24) ++#define USART_TDR U(0x28) ++#define USART_PRESC U(0x2C) ++ ++/* USART_CR1 register fields */ ++#define USART_CR1_UE BIT(0) ++#define USART_CR1_UESM BIT(1) ++#define USART_CR1_RE BIT(2) ++#define USART_CR1_TE BIT(3) ++#define USART_CR1_IDLEIE BIT(4) ++#define USART_CR1_RXNEIE BIT(5) ++#define USART_CR1_TCIE BIT(6) ++#define USART_CR1_TXEIE BIT(7) ++#define USART_CR1_PEIE BIT(8) ++#define USART_CR1_PS BIT(9) ++#define USART_CR1_PCE BIT(10) ++#define USART_CR1_WAKE BIT(11) ++#define USART_CR1_M (BIT(28) | BIT(12)) ++#define USART_CR1_M0 BIT(12) ++#define USART_CR1_MME BIT(13) ++#define USART_CR1_CMIE BIT(14) ++#define USART_CR1_OVER8 BIT(15) ++#define USART_CR1_DEDT GENMASK(20, 16) ++#define USART_CR1_DEDT_0 BIT(16) ++#define USART_CR1_DEDT_1 BIT(17) ++#define USART_CR1_DEDT_2 BIT(18) ++#define USART_CR1_DEDT_3 BIT(19) ++#define USART_CR1_DEDT_4 BIT(20) ++#define USART_CR1_DEAT GENMASK(25, 21) ++#define USART_CR1_DEAT_0 BIT(21) ++#define USART_CR1_DEAT_1 BIT(22) ++#define USART_CR1_DEAT_2 BIT(23) ++#define USART_CR1_DEAT_3 BIT(24) ++#define USART_CR1_DEAT_4 BIT(25) ++#define USART_CR1_RTOIE BIT(26) ++#define USART_CR1_EOBIE BIT(27) ++#define USART_CR1_M1 BIT(28) ++#define USART_CR1_FIFOEN BIT(29) ++#define USART_CR1_TXFEIE BIT(30) ++#define USART_CR1_RXFFIE BIT(31) ++ ++/* USART_CR2 register fields */ ++#define USART_CR2_SLVEN BIT(0) ++#define USART_CR2_DIS_NSS BIT(3) ++#define USART_CR2_ADDM7 BIT(4) ++#define USART_CR2_LBDL BIT(5) ++#define USART_CR2_LBDIE BIT(6) ++#define USART_CR2_LBCL BIT(8) ++#define USART_CR2_CPHA BIT(9) ++#define USART_CR2_CPOL BIT(10) ++#define USART_CR2_CLKEN BIT(11) ++#define USART_CR2_STOP GENMASK(13, 12) ++#define USART_CR2_STOP_0 BIT(12) ++#define USART_CR2_STOP_1 BIT(13) ++#define USART_CR2_LINEN BIT(14) ++#define USART_CR2_SWAP BIT(15) ++#define USART_CR2_RXINV BIT(16) ++#define USART_CR2_TXINV BIT(17) ++#define USART_CR2_DATAINV BIT(18) ++#define USART_CR2_MSBFIRST BIT(19) ++#define USART_CR2_ABREN BIT(20) ++#define USART_CR2_ABRMODE GENMASK(22, 21) ++#define USART_CR2_ABRMODE_0 BIT(21) ++#define USART_CR2_ABRMODE_1 BIT(22) ++#define USART_CR2_RTOEN BIT(23) ++#define USART_CR2_ADD GENMASK(31, 24) ++ ++/* USART_CR3 register fields */ ++#define USART_CR3_EIE BIT(0) ++#define USART_CR3_IREN BIT(1) ++#define USART_CR3_IRLP BIT(2) ++#define USART_CR3_HDSEL BIT(3) ++#define USART_CR3_NACK BIT(4) ++#define USART_CR3_SCEN BIT(5) ++#define USART_CR3_DMAR BIT(6) ++#define USART_CR3_DMAT BIT(7) ++#define USART_CR3_RTSE BIT(8) ++#define USART_CR3_CTSE BIT(9) ++#define USART_CR3_CTSIE BIT(10) ++#define USART_CR3_ONEBIT BIT(11) ++#define USART_CR3_OVRDIS BIT(12) ++#define USART_CR3_DDRE BIT(13) ++#define USART_CR3_DEM BIT(14) ++#define USART_CR3_DEP BIT(15) ++#define USART_CR3_SCARCNT GENMASK(19, 17) ++#define USART_CR3_SCARCNT_0 BIT(17) ++#define USART_CR3_SCARCNT_1 BIT(18) ++#define USART_CR3_SCARCNT_2 BIT(19) ++#define USART_CR3_WUS GENMASK(21, 20) ++#define USART_CR3_WUS_0 BIT(20) ++#define USART_CR3_WUS_1 BIT(21) ++#define USART_CR3_WUFIE BIT(22) ++#define USART_CR3_TXFTIE BIT(23) ++#define USART_CR3_TCBGTIE BIT(24) ++#define USART_CR3_RXFTCFG GENMASK(27, 25) ++#define USART_CR3_RXFTCFG_0 BIT(25) ++#define USART_CR3_RXFTCFG_1 BIT(26) ++#define USART_CR3_RXFTCFG_2 BIT(27) ++#define USART_CR3_RXFTIE BIT(28) ++#define USART_CR3_TXFTCFG GENMASK(31, 29) ++#define USART_CR3_TXFTCFG_0 BIT(29) ++#define USART_CR3_TXFTCFG_1 BIT(30) ++#define USART_CR3_TXFTCFG_2 BIT(31) ++ ++/* USART_BRR register fields */ ++#define USART_BRR_DIV_FRACTION GENMASK(3, 0) ++#define USART_BRR_DIV_MANTISSA GENMASK(15, 4) ++ ++/* USART_GTPR register fields */ ++#define USART_GTPR_PSC GENMASK(7, 0) ++#define USART_GTPR_GT GENMASK(15, 8) ++ ++/* USART_RTOR register fields */ ++#define USART_RTOR_RTO GENMASK(23, 0) ++#define USART_RTOR_BLEN GENMASK(31, 24) ++ ++/* USART_RQR register fields */ ++#define USART_RQR_ABRRQ BIT(0) ++#define USART_RQR_SBKRQ BIT(1) ++#define USART_RQR_MMRQ BIT(2) ++#define USART_RQR_RXFRQ BIT(3) ++#define USART_RQR_TXFRQ BIT(4) ++ ++/* USART_ISR register fields */ ++#define USART_ISR_PE BIT(0) ++#define USART_ISR_FE BIT(1) ++#define USART_ISR_NE BIT(2) ++#define USART_ISR_ORE BIT(3) ++#define USART_ISR_IDLE BIT(4) ++#define USART_ISR_RXNE BIT(5) ++#define USART_ISR_TC BIT(6) ++#define USART_ISR_TXE BIT(7) ++#define USART_ISR_LBDF BIT(8) ++#define USART_ISR_CTSIF BIT(9) ++#define USART_ISR_CTS BIT(10) ++#define USART_ISR_RTOF BIT(11) ++#define USART_ISR_EOBF BIT(12) ++#define USART_ISR_UDR BIT(13) ++#define USART_ISR_ABRE BIT(14) ++#define USART_ISR_ABRF BIT(15) ++#define USART_ISR_BUSY BIT(16) ++#define USART_ISR_CMF BIT(17) ++#define USART_ISR_SBKF BIT(18) ++#define USART_ISR_RWU BIT(19) ++#define USART_ISR_WUF BIT(20) ++#define USART_ISR_TEACK BIT(21) ++#define USART_ISR_REACK BIT(22) ++#define USART_ISR_TXFE BIT(23) ++#define USART_ISR_RXFF BIT(24) ++#define USART_ISR_TCBGT BIT(25) ++#define USART_ISR_RXFT BIT(26) ++#define USART_ISR_TXFT BIT(27) ++ ++/* USART_ICR register fields */ ++#define USART_ICR_PECF BIT(0) ++#define USART_ICR_FECF BIT(1) ++#define USART_ICR_NCF BIT(2) ++#define USART_ICR_ORECF BIT(3) ++#define USART_ICR_IDLECF BIT(4) ++#define USART_ICR_TCCF BIT(6) ++#define USART_ICR_TCBGT BIT(7) ++#define USART_ICR_LBDCF BIT(8) ++#define USART_ICR_CTSCF BIT(9) ++#define USART_ICR_RTOCF BIT(11) ++#define USART_ICR_EOBCF BIT(12) ++#define USART_ICR_UDRCF BIT(13) ++#define USART_ICR_CMCF BIT(17) ++#define USART_ICR_WUCF BIT(20) ++ ++/* USART_RDR register fields */ ++#define USART_RDR_RDR GENMASK(8, 0) ++ ++/* USART_TDR register fields */ ++#define USART_TDR_TDR GENMASK(8, 0) ++ ++/* USART_PRESC register fields */ ++#define USART_PRESC_PRESCALER GENMASK(3, 0) ++ ++#endif /* STM32_UART_REGS_H */ +diff --git a/include/drivers/st/stm32mp1_clk.h b/include/drivers/st/stm32mp1_clk.h +index 85a1eb8..0c8583a 100644 +--- a/include/drivers/st/stm32mp1_clk.h ++++ b/include/drivers/st/stm32mp1_clk.h +@@ -4,27 +4,72 @@ + * SPDX-License-Identifier: BSD-3-Clause + */ + +-#ifndef __STM32MP1_CLK_H__ +-#define __STM32MP1_CLK_H__ ++#ifndef STM32MP1_CLK_H ++#define STM32MP1_CLK_H + +-#include + #include ++#include ++ ++#include + + int stm32mp1_clk_probe(void); + int stm32mp1_clk_init(void); ++ ++bool stm32mp1_rcc_is_secure(void); ++bool stm32mp1_rcc_is_mckprot(void); ++ ++void __stm32mp1_clk_enable(unsigned long id, bool caller_is_secure); ++void __stm32mp1_clk_disable(unsigned long id, bool caller_is_secure); + bool stm32mp1_clk_is_enabled(unsigned long id); +-int stm32mp1_clk_enable(unsigned long id); +-int stm32mp1_clk_disable(unsigned long id); +-unsigned long stm32mp1_clk_get_rate(unsigned long id); +-void stm32mp1_stgen_increment(unsigned long long offset_in_ms); + +-static inline uint32_t get_timer(uint32_t base) ++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) + { +- if (base == 0U) { +- return (uint32_t)(~read_cntpct_el0()); +- } ++ __stm32mp1_clk_disable(id, false); ++} + +- return base - (uint32_t)(~read_cntpct_el0()); ++static inline void stm32mp1_clk_disable_secure(unsigned long id) ++{ ++ __stm32mp1_clk_disable(id, true); + } + +-#endif /* __STM32MP1_CLK_H__ */ ++unsigned int stm32mp1_clk_get_refcount(unsigned long id); ++ ++unsigned long stm32mp_clk_get_rate(unsigned long id); ++unsigned long stm32mp_clk_timer_get_rate(unsigned long id); ++ ++void stm32mp1_stgen_increment(unsigned long long offset_in_ms); ++ ++bool stm32mp1_rtc_get_read_twice(void); ++ ++/* SMP protection on RCC registers access */ ++void stm32mp1_clk_rcc_regs_lock(void); ++void stm32mp1_clk_rcc_regs_unlock(void); ++ ++unsigned long stm32mp1_clk_rcc2id(unsigned int offset, unsigned int bit); ++ ++#if defined(IMAGE_BL32) ++bool stm32mp1_rcc_get_wakeup(void); ++void stm32mp1_rcc_set_wakeup(bool state); ++void stm32mp1_rcc_it_handler(uint32_t id); ++int stm32mp1_rcc_start_hsi_cal(void); ++int stm32mp1_rcc_start_csi_cal(void); ++void stm32mp1_cal_init(void); ++#endif ++ ++void stm32mp1_rcc_init_late(void); ++ ++void stm32mp1_register_clock_parents_secure(unsigned long id); ++ ++void stm32mp1_update_earlyboot_clocks_state(void); ++ ++#endif /* STM32MP1_CLK_H */ +diff --git a/include/drivers/st/stm32mp1_clkfunc.h b/include/drivers/st/stm32mp1_clkfunc.h +index 635a9cd..b488478 100644 +--- a/include/drivers/st/stm32mp1_clkfunc.h ++++ b/include/drivers/st/stm32mp1_clkfunc.h +@@ -4,9 +4,10 @@ + * SPDX-License-Identifier: BSD-3-Clause + */ + +-#ifndef __STM32MP1_CLKFUNC_H__ +-#define __STM32MP1_CLKFUNC_H__ ++#ifndef STM32MP1_CLKFUNC_H ++#define STM32MP1_CLKFUNC_H + ++#include + #include + + enum stm32mp_osc_id { +@@ -16,7 +17,6 @@ enum stm32mp_osc_id { + _LSI, + _LSE, + _I2S_CKIN, +- _USB_PHY_48, + NB_OSC, + _UNKNOWN_OSC_ID = 0xFF + }; +@@ -29,14 +29,6 @@ uint32_t fdt_osc_read_uint32_default(enum stm32mp_osc_id osc_id, + const char *prop_name, + uint32_t dflt_value); + +-uint32_t fdt_rcc_read_addr(void); +-int fdt_rcc_read_uint32_array(const char *prop_name, +- uint32_t *array, uint32_t count); +-int fdt_rcc_subnode_offset(const char *name); +-const uint32_t *fdt_rcc_read_prop(const char *prop_name, int *lenp); +-bool fdt_get_rcc_secure_status(void); ++int fdt_rcc_enable_it(const char *name); + +-uintptr_t fdt_get_stgen_base(void); +-int fdt_get_clock_id(int node); +- +-#endif /* __STM32MP1_CLKFUNC_H__ */ ++#endif /* STM32MP1_CLKFUNC_H */ +diff --git a/include/drivers/st/stm32mp1_ddr.h b/include/drivers/st/stm32mp1_ddr.h +index 0765664..b2773b0 100644 +--- a/include/drivers/st/stm32mp1_ddr.h ++++ b/include/drivers/st/stm32mp1_ddr.h +@@ -4,8 +4,8 @@ + * SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause + */ + +-#ifndef _STM32MP1_DDR_H +-#define _STM32MP1_DDR_H ++#ifndef STM32MP1_DDR_H ++#define STM32MP1_DDR_H + + #include + +@@ -152,7 +152,7 @@ struct stm32mp1_ddrphy_cal { + + struct stm32mp1_ddr_info { + const char *name; +- uint16_t speed; /* in MHZ */ ++ uint32_t speed; /* in kHZ */ + uint32_t size; /* Memory size in byte = col * row * width */ + }; + +@@ -165,9 +165,12 @@ struct stm32mp1_ddr_config { + struct stm32mp1_ddrphy_reg p_reg; + struct stm32mp1_ddrphy_timing p_timing; + struct stm32mp1_ddrphy_cal p_cal; ++ bool self_refresh; ++ uint32_t zdata; + }; + +-int stm32mp1_ddr_clk_enable(struct ddr_info *priv, uint16_t mem_speed); ++int stm32mp1_ddr_clk_enable(struct ddr_info *priv, uint32_t mem_speed); + void stm32mp1_ddr_init(struct ddr_info *priv, + struct stm32mp1_ddr_config *config); +-#endif /* _STM32MP1_DDR_H */ ++ ++#endif /* STM32MP1_DDR_H */ +diff --git a/include/drivers/st/stm32mp1_ddr_helpers.h b/include/drivers/st/stm32mp1_ddr_helpers.h +index 298a080..ecc14d2 100644 +--- a/include/drivers/st/stm32mp1_ddr_helpers.h ++++ b/include/drivers/st/stm32mp1_ddr_helpers.h +@@ -4,9 +4,17 @@ + * SPDX-License-Identifier: BSD-3-Clause + */ + +-#ifndef __STM32MP1_DDR_HELPERS_H__ +-#define __STM32MP1_DDR_HELPERS_H__ ++#ifndef STM32MP1_DDR_HELPERS_H ++#define STM32MP1_DDR_HELPERS_H ++ ++#include + + void ddr_enable_clock(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); ++bool ddr_is_nonsecured_area(uintptr_t address, uint32_t length); + +-#endif /* __STM32MP1_DDR_HELPERS_H__ */ ++#endif /* STM32MP1_DDR_HELPERS_H */ +diff --git a/include/drivers/st/stm32mp1_ddr_regs.h b/include/drivers/st/stm32mp1_ddr_regs.h +index 64ad965..e928688 100644 +--- a/include/drivers/st/stm32mp1_ddr_regs.h ++++ b/include/drivers/st/stm32mp1_ddr_regs.h +@@ -4,9 +4,10 @@ + * SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause + */ + +-#ifndef _RAM_STM32MP1_DDR_REGS_H +-#define _RAM_STM32MP1_DDR_REGS_H ++#ifndef STM32MP1_DDR_REGS_H ++#define STM32MP1_DDR_REGS_H + ++#include + #include + + /* DDR3/LPDDR2/LPDDR3 Controller (DDRCTRL) registers */ +@@ -247,11 +248,14 @@ struct stm32mp1_ddrphy { + #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(13, 12) + #define DDRCTRL_MSTR_DATA_BUS_WIDTH_FULL 0 + #define DDRCTRL_MSTR_DATA_BUS_WIDTH_HALF BIT(12) +@@ -269,7 +273,7 @@ struct stm32mp1_ddrphy { + /* Only one rank supported */ + #define DDRCTRL_MRCTRL0_MR_RANK_SHIFT 4 + #define DDRCTRL_MRCTRL0_MR_RANK_ALL \ +- (0x1U << DDRCTRL_MRCTRL0_MR_RANK_SHIFT) ++ BIT(DDRCTRL_MRCTRL0_MR_RANK_SHIFT) + #define DDRCTRL_MRCTRL0_MR_ADDR_SHIFT 12 + #define DDRCTRL_MRCTRL0_MR_ADDR_MASK GENMASK(15, 12) + #define DDRCTRL_MRCTRL0_MR_WR BIT(31) +@@ -367,6 +371,7 @@ struct stm32mp1_ddrphy { + + #define DDRPHYC_DLLGCR_BPS200 BIT(23) + ++#define DDRPHYC_ACDLLCR_DLLSRST BIT(30) + #define DDRPHYC_ACDLLCR_DLLDIS BIT(31) + + #define DDRPHYC_PTR0_TDLLSRST_OFFSET 0 +@@ -408,6 +413,4 @@ struct stm32mp1_ddrphy { + #define DDRPHYC_DXNDLLCR_SDPHASE_MASK GENMASK(17, 14) + #define DDRPHYC_DXNDLLCR_SDPHASE_SHIFT 14 + +-void ddr_enable_clock(void); +- +-#endif /* _RAM_STM32MP1_DDR_REGS_H */ ++#endif /* STM32MP1_DDR_REGS_H */ +diff --git a/include/drivers/st/stm32mp1_pmic.h b/include/drivers/st/stm32mp1_pmic.h +deleted file mode 100644 +index 5d94b40..0000000 +--- a/include/drivers/st/stm32mp1_pmic.h ++++ /dev/null +@@ -1,18 +0,0 @@ +-/* +- * Copyright (c) 2017-2018, STMicroelectronics - All Rights Reserved +- * +- * SPDX-License-Identifier: BSD-3-Clause +- */ +- +-#ifndef __STM32MP1_PMIC_H__ +-#define __STM32MP1_PMIC_H__ +- +-#include +- +-bool dt_check_pmic(void); +-int dt_pmic_enable_boot_on_regulators(void); +-void initialize_pmic_i2c(void); +-void initialize_pmic(void); +-int pmic_ddr_power_init(enum ddr_type ddr_type); +- +-#endif /* __STM32MP1_PMIC_H__ */ +diff --git a/include/drivers/st/stm32mp1_pwr.h b/include/drivers/st/stm32mp1_pwr.h +index e567042..1a22824 100644 +--- a/include/drivers/st/stm32mp1_pwr.h ++++ b/include/drivers/st/stm32mp1_pwr.h +@@ -1,11 +1,11 @@ + /* +- * Copyright (c) 2017-2018, STMicroelectronics - All Rights Reserved ++ * Copyright (c) 2017-2019, STMicroelectronics - All Rights Reserved + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +-#ifndef __STM32MP1_PWR_H__ +-#define __STM32MP1_PWR_H__ ++#ifndef STM32MP1_PWR_H ++#define STM32MP1_PWR_H + + #include + +@@ -13,20 +13,43 @@ + #define PWR_CR2 U(0x08) + #define PWR_CR3 U(0x0C) + #define PWR_MPUCR U(0x10) ++#define PWR_MCUCR U(0x14) + #define PWR_WKUPCR U(0x20) + #define PWR_MPUWKUPENR U(0x28) + ++#define PWR_OFFSET_MASK GENMASK(9, 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) + +-#endif /* __STM32MP1_PWR_H__ */ ++#define PWR_MCUCR_PDDS BIT(0) ++ ++#define PWR_WKUPCR_MASK GENMASK(27, 16) | GENMASK(13, 8) | GENMASK(5, 0) ++ ++#define PWR_MPUWKUPENR_MASK GENMASK(5, 0) ++ ++#ifndef __ASSEMBLY__ ++/* SMP protection on PWR registers access */ ++void pwr_regs_lock(void); ++void pwr_regs_unlock(void); ++#endif /* __ASSEMBLY__ */ ++ ++#endif /* STM32MP1_PWR_H */ +diff --git a/include/drivers/st/stm32mp1_ram.h b/include/drivers/st/stm32mp1_ram.h +index af96177..38360e7 100644 +--- a/include/drivers/st/stm32mp1_ram.h ++++ b/include/drivers/st/stm32mp1_ram.h +@@ -4,9 +4,9 @@ + * SPDX-License-Identifier: BSD-3-Clause + */ + +-#ifndef _STM32MP1_RAM_H +-#define _STM32MP1_RAM_H ++#ifndef STM32MP1_RAM_H ++#define STM32MP1_RAM_H + + int stm32mp1_ddr_probe(void); + +-#endif /* _STM32MP1_RAM_H */ ++#endif /* STM32MP1_RAM_H */ +diff --git a/include/drivers/st/stm32mp1_rcc.h b/include/drivers/st/stm32mp1_rcc.h +index e28ca97..7e1b337 100644 +--- a/include/drivers/st/stm32mp1_rcc.h ++++ b/include/drivers/st/stm32mp1_rcc.h +@@ -4,8 +4,8 @@ + * SPDX-License-Identifier: BSD-3-Clause + */ + +-#ifndef __STM32MP1_RCC_H__ +-#define __STM32MP1_RCC_H__ ++#ifndef STM32MP1_RCC_H ++#define STM32MP1_RCC_H + + #include + +@@ -68,6 +68,14 @@ + #define RCC_MP_AHB6ENCLRR U(0x21C) + #define RCC_MP_TZAHB6ENSETR U(0x220) + #define RCC_MP_TZAHB6ENCLRR U(0x224) ++#define RCC_MC_APB4ENSETR U(0x280) ++#define RCC_MC_APB4ENCLRR U(0x284) ++#define RCC_MC_APB5ENSETR U(0x288) ++#define RCC_MC_APB5ENCLRR U(0x28C) ++#define RCC_MC_AHB5ENSETR U(0x290) ++#define RCC_MC_AHB5ENCLRR U(0x294) ++#define RCC_MC_AHB6ENSETR U(0x298) ++#define RCC_MC_AHB6ENCLRR U(0x29C) + #define RCC_MP_APB4LPENSETR U(0x300) + #define RCC_MP_APB4LPENCLRR U(0x304) + #define RCC_MP_APB5LPENSETR U(0x308) +@@ -78,6 +86,14 @@ + #define RCC_MP_AHB6LPENCLRR U(0x31C) + #define RCC_MP_TZAHB6LPENSETR U(0x320) + #define RCC_MP_TZAHB6LPENCLRR U(0x324) ++#define RCC_MC_APB4LPENSETR U(0x380) ++#define RCC_MC_APB4LPENCLRR U(0x384) ++#define RCC_MC_APB5LPENSETR U(0x388) ++#define RCC_MC_APB5LPENCLRR U(0x38C) ++#define RCC_MC_AHB5LPENSETR U(0x390) ++#define RCC_MC_AHB5LPENCLRR U(0x394) ++#define RCC_MC_AHB6LPENSETR U(0x398) ++#define RCC_MC_AHB6LPENCLRR U(0x39C) + #define RCC_BR_RSTSCLRR U(0x400) + #define RCC_MP_GRSTCSETR U(0x404) + #define RCC_MP_RSTSCLRR U(0x408) +@@ -95,6 +111,7 @@ + #define RCC_RCK4SELR U(0x824) + #define RCC_TIMG1PRER U(0x828) + #define RCC_TIMG2PRER U(0x82C) ++#define RCC_MCUDIVR U(0x830) + #define RCC_APB1DIVR U(0x834) + #define RCC_APB2DIVR U(0x838) + #define RCC_APB3DIVR U(0x83C) +@@ -162,6 +179,22 @@ + #define RCC_MP_AHB4ENCLRR U(0xA2C) + #define RCC_MP_MLAHBENSETR U(0xA38) + #define RCC_MP_MLAHBENCLRR U(0xA3C) ++#define RCC_MC_APB1ENSETR U(0xA80) ++#define RCC_MC_APB1ENCLRR U(0xA84) ++#define RCC_MC_APB2ENSETR U(0xA88) ++#define RCC_MC_APB2ENCLRR U(0xA8C) ++#define RCC_MC_APB3ENSETR U(0xA90) ++#define RCC_MC_APB3ENCLRR U(0xA94) ++#define RCC_MC_AHB2ENSETR U(0xA98) ++#define RCC_MC_AHB2ENCLRR U(0xA9C) ++#define RCC_MC_AHB3ENSETR U(0xAA0) ++#define RCC_MC_AHB3ENCLRR U(0xAA4) ++#define RCC_MC_AHB4ENSETR U(0xAA8) ++#define RCC_MC_AHB4ENCLRR U(0xAAC) ++#define RCC_MC_AXIMENSETR U(0xAB0) ++#define RCC_MC_AXIMENCLRR U(0xAB4) ++#define RCC_MC_MLAHBENSETR U(0xAB8) ++#define RCC_MC_MLAHBENCLRR U(0xABC) + #define RCC_MP_APB1LPENSETR U(0xB00) + #define RCC_MP_APB1LPENCLRR U(0xB04) + #define RCC_MP_APB2LPENSETR U(0xB08) +@@ -178,12 +211,34 @@ + #define RCC_MP_AXIMLPENCLRR U(0xB34) + #define RCC_MP_MLAHBLPENSETR U(0xB38) + #define RCC_MP_MLAHBLPENCLRR U(0xB3C) ++#define RCC_MC_APB1LPENSETR U(0xB80) ++#define RCC_MC_APB1LPENCLRR U(0xB84) ++#define RCC_MC_APB2LPENSETR U(0xB88) ++#define RCC_MC_APB2LPENCLRR U(0xB8C) ++#define RCC_MC_APB3LPENSETR U(0xB90) ++#define RCC_MC_APB3LPENCLRR U(0xB94) ++#define RCC_MC_AHB2LPENSETR U(0xB98) ++#define RCC_MC_AHB2LPENCLRR U(0xB9C) ++#define RCC_MC_AHB3LPENSETR U(0xBA0) ++#define RCC_MC_AHB3LPENCLRR U(0xBA4) ++#define RCC_MC_AHB4LPENSETR U(0xBA8) ++#define RCC_MC_AHB4LPENCLRR U(0xBAC) ++#define RCC_MC_AXIMLPENSETR U(0xBB0) ++#define RCC_MC_AXIMLPENCLRR U(0xBB4) ++#define RCC_MC_MLAHBLPENSETR U(0xBB8) ++#define RCC_MC_MLAHBLPENCLRR U(0xBBC) ++#define RCC_MC_RSTSCLRR U(0xC00) ++#define RCC_MC_CIER U(0xC14) ++#define RCC_MC_CIFR U(0xC18) + #define RCC_VERR U(0xFF4) + #define RCC_IDR U(0xFF8) + #define RCC_SIDR U(0xFFC) + ++#define RCC_OFFSET_MASK GENMASK(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(2, 0) +@@ -220,6 +275,10 @@ + #define RCC_APBXDIV_MASK GENMASK(2, 0) + #define RCC_MPUDIV_MASK GENMASK(2, 0) + #define RCC_AXIDIV_MASK GENMASK(2, 0) ++#define RCC_MCUDIV_MASK GENMASK(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 U(4) +@@ -228,6 +287,7 @@ + #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(5, 4) + #define RCC_BDCR_LSEDRV_SHIFT 4 + #define RCC_BDCR_LSECSSON BIT(8) +@@ -243,6 +303,7 @@ + /* 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) +@@ -281,8 +342,12 @@ + + /* 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) + +@@ -319,6 +384,16 @@ + + /* Fields of RCC_HSICFGR register */ + #define RCC_HSICFGR_HSIDIV_MASK GENMASK(1, 0) ++#define RCC_HSICFGR_HSITRIM_SHIFT 8 ++#define RCC_HSICFGR_HSITRIM_MASK GENMASK(14, 8) ++#define RCC_HSICFGR_HSICAL_SHIFT 16 ++#define RCC_HSICFGR_HSICAL_MASK GENMASK(27, 16) ++ ++/* Fields of RCC_CSICFGR register */ ++#define RCC_CSICFGR_CSITRIM_SHIFT 8 ++#define RCC_CSICFGR_CSITRIM_MASK GENMASK(12, 8) ++#define RCC_CSICFGR_CSICAL_SHIFT 16 ++#define RCC_CSICFGR_CSICAL_MASK GENMASK(23, 16) + + /* Used for RCC_MCO related operations */ + #define RCC_MCOCFG_MCOON BIT(12) +@@ -330,22 +405,37 @@ + #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_IWDG1RSTF BIT(8) +-#define RCC_MP_RSTSCLRR_IWDG2RSTF BIT(9) +-#define RCC_MP_RSTSCLRR_STDBYRSTF BIT(11) +-#define RCC_MP_RSTSCLRR_CSTDBYRSTF BIT(12) ++#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) ++#define RCC_MP_RSTSCLRR_MPUP0RSTF BIT(13) ++#define RCC_MP_RSTSCLRR_MPUP1RSTF BIT(14) + + /* 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_MASK U(0x110F1F) ++#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_WKUPF BIT(20) + + /* Stop Request Set Register */ +@@ -362,7 +452,29 @@ + /* Values of RCC_MP_APB1ENSETR register */ + #define RCC_MP_APB1ENSETR_UART4EN BIT(16) + ++/* Values of RCC_MP_APB5ENSETR register */ ++#define RCC_MP_APB5ENSETR_SPI6EN BIT(0) ++#define RCC_MP_APB5ENSETR_I2C4EN BIT(2) ++#define RCC_MP_APB5ENSETR_I2C6EN BIT(3) ++#define RCC_MP_APB5ENSETR_USART1EN BIT(4) ++#define RCC_MP_APB5ENSETR_RTCAPBEN BIT(8) ++#define RCC_MP_APB5ENSETR_IWDG1APBEN BIT(15) ++ + /* Values of RCC_MP_AHB4ENSETR register */ + #define RCC_MP_AHB4ENSETR_GPIOGEN BIT(6) ++#define RCC_MP_AHB4ENSETR_GPIOHEN BIT(7) ++ ++/* Values of RCC_MP_AHB5ENSETR register */ ++#define RCC_MP_AHB5ENSETR_GPIOZEN BIT(0) ++#define RCC_MP_AHB5ENSETR_CRYP1EN BIT(4) ++#define RCC_MP_AHB5ENSETR_HASH1EN BIT(5) ++#define RCC_MP_AHB5ENSETR_RNG1EN BIT(6) ++ ++/* Values of RCC_MP_IWDGFZSETR register */ ++#define RCC_MP_IWDGFZSETR_IWDG1 BIT(0) ++#define RCC_MP_IWDGFZSETR_IWDG2 BIT(1) ++ ++/* Values of RCC_PWRLPDLYCR register */ ++#define RCC_PWRLPDLYCR_PWRLP_DLY_MASK GENMASK(21, 0) + +-#endif /* __STM32MP1_RCC_H__ */ ++#endif /* STM32MP1_RCC_H */ +diff --git a/include/drivers/st/stm32mp1_reset.h b/include/drivers/st/stm32mp1_reset.h +deleted file mode 100644 +index 76ee09d..0000000 +--- a/include/drivers/st/stm32mp1_reset.h ++++ /dev/null +@@ -1,15 +0,0 @@ +-/* +- * Copyright (c) 2018, STMicroelectronics - All Rights Reserved +- * +- * SPDX-License-Identifier: BSD-3-Clause +- */ +- +-#ifndef __STM32MP1_RESET_H__ +-#define __STM32MP1_RESET_H__ +- +-#include +- +-void stm32mp1_reset_assert(uint32_t reset_id); +-void stm32mp1_reset_deassert(uint32_t reset_id); +- +-#endif /* __STM32MP1_RESET_H__ */ +diff --git a/include/drivers/st/stm32mp1xx_hal.h b/include/drivers/st/stm32mp1xx_hal.h +new file mode 100644 +index 0000000..5e4f9e7 +--- /dev/null ++++ b/include/drivers/st/stm32mp1xx_hal.h +@@ -0,0 +1,203 @@ ++/* ++ * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved. ++ * ++ * SPDX-License-Identifier: BSD-3-Clause ++ */ ++ ++#ifndef __STM32_HAL_H ++#define __STM32_HAL_H ++ ++#include ++#include ++#include ++#include ++#include ++ ++typedef enum { ++ HAL_OK = 0x00, ++ HAL_ERROR = 0x01, ++ HAL_BUSY = 0x02, ++ HAL_TIMEOUT = 0x03 ++} HAL_StatusTypeDef; ++ ++typedef enum { ++ HAL_UNLOCKED = 0x00, ++ HAL_LOCKED = 0x01 ++} HAL_LockTypeDef; ++ ++typedef enum { ++ RESET = 0, ++ SET = !RESET ++} FlagStatus, ITStatus; ++ ++typedef uint32_t Std_ReturnType; ++ ++#define STD_OK ((uint32_t)0x77) ++#define STD_NOT_OK ((uint32_t)0x66) ++ ++#define WRITE_REG(REG, VAL) ((REG) = (VAL)) ++#define READ_REG(REG) ((REG)) ++#define MODIFY_REG(REG, CLEARMASK, SETMASK) \ ++ WRITE_REG((REG), (((READ_REG(REG)) & (~(CLEARMASK))) | (SETMASK))) ++ ++#define HAL_IS_BIT_SET(REG, BIT) (((REG) & (BIT)) != RESET) ++#define HAL_IS_BIT_CLR(REG, BIT) (((REG) & (BIT)) == RESET) ++ ++#define SET_BIT(_reg, _val) mmio_setbits_32((uintptr_t)&(_reg), _val) ++#define CLEAR_BIT(_reg, _val) mmio_clrbits_32((uintptr_t)&(_reg), _val) ++ ++#define __IO volatile /*!< Defines 'read / write' permissions */ ++#define __I volatile const /*!< Defines 'read only' permissions */ ++ ++#define HAL_MAX_DELAY 0xFFFFFFFF ++ ++#define assert_param(expr) ((void)0) ++ ++#define HAL_GetTick() (uint32_t)read_cntpct_el0() ++ ++static inline void HAL_Delay(uint32_t x) ++{ ++ udelay(x); ++} ++ ++/** ++ * @brief Universal Synchronous Asynchronous Receiver Transmitter ++ */ ++ ++typedef struct { ++ __IO uint32_t CR1; /*!< USART Control register 1, Address offset: 0x00 */ ++ __IO uint32_t CR2; /*!< USART Control register 2, Address offset: 0x04 */ ++ __IO uint32_t CR3; /*!< USART Control register 3, Address offset: 0x08 */ ++ __IO uint32_t BRR; /*!< USART Baud rate register, Address offset: 0x0C */ ++ __IO uint16_t GTPR; /*!< USART Guard time and prescaler register, Address offset: 0x10 */ ++ uint16_t RESERVED2; /*!< Reserved, 0x12 */ ++ __IO uint32_t RTOR; /*!< USART Receiver Time Out register, Address offset: 0x14 */ ++ __IO uint16_t RQR; /*!< USART Request register, Address offset: 0x18 */ ++ uint16_t RESERVED3; /*!< Reserved, 0x1A */ ++ __IO uint32_t ISReg; /*!< USART Interrupt and status register, Address offset: 0x1C */ ++ __IO uint32_t ICR; /*!< USART Interrupt flag Clear register, Address offset: 0x20 */ ++ __IO uint16_t RDR; /*!< USART Receive Data register, Address offset: 0x24 */ ++ uint16_t RESERVED4; /*!< Reserved, 0x26 */ ++ __IO uint16_t TDR; /*!< USART Transmit Data register, Address offset: 0x28 */ ++ uint16_t RESERVED5; /*!< Reserved, 0x2A */ ++ __IO uint32_t PRESC; /*!< USART clock Prescaler register, Address offset: 0x2C */ ++} USART_TypeDef; ++ ++typedef struct { ++ __IO uint32_t POWER; /*!< SDMMC power control register, Address offset: 0x00 */ ++ __IO uint32_t CLKCR; /*!< SDMMC clock control register, Address offset: 0x04 */ ++ __IO uint32_t ARG; /*!< SDMMC argument register, Address offset: 0x08 */ ++ __IO uint32_t CMD; /*!< SDMMC command register, Address offset: 0x0C */ ++ __I uint32_t RESPCMD; /*!< SDMMC command response register, Address offset: 0x10 */ ++ __I uint32_t RESP1; /*!< SDMMC response 1 register, Address offset: 0x14 */ ++ __I uint32_t RESP2; /*!< SDMMC response 2 register, Address offset: 0x18 */ ++ __I uint32_t RESP3; /*!< SDMMC response 3 register, Address offset: 0x1C */ ++ __I uint32_t RESP4; /*!< SDMMC response 4 register, Address offset: 0x20 */ ++ __IO uint32_t DTIMER; /*!< SDMMC data timer register, Address offset: 0x24 */ ++ __IO uint32_t DLEN; /*!< SDMMC data length register, Address offset: 0x28 */ ++ __IO uint32_t DCTRL; /*!< SDMMC data control register, Address offset: 0x2C */ ++ __I uint32_t DCOUNT; /*!< SDMMC data counter register, Address offset: 0x30 */ ++ __I uint32_t STA; /*!< SDMMC status register, Address offset: 0x34 */ ++ __IO uint32_t ICR; /*!< SDMMC interrupt clear register, Address offset: 0x38 */ ++ __IO uint32_t MASK; /*!< SDMMC mask register, Address offset: 0x3C */ ++ __IO uint32_t ACKTIME; /*!< SDMMC Acknowledgment timer register, Address offset: 0x40 */ ++ uint32_t RESERVED0[3]; /*!< Reserved, 0x44 - 0x4C - 0x4C */ ++ __IO uint32_t IDMACTRL; /*!< SDMMC DMA control register, Address offset: 0x50 */ ++ __IO uint32_t IDMABSIZE; /*!< SDMMC DMA buffer size register, Address offset: 0x54 */ ++ __IO uint32_t IDMABASE0; /*!< SDMMC DMA buffer 0 base address register, Address offset: 0x58 */ ++ __IO uint32_t IDMABASE1; /*!< SDMMC DMA buffer 1 base address register, Address offset: 0x5C */ ++ uint32_t RESERVED1[8]; /*!< Reserved, 0x4C-0x7C */ ++ __IO uint32_t FIFO; /*!< SDMMC data FIFO register, Address offset: 0x80 */ ++} SDMMC_TypeDef; ++ ++typedef struct ++{ ++ __IO uint32_t BCR1; /*!< Address offset: 0x00 */ ++ __IO uint32_t BTR1; /*!< Address offset: 0x04 */ ++ __IO uint32_t BCR2; /*!< Address offset: 0x08 */ ++ __IO uint32_t BTR2; /*!< Address offset: 0x0C */ ++ __IO uint32_t BCR3; /*!< Address offset: 0x10 */ ++ __IO uint32_t BTR3; /*!< Address offset: 0x14 */ ++ __IO uint32_t BCR4; /*!< Address offset: 0x18 */ ++ __IO uint32_t BTR4; /*!< Address offset: 0x1C */ ++ uint32_t RESERVED0[24]; ++ __IO uint32_t PCReg; /*!< Address offset: 0x80 */ ++ __IO uint32_t SR; /*!< Address offset: 0x84 */ ++ __IO uint32_t PMEM; /*!< Address offset: 0x88 */ ++ __IO uint32_t PATT; /*!< Address offset: 0x8C */ ++ __IO uint32_t HPR; /*! Address offset: 0x90 */ ++ __IO uint32_t HECCR; /*!< Address offset: 0x94 */ ++ uint32_t RESERVED2[27]; ++ __IO uint32_t BWTR1; /*!< Address offset: 0x104 */ ++ uint32_t RESERVED3; ++ __IO uint32_t BWTR2; /*!< Address offset: 0x10C */ ++ uint32_t RESERVED4; ++ __IO uint32_t BWTR3; /*!< Address offset: 0x114 */ ++ uint32_t RESERVED5; ++ __IO uint32_t BWTR4; /*!< Address offset: 0x11c */ ++ uint32_t RESERVED6[8]; ++ __IO uint32_t SDCR1; /*!< Address offset: 0x140 */ ++ __IO uint32_t SDCR2; /*!< Address offset: 0x144 */ ++ __IO uint32_t SDTR1; /*!< Address offset: 0x148 */ ++ __IO uint32_t SDTR2; /*!< Address offset: 0x14c */ ++ __IO uint32_t SDCMR; /*!< Address offset: 0x150 */ ++ __IO uint32_t SDRTR; /*!< Address offset: 0x154 */ ++ __IO uint32_t SDSR; /*!< Address offset: 0x158 */ ++ uint32_t RESERVED7[9]; ++ __IO uint32_t IER; /*!< Address offset: 0x180 */ ++ __IO uint32_t ISReg; /*!< Address offset: 0x184 */ ++ __IO uint32_t ICR; /*!< Address offset: 0x188 */ ++ uint32_t RESERVED8[29]; ++ __IO uint32_t CSQCR; /*!< Address offset: 0x200 */ ++ __IO uint32_t CSQCFGR1; /*!< Address offset: 0x204 */ ++ __IO uint32_t CSQCFGR2; /*!< Address offset: 0x208 */ ++ __IO uint32_t CSQCFGR3; /*!< Address offset: 0x20c */ ++ __IO uint32_t CSQAR1; /*!< Address offset: 0x210 */ ++ __IO uint32_t CSQAR2; /*!< Address offset: 0x214 */ ++ uint32_t RESERVED9[2]; ++ __IO uint32_t CSQIER; /*!< Address offset: 0x220 */ ++ __IO uint32_t CSQISR; /*!< Address offset: 0x224 */ ++ __IO uint32_t CSQICR; /*!< Address offset: 0x228 */ ++ uint32_t RESERVED10; ++ __IO uint32_t CSQEMSR; /*!< Address offset: 0x230 */ ++ uint32_t RESERVED11[7]; ++ __IO uint32_t BCHIER; /*!< Address offset: 0x250 */ ++ __IO uint32_t BCHISR; /*!< Address offset: 0x254 */ ++ __IO uint32_t BCHICR; /*!< Address offset: 0x258 */ ++ __IO uint32_t BCHSR; /*!< Address offset: 0x25c */ ++ __IO uint32_t BCHPBR1; /*!< Address offset: 0x260 */ ++ __IO uint32_t BCHPBR2; /*!< Address offset: 0x264 */ ++ __IO uint32_t BCHPBR3; /*!< Address offset: 0x268 */ ++ __IO uint32_t BCHPBR4; /*!< Address offset: 0x26c */ ++ uint32_t RESERVED12[3]; ++ __IO uint32_t BCHDSR0; /*!< Address offset: 0x27c */ ++ __IO uint32_t BCHDSR1; /*!< Address offset: 0x280 */ ++ __IO uint32_t BCHDSR2; /*!< Address offset: 0x284 */ ++ __IO uint32_t BCHDSR3; /*!< Address offset: 0x288 */ ++ __IO uint32_t BCHDSR4; /*!< Address offset: 0x28c */ ++ uint32_t RESERVED13[347]; ++ __IO uint32_t HWCFGR2; /*!< Address offset: 0x3ec */ ++ __IO uint32_t HWCFGR1; /*!< Address offset: 0x3f0 */ ++ __IO uint32_t VER; /*!< Address offset: 0x3f4 */ ++ __IO uint32_t ID; /*!< Address offset: 0x3f8 */ ++ __IO uint32_t SID; /*!< Address offset: 0x3fc */ ++} FMC_TypeDef; ++ ++#define __HAL_LOCK(__HANDLE__) \ ++ do{ \ ++ if((__HANDLE__)->Lock == HAL_LOCKED) \ ++ { \ ++ return HAL_BUSY; \ ++ } \ ++ else \ ++ { \ ++ (__HANDLE__)->Lock = HAL_LOCKED; \ ++ } \ ++ }while (0) ++ ++ #define __HAL_UNLOCK(__HANDLE__) \ ++ do{ \ ++ (__HANDLE__)->Lock = HAL_UNLOCKED; \ ++ }while (0) ++ ++#endif /*__STM32_HAL_H*/ +diff --git a/include/drivers/st/stm32mp1xx_hal_uart.h b/include/drivers/st/stm32mp1xx_hal_uart.h +new file mode 100644 +index 0000000..b6af232 +--- /dev/null ++++ b/include/drivers/st/stm32mp1xx_hal_uart.h +@@ -0,0 +1,1586 @@ ++/** ++ ****************************************************************************** ++ * @file stm32mp1xx_hal_uart.h ++ * @author MCD Application Team ++ * @version V0.3.0 ++ * @date 14-January-2015 ++ * @brief Header file of UART HAL module. ++ ****************************************************************************** ++ * @attention ++ * ++ *

© COPYRIGHT(c) 2015 STMicroelectronics

++ * ++ * SPDX-License-Identifier: BSD-3-Clause ++ * ++ ****************************************************************************** ++ */ ++ ++/* Define to prevent recursive inclusion -------------------------------------*/ ++#ifndef __STM32MP1xx_HAL_UART_H ++#define __STM32MP1xx_HAL_UART_H ++ ++#ifdef __cplusplus ++ extern "C" { ++#endif ++ ++#define HAL_UART_MODULE_ENABLED ++ ++/* Includes ------------------------------------------------------------------*/ ++#include ++#include ++ ++/** ++ * @brief UART Init Structure definition ++ */ ++typedef struct ++{ ++ uint32_t BaudRate; /*!< This member configures the UART communication baud rate. ++ The baud rate register is computed using the following formula: ++ - If oversampling is 16 or in LIN mode, ++ Baud Rate Register = ((PCLKx) / ((huart->Init.BaudRate))) ++ - If oversampling is 8, ++ Baud Rate Register[15:4] = ((2 * PCLKx) / ((huart->Init.BaudRate)))[15:4] ++ Baud Rate Register[3] = 0 ++ Baud Rate Register[2:0] = (((2 * PCLKx) / ((huart->Init.BaudRate)))[3:0]) >> 1 */ ++ ++ uint32_t WordLength; /*!< Specifies the number of data bits transmitted or received in a frame. ++ This parameter can be a value of @ref UARTEx_Word_Length. */ ++ ++ uint32_t StopBits; /*!< Specifies the number of stop bits transmitted. ++ This parameter can be a value of @ref UART_Stop_Bits. */ ++ ++ uint32_t Parity; /*!< Specifies the parity mode. ++ This parameter can be a value of @ref UART_Parity ++ @note When parity is enabled, the computed parity is inserted ++ at the MSB position of the transmitted data (9th bit when ++ the word length is set to 9 data bits; 8th bit when the ++ word length is set to 8 data bits). */ ++ ++ uint32_t Mode; /*!< Specifies whether the Receive or Transmit mode is enabled or disabled. ++ This parameter can be a value of @ref UART_Mode. */ ++ ++ uint32_t HwFlowCtl; /*!< Specifies whether the hardware flow control mode is enabled ++ or disabled. ++ This parameter can be a value of @ref UART_Hardware_Flow_Control. */ ++ ++ uint32_t OverSampling; /*!< Specifies whether the Over sampling 8 is enabled or disabled, to achieve higher speed (up to f_PCLK/8). ++ This parameter can be a value of @ref UART_Over_Sampling. */ ++ ++ uint32_t OneBitSampling; /*!< Specifies whether a single sample or three samples' majority vote is selected. ++ Selecting the single sample method increases the receiver tolerance to clock ++ deviations. This parameter can be a value of @ref UART_OneBit_Sampling. */ ++ ++ uint32_t Prescaler; /*!< Specifies the prescaler value used to divide the UART clock source. ++ This parameter can be a value of @ref UART_Prescaler. */ ++ ++ uint32_t FIFOMode; /*!< Specifies if the FIFO mode will be used. This parameter can be a value ++ of @ref UART_FIFO_mode. */ ++ ++ uint32_t TXFIFOThreshold; /*!< Specifies the TXFIFO threshold level. ++ This parameter can be a value of @ref UART_TXFIFO_threshold_level. */ ++ ++ uint32_t RXFIFOThreshold; /*!< Specifies the RXFIFO threshold level. ++ This parameter can be a value of @ref UART_RXFIFO_threshold_level. */ ++ ++} UART_InitTypeDef; ++ ++/** ++ * @brief UART Advanced Features initalization structure definition ++ */ ++typedef struct ++{ ++ uint32_t AdvFeatureInit; /*!< Specifies which advanced UART features is initialized. Several ++ Advanced Features may be initialized at the same time . ++ This parameter can be a value of @ref UART_Advanced_Features_Initialization_Type. */ ++ ++ uint32_t TxPinLevelInvert; /*!< Specifies whether the TX pin active level is inverted. ++ This parameter can be a value of @ref UART_Tx_Inv. */ ++ ++ uint32_t RxPinLevelInvert; /*!< Specifies whether the RX pin active level is inverted. ++ This parameter can be a value of @ref UART_Rx_Inv. */ ++ ++ uint32_t DataInvert; /*!< Specifies whether data are inverted (positive/direct logic ++ vs negative/inverted logic). ++ This parameter can be a value of @ref UART_Data_Inv. */ ++ ++ uint32_t Swap; /*!< Specifies whether TX and RX pins are swapped. ++ This parameter can be a value of @ref UART_Rx_Tx_Swap. */ ++ ++ uint32_t OverrunDisable; /*!< Specifies whether the reception overrun detection is disabled. ++ This parameter can be a value of @ref UART_Overrun_Disable. */ ++ ++ uint32_t DMADisableonRxError; /*!< Specifies whether the DMA is disabled in case of reception error. ++ This parameter can be a value of @ref UART_DMA_Disable_on_Rx_Error. */ ++ ++ uint32_t AutoBaudRateEnable; /*!< Specifies whether auto Baud rate detection is enabled. ++ This parameter can be a value of @ref UART_AutoBaudRate_Enable */ ++ ++ uint32_t AutoBaudRateMode; /*!< If auto Baud rate detection is enabled, specifies how the rate ++ detection is carried out. ++ This parameter can be a value of @ref UART_AutoBaud_Rate_Mode. */ ++ ++ uint32_t MSBFirst; /*!< Specifies whether MSB is sent first on UART line. ++ This parameter can be a value of @ref UART_MSB_First. */ ++} UART_AdvFeatureInitTypeDef; ++ ++ ++ ++/** ++ * @brief HAL UART State structures definition ++ * @note HAL UART State value is a combination of 2 different substates: gState and RxState. ++ * - gState contains UART state information related to global Handle management ++ * and also information related to Tx operations. ++ * gState value coding follow below described bitmap : ++ * b7-b6 Error information ++ * 00 : No Error ++ * 01 : (Not Used) ++ * 10 : Timeout ++ * 11 : Error ++ * b5 IP initilisation status ++ * 0 : Reset (IP not initialized) ++ * 1 : Init done (IP not initialized. HAL UART Init function already called) ++ * b4-b3 (not used) ++ * xx : Should be set to 00 ++ * b2 Intrinsic process state ++ * 0 : Ready ++ * 1 : Busy (IP busy with some configuration or internal operations) ++ * b1 (not used) ++ * x : Should be set to 0 ++ * b0 Tx state ++ * 0 : Ready (no Tx operation ongoing) ++ * 1 : Busy (Tx operation ongoing) ++ * - RxState contains information related to Rx operations. ++ * RxState value coding follow below described bitmap : ++ * b7-b6 (not used) ++ * xx : Should be set to 00 ++ * b5 IP initilisation status ++ * 0 : Reset (IP not initialized) ++ * 1 : Init done (IP not initialized) ++ * b4-b2 (not used) ++ * xxx : Should be set to 000 ++ * b1 Rx state ++ * 0 : Ready (no Rx operation ongoing) ++ * 1 : Busy (Rx operation ongoing) ++ * b0 (not used) ++ * x : Should be set to 0. ++ */ ++typedef enum { ++ HAL_UART_STATE_RESET = 0x00U, /*!< Peripheral is not initialized ++ Value is allowed for gState and RxState */ ++ HAL_UART_STATE_READY = 0x20U, /*!< Peripheral Initialized and ready for use ++ Value is allowed for gState and RxState */ ++ HAL_UART_STATE_BUSY = 0x24U, /*!< an internal process is ongoing ++ Value is allowed for gState only */ ++ HAL_UART_STATE_BUSY_TX = 0x21U, /*!< Data Transmission process is ongoing ++ Value is allowed for gState only */ ++ HAL_UART_STATE_BUSY_RX = 0x22U, /*!< Data Reception process is ongoing ++ Value is allowed for RxState only */ ++ HAL_UART_STATE_BUSY_TX_RX = 0x23U, /*!< Data Transmission and Reception process is ongoing ++ Not to be used for neither gState nor RxState. ++ Value is result of combination (Or) between gState and RxState values */ ++ HAL_UART_STATE_TIMEOUT = 0xA0U, /*!< Timeout state ++ Value is allowed for gState only */ ++ HAL_UART_STATE_ERROR = 0xE0U /*!< Error ++ Value is allowed for gState only */ ++} HAL_UART_StateTypeDef; ++ ++/** ++ * @brief HAL UART Error Code structure definition ++ */ ++typedef enum ++{ ++ HAL_UART_ERROR_NONE = 0x00U, /*!< No error */ ++ HAL_UART_ERROR_PE = 0x01U, /*!< Parity error */ ++ HAL_UART_ERROR_NE = 0x02U, /*!< Noise error */ ++ HAL_UART_ERROR_FE = 0x04U, /*!< frame error */ ++ HAL_UART_ERROR_ORE = 0x08U, /*!< Overrun error */ ++ HAL_UART_ERROR_DMA = 0x10U /*!< DMA transfer error */ ++} HAL_UART_ErrorTypeDef; ++ ++/** ++ * @brief UART clock sources definition ++ */ ++typedef enum { ++ UART_CLOCKSOURCE_PCLK1 = 0x00U, /*!< PCLK1 clock source */ ++ UART_CLOCKSOURCE_PCLK2 = 0x01U, /*!< PCLK2 clock source */ ++ UART_CLOCKSOURCE_PCLK5 = 0x02U, /*!< PCLK5 clock source (only used by UART1) */ ++ UART_CLOCKSOURCE_PLL3Q = 0x04U, /*!< PLL3Q clock source (only used by UART1) */ ++ UART_CLOCKSOURCE_PLL4Q = 0x08U, /*!< PLL4Q clock source */ ++ UART_CLOCKSOURCE_HSI = 0x10U, /*!< HSI clock source */ ++ UART_CLOCKSOURCE_CSI = 0x20U, /*!< CSI clock source */ ++ UART_CLOCKSOURCE_HSE = 0x40U, /*!< HSE clock source */ ++ UART_CLOCKSOURCE_UNDEFINED = 0x80U /*!< Undefined clock source */ ++} UART_ClockSourceTypeDef; ++ ++/** ++ * @brief UART handle Structure definition ++ */ ++typedef struct { ++ USART_TypeDef *Instance; /*!< UART registers base address */ ++ ++ UART_InitTypeDef Init; /*!< UART communication parameters */ ++ ++ UART_AdvFeatureInitTypeDef AdvancedInit; /*!< UART Advanced Features initialization parameters */ ++ ++ uint8_t *pTxBuffPtr; /*!< Pointer to UART Tx transfer Buffer */ ++ ++ uint16_t TxXferSize; /*!< UART Tx Transfer size */ ++ ++ __IO uint16_t TxXferCount; /*!< UART Tx Transfer Counter */ ++ ++ uint8_t *pRxBuffPtr; /*!< Pointer to UART Rx transfer Buffer */ ++ ++ uint16_t RxXferSize; /*!< UART Rx Transfer size */ ++ ++ __IO uint16_t RxXferCount; /*!< UART Rx Transfer Counter */ ++ ++ uint16_t Mask; /*!< UART Rx RDR register mask */ ++ ++#if defined(HAL_DMA_MODULE_ENABLED) ++ DMA_HandleTypeDef *hdmatx; /*!< UART Tx DMA Handle parameters */ ++ ++ DMA_HandleTypeDef *hdmarx; /*!< UART Rx DMA Handle parameters */ ++#endif ++#if defined(HAL_MDMA_MODULE_ENABLED) ++ MDMA_HandleTypeDef *hmdmatx; /*!< UART Tx MDMA Handle parameters */ ++ ++ MDMA_HandleTypeDef *hmdmarx; /*!< UART Rx MDMA Handle parameters */ ++#endif /* HAL_MDMA_MODULE_ENABLED */ ++ ++ HAL_LockTypeDef Lock; /*!< Locking object */ ++ ++ __IO HAL_UART_StateTypeDef gState; /*!< UART state information related to global Handle management ++ and also related to Tx operations. ++ This parameter can be a value of @ref HAL_UART_StateTypeDef */ ++ ++ __IO HAL_UART_StateTypeDef RxState; /*!< UART state information related to Rx operations. ++ This parameter can be a value of @ref HAL_UART_StateTypeDef */ ++ ++ __IO uint32_t ErrorCode; /*!< UART Error code */ ++ ++} UART_HandleTypeDef; ++ ++/** ++ * @} ++ */ ++ ++/* Exported constants --------------------------------------------------------*/ ++/** @defgroup UART_Exported_Constants UART Exported Constants ++ * @{ ++ */ ++ ++/** @defgroup UART_Stop_Bits UART Number of Stop Bits ++ * @{ ++ */ ++#define UART_STOPBITS_0_5 USART_CR2_STOP_0 /*!< UART frame with 0.5 stop bit */ ++#define UART_STOPBITS_1 ((uint32_t)0x00000000U) /*!< UART frame with 1 stop bit */ ++#define UART_STOPBITS_1_5 (USART_CR2_STOP_0 | USART_CR2_STOP_1) /*!< UART frame with 1.5 stop bits */ ++#define UART_STOPBITS_2 USART_CR2_STOP_1 /*!< UART frame with 2 stop bits */ ++/** ++ * @} ++ */ ++ ++/** @defgroup UART_Parity UART Parity ++ * @{ ++ */ ++#define UART_PARITY_NONE ((uint32_t)0x00000000U) /*!< No parity */ ++#define UART_PARITY_EVEN ((uint32_t)USART_CR1_PCE) /*!< Even parity */ ++#define UART_PARITY_ODD ((uint32_t)(USART_CR1_PCE | USART_CR1_PS)) /*!< Odd parity */ ++/** ++ * @} ++ */ ++ ++/** @defgroup UART_Hardware_Flow_Control UART Hardware Flow Control ++ * @{ ++ */ ++#define UART_HWCONTROL_NONE ((uint32_t)0x00000000U) /*!< No hardware control */ ++#define UART_HWCONTROL_RTS ((uint32_t)USART_CR3_RTSE) /*!< Request To Send */ ++#define UART_HWCONTROL_CTS ((uint32_t)USART_CR3_CTSE) /*!< Clear To Send */ ++#define UART_HWCONTROL_RTS_CTS ((uint32_t)(USART_CR3_RTSE | USART_CR3_CTSE)) /*!< Request and Clear To Send */ ++/** ++ * @} ++ */ ++ ++/** @defgroup UART_Mode UART Transfer Mode ++ * @{ ++ */ ++#define UART_MODE_RX ((uint32_t)USART_CR1_RE) /*!< RX mode */ ++#define UART_MODE_TX ((uint32_t)USART_CR1_TE) /*!< TX mode */ ++#define UART_MODE_TX_RX ((uint32_t)(USART_CR1_TE | USART_CR1_RE)) /*!< RX and TX mode */ ++/** ++ * @} ++ */ ++ ++/** @defgroup UART_State UART State ++ * @{ ++ */ ++#define UART_STATE_DISABLE ((uint32_t)0x00000000U) /*!< UART disabled */ ++#define UART_STATE_ENABLE ((uint32_t)USART_CR1_UE) /*!< UART enabled */ ++/** ++ * @} ++ */ ++ ++/** @defgroup UART_Over_Sampling UART Over Sampling ++ * @{ ++ */ ++#define UART_OVERSAMPLING_16 ((uint32_t)0x00000000U) /*!< Oversampling by 16 */ ++#define UART_OVERSAMPLING_8 ((uint32_t)USART_CR1_OVER8) /*!< Oversampling by 8 */ ++/** ++ * @} ++ */ ++ ++/** @defgroup UART_OneBit_Sampling UART One Bit Sampling Method ++ * @{ ++ */ ++#define UART_ONE_BIT_SAMPLE_DISABLE ((uint32_t)0x00000000U) /*!< One-bit sampling disable */ ++#define UART_ONE_BIT_SAMPLE_ENABLE ((uint32_t)USART_CR3_ONEBIT) /*!< One-bit sampling enable */ ++/** ++ * @} ++ */ ++ ++/** @defgroup UART_Prescaler UART Prescaler ++ * @{ ++ */ ++#define UART_PRESCALER_DIV1 ((uint32_t)0x00000000U) /*!< UART clock /1 */ ++#define UART_PRESCALER_DIV2 ((uint32_t)0x00000001U) /*!< UART clock /2 */ ++#define UART_PRESCALER_DIV4 ((uint32_t)0x00000002U) /*!< UART clock /4 */ ++#define UART_PRESCALER_DIV6 ((uint32_t)0x00000003U) /*!< UART clock /6 */ ++#define UART_PRESCALER_DIV8 ((uint32_t)0x00000004U) /*!< UART clock /8 */ ++#define UART_PRESCALER_DIV10 ((uint32_t)0x00000005U) /*!< UART clock /10 */ ++#define UART_PRESCALER_DIV12 ((uint32_t)0x00000006U) /*!< UART clock /12 */ ++#define UART_PRESCALER_DIV16 ((uint32_t)0x00000007U) /*!< UART clock /16 */ ++#define UART_PRESCALER_DIV32 ((uint32_t)0x00000008U) /*!< UART clock /32 */ ++#define UART_PRESCALER_DIV64 ((uint32_t)0x00000009U) /*!< UART clock /64 */ ++#define UART_PRESCALER_DIV128 ((uint32_t)0x0000000AU) /*!< UART clock /128 */ ++#define UART_PRESCALER_DIV256 ((uint32_t)0x0000000BU) /*!< UART clock /256 */ ++ ++/** ++ * @} ++ */ ++ ++/** @defgroup UART_FIFO_mode UART FIFO mode ++ * @brief UART FIFO mode ++ * @{ ++ */ ++#define UART_FIFOMODE_DISABLE ((uint32_t)0x00000000U) /*!< FIFO mode disable */ ++#define UART_FIFOMODE_ENABLE ((uint32_t)USART_CR1_FIFOEN) /*!< FIFO mode enable */ ++/** ++ * @} ++ */ ++ ++/** @defgroup UART_TXFIFO_threshold_level UART TXFIFO threshold level ++ * @brief UART TXFIFO level ++ * @{ ++ */ ++#define UART_TXFIFO_THRESHOLD_1EIGHTHFULL ((uint32_t)0x00000000U) /*!< TXFIFO reaches 1/8 of its depth */ ++#define UART_TXFIFO_THRESHOLD_1QUARTERFULL ((uint32_t)USART_CR3_TXFTCFG_0) /*!< TXFIFO reaches 1/4 of its depth */ ++#define UART_TXFIFO_THRESHOLD_HALFFULL ((uint32_t)USART_CR3_TXFTCFG_1) /*!< TXFIFO reaches 1/2 of its depth */ ++#define UART_TXFIFO_THRESHOLD_3QUARTERSFULL ((uint32_t)(USART_CR3_TXFTCFG_0 | USART_CR3_TXFTCFG_1)) /*!< TXFIFO reaches 3/4 of its depth */ ++#define UART_TXFIFO_THRESHOLD_7EIGHTHFULL ((uint32_t)USART_CR3_TXFTCFG_2) /*!< TXFIFO reaches 7/8 of its depth */ ++#define UART_TXFIFO_THRESHOLD_EMPTY ((uint32_t)(USART_CR3_TXFTCFG_2 | USART_CR3_TXFTCFG_0)) /*!< TXFIFO becomes empty */ ++/** ++ * @} ++ */ ++ ++/** @defgroup UART_RXFIFO_threshold_level UART RXFIFO threshold level ++ * @brief UART RXFIFO level ++ * @{ ++ */ ++#define UART_RXFIFO_THRESHOLD_1EIGHTHFULL ((uint32_t)0x00000000U) /*!< RXFIFO reaches 1/8 of its depth */ ++#define UART_RXFIFO_THRESHOLD_1QUARTERFULL ((uint32_t)USART_CR3_RXFTCFG_0) /*!< RXFIFO reaches 1/4 of its depth */ ++#define UART_RXFIFO_THRESHOLD_HALFFULL ((uint32_t)USART_CR3_RXFTCFG_1) /*!< RXFIFO reaches 1/2 of its depth */ ++#define UART_RXFIFO_THRESHOLD_3QUARTERSFULL ((uint32_t)(USART_CR3_RXFTCFG_0 | USART_CR3_RXFTCFG_1)) /*!< RXFIFO reaches 3/4 of its depth */ ++#define UART_RXFIFO_THRESHOLD_7EIGHTHFULL ((uint32_t)USART_CR3_RXFTCFG_2) /*!< RXFIFO reaches 7/8 of its depth */ ++#define UART_RXFIFO_THRESHOLD_FULL ((uint32_t)(USART_CR3_RXFTCFG_2 | USART_CR3_RXFTCFG_0)) /*!< RXFIFO becomes full */ ++/** ++ * @} ++ */ ++ ++/** @defgroup UART_AutoBaud_Rate_Mode UART Advanced Feature AutoBaud Rate Mode ++ * @{ ++ */ ++#define UART_ADVFEATURE_AUTOBAUDRATE_ONSTARTBIT ((uint32_t)0x00000000U) /*!< Auto Baud rate detection on start bit */ ++#define UART_ADVFEATURE_AUTOBAUDRATE_ONFALLINGEDGE ((uint32_t)USART_CR2_ABRMODE_0) /*!< Auto Baud rate detection on falling edge */ ++#define UART_ADVFEATURE_AUTOBAUDRATE_ON0X7FFRAME ((uint32_t)USART_CR2_ABRMODE_1) /*!< Auto Baud rate detection on 0x7F frame detection */ ++#define UART_ADVFEATURE_AUTOBAUDRATE_ON0X55FRAME ((uint32_t)USART_CR2_ABRMODE) /*!< Auto Baud rate detection on 0x55 frame detection */ ++/** ++ * @} ++ */ ++ ++/** @defgroup UART_Receiver_TimeOut UART Receiver TimeOut ++ * @{ ++ */ ++#define UART_RECEIVER_TIMEOUT_DISABLE ((uint32_t)0x00000000U) /*!< UART receiver timeout disable */ ++#define UART_RECEIVER_TIMEOUT_ENABLE ((uint32_t)USART_CR2_RTOEN) /*!< UART receiver timeout enable */ ++/** ++ * @} ++ */ ++ ++/** @defgroup UART_LIN UART Local Interconnection Network mode ++ * @{ ++ */ ++#define UART_LIN_DISABLE ((uint32_t)0x00000000U) /*!< Local Interconnect Network disable */ ++#define UART_LIN_ENABLE ((uint32_t)USART_CR2_LINEN) /*!< Local Interconnect Network enable */ ++/** ++ * @} ++ */ ++ ++/** @defgroup UART_LIN_Break_Detection UART LIN Break Detection ++ * @{ ++ */ ++#define UART_LINBREAKDETECTLENGTH_10B ((uint32_t)0x00000000U) /*!< LIN 10-bit break detection length */ ++#define UART_LINBREAKDETECTLENGTH_11B ((uint32_t)USART_CR2_LBDL) /*!< LIN 11-bit break detection length */ ++/** ++ * @} ++ */ ++ ++/** @defgroup UART_DMA_Tx UART DMA Tx ++ * @{ ++ */ ++#define UART_DMA_TX_DISABLE ((uint32_t)0x00000000U) /*!< UART DMA TX disabled */ ++#define UART_DMA_TX_ENABLE ((uint32_t)USART_CR3_DMAT) /*!< UART DMA TX enabled */ ++/** ++ * @} ++ */ ++ ++/** @defgroup UART_DMA_Rx UART DMA Rx ++ * @{ ++ */ ++#define UART_DMA_RX_DISABLE ((uint32_t)0x00000000U) /*!< UART DMA RX disabled */ ++#define UART_DMA_RX_ENABLE ((uint32_t)USART_CR3_DMAR) /*!< UART DMA RX enabled */ ++/** ++ * @} ++ */ ++ ++/** @defgroup UART_Half_Duplex_Selection UART Half Duplex Selection ++ * @{ ++ */ ++#define UART_HALF_DUPLEX_DISABLE ((uint32_t)0x00000000U) /*!< UART half-duplex disabled */ ++#define UART_HALF_DUPLEX_ENABLE ((uint32_t)USART_CR3_HDSEL) /*!< UART half-duplex enabled */ ++/** ++ * @} ++ */ ++ ++/** @defgroup UART_WakeUp_Methods UART WakeUp Methods ++ * @{ ++ */ ++#define UART_WAKEUPMETHOD_IDLELINE ((uint32_t)0x00000000U) /*!< UART wake-up on idle line */ ++#define UART_WAKEUPMETHOD_ADDRESSMARK ((uint32_t)USART_CR1_WAKE) /*!< UART wake-up on address mark */ ++/** ++ * @} ++ */ ++ ++/** @defgroup UART_Request_Parameters UART Request Parameters ++ * @{ ++ */ ++#define UART_AUTOBAUD_REQUEST ((uint32_t)USART_RQR_ABRRQ) /*!< Auto-Baud Rate Request */ ++#define UART_SENDBREAK_REQUEST ((uint32_t)USART_RQR_SBKRQ) /*!< Send Break Request */ ++#define UART_MUTE_MODE_REQUEST ((uint32_t)USART_RQR_MMRQ) /*!< Mute Mode Request */ ++#define UART_RXDATA_FLUSH_REQUEST ((uint32_t)USART_RQR_RXFRQ) /*!< Receive Data flush Request */ ++#define UART_TXDATA_FLUSH_REQUEST ((uint32_t)USART_RQR_TXFRQ) /*!< Transmit data flush Request */ ++/** ++ * @} ++ */ ++ ++/** @defgroup UART_Advanced_Features_Initialization_Type UART Advanced Feature Initialization Type ++ * @{ ++ */ ++#define UART_ADVFEATURE_NO_INIT ((uint32_t)0x00000000U) /*!< No advanced feature initialization */ ++#define UART_ADVFEATURE_TXINVERT_INIT ((uint32_t)0x00000001U) /*!< TX pin active level inversion */ ++#define UART_ADVFEATURE_RXINVERT_INIT ((uint32_t)0x00000002U) /*!< RX pin active level inversion */ ++#define UART_ADVFEATURE_DATAINVERT_INIT ((uint32_t)0x00000004U) /*!< Binary data inversion */ ++#define UART_ADVFEATURE_SWAP_INIT ((uint32_t)0x00000008U) /*!< TX/RX pins swap */ ++#define UART_ADVFEATURE_RXOVERRUNDISABLE_INIT ((uint32_t)0x00000010U) /*!< RX overrun disable */ ++#define UART_ADVFEATURE_DMADISABLEONERROR_INIT ((uint32_t)0x00000020U) /*!< DMA disable on Reception Error */ ++#define UART_ADVFEATURE_AUTOBAUDRATE_INIT ((uint32_t)0x00000040U) /*!< Auto Baud rate detection initialization */ ++#define UART_ADVFEATURE_MSBFIRST_INIT ((uint32_t)0x00000080U) /*!< Most significant bit sent/received first */ ++/** ++ * @} ++ */ ++ ++/** @defgroup UART_Tx_Inv UART Advanced Feature TX Pin Active Level Inversion ++ * @{ ++ */ ++#define UART_ADVFEATURE_TXINV_DISABLE ((uint32_t)0x00000000U) /*!< TX pin active level inversion disable */ ++#define UART_ADVFEATURE_TXINV_ENABLE ((uint32_t)USART_CR2_TXINV) /*!< TX pin active level inversion enable */ ++/** ++ * @} ++ */ ++ ++/** @defgroup UART_Rx_Inv UART Advanced Feature RX Pin Active Level Inversion ++ * @{ ++ */ ++#define UART_ADVFEATURE_RXINV_DISABLE ((uint32_t)0x00000000U) /*!< RX pin active level inversion disable */ ++#define UART_ADVFEATURE_RXINV_ENABLE ((uint32_t)USART_CR2_RXINV) /*!< RX pin active level inversion enable */ ++/** ++ * @} ++ */ ++ ++/** @defgroup UART_Data_Inv UART Advanced Feature Binary Data Inversion ++ * @{ ++ */ ++#define UART_ADVFEATURE_DATAINV_DISABLE ((uint32_t)0x00000000U) /*!< Binary data inversion disable */ ++#define UART_ADVFEATURE_DATAINV_ENABLE ((uint32_t)USART_CR2_DATAINV) /*!< Binary data inversion enable */ ++/** ++ * @} ++ */ ++ ++/** @defgroup UART_Rx_Tx_Swap UART Advanced Feature RX TX Pins Swap ++ * @{ ++ */ ++#define UART_ADVFEATURE_SWAP_DISABLE ((uint32_t)0x00000000U) /*!< TX/RX pins swap disable */ ++#define UART_ADVFEATURE_SWAP_ENABLE ((uint32_t)USART_CR2_SWAP) /*!< TX/RX pins swap enable */ ++/** ++ * @} ++ */ ++ ++/** @defgroup UART_Overrun_Disable UART Advanced Feature Overrun Disable ++ * @{ ++ */ ++#define UART_ADVFEATURE_OVERRUN_ENABLE ((uint32_t)0x00000000U) /*!< RX overrun enable */ ++#define UART_ADVFEATURE_OVERRUN_DISABLE ((uint32_t)USART_CR3_OVRDIS) /*!< RX overrun disable */ ++/** ++ * @} ++ */ ++ ++/** @defgroup UART_AutoBaudRate_Enable UART Advanced Feature Auto BaudRate Enable ++ * @{ ++ */ ++#define UART_ADVFEATURE_AUTOBAUDRATE_DISABLE ((uint32_t)0x00000000U) /*!< RX Auto Baud rate detection enable */ ++#define UART_ADVFEATURE_AUTOBAUDRATE_ENABLE ((uint32_t)USART_CR2_ABREN) /*!< RX Auto Baud rate detection disable */ ++/** ++ * @} ++ */ ++ ++/** @defgroup UART_DMA_Disable_on_Rx_Error UART Advanced Feature DMA Disable On Rx Error ++ * @{ ++ */ ++#define UART_ADVFEATURE_DMA_ENABLEONRXERROR ((uint32_t)0x00000000U) /*!< DMA enable on Reception Error */ ++#define UART_ADVFEATURE_DMA_DISABLEONRXERROR ((uint32_t)USART_CR3_DDRE) /*!< DMA disable on Reception Error */ ++/** ++ * @} ++ */ ++ ++/** @defgroup UART_MSB_First UART Advanced Feature MSB First ++ * @{ ++ */ ++#define UART_ADVFEATURE_MSBFIRST_DISABLE ((uint32_t)0x00000000U) /*!< Most significant bit sent/received first disable */ ++#define UART_ADVFEATURE_MSBFIRST_ENABLE ((uint32_t)USART_CR2_MSBFIRST) /*!< Most significant bit sent/received first enable */ ++/** ++ * @} ++ */ ++ ++/** @defgroup UART_Stop_Mode_Enable UART Advanced Feature Stop Mode Enable ++ * @{ ++ */ ++#define UART_ADVFEATURE_STOPMODE_DISABLE ((uint32_t)0x00000000U) /*!< UART stop mode disable */ ++#define UART_ADVFEATURE_STOPMODE_ENABLE ((uint32_t)USART_CR1_UESM) /*!< UART stop mode enable */ ++/** ++ * @} ++ */ ++ ++/** @defgroup UART_Mute_Mode UART Advanced Feature Mute Mode Enable ++ * @{ ++ */ ++#define UART_ADVFEATURE_MUTEMODE_DISABLE ((uint32_t)0x00000000U) /*!< UART mute mode disable */ ++#define UART_ADVFEATURE_MUTEMODE_ENABLE ((uint32_t)USART_CR1_MME) /*!< UART mute mode enable */ ++/** ++ * @} ++ */ ++ ++/** @defgroup UART_CR2_ADDRESS_LSB_POS UART Address-matching LSB Position In CR2 Register ++ * @{ ++ */ ++#define UART_CR2_ADDRESS_LSB_POS ((uint32_t)24U) /*!< UART address-matching LSB position in CR2 register */ ++/** ++ * @} ++ */ ++ ++/** @defgroup UART_WakeUp_from_Stop_Selection UART WakeUp From Stop Selection ++ * @{ ++ */ ++#define UART_WAKEUP_ON_ADDRESS ((uint32_t)0x00000000U) /*!< UART wake-up on address */ ++#define UART_WAKEUP_ON_STARTBIT ((uint32_t)USART_CR3_WUS_1) /*!< UART wake-up on start bit */ ++#define UART_WAKEUP_ON_READDATA_NONEMPTY ((uint32_t)USART_CR3_WUS) /*!< UART wake-up on receive data register not empty */ ++#define UART_WAKEUP_ON_RXFIFO_THRESHOLD ((uint32_t)USART_CR3_RXFTIE) /*!< UART wake-up when the RXFIFO reaches threshold */ ++#define UART_WAKEUP_ON_RXFIFO_FULL ((uint32_t)USART_CR1_RXFFIE) /*!< UART wake-up when the RXFIFO is full */ ++#define UART_WAKEUP_ON_TXFIFO_THRESHOLD ((uint32_t)USART_CR3_TXFTIE) /*!< UART wake-up when the TXFIFO reaches threshold */ ++#define UART_WAKEUP_ON_TXFIFO_EMPTY ((uint32_t)USART_CR1_TXFEIE) /*!< UART wake-up when the TXFIFO is empty */ ++/** ++ * @} ++ */ ++ ++/** @defgroup UART_DriverEnable_Polarity UART DriverEnable Polarity ++ * @{ ++ */ ++#define UART_DE_POLARITY_HIGH ((uint32_t)0x00000000U) /*!< Driver enable signal is active high */ ++#define UART_DE_POLARITY_LOW ((uint32_t)USART_CR3_DEP) /*!< Driver enable signal is active low */ ++/** ++ * @} ++ */ ++ ++/** @defgroup UART_CR1_DEAT_ADDRESS_LSB_POS UART Driver Enable Assertion Time LSB Position In CR1 Register ++ * @{ ++ */ ++#define UART_CR1_DEAT_ADDRESS_LSB_POS ((uint32_t)21U) /*!< UART Driver Enable assertion time LSB position in CR1 register */ ++/** ++ * @} ++ */ ++ ++/** @defgroup UART_CR1_DEDT_ADDRESS_LSB_POS UART Driver Enable DeAssertion Time LSB Position In CR1 Register ++ * @{ ++ */ ++#define UART_CR1_DEDT_ADDRESS_LSB_POS ((uint32_t)16U) /*!< UART Driver Enable de-assertion time LSB position in CR1 register */ ++/** ++ * @} ++ */ ++ ++/** @defgroup UART_Interruption_Mask UART Interruptions Flag Mask ++ * @{ ++ */ ++#define UART_IT_MASK ((uint32_t)0x001FU) /*!< UART interruptions flags mask */ ++/** ++ * @} ++ */ ++ ++/** @defgroup UART_TimeOut_Value UART polling-based communications time-out value ++ * @{ ++ */ ++#define HAL_UART_TIMEOUT_VALUE 0x1FFFFFFU /*!< UART polling-based communications time-out value */ ++/** ++ * @} ++ */ ++ ++/** @defgroup UART_Flags UART Status Flags ++ * Elements values convention: 0xXXXX ++ * - 0xXXXX : Flag mask in the ISR register ++ * @{ ++ */ ++#define UART_FLAG_TXFT USART_ISR_TXFT /*!< UART TXFIFO threshold flag */ ++#define UART_FLAG_RXFT USART_ISR_RXFT /*!< UART RXFIFO threshold flag */ ++#define UART_FLAG_RXFF USART_ISR_RXFF /*!< UART RXFIFO Full flag */ ++#define UART_FLAG_TXFE USART_ISR_TXFE /*!< UART TXFIFO Empty flag */ ++#define UART_FLAG_REACK USART_ISR_REACK /*!< UART receive enable acknowledge flag */ ++#define UART_FLAG_TEACK USART_ISR_TEACK /*!< UART transmit enable acknowledge flag */ ++#define UART_FLAG_WUF USART_ISR_WUF /*!< UART wake-up from stop mode flag */ ++#define UART_FLAG_RWU USART_ISR_RWU /*!< UART receiver wake-up from mute mode flag */ ++#define UART_FLAG_SBKF USART_ISR_SBKF /*!< UART send break flag */ ++#define UART_FLAG_CMF USART_ISR_CMF /*!< UART character match flag */ ++#define UART_FLAG_BUSY USART_ISR_BUSY /*!< UART busy flag */ ++#define UART_FLAG_ABRF USART_ISR_ABRF /*!< UART auto Baud rate flag */ ++#define UART_FLAG_ABRE USART_ISR_ABRE /*!< UART uto Baud rate error */ ++#define UART_FLAG_RTOF USART_ISR_RTOF /*!< UART receiver timeout flag */ ++#define UART_FLAG_CTS USART_ISR_CTS /*!< UART clear to send flag */ ++#define UART_FLAG_CTSIF USART_ISR_CTSIF /*!< UART clear to send interrupt flag */ ++#define UART_FLAG_LBDF USART_ISR_LBDF /*!< UART LIN break detection flag */ ++#define UART_FLAG_TXE USART_ISR_TXE /*!< UART transmit data register empty */ ++#define UART_FLAG_TXFNF USART_ISR_TXE /*!< UART TXFIFO not full */ ++#define UART_FLAG_TC USART_ISR_TC /*!< UART transmission complete */ ++#define UART_FLAG_RXNE USART_ISR_RXNE /*!< UART read data register not empty */ ++#define UART_FLAG_RXFNE USART_ISR_RXNE /*!< UART RXFIFO not empty */ ++#define UART_FLAG_IDLE USART_ISR_IDLE /*!< UART idle flag */ ++#define UART_FLAG_ORE USART_ISR_ORE /*!< UART overrun error */ ++#define UART_FLAG_NE USART_ISR_NE /*!< UART noise error */ ++#define UART_FLAG_FE USART_ISR_FE /*!< UART frame error */ ++#define UART_FLAG_PE USART_ISR_PE /*!< UART parity error */ ++/** ++ * @} ++ */ ++ ++/** @defgroup UART_Interrupt_definition UART Interrupts Definition ++ * Elements values convention: 000ZZZZZ0XXYYYYYb ++ * - YYYYY : Interrupt source position in the XX register (5bits) ++ * - XX : Interrupt source register (2bits) ++ * - 01: CR1 register ++ * - 10: CR2 register ++ * - 11: CR3 register ++ * - ZZZZZ : Flag position in the ISR register(5bits) ++ * @{ ++ */ ++#define UART_IT_PE ((uint32_t)0x0028U) /*!< UART parity error interruption */ ++#define UART_IT_TXE ((uint32_t)0x0727U) /*!< UART transmit data register empty interruption */ ++#define UART_IT_TC ((uint32_t)0x0626U) /*!< UART transmission complete interruption */ ++#define UART_IT_RXNE ((uint32_t)0x0525U) /*!< UART read data register not empty interruption */ ++#define UART_IT_LBD ((uint32_t)0x0846U) /*!< UART LIN break detection interruption */ ++#define UART_IT_CTS ((uint32_t)0x096AU) /*!< UART CTS interruption */ ++#define UART_IT_CM ((uint32_t)0x112EU) /*!< UART character match interruption */ ++#define UART_IT_WUF ((uint32_t)0x1476U) /*!< UART wake-up from stop mode interruption */ ++#define UART_IT_RXFF ((uint16_t)0x183FU) ++#define UART_IT_TXFE ((uint16_t)0x173EU) ++#define UART_IT_RXFT ((uint16_t)0x1A7CU) ++#define UART_IT_TXFT ((uint16_t)0x1B77U) ++ ++ ++/** Elements values convention: 000000000XXYYYYYb ++ * - YYYYY : Interrupt source position in the XX register (5bits) ++ * - XX : Interrupt source register (2bits) ++ * - 01: CR1 register ++ * - 10: CR2 register ++ * - 11: CR3 register ++ */ ++#define UART_IT_ERR ((uint32_t)0x0060U) /*!< UART error interruption */ ++ ++/** Elements values convention: 0000ZZZZ00000000b ++ * - ZZZZ : Flag position in the ISR register(4bits) ++ */ ++#define UART_IT_ORE ((uint32_t)0x0300U) /*!< UART overrun error interruption */ ++#define UART_IT_NE ((uint32_t)0x0200U) /*!< UART noise error interruption */ ++#define UART_IT_FE ((uint32_t)0x0100U) /*!< UART frame error interruption */ ++/** ++ * @} ++ */ ++ ++/** @defgroup UART_IT_CLEAR_Flags UART Interruption Clear Flags ++ * @{ ++ */ ++#define UART_CLEAR_PEF USART_ICR_PECF /*!< Parity Error Clear Flag */ ++#define UART_CLEAR_FEF USART_ICR_FECF /*!< Framing Error Clear Flag */ ++#define UART_CLEAR_NEF USART_ICR_NCF /*!< Noise detected Clear Flag */ ++#define UART_CLEAR_OREF USART_ICR_ORECF /*!< OverRun Error Clear Flag */ ++#define UART_CLEAR_IDLEF USART_ICR_IDLECF /*!< IDLE line detected Clear Flag */ ++#define UART_CLEAR_TXFECF USART_ICR_TXFECF /*!< TXFIFO empty clear flag */ ++#define UART_CLEAR_TCF USART_ICR_TCCF /*!< Transmission Complete Clear Flag */ ++#define UART_CLEAR_LBDF USART_ICR_LBDCF /*!< LIN Break Detection Clear Flag */ ++#define UART_CLEAR_CTSF USART_ICR_CTSCF /*!< CTS Interrupt Clear Flag */ ++#define UART_CLEAR_RTOF USART_ICR_RTOCF /*!< Receiver Time Out Clear Flag */ ++#define UART_CLEAR_CMF USART_ICR_CMCF /*!< Character Match Clear Flag */ ++#define UART_CLEAR_WUF USART_ICR_WUCF /*!< Wake Up from stop mode Clear Flag */ ++/** ++ * @} ++ */ ++ ++ ++/** ++ * @} ++ */ ++ ++/* Exported macros -----------------------------------------------------------*/ ++/** @defgroup UART_Exported_Macros UART Exported Macros ++ * @{ ++ */ ++ ++/** @brief Reset UART handle states. ++ * @param __HANDLE__: UART handle. ++ * @retval None ++ */ ++#define __HAL_UART_RESET_HANDLE_STATE(__HANDLE__) \ ++ do { \ ++ (__HANDLE__)->gState = HAL_UART_STATE_RESET; \ ++ (__HANDLE__)->RxState = HAL_UART_STATE_RESET; \ ++ } while (0) ++ ++/** @brief Flush the UART Data registers. ++ * @param __HANDLE__: specifies the UART Handle. ++ * @retval None ++ */ ++#define __HAL_UART_FLUSH_DRREGISTER(__HANDLE__) \ ++ do { \ ++ SET_BIT((__HANDLE__)->Instance->RQR, \ ++ UART_RXDATA_FLUSH_REQUEST); \ ++ SET_BIT((__HANDLE__)->Instance->RQR, \ ++ UART_TXDATA_FLUSH_REQUEST); \ ++ } while (0) ++ ++/** @brief Clear the specified UART pending flag. ++ * @param __HANDLE__: specifies the UART Handle. ++ * @param __FLAG__: specifies the flag to check. ++ * This parameter can be any combination of the following values: ++ * @arg UART_FLAG_WUF: Wake up from stop mode flag ++ * @arg UART_FLAG_CMF: Character match flag ++ * @arg UART_FLAG_RTOF: Receiver timeout flag ++ * @arg UART_FLAG_CTS: CTS Change flag (not available for UART4 and UART5) ++ * @arg UART_FLAG_LBD: LIN Break detection flag ++ * @arg UART_FLAG_TC: Transmission Complete flag ++ * @arg UART_FLAG_TXFE: TXFIFO Empty flag ++ * @arg UART_FLAG_IDLE: Idle Line detection flag ++ * @arg UART_FLAG_ORE: OverRun Error flag ++ * @arg UART_FLAG_NE: Noise Error flag ++ * @arg UART_FLAG_FE: Framing Error flag ++ * @arg UART_FLAG_PE: Parity Error flag ++ * @retval The new state of __FLAG__ (TRUE or FALSE). ++ */ ++#define __HAL_UART_CLEAR_FLAG(__HANDLE__, __FLAG__) \ ++ ((__HANDLE__)->Instance->ICR = (__FLAG__)) ++ ++/** @brief Clear the UART PE pending flag. ++ * @param __HANDLE__: specifies the UART Handle. ++ * @retval None ++ */ ++#define __HAL_UART_CLEAR_PEFLAG(__HANDLE__) \ ++ __HAL_UART_CLEAR_FLAG((__HANDLE__), UART_CLEAR_PEF) ++ ++/** @brief Clear the UART FE pending flag. ++ * @param __HANDLE__: specifies the UART Handle. ++ * @retval None ++ */ ++#define __HAL_UART_CLEAR_FEFLAG(__HANDLE__) \ ++ __HAL_UART_CLEAR_FLAG((__HANDLE__), UART_CLEAR_FEF) ++ ++/** @brief Clear the UART NE pending flag. ++ * @param __HANDLE__: specifies the UART Handle. ++ * @retval None ++ */ ++#define __HAL_UART_CLEAR_NEFLAG(__HANDLE__) \ ++ __HAL_UART_CLEAR_FLAG((__HANDLE__), UART_CLEAR_NEF) ++ ++/** @brief Clear the UART ORE pending flag. ++ * @param __HANDLE__: specifies the UART Handle. ++ * @retval None ++ */ ++#define __HAL_UART_CLEAR_OREFLAG(__HANDLE__) \ ++ __HAL_UART_CLEAR_FLAG((__HANDLE__), UART_CLEAR_OREF) ++ ++/** @brief Clear the UART IDLE pending flag. ++ * @param __HANDLE__: specifies the UART Handle. ++ * @retval None ++ */ ++#define __HAL_UART_CLEAR_IDLEFLAG(__HANDLE__) \ ++ __HAL_UART_CLEAR_FLAG((__HANDLE__), UART_CLEAR_IDLEF) ++ ++/** @brief Clear the UART TX FIFO empty clear flag. ++ * @param __HANDLE__: specifies the UART Handle. ++ * @retval None ++ */ ++#define __HAL_UART_CLEAR_TXFECF(__HANDLE__) \ ++ __HAL_UART_CLEAR_FLAG((__HANDLE__), UART_CLEAR_TXFECF) ++ ++/** @brief Check whether the specified UART flag is set or not. ++ * @param __HANDLE__: specifies the UART Handle. ++ * @param __FLAG__: specifies the flag to check. ++ * This parameter can be one of the following values: ++ * @arg UART_FLAG_TXFT: TXFIFO threshold flag ++ * @arg UART_FLAG_RXFT: RXFIFO threshold flag ++ * @arg UART_FLAG_RXFF: RXFIFO Full flag ++ * @arg UART_FLAG_TXFE: TXFIFO Empty flag ++ * @arg UART_FLAG_REACK: Receive enable acknowledge flag ++ * @arg UART_FLAG_TEACK: Transmit enable acknowledge flag ++ * @arg UART_FLAG_WUF: Wake up from stop mode flag ++ * @arg UART_FLAG_RWU: Receiver wake up flag (if the UART in mute mode) ++ * @arg UART_FLAG_SBKF: Send Break flag ++ * @arg UART_FLAG_CMF: Character match flag ++ * @arg UART_FLAG_BUSY: Busy flag ++ * @arg UART_FLAG_ABRF: Auto Baud rate detection flag ++ * @arg UART_FLAG_ABRE: Auto Baud rate detection error flag ++ * @arg UART_FLAG_RTOF: Receiver timeout flag ++ * @arg UART_FLAG_CTS: CTS Change flag ++ * @arg UART_FLAG_LBD: LIN Break detection flag ++ * @arg UART_FLAG_TXE: Transmit data register empty flag ++ * @arg UART_FLAG_TC: Transmission Complete flag ++ * @arg UART_FLAG_RXNE: Receive data register not empty flag ++ * @arg UART_FLAG_IDLE: Idle Line detection flag ++ * @arg UART_FLAG_ORE: OverRun Error flag ++ * @arg.UART_FLAG_NE: Noise Error flag ++ * @arg UART_FLAG_FE: Framing Error flag ++ * @arg UART_FLAG_PE: Parity Error flag ++ * @retval The new state of __FLAG__ (TRUE or FALSE). ++ */ ++#define __HAL_UART_GET_FLAG(__HANDLE__, __FLAG__) \ ++ (((__HANDLE__)->Instance->ISReg & (__FLAG__)) == (__FLAG__)) ++ ++/** @brief Enable the specified UART interrupt. ++ * @param __HANDLE__: specifies the UART Handle. ++ * @param __INTERRUPT__: specifies the UART interrupt source to enable. ++ * This parameter can be one of the following values: ++ * @arg UART_IT_RXFF : RXFIFO Full interrupt ++ * @arg UART_IT_TXFE : TXFIFO Empty interrupt ++ * @arg UART_IT_RXFT : RXFIFO threshold interrupt ++ * @arg UART_IT_TXFT : TXFIFO threshold interrupt ++ * @arg UART_IT_WUF: Wakeup from stop mode interrupt ++ * @arg UART_IT_CM: Character match interrupt ++ * @arg UART_IT_CTS: CTS change interrupt ++ * @arg UART_IT_LBD: LIN Break detection interrupt ++ * @arg UART_IT_TXE: Transmit Data Register empty interrupt ++ * @arg UART_IT_TC: Transmission complete interrupt ++ * @arg UART_IT_RXNE: Receive Data register not empty interrupt ++ * @arg UART_IT_IDLE: Idle line detection interrupt ++ * @arg UART_IT_PE: Parity Error interrupt ++ * @arg UART_IT_ERR: Error interrupt (Frame error, noise error, overrun error) ++ * @retval None ++ */ ++#define __HAL_UART_ENABLE_IT(__HANDLE__, __INTERRUPT__) \ ++ (((((uint8_t)((__INTERRUPT__) & 0xFF)) >> 5U) == 1) ? \ ++ ((__HANDLE__)->Instance->CR1 |= \ ++ (1U << ((__INTERRUPT__) & UART_IT_MASK))) : \ ++ ((((uint8_t)((__INTERRUPT__) & 0xFF)) >> 5U) == 2) ? \ ++ ((__HANDLE__)->Instance->CR2 |= \ ++ (1U << ((__INTERRUPT__) & UART_IT_MASK))) : \ ++ ((__HANDLE__)->Instance->CR3 |= \ ++ (1U << ((__INTERRUPT__) & UART_IT_MASK)))) ++ ++ ++/** @brief Disable the specified UART interrupt. ++ * @param __HANDLE__: specifies the UART Handle. ++ * @param __INTERRUPT__: specifies the UART interrupt source to disable. ++ * This parameter can be one of the following values: ++ * @arg UART_IT_RXFF : RXFIFO Full interrupt ++ * @arg UART_IT_TXFE : TXFIFO Empty interrupt ++ * @arg UART_IT_RXFT : RXFIFO threshold interrupt ++ * @arg UART_IT_TXFT : TXFIFO threshold interrupt ++ * @arg UART_IT_WUF: Wakeup from stop mode interrupt ++ * @arg UART_IT_CM: Character match interrupt ++ * @arg UART_IT_CTS: CTS change interrupt ++ * @arg UART_IT_LBD: LIN Break detection interrupt ++ * @arg UART_IT_TXE: Transmit Data Register empty interrupt ++ * @arg UART_IT_TC: Transmission complete interrupt ++ * @arg UART_IT_RXNE: Receive Data register not empty interrupt ++ * @arg UART_IT_IDLE: Idle line detection interrupt ++ * @arg UART_IT_PE: Parity Error interrupt ++ * @arg UART_IT_ERR: Error interrupt (Frame error, noise error, overrun error) ++ * @retval None ++ */ ++#define __HAL_UART_DISABLE_IT(__HANDLE__, __INTERRUPT__) \ ++ (((((uint8_t)((__INTERRUPT__) & 0xFF)) >> 5U) == 1) ? \ ++ ((__HANDLE__)->Instance->CR1 &= \ ++ ~(1U << ((__INTERRUPT__) & UART_IT_MASK))) : \ ++ ((((uint8_t)((__INTERRUPT__) & 0xFF)) >> 5U) == 2) ? \ ++ ((__HANDLE__)->Instance->CR2 &= \ ++ ~(1U << ((__INTERRUPT__) & UART_IT_MASK))) : \ ++ ((__HANDLE__)->Instance->CR3 &= \ ++ ~(1U << ((__INTERRUPT__) & UART_IT_MASK)))) ++ ++/** @brief Check whether the specified UART interrupt has occurred or not. ++ * @param __HANDLE__: specifies the UART Handle. ++ * @param __IT__: specifies the UART interrupt to check. ++ * This parameter can be one of the following values: ++ * @arg UART_IT_RXFF : RXFIFO Full interrupt ++ * @arg UART_IT_TXFE : TXFIFO Empty interrupt ++ * @arg UART_IT_RXFT : RXFIFO threshold interrupt ++ * @arg UART_IT_TXFT : TXFIFO threshold interrupt ++ * @arg UART_IT_WUF: Wakeup from stop mode interrupt ++ * @arg UART_IT_CM: Character match interrupt ++ * @arg UART_IT_CTS: CTS change interrupt ++ * @arg UART_IT_LBD: LIN Break detection interrupt ++ * @arg UART_IT_TXE: Transmit Data Register empty interrupt ++ * @arg UART_IT_TC: Transmission complete interrupt ++ * @arg UART_IT_RXNE: Receive Data register not empty interrupt ++ * @arg UART_IT_IDLE: Idle line detection interrupt ++ * @arg UART_IT_ORE: OverRun Error interrupt ++ * @arg UART_IT_NE: Noise Error interrupt ++ * @arg UART_IT_FE: Framing Error interrupt ++ * @arg UART_IT_PE: Parity Error interrupt ++ * @retval The new state of __IT__ (TRUE or FALSE). ++ */ ++#define __HAL_UART_GET_IT(__HANDLE__, __IT__) \ ++ ((__HANDLE__)->Instance->ISReg & ((uint32_t)1 << ((__IT__) >> 0x08))) ++ ++/** @brief Check whether the specified UART interrupt source is enabled or not. ++ * @param __HANDLE__: specifies the UART Handle. ++ * @param __IT__: specifies the UART interrupt source to check. ++ * This parameter can be one of the following values: ++ * @arg UART_IT_RXFF : RXFIFO Full interrupt ++ * @arg UART_IT_TXFE : TXFIFO Empty interrupt ++ * @arg UART_IT_RXFT : RXFIFO threshold interrupt ++ * @arg UART_IT_TXFT : TXFIFO threshold interrupt ++ * @arg UART_IT_CTS: CTS change interrupt (not available for UART4 and UART5) ++ * @arg UART_IT_LBD: LIN Break detection interrupt ++ * @arg UART_IT_TXE: Transmit Data Register empty interrupt ++ * @arg UART_IT_TC: Transmission complete interrupt ++ * @arg UART_IT_RXNE: Receive Data register not empty interrupt ++ * @arg UART_IT_IDLE: Idle line detection interrupt ++ * @arg UART_IT_ORE: OverRun Error interrupt ++ * @arg UART_IT_NE: Noise Error interrupt ++ * @arg UART_IT_FE: Framing Error interrupt ++ * @arg UART_IT_PE: Parity Error interrupt ++ * @retval The new state of __IT__ (TRUE or FALSE). ++ */ ++#define __HAL_UART_GET_IT_SOURCE(__HANDLE__, __IT__) \ ++ ((((((uint8_t)(__IT__)) >> 5U) == 1) ? \ ++ (__HANDLE__)->Instance->CR1 : \ ++ (((((uint8_t)(__IT__)) >> 5U) == 2) ? \ ++ (__HANDLE__)->Instance->CR2 : \ ++ (__HANDLE__)->Instance->CR3)) & \ ++ ((uint32_t)1 << (((uint16_t)(__IT__)) & UART_IT_MASK))) ++ ++/** @brief Clear the specified UART ISR flag, in setting the proper ICR register flag. ++ * @param __HANDLE__: specifies the UART Handle. ++ * @param __IT_CLEAR__: specifies the interrupt clear register flag that needs to be set ++ * to clear the corresponding interrupt ++ * This parameter can be one of the following values: ++ * @arg UART_CLEAR_PEF: Parity Error Clear Flag ++ * @arg UART_CLEAR_FEF: Framing Error Clear Flag ++ * @arg UART_CLEAR_NEF: Noise detected Clear Flag ++ * @arg UART_CLEAR_OREF: OverRun Error Clear Flag ++ * @arg UART_CLEAR_IDLEF: IDLE line detected Clear Flag ++ * @arg UART_CLEAR_TCF: Transmission Complete Clear Flag ++ * @arg UART_CLEAR_LBDF: LIN Break Detection Clear Flag ++ * @arg UART_CLEAR_CTSF: CTS Interrupt Clear Flag ++ * @arg UART_CLEAR_RTOF: Receiver Time Out Clear Flag ++ * @arg UART_CLEAR_CMF: Character Match Clear Flag ++ * @arg UART_CLEAR_WUF: Wake Up from stop mode Clear Flag ++ * @arg UART_CLEAR_TXFECF: TXFIFO empty Clear Flag ++ * @retval None ++ */ ++#define __HAL_UART_CLEAR_IT(__HANDLE__, __IT_CLEAR__) \ ++ ((__HANDLE__)->Instance->ICR = (uint32_t)(__IT_CLEAR__)) ++ ++/** @brief Set a specific UART request flag. ++ * @param __HANDLE__: specifies the UART Handle. ++ * @param __REQ__: specifies the request flag to set ++ * This parameter can be one of the following values: ++ * @arg UART_AUTOBAUD_REQUEST: Auto-Baud Rate Request ++ * @arg UART_SENDBREAK_REQUEST: Send Break Request ++ * @arg UART_MUTE_MODE_REQUEST: Mute Mode Request ++ * @arg UART_RXDATA_FLUSH_REQUEST: Receive Data flush Request ++ * @arg UART_TXDATA_FLUSH_REQUEST: Transmit data flush Request ++ * @retval None ++ */ ++#define __HAL_UART_SEND_REQ(__HANDLE__, __REQ__) \ ++ ((__HANDLE__)->Instance->RQR |= (uint32_t)(__REQ__)) ++ ++/** @brief Enable the UART one bit sample method. ++ * @param __HANDLE__: specifies the UART Handle. ++ * @retval None ++ */ ++#define __HAL_UART_ONE_BIT_SAMPLE_ENABLE(__HANDLE__) \ ++ ((__HANDLE__)->Instance->CR3 |= USART_CR3_ONEBIT) ++ ++/** @brief Disable the UART one bit sample method. ++ * @param __HANDLE__: specifies the UART Handle. ++ * @retval None ++ */ ++#define __HAL_UART_ONE_BIT_SAMPLE_DISABLE(__HANDLE__) \ ++ ((__HANDLE__)->Instance->CR3 &= (uint32_t)~((uint32_t)USART_CR3_ONEBIT)) ++ ++/** @brief Enable UART. ++ * @param __HANDLE__: specifies the UART Handle. ++ * @retval None ++ */ ++#define __HAL_UART_ENABLE(__HANDLE__) \ ++ ((__HANDLE__)->Instance->CR1 |= USART_CR1_UE) ++ ++/** @brief Disable UART. ++ * @param __HANDLE__: specifies the UART Handle. ++ * @retval None ++ */ ++#define __HAL_UART_DISABLE(__HANDLE__) \ ++ ((__HANDLE__)->Instance->CR1 &= ~USART_CR1_UE) ++ ++/** @brief Enable TX UART ++ * @param __HANDLE__: specifies the UART Handle. ++ * @retval None ++ */ ++#define __HAL_UART_ENABLE_TX(__HANDLE__) \ ++ ((__HANDLE__)->Instance->CR1 |= USART_CR1_TE) ++ ++/** @brief Disable TX UART ++ * @param __HANDLE__: specifies the UART Handle. ++ * @retval None ++ */ ++#define __HAL_UART_DISABLE_TX(__HANDLE__) \ ++ ((__HANDLE__)->Instance->CR1 &= ~USART_CR1_TE) ++ ++/** @brief Enable CTS flow control ++ * This macro allows to enable CTS hardware flow control for a given UART instance, ++ * without need to call HAL_UART_Init() function. ++ * As involving direct access to UART registers, usage of this macro should be fully endorsed by user. ++ * @note As macro is expected to be used for modifying CTS Hw flow control feature activation, without need ++ * for USART instance Deinit/Init, following conditions for macro call should be fulfilled : ++ * - UART instance should have already been initialised (through call of HAL_UART_Init() ) ++ * - macro could only be called when corresponding UART instance is disabled (i.e. __HAL_UART_DISABLE(__HANDLE__)) ++ * and should be followed by an Enable macro (i.e. __HAL_UART_ENABLE(__HANDLE__)). ++ * @param __HANDLE__: specifies the UART Handle. ++ * @retval None ++ */ ++#define __HAL_UART_HWCONTROL_CTS_ENABLE(__HANDLE__) \ ++ do { \ ++ SET_BIT((__HANDLE__)->Instance->CR3, USART_CR3_CTSE); \ ++ (__HANDLE__)->Init.HwFlowCtl |= USART_CR3_CTSE; \ ++ } while (0) ++ ++/** @brief Disable CTS flow control. ++ * @note This macro allows to disable CTS hardware flow control for a given UART instance, ++ * without need to call HAL_UART_Init() function. ++ * As involving direct access to UART registers, usage of this macro should be fully endorsed by user. ++ * @note As macro is expected to be used for modifying CTS Hw flow control feature activation, without need ++ * for USART instance Deinit/Init, following conditions for macro call should be fulfilled : ++ * - UART instance should have already been initialised (through call of HAL_UART_Init() ) ++ * - macro could only be called when corresponding UART instance is disabled (i.e. __HAL_UART_DISABLE(__HANDLE__)) ++ * and should be followed by an Enable macro (i.e. __HAL_UART_ENABLE(__HANDLE__)). ++ * @param __HANDLE__: specifies the UART Handle. ++ * @retval None ++ */ ++#define __HAL_UART_HWCONTROL_CTS_DISABLE(__HANDLE__) \ ++ do { \ ++ CLEAR_BIT((__HANDLE__)->Instance->CR3, USART_CR3_CTSE); \ ++ (__HANDLE__)->Init.HwFlowCtl &= ~(USART_CR3_CTSE); \ ++ } while (0) ++ ++/** @brief Enable RTS flow control. ++ * @note This macro allows to enable RTS hardware flow control for a given UART instance, ++ * without need to call HAL_UART_Init() function. ++ * As involving direct access to UART registers, usage of this macro should be fully endorsed by user. ++ * @note As macro is expected to be used for modifying RTS Hw flow control feature activation, without need ++ * for USART instance Deinit/Init, following conditions for macro call should be fulfilled : ++ * - UART instance should have already been initialised (through call of HAL_UART_Init() ) ++ * - macro could only be called when corresponding UART instance is disabled (i.e. __HAL_UART_DISABLE(__HANDLE__)) ++ * and should be followed by an Enable macro (i.e. __HAL_UART_ENABLE(__HANDLE__)). ++ * @param __HANDLE__: specifies the UART Handle. ++ * @retval None ++ */ ++#define __HAL_UART_HWCONTROL_RTS_ENABLE(__HANDLE__) \ ++ do { \ ++ SET_BIT((__HANDLE__)->Instance->CR3, USART_CR3_RTSE); \ ++ (__HANDLE__)->Init.HwFlowCtl |= USART_CR3_RTSE; \ ++ } while (0) ++ ++/** @brief Disable RTS flow control. ++ * @note This macro allows to disable RTS hardware flow control for a given UART instance, ++ * without need to call HAL_UART_Init() function. ++ * As involving direct access to UART registers, usage of this macro should be fully endorsed by user. ++ * @note As macro is expected to be used for modifying RTS Hw flow control feature activation, without need ++ * for USART instance Deinit/Init, following conditions for macro call should be fulfilled : ++ * - UART instance should have already been initialised (through call of HAL_UART_Init() ) ++ * - macro could only be called when corresponding UART instance is disabled (i.e. __HAL_UART_DISABLE(__HANDLE__)) ++ * and should be followed by an Enable macro (i.e. __HAL_UART_ENABLE(__HANDLE__)). ++ * @param __HANDLE__: specifies the UART Handle. ++ * @retval None ++ */ ++#define __HAL_UART_HWCONTROL_RTS_DISABLE(__HANDLE__) \ ++ do { \ ++ CLEAR_BIT((__HANDLE__)->Instance->CR3, USART_CR3_RTSE);\ ++ (__HANDLE__)->Init.HwFlowCtl &= ~(USART_CR3_RTSE); \ ++ } while (0) ++ ++/** ++ * @} ++ */ ++ ++/* Private variables -----------------------------------------------------*/ ++/** @defgroup UART_Private_Variables UART Private Variables ++ * @{ ++ */ ++static const uint16_t presc_table[12] = { ++ 1, 2, 4, 6, 8, 10, 12, 16, 32, 64, 128, 256 ++}; ++ ++/** @brief BRR division operation to set BRR register in 8-bit oversampling ++ * mode. ++ * @param clockfreq: UART clock. ++ * @param baud_rate: Baud rate set by the user. ++ * @param prescaler: UART prescaler value. ++ * @retval Division result ++ */ ++static inline uint32_t uart_div_sampling8(unsigned long clockfreq, ++ uint32_t baud_rate, ++ uint32_t prescaler) ++{ ++ uint32_t scaled_freq = clockfreq / presc_table[prescaler]; ++ ++ return ((scaled_freq * 2) + (baud_rate / 2)) / baud_rate; ++ ++} ++ ++/** @brief BRR division operation to set BRR register in 16-bit oversampling ++ * mode. ++ * @param clockfreq: UART clock. ++ * @param baud_rate: Baud rate set by the user. ++ * @param prescaler: UART prescaler value. ++ * @retval Division result ++ */ ++static inline uint32_t uart_div_sampling16(unsigned long clockfreq, ++ uint32_t baud_rate, ++ uint32_t prescaler) ++{ ++ uint32_t scaled_freq = clockfreq / presc_table[prescaler]; ++ ++ return (scaled_freq + (baud_rate / 2)) / baud_rate; ++ ++} ++ ++/* Private macros --------------------------------------------------------*/ ++/** @defgroup UART_Private_Macros UART Private Macros ++ * @{ ++ */ ++/** @brief Check UART Baud rate. ++ * @param __BAUDRATE__: Baudrate specified by the user. ++ * The maximum Baud Rate is derived from the maximum clock on MP1 (i.e. 100 MHz) ++ * divided by the smallest oversampling used on the USART (i.e. 8) ++ * @retval SET (__BAUDRATE__ is valid) or RESET (__BAUDRATE__ is invalid) ++ */ ++#define IS_UART_BAUDRATE(__BAUDRATE__) ((__BAUDRATE__) < 12500001U) ++ ++/** @brief Check UART assertion time. ++ * @param __TIME__: 5-bit value assertion time. ++ * @retval Test result (TRUE or FALSE). ++ */ ++#define IS_UART_ASSERTIONTIME(__TIME__) ((__TIME__) <= 0x1FU) ++ ++/** @brief Check UART deassertion time. ++ * @param __TIME__: 5-bit value deassertion time. ++ * @retval Test result (TRUE or FALSE). ++ */ ++#define IS_UART_DEASSERTIONTIME(__TIME__) ((__TIME__) <= 0x1FU) ++ ++/** ++ * @brief Ensure that UART frame number of stop bits is valid. ++ * @param __STOPBITS__: UART frame number of stop bits. ++ * @retval SET (__STOPBITS__ is valid) or RESET (__STOPBITS__ is invalid) ++ */ ++#define IS_UART_STOPBITS(__STOPBITS__) \ ++ (((__STOPBITS__) == UART_STOPBITS_0_5) || \ ++ ((__STOPBITS__) == UART_STOPBITS_1) || \ ++ ((__STOPBITS__) == UART_STOPBITS_1_5) || \ ++ ((__STOPBITS__) == UART_STOPBITS_2)) ++ ++/** ++ * @brief Ensure that UART frame parity is valid. ++ * @param __PARITY__: UART frame parity. ++ * @retval SET (__PARITY__ is valid) or RESET (__PARITY__ is invalid) ++ */ ++#define IS_UART_PARITY(__PARITY__) \ ++ (((__PARITY__) == UART_PARITY_NONE) || \ ++ ((__PARITY__) == UART_PARITY_EVEN) || \ ++ ((__PARITY__) == UART_PARITY_ODD)) ++ ++/** ++ * @brief Ensure that UART hardware flow control is valid. ++ * @param __CONTROL__: UART hardware flow control. ++ * @retval SET (__CONTROL__ is valid) or RESET (__CONTROL__ is invalid) ++ */ ++#define IS_UART_HARDWARE_FLOW_CONTROL(__CONTROL__) \ ++ (((__CONTROL__) == UART_HWCONTROL_NONE) || \ ++ ((__CONTROL__) == UART_HWCONTROL_RTS) || \ ++ ((__CONTROL__) == UART_HWCONTROL_CTS) || \ ++ ((__CONTROL__) == UART_HWCONTROL_RTS_CTS)) ++ ++/** ++ * @brief Ensure that UART communication mode is valid. ++ * @param __MODE__: UART communication mode. ++ * @retval SET (__MODE__ is valid) or RESET (__MODE__ is invalid) ++ */ ++#define IS_UART_MODE(__MODE__) \ ++ ((((__MODE__) & (~((uint32_t)(UART_MODE_TX_RX)))) == \ ++ (uint32_t)0x00) && \ ++ ((__MODE__) != (uint32_t)0x00)) ++ ++/** ++ * @brief Ensure that UART state is valid. ++ * @param __STATE__: UART state. ++ * @retval SET (__STATE__ is valid) or RESET (__STATE__ is invalid) ++ */ ++#define IS_UART_STATE(__STATE__) (((__STATE__) == UART_STATE_DISABLE) || \ ++ ((__STATE__) == UART_STATE_ENABLE)) ++ ++/** ++ * @brief Ensure that UART oversampling is valid. ++ * @param __SAMPLING__: UART oversampling. ++ * @retval SET (__SAMPLING__ is valid) or RESET (__SAMPLING__ is invalid) ++ */ ++#define IS_UART_OVERSAMPLING(__SAMPLING__) \ ++ (((__SAMPLING__) == UART_OVERSAMPLING_16) || \ ++ ((__SAMPLING__) == UART_OVERSAMPLING_8)) ++ ++/** ++ * @brief Ensure that UART frame sampling is valid. ++ * @param __ONEBIT__: UART frame sampling. ++ * @retval SET (__ONEBIT__ is valid) or RESET (__ONEBIT__ is invalid) ++ */ ++#define IS_UART_ONE_BIT_SAMPLE(__ONEBIT__) \ ++ (((__ONEBIT__) == UART_ONE_BIT_SAMPLE_DISABLE) || \ ++ ((__ONEBIT__) == UART_ONE_BIT_SAMPLE_ENABLE)) ++ ++/** ++ * @brief Ensure that UART auto Baud rate detection mode is valid. ++ * @param __MODE__: UART auto Baud rate detection mode. ++ * @retval SET (__MODE__ is valid) or RESET (__MODE__ is invalid) ++ */ ++#define IS_UART_ADVFEATURE_AUTOBAUDRATEMODE(__MODE__) \ ++ (((__MODE__) == UART_ADVFEATURE_AUTOBAUDRATE_ONSTARTBIT) || \ ++ ((__MODE__) == UART_ADVFEATURE_AUTOBAUDRATE_ONFALLINGEDGE) || \ ++ ((__MODE__) == UART_ADVFEATURE_AUTOBAUDRATE_ON0X7FFRAME) || \ ++ ((__MODE__) == UART_ADVFEATURE_AUTOBAUDRATE_ON0X55FRAME)) ++ ++/** ++ * @brief Ensure that UART receiver timeout setting is valid. ++ * @param __TIMEOUT__: UART receiver timeout setting. ++ * @retval SET (__TIMEOUT__ is valid) or RESET (__TIMEOUT__ is invalid) ++ */ ++#define IS_UART_RECEIVER_TIMEOUT(__TIMEOUT__) \ ++ (((__TIMEOUT__) == UART_RECEIVER_TIMEOUT_DISABLE) || \ ++ ((__TIMEOUT__) == UART_RECEIVER_TIMEOUT_ENABLE)) ++ ++/** ++ * @brief Ensure that UART LIN state is valid. ++ * @param __LIN__: UART LIN state. ++ * @retval SET (__LIN__ is valid) or RESET (__LIN__ is invalid) ++ */ ++#define IS_UART_LIN(__LIN__) \ ++ (((__LIN__) == UART_LIN_DISABLE) || \ ++ ((__LIN__) == UART_LIN_ENABLE)) ++ ++/** ++ * @brief Ensure that UART LIN break detection length is valid. ++ * @param __LENGTH__: UART LIN break detection length. ++ * @retval SET (__LENGTH__ is valid) or RESET (__LENGTH__ is invalid) ++ */ ++#define IS_UART_LIN_BREAK_DETECT_LENGTH(__LENGTH__) \ ++ (((__LENGTH__) == UART_LINBREAKDETECTLENGTH_10B) || \ ++ ((__LENGTH__) == UART_LINBREAKDETECTLENGTH_11B)) ++ ++/** ++ * @brief Ensure that UART DMA TX state is valid. ++ * @param __DMATX__: UART DMA TX state. ++ * @retval SET (__DMATX__ is valid) or RESET (__DMATX__ is invalid) ++ */ ++#define IS_UART_DMA_TX(__DMATX__) \ ++ (((__DMATX__) == UART_DMA_TX_DISABLE) || \ ++ ((__DMATX__) == UART_DMA_TX_ENABLE)) ++ ++/** ++ * @brief Ensure that UART DMA RX state is valid. ++ * @param __DMARX__: UART DMA RX state. ++ * @retval SET (__DMARX__ is valid) or RESET (__DMARX__ is invalid) ++ */ ++#define IS_UART_DMA_RX(__DMARX__) \ ++ (((__DMARX__) == UART_DMA_RX_DISABLE) || \ ++ ((__DMARX__) == UART_DMA_RX_ENABLE)) ++ ++/** ++ * @brief Ensure that UART half-duplex state is valid. ++ * @param __HDSEL__: UART half-duplex state. ++ * @retval SET (__HDSEL__ is valid) or RESET (__HDSEL__ is invalid) ++ */ ++#define IS_UART_HALF_DUPLEX(__HDSEL__) \ ++ (((__HDSEL__) == UART_HALF_DUPLEX_DISABLE) || \ ++ ((__HDSEL__) == UART_HALF_DUPLEX_ENABLE)) ++ ++/** ++ * @brief Ensure that UART wake-up method is valid. ++ * @param __WAKEUP__: UART wake-up method . ++ * @retval SET (__WAKEUP__ is valid) or RESET (__WAKEUP__ is invalid) ++ */ ++#define IS_UART_WAKEUPMETHOD(__WAKEUP__) \ ++ (((__WAKEUP__) == UART_WAKEUPMETHOD_IDLELINE) || \ ++ ((__WAKEUP__) == UART_WAKEUPMETHOD_ADDRESSMARK)) ++ ++/** ++ * @brief Ensure that UART request parameter is valid. ++ * @param __PARAM__: UART request parameter. ++ * @retval SET (__PARAM__ is valid) or RESET (__PARAM__ is invalid) ++ */ ++#define IS_UART_REQUEST_PARAMETER(__PARAM__) \ ++ (((__PARAM__) == UART_AUTOBAUD_REQUEST) || \ ++ ((__PARAM__) == UART_SENDBREAK_REQUEST) || \ ++ ((__PARAM__) == UART_MUTE_MODE_REQUEST) || \ ++ ((__PARAM__) == UART_RXDATA_FLUSH_REQUEST) || \ ++ ((__PARAM__) == UART_TXDATA_FLUSH_REQUEST)) ++ ++/** ++ * @brief Ensure that UART advanced features initialization is valid. ++ * @param __INIT__: UART advanced features initialization. ++ * @retval SET (__INIT__ is valid) or RESET (__INIT__ is invalid) ++ */ ++#define IS_UART_ADVFEATURE_INIT(__INIT__) \ ++ ((__INIT__) <= (UART_ADVFEATURE_NO_INIT | \ ++ UART_ADVFEATURE_TXINVERT_INIT | \ ++ UART_ADVFEATURE_RXINVERT_INIT | \ ++ UART_ADVFEATURE_DATAINVERT_INIT | \ ++ UART_ADVFEATURE_SWAP_INIT | \ ++ UART_ADVFEATURE_RXOVERRUNDISABLE_INIT | \ ++ UART_ADVFEATURE_DMADISABLEONERROR_INIT | \ ++ UART_ADVFEATURE_AUTOBAUDRATE_INIT | \ ++ UART_ADVFEATURE_MSBFIRST_INIT)) ++ ++/** ++ * @brief Ensure that UART frame TX inversion setting is valid. ++ * @param __TXINV__: UART frame TX inversion setting. ++ * @retval SET (__TXINV__ is valid) or RESET (__TXINV__ is invalid) ++ */ ++#define IS_UART_ADVFEATURE_TXINV(__TXINV__) \ ++ (((__TXINV__) == UART_ADVFEATURE_TXINV_DISABLE) || \ ++ ((__TXINV__) == UART_ADVFEATURE_TXINV_ENABLE)) ++ ++/** ++ * @brief Ensure that UART frame RX inversion setting is valid. ++ * @param __RXINV__: UART frame RX inversion setting. ++ * @retval SET (__RXINV__ is valid) or RESET (__RXINV__ is invalid) ++ */ ++#define IS_UART_ADVFEATURE_RXINV(__RXINV__) \ ++ (((__RXINV__) == UART_ADVFEATURE_RXINV_DISABLE) || \ ++ ((__RXINV__) == UART_ADVFEATURE_RXINV_ENABLE)) ++ ++/** ++ * @brief Ensure that UART frame data inversion setting is valid. ++ * @param __DATAINV__: UART frame data inversion setting. ++ * @retval SET (__DATAINV__ is valid) or RESET (__DATAINV__ is invalid) ++ */ ++#define IS_UART_ADVFEATURE_DATAINV(__DATAINV__) \ ++ (((__DATAINV__) == UART_ADVFEATURE_DATAINV_DISABLE) || \ ++ ((__DATAINV__) == UART_ADVFEATURE_DATAINV_ENABLE)) ++ ++/** ++ * @brief Ensure that UART frame RX/TX pins swap setting is valid. ++ * @param __SWAP__: UART frame RX/TX pins swap setting. ++ * @retval SET (__SWAP__ is valid) or RESET (__SWAP__ is invalid) ++ */ ++#define IS_UART_ADVFEATURE_SWAP(__SWAP__) \ ++ (((__SWAP__) == UART_ADVFEATURE_SWAP_DISABLE) || \ ++ ((__SWAP__) == UART_ADVFEATURE_SWAP_ENABLE)) ++ ++/** ++ * @brief Ensure that UART frame overrun setting is valid. ++ * @param __OVERRUN__: UART frame overrun setting. ++ * @retval SET (__OVERRUN__ is valid) or RESET (__OVERRUN__ is invalid) ++ */ ++#define IS_UART_OVERRUN(__OVERRUN__) \ ++ (((__OVERRUN__) == UART_ADVFEATURE_OVERRUN_ENABLE) || \ ++ ((__OVERRUN__) == UART_ADVFEATURE_OVERRUN_DISABLE)) ++ ++/** ++ * @brief Ensure that UART auto Baud rate state is valid. ++ * @param __AUTOBAUDRATE__: UART auto Baud rate state. ++ * @retval SET (__AUTOBAUDRATE__ is valid) or RESET (__AUTOBAUDRATE__ is invalid) ++ */ ++#define IS_UART_ADVFEATURE_AUTOBAUDRATE(__AUTOBAUDRATE__) \ ++ (((__AUTOBAUDRATE__) == UART_ADVFEATURE_AUTOBAUDRATE_DISABLE) || \ ++ ((__AUTOBAUDRATE__) == UART_ADVFEATURE_AUTOBAUDRATE_ENABLE)) ++ ++/** ++ * @brief Ensure that UART DMA enabling or disabling on error setting is valid. ++ * @param __DMA__: UART DMA enabling or disabling on error setting. ++ * @retval SET (__DMA__ is valid) or RESET (__DMA__ is invalid) ++ */ ++#define IS_UART_ADVFEATURE_DMAONRXERROR(__DMA__) \ ++ (((__DMA__) == UART_ADVFEATURE_DMA_ENABLEONRXERROR) || \ ++ ((__DMA__) == UART_ADVFEATURE_DMA_DISABLEONRXERROR)) ++ ++/** ++ * @brief Ensure that UART frame MSB first setting is valid. ++ * @param __MSBFIRST__: UART frame MSB first setting. ++ * @retval SET (__MSBFIRST__ is valid) or RESET (__MSBFIRST__ is invalid) ++ */ ++#define IS_UART_ADVFEATURE_MSBFIRST(__MSBFIRST__) \ ++ (((__MSBFIRST__) == UART_ADVFEATURE_MSBFIRST_DISABLE) || \ ++ ((__MSBFIRST__) == UART_ADVFEATURE_MSBFIRST_ENABLE)) ++ ++/** ++ * @brief Ensure that UART stop mode state is valid. ++ * @param __STOPMODE__: UART stop mode state. ++ * @retval SET (__STOPMODE__ is valid) or RESET (__STOPMODE__ is invalid) ++ */ ++#define IS_UART_ADVFEATURE_STOPMODE(__STOPMODE__) \ ++ (((__STOPMODE__) == UART_ADVFEATURE_STOPMODE_DISABLE) || \ ++ ((__STOPMODE__) == UART_ADVFEATURE_STOPMODE_ENABLE)) ++ ++/** ++ * @brief Ensure that UART mute mode state is valid. ++ * @param __MUTE__: UART mute mode state. ++ * @retval SET (__MUTE__ is valid) or RESET (__MUTE__ is invalid) ++ */ ++#define IS_UART_MUTE_MODE(__MUTE__) \ ++ (((__MUTE__) == UART_ADVFEATURE_MUTEMODE_DISABLE) || \ ++ ((__MUTE__) == UART_ADVFEATURE_MUTEMODE_ENABLE)) ++ ++/** ++ * @brief Ensure that UART wake-up selection is valid. ++ * @param __WAKE__: UART wake-up selection. ++ * @retval SET (__WAKE__ is valid) or RESET (__WAKE__ is invalid) ++ */ ++#define IS_UART_WAKEUP_SELECTION(__WAKE__) \ ++ (((__WAKE__) == UART_WAKEUP_ON_ADDRESS) || \ ++ ((__WAKE__) == UART_WAKEUP_ON_STARTBIT) || \ ++ ((__WAKE__) == UART_WAKEUP_ON_READDATA_NONEMPTY) || \ ++ ((__WAKE__) == UART_WAKEUP_ON_RXFIFO_THRESHOLD) || \ ++ ((__WAKE__) == UART_WAKEUP_ON_RXFIFO_FULL) || \ ++ ((__WAKE__) == UART_WAKEUP_ON_TXFIFO_THRESHOLD) || \ ++ ((__WAKE__) == UART_WAKEUP_ON_TXFIFO_EMPTY)) ++ ++/** ++ * @brief Ensure that UART driver enable polarity is valid. ++ * @param __POLARITY__: UART driver enable polarity. ++ * @retval SET (__POLARITY__ is valid) or RESET (__POLARITY__ is invalid) ++ */ ++#define IS_UART_DE_POLARITY(__POLARITY__) \ ++ (((__POLARITY__) == UART_DE_POLARITY_HIGH) || \ ++ ((__POLARITY__) == UART_DE_POLARITY_LOW)) ++ ++/** ++ * @brief Ensure that UART Prescaler is valid. ++ * @param __PRESCALER__: UART Prescaler value. ++ * @retval SET (__PRESCALER__ is valid) or RESET (__PRESCALER__ is invalid) ++ */ ++#define IS_UART_PRESCALER(__PRESCALER__) \ ++ (((__PRESCALER__) == UART_PRESCALER_DIV1) || \ ++ ((__PRESCALER__) == UART_PRESCALER_DIV2) || \ ++ ((__PRESCALER__) == UART_PRESCALER_DIV4) || \ ++ ((__PRESCALER__) == UART_PRESCALER_DIV6) || \ ++ ((__PRESCALER__) == UART_PRESCALER_DIV8) || \ ++ ((__PRESCALER__) == UART_PRESCALER_DIV10) || \ ++ ((__PRESCALER__) == UART_PRESCALER_DIV12) || \ ++ ((__PRESCALER__) == UART_PRESCALER_DIV16) || \ ++ ((__PRESCALER__) == UART_PRESCALER_DIV32) || \ ++ ((__PRESCALER__) == UART_PRESCALER_DIV64) || \ ++ ((__PRESCALER__) == UART_PRESCALER_DIV128) || \ ++ ((__PRESCALER__) == UART_PRESCALER_DIV256)) ++ ++/** ++ * @brief Ensure that UART FIFO mode is valid. ++ * @param __STATE__: UART FIFO mode. ++ * @retval SET (__STATE__ is valid) or RESET (__STATE__ is invalid) ++ */ ++#define IS_UART_FIFO_MODE_STATE(__STATE__) \ ++ (((__STATE__) == UART_FIFOMODE_DISABLE) || \ ++ ((__STATE__) == UART_FIFOMODE_ENABLE)) ++ ++/** ++ * @brief Ensure that UART TXFIFO threshold level is valid. ++ * @param __THRESHOLD__: UART TXFIFO threshold level. ++ * @retval SET (__THRESHOLD__ is valid) or RESET (__THRESHOLD__ is invalid) ++ */ ++#define IS_UART_TXFIFO_THRESHOLD(__THRESHOLD__) \ ++ ((((__THRESHOLD__) == UART_TXFIFO_THRESHOLD_1EIGHTHFULL) || \ ++ ((__THRESHOLD__) == UART_TXFIFO_THRESHOLD_1QUARTERFULL) || \ ++ ((__THRESHOLD__) == UART_TXFIFO_THRESHOLD_HALFFULL) || \ ++ ((__THRESHOLD__) == UART_TXFIFO_THRESHOLD_3QUARTERSFULL) || \ ++ ((__THRESHOLD__) == UART_TXFIFO_THRESHOLD_7EIGHTHFULL)) || \ ++ ((__THRESHOLD__) == UART_TXFIFO_THRESHOLD_EMPTY)) ++ ++/** ++ * @brief Ensure that UART RXFIFO threshold level is valid. ++ * @param __THRESHOLD__: UART RXFIFO threshold level. ++ * @retval SET (__THRESHOLD__ is valid) or RESET (__THRESHOLD__ is invalid) ++ */ ++#define IS_UART_RXFIFO_THRESHOLD(__THRESHOLD__) \ ++ ((((__THRESHOLD__) == UART_RXFIFO_THRESHOLD_1EIGHTHFULL) || \ ++ ((__THRESHOLD__) == UART_RXFIFO_THRESHOLD_1QUARTERFULL) || \ ++ ((__THRESHOLD__) == UART_RXFIFO_THRESHOLD_HALFFULL) || \ ++ ((__THRESHOLD__) == UART_RXFIFO_THRESHOLD_3QUARTERSFULL) || \ ++ ((__THRESHOLD__) == UART_RXFIFO_THRESHOLD_7EIGHTHFULL)) || \ ++ ((__THRESHOLD__) == UART_RXFIFO_THRESHOLD_FULL)) ++ ++/* Include UART HAL Extension module */ ++#include "stm32mp1xx_hal_uart_ex.h" ++ ++/* Initialization and de-initialization functions ****************************/ ++HAL_StatusTypeDef HAL_UART_Init(UART_HandleTypeDef *huart); ++ ++/* IO operation functions *****************************************************/ ++HAL_StatusTypeDef HAL_UART_Transmit(UART_HandleTypeDef *huart, uint8_t *pData, ++ uint16_t Size, uint32_t Timeout); ++HAL_StatusTypeDef HAL_UART_Receive(UART_HandleTypeDef *huart, uint8_t *pData, ++ uint16_t Size, uint32_t Timeout); ++ ++/* Peripheral State and Errors functions **************************************************/ ++HAL_UART_StateTypeDef HAL_UART_GetState(UART_HandleTypeDef *huart); ++uint32_t HAL_UART_GetError(UART_HandleTypeDef *huart); ++ ++/* Private functions -----------------------------------------------------------*/ ++/** @addtogroup UART_Private_Functions UART Private Functions ++ * @{ ++ */ ++ ++HAL_StatusTypeDef UART_SetConfig(UART_HandleTypeDef *huart); ++HAL_StatusTypeDef UART_CheckIdleState(UART_HandleTypeDef *huart); ++HAL_StatusTypeDef UART_WaitOnFlagUntilTimeout(UART_HandleTypeDef *huart, ++ uint32_t Flag, FlagStatus Status, ++ uint32_t Tickstart, ++ uint32_t Timeout); ++void UART_AdvFeatureConfig(UART_HandleTypeDef *huart); ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif /* __STM32MP1xx_HAL_UART_H */ ++ ++/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ +diff --git a/include/drivers/st/stm32mp1xx_hal_uart_ex.h b/include/drivers/st/stm32mp1xx_hal_uart_ex.h +new file mode 100644 +index 0000000..193f870 +--- /dev/null ++++ b/include/drivers/st/stm32mp1xx_hal_uart_ex.h +@@ -0,0 +1,87 @@ ++/** ++ ****************************************************************************** ++ * @file stm32mp1xx_hal_uart_ex.h ++ * @author MCD Application Team ++ * @version $VERSION$ ++ * @date $DATE$ ++ * @brief Header file of UART HAL Extended module. ++ ****************************************************************************** ++ * @attention ++ * ++ *

© COPYRIGHT(c) 2015-2017 STMicroelectronics

++ * ++ * SPDX-License-Identifier: BSD-3-Clause ++ * ++ ****************************************************************************** ++ */ ++ ++/* Define to prevent recursive inclusion -------------------------------------*/ ++#ifndef __STM32MP1xx_HAL_UART_EX_H ++#define __STM32MP1xx_HAL_UART_EX_H ++ ++/* Exported constants --------------------------------------------------------*/ ++/** @defgroup UARTEx_Exported_Constants UARTEx Exported Constants ++ * @{ ++ */ ++ ++/** @defgroup UARTEx_Word_Length UART Word Length ++ * @{ ++ */ ++#define UART_WORDLENGTH_7B ((uint32_t)USART_CR1_M1) /*!< 7-bit long UART frame */ ++#define UART_WORDLENGTH_8B ((uint32_t)0x00000000U) /*!< 8-bit long UART frame */ ++#define UART_WORDLENGTH_9B ((uint32_t)USART_CR1_M0) /*!< 9-bit long UART frame */ ++ ++/* Private macros ------------------------------------------------------------*/ ++/** @defgroup UARTEx_Private_Macros UARTEx Private Macros ++ * @{ ++ */ ++ ++/** @brief Report the UART mask to apply to retrieve the received data ++ * according to the word length and to the parity bits activation. ++ * @note If PCE = 1, the parity bit is not included in the data extracted ++ * by the reception API(). ++ * This masking operation is not carried out in the case of ++ * DMA transfers. ++ * @param __HANDLE__: specifies the UART Handle. ++ * @retval None, the mask to apply to UART RDR register is stored in (__HANDLE__)->Mask field. ++ */ ++#define UART_MASK_COMPUTATION(__HANDLE__) \ ++ do { \ ++ if ((__HANDLE__)->Init.WordLength == UART_WORDLENGTH_9B) \ ++ { \ ++ if ((__HANDLE__)->Init.Parity == UART_PARITY_NONE) \ ++ { \ ++ (__HANDLE__)->Mask = 0x01FF ; \ ++ } \ ++ else \ ++ { \ ++ (__HANDLE__)->Mask = 0x00FF ; \ ++ } \ ++ } \ ++ else if ((__HANDLE__)->Init.WordLength == UART_WORDLENGTH_8B) \ ++ { \ ++ if ((__HANDLE__)->Init.Parity == UART_PARITY_NONE) \ ++ { \ ++ (__HANDLE__)->Mask = 0x00FF ; \ ++ } \ ++ else \ ++ { \ ++ (__HANDLE__)->Mask = 0x007F ; \ ++ } \ ++ } \ ++ else if ((__HANDLE__)->Init.WordLength == UART_WORDLENGTH_7B) \ ++ { \ ++ if ((__HANDLE__)->Init.Parity == UART_PARITY_NONE) \ ++ { \ ++ (__HANDLE__)->Mask = 0x007F ; \ ++ } \ ++ else \ ++ { \ ++ (__HANDLE__)->Mask = 0x003F ; \ ++ } \ ++ } \ ++} while(0) ++ ++#endif /* __STM32MP1xx_HAL_UART_EX_H */ ++ ++/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ +diff --git a/include/drivers/st/stm32mp_clkfunc.h b/include/drivers/st/stm32mp_clkfunc.h +new file mode 100644 +index 0000000..c77c0b5 +--- /dev/null ++++ b/include/drivers/st/stm32mp_clkfunc.h +@@ -0,0 +1,28 @@ ++/* ++ * Copyright (c) 2017-2018, STMicroelectronics - All Rights Reserved ++ * ++ * SPDX-License-Identifier: BSD-3-Clause ++ */ ++ ++#ifndef STM32MP_CLKFUNC_H ++#define STM32MP_CLKFUNC_H ++ ++#include ++#include ++ ++int fdt_get_rcc_node(void *fdt); ++uint32_t fdt_rcc_read_addr(void); ++int fdt_rcc_read_uint32_array(const char *prop_name, ++ uint32_t *array, uint32_t count); ++uint32_t fdt_rcc_read_uint32_default(const char *prop_name, ++ uint32_t dflt_value); ++int fdt_rcc_subnode_offset(const char *name); ++const fdt32_t *fdt_rcc_read_prop(const char *prop_name, int *lenp); ++bool fdt_get_rcc_secure_status(void); ++ ++uintptr_t fdt_get_stgen_base(void); ++int fdt_get_clock_id(int node); ++int fdt_get_clock_id_by_name(int node, const char *name); ++unsigned long fdt_get_uart_clock_freq(uintptr_t instance); ++ ++#endif /* STM32MP_CLKFUNC_H */ +diff --git a/include/drivers/st/stm32mp_pmic.h b/include/drivers/st/stm32mp_pmic.h +new file mode 100644 +index 0000000..39c80e4 +--- /dev/null ++++ b/include/drivers/st/stm32mp_pmic.h +@@ -0,0 +1,24 @@ ++/* ++ * Copyright (c) 2017-2018, STMicroelectronics - All Rights Reserved ++ * ++ * SPDX-License-Identifier: BSD-3-Clause ++ */ ++ ++#ifndef STM32MP_PMIC_H ++#define STM32MP_PMIC_H ++ ++#include ++#include ++#include ++ ++int dt_pmic_status(void); ++int dt_pmic_configure_boot_on_regulators(void); ++int dt_pmic_set_lp_config(const char *node_name); ++bool initialize_pmic_i2c(void); ++void initialize_pmic(void); ++#if STM32MP1_DEBUG_ENABLE ++int pmic_keep_debug_unit(void); ++#endif ++int pmic_ddr_power_init(enum ddr_type ddr_type); ++ ++#endif /* STM32MP_PMIC_H */ +diff --git a/include/drivers/st/stm32mp_reset.h b/include/drivers/st/stm32mp_reset.h +new file mode 100644 +index 0000000..5bd159f +--- /dev/null ++++ b/include/drivers/st/stm32mp_reset.h +@@ -0,0 +1,15 @@ ++/* ++ * Copyright (c) 2018, STMicroelectronics - All Rights Reserved ++ * ++ * SPDX-License-Identifier: BSD-3-Clause ++ */ ++ ++#ifndef STM32MP_RESET_H ++#define STM32MP_RESET_H ++ ++#include ++ ++void stm32mp_reset_assert(uint32_t reset_id); ++void stm32mp_reset_deassert(uint32_t reset_id); ++ ++#endif /* STM32MP_RESET_H */ +diff --git a/include/drivers/st/stpmic1.h b/include/drivers/st/stpmic1.h +new file mode 100644 +index 0000000..803a69e +--- /dev/null ++++ b/include/drivers/st/stpmic1.h +@@ -0,0 +1,173 @@ ++/* ++ * Copyright (c) 2016-2018, STMicroelectronics - All Rights Reserved ++ * ++ * SPDX-License-Identifier: BSD-3-Clause ++ */ ++ ++#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 0 ++#define BUCK2_MASK_RESET 1 ++#define BUCK3_MASK_RESET 2 ++#define BUCK4_MASK_RESET 3 ++ ++/* LDO Mask reset register */ ++#define LDO1_MASK_RESET 0 ++#define LDO2_MASK_RESET 1 ++#define LDO3_MASK_RESET 2 ++#define LDO4_MASK_RESET 3 ++#define LDO5_MASK_RESET 4 ++#define LDO6_MASK_RESET 5 ++#define VREF_DDR_MASK_RESET 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_pull_down_set(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); ++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/include/drivers/st/stpmu1.h b/include/drivers/st/stpmu1.h +deleted file mode 100644 +index 1b93ab2..0000000 +--- a/include/drivers/st/stpmu1.h ++++ /dev/null +@@ -1,141 +0,0 @@ +-/* +- * Copyright (c) 2016-2018, STMicroelectronics - All Rights Reserved +- * +- * SPDX-License-Identifier: BSD-3-Clause +- */ +- +- +-#ifndef __STPMU1_H__ +-#define __STPMU1_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 +-#define LDO_VOLTAGE_MASK 0x7CU +-#define BUCK_VOLTAGE_MASK 0xFCU +-#define LDO_BUCK_VOLTAGE_SHIFT 2 +-#define LDO_ENABLE_MASK 0x01U +-#define BUCK_ENABLE_MASK 0x01U +-#define BUCK_HPLP_ENABLE_MASK 0x02U +-#define LDO_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 +- +-/* 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 stpmu1_switch_off(void); +-int stpmu1_register_read(uint8_t register_id, uint8_t *value); +-int stpmu1_register_write(uint8_t register_id, uint8_t value); +-int stpmu1_register_update(uint8_t register_id, uint8_t value, uint8_t mask); +-int stpmu1_regulator_enable(const char *name); +-int stpmu1_regulator_disable(const char *name); +-uint8_t stpmu1_is_regulator_enabled(const char *name); +-int stpmu1_regulator_voltage_set(const char *name, uint16_t millivolts); +-void stpmu1_bind_i2c(struct i2c_handle_s *i2c_handle, uint16_t i2c_addr); +- +-#endif /* __STPMU1_H__ */ +diff --git a/include/drivers/st/usb_dwc2.h b/include/drivers/st/usb_dwc2.h +new file mode 100644 +index 0000000..85628f1 +--- /dev/null ++++ b/include/drivers/st/usb_dwc2.h +@@ -0,0 +1,443 @@ ++/* ++ * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved. ++ * ++ * SPDX-License-Identifier: BSD-3-Clause ++ */ ++ ++#ifndef __USB_DWC2_H ++#define __USB_DWC2_H ++ ++#include ++ ++/* define value use in register */ ++ ++#define USB_OTG_MODE_DEVICE 0 ++#define USB_OTG_MODE_HOST 1 ++#define USB_OTG_MODE_DRD 2 ++ ++#define DSTS_ENUMSPD_HS_PHY_30MHZ_OR_60MHZ (0 << 1) ++#define DSTS_ENUMSPD_FS_PHY_30MHZ_OR_60MHZ (1 << 1) ++#define DSTS_ENUMSPD_LS_PHY_6MHZ (2 << 1) ++#define DSTS_ENUMSPD_FS_PHY_48MHZ (3 << 1) ++ ++#define EP_TYPE_CTRL 0 ++#define EP_TYPE_ISOC 1 ++#define EP_TYPE_BULK 2 ++#define EP_TYPE_INTR 3 ++ ++#define STS_GOUT_NAK 1 ++#define STS_DATA_UPDT 2 ++#define STS_XFER_COMP 3 ++#define STS_SETUP_COMP 4 ++#define STS_SETUP_UPDT 6 ++ ++#define USBD_HS_TRDT_VALUE 9 ++ ++#define USB_OTG_DEVICE_BASE ((uint32_t)0x800) ++#define USB_OTG_IN_ENDPOINT_BASE ((uint32_t)0x900) ++#define USB_OTG_OUT_ENDPOINT_BASE ((uint32_t)0xB00) ++#define USB_OTG_FIFO_BASE ((uint32_t)0x1000) ++#define USB_OTG_FIFO_SIZE ((uint32_t)0x1000) ++#define USB_MAX_ENDPOINT_NB 0x10 ++ ++/* Bit definition for register */ ++/* USB_OTG_GRSTCTL register */ ++/* Core soft reset */ ++#define USB_OTG_GRSTCTL_CSRST ((uint32_t)0x00000001) ++/* HCLK soft reset */ ++#define USB_OTG_GRSTCTL_HSRST ((uint32_t)0x00000002) ++/* Host frame counter reset */ ++#define USB_OTG_GRSTCTL_FCRST ((uint32_t)0x00000004) ++/* RxFIFOflush */ ++#define USB_OTG_GRSTCTL_RXFFLSH ((uint32_t)0x00000010) ++/* TxFIFOflush */ ++#define USB_OTG_GRSTCTL_TXFFLSH ((uint32_t)0x00000020) ++ ++/* USB_OTG_DIEPCTLregister */ ++/* Maximum packet size */ ++#define USB_OTG_DIEPCTL_MPSIZ ((uint32_t)0x000007FF) ++/* USB active endpoint */ ++#define USB_OTG_DIEPCTL_USBAEP ((uint32_t)0x00008000) ++/* Even/odd frame */ ++#define USB_OTG_DIEPCTL_EONUM_DPID ((uint32_t)0x00010000) ++/* NAK status */ ++#define USB_OTG_DIEPCTL_NAKSTS ((uint32_t)0x00020000) ++/* Endpoint type */ ++#define USB_OTG_DIEPCTL_EPTYP ((uint32_t)0x000C0000) ++/* Bit0 */ ++#define USB_OTG_DIEPCTL_EPTYP_0 ((uint32_t)0x00040000) ++/* Bit1 */ ++#define USB_OTG_DIEPCTL_EPTYP_1 ((uint32_t)0x00080000) ++/* STALL handshake */ ++#define USB_OTG_DIEPCTL_STALL ((uint32_t)0x00200000) ++/* TxFIFO number */ ++#define USB_OTG_DIEPCTL_TXFNUM ((uint32_t)0x03C00000) ++/* Bit0 */ ++#define USB_OTG_DIEPCTL_TXFNUM_0 ((uint32_t)0x00400000) ++/* Bit1 */ ++#define USB_OTG_DIEPCTL_TXFNUM_1 ((uint32_t)0x00800000) ++/* Bit2 */ ++#define USB_OTG_DIEPCTL_TXFNUM_2 ((uint32_t)0x01000000) ++/* Bit3 */ ++#define USB_OTG_DIEPCTL_TXFNUM_3 ((uint32_t)0x02000000) ++/* Clear NAK */ ++#define USB_OTG_DIEPCTL_CNAK ((uint32_t)0x04000000) ++/* Set NAK */ ++#define USB_OTG_DIEPCTL_SNAK ((uint32_t)0x08000000) ++/* Set DATA0 PID */ ++#define USB_OTG_DIEPCTL_SD0PID_SEVNFRM ((uint32_t)0x10000000) ++/* Set odd frame */ ++#define USB_OTG_DIEPCTL_SODDFRM ((uint32_t)0x20000000) ++/* Endpoint disable */ ++#define USB_OTG_DIEPCTL_EPDIS ((uint32_t)0x40000000) ++/* Endpoint enable */ ++#define USB_OTG_DIEPCTL_EPENA ((uint32_t)0x80000000) ++ ++/* USB_OTG_DOEPCTL register */ ++/* Maximum packet size */ ++#define USB_OTG_DOEPCTL_MPSIZ ((uint32_t)0x000007FF) ++/* USB active endpoint */ ++#define USB_OTG_DOEPCTL_USBAEP ((uint32_t)0x00008000) ++/* NAK status */ ++#define USB_OTG_DOEPCTL_NAKSTS ((uint32_t)0x00020000) ++/* Set DATA0 PID */ ++#define USB_OTG_DOEPCTL_SD0PID_SEVNFRM ((uint32_t)0x10000000) ++/* Set odd frame */ ++#define USB_OTG_DOEPCTL_SODDFRM ((uint32_t)0x20000000) ++/* Endpoint type */ ++#define USB_OTG_DOEPCTL_EPTYP ((uint32_t)0x000C0000) ++/* Bit0 */ ++#define USB_OTG_DOEPCTL_EPTYP_0 ((uint32_t)0x00040000) ++/* Bit1 */ ++#define USB_OTG_DOEPCTL_EPTYP_1 ((uint32_t)0x00080000) ++/* Snoop mode */ ++#define USB_OTG_DOEPCTL_SNPM ((uint32_t)0x00100000) ++/* STALL handshake */ ++#define USB_OTG_DOEPCTL_STALL ((uint32_t)0x00200000) ++/* Clear NAK */ ++#define USB_OTG_DOEPCTL_CNAK ((uint32_t)0x04000000) ++/* Set NAK */ ++#define USB_OTG_DOEPCTL_SNAK ((uint32_t)0x08000000) ++/* Endpoint disable */ ++#define USB_OTG_DOEPCTL_EPDIS ((uint32_t)0x40000000) ++/* Endpoint enable */ ++#define USB_OTG_DOEPCTL_EPENA ((uint32_t)0x80000000) ++ ++/* USB_OTG_DSTSregister */ ++/* Suspend status */ ++#define USB_OTG_DSTS_SUSPSTS ((uint32_t)0x00000001) ++/* Enumerated speed */ ++#define USB_OTG_DSTS_ENUMSPD ((uint32_t)0x00000006) ++/* Bit0 */ ++#define USB_OTG_DSTS_ENUMSPD_0 ((uint32_t)0x00000002) ++/* Bit1 */ ++#define USB_OTG_DSTS_ENUMSPD_1 ((uint32_t)0x00000004) ++/* Erratic error */ ++#define USB_OTG_DSTS_EERR ((uint32_t)0x00000008) ++/* Frame number of the received SOF */ ++#define USB_OTG_DSTS_FNSOF ((uint32_t)0x003FFF00) ++ ++/* USB_OTG_DCTLregister */ ++/* Remote wakeup signaling */ ++#define USB_OTG_DCTL_RWUSIG ((uint32_t)0x00000001) ++/* Soft disconnect */ ++#define USB_OTG_DCTL_SDIS ((uint32_t)0x00000002) ++/* Global IN NAK status */ ++#define USB_OTG_DCTL_GINSTS ((uint32_t)0x00000004) ++/* Global OUT NAK status */ ++#define USB_OTG_DCTL_GONSTS ((uint32_t)0x00000008) ++/* Test control */ ++#define USB_OTG_DCTL_TCTL ((uint32_t)0x00000070) ++/* Bit0 */ ++#define USB_OTG_DCTL_TCTL_0 ((uint32_t)0x00000010) ++/* Bit1 */ ++#define USB_OTG_DCTL_TCTL_1 ((uint32_t)0x00000020) ++/* Bit2 */ ++#define USB_OTG_DCTL_TCTL_2 ((uint32_t)0x00000040) ++/* Set global IN NAK */ ++#define USB_OTG_DCTL_SGINAK ((uint32_t)0x00000080) ++/* Clear global IN NAK */ ++#define USB_OTG_DCTL_CGINAK ((uint32_t)0x00000100) ++/* Set global OUT NAK */ ++#define USB_OTG_DCTL_SGONAK ((uint32_t)0x00000200) ++/* Clear global OUT NAK */ ++#define USB_OTG_DCTL_CGONAK ((uint32_t)0x00000400) ++/* Power-on programming done */ ++#define USB_OTG_DCTL_POPRGDNE ((uint32_t)0x00000800) ++ ++/* USB_OTG_GAHBCFG register */ ++/* Global interrupt mask */ ++#define USB_OTG_GAHBCFG_GINT ((uint32_t)0x00000001) ++ ++/* USB_OTG_DOEPTSIZr egister */ ++/* Transfer size */ ++#define USB_OTG_DOEPTSIZ_XFRSIZ ((uint32_t)0x0007FFFF) ++/* Packet count */ ++#define USB_OTG_DOEPTSIZ_PKTCNT ((uint32_t)0x1FF80000) ++/* SETUP packet count */ ++#define USB_OTG_DOEPTSIZ_STUPCNT ((uint32_t)0x60000000) ++/* Bit0 */ ++#define USB_OTG_DOEPTSIZ_STUPCNT_0 ((uint32_t)0x20000000) ++/* Bit1 */ ++#define USB_OTG_DOEPTSIZ_STUPCNT_1 ((uint32_t)0x40000000) ++ ++/* USB_OTG_DIEPTSIZ register */ ++/* Transfer size */ ++#define USB_OTG_DIEPTSIZ_XFRSIZ ((uint32_t)0x0007FFFF) ++/* Packet count */ ++#define USB_OTG_DIEPTSIZ_PKTCNT ((uint32_t)0x1FF80000) ++/* Packet count */ ++#define USB_OTG_DIEPTSIZ_MULCNT ((uint32_t)0x60000000) ++ ++/* USB_OTG_DCFG register */ ++/* Device address */ ++#define USB_OTG_DCFG_DAD ((uint32_t)0x000007F0) ++ ++/* USB_OTG_DTXFSTS register */ ++/* IN endpoint Tx FIFO space available */ ++#define USB_OTG_DTXFSTS_INEPTFSAV ((uint32_t)0x0000FFFF) ++ ++/* USB_OTG_GINTSTS register */ ++/* Current mode of operation */ ++#define USB_OTG_GINTSTS_CMOD ((uint32_t)0x00000001) ++/* Modem is match interrupt */ ++#define USB_OTG_GINTSTS_MMIS ((uint32_t)0x00000002) ++/* OTG interrupt */ ++#define USB_OTG_GINTSTS_OTGINT ((uint32_t)0x00000004) ++/* Start offrame */ ++#define USB_OTG_GINTSTS_SOF ((uint32_t)0x00000008) ++/* Rx FIFO nonempty */ ++#define USB_OTG_GINTSTS_RXFLVL ((uint32_t)0x00000010) ++/* Non periodic Tx FIFO empty */ ++#define USB_OTG_GINTSTS_NPTXFE ((uint32_t)0x00000020) ++/* Global IN non periodic NAK effective */ ++#define USB_OTG_GINTSTS_GINAKEFF ((uint32_t)0x00000040) ++/* Global OUT NAK effective */ ++#define USB_OTG_GINTSTS_BOUTNAKEFF ((uint32_t)0x00000080) ++/* Early suspend */ ++#define USB_OTG_GINTSTS_ESUSP ((uint32_t)0x00000400) ++/* USB suspend */ ++#define USB_OTG_GINTSTS_USBSUSP ((uint32_t)0x00000800) ++/* USB reset */ ++#define USB_OTG_GINTSTS_USBRST ((uint32_t)0x00001000) ++/* Enumeration done */ ++#define USB_OTG_GINTSTS_ENUMDNE ((uint32_t)0x00002000) ++/* Isochronous OUT packet dropped interrupt */ ++#define USB_OTG_GINTSTS_ISOODRP ((uint32_t)0x00004000) ++/* End of periodic frame interrupt */ ++#define USB_OTG_GINTSTS_EOPF ((uint32_t)0x00008000) ++/* IN endpoint interrupt */ ++#define USB_OTG_GINTSTS_IEPINT ((uint32_t)0x00040000) ++/* OUT endpoint interrupt */ ++#define USB_OTG_GINTSTS_OEPINT ((uint32_t)0x00080000) ++/* Incomplete isochronous IN transfer */ ++#define USB_OTG_GINTSTS_IISOIXFR ((uint32_t)0x00100000) ++/* Incomplete periodic transfer */ ++#define USB_OTG_GINTSTS_PXFR_INCOMPISOOUT ((uint32_t)0x00200000) ++/* Data fetch suspended */ ++#define USB_OTG_GINTSTS_DATAFSUSP ((uint32_t)0x00400000) ++/* Reset detected interrupt */ ++#define USB_OTG_GINTSTS_RSTDET ((uint32_t)0x00800000) ++/* Host port interrupt */ ++#define USB_OTG_GINTSTS_HPRTINT ((uint32_t)0x01000000) ++/* Host channels interrupt */ ++#define USB_OTG_GINTSTS_HCINT ((uint32_t)0x02000000) ++/* Periodic Tx FIFO empty */ ++#define USB_OTG_GINTSTS_PTXFE ((uint32_t)0x04000000) ++/* LPM interrupt */ ++#define USB_OTG_GINTSTS_LPMINT ((uint32_t)0x08000000) ++/* Connector ID status change */ ++#define USB_OTG_GINTSTS_CIDSCHG ((uint32_t)0x10000000) ++/* Disconnect detected interrupt */ ++#define USB_OTG_GINTSTS_DISCINT ((uint32_t)0x20000000) ++/* Session request/new session detected interrupt */ ++#define USB_OTG_GINTSTS_SRQINT ((uint32_t)0x40000000) ++/* Resume/remote wakeup detected interrupt */ ++#define USB_OTG_GINTSTS_WKUINT ((uint32_t)0x80000000) ++ ++/* USB_OTG_DOEPINT register */ ++/* Transfer completed interrupt */ ++#define USB_OTG_DOEPINT_XFRC ((uint32_t)0x00000001) ++/* Endpoint disabled interrupt */ ++#define USB_OTG_DOEPINT_EPDISD ((uint32_t)0x00000002) ++/* SETUP phase done */ ++#define USB_OTG_DOEPINT_STUP ((uint32_t)0x00000008) ++/* OUT token received when endpoint disabled */ ++#define USB_OTG_DOEPINT_OTEPDIS ((uint32_t)0x00000010) ++/* Back-to-back SETUP packets received */ ++#define USB_OTG_DOEPINT_B2BSTUP ((uint32_t)0x00000040) ++/* NYET interrupt */ ++#define USB_OTG_DOEPINT_NYET ((uint32_t)0x00004000) ++ ++/* USB_OTG_DIEPINTregister */ ++/* Transfer completed interrupt */ ++#define USB_OTG_DIEPINT_XFRC ((uint32_t)0x00000001) ++/* Endpoint disabled interrupt */ ++#define USB_OTG_DIEPINT_EPDISD ((uint32_t)0x00000002) ++/* Timeout condition */ ++#define USB_OTG_DIEPINT_TOC ((uint32_t)0x00000008) ++/* IN token received when Tx FIFO is empty */ ++#define USB_OTG_DIEPINT_ITTXFE ((uint32_t)0x00000010) ++/* IN endpoint NAK effective */ ++#define USB_OTG_DIEPINT_INEPNE ((uint32_t)0x00000040) ++/* Transmit Fifo empty */ ++#define USB_OTG_DIEPINT_TXFE ((uint32_t)0x00000080) ++/* Transmit Fifo Underrun */ ++#define USB_OTG_DIEPINT_TXFIFOUDRN ((uint32_t)0x00000100) ++/* Buffer not available interrupt */ ++#define USB_OTG_DIEPINT_BNA ((uint32_t)0x00000200) ++/* Packet dropped status */ ++#define USB_OTG_DIEPINT_PKTDRPSTS ((uint32_t)0x00000800) ++/* Babble error interrupt */ ++#define USB_OTG_DIEPINT_BERR ((uint32_t)0x00001000) ++/* NAK interrupt */ ++#define USB_OTG_DIEPINT_NAK ((uint32_t)0x00002000) ++ ++/* USB_OTG_GLPMCFG register */ ++/* BESL value received with last ACKed LPM Token */ ++#define USB_OTG_GLPMCFG_BESL ((uint32_t)0x0000003C) ++ ++/* USB_OTG_GOTGINT register */ ++/* Session end detected */ ++#define USB_OTG_GOTGINT_SEDET ((uint32_t)0x00000004) ++ ++/* USB_OTG_GRXSTSP register */ ++/* IN EP interrupt mask bits */ ++#define USB_OTG_GRXSTSP_EPNUM ((uint32_t)0x0000000F) ++/* OUT EP interrupt mask bits */ ++#define USB_OTG_GRXSTSP_BCNT ((uint32_t)0x00007FF0) ++/* OUT EP interrupt mask bits */ ++#define USB_OTG_GRXSTSP_DPID ((uint32_t)0x00018000) ++/* OUT EP interrupt mask bits */ ++#define USB_OTG_GRXSTSP_PKTSTS ((uint32_t)0x001E0000) ++ ++/* USB_OTG_GUSBCFG register */ ++/* USB turn around time */ ++#define USB_OTG_GUSBCFG_TRDT ((uint32_t)0x00003C00) ++ ++/* USB_OTG_DOEPMSK register */ ++/* Transfer completed interrupt mask */ ++#define USB_OTG_DOEPMSK_XFRCM ((uint32_t)0x00000001) ++/* Endpoint disabled interrupt mask */ ++#define USB_OTG_DOEPMSK_EPDM ((uint32_t)0x00000002) ++/* SETUP phase done mask */ ++#define USB_OTG_DOEPMSK_STUPM ((uint32_t)0x00000008) ++/* OUT token received when endpoint disabled mask */ ++#define USB_OTG_DOEPMSK_OTEPDM ((uint32_t)0x00000010) ++/* Back-to-back SETUP packets received mask */ ++#define USB_OTG_DOEPMSK_B2BSTUP ((uint32_t)0x00000040) ++/* OUT packet error mask */ ++#define USB_OTG_DOEPMSK_OPEM ((uint32_t)0x00000100) ++/* BNA interrupt mask */ ++#define USB_OTG_DOEPMSK_BOIM ((uint32_t)0x00000200) ++ ++/* USB_OTG_DIEPMSK register */ ++/* Transfer completed interrupt mask */ ++#define USB_OTG_DIEPMSK_XFRCM ((uint32_t)0x00000001) ++/* Endpoint disabled interrupt mask */ ++#define USB_OTG_DIEPMSK_EPDM ((uint32_t)0x00000002) ++/* Timeout condition mask(non isochronous endpoints) */ ++#define USB_OTG_DIEPMSK_TOM ((uint32_t)0x00000008) ++/* IN token received when Tx FIFO empty mask */ ++#define USB_OTG_DIEPMSK_ITTXFEMSK ((uint32_t)0x00000010) ++/* IN token received with EP mismatch mask */ ++#define USB_OTG_DIEPMSK_INEPNMM ((uint32_t)0x00000020) ++/* IN endpoint NAK effective mask */ ++#define USB_OTG_DIEPMSK_INEPNEM ((uint32_t)0x00000040) ++/* FIFO under run mask */ ++#define USB_OTG_DIEPMSK_TXFURM ((uint32_t)0x00000100) ++/* BNA interrupt mask */ ++#define USB_OTG_DIEPMSK_BIM ((uint32_t)0x00000200) ++ ++typedef struct { ++ uint32_t dcfg;/* dev Configuration Register */ ++ uint32_t dctl;/* dev Control Register */ ++ uint32_t dsts;/* dev Status Register(RO) */ ++ uint32_t reserved1;/* reserved */ ++ uint32_t diepmsk;/* dev IN Endpoint Mask */ ++ uint32_t doepmsk;/* dev OUT Endpoint Mask */ ++ uint32_t daint;/* dev All Endpoints Itr Reg */ ++ uint32_t daintmsk;/* dev All Endpoints Itr Mask */ ++ uint32_t reserved2;/* reserved */ ++ uint32_t reserved3;/* reserved */ ++ uint32_t dvbusdis;/* dev VBUS discharge Register */ ++ uint32_t dvbuspulse;/* dev VBUS Pulse Register */ ++ uint32_t dthrctl;/* dev threshold */ ++ uint32_t diepempmsk;/* dev empty msk */ ++ uint32_t deachint;/* dedicated EP interrupt */ ++ uint32_t deachmsk;/* dedicated EP msk */ ++ uint32_t reserved4;/* dedicated EP mask */ ++ uint32_t dinep1msk;/* dedicated EP mask */ ++ uint32_t reserved5[15];/* reserved */ ++ uint32_t doutep1msk;/* dedicated EP msk */ ++} usb_dwc2_device_t; ++ ++typedef struct { ++ uint32_t epctl;/* dev IN Endpoint Control Reg */ ++ uint32_t reserved1;/* reserved */ ++ uint32_t epint;/* dev IN Endpoint Itr Reg */ ++ uint32_t reserved2;/* reserved*/ ++ uint32_t eptsiz;/* IN Endpoint Txfer Size */ ++ uint32_t epdma;/* IN Endpoint DMA Address Reg */ ++ uint32_t txfsts;/* IN Endpoint Tx FIFO Status Reg */ ++ uint32_t reserved3;/* reserved */ ++} usb_dwc2_endpoint_t; ++ ++typedef struct { ++ uint32_t gotgctl;/* USB_OTG Control and Status Register */ ++ uint32_t gotgint;/* USB_OTG Interrupt Register */ ++ uint32_t gahbcfg;/* Core AHB Configuration Register */ ++ uint32_t gusbcfg;/* Core USB Configuration Register */ ++ uint32_t grstctl;/* Core Reset Register */ ++ uint32_t gintsts;/* Core Interrupt Register */ ++ uint32_t gintmsk;/* Core Interrupt Mask Register */ ++ uint32_t grxstsr;/* Receive StsQ Read Register */ ++ uint32_t grxstsp;/* Receive StsQ Read & POP Register */ ++ uint32_t grxfsiz;/* Receive FIFO SizeRegister */ ++ uint32_t dieptxfo;/* EP0/Non Periodic Tx FIFO Size Reg */ ++ uint32_t hnptxsts;/* Non Periodic Tx FIFO / Queue Sts reg */ ++ uint32_t reserved1[2];/* reserved */ ++ uint32_t gccfg;/* General Purpose IO Register */ ++ uint32_t cid;/* User ID Register */ ++ uint32_t reserved2[3];/* reserved */ ++ uint32_t ghwcfg3;/* User HW config */ ++ uint32_t reserved3;/* reserved */ ++ uint32_t glpmcfg;/* LPM Register */ ++ uint32_t gpwrdn;/* Power Down Register */ ++ uint32_t gdfifocfg;/* DFIFO Software Config Register */ ++ uint32_t gadpctl;/* ADPTimer, Control and Status Register */ ++ uint32_t reserved4[39];/* reserved */ ++ uint32_t hptxfsiz;/* Host Periodic Tx FIFO Size Reg */ ++ uint32_t dieptxf[0x0F];/* dev Periodic Transmit FIFO */ ++} usb_dwc2_global_t; ++ ++typedef struct { ++ usb_dwc2_global_t *usb_global; ++ usb_dwc2_device_t *usb_device; ++ usb_dwc2_endpoint_t *usb_in_endpoint[USB_MAX_ENDPOINT_NB]; ++ usb_dwc2_endpoint_t *usb_out_endpoint[USB_MAX_ENDPOINT_NB]; ++ uint32_t *usb_fifo[USB_MAX_ENDPOINT_NB]; ++} usb_dwc2_t; ++ ++usb_status_t usb_dwc2_disable_int(void *handle); ++usb_status_t usb_dwc2_ep0_out_start(void *handle); ++usb_status_t usb_dwc2_ep_start_xfer(void *handle, usb_otg_ep_t *ep); ++usb_status_t usb_dwc2_ep0_start_xfer(void *handle, usb_otg_ep_t *ep); ++usb_status_t usb_dwc2_write_packet(void *handle, uint8_t *src, ++ uint8_t ch_ep_num, uint16_t len); ++void *usb_dwc2_read_packet(void *handle, uint8_t *dest, uint16_t len); ++usb_status_t usb_dwc2_ep_set_stall(void *handle, usb_otg_ep_t *ep); ++usb_status_t usb_dwc2_stop_device(void *handle); ++usb_status_t usb_dwc2_set_address(void *handle, uint8_t address); ++usb_status_t usb_dwc2_dev_disconnect(void *handle); ++usb_status_t usb_dwc2_write_empty_tx_fifo(void *handle, uint32_t epnum, ++ uint32_t xfer_len, ++ uint32_t *xfer_count, ++ uint32_t maxpacket, ++ uint8_t **xfer_buff); ++usb_action_t usb_dwc2_it_handler(void *handle, uint32_t *param); ++void usb_dwc2_init_driver(usb_handle_t *usb_core_handle, ++ uint32_t *base_register); ++ ++#endif /* __USB_DWC2_H */ ++ +diff --git a/include/dt-bindings/interrupt-controller/arm-gic.h b/include/dt-bindings/interrupt-controller/arm-gic.h +new file mode 100644 +index 0000000..aa9158c +--- /dev/null ++++ b/include/dt-bindings/interrupt-controller/arm-gic.h +@@ -0,0 +1,21 @@ ++/* SPDX-License-Identifier: GPL-2.0 or BSD-3-Clause */ ++/* ++ * This header provides constants for the ARM GIC. ++ */ ++ ++#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/include/dt-bindings/pinctrl/stm32-pinfunc.h b/include/dt-bindings/pinctrl/stm32-pinfunc.h +index e2f1f1b..7f6e4b9 100644 +--- a/include/dt-bindings/pinctrl/stm32-pinfunc.h ++++ b/include/dt-bindings/pinctrl/stm32-pinfunc.h +@@ -32,4 +32,10 @@ + + #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/include/dt-bindings/power/stm32mp1-power.h b/include/dt-bindings/power/stm32mp1-power.h +new file mode 100644 +index 0000000..bfb7f78 +--- /dev/null ++++ b/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/include/dt-bindings/soc/st,stm32-etzpc.h b/include/dt-bindings/soc/st,stm32-etzpc.h +new file mode 100644 +index 0000000..6678b8e +--- /dev/null ++++ b/include/dt-bindings/soc/st,stm32-etzpc.h +@@ -0,0 +1,107 @@ ++/* ++ * 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_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(id, mode, lock) (((id) << 16) | ((mode) << 8) | (lock)) ++ ++#endif /* _DT_BINDINGS_STM32_ETZPC_H */ ++ +diff --git a/include/lib/aarch32/arch.h b/include/lib/aarch32/arch.h +index 3536d20..aa34b9c 100644 +--- a/include/lib/aarch32/arch.h ++++ b/include/lib/aarch32/arch.h +@@ -61,6 +61,9 @@ + * Generic timer memory mapped registers & offsets + ******************************************************************************/ + #define CNTCR_OFF U(0x000) ++#define CNTSR_OFF U(0x004) ++#define CNTCVL_OFF U(0x008) ++#define CNTCVU_OFF U(0x00C) + #define CNTFID_OFF U(0x020) + + #define CNTCR_EN (U(1) << 0) +@@ -457,6 +460,8 @@ + #define HSTR p15, 4, c1, c1, 3 + #define CNTHCTL p15, 4, c14, c1, 0 + #define CNTKCTL p15, 0, c14, c1, 0 ++#define CNTPTVAL p15, 0, c14, c2, 0 ++#define CNTPCTL p15, 0, c14, c2, 1 + #define VPIDR p15, 4, c0, c0, 0 + #define VMPIDR p15, 4, c0, c0, 5 + #define ISR p15, 0, c12, c1, 0 +@@ -466,6 +471,7 @@ + #define HTCR p15, 4, c2, c0, 2 + #define HMAIR0 p15, 4, c10, c2, 0 + #define ATS1CPR p15, 0, c7, c8, 0 ++#define ATS1CPW p15, 0, c7, c8, 1 + #define ATS1HR p15, 4, c7, c8, 0 + #define DBGOSDLR p14, 0, c1, c3, 4 + +@@ -514,6 +520,12 @@ + #define ICC_ASGI1R_EL1_64 p15, 1, c12 + #define ICC_SGI0R_EL1_64 p15, 2, c12 + ++/* Fault registers. The format is: coproc, opt1, CRn, CRm, opt2 */ ++#define DFSR p15, 0, c5, c0, 0 ++#define IFSR p15, 0, c5, c0, 1 ++#define DFAR p15, 0, c6, c0, 0 ++#define IFAR p15, 0, c6, c0, 2 ++ + /******************************************************************************* + * Definitions of MAIR encodings for device and normal memory + ******************************************************************************/ +@@ -567,6 +579,8 @@ + /* PAR fields */ + #define PAR_F_SHIFT U(0) + #define PAR_F_MASK ULL(0x1) ++#define PAR_NS_SHIFT U(9) ++#define PAR_NS_MASK U(0x1) + #define PAR_ADDR_SHIFT U(12) + #define PAR_ADDR_MASK (BIT_64(40) - ULL(1)) /* 40-bits-wide page address */ + +diff --git a/include/lib/aarch32/arch_helpers.h b/include/lib/aarch32/arch_helpers.h +index 5d9c1c1..e48123c 100644 +--- a/include/lib/aarch32/arch_helpers.h ++++ b/include/lib/aarch32/arch_helpers.h +@@ -261,6 +261,8 @@ DEFINE_COPROCR_RW_FUNCS_64(ttbr1, TTBR1_64) + DEFINE_COPROCR_RW_FUNCS_64(cntvoff, CNTVOFF_64) + DEFINE_COPROCR_RW_FUNCS(csselr, CSSELR) + DEFINE_COPROCR_RW_FUNCS(hstr, HSTR) ++DEFINE_COPROCR_RW_FUNCS(cntptval, CNTPTVAL) ++DEFINE_COPROCR_RW_FUNCS(cntpctl, CNTPCTL) + + DEFINE_COPROCR_RW_FUNCS(icc_sre_el1, ICC_SRE) + DEFINE_COPROCR_RW_FUNCS(icc_sre_el2, ICC_HSRE) +@@ -282,6 +284,7 @@ DEFINE_COPROCR_RW_FUNCS(cnthp_ctl, CNTHP_CTL) + DEFINE_COPROCR_READ_FUNC(pmcr, PMCR) + + DEFINE_COPROCR_RW_FUNCS(ats1cpr, ATS1CPR) ++DEFINE_COPROCR_RW_FUNCS(ats1cpw, ATS1CPW) + DEFINE_COPROCR_RW_FUNCS(ats1hr, ATS1HR) + DEFINE_COPROCR_RW_FUNCS_64(par, PAR_64) + +diff --git a/include/lib/cpus/aarch32/cortex_a9.h b/include/lib/cpus/aarch32/cortex_a9.h +index be85f9b..ea8412f 100644 +--- a/include/lib/cpus/aarch32/cortex_a9.h ++++ b/include/lib/cpus/aarch32/cortex_a9.h +@@ -18,6 +18,11 @@ + #define CORTEX_A9_ACTLR_SMP_BIT (1 << 6) + #define CORTEX_A9_ACTLR_FLZW_BIT (1 << 3) + ++#if defined(ARMV7_CORTEX_A_ACTLR_FLZW_BIT) && \ ++ ARMV7_CORTEX_A_ACTLR_FLZW_BIT != CORTEX_A9_ACTLR_FLZW_BIT ++#error Cortex-A9 ACTLR field FLZW does not match ++#endif ++ + /******************************************************************************* + * CPU Power Control Register + ******************************************************************************/ +diff --git a/include/lib/optee_utils.h b/include/lib/optee_utils.h +index 3d35b19..96c90bd 100644 +--- a/include/lib/optee_utils.h ++++ b/include/lib/optee_utils.h +@@ -8,6 +8,7 @@ + + #include + ++int get_optee_header_ep(entry_point_info_t *header_ep, uintptr_t *pc); + int parse_optee_header(entry_point_info_t *header_ep, + image_info_t *pager_image_info, + image_info_t *paged_image_info); +diff --git a/include/lib/psci/psci.h b/include/lib/psci/psci.h +index b27e481..b7febc3 100644 +--- a/include/lib/psci/psci.h ++++ b/include/lib/psci/psci.h +@@ -302,10 +302,10 @@ typedef struct plat_psci_ops { + void (*pwr_domain_on_finish)(const psci_power_state_t *target_state); + void (*pwr_domain_suspend_finish)( + const psci_power_state_t *target_state); +- void (*pwr_domain_pwr_down_wfi)( +- const psci_power_state_t *target_state) __dead2; +- void (*system_off)(void) __dead2; +- void (*system_reset)(void) __dead2; ++ void __dead2 (*pwr_domain_pwr_down_wfi)( ++ const psci_power_state_t *target_state); ++ void __dead2 (*system_off)(void); ++ void __dead2 (*system_reset)(void); + int (*validate_power_state)(unsigned int power_state, + psci_power_state_t *req_state); + int (*validate_ns_entrypoint)(uintptr_t ns_entrypoint); +diff --git a/include/lib/usb/usb_core.h b/include/lib/usb/usb_core.h +new file mode 100644 +index 0000000..eb0e87a +--- /dev/null ++++ b/include/lib/usb/usb_core.h +@@ -0,0 +1,352 @@ ++/* ++ * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved. ++ * ++ * SPDX-License-Identifier: BSD-3-Clause ++ */ ++ ++#ifndef __USBD_CORE_H ++#define __USBD_CORE_H ++ ++#include ++#include ++ ++#define USBD_MAX_NUM_INTERFACES 1 ++#define USBD_MAX_NUM_CONFIGURATION 1 ++ ++#define USB_LEN_DEV_QUALIFIER_DESC 0x0A ++#define USB_LEN_DEV_DESC 0x12 ++#define USB_LEN_CFG_DESC 0x09 ++#define USB_LEN_IF_DESC 0x09 ++#define USB_LEN_EP_DESC 0x07 ++#define USB_LEN_OTG_DESC 0x03 ++#define USB_LEN_LANGID_STR_DESC 0x04 ++#define USB_LEN_OTHER_SPEED_DESC_SIZ 0x09 ++ ++#define USBD_IDX_LANGID_STR 0x00 ++#define USBD_IDX_MFC_STR 0x01 ++#define USBD_IDX_PRODUCT_STR 0x02 ++#define USBD_IDX_SERIAL_STR 0x03 ++#define USBD_IDX_CONFIG_STR 0x04 ++#define USBD_IDX_INTERFACE_STR 0x05 ++ ++#define USB_REQ_TYPE_STANDARD 0x00 ++#define USB_REQ_TYPE_CLASS 0x20 ++#define USB_REQ_TYPE_VENDOR 0x40 ++#define USB_REQ_TYPE_MASK 0x60 ++ ++#define USB_REQ_RECIPIENT_DEVICE 0x00 ++#define USB_REQ_RECIPIENT_INTERFACE 0x01 ++#define USB_REQ_RECIPIENT_ENDPOINT 0x02 ++#define USB_REQ_RECIPIENT_MASK 0x03 ++ ++#define USB_REQ_GET_STATUS 0x00 ++#define USB_REQ_CLEAR_FEATURE 0x01 ++#define USB_REQ_SET_FEATURE 0x03 ++#define USB_REQ_SET_ADDRESS 0x05 ++#define USB_REQ_GET_DESCRIPTOR 0x06 ++#define USB_REQ_SET_DESCRIPTOR 0x07 ++#define USB_REQ_GET_CONFIGURATION 0x08 ++#define USB_REQ_SET_CONFIGURATION 0x09 ++#define USB_REQ_GET_INTERFACE 0x0A ++#define USB_REQ_SET_INTERFACE 0x0B ++#define USB_REQ_SYNCH_FRAME 0x0C ++ ++#define USB_DESC_TYPE_DEVICE 0x01 ++#define USB_DESC_TYPE_CONFIGURATION 0x02 ++#define USB_DESC_TYPE_STRING 0x03 ++#define USB_DESC_TYPE_INTERFACE 0x04 ++#define USB_DESC_TYPE_ENDPOINT 0x05 ++#define USB_DESC_TYPE_DEVICE_QUALIFIER 0x06 ++#define USB_DESC_TYPE_OTHER_SPEED_CONFIGURATION 0x07 ++#define USB_DESC_TYPE_BOS 0x0F ++ ++#define USB_CONFIG_REMOTE_WAKEUP 2 ++#define USB_CONFIG_SELF_POWERED 1 ++ ++#define USB_FEATURE_EP_HALT 0 ++#define USB_FEATURE_REMOTE_WAKEUP 1 ++#define USB_FEATURE_TEST_MODE 2 ++ ++#define USB_DEVICE_CAPABITY_TYPE 0x10 ++ ++#define USB_HS_MAX_PACKET_SIZE 512 ++#define USB_FS_MAX_PACKET_SIZE 64 ++#define USB_MAX_EP0_SIZE 64 ++ ++/* Device Status */ ++#define USBD_STATE_DEFAULT 1 ++#define USBD_STATE_ADDRESSED 2 ++#define USBD_STATE_CONFIGURED 3 ++#define USBD_STATE_SUSPENDED 4 ++ ++/* EP0 State */ ++#define USBD_EP0_IDLE 0 ++#define USBD_EP0_SETUP 1 ++#define USBD_EP0_DATA_IN 2 ++#define USBD_EP0_DATA_OUT 3 ++#define USBD_EP0_STATUS_IN 4 ++#define USBD_EP0_STATUS_OUT 5 ++#define USBD_EP0_STALL 6 ++ ++#define USBD_EP_TYPE_CTRL 0 ++#define USBD_EP_TYPE_ISOC 1 ++#define USBD_EP_TYPE_BULK 2 ++#define USBD_EP_TYPE_INTR 3 ++ ++#define USB_OTG_SPEED_HIGH 0 ++#define USB_OTG_SPEED_HIGH_IN_FULL 1 ++#define USB_OTG_SPEED_LOW 2 ++#define USB_OTG_SPEED_FULL 3 ++ ++#define USB_OTG_HS_MAX_PACKET_SIZE 512 ++#define USB_OTG_FS_MAX_PACKET_SIZE 64 ++#define USB_OTG_MAX_EP0_SIZE 64 ++ ++#define USB_OTG_OUT_EPNUM_MASK 0x0000FFFF ++#define USB_OTG_OUT_COUNT_MASK 0xFFFF0000 ++ ++#define SWAPBYTE(addr) (((uint16_t)(*((uint8_t *)(addr)))) + \ ++ (((uint16_t)(*(((uint8_t *)(addr)) + 1))) << 8)) ++ ++#define LOBYTE(x) ((uint8_t)((x) & 0x00FF)) ++#define HIBYTE(x) ((uint8_t)(((x) & 0xFF00) >> 8)) ++ ++typedef struct { ++ uint8_t bm_request; ++ uint8_t b_request; ++ uint16_t value; ++ uint16_t index; ++ uint16_t length; ++} usb_setup_req_t; ++ ++struct usb_handle; ++ ++typedef struct { ++ uint8_t (*init)(struct usb_handle *pdev, uint8_t cfgidx); ++ uint8_t (*de_init)(struct usb_handle *pdev, uint8_t cfgidx); ++ /* Control Endpoints*/ ++ uint8_t (*setup)(struct usb_handle *pdev, usb_setup_req_t *req); ++ uint8_t (*ep0_tx_sent)(struct usb_handle *pdev); ++ uint8_t (*ep0_rx_ready)(struct usb_handle *pdev); ++ /* Class Specific Endpoints*/ ++ uint8_t (*data_in)(struct usb_handle *pdev, uint8_t epnum); ++ uint8_t (*data_out)(struct usb_handle *pdev, uint8_t epnum); ++ uint8_t (*sof)(struct usb_handle *pdev); ++ uint8_t (*iso_in_incomplete)(struct usb_handle *pdev, uint8_t epnum); ++ uint8_t (*iso_out_incomplete)(struct usb_handle *pdev, uint8_t epnum); ++ uint32_t reserved; ++} usb_class_t; ++ ++/* Following USB Device status */ ++typedef enum { ++ USBD_OK = 0, ++ USBD_BUSY, ++ USBD_FAIL, ++ USBD_TIMEOUT ++} usb_status_t; ++ ++/* Action to do after IT handling */ ++typedef enum { ++ USB_NOTHING = 0, ++ USB_DATA_OUT, ++ USB_DATA_IN, ++ USB_SETUP, ++ USB_ENUM_DONE, ++ USB_READ_DATA_PACKET, ++ USB_READ_SETUP_PACKET, ++ USB_RESUME, ++ USB_SUSPEND, ++ USB_LPM, ++ USB_SOF, ++ USB_DISCONNECT, ++ USB_WRITE_EMPTY ++} usb_action_t; ++ ++/* USB Device descriptors structure */ ++typedef struct { ++ uint8_t *(*get_device_desc)(uint16_t *length); ++ uint8_t *(*get_lang_id_desc)(uint16_t *length); ++ uint8_t *(*get_manufacturer_desc)(uint16_t *length); ++ uint8_t *(*get_product_desc)(uint16_t *length); ++ uint8_t *(*get_serial_desc)(uint16_t *length); ++ uint8_t *(*get_configuration_desc)(uint16_t *length); ++ uint8_t *(*get_interface_desc)(uint16_t *length); ++ uint8_t *(*get_usr_desc)(uint8_t index, uint16_t *length); ++ uint8_t *(*get_hs_config_desc)(uint16_t *length); ++ uint8_t *(*get_fs_config_desc)(uint16_t *length); ++ uint8_t *(*get_other_speed_config_desc)(uint16_t *length); ++ uint8_t *(*get_device_qualifier_desc)(uint16_t *length); ++ uint8_t *(*get_dfu_desc)(uint16_t *length); ++} usb_desc_t; ++ ++/* USB Device handle structure */ ++typedef struct { ++ uint32_t status; ++ uint32_t total_length; ++ uint32_t rem_length; ++ uint32_t maxpacket; ++} usb_endpoint_t; ++ ++typedef struct { ++ uint32_t dev_endpoints; /* Device Endpoints number. ++ * This parameter depends on the used USB core. ++ * This This parameter must be a number between ++ * This Min_Data = 1 and Max_Data = 15 ++ */ ++ uint32_t host_channels; /* Host Channels number. ++ * This parameter Depends on the used USB core. ++ * This parameter must be a number between ++ * Min_Data = 1 and Max_Data = 15 ++ */ ++ uint32_t speed; /* USB Core speed. */ ++ uint32_t can_be_deleted; /* Enable or disable of the ++ * USB embedded DMA. ++ */ ++ uint32_t ep0_mps; /* Set the Endpoint 0 Max Packet size. */ ++ uint32_t phy_itface; /* Select the used PHY interface. */ ++ uint32_t sof_enable; /* Enable or disable the output of ++ * the SOF signal. ++ */ ++ uint32_t low_power_enable; /* Enable or disable the low power mode. */ ++ uint32_t lpm_enable; /* Enable or disable Link Power Management.*/ ++ uint32_t vbus_sensing_enable; /* Enable or disable the VBUS ++ * Sensing feature. ++ */ ++ uint32_t use_dedicated_ep1; /* Enable or disable the use of the ++ * dedicated EP1 interrupt. ++ */ ++ uint32_t use_external_vbus; /* Enable or disable the use of ++ * the external VBUS. ++ */ ++} usb_otg_cfg_t; ++ ++typedef struct { ++ uint8_t num;/* Endpoint number ++ * This parameter must be a number between Min_Data = 1 ++ * and Max_Data = 15 ++ */ ++ uint8_t is_in; /* Endpoint direction ++ * This parameter must be a number between ++ * Min_Data = 0 and Max_Data = 1 ++ */ ++ uint8_t is_stall; /* Endpoint stall condition ++ * This parameter must be a number between ++ * Min_Data = 0 and Max_Data = 1 ++ */ ++ uint8_t type; /* Endpoint type */ ++ uint8_t data_pid_start; /* Initial data PID ++ * This parameter must be a number between ++ * Min_Data = 0 and Max_Data = 1 ++ */ ++ uint8_t even_odd_frame; /* IFrame parity ++ * This parameter must be a number between ++ * Min_Data = 0 and Max_Data = 1 ++ */ ++ uint16_t tx_fifo_num; /* Transmission FIFO number ++ * This parameter must be a number between ++ * Min_Data = 1 and Max_Data = 15 ++ */ ++ uint32_t maxpacket; /* Endpoint Max packet size ++ * This parameter must be a number between ++ * Min_Data = 0 and Max_Data = 64KB ++ */ ++ uint8_t *xfer_buff; /* Pointer to transfer buffer */ ++ uint32_t dma_addr; /* 32 bits aligned transfer buffer address */ ++ uint32_t xfer_len; /* Current transfer length */ ++ uint32_t xfer_count; /* Partial transfer length in case of multi ++ * packet transfer ++ */ ++} usb_otg_ep_t; ++ ++typedef enum { ++ HAL_PCD_STATE_RESET = 0x00, ++ HAL_PCD_STATE_READY = 0x01, ++ HAL_PCD_STATE_ERROR = 0x02, ++ HAL_PCD_STATE_BUSY = 0x03, ++ HAL_PCD_STATE_TIMEOUT = 0x04 ++} pcd_state_t; ++ ++typedef enum { ++ LPM_L0 = 0x00, /* on */ ++ LPM_L1 = 0x01, /* LPM L1 sleep */ ++ LPM_L2 = 0x02, /* suspend */ ++ LPM_L3 = 0x03, /* off */ ++} pcd_lpm_state_t; ++ ++/* USB Device descriptors structure */ ++typedef struct { ++ usb_status_t (*disable_int)(void *handle); ++ usb_status_t (*ep0_out_start)(void *handle); ++ usb_status_t (*ep_start_xfer)(void *handle, usb_otg_ep_t *ep); ++ usb_status_t (*ep0_start_xfer)(void *handle, usb_otg_ep_t *ep); ++ usb_status_t (*write_packet)(void *handle, uint8_t *src, ++ uint8_t ch_ep_num, uint16_t len); ++ void * (*read_packet)(void *handle, uint8_t *dest, uint16_t len); ++ usb_status_t (*ep_set_stall)(void *handle, usb_otg_ep_t *ep); ++ usb_status_t (*stop_device)(void *handle); ++ usb_status_t (*set_address)(void *handle, uint8_t address); ++ usb_status_t (*dev_disconnect)(void *handle); ++ usb_status_t (*write_empty_tx_fifo)(void *handle, ++ uint32_t epnum, uint32_t xfer_len, ++ uint32_t *xfer_count, ++ uint32_t maxpacket, ++ uint8_t **xfer_buff); ++ usb_action_t (*it_handler)(void *handle, uint32_t *param); ++} usb_driver_t; ++ ++typedef struct { ++ void *instance; /* Register base address */ ++ usb_otg_cfg_t init; /* PCD required parameters */ ++ usb_otg_ep_t in_ep[15]; /* IN endpoint parameters */ ++ usb_otg_ep_t out_ep[15]; /* OUT endpoint parameters */ ++ pcd_state_t state; /* PCD communication state */ ++ uint32_t setup[12]; /* Setup packet buffer */ ++ pcd_lpm_state_t lpm_state; /* LPM State */ ++ uint32_t besl; ++ uint32_t lpm_active; /* Enable or disable the Link Power Management. ++ * This parameter can be set to ENABLE or DISABLE ++ */ ++ void *p_data; /* Pointer to upper stack Handler*/ ++ uint32_t RESERVED[4]; /* For future use */ ++} pcd_handle_t; ++ ++/* USB Device handle structure */ ++typedef struct usb_handle { ++ uint8_t id; ++ uint32_t dev_config; ++ uint32_t dev_default_config; ++ uint32_t dev_config_status; ++ uint32_t dev_speed; ++ usb_endpoint_t ep_in[15]; ++ usb_endpoint_t ep_out[15]; ++ uint32_t ep0_state; ++ uint32_t ep0_data_len; ++ uint8_t dev_state; ++ uint8_t dev_old_state; ++ uint8_t dev_address; ++ uint8_t dev_connection_status; ++ uint8_t dev_test_mode; ++ uint32_t dev_remote_wakeup; ++ usb_setup_req_t request; ++ const usb_desc_t *desc; ++ usb_class_t *class; ++ void *class_data; ++ void *user_data; ++ pcd_handle_t *data; ++ const usb_driver_t *driver; ++ uint32_t RESERVED[3]; ++} usb_handle_t; ++ ++usb_status_t usb_core_handle_it(usb_handle_t *pdev); ++usb_status_t usb_core_receive(usb_handle_t *pdev, uint8_t ep_addr, ++ uint8_t *p_buf, uint32_t len); ++usb_status_t usb_core_transmit(usb_handle_t *pdev, uint8_t ep_addr, ++ uint8_t *p_buf, uint32_t len); ++void usb_core_ctl_error(usb_handle_t *pdev); ++usb_status_t usb_core_stop(usb_handle_t *pdev); ++usb_status_t register_usb_driver(usb_handle_t *pdev, const usb_driver_t *driver, ++ void *driver_handle); ++usb_status_t register_platform(usb_handle_t *pdev, ++ const usb_desc_t *plat_call_back); ++ ++#endif /* __USBD_CORE_H */ +diff --git a/include/lib/usb/usb_st_dfu.h b/include/lib/usb/usb_st_dfu.h +new file mode 100644 +index 0000000..3709683 +--- /dev/null ++++ b/include/lib/usb/usb_st_dfu.h +@@ -0,0 +1,115 @@ ++/* ++ * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved. ++ * ++ * SPDX-License-Identifier: BSD-3-Clause ++ */ ++ ++#ifndef __USB_DFU_H ++#define __USB_DFU_H ++ ++#include ++#include ++ ++#define DFU_DESCRIPTOR_TYPE 0x21 ++ ++/* bmAttribute : ++ * bitCanDnload = 1(bit 0) ++ * bitCanUpload = 1(bit 1) ++ * bitManifestationTolerant = 1 (bit 2) ++ * bitWillDetach = 1(bit 3) ++ * Reserved (bit4-6) ++ * bitAcceleratedST = 0(bit 7) ++ */ ++#define DFU_BM_ATTRIBUTE 0x0F ++ ++#define DFU_GET_PHASE 0x5 ++ ++/* DFU Requests DFU states */ ++#define APP_STATE_IDLE 0 ++#define APP_STATE_DETACH 1 ++#define DFU_STATE_IDLE 2 ++#define DFU_STATE_DNLOAD_SYNC 3 ++#define DFU_STATE_DNLOAD_BUSY 4 ++#define DFU_STATE_DNLOAD_IDLE 5 ++#define DFU_STATE_MANIFEST_SYNC 6 ++#define DFU_STATE_MANIFEST 7 ++#define DFU_STATE_MANIFEST_WAIT_RESET 8 ++#define DFU_STATE_UPLOAD_IDLE 9 ++#define DFU_STATE_ERROR 10 ++ ++/* DFU errors */ ++#define DFU_ERROR_NONE 0x00 ++#define DFU_ERROR_TARGET 0x01 ++#define DFU_ERROR_FILE 0x02 ++#define DFU_ERROR_WRITE 0x03 ++#define DFU_ERROR_ERASE 0x04 ++#define DFU_ERROR_CHECK_ERASED 0x05 ++#define DFU_ERROR_PROG 0x06 ++#define DFU_ERROR_VERIFY 0x07 ++#define DFU_ERROR_ADDRESS 0x08 ++#define DFU_ERROR_NOTDONE 0x09 ++#define DFU_ERROR_FIRMWARE 0x0A ++#define DFU_ERROR_VENDOR 0x0B ++#define DFU_ERROR_USB 0x0C ++#define DFU_ERROR_POR 0x0D ++#define DFU_ERROR_UNKNOWN 0x0E ++#define DFU_ERROR_STALLEDPKT 0x0F ++ ++/* DFU Manifestation State */ ++#define DFU_MANIFEST_COMPLETE 0x00 ++#define DFU_MANIFEST_IN_PROGRESS 0x01 ++ ++/* Special Commands with Download Request */ ++#define DFU_CMD_GETCOMMANDS 0x00 ++#define DFU_CMD_SETADDRESSPOINTER 0x21 ++#define DFU_CMD_ERASE 0x41 ++ ++#define DFU_MEDIA_STATE_READY 0x00 ++#define DFU_MEDIA_STATE_WRITTEN 0x01 ++#define DFU_MEDIA_STATE_ERROR 0x02 ++ ++/* Bit Detach capable = bit 3 in bmAttributes field */ ++#define DFU_DETACH_MASK (uint8_t)(1 << 4) ++#define DFU_STATUS_DEPTH (6) ++ ++/* Undefined download address */ ++#define UNDEFINE_DOWN_ADDR 0xFFFFFFFF ++ ++typedef enum { ++ DFU_DETACH = 0, ++ DFU_DNLOAD, ++ DFU_UPLOAD, ++ DFU_GETSTATUS, ++ DFU_CLRSTATUS, ++ DFU_GETSTATE, ++ DFU_ABORT ++} dfu_request_t; ++ ++typedef void (*p_function)(void); ++ ++typedef struct { ++ uint8_t buffer[10]; ++ uint8_t dev_state; ++ uint8_t dev_status[DFU_STATUS_DEPTH]; ++ uint8_t manif_state; ++ uint32_t wblock_num; ++ uint32_t wlength; ++ uintptr_t data_ptr; ++ uint32_t alt_setting; ++} usb_dfu_handle_t; ++ ++typedef struct { ++ uint16_t (*write_done)(uint32_t *written_in, uint32_t len); ++ uint8_t* (*read)(uint8_t *src, uint8_t *dest, uint32_t len); ++ uint16_t (*get_status)(void); ++} usb_dfu_media_t; ++ ++void usb_dfu_register_callback(usb_handle_t *pdev); ++void usb_dfu_set_phase_id(uint32_t phase_id); ++void usb_dfu_set_download_addr(uintptr_t addr); ++uint32_t usb_dfu_download_is_completed(void); ++uint32_t usb_dfu_get_current_req(void); ++uint32_t usb_dfu_detach_req(void); ++void usb_dfu_request_detach(void); ++ ++#endif /* __USB_DFU_H */ +diff --git a/include/lib/utils.h b/include/lib/utils.h +index d46d846..b6ab26e 100644 +--- a/include/lib/utils.h ++++ b/include/lib/utils.h +@@ -4,8 +4,8 @@ + * SPDX-License-Identifier: BSD-3-Clause + */ + +-#ifndef __UTILS_H__ +-#define __UTILS_H__ ++#ifndef UTILS_H ++#define UTILS_H + + /* + * C code should be put in this part of the header to avoid breaking ASM files +@@ -67,6 +67,29 @@ void zero_normalmem(void *mem, u_register_t length); + * zeroing. + */ + void zeromem(void *mem, u_register_t length); ++ ++/* ++ * Utility function to return the address of a symbol. By default, the ++ * compiler generates adr/adrp instruction pair to return the reference ++ * to the symbol and this utility is used to override this compiler ++ * generated to code to use `ldr` instruction. ++ * ++ * This helps when Position Independent Executable needs to reference a symbol ++ * which is constant and does not depend on the execute address of the binary. ++ */ ++#define DEFINE_LOAD_SYM_ADDR(_name) \ ++static inline u_register_t load_addr_## _name(void) \ ++{ \ ++ u_register_t v; \ ++ /* Create a void reference to silence compiler */ \ ++ (void) _name; \ ++ __asm__ volatile ("ldr %0, =" #_name : "=r" (v)); \ ++ return v; \ ++} ++ ++/* Helper to invoke the function defined by DEFINE_LOAD_SYM_ADDR() */ ++#define LOAD_ADDR_OF(_name) (typeof(_name) *) load_addr_## _name() ++ + #endif /* !(defined(__LINKER__) || defined(__ASSEMBLY__)) */ + +-#endif /* __UTILS_H__ */ ++#endif /* UTILS_H */ +diff --git a/include/lib/utils_def.h b/include/lib/utils_def.h +index 5b4fd78..51863d8 100644 +--- a/include/lib/utils_def.h ++++ b/include/lib/utils_def.h +@@ -30,11 +30,19 @@ + * position @h. For example + * GENMASK_64(39, 21) gives us the 64bit vector 0x000000ffffe00000. + */ ++#if defined(__LINKER__) || defined(__ASSEMBLY__) ++#define GENMASK_32(h, l) \ ++ (((0xFFFFFFFF) << (l)) & (0xFFFFFFFF >> (32 - 1 - (h)))) ++ ++#define GENMASK_64(h, l) \ ++ ((~0 << (l)) & (~0 >> (64 - 1 - (h)))) ++#else + #define GENMASK_32(h, l) \ + (((~UINT32_C(0)) << (l)) & (~UINT32_C(0) >> (32 - 1 - (h)))) + + #define GENMASK_64(h, l) \ + (((~UINT64_C(0)) << (l)) & (~UINT64_C(0) >> (64 - 1 - (h)))) ++#endif + + #ifdef AARCH32 + #define GENMASK GENMASK_32 +@@ -50,7 +58,17 @@ + + #define div_round_up(val, div) __extension__ ({ \ + __typeof__(div) _div = (div); \ +- ((val) + _div - 1) / _div; \ ++ ((val) + _div - (__typeof__(div)) 1) / _div; \ ++}) ++ ++/* ++ * Macro for unsigned integer division with nearest rounding variant. ++ * Default integer division rounds down. ++ */ ++#define udiv_round_nearest(x, y) __extension__ ({ \ ++ __typeof__(x) _x = (x); \ ++ __typeof__(y) _y = (y); \ ++ (_x + (_y / 2)) / _y; \ + }) + + #define MIN(x, y) __extension__ ({ \ +diff --git a/include/lib/xlat_tables/xlat_tables_v2_helpers.h b/include/lib/xlat_tables/xlat_tables_v2_helpers.h +index fa89958..c9504b3 100644 +--- a/include/lib/xlat_tables/xlat_tables_v2_helpers.h ++++ b/include/lib/xlat_tables/xlat_tables_v2_helpers.h +@@ -120,6 +120,37 @@ struct xlat_ctx { + /* do nothing */ + #endif /* PLAT_XLAT_TABLES_DYNAMIC */ + ++#ifdef PLAT_XLAT_BASE ++#define tf_xlat_tables (void *)PLAT_XLAT_BASE ++ ++#define XLAT_TABLES(_ctx_name, _xlat_tables_count, _section_name) \ ++ CASSERT(!(PLAT_XLAT_BASE & (XLAT_TABLE_SIZE - 1)), \ ++ invalid_plat_xlat_base); \ ++ CASSERT(PLAT_XLAT_SIZE >= (sizeof(uint64_t) * \ ++ XLAT_TABLE_ENTRIES * _xlat_tables_count), \ ++ invalid_plat_xlat_size); ++ ++#else ++#define XLAT_TABLES(_ctx_name, _xlat_tables_count, _section_name) \ ++ static uint64_t _ctx_name##_xlat_tables[_xlat_tables_count][XLAT_TABLE_ENTRIES] \ ++ __aligned(XLAT_TABLE_SIZE) __section(_section_name); ++#endif ++ ++#ifdef PLAT_BASE_XLAT_BASE ++#define tf_base_xlat_table (void *)PLAT_BASE_XLAT_BASE ++ ++#define BASE_XLAT_TABLE(_ctx_name, _virt_addr_space_size) \ ++ CASSERT(!(PLAT_BASE_XLAT_BASE & \ ++ ((GET_NUM_BASE_LEVEL_ENTRIES(_virt_addr_space_size) * \ ++ sizeof(uint64_t)) - 1)), invalid_plat_base_xlat_cfg); ++#else ++#define BASE_XLAT_TABLE(_ctx_name, _virt_addr_space_size) \ ++ static uint64_t _ctx_name##_base_xlat_table \ ++ [GET_NUM_BASE_LEVEL_ENTRIES(_virt_addr_space_size)] \ ++ __aligned(GET_NUM_BASE_LEVEL_ENTRIES(_virt_addr_space_size) * \ ++ sizeof(uint64_t)); ++#endif ++ + #define REGISTER_XLAT_CONTEXT_FULL_SPEC(_ctx_name, _mmap_count, \ + _xlat_tables_count, _virt_addr_space_size, \ + _phy_addr_space_size, _xlat_regime, _section_name)\ +@@ -131,14 +162,8 @@ struct xlat_ctx { + \ + static mmap_region_t _ctx_name##_mmap[_mmap_count + 1]; \ + \ +- static uint64_t _ctx_name##_xlat_tables[_xlat_tables_count] \ +- [XLAT_TABLE_ENTRIES] \ +- __aligned(XLAT_TABLE_SIZE) __section(_section_name); \ +- \ +- static uint64_t _ctx_name##_base_xlat_table \ +- [GET_NUM_BASE_LEVEL_ENTRIES(_virt_addr_space_size)] \ +- __aligned(GET_NUM_BASE_LEVEL_ENTRIES(_virt_addr_space_size)\ +- * sizeof(uint64_t)); \ ++ XLAT_TABLES(_ctx_name, _xlat_tables_count, _section_name) \ ++ BASE_XLAT_TABLE(_ctx_name, _virt_addr_space_size) \ + \ + XLAT_ALLOC_DYNMAP_STRUCT(_ctx_name, _xlat_tables_count) \ + \ +diff --git a/include/plat/common/platform.h b/include/plat/common/platform.h +index a30b579..1a6161e 100644 +--- a/include/plat/common/platform.h ++++ b/include/plat/common/platform.h +@@ -93,6 +93,11 @@ unsigned int plat_ic_get_interrupt_id(unsigned int raw); + ******************************************************************************/ + uintptr_t plat_get_my_stack(void); + void plat_report_exception(unsigned int exception_type); ++#if AARCH32_EXCEPTION_DEBUG ++void plat_report_undef_inst(unsigned int fault_address); ++void plat_report_prefetch_abort(unsigned int fault_address); ++void plat_report_data_abort(unsigned int fault_address); ++#endif + int plat_crash_console_init(void); + int plat_crash_console_putc(int c); + int plat_crash_console_flush(void); +diff --git a/lib/compiler-rt/builtins/int_lib.h b/lib/compiler-rt/builtins/int_lib.h +index 787777a..80a7c41 100644 +--- a/lib/compiler-rt/builtins/int_lib.h ++++ b/lib/compiler-rt/builtins/int_lib.h +@@ -27,27 +27,28 @@ + + #if defined(__ELF__) + #define FNALIAS(alias_name, original_name) \ +- void alias_name() __attribute__((alias(#original_name))) ++ void alias_name() __attribute__((__alias__(#original_name))) ++#define COMPILER_RT_ALIAS(aliasee) __attribute__((__alias__(#aliasee))) + #else + #define FNALIAS(alias, name) _Pragma("GCC error(\"alias unsupported on this file format\")") ++#define COMPILER_RT_ALIAS(aliasee) _Pragma("GCC error(\"alias unsupported on this file format\")") + #endif + + /* ABI macro definitions */ + + #if __ARM_EABI__ +-# define ARM_EABI_FNALIAS(aeabi_name, name) \ +- void __aeabi_##aeabi_name() __attribute__((alias("__" #name))); + # ifdef COMPILER_RT_ARMHF_TARGET + # define COMPILER_RT_ABI + # else +-# define COMPILER_RT_ABI __attribute__((pcs("aapcs"))) ++# define COMPILER_RT_ABI __attribute__((__pcs__("aapcs"))) + # endif + #else +-# define ARM_EABI_FNALIAS(aeabi_name, name) + # define COMPILER_RT_ABI + #endif + +-#ifdef _MSC_VER ++#define AEABI_RTABI __attribute__((__pcs__("aapcs"))) ++ ++#if defined(_MSC_VER) && !defined(__clang__) + #define ALWAYS_INLINE __forceinline + #define NOINLINE __declspec(noinline) + #define NORETURN __declspec(noreturn) +diff --git a/lib/compiler-rt/builtins/lshrdi3.c b/lib/compiler-rt/builtins/lshrdi3.c +new file mode 100644 +index 0000000..67b2a76 +--- /dev/null ++++ b/lib/compiler-rt/builtins/lshrdi3.c +@@ -0,0 +1,45 @@ ++/* ===-- lshrdi3.c - Implement __lshrdi3 -----------------------------------=== ++ * ++ * The LLVM Compiler Infrastructure ++ * ++ * This file is dual licensed under the MIT and the University of Illinois Open ++ * Source Licenses. See LICENSE.TXT for details. ++ * ++ * ===----------------------------------------------------------------------=== ++ * ++ * This file implements __lshrdi3 for the compiler_rt library. ++ * ++ * ===----------------------------------------------------------------------=== ++ */ ++ ++#include "int_lib.h" ++ ++/* Returns: logical a >> b */ ++ ++/* Precondition: 0 <= b < bits_in_dword */ ++ ++COMPILER_RT_ABI di_int ++__lshrdi3(di_int a, si_int b) ++{ ++ const int bits_in_word = (int)(sizeof(si_int) * CHAR_BIT); ++ udwords input; ++ udwords result; ++ input.all = a; ++ if (b & bits_in_word) /* bits_in_word <= b < bits_in_dword */ ++ { ++ result.s.high = 0; ++ result.s.low = input.s.high >> (b - bits_in_word); ++ } ++ else /* 0 <= b < bits_in_word */ ++ { ++ if (b == 0) ++ return a; ++ result.s.high = input.s.high >> b; ++ result.s.low = (input.s.high << (bits_in_word - b)) | (input.s.low >> b); ++ } ++ return result.all; ++} ++ ++#if defined(__ARM_EABI__) ++AEABI_RTABI di_int __aeabi_llsr(di_int a, si_int b) COMPILER_RT_ALIAS(__lshrdi3); ++#endif +diff --git a/lib/compiler-rt/compiler-rt.mk b/lib/compiler-rt/compiler-rt.mk +index cb5ab31..49e497e 100644 +--- a/lib/compiler-rt/compiler-rt.mk ++++ b/lib/compiler-rt/compiler-rt.mk +@@ -31,5 +31,6 @@ + ifeq (${ARCH},aarch32) + COMPILER_RT_SRCS := lib/compiler-rt/builtins/arm/aeabi_uldivmod.S \ + lib/compiler-rt/builtins/udivmoddi4.c \ +- lib/compiler-rt/builtins/ctzdi2.c ++ lib/compiler-rt/builtins/ctzdi2.c \ ++ lib/compiler-rt/builtins/lshrdi3.c + endif +diff --git a/lib/libfdt/fdt_ro.c b/lib/libfdt/fdt_ro.c +index 0459098..88aeb59 100644 +--- a/lib/libfdt/fdt_ro.c ++++ b/lib/libfdt/fdt_ro.c +@@ -597,7 +597,7 @@ int fdt_stringlist_search(const void *fdt, int nodeoffset, const char *property, + + list = fdt_getprop(fdt, nodeoffset, property, &length); + if (!list) +- return -length; ++ return length; + + len = strlen(string) + 1; + end = list + length; +diff --git a/lib/optee/optee_utils.c b/lib/optee/optee_utils.c +index 34d095b..0f1e560 100644 +--- a/lib/optee/optee_utils.c ++++ b/lib/optee/optee_utils.c +@@ -132,6 +132,36 @@ static int parse_optee_image(image_info_t *image_info, + } + + /******************************************************************************* ++ * Parse the OPTEE header for an executable entry point address. ++ * Return 1 on success, 0 on failure. ++ ******************************************************************************/ ++int get_optee_header_ep(entry_point_info_t *header_ep, uintptr_t *pc) ++{ ++ optee_header_t *optee_header; ++ int num; ++ ++ assert(pc && header_ep && header_ep->pc); ++ optee_header = (optee_header_t *)header_ep->pc; ++ ++ if (!tee_validate_header(optee_header)) ++ return 0; ++ ++ for (num = 0; num < optee_header->nb_images; num++) { ++ optee_image_t *optee_image = ++ &optee_header->optee_image_list[num]; ++ ++ if (optee_image->image_id != OPTEE_PAGER_IMAGE_ID) ++ continue; ++ ++ *pc = ((uint64_t)optee_image->load_addr_hi << 32) | ++ optee_image->load_addr_lo; ++ return 1; ++ } ++ ++ return 0; ++} ++ ++/******************************************************************************* + * Parse the OPTEE header + * Return 0 on success or a negative error code otherwise. + ******************************************************************************/ +diff --git a/lib/usb/usb_core.c b/lib/usb/usb_core.c +new file mode 100644 +index 0000000..240c1c1 +--- /dev/null ++++ b/lib/usb/usb_core.c +@@ -0,0 +1,732 @@ ++/* ++ * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved. ++ * ++ * SPDX-License-Identifier: BSD-3-Clause ++ */ ++ ++#include ++#include ++#include "usb_core.h" ++ ++/* ++ * @brief Set a STALL condition over an endpoint ++ * @param hpcd: PCD handle ++ * @param ep_addr: endpoint address ++ * @retval HAL status ++ */ ++static usb_status_t usb_core_set_stall(usb_handle_t *pdev, uint8_t ep_addr) ++{ ++ usb_otg_ep_t *ep; ++ pcd_handle_t *hpcd = (pcd_handle_t *)pdev->data; ++ ++ if ((0x80 & ep_addr) == 0x80) ++ ep = &hpcd->in_ep[ep_addr & 0x7F]; ++ else ++ ep = &hpcd->out_ep[ep_addr]; ++ ++ ep->is_stall = 1; ++ ep->num = ep_addr & 0x7F; ++ ep->is_in = ((ep_addr & 0x80) == 0x80); ++ ++ pdev->driver->ep_set_stall(hpcd->instance, ep); ++ if ((ep_addr & 0x7F) == 0) ++ pdev->driver->ep0_out_start(hpcd->instance); ++ ++ return USBD_OK; ++} ++ ++/* ++ * usb_core_get_desc ++ * Handle Get Descriptor requests ++ * pdev : device instance ++ * req : usb request ++ * return : status ++ */ ++static void usb_core_get_desc(usb_handle_t *pdev, ++ usb_setup_req_t *req) ++{ ++ uint16_t len; ++ uint8_t *pbuf; ++ ++ switch (req->value >> 8) { ++ case USB_DESC_TYPE_DEVICE: ++ pbuf = pdev->desc->get_device_desc(&len); ++ break; ++ ++ case USB_DESC_TYPE_CONFIGURATION: ++ pbuf = (uint8_t *)pdev->desc->get_hs_config_desc(&len); ++ pbuf[1] = USB_DESC_TYPE_CONFIGURATION; ++ break; ++ ++ case USB_DESC_TYPE_STRING: ++ switch ((uint8_t)(req->value)) { ++ case USBD_IDX_LANGID_STR: ++ pbuf = pdev->desc->get_lang_id_desc(&len); ++ break; ++ ++ case USBD_IDX_MFC_STR: ++ pbuf = pdev->desc->get_manufacturer_desc(&len); ++ break; ++ ++ case USBD_IDX_PRODUCT_STR: ++ pbuf = pdev->desc->get_product_desc(&len); ++ break; ++ ++ case USBD_IDX_SERIAL_STR: ++ pbuf = pdev->desc->get_serial_desc(&len); ++ break; ++ ++ case USBD_IDX_CONFIG_STR: ++ pbuf = pdev->desc->get_configuration_desc(&len); ++ break; ++ ++ case USBD_IDX_INTERFACE_STR: ++ pbuf = pdev->desc->get_interface_desc(&len); ++ break; ++ ++ default: ++ pbuf = pdev->desc->get_usr_desc(req->value, &len); ++ break; ++ } ++ break; ++ ++ case USB_DESC_TYPE_DEVICE_QUALIFIER: ++ pbuf = (uint8_t *)pdev->desc->get_device_qualifier_desc(&len); ++ break; ++ ++ case USB_DESC_TYPE_OTHER_SPEED_CONFIGURATION: ++ pbuf = (uint8_t *)pdev->desc->get_other_speed_config_desc(&len); ++ pbuf[1] = USB_DESC_TYPE_OTHER_SPEED_CONFIGURATION; ++ break; ++ ++ default: ++ ERROR("Unknown request %i\n", req->value >> 8); ++ usb_core_ctl_error(pdev); ++ return; ++ } ++ ++ if ((len != 0) && (req->length != 0)) { ++ len = MIN(len, req->length); ++ ++ /* Set EP0 State */ ++ pdev->ep0_state = USBD_EP0_DATA_IN; ++ pdev->ep_in[0].total_length = len; ++ pdev->ep_in[0].rem_length = len; ++ /* Start the transfer */ ++ usb_core_transmit(pdev, 0x00, pbuf, len); ++ } ++} ++ ++/* ++ * usb_core_set_config ++ * Handle Set device configuration request ++ * pdev : device instance ++ * req : usb request ++ * return : status ++ */ ++static void usb_core_set_config(usb_handle_t *pdev, usb_setup_req_t *req) ++{ ++ static uint8_t cfgidx; ++ ++ cfgidx = (uint8_t)(req->value); ++ ++ if (cfgidx > USBD_MAX_NUM_CONFIGURATION) { ++ usb_core_ctl_error(pdev); ++ } else { ++ switch (pdev->dev_state) { ++ case USBD_STATE_ADDRESSED: ++ if (cfgidx) { ++ pdev->dev_config = cfgidx; ++ pdev->dev_state = USBD_STATE_CONFIGURED; ++ if (!pdev->class) { ++ usb_core_ctl_error(pdev); ++ return; ++ } ++ /* Set configuration and Start the Class*/ ++ if (pdev->class->init(pdev, cfgidx) != 0) { ++ usb_core_ctl_error(pdev); ++ return; ++ } ++ } ++ break; ++ ++ case USBD_STATE_CONFIGURED: ++ if (cfgidx == 0) { ++ pdev->dev_state = USBD_STATE_ADDRESSED; ++ pdev->dev_config = cfgidx; ++ pdev->class->de_init(pdev, cfgidx); ++ } else if (cfgidx != pdev->dev_config) { ++ if (!pdev->class) { ++ usb_core_ctl_error(pdev); ++ return; ++ } ++ /* Clear old configuration */ ++ pdev->class->de_init(pdev, pdev->dev_config); ++ ++ /* set new configuration */ ++ pdev->dev_config = cfgidx; ++ /* Set configuration and Start the Class*/ ++ if (pdev->class->init(pdev, cfgidx) != 0) { ++ usb_core_ctl_error(pdev); ++ return; ++ } ++ } ++ break; ++ ++ default: ++ usb_core_ctl_error(pdev); ++ return; ++ } ++ /* Set EP0 State */ ++ pdev->ep0_state = USBD_EP0_STATUS_IN; ++ ++ /* Send status */ ++ usb_core_transmit(pdev, 0, NULL, 0); ++ } ++} ++ ++/* ++ * usb_core_get_status ++ * Handle Get Status request ++ * pdev : device instance ++ * req : usb request ++ * return : status ++ */ ++static void usb_core_get_status(usb_handle_t *pdev, usb_setup_req_t *req) ++{ ++ if ((pdev->dev_state == USBD_STATE_ADDRESSED) || ++ (pdev->dev_state == USBD_STATE_CONFIGURED)) { ++ pdev->dev_config_status = USB_CONFIG_SELF_POWERED; ++ ++ if (pdev->dev_remote_wakeup) ++ pdev->dev_config_status |= USB_CONFIG_REMOTE_WAKEUP; ++ ++ /* Set EP0 State */ ++ pdev->ep0_state = USBD_EP0_DATA_IN; ++ pdev->ep_in[0].total_length = 2; ++ pdev->ep_in[0].rem_length = 2; ++ /* Start the transfer */ ++ usb_core_transmit(pdev, 0x00, ++ (uint8_t *)&pdev->dev_config_status, 2); ++ return; ++ } ++ ++ usb_core_ctl_error(pdev); ++} ++ ++/* ++ * usb_core_set_address ++ * Set device address ++ * pdev : device instance ++ * req : usb request ++ * return : status ++ */ ++static void usb_core_set_address(usb_handle_t *pdev, usb_setup_req_t *req) ++{ ++ if ((req->index == 0) && (req->length == 0)) { ++ uint8_t dev_addr = (uint8_t)(req->value) & 0x7F; ++ ++ if (pdev->dev_state == USBD_STATE_CONFIGURED) { ++ usb_core_ctl_error(pdev); ++ } else { ++ pdev->dev_address = dev_addr; ++ pdev->driver->set_address(((pcd_handle_t *) ++ (pdev->data))->instance, ++ dev_addr); ++ /* Set EP0 State */ ++ pdev->ep0_state = USBD_EP0_STATUS_IN; ++ ++ /* Send status */ ++ usb_core_transmit(pdev, 0, NULL, 0); ++ ++ if (dev_addr != 0) ++ pdev->dev_state = USBD_STATE_ADDRESSED; ++ else ++ pdev->dev_state = USBD_STATE_DEFAULT; ++ } ++ } else { ++ usb_core_ctl_error(pdev); ++ } ++} ++ ++/* ++ * usb_core_dev_req ++ * Handle standard usb device requests ++ * pdev : device instance ++ * req : usb request ++ * return : status ++ */ ++static usb_status_t usb_core_dev_req(usb_handle_t *pdev, usb_setup_req_t *req) ++{ ++ INFO("receive request %i\n", req->b_request); ++ switch (req->b_request) { ++ case USB_REQ_GET_DESCRIPTOR: ++ usb_core_get_desc(pdev, req); ++ break; ++ ++ case USB_REQ_SET_CONFIGURATION: ++ usb_core_set_config(pdev, req); ++ break; ++ ++ case USB_REQ_GET_STATUS: ++ usb_core_get_status(pdev, req); ++ break; ++ case USB_REQ_SET_ADDRESS: ++ usb_core_set_address(pdev, req); ++ break; ++ case USB_REQ_GET_CONFIGURATION: ++ case USB_REQ_SET_FEATURE: ++ case USB_REQ_CLEAR_FEATURE: ++ default: ++ ERROR("NOT SUPPORTED %i\n", req->b_request); ++ usb_core_ctl_error(pdev); ++ break; ++ } ++ ++ return USBD_OK; ++} ++ ++/* ++ * usb_core_itf_req ++ * Handle standard usb interface requests ++ * pdev : device instance ++ * req : usb request ++ * return : status ++ */ ++static usb_status_t usb_core_itf_req(usb_handle_t *pdev, usb_setup_req_t *req) ++{ ++ switch (pdev->dev_state) { ++ case USBD_STATE_CONFIGURED: ++ if (LOBYTE(req->index) <= USBD_MAX_NUM_INTERFACES) { ++ pdev->class->setup(pdev, req); ++ ++ if (req->length == 0) { ++ /* Set EP0 State */ ++ pdev->ep0_state = USBD_EP0_STATUS_IN; ++ ++ usb_core_transmit(pdev, 0, NULL, 0); ++ } ++ } else { ++ usb_core_ctl_error(pdev); ++ } ++ break; ++ ++ default: ++ usb_core_ctl_error(pdev); ++ break; ++ } ++ return USBD_OK; ++} ++ ++/* ++ * @brief USBD_ParseSetupRequest ++ * Copy buffer into setup structure ++ * @param pdev: device instance ++ * @param req: usb request ++ * @retval None ++ */ ++static void usb_core_parse_req(usb_setup_req_t *req, uint8_t *pdata) ++{ ++ req->bm_request = *(uint8_t *)(pdata); ++ req->b_request = *(uint8_t *)(pdata + 1); ++ req->value = SWAPBYTE(pdata + 2); ++ req->index = SWAPBYTE(pdata + 4); ++ req->length = SWAPBYTE(pdata + 6); ++} ++ ++/* ++ * usb_core_setup_stage ++ * Handle the setup stage ++ * pdev: device instance ++ * return : status ++ */ ++static usb_status_t usb_core_setup_stage(usb_handle_t *pdev, uint8_t *psetup) ++{ ++ usb_core_parse_req(&pdev->request, psetup); ++ ++ pdev->ep0_state = USBD_EP0_SETUP; ++ pdev->ep0_data_len = pdev->request.length; ++ ++ switch (pdev->request.bm_request & 0x1F) { ++ case USB_REQ_RECIPIENT_DEVICE: ++ usb_core_dev_req(pdev, &pdev->request); ++ break; ++ ++ case USB_REQ_RECIPIENT_INTERFACE: ++ usb_core_itf_req(pdev, &pdev->request); ++ break; ++ ++ case USB_REQ_RECIPIENT_ENDPOINT: ++ default: ++ ERROR("receive unsupported request %i", ++ pdev->request.bm_request & 0x1F); ++ usb_core_set_stall(pdev, pdev->request.bm_request & 0x80); ++ return USBD_FAIL; ++ } ++ return USBD_OK; ++} ++ ++/* ++ * usb_core_data_out ++ * Handle data OUT stage ++ * pdev: device instance ++ * epnum: endpoint index ++ * return : status ++ */ ++static usb_status_t usb_core_data_out(usb_handle_t *pdev, uint8_t epnum, ++ uint8_t *pdata) ++{ ++ usb_endpoint_t *pep; ++ ++ if (epnum == 0) { ++ pep = &pdev->ep_out[0]; ++ if (pdev->ep0_state == USBD_EP0_DATA_OUT) { ++ if (pep->rem_length > pep->maxpacket) { ++ pep->rem_length -= pep->maxpacket; ++ ++ usb_core_receive(pdev, 0, pdata, ++ MIN(pep->rem_length, ++ pep->maxpacket)); ++ } else { ++ if (pdev->class->ep0_rx_ready && ++ (pdev->dev_state == USBD_STATE_CONFIGURED)) ++ pdev->class->ep0_rx_ready(pdev); ++ ++ pdev->ep0_state = USBD_EP0_STATUS_IN; ++ usb_core_transmit(pdev, 0x00, NULL, 0); ++ } ++ } ++ } else if (pdev->class->data_out && ++ (pdev->dev_state == USBD_STATE_CONFIGURED)) ++ pdev->class->data_out(pdev, epnum); ++ ++ return USBD_OK; ++} ++ ++/* ++ * usb_core_data_in ++ * Handle data in stage ++ * pdev: device instance ++ * epnum: endpoint index ++ * return : status ++ */ ++static usb_status_t usb_core_data_in(usb_handle_t *pdev, uint8_t epnum, ++ uint8_t *pdata) ++{ ++ if (epnum == 0) { ++ usb_endpoint_t *pep = &pdev->ep_in[0]; ++ ++ if (pdev->ep0_state == USBD_EP0_DATA_IN) { ++ if (pep->rem_length > pep->maxpacket) { ++ pep->rem_length -= pep->maxpacket; ++ ++ usb_core_transmit(pdev, 0, pdata, ++ pep->rem_length); ++ ++ /* Prepare endpoint for premature ++ * end of transfer ++ */ ++ usb_core_receive(pdev, 0, NULL, 0); ++ } else { ++ /* last packet is MPS multiple, ++ * so send ZLP packet ++ */ ++ if ((pep->total_length % pep->maxpacket == 0) && ++ (pep->total_length >= pep->maxpacket) && ++ (pep->total_length < pdev->ep0_data_len)) { ++ usb_core_transmit(pdev, 0, NULL, 0); ++ ++ pdev->ep0_data_len = 0; ++ ++ /* Prepare endpoint for premature ++ * end of transfer ++ */ ++ usb_core_receive(pdev, 0, NULL, 0); ++ } else { ++ if (pdev->class->ep0_tx_sent && ++ (pdev->dev_state == ++ USBD_STATE_CONFIGURED)) ++ pdev->class->ep0_tx_sent(pdev); ++ ++ /* Set EP0 State */ ++ pdev->ep0_state = USBD_EP0_STATUS_OUT; ++ ++ /* Start the transfer */ ++ usb_core_receive(pdev, 0, NULL, 0); ++ } ++ } ++ } ++ if (pdev->dev_test_mode == 1) { ++ ERROR("Not supported"); ++ pdev->dev_test_mode = 0; ++ return USBD_FAIL; ++ } ++ } else if (pdev->class->data_in && ++ (pdev->dev_state == USBD_STATE_CONFIGURED)) { ++ pdev->class->data_in(pdev, epnum); ++ } ++ return USBD_OK; ++} ++ ++/* ++ * usb_core_Suspend ++ * Handle Suspend event ++ * pdev : device instance ++ * return : status ++ */ ++ ++static usb_status_t usb_core_suspend(usb_handle_t *pdev) ++{ ++ INFO("USB Suspend mode\n"); ++ ++ pdev->dev_old_state = pdev->dev_state; ++ pdev->dev_state = USBD_STATE_SUSPENDED; ++ ++ return USBD_OK; ++} ++ ++/* ++ * usb_core_resume ++ * Handle Resume event ++ * pdev : device instance ++ * return : status ++ */ ++ ++static usb_status_t usb_core_resume(usb_handle_t *pdev) ++{ ++ INFO("USB Resume\n"); ++ pdev->dev_state = pdev->dev_old_state; ++ ++ return USBD_OK; ++} ++ ++/* ++ * usb_core_sof ++ * Handle SOF event ++ * pdev : device instance ++ * return : status ++ */ ++ ++static usb_status_t usb_core_sof(usb_handle_t *pdev) ++{ ++ if (pdev->dev_state == USBD_STATE_CONFIGURED) { ++ if (pdev->class->sof) ++ pdev->class->sof(pdev); ++ } ++ ++ return USBD_OK; ++} ++ ++/* ++ * usb_core_DevDisconnected ++ * Handle device disconnection event ++ * pdev : device instance ++ * return : status ++ */ ++static usb_status_t usb_core_disconnect(usb_handle_t *pdev) ++{ ++ /* Free Class Resources */ ++ pdev->dev_state = USBD_STATE_DEFAULT; ++ pdev->class->de_init(pdev, pdev->dev_config); ++ ++ return USBD_OK; ++} ++ ++usb_status_t usb_core_handle_it(usb_handle_t *pdev) ++{ ++ uint32_t param = 0; ++ uint32_t len = 0; ++ usb_otg_ep_t *ep; ++ ++ switch (pdev->driver->it_handler(pdev->data->instance, ¶m)) { ++ case USB_DATA_OUT: ++ usb_core_data_out(pdev, param, ++ pdev->data->out_ep[param].xfer_buff); ++ break; ++ case USB_DATA_IN: ++ usb_core_data_in(pdev, param, ++ pdev->data->in_ep[param].xfer_buff); ++ break; ++ case USB_SETUP: ++ usb_core_setup_stage(pdev, (uint8_t *)pdev->data->setup); ++ break; ++ case USB_ENUM_DONE: ++ pdev->data->init.speed = USB_OTG_SPEED_HIGH; ++ pdev->data->init.ep0_mps = USB_OTG_HS_MAX_PACKET_SIZE; ++ break; ++ case USB_READ_DATA_PACKET: ++ ep = &pdev->data->out_ep[param & USB_OTG_OUT_EPNUM_MASK]; ++ len = (param & USB_OTG_OUT_COUNT_MASK) >> 0x10; ++ pdev->driver->read_packet(pdev->data->instance, ++ ep->xfer_buff, len); ++ ep->xfer_buff += len; ++ ep->xfer_count += len; ++ break; ++ case USB_READ_SETUP_PACKET: ++ ep = &pdev->data->out_ep[param & USB_OTG_OUT_EPNUM_MASK]; ++ len = (param & USB_OTG_OUT_COUNT_MASK) >> 0x10; ++ pdev->driver->read_packet(pdev->data->instance, ++ (uint8_t *)pdev->data->setup, 8); ++ ep->xfer_count += len; ++ break; ++ case USB_RESUME: ++ if (pdev->data->lpm_state == LPM_L1) ++ pdev->data->lpm_state = LPM_L0; ++ else ++ usb_core_resume(pdev); ++ break; ++ case USB_SUSPEND: ++ usb_core_suspend(pdev); ++ break; ++ case USB_LPM: ++ if (pdev->data->lpm_state == LPM_L0) { ++ pdev->data->lpm_state = LPM_L1; ++ pdev->data->besl = param; ++ } else { ++ usb_core_suspend(pdev); ++ } ++ break; ++ case USB_SOF: ++ usb_core_sof(pdev); ++ break; ++ case USB_DISCONNECT: ++ usb_core_disconnect(pdev); ++ break; ++ case USB_WRITE_EMPTY: ++ pdev->driver->write_empty_tx_fifo(pdev->data->instance, param, ++ pdev->data->in_ep[param].xfer_len, ++ (uint32_t *) ++ &pdev->data->in_ep[param].xfer_count, ++ pdev->data->in_ep[param].maxpacket, ++ &pdev->data->in_ep[param].xfer_buff); ++ break; ++ case USB_NOTHING: ++ default: ++ break; ++ } ++ return USBD_OK; ++} ++ ++/** ++ * @brief Receive an amount of data ++ * @param hpcd: PCD handle ++ * @param ep_addr: endpoint address ++ * @param pBuf: pointer to the reception buffer ++ * @param len: amount of data to be received ++ * @retval HAL status ++ */ ++usb_status_t usb_core_receive(usb_handle_t *pdev, uint8_t ep_addr, ++ uint8_t *buf, uint32_t len) ++{ ++ usb_otg_ep_t *ep; ++ pcd_handle_t *hpcd = (pcd_handle_t *)pdev->data; ++ ++ ep = &hpcd->out_ep[ep_addr & 0x7F]; ++ ++ /*setup and start the Xfer */ ++ ep->xfer_buff = buf; ++ ep->xfer_len = len; ++ ep->xfer_count = 0; ++ ep->is_in = 0; ++ ep->num = ep_addr & 0x7F; ++ ++ if ((ep_addr & 0x7F) == 0) ++ pdev->driver->ep0_start_xfer(hpcd->instance, ep); ++ else ++ pdev->driver->ep_start_xfer(hpcd->instance, ep); ++ ++ return USBD_OK; ++} ++ ++/* ++ * @brief Send an amount of data ++ * @param hpcd: PCD handle ++ * @param ep_addr: endpoint address ++ * @param pBuf: pointer to the transmission buffer ++ * @param len: amount of data to be sent ++ * @retval HAL status ++ */ ++usb_status_t usb_core_transmit(usb_handle_t *pdev, uint8_t ep_addr, ++ uint8_t *buf, uint32_t len) ++{ ++ usb_otg_ep_t *ep; ++ pcd_handle_t *hpcd = (pcd_handle_t *)pdev->data; ++ ++ ep = &hpcd->in_ep[ep_addr & 0x7F]; ++ ++ /*setup and start the Xfer */ ++ ep->xfer_buff = buf; ++ ep->xfer_len = len; ++ ep->xfer_count = 0; ++ ep->is_in = 1; ++ ep->num = ep_addr & 0x7F; ++ ++ if ((ep_addr & 0x7F) == 0) ++ pdev->driver->ep0_start_xfer(hpcd->instance, ep); ++ else ++ pdev->driver->ep_start_xfer(hpcd->instance, ep); ++ ++ return USBD_OK; ++} ++ ++/* ++ * @brief usb_core_ctl_error ++ * Handle USB low level Error ++ * @param pdev: device instance ++ * @param req: usb request ++ * @retval None ++ */ ++ ++void usb_core_ctl_error(usb_handle_t *pdev) ++{ ++ ERROR("%s : Send an ERROR\n", __func__); ++ usb_core_set_stall(pdev, 0x80); ++ usb_core_set_stall(pdev, 0); ++} ++ ++/* ++ * usb_core_stop ++ * Stop the USB Device Core. ++ * pdev: Device Handle ++ * return : USBD Status ++ */ ++usb_status_t usb_core_stop(usb_handle_t *pdev) ++{ ++ /* Free Class Resources */ ++ pdev->class->de_init(pdev, pdev->dev_config); ++ ++ /* Stop the low level driver */ ++ pdev->driver->disable_int(pdev->data->instance); ++ pdev->driver->stop_device(pdev->data->instance); ++ pdev->driver->dev_disconnect(pdev->data->instance); ++ return USBD_OK; ++} ++ ++/* ++ * usb_core_stop ++ * Stop the USB Device Core. ++ * pdev: Device Handle ++ * return : USBD Status ++ */ ++usb_status_t register_usb_driver(usb_handle_t *pdev, const usb_driver_t *driver, ++ void *driver_handle) ++{ ++ /* Free Class Resources */ ++ pdev->driver = driver; ++ pdev->data->instance = driver_handle; ++ return USBD_OK; ++} ++ ++/* ++ * usb_core_stop ++ * Stop the USB Device Core. ++ * pdev: Device Handle ++ * return : USBD Status ++ */ ++usb_status_t register_platform(usb_handle_t *pdev, ++ const usb_desc_t *plat_call_back) ++{ ++ /* Free Class Resources */ ++ pdev->desc = plat_call_back; ++ return USBD_OK; ++} +diff --git a/lib/usb/usb_st_dfu.c b/lib/usb/usb_st_dfu.c +new file mode 100644 +index 0000000..2cf01f6 +--- /dev/null ++++ b/lib/usb/usb_st_dfu.c +@@ -0,0 +1,865 @@ ++/* ++ * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved. ++ * ++ * SPDX-License-Identifier: BSD-3-Clause ++ */ ++ ++#include ++#include ++#include ++#include ++ ++static uintptr_t usbd_dfu_download_address; ++static uint32_t usbd_dfu_phase_id; ++static uint32_t usbd_dfu_operation_complete; ++static uint32_t usbd_dfu_current_req; ++static uint32_t usbd_detach_req; ++ ++/* ++ * @brief USBD_DFU_Init ++ * Initialize the DFU interface ++ * @param pdev: device instance ++ * @param cfgidx: Configuration index ++ * @retval status ++ */ ++static uint8_t usb_dfu_init(usb_handle_t *pdev, uint8_t cfgidx) ++{ ++ /* Nothing to do in this stage */ ++ return USBD_OK; ++} ++ ++/** ++ * @brief USBD_DFU_Init ++ * De-Initialize the DFU layer ++ * @param pdev: device instance ++ * @param cfgidx: Configuration index ++ * @retval status ++ */ ++static uint8_t usb_dfu_de_init(usb_handle_t *pdev, uint8_t cfgidx) ++{ ++ /* Nothing to do in this stage */ ++ return USBD_OK; ++} ++ ++/* ++ * @brief USBD_DFU_DataIn ++ * handle data IN Stage ++ * @param pdev: device instance ++ * @param epnum: endpoint index ++ * @retval status ++ */ ++static uint8_t usb_dfu_data_in(usb_handle_t *pdev, uint8_t epnum) ++{ ++ (void)pdev; ++ (void)epnum; ++ ++ return USBD_OK; ++} ++ ++/* ++ * @brief DFU_Leave ++ * Handles the sub-protocol DFU leave DFU mode request (leaves DFU mode ++ * and resets device to jump to user loaded code). ++ * @param pdev: device instance ++ * @retval None ++ */ ++static void usb_dfu_leave(usb_handle_t *pdev) ++{ ++ usb_dfu_handle_t *hdfu = (usb_dfu_handle_t *)pdev->class_data; ++ ++ hdfu->manif_state = DFU_MANIFEST_COMPLETE; ++ ++ if (DFU_BM_ATTRIBUTE & 0x04) { ++ hdfu->dev_state = DFU_STATE_MANIFEST_SYNC; ++ ++ hdfu->dev_status[1] = 0; ++ hdfu->dev_status[2] = 0; ++ hdfu->dev_status[3] = 0; ++ hdfu->dev_status[4] = hdfu->dev_state; ++ } else { ++ hdfu->dev_state = DFU_STATE_MANIFEST_WAIT_RESET; ++ ++ hdfu->dev_status[1] = 0; ++ hdfu->dev_status[2] = 0; ++ hdfu->dev_status[3] = 0; ++ hdfu->dev_status[4] = hdfu->dev_state; ++ ++ /* Disconnect the USB device */ ++ usb_core_stop(pdev); ++ } ++} ++ ++/* ++ * @brief USBD_DFU_EP0_RxReady ++ * handle EP0 Rx Ready event ++ * @param pdev: device instance ++ * @retval status ++ */ ++static uint8_t usb_dfu_ep0_rx_ready(usb_handle_t *pdev) ++{ ++ (void)pdev; ++ ++ return USBD_OK; ++} ++ ++/* ++ * @brief USBD_DFU_EP0_TxReady ++ * handle EP0 TRx Ready event ++ * @param pdev: device instance ++ * @retval status ++ */ ++static uint8_t usb_dfu_ep0_tx_ready(usb_handle_t *pdev) ++{ ++ usb_dfu_handle_t *hdfu = (usb_dfu_handle_t *)pdev->class_data; ++ uint16_t len, dfu_version = 0; ++ uint8_t *serial = pdev->desc->get_dfu_desc(&len); ++ ++ dfu_version = serial[len - 1] << 8 | serial[len - 2]; ++ ++ if (hdfu->dev_state == DFU_STATE_DNLOAD_BUSY) { ++ if (dfu_version == 0x011a) { ++ /* Decode the Special Command*/ ++ if (hdfu->wblock_num == 0) { ++ if (hdfu->buffer[0] == ++ DFU_CMD_SETADDRESSPOINTER && ++ hdfu->wlength == 5) { ++ hdfu->data_ptr = hdfu->buffer[1]; ++ hdfu->data_ptr += ++ hdfu->buffer[2] << 8; ++ hdfu->data_ptr += ++ hdfu->buffer[3] << 16; ++ hdfu->data_ptr += ++ hdfu->buffer[4] << 24; ++ } else if (hdfu->buffer[0] == ++ DFU_CMD_ERASE && ++ hdfu->wlength == 5) { ++ hdfu->data_ptr = hdfu->buffer[1]; ++ hdfu->data_ptr += ++ hdfu->buffer[2] << 8; ++ hdfu->data_ptr += ++ hdfu->buffer[3] << 16; ++ hdfu->data_ptr += ++ hdfu->buffer[4] << 24; ++ } else { ++ /* Reset the global length and block number */ ++ hdfu->wlength = 0; ++ hdfu->wblock_num = 0; ++ /* Call the error management function ++ * (command will be nacked) ++ */ ++ usb_core_ctl_error(pdev); ++ } ++ } ++ } ++ if ((hdfu->wblock_num > 1 && dfu_version == 0x011a) || ++ dfu_version != 0x011a) { ++ /* Perform the write operation */ ++ if (((usb_dfu_media_t *) ++ pdev->user_data)->write_done((uint32_t *) ++ hdfu->data_ptr, ++ hdfu->wlength) ++ != USBD_OK) ++ return USBD_FAIL; ++ } ++ ++ /* Reset the global length and block number */ ++ hdfu->wlength = 0; ++ hdfu->wblock_num = 0; ++ ++ /* Update the state machine */ ++ hdfu->dev_state = DFU_STATE_DNLOAD_SYNC; ++ hdfu->dev_status[1] = 0; ++ hdfu->dev_status[2] = 0; ++ hdfu->dev_status[3] = 0; ++ hdfu->dev_status[4] = hdfu->dev_state; ++ return USBD_OK; ++ } else if (hdfu->dev_state == DFU_STATE_MANIFEST) { ++ /* Manifestation in progress*/ ++ /* Start leaving DFU mode */ ++ usb_dfu_leave(pdev); ++ } ++ ++ return USBD_OK; ++} ++ ++/* ++ * @brief USBD_DFU_SOF ++ * handle SOF event ++ * @param pdev: device instance ++ * @retval status ++ */ ++static uint8_t usb_dfu_sof(usb_handle_t *pdev) ++{ ++ (void)pdev; ++ ++ return USBD_OK; ++} ++ ++/* ++ * @brief USBD_DFU_IsoINIncomplete ++ * handle data ISO IN Incomplete event ++ * @param pdev: device instance ++ * @param epnum: endpoint index ++ * @retval status ++ */ ++static uint8_t usb_dfu_iso_in_incomplete(usb_handle_t *pdev, uint8_t epnum) ++{ ++ (void)pdev; ++ (void)epnum; ++ return USBD_OK; ++} ++ ++/* ++ * @brief USBD_DFU_IsoOutIncomplete ++ * handle data ISO OUT Incomplete event ++ * @param pdev: device instance ++ * @param epnum: endpoint index ++ * @retval status ++ */ ++static uint8_t usb_dfu_iso_out_incomplete(usb_handle_t *pdev, uint8_t epnum) ++{ ++ (void)pdev; ++ (void)epnum; ++ return USBD_OK; ++} ++ ++/* ++ * @brief USBD_DFU_DataOut ++ * handle data OUT Stage ++ * @param pdev: device instance ++ * @param epnum: endpoint index ++ * @retval status ++ */ ++static uint8_t usb_dfu_data_out(usb_handle_t *pdev, uint8_t epnum) ++{ ++ (void)pdev; ++ (void)epnum; ++ return USBD_OK; ++} ++ ++/* ++ * @brief DFU_Detach ++ * Handles the DFU DETACH request. ++ * @param pdev: device instance ++ * @param req: pointer to the request structure. ++ * @retval None. ++ */ ++static void usb_dfu_detach(usb_handle_t *pdev, usb_setup_req_t *req) ++{ ++ usb_dfu_handle_t *hdfu = (usb_dfu_handle_t *)pdev->class_data; ++ ++ INFO("Receive Detach\n"); ++ ++ if (hdfu->dev_state == DFU_STATE_IDLE || ++ hdfu->dev_state == DFU_STATE_DNLOAD_SYNC || ++ hdfu->dev_state == DFU_STATE_DNLOAD_IDLE || ++ hdfu->dev_state == DFU_STATE_MANIFEST_SYNC || ++ hdfu->dev_state == DFU_STATE_UPLOAD_IDLE) { ++ /* Update the state machine */ ++ hdfu->dev_state = DFU_STATE_IDLE; ++ hdfu->dev_status[0] = DFU_ERROR_NONE; ++ hdfu->dev_status[1] = 0; ++ hdfu->dev_status[2] = 0; ++ hdfu->dev_status[3] = 0; /*bwPollTimeout=0ms*/ ++ hdfu->dev_status[4] = hdfu->dev_state; ++ hdfu->dev_status[5] = 0; /*iString*/ ++ hdfu->wblock_num = 0; ++ } ++ hdfu->wlength = 0; ++ ++ usbd_detach_req = 0; ++} ++ ++/* ++ * @brief DFU_Download ++ * Handles the DFU DNLOAD request. ++ * @param pdev: device instance ++ * @param req: pointer to the request structure ++ * @retval None ++ */ ++static void usb_dfu_download(usb_handle_t *pdev, usb_setup_req_t *req) ++{ ++ usb_dfu_handle_t *hdfu = (usb_dfu_handle_t *)pdev->class_data; ++ ++ /* Data setup request */ ++ if (req->length > 0) { ++ if ((hdfu->dev_state == DFU_STATE_IDLE) || ++ (hdfu->dev_state == DFU_STATE_DNLOAD_IDLE)) { ++ /* Update the global length and block number */ ++ hdfu->wblock_num = req->value; ++ hdfu->wlength = req->length; ++ ++ /* Update the data address */ ++ hdfu->data_ptr = usbd_dfu_download_address; ++ ++ /* Update the state machine */ ++ hdfu->dev_state = DFU_STATE_DNLOAD_SYNC; ++ hdfu->dev_status[4] = hdfu->dev_state; ++ ++ /* Prepare the reception of the buffer over EP0 */ ++ /* Set EP0 State */ ++ pdev->ep0_state = USBD_EP0_DATA_OUT; ++ pdev->ep_out[0].total_length = hdfu->wlength; ++ pdev->ep_out[0].rem_length = hdfu->wlength; ++ ++ /* Start the transfer */ ++ usb_core_receive(pdev, ++ 0, ++ (uint8_t *)usbd_dfu_download_address, ++ hdfu->wlength); ++ ++ usbd_dfu_download_address += hdfu->wlength; ++ } else { ++ /* Unsupported state */ ++ /* Call the error management function ++ * (command will be nacked) ++ */ ++ usb_core_ctl_error(pdev); ++ } ++ } else { ++ /* End of DNLOAD operation*/ ++ if (hdfu->dev_state == DFU_STATE_DNLOAD_IDLE || ++ hdfu->dev_state == DFU_STATE_IDLE) { ++ hdfu->manif_state = DFU_MANIFEST_IN_PROGRESS; ++ hdfu->dev_state = DFU_STATE_MANIFEST_SYNC; ++ hdfu->dev_status[1] = 0; ++ hdfu->dev_status[2] = 0; ++ hdfu->dev_status[3] = 0; ++ hdfu->dev_status[4] = hdfu->dev_state; ++ } else { ++ /* Call the error management function ++ * (command will be nacked) ++ */ ++ usb_core_ctl_error(pdev); ++ } ++ } ++} ++ ++/* ++ * @brief DFU_Upload ++ * Handles the DFU UPLOAD request. ++ * @param pdev: instance ++ * @param req: pointer to the request structure ++ * @retval status ++ */ ++static void usb_dfu_upload(usb_handle_t *pdev, usb_setup_req_t *req) ++{ ++ usb_dfu_handle_t *hdfu = (usb_dfu_handle_t *)pdev->class_data; ++ ++ /* Data setup request */ ++ if (req->length > 0) { ++ if ((hdfu->dev_state == DFU_STATE_IDLE) || ++ (hdfu->dev_state == DFU_STATE_UPLOAD_IDLE)) { ++ /* Update the global length and block number */ ++ hdfu->wblock_num = req->value; ++ hdfu->wlength = req->length; ++ ++ /* DFU GetPhase Command */ ++ if (hdfu->wblock_num == 0) { ++ /* Update the state machine */ ++ hdfu->dev_state = (hdfu->wlength > 3) ? ++ DFU_STATE_IDLE : ++ DFU_STATE_UPLOAD_IDLE; ++ ++ hdfu->dev_status[1] = 0; ++ hdfu->dev_status[2] = 0; ++ hdfu->dev_status[3] = 0; ++ hdfu->dev_status[4] = hdfu->dev_state; ++ ++ INFO("UPLOAD :\n"); ++ INFO("\t\tPhase ID : %i\n", usbd_dfu_phase_id); ++ INFO("\t\taddress 0x%lx\n", ++ usbd_dfu_download_address); ++ ++ hdfu->buffer[0] = usbd_dfu_phase_id; ++ hdfu->buffer[1] = (uint8_t) ++ (usbd_dfu_download_address); ++ hdfu->buffer[2] = (uint8_t) ++ (usbd_dfu_download_address >> ++ 8); ++ hdfu->buffer[3] = (uint8_t) ++ (usbd_dfu_download_address >> ++ 16); ++ hdfu->buffer[4] = (uint8_t) ++ (usbd_dfu_download_address >> ++ 24); ++ ++ hdfu->buffer[5] = 0x00; ++ hdfu->buffer[6] = 0x00; ++ hdfu->buffer[7] = 0x00; ++ hdfu->buffer[8] = 0x00; ++ ++ if ((usbd_dfu_download_address == ++ UNDEFINE_DOWN_ADDR) && ++ (usbd_detach_req)) { ++ INFO("Send detach request\n"); ++ hdfu->buffer[9] = 0x01; ++ pdev->ep_in[0].total_length = 10; ++ pdev->ep_in[0].rem_length = 10; ++ } else { ++ pdev->ep_in[0].total_length = 9; ++ pdev->ep_in[0].rem_length = 9; ++ } ++ ++ /* Send the status data over EP0 */ ++ pdev->ep0_state = USBD_EP0_DATA_IN; ++ /* Start the transfer */ ++ usb_core_transmit(pdev, 0x00, ++ (uint8_t *)&hdfu->buffer[0], ++ pdev->ep_in[0].total_length); ++ } else { ++ /* unsupported hdfu->wblock_num */ ++ ERROR("UPLOAD : Unsupported block : %i\n", ++ hdfu->wblock_num); ++ ++ hdfu->dev_state = DFU_ERROR_STALLEDPKT; ++ ++ hdfu->dev_status[1] = 0; ++ hdfu->dev_status[2] = 0; ++ hdfu->dev_status[3] = 0; ++ hdfu->dev_status[4] = hdfu->dev_state; ++ ++ /* Call the error management function ++ * (command will be nacked ++ */ ++ usb_core_ctl_error(pdev); ++ } ++ } else { ++ /* Unsupported state */ ++ ERROR("UPLOAD : Unsupported State\n"); ++ ++ hdfu->wlength = 0; ++ hdfu->wblock_num = 0; ++ /* Call the error management function ++ * (command will be nacked ++ */ ++ usb_core_ctl_error(pdev); ++ } ++ } else { ++ /* No Data setup request */ ++ INFO("USB : DFU : Nothing to do\n"); ++ hdfu->dev_state = DFU_STATE_IDLE; ++ ++ hdfu->dev_status[1] = 0; ++ hdfu->dev_status[2] = 0; ++ hdfu->dev_status[3] = 0; ++ hdfu->dev_status[4] = hdfu->dev_state; ++ } ++} ++ ++/* ++ * @brief DFU_GetStatus ++ * Handles the DFU GETSTATUS request. ++ * @param pdev: instance ++ * @retval status ++ */ ++static void usb_dfu_get_status(usb_handle_t *pdev) ++{ ++ usb_dfu_handle_t *hdfu = (usb_dfu_handle_t *)pdev->class_data; ++ uint16_t status; ++ uint8_t dfu_bm_attribute = DFU_BM_ATTRIBUTE; ++ ++ switch (hdfu->dev_state) { ++ case DFU_STATE_DNLOAD_SYNC: ++ status = ((usb_dfu_media_t *)pdev->user_data)->get_status(); ++ ++ switch (status) { ++ case DFU_MEDIA_STATE_WRITTEN: ++ /* SRAM block writing is finished, checks if checksum ++ * error has been detected ++ */ ++ hdfu->dev_state = DFU_STATE_DNLOAD_IDLE; ++ break; ++ ++ case DFU_MEDIA_STATE_ERROR: ++ hdfu->dev_state = DFU_STATE_ERROR; ++ break; ++ ++ case DFU_MEDIA_STATE_READY: ++ default: ++ /* SRAM is ready to be written */ ++ hdfu->dev_state = DFU_STATE_DNLOAD_BUSY; ++ break; ++ } ++ hdfu->dev_status[1] = 0; ++ hdfu->dev_status[2] = 0; ++ hdfu->dev_status[3] = 0; ++ hdfu->dev_status[4] = hdfu->dev_state; ++ break; ++ ++ case DFU_STATE_MANIFEST_SYNC: ++ if (hdfu->manif_state == DFU_MANIFEST_IN_PROGRESS) { ++ hdfu->dev_state = DFU_STATE_MANIFEST; ++ ++ hdfu->dev_status[1] = 1;/*bwPollTimeout = 1ms*/ ++ hdfu->dev_status[2] = 0; ++ hdfu->dev_status[3] = 0; ++ hdfu->dev_status[4] = hdfu->dev_state; ++ } else if ((hdfu->manif_state == DFU_MANIFEST_COMPLETE) && ++ (dfu_bm_attribute & 0x04)) { ++ INFO("USB : DFU : end of download partition : %i\n", ++ hdfu->alt_setting); ++ hdfu->dev_state = DFU_STATE_IDLE; ++ usbd_dfu_operation_complete = 1; ++ ++ hdfu->dev_status[1] = 0; ++ hdfu->dev_status[2] = 0; ++ hdfu->dev_status[3] = 0; ++ hdfu->dev_status[4] = hdfu->dev_state; ++ } ++ break; ++ ++ default: ++ break; ++ } ++ ++ /* Send the status data over EP0 */ ++ pdev->ep0_state = USBD_EP0_DATA_IN; ++ pdev->ep_in[0].total_length = 6; ++ pdev->ep_in[0].rem_length = 6; ++ /* Start the transfer */ ++ usb_core_transmit(pdev, 0x00, (uint8_t *)&hdfu->dev_status[0], 6); ++} ++ ++/* ++ * @brief DFU_ClearStatus ++ * Handles the DFU CLRSTATUS request. ++ * @param pdev: device instance ++ * @retval status ++ */ ++static void usb_dfu_clear_status(usb_handle_t *pdev) ++{ ++ usb_dfu_handle_t *hdfu = (usb_dfu_handle_t *)pdev->class_data; ++ ++ if (hdfu->dev_state == DFU_STATE_ERROR) { ++ hdfu->dev_state = DFU_STATE_IDLE; ++ hdfu->dev_status[0] = DFU_ERROR_NONE;/*bStatus*/ ++ hdfu->dev_status[1] = 0; ++ hdfu->dev_status[2] = 0; ++ hdfu->dev_status[3] = 0; /*bwPollTimeout=0ms*/ ++ hdfu->dev_status[4] = hdfu->dev_state;/*bState*/ ++ hdfu->dev_status[5] = 0;/*iString*/ ++ } else { ++ /*State Error*/ ++ hdfu->dev_state = DFU_STATE_ERROR; ++ hdfu->dev_status[0] = DFU_ERROR_UNKNOWN;/*bStatus*/ ++ hdfu->dev_status[1] = 0; ++ hdfu->dev_status[2] = 0; ++ hdfu->dev_status[3] = 0; /*bwPollTimeout=0ms*/ ++ hdfu->dev_status[4] = hdfu->dev_state;/*bState*/ ++ hdfu->dev_status[5] = 0;/*iString*/ ++ } ++} ++ ++/* ++ * @brief DFU_GetState ++ * Handles the DFU GETSTATE request. ++ * @param pdev: device instance ++ * @retval None ++ */ ++static void usb_dfu_get_state(usb_handle_t *pdev) ++{ ++ usb_dfu_handle_t *hdfu = (usb_dfu_handle_t *)pdev->class_data; ++ ++ /* Return the current state of the DFU interface */ ++ /* Send the status data over EP0 */ ++ pdev->ep0_state = USBD_EP0_DATA_IN; ++ pdev->ep_in[0].total_length = 1; ++ pdev->ep_in[0].rem_length = 1; ++ ++ /* Start the transfer */ ++ usb_core_transmit(pdev, 0x00, &hdfu->dev_state, 1); ++} ++ ++/* ++ * @brief DFU_Abort ++ * Handles the DFU ABORT request. ++ * @param pdev: device instance ++ * @retval None ++ */ ++static void usb_dfu_abort(usb_handle_t *pdev) ++{ ++ usb_dfu_handle_t *hdfu = (usb_dfu_handle_t *)pdev->class_data; ++ ++ if (hdfu->dev_state == DFU_STATE_IDLE || ++ hdfu->dev_state == DFU_STATE_DNLOAD_SYNC || ++ hdfu->dev_state == DFU_STATE_DNLOAD_IDLE || ++ hdfu->dev_state == DFU_STATE_MANIFEST_SYNC || ++ hdfu->dev_state == DFU_STATE_UPLOAD_IDLE) { ++ hdfu->dev_state = DFU_STATE_IDLE; ++ hdfu->dev_status[0] = DFU_ERROR_NONE; ++ hdfu->dev_status[1] = 0; ++ hdfu->dev_status[2] = 0; ++ hdfu->dev_status[3] = 0; /*bwPollTimeout=0ms*/ ++ hdfu->dev_status[4] = hdfu->dev_state; ++ hdfu->dev_status[5] = 0; /*iString*/ ++ hdfu->wblock_num = 0; ++ hdfu->wlength = 0; ++ } ++} ++ ++/* ++ * @brief USBD_DFU_Setup ++ * Handle the DFU specific requests ++ * @param pdev: instance ++ * @param req: usb requests ++ * @retval status ++ */ ++static uint8_t usb_dfu_setup(usb_handle_t *pdev, usb_setup_req_t *req) ++{ ++ uint8_t *pbuf = NULL; ++ uint16_t len = 0; ++ uint8_t ret = USBD_OK; ++ usb_dfu_handle_t *hdfu = (usb_dfu_handle_t *)pdev->class_data; ++ ++ VERBOSE("alt_setting %i, bmRequest : 0x%x, brequest : 0x%x\n", ++ hdfu->alt_setting, req->bm_request & USB_REQ_TYPE_MASK, ++ req->b_request); ++ switch (req->bm_request & USB_REQ_TYPE_MASK) { ++ case USB_REQ_TYPE_CLASS: ++ usbd_dfu_current_req = req->b_request; ++ if (hdfu->alt_setting == usbd_dfu_phase_id) { ++ switch (req->b_request) { ++ case DFU_DNLOAD: ++ usb_dfu_download(pdev, req); ++ break; ++ ++ case DFU_UPLOAD: ++ usb_dfu_upload(pdev, req); ++ break; ++ ++ case DFU_GETSTATUS: ++ usb_dfu_get_status(pdev); ++ break; ++ ++ case DFU_CLRSTATUS: ++ usb_dfu_clear_status(pdev); ++ break; ++ ++ case DFU_GETSTATE: ++ usb_dfu_get_state(pdev); ++ break; ++ ++ case DFU_ABORT: ++ usb_dfu_abort(pdev); ++ break; ++ ++ case DFU_DETACH: ++ usb_dfu_detach(pdev, req); ++ break; ++ ++ default: ++ ERROR("phase ID :%i\n", usbd_dfu_phase_id); ++ usb_core_ctl_error(pdev); ++ ret = USBD_FAIL; ++ break; ++ } ++ } else if (hdfu->alt_setting == DFU_GET_PHASE) { ++ switch (req->b_request) { ++ case DFU_UPLOAD: ++ usb_dfu_upload(pdev, req); ++ break; ++ ++ case DFU_GETSTATUS: ++ INFO("GETSTATUS :\n"); ++ usb_dfu_get_status(pdev); ++ ++ switch (hdfu->dev_state) { ++ case APP_STATE_IDLE: ++ INFO("\t\tAPP_STATE_IDLE\n"); ++ break; ++ case APP_STATE_DETACH: ++ INFO("\t\tAPP_STATE_DETACH\n"); ++ break; ++ case DFU_STATE_IDLE: ++ INFO("\t\tDFU_STATE_IDLE\n"); ++ break; ++ case DFU_STATE_DNLOAD_SYNC: ++ INFO("\t\tDFU_STATE_DNLOAD_SYNC\n"); ++ break; ++ case DFU_STATE_DNLOAD_BUSY: ++ INFO("\t\tDFU_STATE_DNLOAD_BUSY\n"); ++ break; ++ case DFU_STATE_DNLOAD_IDLE: ++ INFO("\t\tDFU_STATE_DNLOAD_IDLE\n"); ++ break; ++ case DFU_STATE_MANIFEST_SYNC: ++ INFO("\t\tDFU_STATE_MANIFEST_SYNC\n"); ++ break; ++ case DFU_STATE_MANIFEST: ++ INFO("\t\tDFU_STATE_MANIFEST\n"); ++ break; ++ case DFU_STATE_MANIFEST_WAIT_RESET: ++ INFO( ++ "\t\tDFU_STATE_MANIFEST_WAIT_RESET\n"); ++ break; ++ case DFU_STATE_UPLOAD_IDLE: ++ INFO("\t\tDFU_STATE_UPLOAD_IDLE\n"); ++ break; ++ case DFU_STATE_ERROR: ++ ERROR("\t\tDFU_STATE_ERROR\n"); ++ break; ++ default: ++ break; ++ } ++ break; ++ ++ case DFU_CLRSTATUS: ++ INFO("Receive DFU clear status\n"); ++ usb_dfu_clear_status(pdev); ++ break; ++ ++ case DFU_GETSTATE: ++ INFO("GETSTATE :\n"); ++ usb_dfu_get_state(pdev); ++ ++ switch (hdfu->dev_state) { ++ case APP_STATE_IDLE: ++ INFO("\t\tAPP_STATE_IDLE\n"); ++ break; ++ case APP_STATE_DETACH: ++ INFO("\t\tAPP_STATE_DETACH\n"); ++ break; ++ case DFU_STATE_IDLE: ++ INFO("\t\tDFU_STATE_IDLE\n"); ++ break; ++ case DFU_STATE_DNLOAD_SYNC: ++ INFO("\t\tDFU_STATE_DNLOAD_SYNC\n"); ++ break; ++ case DFU_STATE_DNLOAD_BUSY: ++ INFO("\t\tDFU_STATE_DNLOAD_BUSY\n"); ++ break; ++ case DFU_STATE_DNLOAD_IDLE: ++ INFO("\t\tDFU_STATE_DNLOAD_IDLE\n"); ++ break; ++ case DFU_STATE_MANIFEST_SYNC: ++ INFO("\t\tDFU_STATE_MANIFEST_SYNC\n"); ++ break; ++ case DFU_STATE_MANIFEST: ++ INFO("\t\tDFU_STATE_MANIFEST\n"); ++ break; ++ case DFU_STATE_MANIFEST_WAIT_RESET: ++ INFO( ++ "\t\tDFU_STATE_MANIFEST_WAIT_RESET\n"); ++ break; ++ case DFU_STATE_UPLOAD_IDLE: ++ INFO("\t\tDFU_STATE_UPLOAD_IDLE\n"); ++ break; ++ case DFU_STATE_ERROR: ++ ERROR("\t\tDFU_STATE_ERROR\n"); ++ break; ++ default: ++ break; ++ } ++ break; ++ ++ case DFU_ABORT: ++ INFO("Receive DFU abort\n"); ++ usb_dfu_abort(pdev); ++ break; ++ ++ case DFU_DETACH: ++ INFO("Receive DFU detach\n"); ++ break; ++ ++ default: ++ ERROR("phase ID :%i\n", DFU_GET_PHASE); ++ usb_core_ctl_error(pdev); ++ ret = USBD_FAIL; ++ break; ++ } ++ } else { ++ ERROR("Unknown alternate : %i\n", hdfu->alt_setting); ++ ret = USBD_FAIL; ++ } ++ break; ++ case USB_REQ_TYPE_STANDARD: ++ switch (req->b_request) { ++ case USB_REQ_GET_DESCRIPTOR: ++ if ((req->value >> 8) == DFU_DESCRIPTOR_TYPE) { ++ pbuf = pdev->desc->get_dfu_desc(&len); ++ len = MIN(len, req->length); ++ } ++ ++ pdev->ep0_state = USBD_EP0_DATA_IN; ++ pdev->ep_in[0].total_length = len; ++ pdev->ep_in[0].rem_length = len; ++ /* Start the transfer */ ++ usb_core_transmit(pdev, 0x00, pbuf, len); ++ ++ break; ++ ++ case USB_REQ_GET_INTERFACE: ++ pdev->ep0_state = USBD_EP0_DATA_IN; ++ pdev->ep_in[0].total_length = 1; ++ pdev->ep_in[0].rem_length = 1; ++ /* Start the transfer */ ++ usb_core_transmit(pdev, 0x00, ++ (uint8_t *)&hdfu->alt_setting, 1); ++ break; ++ ++ case USB_REQ_SET_INTERFACE: ++ hdfu->alt_setting = (uint8_t)(req->value); ++ break; ++ ++ default: ++ usb_core_ctl_error(pdev); ++ ret = USBD_FAIL; ++ break; ++ } ++ default: ++ break; ++ } ++ ++ return ret; ++} ++ ++static const usb_class_t USBD_DFU_initvalue = { ++ usb_dfu_init, ++ usb_dfu_de_init, ++ usb_dfu_setup, ++ usb_dfu_ep0_tx_ready, ++ usb_dfu_ep0_rx_ready, ++ usb_dfu_data_in, ++ usb_dfu_data_out, ++ usb_dfu_sof, ++ usb_dfu_iso_in_incomplete, ++ usb_dfu_iso_out_incomplete, ++ 0 ++}; ++ ++void usb_dfu_register_callback(usb_handle_t *pdev) ++{ ++ pdev->class = (usb_class_t *)&USBD_DFU_initvalue; ++} ++ ++void usb_dfu_set_phase_id(uint32_t phase_id) ++{ ++ usbd_dfu_phase_id = phase_id; ++ usbd_dfu_operation_complete = 0; ++} ++ ++void usb_dfu_set_download_addr(uintptr_t addr) ++{ ++ usbd_dfu_download_address = addr; ++} ++ ++uint32_t usb_dfu_download_is_completed(void) ++{ ++ return usbd_dfu_operation_complete; ++} ++ ++uint32_t usb_dfu_get_current_req(void) ++{ ++ return usbd_dfu_current_req; ++} ++ ++uint32_t usb_dfu_detach_req(void) ++{ ++ return usbd_detach_req; ++} ++ ++void usb_dfu_request_detach(void) ++{ ++ usbd_detach_req = 1; ++} +diff --git a/lib/xlat_tables/aarch32/xlat_tables.c b/lib/xlat_tables/aarch32/xlat_tables.c +index 5595703..27e7207 100644 +--- a/lib/xlat_tables/aarch32/xlat_tables.c ++++ b/lib/xlat_tables/aarch32/xlat_tables.c +@@ -23,8 +23,17 @@ + #define NUM_BASE_LEVEL_ENTRIES \ + GET_NUM_BASE_LEVEL_ENTRIES(PLAT_VIRT_ADDR_SPACE_SIZE) + ++#ifdef PLAT_BASE_XLAT_BASE ++CASSERT(!(PLAT_BASE_XLAT_BASE & ++ (NUM_BASE_LEVEL_ENTRIES * sizeof(uint64_t) - 1)), ++ invalid_plat_base_xlat_base); ++CASSERT(PLAT_BASE_XLAT_SIZE == sizeof(uint64_t) * NUM_BASE_LEVEL_ENTRIES, ++ invalid_plat_base_xlat_size); ++static uint64_t *base_xlation_table = (uint64_t *)PLAT_BASE_XLAT_BASE; ++#else + static uint64_t base_xlation_table[NUM_BASE_LEVEL_ENTRIES] + __aligned(NUM_BASE_LEVEL_ENTRIES * sizeof(uint64_t)); ++#endif + + #if ENABLE_ASSERTIONS + static unsigned long long get_max_supported_pa(void) +diff --git a/lib/xlat_tables/aarch64/xlat_tables.c b/lib/xlat_tables/aarch64/xlat_tables.c +index 4afdeed..309fda1 100644 +--- a/lib/xlat_tables/aarch64/xlat_tables.c ++++ b/lib/xlat_tables/aarch64/xlat_tables.c +@@ -22,6 +22,10 @@ + #define NUM_BASE_LEVEL_ENTRIES \ + GET_NUM_BASE_LEVEL_ENTRIES(PLAT_VIRT_ADDR_SPACE_SIZE) + ++#ifdef PLAT_BASE_XLAT_BASE ++#error "PLAT_BASE_XLAT_BASE is not allowed on AArch64 capable architectures" ++#endif ++ + static uint64_t base_xlation_table[NUM_BASE_LEVEL_ENTRIES] + __aligned(NUM_BASE_LEVEL_ENTRIES * sizeof(uint64_t)); + +diff --git a/lib/xlat_tables/xlat_tables_common.c b/lib/xlat_tables/xlat_tables_common.c +index ca67f2a..9c903f9 100644 +--- a/lib/xlat_tables/xlat_tables_common.c ++++ b/lib/xlat_tables/xlat_tables_common.c +@@ -35,8 +35,17 @@ + #define UNSET_DESC ~0ULL + #define MT_UNKNOWN ~0U + ++#ifdef PLAT_XLAT_BASE ++#define XLAT_TABLE_REQUIRED_ENTRIES (XLAT_TABLE_ENTRIES * MAX_XLAT_TABLES) ++CASSERT(PLAT_XLAT_SIZE == sizeof(uint64_t) * XLAT_TABLE_REQUIRED_ENTRIES, ++ invalid_plat_xlat_size); ++CASSERT(!(PLAT_XLAT_BASE & (XLAT_TABLE_SIZE - 1)), invalid_plat_xlat_base); ++#define xlat_tables ((uint64_t (*)[XLAT_TABLE_ENTRIES]) \ ++ (unsigned long *)PLAT_XLAT_BASE) ++#else + static uint64_t xlat_tables[MAX_XLAT_TABLES][XLAT_TABLE_ENTRIES] + __aligned(XLAT_TABLE_SIZE) __section("xlat_table"); ++#endif + + static unsigned int next_xlat; + static unsigned long long xlat_max_pa; +@@ -408,6 +417,15 @@ void init_xlation_table(uintptr_t base_va, uint64_t *table, + ap1_mask = 0ULL; + } + ++#ifdef PLAT_BASE_XLAT_BASE ++ inv_dcache_range(PLAT_BASE_XLAT_BASE, PLAT_BASE_XLAT_SIZE); ++ zeromem((void *)PLAT_BASE_XLAT_BASE, PLAT_BASE_XLAT_SIZE); ++#endif ++#ifdef PLAT_XLAT_BASE ++ inv_dcache_range(PLAT_XLAT_BASE, PLAT_XLAT_SIZE); ++ zeromem((void *)PLAT_XLAT_BASE, PLAT_XLAT_SIZE); ++#endif ++ + init_xlation_table_inner(mmap, base_va, table, level); + *max_va = xlat_max_va; + *max_pa = xlat_max_pa; +diff --git a/lib/xlat_tables_v2/xlat_tables_core.c b/lib/xlat_tables_v2/xlat_tables_core.c +index 003718e..a410ad6 100644 +--- a/lib/xlat_tables_v2/xlat_tables_core.c ++++ b/lib/xlat_tables_v2/xlat_tables_core.c +@@ -1026,7 +1026,12 @@ void init_xlat_tables_ctx(xlat_ctx_t *ctx) + xlat_mmap_print(mm); + + /* All tables must be zeroed before mapping any region. */ +- ++#ifdef PLAT_BASE_XLAT_BASE ++ inv_dcache_range(PLAT_BASE_XLAT_BASE, PLAT_BASE_XLAT_SIZE); ++#endif ++#ifdef PLAT_XLAT_BASE ++ inv_dcache_range(PLAT_XLAT_BASE, PLAT_XLAT_SIZE); ++#endif + for (unsigned int i = 0U; i < ctx->base_table_entries; i++) + ctx->base_table[i] = INVALID_DESC; + +diff --git a/make_helpers/build_macros.mk b/make_helpers/build_macros.mk +index 92a0f6e..44c537b 100644 +--- a/make_helpers/build_macros.mk ++++ b/make_helpers/build_macros.mk +@@ -450,17 +450,24 @@ endef + # $(2) = input dts + define MAKE_DTB + ++# List of DTB file(s) to generate, based on DTS file basename list + $(eval DOBJ := $(addprefix $(1)/,$(call SOURCES_TO_DTBS,$(2)))) ++# List of the pre-compiled DTS file(s) + $(eval DPRE := $(addprefix $(1)/,$(patsubst %.dts,%.pre.dts,$(notdir $(2))))) +-$(eval DEP := $(patsubst %.dtb,%.d,$(DOBJ))) ++# Dependencies of the pre-compiled DTS file(s) on its source and included files ++$(eval DTSDEP := $(patsubst %.dtb,%.o.d,$(DOBJ))) ++# Dependencies of the DT compilation on its pre-compiled DTS ++$(eval DTBDEP := $(patsubst %.dtb,%.d,$(DOBJ))) + + $(DOBJ): $(2) $(filter-out %.d,$(MAKEFILE_LIST)) | fdt_dirs + @echo " CPP $$<" +- $$(Q)$$(CPP) $$(CPPFLAGS) -x assembler-with-cpp -o $(DPRE) $$< ++ $(eval DTBS := $(addprefix $(1)/,$(call SOURCES_TO_DTBS,$(2)))) ++ $$(Q)$$(CPP) $$(CPPFLAGS) -x assembler-with-cpp -MT $(DTBS) -MMD -MF $(DTSDEP) -o $(DPRE) $$< + @echo " DTC $$<" +- $$(Q)$$(DTC) $$(DTC_FLAGS) -i fdts -d $(DEP) -o $$@ $(DPRE) ++ $$(Q)$$(DTC) $$(DTC_FLAGS) -i fdts -d $(DTBDEP) -o $$@ $(DPRE) + +--include $(DEP) ++-include $(DTBDEP) ++-include $(DTSDEP) + + endef + +diff --git a/make_helpers/defaults.mk b/make_helpers/defaults.mk +index 7df4cd2..0ade4e7 100644 +--- a/make_helpers/defaults.mk ++++ b/make_helpers/defaults.mk +@@ -79,6 +79,9 @@ ENABLE_STACK_PROTECTOR := 0 + # Flag to enable exception handling in EL3 + EL3_EXCEPTION_HANDLING := 0 + ++# Flag to enable exception debug for AARCH32 ++AARCH32_EXCEPTION_DEBUG := 0 ++ + # Build flag to treat usage of deprecated platform and framework APIs as error. + ERROR_DEPRECATED := 0 + +diff --git a/plat/arm/common/aarch32/arm_helpers.S b/plat/arm/common/aarch32/arm_helpers.S +index c4cfa8a..badddd3 100644 +--- a/plat/arm/common/aarch32/arm_helpers.S ++++ b/plat/arm/common/aarch32/arm_helpers.S +@@ -48,7 +48,7 @@ func plat_crash_console_init + ldr r0, =PLAT_ARM_CRASH_UART_BASE + ldr r1, =PLAT_ARM_CRASH_UART_CLK_IN_HZ + ldr r2, =ARM_CONSOLE_BAUDRATE +- b console_core_init ++ b console_pl011_core_init + endfunc plat_crash_console_init + + /* --------------------------------------------- +@@ -60,7 +60,7 @@ endfunc plat_crash_console_init + */ + func plat_crash_console_putc + ldr r1, =PLAT_ARM_CRASH_UART_BASE +- b console_core_putc ++ b console_pl011_core_putc + endfunc plat_crash_console_putc + + /* --------------------------------------------- +@@ -73,5 +73,5 @@ endfunc plat_crash_console_putc + */ + func plat_crash_console_flush + ldr r0, =PLAT_ARM_CRASH_UART_BASE +- b console_core_flush ++ b console_pl011_core_flush + endfunc plat_crash_console_flush +diff --git a/plat/arm/common/arm_common.mk b/plat/arm/common/arm_common.mk +index a8df5ba..9d31f08 100644 +--- a/plat/arm/common/arm_common.mk ++++ b/plat/arm/common/arm_common.mk +@@ -123,9 +123,7 @@ ENABLE_PMF := 1 + SEPARATE_CODE_AND_RODATA := 1 + + # Use the multi console API, which is only available for AArch64 for now +-ifeq (${ARCH}, aarch64) +- MULTI_CONSOLE_API := 1 +-endif ++MULTI_CONSOLE_API := 1 + + # Disable ARM Cryptocell by default + ARM_CRYPTOCELL_INTEG := 0 +diff --git a/plat/arm/common/sp_min/arm_sp_min_setup.c b/plat/arm/common/sp_min/arm_sp_min_setup.c +index 10c1914..b8234c1 100644 +--- a/plat/arm/common/sp_min/arm_sp_min_setup.c ++++ b/plat/arm/common/sp_min/arm_sp_min_setup.c +@@ -9,6 +9,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -61,8 +62,7 @@ void arm_sp_min_early_platform_setup(void *from_bl2, uintptr_t tos_fw_config, + uintptr_t hw_config, void *plat_params_from_bl2) + { + /* Initialize the console to provide early debug support */ +- console_init(PLAT_ARM_BOOT_UART_BASE, PLAT_ARM_BOOT_UART_CLK_IN_HZ, +- ARM_CONSOLE_BAUDRATE); ++ arm_console_boot_init(); + + #if RESET_TO_SP_MIN + /* There are no parameters from BL2 if SP_MIN is a reset vector */ +@@ -152,8 +152,7 @@ void sp_min_early_platform_setup2(u_register_t arg0, u_register_t arg1, + void arm_sp_min_plat_runtime_setup(void) + { + /* Initialize the runtime console */ +- console_init(PLAT_ARM_SP_MIN_RUN_UART_BASE, +- PLAT_ARM_SP_MIN_RUN_UART_CLK_IN_HZ, ARM_CONSOLE_BAUDRATE); ++ arm_console_runtime_init(); + } + + /******************************************************************************* +diff --git a/plat/common/aarch32/crash_console_helpers.S b/plat/common/aarch32/crash_console_helpers.S +new file mode 100644 +index 0000000..fc37c08 +--- /dev/null ++++ b/plat/common/aarch32/crash_console_helpers.S +@@ -0,0 +1,92 @@ ++/* ++ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. ++ * ++ * SPDX-License-Identifier: BSD-3-Clause ++ */ ++ ++/* ++ * If a platform wishes to use the functions in this file it has to be added to ++ * the Makefile of the platform. It is not included in the common Makefile. ++ */ ++ ++#include ++#include ++ ++ .globl plat_crash_console_init ++ .globl plat_crash_console_putc ++ .globl plat_crash_console_flush ++ ++#if MULTI_CONSOLE_API ++ ++ /* ----------------------------------------------------- ++ * int plat_crash_console_init(void) ++ * Use normal console by default. Switch it to crash ++ * mode so serial consoles become active again. ++ * NOTE: This default implementation will only work for ++ * crashes that occur after a normal console (marked ++ * valid for the crash state) has been registered with ++ * the console framework. To debug crashes that occur ++ * earlier, the platform has to override these functions ++ * with an implementation that initializes a console ++ * driver with hardcoded parameters. See ++ * docs/porting-guide.rst for more information. ++ * ----------------------------------------------------- ++ */ ++func plat_crash_console_init ++#if defined(IMAGE_BL1) ++ /* ++ * BL1 code can possibly crash so early that the data segment is not yet ++ * accessible. Don't risk undefined behavior by trying to run the normal ++ * console framework. Platforms that want to debug BL1 will need to ++ * override this with custom functions that can run from registers only. ++ */ ++ mov r0, #0 ++ bx lr ++#else /* IMAGE_BL1 */ ++ mov r3, lr ++ mov r0, #CONSOLE_FLAG_CRASH ++ bl console_switch_state ++ mov r0, #1 ++ bx r3 ++#endif ++endfunc plat_crash_console_init ++ ++ /* ----------------------------------------------------- ++ * void plat_crash_console_putc(int character) ++ * Output through the normal console by default. ++ * ----------------------------------------------------- ++ */ ++func plat_crash_console_putc ++ b console_putc ++endfunc plat_crash_console_putc ++ ++ /* ----------------------------------------------------- ++ * void plat_crash_console_flush(void) ++ * Flush normal console by default. ++ * ----------------------------------------------------- ++ */ ++func plat_crash_console_flush ++ b console_flush ++endfunc plat_crash_console_flush ++ ++#else /* MULTI_CONSOLE_API */ ++ ++ /* ----------------------------------------------------- ++ * In the old API these are all no-op stubs that need to ++ * be overridden by the platform to be useful. ++ * ----------------------------------------------------- ++ */ ++func plat_crash_console_init ++ mov r0, #0 ++ bx lr ++endfunc plat_crash_console_init ++ ++func plat_crash_console_putc ++ bx lr ++endfunc plat_crash_console_putc ++ ++func plat_crash_console_flush ++ bx lr ++endfunc plat_crash_console_flush ++ ++#endif +diff --git a/plat/common/aarch32/plat_sp_min_common.c b/plat/common/aarch32/plat_sp_min_common.c +index a9a92c7..f1b1e9c 100644 +--- a/plat/common/aarch32/plat_sp_min_common.c ++++ b/plat/common/aarch32/plat_sp_min_common.c +@@ -21,5 +21,9 @@ void sp_min_plat_runtime_setup(void) + * Finish the use of console driver in SP_MIN so that any runtime logs + * from SP_MIN will be suppressed. + */ ++#if MULTI_CONSOLE_API ++ console_switch_state(CONSOLE_FLAG_RUNTIME); ++#else + console_uninit(); ++#endif + } +diff --git a/plat/common/aarch32/platform_helpers.S b/plat/common/aarch32/platform_helpers.S +index d618539..91ddc47 100644 +--- a/plat/common/aarch32/platform_helpers.S ++++ b/plat/common/aarch32/platform_helpers.S +@@ -8,9 +8,16 @@ + #include + + .weak plat_report_exception ++#if AARCH32_EXCEPTION_DEBUG ++ .weak plat_report_undef_inst ++ .weak plat_report_prefetch_abort ++ .weak plat_report_data_abort ++#endif ++#if !ERROR_DEPRECATED + .weak plat_crash_console_init + .weak plat_crash_console_putc + .weak plat_crash_console_flush ++#endif + .weak plat_reset_handler + .weak plat_disable_acp + .weak bl1_plat_prepare_exit +@@ -26,6 +33,36 @@ func plat_report_exception + bx lr + endfunc plat_report_exception + ++#if AARCH32_EXCEPTION_DEBUG ++ /* ----------------------------------------------------- ++ * Placeholder function which should be redefined by ++ * each platform. ++ * ----------------------------------------------------- ++ */ ++func plat_report_undef_inst ++ bx lr ++endfunc plat_report_undef_inst ++ ++ /* ----------------------------------------------------- ++ * Placeholder function which should be redefined by ++ * each platform. ++ * ----------------------------------------------------- ++ */ ++func plat_report_prefetch_abort ++ bx lr ++endfunc plat_report_prefetch_abort ++ ++ /* ----------------------------------------------------- ++ * Placeholder function which should be redefined by ++ * each platform. ++ * ----------------------------------------------------- ++ */ ++func plat_report_data_abort ++ bx lr ++endfunc plat_report_data_abort ++#endif ++ ++#if !ERROR_DEPRECATED + /* ----------------------------------------------------- + * Placeholder function which should be redefined by + * each platform. +@@ -54,6 +91,7 @@ func plat_crash_console_flush + mov r0, #0 + bx lr + endfunc plat_crash_console_flush ++#endif + + /* ----------------------------------------------------- + * Placeholder function which should be redefined by +diff --git a/plat/common/aarch64/crash_console_helpers.S b/plat/common/aarch64/crash_console_helpers.S +new file mode 100644 +index 0000000..5af8db2 +--- /dev/null ++++ b/plat/common/aarch64/crash_console_helpers.S +@@ -0,0 +1,92 @@ ++/* ++ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. ++ * ++ * SPDX-License-Identifier: BSD-3-Clause ++ */ ++ ++/* ++ * If a platform wishes to use the functions in this file it has to be added to ++ * the Makefile of the platform. It is not included in the common Makefile. ++ */ ++ ++#include ++#include ++ ++ .globl plat_crash_console_init ++ .globl plat_crash_console_putc ++ .globl plat_crash_console_flush ++ ++#if MULTI_CONSOLE_API ++ ++ /* ----------------------------------------------------- ++ * int plat_crash_console_init(void) ++ * Use normal console by default. Switch it to crash ++ * mode so serial consoles become active again. ++ * NOTE: This default implementation will only work for ++ * crashes that occur after a normal console (marked ++ * valid for the crash state) has been registered with ++ * the console framework. To debug crashes that occur ++ * earlier, the platform has to override these functions ++ * with an implementation that initializes a console ++ * driver with hardcoded parameters. See ++ * docs/porting-guide.rst for more information. ++ * ----------------------------------------------------- ++ */ ++func plat_crash_console_init ++#if defined(IMAGE_BL1) ++ /* ++ * BL1 code can possibly crash so early that the data segment is not yet ++ * accessible. Don't risk undefined behavior by trying to run the normal ++ * console framework. Platforms that want to debug BL1 will need to ++ * override this with custom functions that can run from registers only. ++ */ ++ mov x0, #0 ++ ret ++#else /* IMAGE_BL1 */ ++ mov x3, x30 ++ mov x0, #CONSOLE_FLAG_CRASH ++ bl console_switch_state ++ mov x0, #1 ++ ret x3 ++#endif ++endfunc plat_crash_console_init ++ ++ /* ----------------------------------------------------- ++ * void plat_crash_console_putc(int character) ++ * Output through the normal console by default. ++ * ----------------------------------------------------- ++ */ ++func plat_crash_console_putc ++ b console_putc ++endfunc plat_crash_console_putc ++ ++ /* ----------------------------------------------------- ++ * void plat_crash_console_flush(void) ++ * Flush normal console by default. ++ * ----------------------------------------------------- ++ */ ++func plat_crash_console_flush ++ b console_flush ++endfunc plat_crash_console_flush ++ ++#else /* MULTI_CONSOLE_API */ ++ ++ /* ----------------------------------------------------- ++ * In the old API these are all no-op stubs that need to ++ * be overridden by the platform to be useful. ++ * ----------------------------------------------------- ++ */ ++func plat_crash_console_init ++ mov x0, #0 ++ ret ++endfunc plat_crash_console_init ++ ++func plat_crash_console_putc ++ ret ++endfunc plat_crash_console_putc ++ ++func plat_crash_console_flush ++ ret ++endfunc plat_crash_console_flush ++ ++#endif +diff --git a/plat/common/aarch64/platform_helpers.S b/plat/common/aarch64/platform_helpers.S +index 7214588..d3ffcaf 100644 +--- a/plat/common/aarch64/platform_helpers.S ++++ b/plat/common/aarch64/platform_helpers.S +@@ -10,9 +10,11 @@ + #include + + .weak plat_report_exception ++#if !ERROR_DEPRECATED + .weak plat_crash_console_init + .weak plat_crash_console_putc + .weak plat_crash_console_flush ++#endif + .weak plat_reset_handler + .weak plat_disable_acp + .weak bl1_plat_prepare_exit +@@ -37,6 +39,7 @@ func plat_report_exception + ret + endfunc plat_report_exception + ++#if !ERROR_DEPRECATED + #if MULTI_CONSOLE_API + /* ----------------------------------------------------- + * int plat_crash_console_init(void) +@@ -109,6 +112,7 @@ func plat_crash_console_flush + ret + endfunc plat_crash_console_flush + #endif ++#endif /* ERROR_DEPRECATED */ + + /* ----------------------------------------------------- + * Placeholder function which should be redefined by +diff --git a/plat/common/plat_log_common.c b/plat/common/plat_log_common.c +index 49e1c15..c757c6b 100644 +--- a/plat/common/plat_log_common.c ++++ b/plat/common/plat_log_common.c +@@ -5,6 +5,7 @@ + */ + + #include ++#include + + /* Allow platforms to override the log prefix string */ + #pragma weak plat_log_get_prefix +diff --git a/plat/imx/common/lpuart_console.S b/plat/imx/common/lpuart_console.S +index ad71b89..668fd62 100644 +--- a/plat/imx/common/lpuart_console.S ++++ b/plat/imx/common/lpuart_console.S +@@ -6,6 +6,7 @@ + + #include + #include ++#define USE_FINISH_CONSOLE_REG_2 + #include + #include + #include "imx8_lpuart.h" +@@ -26,7 +27,7 @@ func console_lpuart_register + + mov x0, x6 + mov x30, x7 +- finish_console_register lpuart ++ finish_console_register lpuart putc=1, getc=1 + + register_fail: + ret x7 +diff --git a/plat/layerscape/common/aarch64/ls_console.S b/plat/layerscape/common/aarch64/ls_console.S +index 5c87465..ec4390a 100644 +--- a/plat/layerscape/common/aarch64/ls_console.S ++++ b/plat/layerscape/common/aarch64/ls_console.S +@@ -6,6 +6,7 @@ + + #include + #include ++#define USE_FINISH_CONSOLE_REG_2 + #include + #include + #include "ls_16550.h" +@@ -106,7 +107,7 @@ func console_ls_16550_register + + mov x0, x6 + mov x30, x7 +- finish_console_register ls_16550 ++ finish_console_register ls_16550 putc=1, getc=1, flush=1 + + register_fail: + ret x7 +diff --git a/plat/st/common/bl2_io_storage.c b/plat/st/common/bl2_io_storage.c +new file mode 100644 +index 0000000..263c3ba +--- /dev/null ++++ b/plat/st/common/bl2_io_storage.c +@@ -0,0 +1,773 @@ ++/* ++ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. ++ * ++ * SPDX-License-Identifier: BSD-3-Clause ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#if STM32MP_FMC_NAND ++#include ++#endif ++#include ++#if STM32MP1_QSPI_NOR ++#include ++#endif ++#include ++#include ++#if STM32MP_UART_PROGRAMMER ++#include ++#endif ++#include ++#include ++#if STM32MP_FMC_NAND ++#include ++#endif ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#ifdef STM32MP_USB ++#include ++#include ++#include ++#include ++#endif ++#include ++ ++/* IO devices */ ++static const io_dev_connector_t *dummy_dev_con; ++static uintptr_t dummy_dev_handle; ++static uintptr_t dummy_dev_spec; ++ ++static uintptr_t image_dev_handle; ++ ++#if STM32MP_SDMMC || STM32MP_EMMC ++static io_block_spec_t gpt_block_spec = { ++ .offset = 0, ++ .length = 34 * MMC_BLOCK_SIZE, /* Size of GPT table */ ++}; ++ ++static uint32_t block_buffer[MMC_BLOCK_SIZE] __aligned(MMC_BLOCK_SIZE); ++ ++static const io_block_dev_spec_t mmc_block_dev_spec = { ++ /* It's used as temp buffer in block driver */ ++ .buffer = { ++ .offset = (size_t)&block_buffer, ++ .length = MMC_BLOCK_SIZE, ++ }, ++ .ops = { ++ .read = mmc_read_blocks, ++ .write = NULL, ++ }, ++ .block_size = MMC_BLOCK_SIZE, ++}; ++#endif ++ ++static uintptr_t storage_dev_handle; ++#if STM32MP_SDMMC || STM32MP_EMMC ++static const io_dev_connector_t *mmc_dev_con; ++#endif ++ ++#if STM32MP1_QSPI_NOR ++static const io_dev_connector_t *qspi_dev_con; ++ ++static QSPI_HandleTypeDef qspi_dev_spec = { ++ .instance = (QUADSPI_TypeDef *)STM32MP1_QSPI1_BASE, ++ .is_dual = 0, ++}; ++#endif ++ ++#if STM32MP_UART_PROGRAMMER ++/* uart*/ ++static const io_dev_connector_t *uart_dev_con; ++ ++static UART_HandleTypeDef uart_programmer = { ++ .Init.BaudRate = STM32MP_UART_BAUDRATE, ++ .Init.StopBits = UART_STOPBITS_1, ++ .Init.HwFlowCtl = UART_HWCONTROL_NONE, ++ .Init.Mode = UART_MODE_TX_RX, ++ .Init.OverSampling = UART_OVERSAMPLING_16, ++ .Init.FIFOMode = UART_FIFOMODE_ENABLE, ++ .AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_AUTOBAUDRATE_INIT, ++ .AdvancedInit.AutoBaudRateEnable = UART_ADVFEATURE_AUTOBAUDRATE_DISABLE, ++}; ++#endif /* STM32MP_UART_PROGRAMMER */ ++ ++#ifdef STM32MP_USB ++static usb_handle_t usb_core_handle; ++static usb_dfu_handle_t usb_dfu_handle; ++static pcd_handle_t pcd_handle; ++static const io_dev_connector_t *usb_dev_con; ++#endif /*STM32MP_USB*/ ++ ++#if STM32MP_FMC_NAND ++/* nand */ ++static const io_dev_connector_t *nand_dev_con; ++static NAND_HandleTypeDef nand_dev_spec; ++#endif ++ ++#ifdef AARCH32_SP_OPTEE ++static const struct stm32image_part_info optee_header_partition_spec = { ++ .name = OPTEE_HEADER_IMAGE_NAME, ++ .binary_type = OPTEE_HEADER_BINARY_TYPE, ++}; ++ ++static const struct stm32image_part_info optee_pager_partition_spec = { ++ .name = OPTEE_PAGER_IMAGE_NAME, ++ .binary_type = OPTEE_PAGER_BINARY_TYPE, ++}; ++ ++static const struct stm32image_part_info optee_paged_partition_spec = { ++ .name = OPTEE_PAGED_IMAGE_NAME, ++ .binary_type = OPTEE_PAGED_BINARY_TYPE, ++}; ++#else ++static const io_block_spec_t bl32_block_spec = { ++ .offset = BL32_BASE, ++ .length = STM32MP_BL32_SIZE ++}; ++#endif ++ ++static const io_block_spec_t bl2_block_spec = { ++ .offset = BL2_BASE, ++ .length = STM32MP_BL2_SIZE, ++}; ++ ++static const struct stm32image_part_info bl33_partition_spec = { ++ .name = BL33_IMAGE_NAME, ++ .binary_type = BL33_BINARY_TYPE, ++}; ++ ++enum { ++ IMG_IDX_BL33, ++#ifdef AARCH32_SP_OPTEE ++ IMG_IDX_OPTEE_HEADER, ++ IMG_IDX_OPTEE_PAGER, ++ IMG_IDX_OPTEE_PAGED, ++#endif ++ IMG_IDX_NUM ++}; ++ ++static struct stm32image_device_info stm32image_dev_info_spec = { ++ .lba_size = MMC_BLOCK_SIZE, ++ .part_info[IMG_IDX_BL33] = { ++ .name = BL33_IMAGE_NAME, ++ .binary_type = BL33_BINARY_TYPE, ++ }, ++#ifdef AARCH32_SP_OPTEE ++ .part_info[IMG_IDX_OPTEE_HEADER] = { ++ .name = OPTEE_HEADER_IMAGE_NAME, ++ .binary_type = OPTEE_HEADER_BINARY_TYPE, ++ }, ++ .part_info[IMG_IDX_OPTEE_PAGER] = { ++ .name = OPTEE_PAGER_IMAGE_NAME, ++ .binary_type = OPTEE_PAGER_BINARY_TYPE, ++ }, ++ .part_info[IMG_IDX_OPTEE_PAGED] = { ++ .name = OPTEE_PAGED_IMAGE_NAME, ++ .binary_type = OPTEE_PAGED_BINARY_TYPE, ++ }, ++#endif ++}; ++ ++static io_block_spec_t stm32image_block_spec = { ++ .offset = 0, ++ .length = 0, ++}; ++ ++static const io_dev_connector_t *stm32image_dev_con; ++ ++static int open_dummy(const uintptr_t spec); ++static int open_image(const uintptr_t spec); ++static int open_storage(const uintptr_t spec); ++ ++struct plat_io_policy { ++ uintptr_t *dev_handle; ++ uintptr_t image_spec; ++ int (*check)(const uintptr_t spec); ++}; ++ ++static const struct plat_io_policy policies[] = { ++ [BL2_IMAGE_ID] = { ++ .dev_handle = &dummy_dev_handle, ++ .image_spec = (uintptr_t)&bl2_block_spec, ++ .check = open_dummy ++ }, ++#ifdef AARCH32_SP_OPTEE ++ [BL32_IMAGE_ID] = { ++ .dev_handle = &image_dev_handle, ++ .image_spec = (uintptr_t)&optee_header_partition_spec, ++ .check = open_image ++ }, ++ [BL32_EXTRA1_IMAGE_ID] = { ++ .dev_handle = &image_dev_handle, ++ .image_spec = (uintptr_t)&optee_pager_partition_spec, ++ .check = open_image ++ }, ++ [BL32_EXTRA2_IMAGE_ID] = { ++ .dev_handle = &image_dev_handle, ++ .image_spec = (uintptr_t)&optee_paged_partition_spec, ++ .check = open_image ++ }, ++#else ++ [BL32_IMAGE_ID] = { ++ .dev_handle = &dummy_dev_handle, ++ .image_spec = (uintptr_t)&bl32_block_spec, ++ .check = open_dummy ++ }, ++#endif ++ [BL33_IMAGE_ID] = { ++ .dev_handle = &image_dev_handle, ++ .image_spec = (uintptr_t)&bl33_partition_spec, ++ .check = open_image ++ }, ++#if STM32MP_SDMMC || STM32MP_EMMC ++ [GPT_IMAGE_ID] = { ++ .dev_handle = &storage_dev_handle, ++ .image_spec = (uintptr_t)&gpt_block_spec, ++ .check = open_storage ++ }, ++#endif ++ [STM32_IMAGE_ID] = { ++ .dev_handle = &storage_dev_handle, ++ .image_spec = (uintptr_t)&stm32image_block_spec, ++ .check = open_storage ++ } ++}; ++ ++static int open_dummy(const uintptr_t spec) ++{ ++ return io_dev_init(dummy_dev_handle, 0); ++} ++ ++static int open_image(const uintptr_t spec) ++{ ++ return io_dev_init(image_dev_handle, 0); ++} ++ ++static int open_storage(const uintptr_t spec) ++{ ++ return io_dev_init(storage_dev_handle, 0); ++} ++ ++static void print_boot_device(boot_api_context_t *boot_context) ++{ ++ switch (boot_context->boot_interface_selected) { ++ case BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_SD: ++ INFO("Using SDMMC\n"); ++ break; ++ case BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_EMMC: ++ INFO("Using EMMC\n"); ++ break; ++#if STM32MP_UART_PROGRAMMER ++ case BOOT_API_CTX_BOOT_INTERFACE_SEL_SERIAL_UART: ++ INFO("Using UART\n"); ++ break; ++#endif ++ case BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_NOR_QSPI: ++ INFO("Using NOR\n"); ++ if (boot_context->nor_isdual != 0U) { ++ INFO("NOR is configured in Dual Flash Mode\n"); ++ } ++ break; ++ case BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_NAND_FMC: ++ INFO("Using NAND\n"); ++ break; ++#ifdef STM32MP_USB ++ case BOOT_API_CTX_BOOT_INTERFACE_SEL_SERIAL_USB: ++ INFO("Using USB\n"); ++ break; ++#endif ++#ifdef STM32MP1_QSPI_NAND ++ case BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_NAND_QSPI: ++ INFO("Using QSPI NAND\n"); ++ break; ++#endif ++ default: ++ ERROR("Boot interface not found\n"); ++ panic(); ++ break; ++ } ++ ++ if (boot_context->boot_interface_instance != 0U) { ++ INFO(" Instance %d\n", boot_context->boot_interface_instance); ++ } ++} ++ ++#if STM32MP_EMMC || STM32MP_SDMMC ++static void print_bootrom_sd_status(boot_api_context_t *boot_context) ++{ ++ if (boot_context->sd_err_internal_timeout_cnt != 0U) { ++ WARN("BootROM: %d timeout issues\n", ++ boot_context->sd_err_internal_timeout_cnt); ++ } ++ ++ if (boot_context->sd_err_dcrc_fail_cnt != 0U) { ++ WARN("BootROM: %d DCRCFAIL error\n", ++ boot_context->sd_err_dcrc_fail_cnt); ++ } ++ ++ if (boot_context->sd_err_dtimeout_cnt != 0U) { ++ WARN("BootROM: %d DTIMEOUT error\n", ++ boot_context->sd_err_dtimeout_cnt); ++ } ++ ++ if (boot_context->sd_err_ctimeout_cnt != 0U) { ++ WARN("BootROM: %d CTIMEOUT error\n", ++ boot_context->sd_err_ctimeout_cnt); ++ } ++ ++ if (boot_context->sd_err_ccrc_fail_cnt != 0U) { ++ WARN("BootROM: %d CCRCFAIL error count\n", ++ boot_context->sd_err_ccrc_fail_cnt); ++ } ++ ++ if (boot_context->sd_overall_retry_cnt != 0U) { ++ WARN("BootROM: %d command retries\n", ++ boot_context->sd_overall_retry_cnt); ++ } ++} ++ ++static void print_bootrom_emmc_status(boot_api_context_t *boot_context) ++{ ++ INFO("BootROM: %d (0x%x) bytes copied from eMMC\n", ++ boot_context->emmc_nbbytes_rxcopied_tosysram_download_area, ++ boot_context->emmc_nbbytes_rxcopied_tosysram_download_area); ++ ++ if (boot_context->emmc_error_status != ++ BOOT_API_CTX_EMMC_ERROR_STATUS_NONE) { ++ WARN("BootROM eMMC error:\n"); ++ switch (boot_context->emmc_error_status) { ++ case BOOT_API_CTX_EMMC_ERROR_STATUS_CMD_TIMEOUT: ++ WARN(" CMD timeout\n"); ++ break; ++ case BOOT_API_CTX_EMMC_ERROR_STATUS_ACK_TIMEOUT: ++ WARN(" ACK timeout\n"); ++ break; ++ case BOOT_API_CTX_EMMC_ERROR_STATUS_DATA_CRC_FAIL: ++ WARN(" DATA CRC failed\n"); ++ break; ++ case BOOT_API_CTX_EMMC_ERROR_STATUS_NOT_ENOUGH_BOOT_DATA_RX: ++ WARN(" Not enough data copied\n"); ++ break; ++ case BOOT_API_CTX_EMMC_ERROR_STATUS_HEADER_NOT_FOUND: ++ WARN(" Header not found\n"); ++ break; ++ case BOOT_API_CTX_EMMC_ERROR_STATUS_HEADER_SIZE_ZERO: ++ WARN(" Header size is zero\n"); ++ break; ++ case BOOT_API_CTX_EMMC_ERROR_STATUS_IMAGE_NOT_COMPLETE: ++ WARN(" Image not complete\n"); ++ break; ++ default: ++ WARN(" Error not listed\n"); ++ break; ++ } ++ } ++ ++ switch (boot_context->emmc_xfer_status) { ++ case BOOT_API_CTX_EMMC_XFER_STATUS_NOT_STARTED: ++ WARN("BootROM: eMMC transfer status:\n"); ++ WARN(" not started\n"); ++ break; ++ case BOOT_API_CTX_EMMC_XFER_STATUS_DATAEND_DETECTED: ++ break; ++ case BOOT_API_CTX_EMMC_XFER_STATUS_XFER_OVERALL_TIMEOUT_DETECTED: ++ WARN("BootROM: eMMC transfer status:\n"); ++ WARN(" timeout detected\n"); ++ break; ++ case BOOT_API_CTX_EMMC_XFER_STATUS_XFER_DATA_TIMEOUT: ++ WARN("BootROM: eMMC transfer status:\n"); ++ WARN(" data timeout detected\n"); ++ break; ++ default: ++ WARN("BootROM: eMMC transfer status:\n"); ++ WARN(" status not listed\n"); ++ break; ++ } ++} ++#endif ++ ++ ++void stm32mp_io_setup(void) ++{ ++ int io_result __unused; ++ uint8_t idx; ++ struct stm32image_part_info *part; ++#if STM32MP_UART_PROGRAMMER ++ uintptr_t uart_addr; ++#endif ++#if STM32MP_SDMMC || STM32MP_EMMC ++ struct stm32_sdmmc2_params params; ++ struct mmc_device_info device_info; ++ uintptr_t mmc_default_instance; ++ const partition_entry_t *entry; ++#endif ++#ifdef STM32MP_USB ++ struct usb_ctx *usb_context; ++#endif ++ boot_api_context_t *boot_context = ++ (boot_api_context_t *)stm32mp_get_boot_ctx_address(); ++ ++ print_boot_device(boot_context); ++ ++ if ((boot_context->boot_partition_used_toboot == 1U) || ++ (boot_context->boot_partition_used_toboot == 2U)) { ++ INFO("Boot used partition fsbl%d\n", ++ boot_context->boot_partition_used_toboot); ++ } ++ ++ io_result = register_io_dev_dummy(&dummy_dev_con); ++ assert(io_result == 0); ++ ++ io_result = io_dev_open(dummy_dev_con, dummy_dev_spec, ++ &dummy_dev_handle); ++ assert(io_result == 0); ++ ++ switch (boot_context->boot_interface_selected) { ++ case BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_SD: ++ case BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_EMMC: ++ dmbsy(); ++ ++#if STM32MP_EMMC || STM32MP_SDMMC ++ memset(¶ms, 0, sizeof(struct stm32_sdmmc2_params)); ++ ++ if (boot_context->boot_interface_selected == ++ BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_EMMC) { ++ device_info.mmc_dev_type = MMC_IS_EMMC; ++ print_bootrom_emmc_status(boot_context); ++#if STM32MP_EMMC ++ mmc_default_instance = STM32MP_SDMMC2_BASE; ++#else ++ ERROR("MMC driver is not enabled\n"); ++ panic(); ++#endif ++ } else { ++ device_info.mmc_dev_type = MMC_IS_SD; ++ print_bootrom_sd_status(boot_context); ++#if STM32MP_SDMMC ++ mmc_default_instance = STM32MP_SDMMC1_BASE; ++#else ++ ERROR("MMC driver is not enabled\n"); ++ panic(); ++#endif ++ } ++ ++ switch (boot_context->boot_interface_instance) { ++ case 1: ++ params.reg_base = STM32MP_SDMMC1_BASE; ++ break; ++ case 2: ++ params.reg_base = STM32MP_SDMMC2_BASE; ++ break; ++ case 3: ++ params.reg_base = STM32MP_SDMMC3_BASE; ++ break; ++ default: ++ WARN("SDMMC instance not found, using default\n"); ++ params.reg_base = mmc_default_instance; ++ break; ++ } ++ ++ params.device_info = &device_info; ++ if (stm32_sdmmc2_mmc_init(¶ms) != 0) { ++ ERROR("SDMMC%u init failed\n", ++ boot_context->boot_interface_instance); ++ panic(); ++ } ++ ++ /* Open MMC as a block device to read GPT table */ ++ io_result = register_io_dev_block(&mmc_dev_con); ++ if (io_result != 0) { ++ panic(); ++ } ++ ++ io_result = io_dev_open(mmc_dev_con, ++ (uintptr_t)&mmc_block_dev_spec, ++ &storage_dev_handle); ++ assert(io_result == 0); ++ ++ partition_init(GPT_IMAGE_ID); ++ ++ io_result = io_dev_close(storage_dev_handle); ++ assert(io_result == 0); ++ ++ stm32image_dev_info_spec.device_size = ++ stm32_sdmmc2_mmc_get_device_size(); ++ ++ for (idx = 0U; idx < IMG_IDX_NUM; idx++) { ++ part = &stm32image_dev_info_spec.part_info[idx]; ++ entry = get_partition_entry(part->name); ++ if (entry == NULL) { ++ ERROR("Partition %s not found\n", ++ part->name); ++ panic(); ++ } ++ ++ part->part_offset = entry->start; ++ part->bkp_offset = 0U; ++ } ++ ++ /* ++ * Re-open MMC with io_mmc, for better perfs compared to ++ * io_block. ++ */ ++ io_result = register_io_dev_mmc(&mmc_dev_con); ++ assert(io_result == 0); ++ ++ io_result = io_dev_open(mmc_dev_con, 0, &storage_dev_handle); ++ assert(io_result == 0); ++ ++ io_result = register_io_dev_stm32image(&stm32image_dev_con); ++ assert(io_result == 0); ++ ++ io_result = io_dev_open(stm32image_dev_con, ++ (uintptr_t)&stm32image_dev_info_spec, ++ &image_dev_handle); ++ assert(io_result == 0); ++#else /* STM32MP_EMMC || STM32MP_SDMMC */ ++ ERROR("EMMC or SDMMC driver not enabled\n"); ++ panic(); ++#endif /* STM32MP_EMMC || STM32MP_SDMMC */ ++ break; ++ ++#if STM32MP1_QSPI_NOR ++ case BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_NOR_QSPI: ++ dmbsy(); ++ ++ io_result = register_io_dev_qspi(&qspi_dev_con); ++ ++ assert(io_result == 0); ++ switch (boot_context->boot_interface_instance) { ++ case 1: ++ qspi_dev_spec.instance = ++ (QUADSPI_TypeDef *)STM32MP1_QSPI1_BASE; ++ break; ++ default: ++ WARN("NOR instance not found, using default\n"); ++ qspi_dev_spec.instance = ++ (QUADSPI_TypeDef *)STM32MP1_QSPI1_BASE; ++ break; ++ } ++ qspi_dev_spec.is_dual = boot_context->nor_isdual; ++ ++ /* Open connections to devices and cache the handles */ ++ io_result = io_dev_open(qspi_dev_con, ++ (uintptr_t)&qspi_dev_spec, ++ &storage_dev_handle); ++ assert(io_result == 0); ++ ++ stm32image_dev_info_spec.device_size = QSPI_NOR_MAX_SIZE; ++ stm32image_dev_info_spec.lba_size = QSPI_NOR_LBA_SIZE; ++ ++ idx = IMG_IDX_BL33; ++ part = &stm32image_dev_info_spec.part_info[idx]; ++ part->part_offset = STM32MP_NOR_BL33_OFFSET; ++ part->bkp_offset = QSPI_NOR_BLK_SIZE; ++ ++#ifdef AARCH32_SP_OPTEE ++ idx = IMG_IDX_OPTEE_HEADER; ++ part = &stm32image_dev_info_spec.part_info[idx]; ++ part->part_offset = STM32MP_NOR_TEEH_OFFSET; ++ part->bkp_offset = QSPI_NOR_BLK_SIZE; ++ ++ idx = IMG_IDX_OPTEE_PAGED; ++ part = &stm32image_dev_info_spec.part_info[idx]; ++ part->part_offset = STM32MP_NOR_TEED_OFFSET; ++ part->bkp_offset = QSPI_NOR_BLK_SIZE; ++ ++ idx = IMG_IDX_OPTEE_PAGER; ++ part = &stm32image_dev_info_spec.part_info[idx]; ++ part->part_offset = STM32MP_NOR_TEEX_OFFSET; ++ part->bkp_offset = QSPI_NOR_BLK_SIZE; ++#endif ++ ++ io_result = register_io_dev_stm32image(&stm32image_dev_con); ++ assert(io_result == 0); ++ ++ io_result = io_dev_open(stm32image_dev_con, ++ (uintptr_t)&stm32image_dev_info_spec, ++ &image_dev_handle); ++ assert(io_result == 0); ++ break; ++#endif ++ ++ case BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_NAND_FMC: ++ ++#if STM32MP_FMC_NAND ++ dmbsy(); ++ ++ /* Register the IO devices on this platform */ ++ io_result = register_io_dev_nand(&nand_dev_con); ++ assert(io_result == 0); ++ ++ nand_dev_spec.Instance = (FMC_TypeDef *)STM32MP_FMC_BASE; ++ nand_dev_spec.Info.PageSize = boot_context->nand_page_size; ++ nand_dev_spec.Info.BlockSize = boot_context->nand_block_size; ++ nand_dev_spec.Info.BlockNb = boot_context->nand_block_nb; ++ nand_dev_spec.Info.BusWidth = boot_context->nand_data_width; ++ nand_dev_spec.Info.ECCcorrectability = ++ boot_context->nand_ecc_bits; ++ ++ /* Open connections to devices and cache the handles */ ++ io_result = io_dev_open(nand_dev_con, (uintptr_t)&nand_dev_spec, ++ &storage_dev_handle); ++ assert(io_result == 0); ++ ++ stm32image_dev_info_spec.device_size = ++ nand_dev_spec.Info.PageSize * ++ nand_dev_spec.Info.BlockSize * ++ nand_dev_spec.Info.BlockNb; ++ stm32image_dev_info_spec.lba_size = BCH_PAGE_SECTOR; ++ ++ idx = IMG_IDX_BL33; ++ part = &stm32image_dev_info_spec.part_info[idx]; ++ part->part_offset = STM32MP_NAND_BL33_OFFSET; ++ part->bkp_offset = nand_dev_spec.Info.PageSize * ++ nand_dev_spec.Info.BlockSize; ++ ++#ifdef AARCH32_SP_OPTEE ++ idx = IMG_IDX_OPTEE_HEADER; ++ part = &stm32image_dev_info_spec.part_info[idx]; ++ part->part_offset = STM32MP_NAND_TEEH_OFFSET; ++ part->bkp_offset = nand_dev_spec.Info.PageSize * ++ nand_dev_spec.Info.BlockSize; ++ ++ idx = IMG_IDX_OPTEE_PAGED; ++ part = &stm32image_dev_info_spec.part_info[idx]; ++ part->part_offset = STM32MP_NAND_TEED_OFFSET; ++ part->bkp_offset = nand_dev_spec.Info.PageSize * ++ nand_dev_spec.Info.BlockSize; ++ ++ idx = IMG_IDX_OPTEE_PAGER; ++ part = &stm32image_dev_info_spec.part_info[idx]; ++ part->part_offset = STM32MP_NAND_TEEX_OFFSET; ++ part->bkp_offset = nand_dev_spec.Info.PageSize * ++ nand_dev_spec.Info.BlockSize; ++#endif ++ ++ io_result = register_io_dev_stm32image(&stm32image_dev_con); ++ assert(io_result == 0); ++ ++ io_result = io_dev_open(stm32image_dev_con, ++ (uintptr_t)&stm32image_dev_info_spec, ++ &image_dev_handle); ++ assert(io_result == 0); ++#else ++ ERROR("FMC NAND driver is not enabled\n"); ++ panic(); ++#endif ++ break; ++ ++#if STM32MP_UART_PROGRAMMER ++ case BOOT_API_CTX_BOOT_INTERFACE_SEL_SERIAL_UART: ++ ++ /* Register the IO devices on this platform */ ++ io_result = register_io_dev_uart(&uart_dev_con); ++ assert(io_result == 0); ++ ++ uart_programmer.Init.WordLength = UART_WORDLENGTH_9B; ++ uart_programmer.Init.Parity = UART_PARITY_EVEN; ++ uart_addr = ++ get_uart_address(boot_context->boot_interface_instance); ++ ++ if (uart_addr) { ++ uart_programmer.Instance = (USART_TypeDef *)uart_addr; ++ } else { ++ WARN("UART instance not found, using default\n"); ++ uart_programmer.Instance = (USART_TypeDef *)USART2_BASE; ++ } ++ ++ /* Open connections to devices and cache the handles */ ++ io_result = io_dev_open(uart_dev_con, ++ (uintptr_t)&uart_programmer, ++ &image_dev_handle); ++ assert(!io_result); ++ break; ++#endif ++ ++#ifdef STM32MP_USB ++ case BOOT_API_CTX_BOOT_INTERFACE_SEL_SERIAL_USB: ++ usb_context = (struct usb_ctx *)boot_context->usb_context; ++ ++ pcd_handle.in_ep[0].maxpacket = 0x40; ++ pcd_handle.out_ep[0].maxpacket = 0x40; ++ ++ pcd_handle.state = HAL_PCD_STATE_READY; ++ ++ usb_core_handle.data = &pcd_handle; ++ ++ usb_dwc2_init_driver(&usb_core_handle, ++ (uint32_t *)USB_OTG_BASE); ++ ++ usb_dfu_register_callback(&usb_core_handle); ++ ++ stm32mp_usb_init_desc(&usb_core_handle); ++ ++ usb_core_handle.ep_in[0].maxpacket = 0x40; ++ usb_core_handle.ep_out[0].maxpacket = 0x40; ++ ++ usb_core_handle.ep0_state = ++ usb_context->pusbd_device_ctx->ep0_state; ++ usb_core_handle.dev_state = USBD_STATE_CONFIGURED; ++ ++ usb_core_handle.class_data = &usb_dfu_handle; ++ usb_dfu_handle.dev_state = DFU_STATE_IDLE; ++ ++ /* Register the IO devices on this platform */ ++ io_result = register_io_dev_usb(&usb_dev_con); ++ assert(io_result == 0); ++ ++ /* Open connections to devices and cache the handles */ ++ io_result = io_dev_open(usb_dev_con, ++ (uintptr_t)&usb_core_handle, ++ &image_dev_handle); ++ ++ assert(io_result == 0); ++ break; ++#endif ++#ifdef STM32MP1_QSPI_NAND ++ case BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_NAND_QSPI: ++ ERROR("QSPI NAND not supported\n"); ++ break; ++#endif ++ ++ default: ++ ERROR("Boot interface %d not supported\n", ++ boot_context->boot_interface_selected); ++ break; ++ } ++} ++ ++/* ++ * Return an IO device handle and specification which can be used to access ++ * an image. Use this to enforce platform load policy. ++ */ ++int plat_get_image_source(unsigned int image_id, uintptr_t *dev_handle, ++ uintptr_t *image_spec) ++{ ++ int rc; ++ const struct plat_io_policy *policy; ++ ++ assert(image_id < ARRAY_SIZE(policies)); ++ ++ policy = &policies[image_id]; ++ rc = policy->check(policy->image_spec); ++ if (rc == 0) { ++ *image_spec = policy->image_spec; ++ *dev_handle = *(policy->dev_handle); ++ } ++ ++ return rc; ++} +diff --git a/plat/st/common/include/stm32mp_auth.h b/plat/st/common/include/stm32mp_auth.h +new file mode 100644 +index 0000000..70f8202 +--- /dev/null ++++ b/plat/st/common/include/stm32mp_auth.h +@@ -0,0 +1,15 @@ ++/* ++ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. ++ * ++ * SPDX-License-Identifier: BSD-3-Clause ++ */ ++ ++#ifndef STM32MP_AUTH_H ++#define STM32MP_AUTH_H ++ ++#include ++ ++int check_header(boot_api_image_header_t *header, uintptr_t buffer); ++int check_authentication(boot_api_image_header_t *header, uintptr_t buffer); ++ ++#endif /* STM32MP_AUTH_H */ +diff --git a/plat/st/common/include/stm32mp_common.h b/plat/st/common/include/stm32mp_common.h +new file mode 100644 +index 0000000..dc2568b6 +--- /dev/null ++++ b/plat/st/common/include/stm32mp_common.h +@@ -0,0 +1,49 @@ ++/* ++ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. ++ * ++ * SPDX-License-Identifier: BSD-3-Clause ++ */ ++ ++#ifndef STM32MP_COMMON_H ++#define STM32MP_COMMON_H ++ ++#include ++#include ++ ++void __dead2 stm32mp_plat_reset(int cpu); ++ ++void stm32mp_save_boot_ctx_address(uintptr_t address); ++uintptr_t stm32mp_get_boot_ctx_address(void); ++ ++int stm32mp_is_single_core(void); ++ ++uintptr_t stm32mp_ddrctrl_base(void); ++uintptr_t stm32mp_ddrphyc_base(void); ++uintptr_t stm32mp_pwr_base(void); ++uintptr_t stm32mp_rcc_base(void); ++ ++int stm32_gic_enable_spi(int node, const char *name); ++ ++uint32_t stm32_read_otp_status(uint32_t *otp_value, uint32_t word); ++uint8_t stm32_iwdg_get_instance(uintptr_t base); ++uint32_t stm32_iwdg_get_otp_config(uintptr_t base); ++ ++#if defined(IMAGE_BL2) ++uint32_t stm32_iwdg_shadow_update(uintptr_t base, uint32_t flags); ++#endif ++ ++uintptr_t stm32_get_gpio_bank_base(unsigned int bank); ++int stm32_get_gpio_bank_clock(unsigned int bank); ++uint32_t stm32_get_gpio_bank_offset(unsigned int bank); ++void stm32mp_print_cpuinfo(void); ++void stm32mp_print_boardinfo(void); ++ ++uint64_t s2tick(uint32_t timeout_s); ++uint64_t ms2tick(uint32_t timeout_ms); ++uint64_t us2tick(uint32_t timeout_us); ++uint64_t timeout_start(void); ++bool timeout_elapsed(uint64_t tick_start, uint64_t tick_to); ++ ++void stm32mp_io_setup(void); ++ ++#endif /* STM32MP1_COMMON_H */ +diff --git a/plat/st/common/include/stm32mp_dt.h b/plat/st/common/include/stm32mp_dt.h +new file mode 100644 +index 0000000..ee313d5 +--- /dev/null ++++ b/plat/st/common/include/stm32mp_dt.h +@@ -0,0 +1,54 @@ ++/* ++ * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved. ++ * ++ * SPDX-License-Identifier: BSD-3-Clause ++ */ ++ ++#ifndef STM32MP_DT_H ++#define STM32MP_DT_H ++ ++#include ++#include ++ ++#define DT_DISABLED U(0) ++#define DT_NON_SECURE U(1) ++#define DT_SECURE U(2) ++#define DT_SHARED (DT_NON_SECURE | DT_SECURE) ++ ++struct dt_node_info { ++ uint32_t base; ++ int32_t clock; ++ int32_t reset; ++ uint8_t status; ++}; ++ ++/******************************************************************************* ++ * Function and variable prototypes ++ ******************************************************************************/ ++int dt_open_and_check(void); ++int fdt_get_address(void **fdt_addr); ++bool fdt_check_node(int node); ++uint8_t fdt_get_status(int node); ++int fdt_get_interrupt(int node, const fdt32_t **array, int *len, ++ bool *extended); ++uint32_t fdt_read_uint32_default(int node, const char *prop_name, ++ uint32_t dflt_value); ++int fdt_read_uint32_array(int node, const char *prop_name, ++ uint32_t *array, uint32_t count); ++int fdt_get_reg_props_by_name(int node, const char *name, uintptr_t *base, ++ size_t *size); ++int dt_set_stdout_pinctrl(void); ++void dt_fill_device_info(struct dt_node_info *info, int node); ++int dt_get_node(struct dt_node_info *info, int offset, const char *compat); ++int dt_get_stdout_uart_info(struct dt_node_info *info); ++uint32_t dt_get_ddr_size(void); ++uintptr_t dt_get_ddrctrl_base(void); ++uintptr_t dt_get_ddrphyc_base(void); ++uintptr_t dt_get_pwr_base(void); ++uint32_t dt_get_pwr_vdd_voltage(void); ++uintptr_t dt_get_syscfg_base(void); ++const char *dt_get_board_model(void); ++int fdt_get_gpio_bank_pinctrl_node(unsigned int bank); ++int fdt_get_gpioz_nbpins_from_dt(void); ++ ++#endif /* STM32MP_DT_H */ +diff --git a/plat/st/common/include/stm32mp_shres_helpers.h b/plat/st/common/include/stm32mp_shres_helpers.h +new file mode 100644 +index 0000000..565b3d4 +--- /dev/null ++++ b/plat/st/common/include/stm32mp_shres_helpers.h +@@ -0,0 +1,86 @@ ++/* ++ * Copyright (C) 2018, STMicroelectronics - All Rights Reserved ++ * ++ * SPDX-License-Identifier: BSD-3-Clause ++ */ ++ ++#ifndef STM32MP_SHRES_HELPERS_H ++#define STM32MP_SHRES_HELPERS_H ++ ++#include ++#include ++ ++/* ++ * Lock/unlock access to shared registers ++ * ++ * @lock - NULL or pointer to spin lock ++ */ ++ ++void stm32mp_lock_shregs(void); ++void stm32mp_unlock_shregs(void); ++void stm32mp_mmio_clrsetbits_32_shregs(uintptr_t addr, uint32_t clear, ++ uint32_t set); ++void stm32mp_mmio_clrbits_32_shregs(uintptr_t addr, uint32_t clear); ++void stm32mp_mmio_setbits_32_shregs(uintptr_t addr, uint32_t set); ++ ++/* ++ * 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. The counter initializes to ++ * either 0, 1 or 2 upon their expect default state. ++ * Counters saturates once above UINT_MAX / 2. ++ */ ++#define SHREFCNT_NONSECURE_FLAG 0x1UL ++#define SHREFCNT_SECURE_STEP 0x2UL ++#define SHREFCNT_MAX (UINT32_MAX / 2) ++ ++/* Return 1 if refcnt increments from 0, else return 0 */ ++static inline int stm32mp_incr_shrefcnt(unsigned int *refcnt, bool secure) ++{ ++ int rc = !*refcnt; ++ ++ if (secure) { ++ *refcnt += SHREFCNT_SECURE_STEP; ++ if (*refcnt >= SHREFCNT_MAX) { ++ panic(); ++ } ++ } else { ++ *refcnt |= SHREFCNT_NONSECURE_FLAG; ++ } ++ ++ return rc; ++} ++ ++/* Return 1 if refcnt decrements to 0, else return 0 */ ++static inline int stm32mp_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 stm32mp_incr_refcnt(unsigned int *refcnt) ++{ ++ return stm32mp_incr_shrefcnt(refcnt, true); ++} ++ ++static inline int stm32mp_decr_refcnt(unsigned int *refcnt) ++{ ++ return stm32mp_decr_shrefcnt(refcnt, true); ++} ++ ++#endif /* STM32MP_SHRES_HELPERS_H */ +diff --git a/plat/st/common/stm32mp_auth.c b/plat/st/common/stm32mp_auth.c +new file mode 100644 +index 0000000..773c95e +--- /dev/null ++++ b/plat/st/common/stm32mp_auth.c +@@ -0,0 +1,121 @@ ++/* ++ * Copyright (c) 2016-2018, STMicroelectronics - All Rights Reserved ++ * ++ * SPDX-License-Identifier: BSD-3-Clause ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++int check_header(boot_api_image_header_t *header, uintptr_t buffer) ++{ ++ uint32_t i; ++ uint32_t img_checksum = 0; ++ ++ /* ++ * Check header/payload validity: ++ * - Header magic ++ * - Header version ++ * - Payload checksum ++ */ ++ if (header->magic != BOOT_API_IMAGE_HEADER_MAGIC_NB) { ++ ERROR("Header magic is not correct\n"); ++ return -EINVAL; ++ } ++ ++ if (header->header_version != BOOT_API_HEADER_VERSION) { ++ ERROR("Header version is not correct\n"); ++ return -EINVAL; ++ } ++ ++ for (i = 0; i < header->image_length; i++) { ++ img_checksum += *(uint8_t *)(buffer + i); ++ } ++ ++ if (header->payload_checksum != img_checksum) { ++ ERROR("Payload checksum is not correct:\n"); ++ ERROR(" Computed: 0x%x (awaited: 0x%x)\n", img_checksum, ++ header->payload_checksum); ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++int check_authentication(boot_api_image_header_t *header, uintptr_t buffer) ++{ ++ uint32_t sec_closed, uret; ++ HASH_HandleTypeDef hhash; ++ uint8_t image_hash[BOOT_API_SHA256_DIGEST_SIZE_IN_BYTES]; ++ uint32_t header_skip_cksum = sizeof(header->magic) + ++ sizeof(header->image_signature) + ++ sizeof(header->payload_checksum); ++ boot_api_context_t *boot_context = ++ (boot_api_context_t *)stm32mp_get_boot_ctx_address(); ++ ++ uret = bsec_read_otp(&sec_closed, BOOT_API_OTP_MODE_WORD_NB); ++ if (uret != 0) { ++ ERROR("Error reading OTP configuration\n"); ++ return -EINVAL; ++ } ++ ++ /* Check Security Status */ ++ if ((sec_closed & BIT(BOOT_API_OTP_MODE_CLOSED_BIT_POS)) == 0U) { ++ if (header->option_flags != 0U) { ++ WARN("Skip signature check (header option)\n"); ++ return 0; ++ } ++ INFO("Check signature on Non-Full-Secured platform\n"); ++ } ++ ++ /* Check Public Key */ ++ if (boot_context->p_bootrom_ext_service_ecdsa_check_key ++ (header->ecc_pubk, NULL) != STD_OK) { ++ return -EINVAL; ++ } ++ ++ /* Compute end of header hash and payload hash */ ++ uret = HASH_SHA256_Init(&hhash); ++ if (uret != STD_OK) { ++ ERROR("Hash init failed\n"); ++ return -EBUSY; ++ } ++ ++ uret = HASH_SHA256_Accumulate(&hhash, ++ (uint8_t *)&header->header_version, ++ sizeof(boot_api_image_header_t) - ++ header_skip_cksum); ++ if (uret != STD_OK) { ++ ERROR("Hash of header failed\n"); ++ return -EINVAL; ++ } ++ ++ uret = HASH_SHA256_Start(&hhash, (uint8_t *)buffer, ++ header->image_length, image_hash, ++ HASH_TIMEOUT_VALUE); ++ if (uret != STD_OK) { ++ ERROR("Hash of payload failed\n"); ++ return -EINVAL; ++ } ++ ++ uret = HASH_SHA256_Finish(&hhash, image_hash, HASH_TIMEOUT_VALUE); ++ if (uret != STD_OK) { ++ ERROR("Hash of payload failed\n"); ++ return -EINVAL; ++ } ++ ++ /* Verify signature */ ++ if (boot_context->p_bootrom_ext_service_ecdsa_verify_signature ++ (image_hash, header->ecc_pubk, header->image_signature, ++ header->ecc_algo_type) != STD_OK) { ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ +diff --git a/plat/st/common/stm32mp_common.c b/plat/st/common/stm32mp_common.c +new file mode 100644 +index 0000000..8efac68 +--- /dev/null ++++ b/plat/st/common/stm32mp_common.c +@@ -0,0 +1,168 @@ ++/* ++ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. ++ * ++ * SPDX-License-Identifier: BSD-3-Clause ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++uintptr_t plat_get_ns_image_entrypoint(void) ++{ ++ return BL33_BASE; ++} ++ ++unsigned int plat_get_syscnt_freq2(void) ++{ ++ return read_cntfrq_el0(); ++} ++ ++#pragma weak stm32mp_plat_reset ++void __dead2 stm32mp_plat_reset(int cpu) ++{ ++ panic(); ++} ++ ++/* Functions to save and get boot context address given by ROM code */ ++static uintptr_t boot_ctx_address; ++ ++void stm32mp_save_boot_ctx_address(uintptr_t address) ++{ ++ boot_ctx_address = address; ++} ++ ++uintptr_t stm32mp_get_boot_ctx_address(void) ++{ ++ return boot_ctx_address; ++} ++ ++/* ++ * This function determines if one single core is presently running. This is ++ * done by OTP read. ++ * Returns 1 if yes, 0 if more that one core is running, -1 if error. ++ */ ++#pragma weak stm32mp_is_single_core ++ ++int stm32mp_is_single_core(void) ++{ ++ return 0; ++} ++ ++uintptr_t stm32mp_ddrctrl_base(void) ++{ ++ static uintptr_t ddrctrl_base; ++ ++ if (ddrctrl_base == 0) { ++ ddrctrl_base = dt_get_ddrctrl_base(); ++ ++ assert(ddrctrl_base == DDRCTRL_BASE); ++ } ++ ++ return ddrctrl_base; ++} ++ ++uintptr_t stm32mp_ddrphyc_base(void) ++{ ++ static uintptr_t ddrphyc_base; ++ ++ if (ddrphyc_base == 0) { ++ ddrphyc_base = dt_get_ddrphyc_base(); ++ ++ assert(ddrphyc_base == DDRPHYC_BASE); ++ } ++ ++ return ddrphyc_base; ++} ++ ++uintptr_t stm32mp_pwr_base(void) ++{ ++ static uintptr_t pwr_base; ++ ++ if (pwr_base == 0) { ++ pwr_base = dt_get_pwr_base(); ++ ++ assert(pwr_base == PWR_BASE); ++ } ++ ++ return pwr_base; ++} ++ ++uintptr_t stm32mp_rcc_base(void) ++{ ++ static uintptr_t rcc_base; ++ ++ if (rcc_base == 0) { ++ rcc_base = fdt_rcc_read_addr(); ++ ++ assert(rcc_base == RCC_BASE); ++ } ++ ++ return rcc_base; ++} ++ ++uintptr_t stm32_get_gpio_bank_base(unsigned int bank) ++{ ++ switch (bank) { ++ case GPIO_BANK_A ... GPIO_BANK_K: ++ return GPIOA_BASE + (bank * GPIO_BANK_OFFSET); ++ case GPIO_BANK_Z: ++ return GPIOZ_BASE; ++ default: ++ panic(); ++ } ++} ++ ++/* Return clock ID on success, negative value on error */ ++int stm32_get_gpio_bank_clock(unsigned int bank) ++{ ++ switch (bank) { ++ case GPIO_BANK_A ... GPIO_BANK_K: ++ return (int)GPIOA + (bank - GPIO_BANK_A); ++ case GPIO_BANK_Z: ++ return (int)GPIOZ; ++ 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; ++ } ++} ++ ++uint64_t s2tick(uint32_t timeout_s) ++{ ++ return (uint64_t)timeout_s * read_cntfrq_el0(); ++} ++ ++uint64_t ms2tick(uint32_t timeout_ms) ++{ ++ return s2tick(timeout_ms) / 1000U; ++} ++ ++uint64_t us2tick(uint32_t timeout_us) ++{ ++ return s2tick(timeout_us) / (1000U * 1000U); ++} ++ ++uint64_t timeout_start(void) ++{ ++ return read_cntpct_el0(); ++} ++ ++bool timeout_elapsed(uint64_t tick_start, uint64_t tick_to) ++{ ++ return (tick_to != 0U) && ((read_cntpct_el0() - tick_start) > tick_to); ++} +diff --git a/plat/st/common/stm32mp_dt.c b/plat/st/common/stm32mp_dt.c +new file mode 100644 +index 0000000..48529cb +--- /dev/null ++++ b/plat/st/common/stm32mp_dt.c +@@ -0,0 +1,559 @@ ++/* ++ * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved. ++ * ++ * SPDX-License-Identifier: BSD-3-Clause ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static int fdt_checked; ++ ++static void *fdt = (void *)(uintptr_t)STM32MP_DTB_BASE; ++ ++/******************************************************************************* ++ * This function checks device tree file with its header. ++ * Returns 0 on success and a negative FDT error code on failure. ++ ******************************************************************************/ ++int dt_open_and_check(void) ++{ ++ int ret = fdt_check_header(fdt); ++ ++ if (ret == 0) { ++ fdt_checked = 1; ++ } ++ ++ return ret; ++} ++ ++/******************************************************************************* ++ * This function gets the address of the DT. ++ * If DT is OK, fdt_addr is filled with DT address. ++ * Returns 1 if success, 0 otherwise. ++ ******************************************************************************/ ++int fdt_get_address(void **fdt_addr) ++{ ++ if (fdt_checked == 1) { ++ *fdt_addr = fdt; ++ } ++ ++ return fdt_checked; ++} ++ ++/******************************************************************************* ++ * This function check the presence of a node (generic use of fdt library). ++ * Returns true if present, else return false. ++ ******************************************************************************/ ++bool fdt_check_node(int node) ++{ ++ int len; ++ const char *cchar; ++ ++ cchar = fdt_get_name(fdt, node, &len); ++ ++ return (cchar != NULL) && (len >= 0); ++} ++ ++/******************************************************************************* ++ * This function return global node status (generic use of fdt library). ++ ******************************************************************************/ ++uint8_t fdt_get_status(int node) ++{ ++ uint8_t status = DT_DISABLED; ++ int len; ++ const char *cchar; ++ ++ cchar = fdt_getprop(fdt, node, "status", &len); ++ if ((cchar == NULL) || ++ (strncmp(cchar, "okay", (size_t)len) == 0)) { ++ status |= DT_NON_SECURE; ++ } ++ ++ cchar = fdt_getprop(fdt, node, "secure-status", &len); ++ if (cchar == NULL) { ++ if (status == DT_NON_SECURE) { ++ status |= DT_SECURE; ++ } ++ } else if (strncmp(cchar, "okay", (size_t)len) == 0) { ++ status |= DT_SECURE; ++ } ++ ++ return status; ++} ++ ++/******************************************************************************* ++ * This function return interrupts from node. ++ ******************************************************************************/ ++int fdt_get_interrupt(int node, const fdt32_t **array, int *len, bool *extended) ++{ ++ uint8_t status = fdt_get_status(node); ++ ++ *extended = false; ++ ++ switch (status) { ++ case DT_SECURE: ++ *array = fdt_getprop(fdt, node, "interrupts-extended", len); ++ if (*array == NULL) { ++ *array = fdt_getprop(fdt, node, "interrupts", len); ++ } else { ++ *extended = true; ++ } ++ break; ++ ++ case DT_SHARED: ++ *array = fdt_getprop(fdt, node, "secure-interrupts", len); ++ break; ++ ++ default: ++ return -FDT_ERR_NOTFOUND; ++ } ++ ++ if (*array == NULL) { ++ return -FDT_ERR_NOTFOUND; ++ } ++ ++ return 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(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 on success and a negative FDT error code on failure. ++ * If success, values are stored at the third parameter address. ++ ******************************************************************************/ ++int fdt_read_uint32_array(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 fills reg node info (base & size) with an index found by ++ * checking the reg-names node. ++ * Returns 0 on success and a negative FDT error code on failure. ++ ******************************************************************************/ ++int fdt_get_reg_props_by_name(int node, const char *name, uintptr_t *base, ++ size_t *size) ++{ ++ const fdt32_t *cuint; ++ int index, len; ++ ++ index = fdt_stringlist_search(fdt, node, "reg-names", name); ++ if (index < 0) { ++ return index; ++ } ++ ++ cuint = fdt_getprop(fdt, node, "reg", &len); ++ if (cuint == NULL) { ++ return -FDT_ERR_NOTFOUND; ++ } ++ ++ if ((index * (int)sizeof(uint32_t)) > len) { ++ return -FDT_ERR_BADVALUE; ++ } ++ ++ cuint += index << 1; ++ *base = fdt32_to_cpu(*cuint); ++ cuint++; ++ *size = fdt32_to_cpu(*cuint); ++ ++ return 0; ++} ++ ++/******************************************************************************* ++ * 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. ++ ******************************************************************************/ ++static int dt_get_stdout_node_offset(void) ++{ ++ 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 the stdout pin configuration information from the DT. ++ * And then calls the sub-function to treat it and set GPIO registers. ++ * Returns 0 on success and a negative FDT error code on failure. ++ ******************************************************************************/ ++int dt_set_stdout_pinctrl(void) ++{ ++ int node; ++ ++ node = dt_get_stdout_node_offset(); ++ if (node < 0) { ++ return -FDT_ERR_NOTFOUND; ++ } ++ ++ return dt_set_pinctrl_config(node); ++} ++ ++/******************************************************************************* ++ * This function fills the generic information from a given node. ++ ******************************************************************************/ ++void dt_fill_device_info(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(node); ++} ++ ++/******************************************************************************* ++ * This function retrieve the generic information from DT. ++ * Returns node on success and a negative FDT error code on failure. ++ ******************************************************************************/ ++int dt_get_node(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; ++ } ++ ++ dt_fill_device_info(info, node); ++ ++ return node; ++} ++ ++/******************************************************************************* ++ * This function gets the UART instance info of stdout from the DT. ++ * Returns node on success and a negative FDT error code on failure. ++ ******************************************************************************/ ++int dt_get_stdout_uart_info(struct dt_node_info *info) ++{ ++ int node; ++ ++ node = dt_get_stdout_node_offset(); ++ if (node < 0) { ++ return -FDT_ERR_NOTFOUND; ++ } ++ ++ dt_fill_device_info(info, node); ++ ++ return node; ++} ++ ++/******************************************************************************* ++ * This function gets DDR size information from the DT. ++ * Returns value in bytes on success, and 0 on failure. ++ ******************************************************************************/ ++uint32_t dt_get_ddr_size(void) ++{ ++ int node; ++ ++ node = fdt_node_offset_by_compatible(fdt, -1, DT_DDR_COMPAT); ++ if (node < 0) { ++ INFO("%s: Cannot read DDR node in DT\n", __func__); ++ return 0; ++ } ++ ++ return fdt_read_uint32_default(node, "st,mem-size", 0); ++} ++ ++/******************************************************************************* ++ * This function gets DDRCTRL base address information from the DT. ++ * Returns value on success, and 0 on failure. ++ ******************************************************************************/ ++uintptr_t dt_get_ddrctrl_base(void) ++{ ++ int node; ++ uint32_t array[4]; ++ ++ node = fdt_node_offset_by_compatible(fdt, -1, DT_DDR_COMPAT); ++ if (node < 0) { ++ INFO("%s: Cannot read DDR node in DT\n", __func__); ++ return 0; ++ } ++ ++ if (fdt_read_uint32_array(node, "reg", array, 4) < 0) { ++ return 0; ++ } ++ ++ return array[0]; ++} ++ ++/******************************************************************************* ++ * This function gets DDRPHYC base address information from the DT. ++ * Returns value on success, and 0 on failure. ++ ******************************************************************************/ ++uintptr_t dt_get_ddrphyc_base(void) ++{ ++ int node; ++ uint32_t array[4]; ++ ++ node = fdt_node_offset_by_compatible(fdt, -1, DT_DDR_COMPAT); ++ if (node < 0) { ++ INFO("%s: Cannot read DDR node in DT\n", __func__); ++ return 0; ++ } ++ ++ if (fdt_read_uint32_array(node, "reg", array, 4) < 0) { ++ return 0; ++ } ++ ++ return array[2]; ++} ++ ++/******************************************************************************* ++ * This function gets PWR base address information from the DT. ++ * Returns value on success, and 0 on failure. ++ ******************************************************************************/ ++uintptr_t dt_get_pwr_base(void) ++{ ++ int node; ++ const fdt32_t *cuint; ++ ++ node = fdt_node_offset_by_compatible(fdt, -1, DT_PWR_COMPAT); ++ if (node < 0) { ++ INFO("%s: Cannot read PWR node in DT\n", __func__); ++ return 0; ++ } ++ ++ cuint = fdt_getprop(fdt, node, "reg", NULL); ++ if (cuint == NULL) { ++ return 0; ++ } ++ ++ return fdt32_to_cpu(*cuint); ++} ++ ++/******************************************************************************* ++ * This function gets PWR VDD regulator voltage information from the DT. ++ * Returns value in microvolts on success, and 0 on failure. ++ ******************************************************************************/ ++uint32_t dt_get_pwr_vdd_voltage(void) ++{ ++ int node; ++ const fdt32_t *cuint; ++ ++ node = fdt_node_offset_by_compatible(fdt, -1, DT_PWR_COMPAT); ++ if (node < 0) { ++ INFO("%s: Cannot read PWR node in DT\n", __func__); ++ return 0; ++ } ++ ++ cuint = fdt_getprop(fdt, node, "pwr-supply", NULL); ++ if (cuint == NULL) { ++ return 0; ++ } ++ ++ node = fdt_node_offset_by_phandle(fdt, fdt32_to_cpu(*cuint)); ++ if (node < 0) { ++ return 0; ++ } ++ ++ cuint = fdt_getprop(fdt, node, "regulator-min-microvolt", NULL); ++ if (cuint == NULL) { ++ return 0; ++ } ++ ++ return fdt32_to_cpu(*cuint); ++} ++ ++/******************************************************************************* ++ * This function gets SYSCFG base address information from the DT. ++ * Returns value on success, and 0 on failure. ++ ******************************************************************************/ ++uintptr_t dt_get_syscfg_base(void) ++{ ++ int node; ++ const fdt32_t *cuint; ++ ++ node = fdt_node_offset_by_compatible(fdt, -1, DT_SYSCFG_COMPAT); ++ if (node < 0) { ++ INFO("%s: Cannot read SYSCFG node in DT\n", __func__); ++ return 0; ++ } ++ ++ cuint = fdt_getprop(fdt, node, "reg", NULL); ++ if (cuint == NULL) { ++ return 0; ++ } ++ ++ return fdt32_to_cpu(*cuint); ++} ++ ++/******************************************************************************* ++ * This function retrieves board model from DT ++ * Returns string taken from model node, NULL otherwise ++ ******************************************************************************/ ++const char *dt_get_board_model(void) ++{ ++ 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(unsigned int bank) ++{ ++ switch (bank) { ++ case GPIO_BANK_A ... 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) ++{ ++ int pinctrl_node; ++ int pinctrl_subnode; ++ ++ pinctrl_node = fdt_get_gpio_bank_pinctrl_node(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(pinctrl_subnode) == DT_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/plat/st/common/stm32mp_shres_helpers.c b/plat/st/common/stm32mp_shres_helpers.c +new file mode 100644 +index 0000000..b8bc2ec +--- /dev/null ++++ b/plat/st/common/stm32mp_shres_helpers.c +@@ -0,0 +1,71 @@ ++/* ++ * Copyright (C) 2018, STMicroelectronics - All Rights Reserved ++ * ++ * SPDX-License-Identifier: BSD-3-Clause ++ */ ++ ++#include ++#include ++#include ++#include ++ ++static struct spinlock shregs_lock; ++ ++static int stm32mp_lock_available(void) ++{ ++ /* The spinlocks are used only when MMU is enabled */ ++#ifdef AARCH32 ++ return (read_sctlr() & SCTLR_M_BIT) && (read_sctlr() & SCTLR_C_BIT); ++#else ++ return (read_sctlr_el3() & SCTLR_M_BIT) && ++ (read_sctlr_el3() & SCTLR_C_BIT); ++#endif ++} ++ ++void stm32mp_lock_shregs(void) ++{ ++ if (stm32mp_lock_available() == 0U) { ++ return; ++ } ++ ++ /* Assume interrupts are masked */ ++ spin_lock(&shregs_lock); ++} ++ ++void stm32mp_unlock_shregs(void) ++{ ++ if (stm32mp_lock_available() == 0U) { ++ return; ++ } ++ ++ spin_unlock(&shregs_lock); ++} ++ ++/* Shared register access: upon shared resource lock */ ++void stm32mp_mmio_clrsetbits_32_shregs(uintptr_t addr, uint32_t clear, ++ uint32_t set) ++{ ++ stm32mp_lock_shregs(); ++ ++ mmio_clrsetbits_32(addr, clear, set); ++ ++ stm32mp_unlock_shregs(); ++} ++ ++void stm32mp_mmio_clrbits_32_shregs(uintptr_t addr, uint32_t clear) ++{ ++ stm32mp_lock_shregs(); ++ ++ mmio_clrbits_32(addr, clear); ++ ++ stm32mp_unlock_shregs(); ++} ++ ++void stm32mp_mmio_setbits_32_shregs(uintptr_t addr, uint32_t set) ++{ ++ stm32mp_lock_shregs(); ++ ++ mmio_setbits_32(addr, set); ++ ++ stm32mp_unlock_shregs(); ++} +diff --git a/plat/st/stm32mp1/bl2_io_storage.c b/plat/st/stm32mp1/bl2_io_storage.c +deleted file mode 100644 +index 7346c0c..0000000 +--- a/plat/st/stm32mp1/bl2_io_storage.c ++++ /dev/null +@@ -1,193 +0,0 @@ +-/* +- * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. +- * +- * SPDX-License-Identifier: BSD-3-Clause +- */ +- +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +- +-/* IO devices */ +-static const io_dev_connector_t *dummy_dev_con; +-static uintptr_t dummy_dev_handle; +-static uintptr_t dummy_dev_spec; +- +-static const io_block_spec_t bl32_block_spec = { +- .offset = BL32_BASE, +- .length = STM32MP1_BL32_SIZE +-}; +- +-static const io_block_spec_t bl2_block_spec = { +- .offset = BL2_BASE, +- .length = STM32MP1_BL2_SIZE, +-}; +- +-static int open_dummy(const uintptr_t spec); +- +-struct plat_io_policy { +- uintptr_t *dev_handle; +- uintptr_t image_spec; +- int (*check)(const uintptr_t spec); +-}; +- +-static const struct plat_io_policy policies[] = { +- [BL2_IMAGE_ID] = { +- .dev_handle = &dummy_dev_handle, +- .image_spec = (uintptr_t)&bl2_block_spec, +- .check = open_dummy +- }, +- [BL32_IMAGE_ID] = { +- .dev_handle = &dummy_dev_handle, +- .image_spec = (uintptr_t)&bl32_block_spec, +- .check = open_dummy +- }, +-}; +- +-static int open_dummy(const uintptr_t spec) +-{ +- return io_dev_init(dummy_dev_handle, 0); +-} +- +-static void print_boot_device(boot_api_context_t *boot_context) +-{ +- switch (boot_context->boot_interface_selected) { +- case BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_SD: +- INFO("Using SDMMC\n"); +- break; +- case BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_EMMC: +- INFO("Using EMMC\n"); +- break; +- default: +- ERROR("Boot interface not found\n"); +- panic(); +- break; +- } +- +- if (boot_context->boot_interface_instance != 0U) { +- INFO(" Instance %d\n", boot_context->boot_interface_instance); +- } +-} +- +-static void print_reset_reason(void) +-{ +- uint32_t rstsr = mmio_read_32(RCC_BASE + RCC_MP_RSTSCLRR); +- +- if (rstsr == 0U) { +- WARN("Reset reason unknown\n"); +- return; +- } +- +- INFO("Reset reason (0x%x):\n", rstsr); +- +- if ((rstsr & RCC_MP_RSTSCLRR_PADRSTF) == 0U) { +- if ((rstsr & RCC_MP_RSTSCLRR_STDBYRSTF) != 0U) { +- INFO("System exits from STANDBY\n"); +- return; +- } +- +- if ((rstsr & RCC_MP_RSTSCLRR_CSTDBYRSTF) != 0U) { +- INFO("MPU exits from CSTANDBY\n"); +- return; +- } +- } +- +- if ((rstsr & RCC_MP_RSTSCLRR_PORRSTF) != 0U) { +- INFO(" Power-on Reset (rst_por)\n"); +- return; +- } +- +- if ((rstsr & RCC_MP_RSTSCLRR_BORRSTF) != 0U) { +- INFO(" Brownout Reset (rst_bor)\n"); +- return; +- } +- +- if ((rstsr & RCC_MP_RSTSCLRR_MPSYSRSTF) != 0U) { +- INFO(" System reset generated by MPU (MPSYSRST)\n"); +- return; +- } +- +- if ((rstsr & RCC_MP_RSTSCLRR_HCSSRSTF) != 0U) { +- INFO(" Reset due to a clock failure on HSE\n"); +- return; +- } +- +- if ((rstsr & RCC_MP_RSTSCLRR_IWDG1RSTF) != 0U) { +- INFO(" IWDG1 Reset (rst_iwdg1)\n"); +- return; +- } +- +- if ((rstsr & RCC_MP_RSTSCLRR_IWDG2RSTF) != 0U) { +- INFO(" IWDG2 Reset (rst_iwdg2)\n"); +- return; +- } +- +- if ((rstsr & RCC_MP_RSTSCLRR_PADRSTF) != 0U) { +- INFO(" Pad Reset from NRST\n"); +- return; +- } +- +- if ((rstsr & RCC_MP_RSTSCLRR_VCORERSTF) != 0U) { +- INFO(" Reset due to a failure of VDD_CORE\n"); +- return; +- } +- +- ERROR(" Unidentified reset reason\n"); +-} +- +-void stm32mp1_io_setup(void) +-{ +- int io_result __unused; +- boot_api_context_t *boot_context = +- (boot_api_context_t *)stm32mp1_get_boot_ctx_address(); +- +- print_reset_reason(); +- +- print_boot_device(boot_context); +- +- if ((boot_context->boot_partition_used_toboot == 1U) || +- (boot_context->boot_partition_used_toboot == 2U)) { +- INFO("Boot used partition fsbl%d\n", +- boot_context->boot_partition_used_toboot); +- } +- +- io_result = register_io_dev_dummy(&dummy_dev_con); +- assert(io_result == 0); +- +- io_result = io_dev_open(dummy_dev_con, dummy_dev_spec, +- &dummy_dev_handle); +- assert(io_result == 0); +-} +- +-/* +- * Return an IO device handle and specification which can be used to access +- * an image. Use this to enforce platform load policy. +- */ +-int plat_get_image_source(unsigned int image_id, uintptr_t *dev_handle, +- uintptr_t *image_spec) +-{ +- int rc; +- const struct plat_io_policy *policy; +- +- assert(image_id < ARRAY_SIZE(policies)); +- +- policy = &policies[image_id]; +- rc = policy->check(policy->image_spec); +- if (rc == 0) { +- *image_spec = policy->image_spec; +- *dev_handle = *(policy->dev_handle); +- } +- +- return rc; +-} +diff --git a/plat/st/stm32mp1/bl2_plat_setup.c b/plat/st/stm32mp1/bl2_plat_setup.c +index 9f2d8bd..cd5d5b3 100644 +--- a/plat/st/stm32mp1/bl2_plat_setup.c ++++ b/plat/st/stm32mp1/bl2_plat_setup.c +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. ++ * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +@@ -8,38 +8,154 @@ + #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 + #include + #include + +-void bl2_el3_early_platform_setup(u_register_t arg0, u_register_t arg1, +- u_register_t arg2, u_register_t arg3) ++#define PWRLP_TEMPO_5_HSI 5 ++ ++static struct console_stm32 console; ++static enum boot_device_e boot_device = BOOT_DEVICE_BOARD; ++ ++static void print_reset_reason(void) + { +- stm32mp1_save_boot_ctx_address(arg0); ++ uint32_t rstsr = mmio_read_32(stm32mp_rcc_base() + RCC_MP_RSTSCLRR); ++ ++ if (rstsr == 0U) { ++ WARN("Reset reason unknown\n"); ++ return; ++ } ++ ++ INFO("Reset reason (0x%x):\n", rstsr); ++ ++ if ((rstsr & RCC_MP_RSTSCLRR_PADRSTF) == 0U) { ++ if ((rstsr & RCC_MP_RSTSCLRR_STDBYRSTF) != 0U) { ++ INFO("System exits from STANDBY\n"); ++ return; ++ } ++ ++ if ((rstsr & RCC_MP_RSTSCLRR_CSTDBYRSTF) != 0U) { ++ INFO("MPU exits from CSTANDBY\n"); ++ return; ++ } ++ } ++ ++ if ((rstsr & RCC_MP_RSTSCLRR_PORRSTF) != 0U) { ++ INFO(" Power-on Reset (rst_por)\n"); ++ return; ++ } ++ ++ if ((rstsr & RCC_MP_RSTSCLRR_BORRSTF) != 0U) { ++ INFO(" Brownout Reset (rst_bor)\n"); ++ return; ++ } ++ ++ if ((rstsr & RCC_MP_RSTSCLRR_MCSYSRSTF) != 0U) { ++ if ((rstsr & RCC_MP_RSTSCLRR_PADRSTF) != 0U) ++ INFO(" System reset generated by MCU (MCSYSRST)\n"); ++ else ++ INFO(" Local reset generated by MCU (MCSYSRST)\n"); ++ return; ++ } ++ ++ if ((rstsr & RCC_MP_RSTSCLRR_MPSYSRSTF) != 0U) { ++ INFO(" System reset generated by MPU (MPSYSRST)\n"); ++ return; ++ } ++ ++ if ((rstsr & RCC_MP_RSTSCLRR_HCSSRSTF) != 0U) { ++ INFO(" Reset due to a clock failure on HSE\n"); ++ return; ++ } ++ ++ if ((rstsr & RCC_MP_RSTSCLRR_IWDG1RSTF) != 0U) { ++ INFO(" IWDG1 Reset (rst_iwdg1)\n"); ++ return; ++ } ++ ++ if ((rstsr & RCC_MP_RSTSCLRR_IWDG2RSTF) != 0U) { ++ INFO(" IWDG2 Reset (rst_iwdg2)\n"); ++ return; ++ } ++ ++ if ((rstsr & RCC_MP_RSTSCLRR_MPUP0RSTF) != 0U) { ++ INFO(" MPU Processor 0 Reset\n"); ++ return; ++ } ++ ++ if ((rstsr & RCC_MP_RSTSCLRR_MPUP1RSTF) != 0U) { ++ INFO(" MPU Processor 1 Reset\n"); ++ return; ++ } ++ ++ if ((rstsr & RCC_MP_RSTSCLRR_PADRSTF) != 0U) { ++ INFO(" Pad Reset from NRST\n"); ++ return; ++ } ++ ++ if ((rstsr & RCC_MP_RSTSCLRR_VCORERSTF) != 0U) { ++ INFO(" Reset due to a failure of VDD_CORE\n"); ++ return; ++ } ++ ++ ERROR(" Unidentified reset reason\n"); ++} ++ ++enum boot_device_e get_boot_device(void) ++{ ++ return boot_device; ++} ++ ++void bl2_el3_early_platform_setup(u_register_t arg0, ++ u_register_t arg1 __unused, ++ u_register_t arg2 __unused, ++ u_register_t arg3 __unused) ++{ ++ stm32mp_save_boot_ctx_address(arg0); + } + + void bl2_platform_setup(void) + { + int ret; + +- if (dt_check_pmic()) { ++ if (dt_pmic_status() > 0) { + initialize_pmic(); ++#if STM32MP1_DEBUG_ENABLE ++ /* Program PMIC to keep debug ON */ ++ if ((stm32mp1_dbgmcu_boot_debug_info() == 1) && ++ (stm32mp1_dbgmcu_is_debug_on() != 0)) { ++ VERBOSE("Program PMIC to keep debug ON\n"); ++ if (pmic_keep_debug_unit() != 0) { ++ ERROR("PMIC not properly set for debug\n"); ++ } ++ } ++#endif + } + + ret = stm32mp1_ddr_probe(); +@@ -48,62 +164,156 @@ void bl2_platform_setup(void) + panic(); + } + ++#ifdef AARCH32_SP_OPTEE ++ INFO("BL2 runs OP-TEE setup\n"); ++ /* Initialize tzc400 after DDR initialization */ ++ stm32mp1_security_setup(); ++#else + INFO("BL2 runs SP_MIN setup\n"); ++#endif + } + + void bl2_el3_plat_arch_setup(void) + { + int32_t result; +- struct dt_node_info dt_dev_info; ++ struct dt_node_info dt_uart_info; + const char *board_model; + boot_api_context_t *boot_context = +- (boot_api_context_t *)stm32mp1_get_boot_ctx_address(); ++ (boot_api_context_t *)stm32mp_get_boot_ctx_address(); + uint32_t clk_rate; ++ uintptr_t pwr_base; ++ uintptr_t rcc_base; ++ uint32_t bkpr_core1_magic = ++ tamp_bkpr(BOOT_API_CORE1_MAGIC_NUMBER_TAMP_BCK_REG_IDX); ++ uint32_t bkpr_core1_addr = ++ tamp_bkpr(BOOT_API_CORE1_BRANCH_ADDRESS_TAMP_BCK_REG_IDX); ++ ++ mmap_add_region(BL_CODE_BASE, BL_CODE_BASE, ++ BL_CODE_END - BL_CODE_BASE, ++ MT_CODE | MT_SECURE); ++ ++#if SEPARATE_CODE_AND_RODATA ++ mmap_add_region(BL_RO_DATA_BASE, BL_RO_DATA_BASE, ++ BL_RO_DATA_LIMIT - BL_RO_DATA_BASE, ++ MT_RO_DATA | MT_SECURE); ++#endif ++ ++#ifdef AARCH32_SP_OPTEE ++ /* OP-TEE image needs post load processing: keep RAM read/write */ ++ mmap_add_region(STM32MP_DDR_BASE + dt_get_ddr_size() - ++ STM32MP_DDR_S_SIZE, ++ STM32MP_DDR_BASE + dt_get_ddr_size() - ++ STM32MP_DDR_S_SIZE, ++ STM32MP_DDR_S_SIZE, ++ MT_MEMORY | MT_RW | MT_SECURE); ++ ++ mmap_add_region(STM32MP_OPTEE_BASE, STM32MP_OPTEE_BASE, ++ STM32MP_OPTEE_SIZE, ++ MT_MEMORY | MT_RW | MT_SECURE); ++#else ++ /* Prevent corruption of preloaded BL32 */ ++ mmap_add_region(BL32_BASE, BL32_BASE, ++ BL32_LIMIT - BL32_BASE, ++ MT_MEMORY | MT_RO | MT_SECURE); ++ ++#endif ++ /* Map non secure DDR for BL33 load and DDR training area restore */ ++ mmap_add_region(STM32MP_DDR_BASE, ++ STM32MP_DDR_BASE, ++ STM32MP_DDR_MAX_SIZE, ++ MT_MEMORY | MT_RW | MT_NS); ++ ++ /* Prevent corruption of preloaded Device Tree */ ++ mmap_add_region(DTB_BASE, DTB_BASE, ++ DTB_LIMIT - DTB_BASE, ++ MT_MEMORY | MT_RO | MT_SECURE); ++ ++ configure_mmu(); ++ ++ if (dt_open_and_check() < 0) { ++ panic(); ++ } ++ ++ pwr_base = stm32mp_pwr_base(); ++ rcc_base = stm32mp_rcc_base(); ++ ++ /* Clear Stop Request bits to correctly manage low-power exit */ ++ mmio_write_32(rcc_base + RCC_MP_SREQCLRR, ++ (uint32_t)(RCC_MP_SREQCLRR_STPREQ_P0 | ++ RCC_MP_SREQCLRR_STPREQ_P1)); + + /* + * Disable the backup domain write protection. + * The protection is enable at each reset by hardware + * and must be disabled by software. + */ +- mmio_setbits_32(PWR_BASE + PWR_CR1, PWR_CR1_DBP); ++ mmio_setbits_32(pwr_base + PWR_CR1, PWR_CR1_DBP); + +- while ((mmio_read_32(PWR_BASE + PWR_CR1) & PWR_CR1_DBP) == 0U) { ++ while ((mmio_read_32(pwr_base + PWR_CR1) & PWR_CR1_DBP) == 0U) { + ; + } + ++ /* ++ * Configure Standby mode available for MCU by default ++ * and allow to switch in standby SoC in all case ++ */ ++ mmio_setbits_32(pwr_base + PWR_MCUCR, PWR_MCUCR_PDDS); ++ ++ if (bsec_probe() != 0) { ++ panic(); ++ } ++ + /* Reset backup domain on cold boot cases */ +- if ((mmio_read_32(RCC_BASE + RCC_BDCR) & RCC_BDCR_RTCSRC_MASK) == 0U) { +- mmio_setbits_32(RCC_BASE + RCC_BDCR, RCC_BDCR_VSWRST); ++ if ((mmio_read_32(rcc_base + RCC_BDCR) & RCC_BDCR_RTCSRC_MASK) == 0U) { ++ mmio_setbits_32(rcc_base + RCC_BDCR, RCC_BDCR_VSWRST); + +- while ((mmio_read_32(RCC_BASE + RCC_BDCR) & RCC_BDCR_VSWRST) == ++ while ((mmio_read_32(rcc_base + RCC_BDCR) & RCC_BDCR_VSWRST) == + 0U) { + ; + } + +- mmio_clrbits_32(RCC_BASE + RCC_BDCR, RCC_BDCR_VSWRST); ++ mmio_clrbits_32(rcc_base + RCC_BDCR, RCC_BDCR_VSWRST); + } + +- mmap_add_region(BL_CODE_BASE, BL_CODE_BASE, +- BL_CODE_END - BL_CODE_BASE, +- MT_CODE | MT_SECURE); ++ /* Wait 5 HSI periods before re-enabling PLLs after STOP modes */ ++ mmio_clrsetbits_32(rcc_base + RCC_PWRLPDLYCR, ++ RCC_PWRLPDLYCR_PWRLP_DLY_MASK, ++ PWRLP_TEMPO_5_HSI); + +- /* Prevent corruption of preloaded BL32 */ +- mmap_add_region(BL32_BASE, BL32_BASE, +- BL32_LIMIT - BL32_BASE, +- MT_MEMORY | MT_RO | MT_SECURE); ++ /* Keep retention and backup ram content in standby */ ++ mmio_setbits_32(pwr_base + PWR_CR2, PWR_CR2_BREN); ++ mmio_setbits_32(pwr_base + PWR_CR2, PWR_CR2_RREN); + +- /* Prevent corruption of preloaded Device Tree */ +- mmap_add_region(DTB_BASE, DTB_BASE, +- DTB_LIMIT - DTB_BASE, +- MT_MEMORY | MT_RO | MT_SECURE); ++ /* Disable MCKPROT */ ++ mmio_clrbits_32(rcc_base + RCC_TZCR, RCC_TZCR_MCKPROT); + +- configure_mmu(); ++ if ((boot_context->boot_action != ++ BOOT_API_CTX_BOOT_ACTION_WAKEUP_CSTANDBY) && ++ (boot_context->boot_action != ++ BOOT_API_CTX_BOOT_ACTION_WAKEUP_STANDBY)) { ++ mmio_write_32(bkpr_core1_addr, 0); ++ mmio_write_32(bkpr_core1_magic, 0); ++ } + + generic_delay_timer_init(); + +- if (dt_open_and_check() < 0) { +- panic(); ++#ifdef STM32MP_USB ++ if (boot_context->boot_interface_selected == ++ BOOT_API_CTX_BOOT_INTERFACE_SEL_SERIAL_USB) { ++ boot_device = BOOT_DEVICE_USB; + } ++#endif ++ ++#if STM32MP_UART_PROGRAMMER ++ /* Disable programmer UART before changing clock tree */ ++ if (boot_context->boot_interface_selected == ++ BOOT_API_CTX_BOOT_INTERFACE_SEL_SERIAL_UART) { ++ uintptr_t uart_prog_addr = ++ get_uart_address(boot_context->boot_interface_instance); ++ ++ ((USART_TypeDef *)uart_prog_addr)->CR1 &= ~USART_CR1_UE; ++ } ++#endif + + if (stm32mp1_clk_probe() < 0) { + panic(); +@@ -113,12 +323,18 @@ void bl2_el3_plat_arch_setup(void) + panic(); + } + +- result = dt_get_stdout_uart_info(&dt_dev_info); ++ result = dt_get_stdout_uart_info(&dt_uart_info); + + if ((result <= 0) || +- (dt_dev_info.status == 0U) || +- (dt_dev_info.clock < 0) || +- (dt_dev_info.reset < 0)) { ++ (dt_uart_info.status == 0U) || ++#if STM32MP_UART_PROGRAMMER ++ ((boot_context->boot_interface_selected == ++ BOOT_API_CTX_BOOT_INTERFACE_SEL_SERIAL_UART) && ++ (get_uart_address(boot_context->boot_interface_instance) == ++ dt_uart_info.base)) || ++#endif ++ (dt_uart_info.clock < 0) || ++ (dt_uart_info.reset < 0)) { + goto skip_console_init; + } + +@@ -126,29 +342,57 @@ void bl2_el3_plat_arch_setup(void) + goto skip_console_init; + } + +- if (stm32mp1_clk_enable((unsigned long)dt_dev_info.clock) != 0) { +- goto skip_console_init; ++ if (dt_uart_info.status == DT_DISABLED) { ++ panic(); ++ } else if (dt_uart_info.status == DT_SECURE) { ++ stm32mp_register_secure_periph_iomem(dt_uart_info.base); ++ } else { ++ stm32mp_register_non_secure_periph_iomem(dt_uart_info.base); + } + +- stm32mp1_reset_assert((uint32_t)dt_dev_info.reset); ++ stm32mp_clk_enable((unsigned long)dt_uart_info.clock); ++ ++ stm32mp_reset_assert((uint32_t)dt_uart_info.reset); + udelay(2); +- stm32mp1_reset_deassert((uint32_t)dt_dev_info.reset); ++ stm32mp_reset_deassert((uint32_t)dt_uart_info.reset); + mdelay(1); + +- clk_rate = stm32mp1_clk_get_rate((unsigned long)dt_dev_info.clock); ++ clk_rate = stm32mp_clk_get_rate((unsigned long)dt_uart_info.clock); + +- if (console_init(dt_dev_info.base, clk_rate, +- STM32MP1_UART_BAUDRATE) == 0) { ++ if (console_stm32_register(dt_uart_info.base, clk_rate, ++ STM32MP_UART_BAUDRATE, &console) == 0) { + panic(); + } + ++ stm32mp_print_cpuinfo(); + board_model = dt_get_board_model(); + if (board_model != NULL) { +- NOTICE("%s\n", board_model); ++ NOTICE("Model: %s\n", board_model); ++ } ++ stm32mp_print_boardinfo(); ++ ++ if (boot_context->auth_status != BOOT_API_CTX_AUTH_NO) { ++ NOTICE("%s\n", (boot_context->auth_status == ++ BOOT_API_CTX_AUTH_FAILED) ? ++ "Boot authentication Failed" : ++ "Boot authentication Success"); + } + + skip_console_init: + ++ /* Initialize IWDG Status, no startup */ ++ if (stm32_iwdg_init() < 0) { ++ panic(); ++ } ++ ++ /* Reload watchdog */ ++ stm32_iwdg_refresh(IWDG2_INST); ++ ++ result = stm32mp1_dbgmcu_freeze_iwdg2(); ++ if (result != 0) { ++ INFO("IWDG2 freeze error : %i\n", result); ++ } ++ + if (stm32_save_boot_interface(boot_context->boot_interface_selected, + boot_context->boot_interface_instance) != + 0) { +@@ -157,5 +401,118 @@ skip_console_init: + + stm32mp1_arch_security_setup(); + +- stm32mp1_io_setup(); ++ print_reset_reason(); ++ ++ stm32mp_io_setup(); ++ ++ stm32mp1_syscfg_init(); ++} ++ ++#if defined(AARCH32_SP_OPTEE) ++static void set_mem_params_info(entry_point_info_t *ep_info, ++ image_info_t *unpaged, image_info_t *paged) ++{ ++ uintptr_t bl32_ep = 0; ++ ++ /* Use the default dram setup if no valid ep found */ ++ if (get_optee_header_ep(ep_info, &bl32_ep) && ++ (bl32_ep >= STM32MP_OPTEE_BASE) && ++ (bl32_ep < (STM32MP_OPTEE_BASE + STM32MP_OPTEE_SIZE))) { ++ assert((STM32MP_OPTEE_BASE >= BL2_LIMIT) || ++ ((STM32MP_OPTEE_BASE + STM32MP_OPTEE_SIZE) <= BL2_BASE)); ++ ++ unpaged->image_base = STM32MP_OPTEE_BASE; ++ unpaged->image_max_size = STM32MP_OPTEE_SIZE; ++ } else { ++ unpaged->image_base = STM32MP_DDR_BASE + dt_get_ddr_size() - ++ STM32MP_DDR_S_SIZE; ++ unpaged->image_max_size = STM32MP_DDR_S_SIZE; ++ } ++ paged->image_base = STM32MP_DDR_BASE + dt_get_ddr_size() - ++ STM32MP_DDR_S_SIZE; ++ paged->image_max_size = STM32MP_DDR_S_SIZE; ++} ++#endif ++ ++/******************************************************************************* ++ * This function can be used by the platforms to update/use image ++ * information for given `image_id`. ++ ******************************************************************************/ ++int bl2_plat_handle_post_image_load(unsigned int image_id) ++{ ++ int err = 0; ++ bl_mem_params_node_t *bl_mem_params = get_bl_mem_params_node(image_id); ++#if defined(AARCH32_SP_OPTEE) ++ bl_mem_params_node_t *bl32_mem_params; ++ bl_mem_params_node_t *pager_mem_params; ++ bl_mem_params_node_t *paged_mem_params; ++#endif ++ ++ assert(bl_mem_params != NULL); ++ ++ switch (image_id) { ++ case BL32_IMAGE_ID: ++#if defined(AARCH32_SP_OPTEE) ++ pager_mem_params = get_bl_mem_params_node(BL32_EXTRA1_IMAGE_ID); ++ assert(pager_mem_params); ++ ++ paged_mem_params = get_bl_mem_params_node(BL32_EXTRA2_IMAGE_ID); ++ assert(paged_mem_params); ++ ++ bl_mem_params->ep_info.pc = ++ bl_mem_params->image_info.image_base; ++ ++ set_mem_params_info(&bl_mem_params->ep_info, ++ &pager_mem_params->image_info, ++ &paged_mem_params->image_info); ++ ++ err = parse_optee_header(&bl_mem_params->ep_info, ++ &pager_mem_params->image_info, ++ &paged_mem_params->image_info); ++ if (err) { ++ ERROR("OPTEE header parse error.\n"); ++ panic(); ++ } ++ ++ /* Set optee boot info from parsed header data */ ++ bl_mem_params->ep_info.pc = ++ pager_mem_params->image_info.image_base; ++ bl_mem_params->ep_info.args.arg0 = ++ paged_mem_params->image_info.image_base; ++ bl_mem_params->ep_info.args.arg1 = 0; /* Unused */ ++ bl_mem_params->ep_info.args.arg2 = 0; /* No DT supported */ ++#endif ++ break; ++ ++ case BL33_IMAGE_ID: ++#ifdef AARCH32_SP_OPTEE ++ bl32_mem_params = get_bl_mem_params_node(BL32_IMAGE_ID); ++ assert(bl32_mem_params); ++ bl32_mem_params->ep_info.lr_svc = bl_mem_params->ep_info.pc; ++#else ++ /* BL33 expects to receive : TBD */ ++ bl_mem_params->ep_info.args.arg0 = 0; ++ bl_mem_params->ep_info.spsr = ++ SPSR_MODE32(MODE32_svc, SPSR_T_ARM, SPSR_E_LITTLE, ++ DISABLE_ALL_EXCEPTIONS); ++#endif ++ flush_dcache_range(bl_mem_params->image_info.image_base, ++ bl_mem_params->image_info.image_max_size); ++ break; ++ ++#ifdef AARCH32_SP_OPTEE ++ case BL32_EXTRA1_IMAGE_ID: ++ case BL32_EXTRA2_IMAGE_ID: ++ clean_dcache_range(bl_mem_params->image_info.image_base, ++ bl_mem_params->image_info.image_max_size); ++ break; ++#endif ++ ++ default: ++ err = -1; ++ break; ++ } ++ ++ return err; + } ++ +diff --git a/plat/st/stm32mp1/include/boot_api.h b/plat/st/stm32mp1/include/boot_api.h +index 71c3593..5953e6e 100644 +--- a/plat/st/stm32mp1/include/boot_api.h ++++ b/plat/st/stm32mp1/include/boot_api.h +@@ -1,13 +1,108 @@ + /* +- * Copyright (c) 2017, STMicroelectronics - All Rights Reserved ++ * Copyright (c) 2017-2018, STMicroelectronics - All Rights Reserved + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +-#ifndef __BOOT_API_H +-#define __BOOT_API_H ++#ifndef BOOT_API_H ++#define BOOT_API_H + + #include ++#include ++ ++/* ++ * Exported constants ++ */ ++ ++/* ++ * Boot Context related definitions ++ */ ++ ++/* ++ * Possible value of boot context field 'boot_action' ++ */ ++/* Boot action is Process Cold Boot */ ++#define BOOT_API_CTX_BOOT_ACTION_COLD_BOOT_PROCESS 0x09U ++/* Boot action is Process Wakeup from CSTANDBY */ ++#define BOOT_API_CTX_BOOT_ACTION_WAKEUP_CSTANDBY 0x0AU ++/* Boot action is Process Wakeup from STANDBY */ ++#define BOOT_API_CTX_BOOT_ACTION_WAKEUP_STANDBY 0x0BU ++/* Boot action is Process Engineering Boot */ ++#define BOOT_API_CTX_BOOT_ACTION_ENGI_BOOT 0x0CU ++ ++#define BOOT_API_CTX_BOOT_ACTION_MPU_CORE0_RESET_PROCESS 0x0F ++ ++/* ++ * Possible value of boot context field 'stby_exit_status' ++ */ ++ ++/* The boot reason is not a STANDBY Exit reason */ ++#define BOOT_API_CTX_STBY_EXIT_STATUS_NO_STANDBY 0x00 ++ ++/* STANDBY Exit with MPU_BEN=1, MCU_BEN=0 */ ++#define BOOT_API_CTX_STBY_EXIT_STATUS_WKUP_MPU_ONLY 0x01 ++ ++/* ++ * STANDBY Exit with MPU_BEN=1, MCU_BEN=1, MPU will go for cold boot ++ * MCU restarted by bootROM ++ */ ++#define BOOT_API_CTX_STBY_EXIT_STATUS_WKUP_ALL_CORES 0x02 ++ ++/* ++ * STANDBY Exit with MPU_BEN=1, MCU_BEN=1, MPU will go for cold boot ++ * but MCU restart aborted (code integrity check) : have not been restarted ++ * by bootROM ++ */ ++#define BOOT_API_CTX_STBY_EXIT_STATUS_WKUP_ALL_CORES_MCU_ABT 0x03 ++ ++/* ++ * STANDBY Exit with MPU_BEN=0, MCU_BEN=1, MPU gone to CSTANDBY, ++ * MCU restarted correctly by bootROM ++ * This value should never be read by FSBL, because not executed in that case ++ */ ++#define BOOT_API_CTX_STBY_EXIT_STATUS_WKUP_MCU_ONLY 0x04 ++ ++/* ++ * STANDBY Exit with MPU_BEN=0, MCU_BEN=1, MCU restart aborted ++ * due code integrity check, then MPU will go for cold boot despite ++ * was not planned initially ++ */ ++#define BOOT_API_CTX_STBY_EXIT_STATUS_WKUP_MCU_ONLY_MCU_ABT 0x05 ++ ++/* ++ * STANDBY Exit with MPU_BEN=1, MCU_BEN=1, MCU restart aborted ++ * due to MCU security perimeter issue ++ */ ++#define \ ++BOOT_API_CTX_STBY_EXIT_STATUS_WKUP_ALL_CORES_MCU_ABT_SEC_PERIMETER_ISSUE 0x06 ++ ++/* ++ * STANDBY Exit with MPU_BEN=0, MCU_BEN=1, MCU restart aborted ++ * due to MCU security perimeter issue, then MPU will go for cold boot ++ * despite was not planned initially ++ */ ++#define \ ++BOOT_API_CTX_STBY_EXIT_STATUS_WKUP_MCU_ONLY_MCU_ABT_SEC_PERIMETER_ISSUE 0x07 ++ ++/* ++ * Possible value of boot context field 'cstby_exit_status' ++ */ ++/* The boot reason is not a CSTANDBY Exit reason */ ++#define BOOT_API_CTX_CSTBY_EXIT_STATUS_NO_CSTBY 0x00 ++/* CSTANDBY Exit with MCU detected as Not running */ ++#define BOOT_API_CTX_CSTBY_EXIT_STATUS_MCU_NOT_RUNNING 0x01 ++/* CSTANDBY Exit with MCU detected as Running */ ++#define BOOT_API_CTX_CSTBY_EXIT_STATUS_MCU_RUNNING 0x02 ++ ++/* ++ * Possible value of boot context field 'auth_status' ++ */ ++ /* No authentication done */ ++#define BOOT_API_CTX_AUTH_NO 0x00 ++ /* Authentication done and failed */ ++#define BOOT_API_CTX_AUTH_FAILED 0x01 ++ /* Authentication done and success */ ++#define BOOT_API_CTX_AUTH_SUCCESS 0x02 + + /* + * Possible value of boot context field 'boot_interface_sel' +@@ -22,6 +117,21 @@ + /* Boot occurred on EMMC */ + #define BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_EMMC 0x2U + ++/* boot occurred on NAND FMC */ ++#define BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_NAND_FMC 0x3U ++ ++/* boot occurred on QSPI NOR */ ++#define BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_NOR_QSPI 0x4U ++ ++/* boot occurred on UART */ ++#define BOOT_API_CTX_BOOT_INTERFACE_SEL_SERIAL_UART 0x5U ++ ++/* boot occurred on USB */ ++#define BOOT_API_CTX_BOOT_INTERFACE_SEL_SERIAL_USB 0x6U ++ ++/* boot occurred on NAND QSPI */ ++#define BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_NAND_QSPI 0x7U ++ + /** + * @brief Possible value of boot context field 'EmmcXferStatus' + */ +@@ -45,6 +155,10 @@ + #define BOOT_API_CTX_EMMC_ERROR_STATUS_HEADER_SIZE_ZERO 0x6U + #define BOOT_API_CTX_EMMC_ERROR_STATUS_IMAGE_NOT_COMPLETE 0x7U + ++/* Definitions relative to 'p_rom_version_info->platform_type_ver' field */ ++#define BOOT_API_CTX_ROM_VERSION_PLAT_VER_IC_EMU_FPGA 0xAA ++#define BOOT_API_CTX_ROM_VERSION_PLAT_VER_FPGA_ONLY 0xBB ++ + /* Image Header related definitions */ + + /* Definition of header version */ +@@ -76,6 +190,64 @@ + #define BOOT_API_A7_CORE1_MAGIC_NUMBER 0xCA7FACE1U + + /* ++ * MCU Code Integrity Check related definitions ++ */ ++ ++/* ++ * Defines to identify RTC backup registers to be used for MCU code integrity ++ * check ++ */ ++ ++/* ++ * TAMP_BCK0R contains two bits ++ * bit 0 : wanted value of 'RCC_TZCR.TZEN' ++ * bit 1 : wanted value of 'RCC_TZCR.MCKPROT' ++ */ ++ ++/* ++ * TAMP_BCK0R bit position coding wanted value of 'RCC_TZCR.TZEN' ++ * trustZone aware domain enabling/disabling ++ */ ++#define BOOT_API_MCIC_MCU_SECURITY_PERIMETER_TZEN_BIT 0 ++ ++/* ++ * TAMP_BCK0R bit position coding wanted value of 'RCC_TZCR.MCKPROT' ++ * ability of MCU to modify some clock settings in RCC ++ */ ++#define BOOT_API_MCIC_MCU_SECURITY_PERIMETER_MCKPROT_BIT 1 ++ ++/* TAMP_BCK0R register index */ ++#define \ ++BOOT_API_MCIC_MCU_SECURITY_PERIMETER_TZEN_MCKPROT_TAMP_BCK_REG_IDX 0 ++ ++/* ++ * TAMP_BCK1R register index ++ * This register is coding the wanted value of register 'EXTI_TZENR1' ++ * to be programmed by bootROM on wakeup from STANDBY when MCUBEN=1 ++ * that is MCU quick restart requested ++ */ ++#define \ ++BOOT_API_MCIC_MCU_SECURITY_PERIMETER_EXTI_TZENR1_TAMP_BCK_REG_IDX 1 ++ ++/* ++ * TAMP_BCK2R register index ++ * This register is coding the wanted value of register 'EXTI_TZENR2' ++ * to be programmed by bootROM on wakeup from STANDBY when MCUBEN=1 ++ * that is MCU quick restart requested ++ */ ++#define \ ++BOOT_API_MCIC_MCU_SECURITY_PERIMETER_EXTI_TZENR2_TAMP_BCK_REG_IDX 2 ++ ++/* ++ * TAMP_BCK3R register index ++ * This register is coding the wanted value of register 'EXTI_TZENR3' ++ * to be programmed by bootROM on wakeup from STANDBY when MCUBEN=1 ++ * that is MCU quick restart requested ++ */ ++#define \ ++BOOT_API_MCIC_MCU_SECURITY_PERIMETER_EXTI_TZENR3_TAMP_BCK_REG_IDX 3 ++ ++/* + * TAMP_BCK4R register index + * This register is used to write a Magic Number in order to restart + * Cortex A7 Core 1 and make it execute @ branch address from TAMP_BCK5R +@@ -90,6 +262,39 @@ + #define BOOT_API_CORE1_BRANCH_ADDRESS_TAMP_BCK_REG_IDX 5U + + /* ++ * TAMP_BCK22R register index ++ * This register contains offset in bytes of code to Hash in RETRAM region ++ * Note : offset is intended as relative value from start of RETRAM ++ */ ++#define \ ++BOOT_API_MCIC_OFFSET_IN_BYTES_CODE_TO_HASH_RETRAM_TAMP_BCK_REG_IDX 22 ++ ++/* ++ * TAMP_BCK23R register index ++ * This register contains the size in bytes of the single consecutive region ++ * of MCU Firmware in RETRAM (Retention RAM) to hash (by SHA-256) ++ * Note : This is required as a MCU firmware Code Integrity Check (aka : MCIC) ++ * to avoid bootROM restarting MCU on a corrupted firmware ++ */ ++#define \ ++BOOT_API_MCIC_RETRAM_REGION_TO_HASH_IN_BYTES_TAMP_BCK_REG_IDX 23 ++ ++/* ++ * TAMP_BCK24R to TAMP_BCK31R register indexes ++ * Those registers contains SHA-256 digest of RETRAM MCU Firmware code between ++ * [(RETRAM_start + offset) -- (RETRAM_start + offset + size_to_hash)] ++ * in this order ++ * This is the MCU Code Integrity Check MCU Firmware signature ++ * value on 256 bits ++ */ ++ ++/* First TAMP_BKP index of MCU Firmware signature : ie TAMP_BCK24R */ ++#define BOOT_API_MCIC_SHA_DIGEST_FIRST_TAMP_BCK_REG_IDX 24 ++ ++/* Last TAMP_BKP index of MCU Firmware signature : ie TAMP_BCK31R */ ++#define BOOT_API_MCIC_SHA_DIGEST_LAST_TAMP_BCK_REG_IDX 31 ++ ++/* + * Possible value of boot context field 'hse_clock_value_in_hz' + */ + #define BOOT_API_CTX_HSE_CLOCK_VALUE_UNDEFINED 0U +@@ -113,6 +318,57 @@ + /* Closed = OTP_CFG0[6] */ + #define BOOT_API_OTP_MODE_CLOSED_BIT_POS 6 + ++/* Mapping of OTP Word and OTP bits managing SSP and useful to FSBL-SSP */ ++/* OTP_CFG8 */ ++#define BOOT_API_OTP_SSP_WORD_NB 8U ++/* SSP_REQ = OTP_CFG8[8] */ ++#define BOOT_API_OTP_SSP_REQ_BIT_POS 8 ++/* SSP_SUCCESS = OTP_CFG8[9] */ ++#define BOOT_API_OTP_SSP_SUCCESS_BIT_POS 9 ++ ++/* ++ * Possible values of boot context field ++ * 'ssp_config_ptr_in->ssp_cmd' ++ */ ++/* 'K' 'B' 'U' 'P' -.> 'PUBK' */ ++#define BOOT_API_CTX_SSP_CMD_CALC_CHIP_PUBK 0x4B425550 ++ ++/* ++ * Exported types ++ */ ++ ++/* SSP Configuration structure */ ++typedef struct { ++ /* SSP Command*/ ++ uint32_t ssp_cmd; ++ uint8_t reserved[20]; ++} boot_api_ssp_config_t; ++ ++/* ++ * bootROM version information structure definition ++ * Total size = 24 bytes = 6 uint32_t ++ */ ++typedef struct { ++ /* Chip Version */ ++ uint32_t chip_ver; ++ ++ /* Cut version within a fixed chip version */ ++ uint32_t cut_ver; ++ ++ /* Version of ROM Mask within a fixed cut version */ ++ uint32_t rom_mask_ver; ++ ++ /* Internal Version of bootROM code */ ++ uint32_t bootrom_ver; ++ ++ /* Version of bootROM adapted */ ++ uint32_t for_chip_design_rtl_ver; ++ ++ /* Restriction on compiled platform when it applies */ ++ uint32_t platform_type_ver; ++ ++} boot_api_rom_version_info_t; ++ + /* + * Boot Context related definitions + */ +@@ -129,9 +385,133 @@ typedef struct { + */ + uint16_t boot_interface_selected; + uint16_t boot_interface_instance; +- uint32_t reserved1[13]; ++ uint32_t reserved1; ++ uint32_t nand_data_width; ++ uint32_t nand_block_size; ++ uint32_t nand_page_size; ++ uint32_t reserved2; ++ uint32_t nand_ecc_bits; ++ uint32_t nand_block_nb; ++ uint32_t reserved3[4]; ++ uint32_t nor_isdual; ++ uint32_t usb_context; + uint32_t otp_afmux_values[3]; +- uint32_t reserved[9]; ++ uint32_t reserved[2]; ++ /* ++ * Log to boot context, what was the kind of boot action ++ * takes values from defines BOOT_API_BOOT_ACTION_XXX above ++ */ ++ uint32_t boot_action; ++ /* ++ * STANDBY Exit status to be checked by FSBL in case ++ * field 'boot_action' == BOOT_API_CTX_BOOT_ACTION_WAKEUP_STANDBY ++ * take values from defines above 'BOOT_API_CTX_STBY_EXIT_STATUS_XXX' ++ * depending on encountered situation ++ */ ++ uint32_t stby_exit_status; ++ /* ++ * CSTANDBY Exit status to be checked by FSBL in case ++ * boot_action == BOOT_API_CTX_BOOT_ACTION_WAKEUP_CSTANDBY ++ * take values from defines above 'BOOT_API_CTX_CSTBY_EXIT_STATUS_XXX' ++ * depending on encountered situation ++ */ ++ uint32_t cstby_exit_status; ++ /* ++ * Returned authentication status : take values from defines ++ * BOOT_API_CTX_AUTH_XXX above ++ */ ++ uint32_t auth_status; ++ ++ /* ++ ******************************************************* ++ * Pointers to bootROM External Secure Services ++ * External Secure Services offered by bootROM ++ * - ECDSA check key ++ * - ECDSA verify signature ++ * - ECDSA verify signature and go ++ ******************************************************* ++ */ ++ /* ++ * Check if hash of p_pub_key_in is equal to hash by SHA-256 ++ * of OEM public key from OTP ++ * ++ * If no: => infinite loop in bootROM : boot failed ++ * ++ * else: copy p_pub_key_in to p_pub_key_out if ++ * p_pub_key_out not NULL. ++ * and return to caller. ++ * ++ * @param[in] p_pub_key_in points to an ECDSA public key : ++ * Very Important : address alignment constraint : ++ * This address should be multiple of 4 bytes only. ++ * @param[in/out] p_pub_key_out points to area where to store copy ++ * of public key. ++ * Very Important : address alignment constraint : ++ * This address should be multiple of 4 bytes only. ++ * @retval STD_OK (0x77) or STD_NOT_OK (0x66) ++ */ ++ uint32_t (*p_bootrom_ext_service_ecdsa_check_key) ++ (uint8_t *p_pub_key_in, ++ uint8_t *p_pub_key_out); ++ /* ++ * verify ECDSA signature ++ * ++ * Decrypt EDCSA signature from 'p_signature' ++ * using public key passed in parameter 'p_pub_key_in' ++ * Then compare it to hash from 'p_hash_in' (SHA-256) ++ * ++ * If no match: => infinite loop in bootROM ++ * ++ * else: return to caller ++ * ++ * @param[in] p_hash_in : points on hash in (SHA-256) ++ * Very Important : address alignment constraint : ++ * This address should be multiple of 4 bytes only. ++ * @param[in] p_pub_key_in : points to an ECDSA public key ++ * Very Important : address alignment constraint : ++ * This address should be multiple of 4 bytes only. ++ * @param[in] p_signature : points to an EDCSA signature. ++ * Very Important : address alignment constraint : ++ * This address should be multiple of 4 bytes only. ++ * @param[in] ecc_algo : Ecc algorithm to be used P256 NIST or ++ * Brain_pool 256. ++ * ++ * @retval STD_OK (0x77) or STD_NOT_OK (0x66) ++ */ ++ uint32_t (*p_bootrom_ext_service_ecdsa_verify_signature) ++ (uint8_t *p_hash_in, uint8_t *p_pub_key_in, ++ uint8_t *p_signature, uint32_t ecc_algo); ++ /* ++ * verify ECDSA signature and branch to entry point if match ++ * ++ * Decrypt EDCSA signature from 'p_signature' ++ * using public key passed in parameter 'p_pub_key_in' ++ * Then compare it to hash from 'p_hash_in' (SHA-256) ++ * ++ * If no match: => infinite loop in bootROM ++ * ++ * else: branch CA7-0 to branch address 'p_entry_in' ++ * ++ * @param[in] p_hash_in : points on hash in (SHA-256) ++ * Very Important : address alignment constraint : ++ * This address should be multiple of 4 bytes only. ++ * @param[in] p_pub_key_in : points to an ECDSA public key ++ * Very Important : address alignment constraint : ++ * This address should be multiple of 4 bytes only. ++ * @param[in] p_signature : points to an EDCSA signature. ++ * Very Important : address alignment constraint : ++ * This address should be multiple of 4 bytes only. ++ * @param[in] ecc_algo : Ecc algorithm to be used P256 NIST or ++ * Brain_pool 256. ++ * @param[in] p_entry_in : points to branch entry point. ++ * ++ * @retval STD_NOT_OK (0x66) ++ */ ++ uint32_t (*p_bootrom_ext_service_ecdsa_verify_and_go) ++ (uint8_t *p_hash_in, uint8_t *p_pub_key_in, ++ uint8_t *p_signature_in, uint32_t ecc_algo, ++ uint32_t *p_entry_in); ++ + /* + * Information specific to an SD boot + * Updated each time an SD boot is at least attempted, +@@ -161,6 +541,21 @@ typedef struct { + * ie FSBL partition on which the boot was successful + */ + uint32_t boot_partition_used_toboot; ++ /* ++ * Address of SSP configuration structure : ++ * given and defined by bootROM ++ * and used by FSBL. The structure is of type ++ * 'boot_api_ssp_config_t' ++ */ ++ boot_api_ssp_config_t *p_ssp_config; ++ /* ++ * boot context field containing bootROM updated SSP Status ++ * Values can be of type BOOT_API_CTX_SSP_STATUS_XXX ++ */ ++ uint32_t ssp_status; ++ ++ /* Pointer on ROM constant containing ROM information */ ++ const boot_api_rom_version_info_t *p_rom_version_info; + + } __packed boot_api_context_t; + +@@ -229,7 +624,9 @@ typedef struct { + */ + uint8_t ecc_pubk[BOOT_API_ECDSA_PUB_KEY_LEN_IN_BYTES]; + /* Pad up to 256 byte total size */ +- uint8_t pad[84]; ++ uint8_t pad[83]; ++ /* Add binary type information */ ++ uint8_t binary_type; + } __packed boot_api_image_header_t; + +-#endif /* __BOOT_API_H */ ++#endif /* BOOT_API_H */ +diff --git a/plat/st/stm32mp1/include/platform_def.h b/plat/st/stm32mp1/include/platform_def.h +index 47e1ffc..fd1ccbf 100644 +--- a/plat/st/stm32mp1/include/platform_def.h ++++ b/plat/st/stm32mp1/include/platform_def.h +@@ -24,12 +24,22 @@ + #define PLATFORM_STACK_SIZE 0xC00 + #endif + ++#ifdef AARCH32_SP_OPTEE ++#define OPTEE_HEADER_IMAGE_NAME "teeh" ++#define OPTEE_PAGED_IMAGE_NAME "teed" ++#define OPTEE_PAGER_IMAGE_NAME "teex" ++#define OPTEE_HEADER_BINARY_TYPE U(0x20) ++#define OPTEE_PAGER_BINARY_TYPE U(0x21) ++#define OPTEE_PAGED_BINARY_TYPE U(0x22) ++#endif ++ + /* SSBL = second stage boot loader */ + #define BL33_IMAGE_NAME "ssbl" ++#define BL33_BINARY_TYPE U(0x0) + +-#define STM32MP1_PRIMARY_CPU U(0x0) ++#define STM32MP_PRIMARY_CPU U(0x0) ++#define STM32MP_SECONDARY_CPU U(0x1) + +-#define PLATFORM_CACHE_LINE_SIZE 64 + #define PLATFORM_CLUSTER_COUNT ULL(1) + #define PLATFORM_CLUSTER0_CORE_COUNT U(2) + #define PLATFORM_CLUSTER1_CORE_COUNT U(0) +@@ -37,8 +47,9 @@ + PLATFORM_CLUSTER0_CORE_COUNT) + #define PLATFORM_MAX_CPUS_PER_CLUSTER 2 + +-#define MAX_IO_DEVICES 4 +-#define MAX_IO_HANDLES 4 ++#define MAX_IO_DEVICES U(4) ++#define MAX_IO_HANDLES U(4) ++#define MAX_IO_BLOCK_DEVICES U(1) + + /******************************************************************************* + * BL2 specific defines. +@@ -47,39 +58,45 @@ + * Put BL2 just below BL3-1. BL2_BASE is calculated using the current BL2 debug + * size plus a little space for growth. + */ +-#define BL2_BASE STM32MP1_BL2_BASE +-#define BL2_LIMIT (STM32MP1_BL2_BASE + \ +- STM32MP1_BL2_SIZE) ++#define BL2_BASE STM32MP_BL2_BASE ++#define BL2_LIMIT (STM32MP_BL2_BASE + \ ++ STM32MP_BL2_SIZE) + + /******************************************************************************* + * BL32 specific defines. + ******************************************************************************/ +-#define BL32_BASE STM32MP1_BL32_BASE +-#define BL32_LIMIT (STM32MP1_BL32_BASE + \ +- STM32MP1_BL32_SIZE) ++#ifndef AARCH32_SP_OPTEE ++#define BL32_BASE STM32MP_BL32_BASE ++#define BL32_LIMIT (STM32MP_BL32_BASE + \ ++ STM32MP_BL32_SIZE) ++#endif + + /******************************************************************************* + * BL33 specific defines. + ******************************************************************************/ +-#define BL33_BASE STM32MP1_BL33_BASE ++#define BL33_BASE STM32MP_BL33_BASE + + /* + * Load address of BL33 for this platform port + */ +-#define PLAT_STM32MP1_NS_IMAGE_OFFSET BL33_BASE ++#define PLAT_STM32MP_NS_IMAGE_OFFSET BL33_BASE ++ ++/* need by flash programmer */ ++#define FLASHLAYOUT_BASE STM32MP_DDR_BASE ++#define FLASHLAYOUT_LIMIT STM32MP_BL33_BASE + + /******************************************************************************* + * DTB specific defines. + ******************************************************************************/ +-#define DTB_BASE STM32MP1_DTB_BASE +-#define DTB_LIMIT (STM32MP1_DTB_BASE + \ +- STM32MP1_DTB_SIZE) ++#define DTB_BASE STM32MP_DTB_BASE ++#define DTB_LIMIT (STM32MP_DTB_BASE + \ ++ STM32MP_DTB_SIZE) + + /******************************************************************************* + * Platform specific page table and MMU setup constants + ******************************************************************************/ +-#define PLAT_PHY_ADDR_SPACE_SIZE (1ULL << 32) +-#define PLAT_VIRT_ADDR_SPACE_SIZE (1ULL << 32) ++#define PLAT_PHY_ADDR_SPACE_SIZE (ULL(1) << 32) ++#define PLAT_VIRT_ADDR_SPACE_SIZE (ULL(1) << 32) + + /******************************************************************************* + * Declarations and constants to access the mailboxes safely. Each mailbox is +@@ -98,6 +115,8 @@ + */ + #define ARM_IRQ_SEC_PHY_TIMER U(29) + ++#define ARM_IRQ_NON_SEC_SGI_0 U(0) ++ + #define ARM_IRQ_SEC_SGI_0 U(8) + #define ARM_IRQ_SEC_SGI_1 U(9) + #define ARM_IRQ_SEC_SGI_2 U(10) +@@ -107,7 +126,15 @@ + #define ARM_IRQ_SEC_SGI_6 U(14) + #define ARM_IRQ_SEC_SGI_7 U(15) + ++/* Platform IRQ Priority */ ++#define STM32MP1_IRQ_RCC_SEC_PRIO U(0x6) ++#define STM32MP1_IRQ_SEC_SPI_PRIO U(0x10) ++ + #define STM32MP1_IRQ_TZC400 U(36) ++#define STM32MP1_IRQ_MCU_SEV U(176) ++#define STM32MP1_IRQ_RCC_WAKEUP U(177) ++#define STM32MP1_IRQ_IWDG1 U(182) ++#define STM32MP1_IRQ_IWDG2 U(183) + #define STM32MP1_IRQ_TAMPSERRS U(229) + #define STM32MP1_IRQ_AXIERRIRQ U(244) + +@@ -120,9 +147,6 @@ + INTR_PROP_DESC(ARM_IRQ_SEC_PHY_TIMER, \ + GIC_HIGHEST_SEC_PRIORITY, \ + grp, GIC_INTR_CFG_LEVEL), \ +- INTR_PROP_DESC(STM32MP1_IRQ_TAMPSERRS, \ +- GIC_HIGHEST_SEC_PRIORITY, \ +- grp, GIC_INTR_CFG_LEVEL), \ + INTR_PROP_DESC(STM32MP1_IRQ_AXIERRIRQ, \ + GIC_HIGHEST_SEC_PRIORITY, \ + grp, GIC_INTR_CFG_LEVEL), \ +diff --git a/plat/st/stm32mp1/include/stm32mp1_context.h b/plat/st/stm32mp1/include/stm32mp1_context.h +index fd08afc..4cd6643 100644 +--- a/plat/st/stm32mp1/include/stm32mp1_context.h ++++ b/plat/st/stm32mp1/include/stm32mp1_context.h +@@ -4,11 +4,23 @@ + * SPDX-License-Identifier: BSD-3-Clause + */ + +-#ifndef __STM32MP1_CONTEXT_H__ +-#define __STM32MP1_CONTEXT_H__ ++#ifndef STM32MP1_CONTEXT_H ++#define STM32MP1_CONTEXT_H + ++#include + #include + ++#define DDR_CRC_GRANULE 32 ++ ++void stm32_clean_context(void); ++int stm32_save_context(uint32_t zq0cr0_zdata); ++int stm32_restore_context(void); ++int stm32_restore_backup_reg(void); ++uint32_t stm32_get_zdata_from_context(void); + int stm32_save_boot_interface(uint32_t interface, uint32_t instance); ++int stm32_get_boot_interface(uint32_t *interface, uint32_t *instance); ++void stm32_save_ddr_training_area(void); ++void stm32_restore_ddr_training_area(void); ++uint32_t stm32_pm_get_optee_ep(void); + +-#endif /* __STM32MP1_CONTEXT_H__ */ ++#endif /* STM32MP1_CONTEXT_H */ +diff --git a/plat/st/stm32mp1/include/stm32mp1_dbgmcu.h b/plat/st/stm32mp1/include/stm32mp1_dbgmcu.h +new file mode 100644 +index 0000000..fd97a16 +--- /dev/null ++++ b/plat/st/stm32mp1/include/stm32mp1_dbgmcu.h +@@ -0,0 +1,26 @@ ++/* ++ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. ++ * ++ * SPDX-License-Identifier: BSD-3-Clause ++ */ ++ ++#ifndef __PLAT_DBGMCU_H__ ++#define __PLAT_DBGMCU_H__ ++ ++#include ++ ++#if LOG_LEVEL >= LOG_LEVEL_VERBOSE ++#define VERBOSE_HEXDUMP8(buf, len) stm32mp1_dbgmcu_hexdump8(buf, len) ++#else ++#define VERBOSE_HEXDUMP8(buf, len) ++#endif ++ ++uint32_t stm32mp1_dbgmcu_get_chip_version(void); ++uint32_t stm32mp1_dbgmcu_get_chip_dev_id(void); ++int stm32mp1_dbgmcu_freeze_iwdg2(void); ++int stm32mp1_dbgmcu_boot_debug_info(void); ++int stm32mp1_dbgmcu_clear_boot_info(void); ++uint32_t stm32mp1_dbgmcu_is_debug_on(void); ++void stm32mp1_dbgmcu_hexdump8(uint8_t *buf, uint32_t len); ++ ++#endif /* __PLAT_DBGMCU_H__ */ +diff --git a/plat/st/stm32mp1/include/stm32mp1_dt.h b/plat/st/stm32mp1/include/stm32mp1_dt.h +deleted file mode 100644 +index 58e10d1..0000000 +--- a/plat/st/stm32mp1/include/stm32mp1_dt.h ++++ /dev/null +@@ -1,41 +0,0 @@ +-/* +- * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. +- * +- * SPDX-License-Identifier: BSD-3-Clause +- */ +- +-#ifndef __STM32MP1_DT_H__ +-#define __STM32MP1_DT_H__ +- +-#include +- +-struct dt_node_info { +- uint32_t base; +- int32_t clock; +- int32_t reset; +- bool status; +- bool sec_status; +-}; +- +-/******************************************************************************* +- * Function and variable prototypes +- ******************************************************************************/ +-int dt_open_and_check(void); +-int fdt_get_address(void **fdt_addr); +-bool fdt_check_node(int node); +-bool fdt_check_status(int node); +-bool fdt_check_secure_status(int node); +-uint32_t fdt_read_uint32_default(int node, const char *prop_name, +- uint32_t dflt_value); +-int fdt_read_uint32_array(int node, const char *prop_name, +- uint32_t *array, uint32_t count); +-int dt_set_pinctrl_config(int node); +-int dt_set_stdout_pinctrl(void); +-void dt_fill_device_info(struct dt_node_info *info, int node); +-int dt_get_node(struct dt_node_info *info, int offset, const char *compat); +-int dt_get_stdout_uart_info(struct dt_node_info *info); +-int dt_get_stdout_node_offset(void); +-uint32_t dt_get_ddr_size(void); +-const char *dt_get_board_model(void); +- +-#endif /* __STM32MP1_DT_H__ */ +diff --git a/plat/st/stm32mp1/include/stm32mp1_low_power.h b/plat/st/stm32mp1/include/stm32mp1_low_power.h +new file mode 100644 +index 0000000..a9b2778 +--- /dev/null ++++ b/plat/st/stm32mp1/include/stm32mp1_low_power.h +@@ -0,0 +1,19 @@ ++/* ++ * Copyright (c) 2017-2018, STMicroelectronics - All Rights Reserved ++ * ++ * SPDX-License-Identifier: BSD-3-Clause ++ */ ++ ++#ifndef STM32MP1_LOW_POWER_H ++#define STM32MP1_LOW_POWER_H ++ ++#include ++#include ++ ++void stm32_rcc_wakeup_update(bool state); ++void stm32_apply_pmic_suspend_config(uint32_t mode); ++void stm32_exit_cstop(void); ++void stm32_pwr_down_wfi(void); ++void stm32_enter_low_power(uint32_t mode, uint32_t nsec_addr); ++ ++#endif /* STM32MP1_LOW_POWER_H */ +diff --git a/plat/st/stm32mp1/include/stm32mp1_power_config.h b/plat/st/stm32mp1/include/stm32mp1_power_config.h +new file mode 100644 +index 0000000..bcee6b6 +--- /dev/null ++++ b/plat/st/stm32mp1/include/stm32mp1_power_config.h +@@ -0,0 +1,28 @@ ++/* ++ * Copyright (c) 2017-2018, STMicroelectronics - All Rights Reserved ++ * ++ * SPDX-License-Identifier: BSD-3-Clause ++ */ ++ ++#ifndef STM32MP1_POWER_CONFIG_H ++#define STM32MP1_POWER_CONFIG_H ++ ++#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 ++}; ++ ++void stm32mp1_init_lp_states(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); ++ ++#endif /* STM32MP1_POWER_CONFIG_H */ +diff --git a/plat/st/stm32mp1/include/stm32mp1_private.h b/plat/st/stm32mp1/include/stm32mp1_private.h +index a789d53..cc6c9e7 100644 +--- a/plat/st/stm32mp1/include/stm32mp1_private.h ++++ b/plat/st/stm32mp1/include/stm32mp1_private.h +@@ -1,22 +1,38 @@ + /* +- * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. ++ * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +-#ifndef __STM32MP1_PRIVATE_H__ +-#define __STM32MP1_PRIVATE_H__ ++#ifndef STM32MP1_PRIVATE_H ++#define STM32MP1_PRIVATE_H ++ ++#include ++#include ++#include ++ ++enum boot_device_e { ++ BOOT_DEVICE_USB, ++ BOOT_DEVICE_BOARD ++}; + +-void stm32mp1_io_setup(void); + void configure_mmu(void); + + void stm32mp1_arch_security_setup(void); + void stm32mp1_security_setup(void); ++void stm32mp1_sp_min_security_setup(void); ++ ++enum boot_device_e get_boot_device(void); + +-void stm32mp1_save_boot_ctx_address(uintptr_t address); +-uintptr_t stm32mp1_get_boot_ctx_address(void); ++#if STM32MP_UART_PROGRAMMER ++uintptr_t get_uart_address(uint32_t instance_nb); ++#endif + + void stm32mp1_gic_pcpu_init(void); + void stm32mp1_gic_init(void); + +-#endif /* __STM32MP1_PRIVATE_H__ */ ++enum etzpc_decprot_attributes stm32mp_etzpc_binding2decprot(uint32_t mode); ++ ++void stm32mp1_syscfg_init(void); ++ ++#endif /* STM32MP1_PRIVATE_H */ +diff --git a/plat/st/stm32mp1/include/stm32mp1_shared_resources.h b/plat/st/stm32mp1/include/stm32mp1_shared_resources.h +new file mode 100644 +index 0000000..b161cab +--- /dev/null ++++ b/plat/st/stm32mp1/include/stm32mp1_shared_resources.h +@@ -0,0 +1,83 @@ ++/* SPDX-License-Identifier: BSD-3-Clause */ ++/* ++ * Copyright (c) 2017-2018, STMicroelectronics ++ */ ++ ++#ifndef STM32MP1_SHARED_RESOURCES_H ++#define STM32MP1_SHARED_RESOURCES_H ++ ++#include ++#include ++#include ++ ++void stm32mp_clk_enable(unsigned long id); ++void stm32mp_clk_disable(unsigned long id); ++ ++#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 stm32mp1_register_secure_periph(unsigned int id); ++void stm32mp1_register_shared_periph(unsigned int id); ++void stm32mp1_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 stm32mp1_register_etzpc_decprot(unsigned int id, ++ enum etzpc_decprot_attributes attr); ++ ++bool stm32mp1_periph_is_shared(unsigned long id); ++bool stm32mp1_periph_is_non_secure(unsigned long id); ++bool stm32mp1_periph_is_secure(unsigned long id); ++bool stm32mp1_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 stm32mp1_clock_is_shareable(unsigned long clock_id); ++bool stm32mp1_clock_is_shared(unsigned long clock_id); ++bool stm32mp1_clock_is_non_secure(unsigned long clock_id); ++ ++void stm32mp1_driver_init_late(void); ++ ++#endif /* STM32MP1_SHARED_RESOURCES_H */ +diff --git a/plat/st/stm32mp1/include/stm32mp1_smc.h b/plat/st/stm32mp1/include/stm32mp1_smc.h +new file mode 100644 +index 0000000..956493f +--- /dev/null ++++ b/plat/st/stm32mp1/include/stm32mp1_smc.h +@@ -0,0 +1,68 @@ ++/* ++ * Copyright (c) 2016-2018, STMicroelectronics - All Rights Reserved ++ * ++ * SPDX-License-Identifier: BSD-3-Clause ++ */ ++ ++#ifndef __STM32MP1_SMC_H__ ++#define __STM32MP1_SMC_H__ ++ ++#include ++ ++/* ++ * 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) ++ * https://developer.arm.com/docs/den0028/latest ++ */ ++ ++/* Secure Service access from Non-secure */ ++#define STM32_SMC_RCC 0x82001000 ++#define STM32_SMC_PWR 0x82001001 ++#define STM32_SMC_RCC_CAL 0x82001002 ++#define STM32_SMC_BSEC 0x82001003 ++ ++/* Low Power services */ ++#define STM32_SMC_SR_MODE 0x82001004 ++#define STM32_SMC_PD_DOMAIN 0x82001008 ++ ++/* SMC function IDs for SiP Service queries */ ++#define STM32_SIP_SVC_CALL_COUNT 0x8200ff00 ++#define STM32_SIP_SVC_UID 0x8200ff01 ++/* 0x8200ff02 is reserved */ ++#define STM32_SIP_SVC_VERSION 0x8200ff03 ++ ++/* STM32 SiP Service Calls version numbers */ ++#define STM32_SIP_SVC_VERSION_MAJOR 0x0 ++#define STM32_SIP_SVC_VERSION_MINOR 0x1 ++ ++/* Number of STM32 SiP Calls implemented */ ++#define STM32_COMMON_SIP_NUM_CALLS 10 ++ ++/* Register access service use for RCC/RTC/PWR */ ++#define STM32_SMC_REG_READ 0x0 ++#define STM32_SMC_REG_WRITE 0x1 ++#define STM32_SMC_REG_SET 0x2 ++#define STM32_SMC_REG_CLEAR 0x3 ++ ++/* Service for BSEC */ ++#define STM32_SMC_READ_SHADOW 0x01 ++#define STM32_SMC_PROG_OTP 0x02 ++#define STM32_SMC_WRITE_SHADOW 0x03 ++#define STM32_SMC_READ_OTP 0x04 ++#define STM32_SMC_READ_ALL 0x05 ++#define STM32_SMC_WRITE_ALL 0x06 ++ ++/* SMC error codes */ ++#define STM32_SMC_OK 0x00000000U ++#define STM32_SMC_NOT_SUPPORTED 0xFFFFFFFFU ++#define STM32_SMC_FAILED 0xFFFFFFFEU ++#define STM32_SMC_INVALID_PARAMS 0xFFFFFFFDU ++ ++/* DDR Self-Refresh modes */ ++#define STM32_SMC_SR_MODE_SSR 0x0 ++#define STM32_SMC_SR_MODE_ASR 0x1 ++#define STM32_SMC_SR_MODE_HSR 0x2 ++ ++#endif /* __STM32MP1_SMC_H__ */ +diff --git a/plat/st/stm32mp1/include/stm32mp1_usb_desc.h b/plat/st/stm32mp1/include/stm32mp1_usb_desc.h +new file mode 100644 +index 0000000..71cacb3 +--- /dev/null ++++ b/plat/st/stm32mp1/include/stm32mp1_usb_desc.h +@@ -0,0 +1,55 @@ ++/* ++ * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved. ++ * ++ * SPDX-License-Identifier: BSD-3-Clause ++ */ ++ ++#ifndef __USBD_DESC_H ++#define __USBD_DESC_H ++ ++#include ++ ++/* Max DFU Packet Size = 1024 bytes */ ++#define USBD_DFU_XFER_SIZE 1024 ++ ++#define TRANSFER_SIZE_BYTES(size) \ ++ ((uint8_t)((size) & 0xFF)), /* XFERSIZEB0 */\ ++ ((uint8_t)((size) >> 8)) /* XFERSIZEB1 */ ++ ++/* Descriptor of DFU interface 0 Alternate setting n */ ++#define USBD_DFU_IF_DESC(n) 0x09, /* Interface Descriptor size */\ ++ USB_DESC_TYPE_INTERFACE, /* descriptor type */\ ++ 0x00, /* Number of Interface */\ ++ (n), /* Alternate setting */\ ++ 0x00, /* bNumEndpoints*/\ ++ 0xFE, /* Application Specific Class Code */\ ++ 0x01, /* Device Firmware Upgrade Code */\ ++ 0x02, /* DFU mode protocol */ \ ++ USBD_IDX_INTERFACE_STR + (n) + 1 /* iInterface: ++ * Index of ++ * string ++ * descriptor ++ */ ++/* DFU1.1 Standard only supported */ ++#define USB_DFU_VERSION 0x0110 ++#define USBD_DESC_MAX_ITF_NUM 0x6 ++#define USB_DFU_CONFIG_DESC_SIZ 72 ++#define USB_DFU_DESC_SIZ 9 ++/* String size (1 byte) + type (1 byte) + 24 UTF16 characters */ ++/* (2 bytes per character) */ ++#define USB_SIZ_STRING_SERIAL (1 + 1 + (24 * 2)) ++#define USBD_MAX_STR_DESC_SIZ 0x100 ++#define USBD_VID 0x0483 ++#define USBD_PID 0xDF11 ++#define USBD_LANGID_STRING 0x409 ++#define USBD_MANUFACTURER_STRING "STMicroelectronics" ++#define USBD_PRODUCT_HS_STRING "DFU in HS Mode @Device ID /0x500, @Revision ID /0x0000" ++#define USBD_PRODUCT_FS_STRING "DFU in FS Mode @Device ID /0x500, @Revision ID /0x0000" ++#define USBD_CONFIGURATION_HS_STRING "DFU Config" ++#define USBD_INTERFACE_HS_STRING "DFU Interface" ++#define USBD_CONFIGURATION_FS_STRING "DFU Config" ++#define USBD_INTERFACE_FS_STRING "DFU Interface" ++ ++void stm32mp_usb_init_desc(usb_handle_t *pdev); ++ ++#endif /* __USBD_DESC_H */ +diff --git a/plat/st/stm32mp1/include/usb_ctx.h b/plat/st/stm32mp1/include/usb_ctx.h +new file mode 100644 +index 0000000..0046bd0 +--- /dev/null ++++ b/plat/st/stm32mp1/include/usb_ctx.h +@@ -0,0 +1,17 @@ ++/* ++ * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved. ++ * ++ * SPDX-License-Identifier: BSD-3-Clause ++ */ ++ ++#ifndef __USB_CTX_H ++#define __USB_CTX_H ++ ++#include ++ ++struct usb_ctx { ++ usb_handle_t *pusbd_device_ctx; ++ pcd_handle_t *phpcd_ctx; ++}; ++ ++#endif /* __USB_CTX_H */ +diff --git a/plat/st/stm32mp1/plat_bl2_mem_params_desc.c b/plat/st/stm32mp1/plat_bl2_mem_params_desc.c +index 6f5bc4c..4ef135e 100644 +--- a/plat/st/stm32mp1/plat_bl2_mem_params_desc.c ++++ b/plat/st/stm32mp1/plat_bl2_mem_params_desc.c +@@ -26,7 +26,9 @@ static bl_mem_params_node_t bl2_mem_params_descs[] = { + VERSION_2, entry_point_info_t, + SECURE | EXECUTABLE | EP_FIRST_EXE), + ++#if !defined(AARCH32_SP_OPTEE) + .ep_info.pc = BL32_BASE, ++#endif + .ep_info.spsr = SPSR_MODE32(MODE32_svc, SPSR_T_ARM, + SPSR_E_LITTLE, + DISABLE_ALL_EXCEPTIONS), +@@ -34,13 +36,48 @@ static bl_mem_params_node_t bl2_mem_params_descs[] = { + SET_STATIC_PARAM_HEAD(image_info, PARAM_EP, + VERSION_2, image_info_t, + IMAGE_ATTRIB_PLAT_SETUP), +- ++#if defined(AARCH32_SP_OPTEE) ++ /* optee header is loaded is SYSRAM above BL2 */ ++ .image_info.image_base = STM32MP_OPTEE_BASE, ++ .image_info.image_max_size = STM32MP_OPTEE_SIZE, ++#else + .image_info.image_base = BL32_BASE, + .image_info.image_max_size = BL32_LIMIT - BL32_BASE, +- ++#endif + .next_handoff_image_id = BL33_IMAGE_ID, + }, + ++#if defined(AARCH32_SP_OPTEE) ++ /* Fill BL32 external 1 image related information */ ++ { ++ .image_id = BL32_EXTRA1_IMAGE_ID, ++ ++ SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP, ++ VERSION_2, entry_point_info_t, ++ SECURE | NON_EXECUTABLE), ++ ++ SET_STATIC_PARAM_HEAD(image_info, PARAM_EP, ++ VERSION_2, image_info_t, ++ IMAGE_ATTRIB_SKIP_LOADING), ++ ++ .next_handoff_image_id = INVALID_IMAGE_ID, ++ }, ++ /* Fill BL32 external 2 image related information */ ++ { ++ .image_id = BL32_EXTRA2_IMAGE_ID, ++ ++ SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP, ++ VERSION_2, entry_point_info_t, ++ SECURE | NON_EXECUTABLE), ++ ++ SET_STATIC_PARAM_HEAD(image_info, PARAM_EP, ++ VERSION_2, image_info_t, ++ IMAGE_ATTRIB_SKIP_LOADING), ++ ++ .next_handoff_image_id = INVALID_IMAGE_ID, ++ }, ++#endif /* AARCH32_SP_OPTEE */ ++ + /* Fill BL33 related information */ + { + .image_id = BL33_IMAGE_ID, +@@ -49,7 +86,7 @@ static bl_mem_params_node_t bl2_mem_params_descs[] = { + VERSION_2, entry_point_info_t, + NON_SECURE | EXECUTABLE), + +- .ep_info.pc = PLAT_STM32MP1_NS_IMAGE_OFFSET, ++ .ep_info.pc = PLAT_STM32MP_NS_IMAGE_OFFSET, + .ep_info.spsr = SPSR_MODE32(MODE32_svc, SPSR_T_ARM, + SPSR_E_LITTLE, + DISABLE_ALL_EXCEPTIONS), +@@ -57,9 +94,9 @@ static bl_mem_params_node_t bl2_mem_params_descs[] = { + SET_STATIC_PARAM_HEAD(image_info, PARAM_EP, + VERSION_2, image_info_t, 0), + +- .image_info.image_base = PLAT_STM32MP1_NS_IMAGE_OFFSET, +- .image_info.image_max_size = STM32MP1_DDR_MAX_SIZE - +- (PLAT_STM32MP1_NS_IMAGE_OFFSET - STM32MP1_DDR_BASE), ++ .image_info.image_base = PLAT_STM32MP_NS_IMAGE_OFFSET, ++ .image_info.image_max_size = STM32MP_DDR_MAX_SIZE - ++ (PLAT_STM32MP_NS_IMAGE_OFFSET - STM32MP_DDR_BASE), + + .next_handoff_image_id = INVALID_IMAGE_ID, + } +diff --git a/plat/st/stm32mp1/plat_image_load.c b/plat/st/stm32mp1/plat_image_load.c +index 3c6d677..db53c37 100644 +--- a/plat/st/stm32mp1/plat_image_load.c ++++ b/plat/st/stm32mp1/plat_image_load.c +@@ -4,7 +4,23 @@ + * SPDX-License-Identifier: BSD-3-Clause + */ + ++#include ++#include ++#include ++#include ++#include + #include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include + + /******************************************************************************* + * This function flushes the data structures so that they are visible +@@ -12,14 +28,101 @@ + ******************************************************************************/ + void plat_flush_next_bl_params(void) + { ++ uint32_t version; ++ + flush_bl_params_desc(); ++ ++ CASSERT(STM32_TF_VERSION <= MAX_MONOTONIC_VALUE, ++ assert_stm32mp1_monotonic_counter_reach_max); ++ ++ /* Check if monotonic counter need to be incremented */ ++ ; ++ if (bsec_shadow_read_otp(&version, MONOTONIC_OTP) != BSEC_OK) { ++ ERROR("BSEC: MONOTONIC_OTP Error\n"); ++ panic(); ++ } ++ ++ INFO("read version %i current version %i\n", version, STM32_TF_VERSION); ++ ++ if ((version + 1U) < BIT(STM32_TF_VERSION)) { ++ uint32_t result; ++ ++ /* need to increment the monotonic counter */ ++ version = BIT(STM32_TF_VERSION) - 1U; ++ ++ result = bsec_program_otp(version, MONOTONIC_OTP); ++ if (result != BSEC_OK) { ++ ERROR("BSEC: MONOTONIC_OTP program Error %i\n", ++ result); ++ panic(); ++ } ++ INFO("Monotonic counter has been incremented value 0x%x\n", ++ version); ++ } + } + ++#ifdef AARCH32_SP_OPTEE ++static bool addr_inside_backupsram(uintptr_t addr) ++{ ++ return (addr >= STM32MP_BACKUP_RAM_BASE) && ++ (addr < (STM32MP_BACKUP_RAM_BASE + STM32MP_BACKUP_RAM_SIZE)); ++} ++#endif ++ + /******************************************************************************* + * This function returns the list of loadable images. + ******************************************************************************/ + bl_load_info_t *plat_get_bl_image_load_info(void) + { ++ boot_api_context_t *boot_context = ++ (boot_api_context_t *)stm32mp_get_boot_ctx_address(); ++#ifdef AARCH32_SP_OPTEE ++ bl_mem_params_node_t *bl32 = get_bl_mem_params_node(BL32_IMAGE_ID); ++#endif ++ bl_mem_params_node_t *bl33 = get_bl_mem_params_node(BL33_IMAGE_ID); ++ uint32_t rstsr = mmio_read_32(stm32mp_rcc_base() + RCC_MP_RSTSCLRR); ++ uint32_t bkpr_core1_addr = ++ tamp_bkpr(BOOT_API_CORE1_BRANCH_ADDRESS_TAMP_BCK_REG_IDX); ++ uintptr_t pwr_base = stm32mp_pwr_base(); ++ ++ /* ++ * If going back from CSTANDBY / STANDBY and DDR was in Self-Refresh, ++ * BL33 must not be loaded as it would overwrite the code already ++ * in DDR. For this, the BL33 part of the bl_mem_params_desc_ptr ++ * struct should be modified to skip its loading ++ */ ++ if (((boot_context->boot_action == ++ BOOT_API_CTX_BOOT_ACTION_WAKEUP_CSTANDBY) || ++ (boot_context->boot_action == ++ BOOT_API_CTX_BOOT_ACTION_WAKEUP_STANDBY)) && ++ ((mmio_read_32(pwr_base + PWR_CR3) & PWR_CR3_DDRSREN) != 0U) && ++ ((rstsr & RCC_MP_RSTSCLRR_PADRSTF) == 0U)) { ++ stm32mp_clk_enable(RTCAPB); ++ ++ if (mmio_read_32(bkpr_core1_addr) != 0U) { ++ bl33->image_info.h.attr |= IMAGE_ATTRIB_SKIP_LOADING; ++ ++#ifdef AARCH32_SP_OPTEE ++ bl32->image_info.h.attr |= IMAGE_ATTRIB_SKIP_LOADING; ++ bl32->ep_info.pc = stm32_pm_get_optee_ep(); ++ ++ if (addr_inside_backupsram(bl32->ep_info.pc)) { ++ stm32mp_clk_enable(BKPSRAM); ++ } ++#else ++ /* ++ * Set ep_info PC to 0, to inform BL32 it is a reset ++ * after STANDBY ++ */ ++ bl33->ep_info.pc = 0; ++#endif ++ } ++ ++ stm32mp_clk_disable(RTCAPB); ++ } ++ ++ bl33->image_info.image_max_size = dt_get_ddr_size(); ++ + return get_bl_load_info_from_mem_params_desc(); + } + +diff --git a/plat/st/stm32mp1/platform.mk b/plat/st/stm32mp1/platform.mk +index 30b2932..06594f0 100644 +--- a/plat/st/stm32mp1/platform.mk ++++ b/plat/st/stm32mp1/platform.mk +@@ -1,5 +1,5 @@ + # +-# Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. ++# Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved. + # + # SPDX-License-Identifier: BSD-3-Clause + # +@@ -8,24 +8,78 @@ ARM_CORTEX_A7 := yes + ARM_WITH_NEON := yes + BL2_AT_EL3 := 1 + USE_COHERENT_MEM := 0 ++MULTI_CONSOLE_API := 1 + ++# Please don't increment this value without good understanding of ++# the monotonic counter + STM32_TF_VERSION ?= 0 ++$(eval $(call add_define_val,STM32_TF_VERSION,${STM32_TF_VERSION})) ++ ++# Enable software PMIC programming in case of debug purpose ++STM32MP1_DEBUG_ENABLE ?= 1 ++$(eval $(call add_define_val,STM32MP1_DEBUG_ENABLE,${STM32MP1_DEBUG_ENABLE})) + + # Not needed for Cortex-A7 + WORKAROUND_CVE_2017_5715:= 0 + +-PLAT_INCLUDES := -Iplat/st/stm32mp1/include/ +-PLAT_INCLUDES += -Iinclude/common/tbbr ++# Specific modification for reset halt workaround ++STM32MP1_RESET_HALT_WORKAROUND ?= 1 ++$(eval $(call add_define,STM32MP1_RESET_HALT_WORKAROUND)) ++ ++AARCH32_EXCEPTION_DEBUG := 1 ++ ++ifeq ($(AARCH32_SP),optee) ++$(eval $(call add_define,AARCH32_SP_OPTEE)) ++endif ++ ++# Number of TF-A copies in the device ++STM32_TF_A_COPIES := 2 ++$(eval $(call add_define,STM32_TF_A_COPIES)) ++ifeq ($(AARCH32_SP),optee) ++PLAT_PARTITION_MAX_ENTRIES := $(shell echo $$(($(STM32_TF_A_COPIES) + 4))) ++else ++PLAT_PARTITION_MAX_ENTRIES := $(shell echo $$(($(STM32_TF_A_COPIES) + 1))) ++endif ++$(eval $(call add_define,PLAT_PARTITION_MAX_ENTRIES)) ++ ++# Boot devices ++STM32MP1_QSPI_NOR := 1 ++$(eval $(call add_define,STM32MP1_QSPI_NOR)) ++STM32MP_FMC_NAND := 1 ++$(eval $(call add_define,STM32MP_FMC_NAND)) ++STM32MP_EMMC := 1 ++$(eval $(call add_define,STM32MP_EMMC)) ++STM32MP_SDMMC := 1 ++$(eval $(call add_define,STM32MP_SDMMC)) ++STM32MP1_QSPI_NAND := 1 ++$(eval $(call add_define,STM32MP1_QSPI_NAND)) ++ ++ifeq ($(filter 1,${STM32MP1_QSPI_NOR} ${STM32MP_FMC_NAND} ${STM32MP_EMMC} ${STM32MP_SDMMC}),) ++$(error "No boot device driver is enabled") ++endif ++ ++STM32MP_UART_PROGRAMMER := 1 ++$(eval $(call add_define,STM32MP_UART_PROGRAMMER)) ++ ++PLAT_INCLUDES := -Iinclude/common/tbbr ++PLAT_INCLUDES += -Iinclude/drivers/partition + PLAT_INCLUDES += -Iinclude/drivers/st ++PLAT_INCLUDES += -Iplat/st/common/include/ ++PLAT_INCLUDES += -Iplat/st/stm32mp1/include/ ++ ++PLAT_INCLUDES += -Iinclude/lib/usb ++ ++STM32MP_USB := 1 + + # Device tree +-STM32_DTB_FILE_NAME ?= stm32mp157c-ev1.dtb +-FDT_SOURCES := $(addprefix fdts/, $(patsubst %.dtb,%.dts,$(STM32_DTB_FILE_NAME))) ++DTB_FILE_NAME ?= stm32mp157c-ev1.dtb ++FDT_SOURCES := $(addprefix fdts/, $(patsubst %.dtb,%.dts,$(DTB_FILE_NAME))) + DTC_FLAGS += -Wno-unit_address_vs_reg + + include lib/libfdt/libfdt.mk + +-PLAT_BL_COMMON_SOURCES := plat/st/stm32mp1/stm32mp1_common.c ++PLAT_BL_COMMON_SOURCES := plat/st/common/stm32mp_common.c \ ++ plat/st/stm32mp1/stm32mp1_private.c + + PLAT_BL_COMMON_SOURCES += drivers/console/aarch32/console.S \ + drivers/st/uart/aarch32/stm32_console.S +@@ -43,23 +97,56 @@ PLAT_BL_COMMON_SOURCES += ${LIBFDT_SRCS} \ + drivers/arm/tzc/tzc400.c \ + drivers/delay_timer/delay_timer.c \ + drivers/delay_timer/generic_delay_timer.c \ ++ drivers/st/bsec/bsec.c \ ++ drivers/st/clk/stm32mp_clkfunc.c \ + drivers/st/clk/stm32mp1_clk.c \ + drivers/st/clk/stm32mp1_clkfunc.c \ + drivers/st/ddr/stm32mp1_ddr_helpers.c \ + drivers/st/gpio/stm32_gpio.c \ +- drivers/st/pmic/stm32_i2c.c \ +- drivers/st/pmic/stm32mp1_pmic.c \ +- drivers/st/pmic/stpmu1.c \ ++ drivers/st/i2c/stm32_i2c.c \ ++ drivers/st/iwdg/stm32_iwdg.c \ ++ drivers/st/pmic/stm32mp_pmic.c \ ++ drivers/st/pmic/stpmic1.c \ + drivers/st/reset/stm32mp1_reset.c \ ++ plat/st/common/stm32mp_dt.c \ ++ plat/st/common/stm32mp_shres_helpers.c \ + plat/st/stm32mp1/stm32mp1_context.c \ +- plat/st/stm32mp1/stm32mp1_dt.c \ ++ plat/st/stm32mp1/stm32mp1_dbgmcu.c \ + plat/st/stm32mp1/stm32mp1_helper.S \ +- plat/st/stm32mp1/stm32mp1_security.c ++ plat/st/stm32mp1/stm32mp1_security.c \ ++ plat/st/stm32mp1/stm32mp1_shared_resources.c + +-BL2_SOURCES += drivers/io/io_dummy.c \ ++BL2_SOURCES += drivers/io/io_block.c \ ++ drivers/io/io_dummy.c \ + drivers/io/io_storage.c \ +- plat/st/stm32mp1/bl2_io_storage.c \ +- plat/st/stm32mp1/bl2_plat_setup.c ++ drivers/st/hash/hash_sec.c \ ++ drivers/st/io/io_stm32image.c \ ++ plat/st/common/bl2_io_storage.c \ ++ plat/st/common/stm32mp_auth.c \ ++ plat/st/stm32mp1/bl2_plat_setup.c \ ++ plat/st/stm32mp1/stm32mp1_syscfg.c ++ ++ifeq (${STM32MP1_QSPI_NOR},1) ++BL2_SOURCES += drivers/st/qspi/io_qspi.c ++endif ++ ++ifeq (${STM32MP_FMC_NAND},1) ++BL2_SOURCES += drivers/st/nand/io_nand.c \ ++ drivers/st/nand/nand.c ++endif ++ ++ifneq ($(filter 1,${STM32MP_EMMC} ${STM32MP_SDMMC}),) ++BL2_SOURCES += drivers/mmc/mmc.c \ ++ drivers/partition/gpt.c \ ++ drivers/partition/partition.c \ ++ drivers/st/io/io_mmc.c \ ++ drivers/st/mmc/stm32_sdmmc2.c ++endif ++ ++ifeq (${STM32MP_UART_PROGRAMMER},1) ++BL2_SOURCES += drivers/st/uart/io_programmer_uart.c \ ++ drivers/st/uart/stm32mp1xx_hal_uart.c ++endif + + BL2_SOURCES += drivers/st/ddr/stm32mp1_ddr.c \ + drivers/st/ddr/stm32mp1_ram.c +@@ -68,19 +155,36 @@ BL2_SOURCES += common/desc_image_load.c \ + plat/st/stm32mp1/plat_bl2_mem_params_desc.c \ + plat/st/stm32mp1/plat_image_load.c + +-# For memory footprint optimization, build with thumb and interwork support +-ASFLAGS += -mthumb -mthumb-interwork +-TF_CFLAGS += -mthumb -mthumb-interwork ++ifneq (${STM32MP_USB},0) ++BL2_SOURCES += drivers/st/io/io_programmer_st_usb.c \ ++ drivers/st/usb_dwc2/usb_dwc2.c \ ++ lib/usb/usb_core.c \ ++ lib/usb/usb_st_dfu.c \ ++ plat/st/stm32mp1/stm32mp1_usb_desc.c ++ ++TF_CFLAGS += -DSTM32MP_USB ++endif ++ ++ifeq ($(AARCH32_SP),optee) ++BL2_SOURCES += lib/optee/optee_utils.c ++endif ++ ++ifeq (${STM32MP1_RESET_HALT_WORKAROUND},1) ++BL2_SOURCES += plat/st/stm32mp1/stm32mp1_helper_dbg.S ++endif ++ ++# Do not use neon in TF-A code, it leads to issues in low-power functions ++TF_CFLAGS += -mfloat-abi=soft + + # Macros and rules to build TF binary + STM32_TF_ELF_LDFLAGS := --hash-style=gnu --as-needed +-STM32_DT_BASENAME := $(STM32_DTB_FILE_NAME:.dtb=) ++STM32_DT_BASENAME := $(DTB_FILE_NAME:.dtb=) + STM32_TF_STM32 := ${BUILD_PLAT}/tf-a-${STM32_DT_BASENAME}.stm32 + STM32_TF_BINARY := $(STM32_TF_STM32:.stm32=.bin) + STM32_TF_MAPFILE := $(STM32_TF_STM32:.stm32=.map) + STM32_TF_LINKERFILE := $(STM32_TF_STM32:.stm32=.ld) + STM32_TF_ELF := $(STM32_TF_STM32:.stm32=.elf) +-STM32_TF_DTBFILE := ${BUILD_PLAT}/fdts/${STM32_DTB_FILE_NAME} ++STM32_TF_DTBFILE := ${BUILD_PLAT}/fdts/${DTB_FILE_NAME} + STM32_TF_OBJS := ${BUILD_PLAT}/stm32mp1.o + + # Variables for use with stm32image +@@ -123,7 +227,7 @@ ${STM32_TF_OBJS}: plat/st/stm32mp1/stm32mp1.S bl2 ${BL32_DEP} ${STM32_TF_DTBFILE + -DDTB_BIN_PATH=\"${STM32_TF_DTBFILE}\" \ + -c plat/st/stm32mp1/stm32mp1.S -o $@ + +-${STM32_TF_LINKERFILE}: plat/st/stm32mp1/stm32mp1.ld.S ++${STM32_TF_LINKERFILE}: plat/st/stm32mp1/stm32mp1.ld.S ${BUILD_PLAT} + @echo " LDS $<" + ${Q}${AS} ${ASFLAGS} ${TF_CFLAGS} -P -E $< -o $@ + +diff --git a/plat/st/stm32mp1/services/bsec_svc.c b/plat/st/stm32mp1/services/bsec_svc.c +new file mode 100644 +index 0000000..e4f86a2 +--- /dev/null ++++ b/plat/st/stm32mp1/services/bsec_svc.c +@@ -0,0 +1,460 @@ ++/* ++ * Copyright (c) 2016-2018, STMicroelectronics - All Rights Reserved ++ * ++ * SPDX-License-Identifier: BSD-3-Clause ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "bsec_svc.h" ++ ++#define SSP_OTP_REQ BIT(BOOT_API_OTP_SSP_REQ_BIT_POS) ++#define SSP_OTP_SUCCESS BIT(BOOT_API_OTP_SSP_SUCCESS_BIT_POS) ++#define SSP_OTP_MASK (SSP_OTP_REQ | SSP_OTP_SUCCESS) ++ ++enum bsec_ssp_status { ++ BSEC_NO_SSP = 0, ++ BSEC_SSP_SET, ++ BSEC_SSP_ERROR ++}; ++ ++struct otp_exchange { ++ uint32_t version; ++ uint32_t configuration; ++ uint32_t reserved; ++ uint32_t status; ++ uint32_t general_lock; ++ uint32_t debug_conf; ++ uint32_t reserved1[2]; ++ uint32_t otp_disturb[3]; ++ uint32_t reserved2[3]; ++ uint32_t error_status[3]; ++ uint32_t reserved3[3]; ++ uint32_t permanent_lock[3]; ++ uint32_t reserved4[3]; ++ uint32_t programming_lock[3]; ++ uint32_t reserved5[3]; ++ uint32_t shadow_write_lock[3]; ++ uint32_t reserved6[3]; ++ uint32_t shadow_read_lock[3]; ++ uint32_t reserved7[3]; ++ uint32_t otp_value[STM32MP1_OTP_MAX_ID + 1]; ++ uint32_t reserved8[112]; ++ uint32_t bsec_hw_conf; ++ uint32_t ip_version; ++ uint32_t ip_id; ++ uint32_t ip_magic_id; ++}; ++ ++static enum bsec_ssp_status bsec_check_ssp(uint32_t otp, uint32_t update) ++{ ++ boot_api_context_t *boot_context = ++ (boot_api_context_t *)BOOT_PARAM_ADDR; ++ ++ /* No SSP update or SSP already done*/ ++ if ((((otp & SSP_OTP_MASK) == 0U) && ((update & SSP_OTP_MASK) == 0U)) || ++ (((otp & SSP_OTP_MASK) == SSP_OTP_MASK) && ++ ((update & SSP_OTP_MASK) == SSP_OTP_MASK))) { ++ return BSEC_NO_SSP; ++ } ++ ++ /* SSP update */ ++ if ((update & SSP_OTP_MASK) != 0U) { ++ if ((update & SSP_OTP_SUCCESS) != 0U) { ++ return BSEC_SSP_ERROR; ++ } ++ ++ /* SSP boot process */ ++ boot_context->p_ssp_config->ssp_cmd = ++ BOOT_API_CTX_SSP_CMD_CALC_CHIP_PUBK; ++#ifndef DCACHE_OFF ++ flush_dcache_range((uintptr_t)boot_context->p_ssp_config, ++ sizeof(boot_api_ssp_config_t)); ++#endif ++ if (dt_pmic_status() > 0) { ++ initialize_pmic(); ++ stpmic1_regulator_mask_reset_set("buck1"); ++ } ++ ++ return BSEC_SSP_SET; ++ } ++ return BSEC_NO_SSP; ++} ++ ++static uint32_t bsec_read_all_bsec(struct otp_exchange *exchange) ++{ ++ uint32_t i; ++ uint32_t result; ++ ++ if (exchange == NULL) { ++ return BSEC_ERROR; ++ } ++ ++ exchange->version = BSEC_SERVICE_VERSION; ++ ++ for (i = 0U; i <= STM32MP1_OTP_MAX_ID; i++) { ++ if (bsec_check_nsec_access_rights(i) == BSEC_OK) { ++ result = bsec_shadow_register(i); ++ if (result != BSEC_OK) { ++ return result; ++ } ++ ++ result = bsec_read_otp(&exchange->otp_value[i], i); ++ if (result != BSEC_OK) { ++ return result; ++ } ++ } ++ } ++ ++ exchange->configuration = mmio_read_32(bsec_get_base() + ++ BSEC_OTP_CONF_OFF); ++ ++ exchange->status = mmio_read_32(bsec_get_base() + BSEC_OTP_STATUS_OFF); ++ ++ exchange->general_lock = mmio_read_32(bsec_get_base() + ++ BSEC_OTP_LOCK_OFF); ++ ++ exchange->debug_conf = mmio_read_32(bsec_get_base() + BSEC_DEN_OFF); ++ ++ exchange->otp_disturb[0] = mmio_read_32(bsec_get_base() + ++ BSEC_DISTURBED_OFF); ++ ++ exchange->otp_disturb[1] = mmio_read_32(bsec_get_base() + ++ BSEC_DISTURBED1_OFF); ++ ++ exchange->otp_disturb[2] = mmio_read_32(bsec_get_base() + ++ BSEC_DISTURBED2_OFF); ++ ++ exchange->error_status[0] = mmio_read_32(bsec_get_base() + ++ BSEC_ERROR_OFF); ++ ++ exchange->error_status[1] = mmio_read_32(bsec_get_base() + ++ BSEC_ERROR1_OFF); ++ ++ exchange->error_status[2] = mmio_read_32(bsec_get_base() + ++ BSEC_ERROR2_OFF); ++ ++ exchange->permanent_lock[0] = mmio_read_32(bsec_get_base() + ++ BSEC_WRLOCK_OFF); ++ ++ exchange->permanent_lock[1] = mmio_read_32(bsec_get_base() + ++ BSEC_WRLOCK1_OFF); ++ ++ exchange->permanent_lock[2] = mmio_read_32(bsec_get_base() + ++ BSEC_WRLOCK2_OFF); ++ ++ exchange->programming_lock[0] = mmio_read_32(bsec_get_base() + ++ BSEC_SPLOCK_OFF); ++ ++ exchange->programming_lock[1] = mmio_read_32(bsec_get_base() + ++ BSEC_SPLOCK1_OFF); ++ ++ exchange->programming_lock[2] = mmio_read_32(bsec_get_base() + ++ BSEC_SPLOCK2_OFF); ++ ++ exchange->shadow_write_lock[0] = mmio_read_32(bsec_get_base() + ++ BSEC_SWLOCK_OFF); ++ ++ exchange->shadow_write_lock[1] = mmio_read_32(bsec_get_base() + ++ BSEC_SWLOCK1_OFF); ++ ++ exchange->shadow_write_lock[2] = mmio_read_32(bsec_get_base() + ++ BSEC_SWLOCK2_OFF); ++ ++ exchange->shadow_read_lock[0] = mmio_read_32(bsec_get_base() + ++ BSEC_SRLOCK_OFF); ++ ++ exchange->shadow_read_lock[1] = mmio_read_32(bsec_get_base() + ++ BSEC_SRLOCK1_OFF); ++ ++ exchange->shadow_read_lock[2] = mmio_read_32(bsec_get_base() + ++ BSEC_SRLOCK2_OFF); ++ ++ exchange->bsec_hw_conf = mmio_read_32(bsec_get_base() + ++ BSEC_IPHW_CFG_OFF); ++ ++ exchange->ip_version = mmio_read_32(bsec_get_base() + BSEC_IPVR_OFF); ++ ++ exchange->ip_id = mmio_read_32(bsec_get_base() + BSEC_IP_ID_OFF); ++ ++ exchange->ip_magic_id = mmio_read_32(bsec_get_base() + ++ BSEC_IP_MAGIC_ID_OFF); ++ ++ return BSEC_OK; ++} ++ ++static uint32_t bsec_write_all_bsec(struct otp_exchange *exchange, ++ uint32_t *ret_otp_value) ++{ ++ uint32_t i; ++ uint32_t j; ++ uint32_t start_otp = 0U; ++ uint32_t value = 0U; ++ uint32_t ret; ++ struct bsec_config config_param; ++ ++ *ret_otp_value = 0U; ++ ++ if (exchange == NULL) { ++ return BSEC_ERROR; ++ } ++ ++ if (exchange->version != BSEC_SERVICE_VERSION) { ++ return BSEC_ERROR; ++ } ++ ++ for (i = start_otp; i <= STM32MP1_OTP_MAX_ID; i++) { ++ if (bsec_check_nsec_access_rights(i) != BSEC_OK) { ++ continue; ++ } ++ ++ ret = bsec_shadow_register(i); ++ if (ret != BSEC_OK) { ++ return ret; ++ } ++ ++ ret = bsec_read_otp(&value, i); ++ if (ret != BSEC_OK) { ++ return ret; ++ } ++ ++ if ((value == exchange->otp_value[i]) && ++ (i != BOOT_API_OTP_SSP_WORD_NB)) { ++ continue; ++ } ++ ++ if (i == BOOT_API_OTP_SSP_WORD_NB) { ++ *ret_otp_value = (uint32_t)bsec_check_ssp(value, ++ exchange->otp_value[i]); ++ VERBOSE("Result OTP SSP %d\n", *ret_otp_value); ++ if (*ret_otp_value == (uint32_t)BSEC_SSP_ERROR) { ++ continue; ++ } ++ } ++ ++ ret = bsec_program_otp(exchange->otp_value[i], i); ++ if (ret != BSEC_OK) { ++ return ret; ++ } ++ ++ ret = bsec_write_otp(exchange->otp_value[i], i); ++ if (ret != BSEC_OK) { ++ return ret; ++ } ++ } ++ ++ ret = bsec_write_debug_conf(exchange->debug_conf); ++ if (ret != BSEC_OK) { ++ return ret; ++ } ++ ++ for (j = 0U; j < 3U; j++) { ++ if (exchange->permanent_lock[j] == 0U) { ++ continue; ++ } ++ ++ for (i = 0U; i < 32U; i++) { ++ if (bsec_check_nsec_access_rights((32U * j) + i) != ++ BSEC_OK) { ++ continue; ++ } ++ ++ value = (exchange->permanent_lock[j] >> i) & 1U; ++ if (value != 0U) { ++ ret = bsec_permanent_lock_otp((32U * j) + i); ++ if (ret != BSEC_OK) { ++ return ret; ++ } ++ } ++ } ++ } ++ ++ for (j = 0U; j < 3U; j++) { ++ if (exchange->programming_lock[j] == 0U) { ++ continue; ++ } ++ ++ for (i = 0U; i < 32U; i++) { ++ if (bsec_check_nsec_access_rights((32U * j) + i) != ++ BSEC_OK) { ++ continue; ++ } ++ ++ value = (exchange->programming_lock[j] >> i) & 1U; ++ if (value != 0U) { ++ if (!bsec_write_sp_lock((32U * j) + i, 1U)) { ++ return BSEC_ERROR; ++ } ++ } ++ } ++ } ++ ++ for (j = 0U; j < 3U; j++) { ++ if (exchange->shadow_write_lock[j] == 0U) { ++ continue; ++ } ++ ++ for (i = 0U; i < 32U; i++) { ++ if (bsec_check_nsec_access_rights((32U * j) + i) != ++ BSEC_OK) { ++ continue; ++ } ++ ++ value = (exchange->shadow_write_lock[j] >> i) & 1U; ++ if (value != 0U) { ++ if (!bsec_write_sw_lock((32U * j) + i, 1U)) { ++ return BSEC_ERROR; ++ } ++ } ++ } ++ } ++ ++ for (j = 0U; j < 3U; j++) { ++ if (exchange->shadow_read_lock[j] == 0U) { ++ continue; ++ } ++ ++ for (i = 0U; i < 32U; i++) { ++ if (bsec_check_nsec_access_rights((32U * j) + i) != ++ BSEC_OK) { ++ continue; ++ } ++ ++ value = (exchange->shadow_read_lock[j] >> i) & 1U; ++ if (value != 0U) { ++ if (!bsec_write_sr_lock((32U * j) + i, 1U)) { ++ return BSEC_ERROR; ++ } ++ } ++ } ++ } ++ ++ ret = bsec_get_config(&config_param); ++ if (ret != BSEC_OK) { ++ return ret; ++ } ++ ++ config_param.power = ++ (uint8_t)(exchange->configuration & BSEC_CONF_POWER_UP_MASK) >> ++ BSEC_CONF_POWER_UP_SHIFT; ++ config_param.freq = ++ (uint8_t)(exchange->configuration & BSEC_CONF_FRQ_MASK) >> ++ BSEC_CONF_FRQ_SHIFT; ++ config_param.pulse_width = ++ (uint8_t)(exchange->configuration & BSEC_CONF_PRG_WIDTH_MASK) >> ++ BSEC_CONF_PRG_WIDTH_SHIFT; ++ config_param.tread = ++ (uint8_t)((exchange->configuration & BSEC_CONF_TREAD_MASK) >> ++ BSEC_CONF_TREAD_SHIFT); ++ config_param.den_lock = ++ (uint8_t)(exchange->general_lock & DENREG_LOCK_MASK) >> ++ DENREG_LOCK_SHIFT; ++ config_param.prog_lock = ++ (uint8_t)(exchange->general_lock & GPLOCK_LOCK_MASK) >> ++ GPLOCK_LOCK_SHIFT; ++ ++ if (!bsec_mode_is_closed_device()) { ++ config_param.upper_otp_lock = ++ (uint8_t)(exchange->general_lock & ++ UPPER_OTP_LOCK_MASK) >> ++ UPPER_OTP_LOCK_SHIFT; ++ } ++ ++ ret = bsec_set_config(&config_param); ++ if (ret != BSEC_OK) { ++ return ret; ++ } ++ ++ INFO("write all otp succeed\n"); ++ ++ return BSEC_OK; ++} ++ ++uint32_t bsec_main(uint32_t x1, uint32_t x2, uint32_t x3, ++ uint32_t *ret_otp_value) ++{ ++ uint32_t result; ++ uint32_t tmp_data = 0U; ++ struct otp_exchange *otp_exch = (struct otp_exchange *)(uintptr_t)x2; ++ ++ if ((x1 != STM32_SMC_READ_ALL) && (x1 != STM32_SMC_WRITE_ALL) && ++ (bsec_check_nsec_access_rights(x2) != BSEC_OK)) { ++ return BSEC_ERROR; ++ } ++ ++ if (((x1 == STM32_SMC_READ_ALL) || (x1 == STM32_SMC_WRITE_ALL)) && ++ (!ddr_is_nonsecured_area((uintptr_t)x2, ++ sizeof(struct otp_exchange)))) { ++ return BSEC_ERROR; ++ } ++ ++ switch (x1) { ++ case STM32_SMC_READ_SHADOW: ++ result = bsec_read_otp(ret_otp_value, x2); ++ break; ++ case STM32_SMC_PROG_OTP: ++ *ret_otp_value = 0U; ++ if (x2 == BOOT_API_OTP_SSP_WORD_NB) { ++ result = bsec_read_otp(&tmp_data, x2); ++ if (result != BSEC_OK) { ++ break; ++ } ++ ++ *ret_otp_value = (uint32_t)bsec_check_ssp(tmp_data, ++ otp_exch->otp_value[x2]); ++ if (*ret_otp_value == (uint32_t)BSEC_SSP_ERROR) { ++ result = BSEC_OK; ++ break; ++ } ++ } ++ result = bsec_program_otp(x3, x2); ++ break; ++ case STM32_SMC_WRITE_SHADOW: ++ *ret_otp_value = 0; ++ result = bsec_write_otp(x3, x2); ++ break; ++ case STM32_SMC_READ_OTP: ++ *ret_otp_value = 0; ++ result = bsec_read_otp(&tmp_data, x2); ++ if (result != BSEC_OK) { ++ break; ++ } ++ ++ result = bsec_shadow_register(x2); ++ if (result != BSEC_OK) { ++ break; ++ } ++ ++ result = bsec_read_otp(ret_otp_value, x2); ++ if (result != BSEC_OK) { ++ break; ++ } ++ ++ result = bsec_write_otp(tmp_data, x2); ++ break; ++ case STM32_SMC_READ_ALL: ++ result = bsec_read_all_bsec(otp_exch); ++ break; ++ case STM32_SMC_WRITE_ALL: ++ result = bsec_write_all_bsec(otp_exch, ret_otp_value); ++ break; ++ default: ++ result = BSEC_ERROR; ++ break; ++ } ++ ++ return result; ++} +diff --git a/plat/st/stm32mp1/services/bsec_svc.h b/plat/st/stm32mp1/services/bsec_svc.h +new file mode 100644 +index 0000000..75c9aa3 +--- /dev/null ++++ b/plat/st/stm32mp1/services/bsec_svc.h +@@ -0,0 +1,21 @@ ++/* ++ * Copyright (c) 2016-2017, STMicroelectronics - All Rights Reserved ++ * ++ * SPDX-License-Identifier: BSD-3-Clause ++ */ ++ ++#ifndef BSEC_SVC_H ++#define BSEC_SVC_H ++ ++#include ++#include ++#include ++ ++/* version of this service */ ++/* must be increase at each structure modification */ ++#define BSEC_SERVICE_VERSION 0x01U ++ ++uint32_t bsec_main(uint32_t x1, uint32_t x2, uint32_t x3, ++ uint32_t *ret_otp_value); ++ ++#endif /* BSEC_SVC_H */ +diff --git a/plat/st/stm32mp1/services/low_power_svc.c b/plat/st/stm32mp1/services/low_power_svc.c +new file mode 100644 +index 0000000..a7fe026 +--- /dev/null ++++ b/plat/st/stm32mp1/services/low_power_svc.c +@@ -0,0 +1,46 @@ ++/* ++ * Copyright (c) 2017-2018, STMicroelectronics - All Rights Reserved ++ * ++ * SPDX-License-Identifier: BSD-3-Clause ++ */ ++ ++#include ++#include ++#include ++#include ++#include "low_power_svc.h" ++ ++uint32_t sr_mode_scv_handler(uint32_t x1, uint32_t x2) ++{ ++ uint32_t ret = STM32_SMC_OK; ++ ++ switch (x2) { ++ case STM32_SMC_SR_MODE_SSR: ++ ddr_sr_mode_ssr(); ++ break; ++ ++ case STM32_SMC_SR_MODE_ASR: ++ ddr_sr_mode_asr(); ++ break; ++ ++ case STM32_SMC_SR_MODE_HSR: ++ ddr_sr_mode_hsr(); ++ break; ++ ++ default: ++ ret = STM32_SMC_INVALID_PARAMS; ++ break; ++ } ++ ++ return ret; ++} ++ ++uint32_t pm_domain_scv_handler(uint32_t x1, uint32_t x2) ++{ ++ if (stm32mp1_set_pm_domain_state((enum stm32mp1_pm_domain)x1, ++ (bool)x2) < 0) { ++ return STM32_SMC_FAILED; ++ } ++ ++ return STM32_SMC_OK; ++} +diff --git a/plat/st/stm32mp1/services/low_power_svc.h b/plat/st/stm32mp1/services/low_power_svc.h +new file mode 100644 +index 0000000..1264fa1 +--- /dev/null ++++ b/plat/st/stm32mp1/services/low_power_svc.h +@@ -0,0 +1,15 @@ ++/* ++ * Copyright (c) 2017-2018, STMicroelectronics - All Rights Reserved ++ * ++ * SPDX-License-Identifier: BSD-3-Clause ++ */ ++ ++#ifndef LOW_POWER_SVC_H ++#define LOW_POWER_SVC_H ++ ++#include ++ ++uint32_t sr_mode_scv_handler(uint32_t x1, uint32_t x2); ++uint32_t pm_domain_scv_handler(uint32_t x1, uint32_t x2); ++ ++#endif /* LOW_POWER_SVC_H */ +diff --git a/plat/st/stm32mp1/services/pwr_svc.c b/plat/st/stm32mp1/services/pwr_svc.c +new file mode 100644 +index 0000000..80dcc7c +--- /dev/null ++++ b/plat/st/stm32mp1/services/pwr_svc.c +@@ -0,0 +1,124 @@ ++/* ++ * Copyright (c) 2017-2018, STMicroelectronics - All Rights Reserved ++ * Copyright (c) 2017-2018 ARM Limited and Contributors. All rights reserved. ++ * ++ * SPDX-License-Identifier: BSD-3-Clause ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "pwr_svc.h" ++ ++static struct spinlock lock; ++ ++void pwr_regs_lock(void) ++{ ++ const uint32_t mask = SCTLR_M_BIT | SCTLR_C_BIT; ++ ++ /* Lock is currently required only when MMU and cache are enabled */ ++ if ((read_sctlr() & mask) == mask) { ++ spin_lock(&lock); ++ } ++} ++ ++void pwr_regs_unlock(void) ++{ ++ const uint32_t mask = SCTLR_M_BIT | SCTLR_C_BIT; ++ ++ /* Unlock is required only when MMU and cache are enabled */ ++ if ((read_sctlr() & mask) == mask) { ++ spin_unlock(&lock); ++ } ++} ++ ++static void access_allowed_mask(uint32_t request, uint32_t offset, ++ uint32_t value, uint32_t allowed_mask) ++{ ++ uint32_t addr = stm32mp_pwr_base() + offset; ++ uint32_t masked_value = value & allowed_mask; ++ ++ pwr_regs_lock(); ++ ++ switch (request) { ++ case STM32_SMC_REG_WRITE: ++ mmio_clrsetbits_32(addr, allowed_mask, masked_value); ++ VERBOSE("wrt 0x%x = 0x%x => 0x%x\n", offset, value, ++ mmio_read_32(addr)); ++ break; ++ ++ case STM32_SMC_REG_SET: ++ mmio_setbits_32(addr, masked_value); ++ VERBOSE("set 0x%x = 0x%x => 0x%x\n", offset, value, ++ mmio_read_32(addr)); ++ break; ++ ++ case STM32_SMC_REG_CLEAR: ++ mmio_clrbits_32(addr, masked_value); ++ VERBOSE("clear 0x%x = 0x%x => 0x%x\n", offset, value, ++ mmio_read_32(addr)); ++ break; ++ ++ default: ++ break; ++ } ++ ++ pwr_regs_unlock(); ++} ++ ++static void raw_allowed_access_request(uint32_t request, ++ uint32_t offset, uint32_t value) ++{ ++ uint32_t allowed_mask = 0; ++ ++ switch (offset) { ++ case PWR_CR3: ++ allowed_mask |= PWR_CR3_VBE | PWR_CR3_VBRS | PWR_CR3_USB33DEN | ++ PWR_CR3_REG18EN | PWR_CR3_REG11EN; ++ break; ++ ++ case PWR_WKUPCR: ++ allowed_mask |= PWR_WKUPCR_MASK; ++ break; ++ ++ case PWR_MPUWKUPENR: ++ allowed_mask |= PWR_MPUWKUPENR_MASK; ++ break; ++ ++ default: ++ return; ++ } ++ ++ if (allowed_mask != 0U) { ++ access_allowed_mask(request, offset, value, allowed_mask); ++ } ++} ++ ++uint32_t pwr_scv_handler(uint32_t x1, uint32_t x2, uint32_t x3) ++{ ++ uint32_t request = x1; ++ uint32_t offset = x2; ++ uint32_t value = x3; ++ ++ /* ++ * x2 may be either the PWR register offset or the register ++ * full physical address. ++ */ ++ if ((offset & ~PWR_OFFSET_MASK) != 0) { ++ if ((offset & ~PWR_OFFSET_MASK) != stm32mp_pwr_base()) { ++ return STM32_SMC_INVALID_PARAMS; ++ } ++ ++ offset &= PWR_OFFSET_MASK; ++ } ++ ++ /* PWR controls for non secure resource may be accessed straight */ ++ raw_allowed_access_request(request, offset, value); ++ ++ return STM32_SMC_OK; ++} +diff --git a/plat/st/stm32mp1/services/pwr_svc.h b/plat/st/stm32mp1/services/pwr_svc.h +new file mode 100644 +index 0000000..90cf1a3 +--- /dev/null ++++ b/plat/st/stm32mp1/services/pwr_svc.h +@@ -0,0 +1,13 @@ ++/* ++ * Copyright (c) 2017, STMicroelectronics - All Rights Reserved ++ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. ++ * ++ * SPDX-License-Identifier: BSD-3-Clause ++ */ ++ ++#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/plat/st/stm32mp1/services/rcc_svc.c b/plat/st/stm32mp1/services/rcc_svc.c +new file mode 100644 +index 0000000..1df6903 +--- /dev/null ++++ b/plat/st/stm32mp1/services/rcc_svc.c +@@ -0,0 +1,477 @@ ++/* ++ * Copyright (c) 2017-2018, STMicroelectronics - All Rights Reserved ++ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. ++ * ++ * SPDX-License-Identifier: BSD-3-Clause ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "rcc_svc.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 long id; ++ unsigned int bit; ++ uint32_t enable_bits = 0; ++ int clr_std_set = STD_REG; ++ ++ switch (request) { ++ case STM32_SMC_REG_WRITE: ++ case STM32_SMC_REG_SET: ++ case STM32_SMC_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: ++ break; ++ } ++ ++ if ((clr_std_set != STD_REG) && (request == STM32_SMC_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; bit < __WORD_BIT; bit++) { ++ ++ if ((BIT(bit) & enable_bits) == 0U) { ++ continue; ++ } ++ ++ id = stm32mp1_clk_rcc2id(offset, bit); ++ if (id == ~0U) { ++ panic(); ++ } ++ ++ switch (clr_std_set) { ++ case SET_REG: ++ if ((BIT(bit) & value) != 0U) { ++ stm32mp1_clk_enable_non_secure(id); ++ } ++ break; ++ case CLR_REG: ++ if ((BIT(bit) & value) != 0U) { ++ stm32mp1_clk_disable_non_secure(id); ++ } ++ break; ++ default: ++ /* Standard registers case */ ++ switch (request) { ++ case STM32_SMC_REG_WRITE: ++ if ((BIT(bit) & value) != 0U) { ++ stm32mp1_clk_enable_non_secure(id); ++ } else { ++ stm32mp1_clk_disable_non_secure(id); ++ } ++ break; ++ case STM32_SMC_REG_SET: ++ if ((BIT(bit) & value) != 0U) { ++ stm32mp1_clk_enable_non_secure(id); ++ } ++ break; ++ case STM32_SMC_REG_CLEAR: ++ if ((BIT(bit) & value) != 0U) { ++ stm32mp1_clk_disable_non_secure(id); ++ } ++ break; ++ default: ++ return; ++ } ++ break; ++ } ++ ++ enable_bits &= ~BIT(bit); ++ if (enable_bits == 0U) { ++ break; ++ } ++ } ++} ++ ++static void access_allowed_mask(uint32_t request, uint32_t offset, ++ uint32_t value, uint32_t allowed_mask) ++{ ++ uint32_t addr = stm32mp_rcc_base() + offset; ++ uint32_t masked_value = value & allowed_mask; ++ ++ switch (request) { ++ case STM32_SMC_REG_WRITE: ++ switch (offset) { ++ /* CLR registers show the SET state, not the CLR state */ ++ 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: ++ mmio_write_32(addr, masked_value); ++ break; ++ default: ++ stm32mp_mmio_clrsetbits_32_shregs(addr, allowed_mask, ++ masked_value); ++ break; ++ } ++ VERBOSE("wrt 0x%x = 0x%x => 0x%x\n", offset, value, ++ mmio_read_32(addr)); ++ break; ++ ++ case STM32_SMC_REG_SET: ++ switch (offset) { ++ /* CLR registers show the SET state, not the CLR state */ ++ 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: ++ mmio_write_32(addr, masked_value); ++ break; ++ default: ++ stm32mp_mmio_setbits_32_shregs(addr, masked_value); ++ break; ++ } ++ VERBOSE("set 0x%x = 0x%x => 0x%x\n", offset, value, ++ mmio_read_32(addr)); ++ break; ++ ++ case STM32_SMC_REG_CLEAR: ++ 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: ++ /* Nothing to do on CLR registers */ ++ break; ++ default: ++ stm32mp_mmio_clrbits_32_shregs(addr, masked_value); ++ break; ++ } ++ VERBOSE("clear 0x%x = 0x%x => 0x%x\n", offset, value, ++ mmio_read_32(addr)); ++ 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 (stm32mp1_periph_is_non_secure(STM32MP1_SHRES_HSI)) { ++ allowed_mask |= RCC_OCENR_HSION | RCC_OCENR_HSIKERON; ++ } ++ if (stm32mp1_periph_is_non_secure(STM32MP1_SHRES_CSI)) { ++ allowed_mask |= RCC_OCENR_CSION | RCC_OCENR_CSIKERON; ++ } ++ if (stm32mp1_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 (stm32mp1_periph_is_non_secure(STM32MP1_SHRES_HSI)) { ++ allowed_mask = UINT32_MAX; ++ } ++ break; ++ ++ case RCC_CSICFGR: ++ if (stm32mp1_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 (stm32mp1_periph_is_non_secure(STM32MP1_SHRES_LSI)) { ++ allowed_mask |= RCC_MP_CIFR_LSIRDYF; ++ } ++ if (stm32mp1_periph_is_non_secure(STM32MP1_SHRES_LSE)) { ++ allowed_mask |= RCC_MP_CIFR_LSERDYF; ++ } ++ if (stm32mp1_periph_is_non_secure(STM32MP1_SHRES_HSI)) { ++ allowed_mask |= RCC_MP_CIFR_HSIRDYF; ++ } ++ if (stm32mp1_periph_is_non_secure(STM32MP1_SHRES_HSE)) { ++ allowed_mask |= RCC_MP_CIFR_HSERDYF; ++ } ++ if (stm32mp1_periph_is_non_secure(STM32MP1_SHRES_CSI)) { ++ allowed_mask |= RCC_MP_CIFR_CSIRDYF; ++ } ++ if (stm32mp1_periph_is_non_secure(STM32MP1_SHRES_PLL1)) { ++ allowed_mask |= RCC_MP_CIFR_PLL1DYF; ++ } ++ if (stm32mp1_periph_is_non_secure(STM32MP1_SHRES_PLL2)) { ++ allowed_mask |= RCC_MP_CIFR_PLL2DYF; ++ } ++ if (stm32mp1_periph_is_non_secure(STM32MP1_SHRES_PLL3)) { ++ allowed_mask |= RCC_MP_CIFR_PLL3DYF; ++ } ++ break; ++ ++ case RCC_PLL1CR: ++ if (stm32mp1_periph_is_non_secure(STM32MP1_SHRES_PLL1_P)) { ++ allowed_mask |= RCC_PLLNCR_DIVPEN; ++ } ++ if (stm32mp1_periph_is_non_secure(STM32MP1_SHRES_PLL1_Q)) { ++ allowed_mask |= RCC_PLLNCR_DIVQEN; ++ } ++ if (stm32mp1_periph_is_non_secure(STM32MP1_SHRES_PLL1_R)) { ++ allowed_mask |= RCC_PLLNCR_DIVREN; ++ } ++ if (stm32mp1_periph_is_non_secure(STM32MP1_SHRES_PLL1)) { ++ allowed_mask |= RCC_PLLNCR_PLLON | RCC_PLLNCR_PLLRDY | ++ RCC_PLLNCR_SSCG_CTRL; ++ } ++ break; ++ ++ case RCC_PLL2CR: ++ if (stm32mp1_periph_is_non_secure(STM32MP1_SHRES_PLL2_P)) { ++ allowed_mask |= RCC_PLLNCR_DIVPEN; ++ } ++ if (stm32mp1_periph_is_non_secure(STM32MP1_SHRES_PLL2_Q)) { ++ allowed_mask |= RCC_PLLNCR_DIVQEN; ++ } ++ if (stm32mp1_periph_is_non_secure(STM32MP1_SHRES_PLL2_R)) { ++ allowed_mask |= RCC_PLLNCR_DIVREN; ++ } ++ if (stm32mp1_periph_is_non_secure(STM32MP1_SHRES_PLL2)) { ++ allowed_mask |= RCC_PLLNCR_PLLON | RCC_PLLNCR_PLLRDY | ++ RCC_PLLNCR_SSCG_CTRL; ++ } ++ break; ++ ++ case RCC_PLL3CR: ++ if (stm32mp1_periph_is_non_secure(STM32MP1_SHRES_PLL3_P)) { ++ allowed_mask |= RCC_PLLNCR_DIVPEN; ++ } ++ if (stm32mp1_periph_is_non_secure(STM32MP1_SHRES_PLL3_Q)) { ++ allowed_mask |= RCC_PLLNCR_DIVQEN; ++ } ++ if (stm32mp1_periph_is_non_secure(STM32MP1_SHRES_PLL3_R)) { ++ allowed_mask |= RCC_PLLNCR_DIVREN; ++ } ++ if (stm32mp1_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/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 (stm32mp1_periph_is_non_secure(STM32MP1_SHRES_SPI6)) { ++ allowed_mask |= RCC_MP_APB5ENSETR_SPI6EN; ++ } ++ if (stm32mp1_periph_is_non_secure(STM32MP1_SHRES_I2C4)) { ++ allowed_mask |= RCC_MP_APB5ENSETR_I2C4EN; ++ } ++ if (stm32mp1_periph_is_non_secure(STM32MP1_SHRES_I2C6)) { ++ allowed_mask |= RCC_MP_APB5ENSETR_I2C6EN; ++ } ++ if (stm32mp1_periph_is_non_secure(STM32MP1_SHRES_USART1)) { ++ allowed_mask |= RCC_MP_APB5ENSETR_USART1EN; ++ } ++ if (stm32mp1_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 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 (stm32mp1_periph_is_non_secure(STM32MP1_SHRES_CRYP1)) { ++ allowed_mask |= RCC_MP_AHB5ENSETR_CRYP1EN; ++ } ++ if (stm32mp1_periph_is_non_secure(STM32MP1_SHRES_HASH1)) { ++ allowed_mask |= RCC_MP_AHB5ENSETR_HASH1EN; ++ } ++ if (stm32mp1_periph_is_non_secure(STM32MP1_SHRES_RNG1)) { ++ allowed_mask |= RCC_MP_AHB5ENSETR_RNG1EN; ++ } ++ break; ++ case RCC_RTCDIVR: ++ if (stm32mp1_periph_is_non_secure(STM32MP1_SHRES_RTC)) { ++ allowed_mask = UINT32_MAX; ++ } ++ break; ++ case RCC_I2C46CKSELR: ++ if (stm32mp1_periph_is_non_secure(STM32MP1_SHRES_I2C4) && ++ stm32mp1_periph_is_non_secure(STM32MP1_SHRES_I2C6)) { ++ allowed_mask = UINT32_MAX; ++ } ++ break; ++ case RCC_SPI6CKSELR: ++ if (stm32mp1_periph_is_non_secure(STM32MP1_SHRES_SPI6)) { ++ allowed_mask = UINT32_MAX; ++ } ++ break; ++ case RCC_UART1CKSELR: ++ if (stm32mp1_periph_is_non_secure(STM32MP1_SHRES_USART1)) { ++ allowed_mask = UINT32_MAX; ++ } ++ break; ++ case RCC_RNG1CKSELR: ++ if (stm32mp1_periph_is_non_secure(STM32MP1_SHRES_RNG1)) { ++ allowed_mask = UINT32_MAX; ++ } ++ break; ++ case RCC_MP_IWDGFZSETR: ++ case RCC_MP_IWDGFZCLRR: ++ if (stm32mp1_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; ++ ++ /* ++ * x2 may be either the RCC register offset or the register ++ * full physical address. ++ */ ++ if ((offset & ~RCC_OFFSET_MASK) != 0) { ++ if ((offset & ~RCC_OFFSET_MASK) != stm32mp_rcc_base()) { ++ return STM32_SMC_INVALID_PARAMS; ++ } ++ ++ offset &= RCC_OFFSET_MASK; ++ } ++ ++ /* 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_SMC_OK; ++} ++ ++uint32_t rcc_cal_scv_handler(uint32_t x1) ++{ ++ uint32_t ret = STM32_SMC_FAILED; ++ ++ switch (x1) { ++ case CK_CSI: ++ if (stm32mp1_rcc_start_csi_cal() == 0) { ++ ret = STM32_SMC_OK; ++ } ++ break; ++ ++ case CK_HSI: ++ if (stm32mp1_rcc_start_hsi_cal() == 0) { ++ ret = STM32_SMC_OK; ++ } ++ break; ++ ++ default: ++ ret = STM32_SMC_INVALID_PARAMS; ++ break; ++ } ++ ++ return ret; ++} +diff --git a/plat/st/stm32mp1/services/rcc_svc.h b/plat/st/stm32mp1/services/rcc_svc.h +new file mode 100644 +index 0000000..75d4a3c +--- /dev/null ++++ b/plat/st/stm32mp1/services/rcc_svc.h +@@ -0,0 +1,14 @@ ++/* ++ * Copyright (c) 2017, STMicroelectronics - All Rights Reserved ++ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. ++ * ++ * SPDX-License-Identifier: BSD-3-Clause ++ */ ++ ++#ifndef RCC_SVC_H ++#define RCC_SVC_H ++ ++uint32_t rcc_scv_handler(uint32_t x1, uint32_t x2, uint32_t x3); ++uint32_t rcc_cal_scv_handler(uint32_t x1); ++ ++#endif /* RCC_SVC_H */ +diff --git a/plat/st/stm32mp1/services/stm32mp1_svc_setup.c b/plat/st/stm32mp1/services/stm32mp1_svc_setup.c +new file mode 100644 +index 0000000..fff91c0 +--- /dev/null ++++ b/plat/st/stm32mp1/services/stm32mp1_svc_setup.c +@@ -0,0 +1,113 @@ ++/* ++ * Copyright (c) 2014-2018, STMicroelectronics - All Rights Reserved ++ * Copyright (c) 2014, ARM Limited and Contributors. All rights reserved. ++ * ++ * SPDX-License-Identifier: BSD-3-Clause ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "bsec_svc.h" ++#include "low_power_svc.h" ++#include "pwr_svc.h" ++#include "rcc_svc.h" ++ ++/* STM32 SiP Service UUID */ ++DEFINE_SVC_UUID2(stm32_sip_svc_uid, ++ 0xa778aa50, 0xf49b, 0x144a, 0x8a, 0x5e, ++ 0x26, 0x4d, 0x59, 0x94, 0xc2, 0x14); ++ ++/* Setup STM32MP1 Standard Services */ ++static int32_t stm32mp1_svc_setup(void) ++{ ++ /* ++ * PSCI is the only specification implemented as a Standard Service. ++ * Invoke PSCI setup from here. ++ */ ++ return 0; ++} ++ ++/* ++ * Top-level Standard Service SMC handler. This handler will in turn dispatch ++ * calls to PSCI SMC handler. ++ */ ++static uintptr_t stm32mp1_svc_smc_handler(uint32_t smc_fid, u_register_t x1, ++ u_register_t x2, u_register_t x3, ++ u_register_t x4, void *cookie, ++ void *handle, u_register_t flags) ++{ ++ uint32_t ret1 = 0U, ret2 = 0U; ++ bool ret_uid = false, ret2_enabled = false; ++ ++ switch (smc_fid) { ++ case STM32_SIP_SVC_CALL_COUNT: ++ ret1 = STM32_COMMON_SIP_NUM_CALLS; ++ break; ++ ++ case STM32_SIP_SVC_UID: ++ /* Return UUID to the caller */ ++ ret_uid = true; ++ break; ++ ++ case STM32_SIP_SVC_VERSION: ++ /* Return the version of current implementation */ ++ ret1 = STM32_SIP_SVC_VERSION_MAJOR; ++ ret2 = STM32_SIP_SVC_VERSION_MINOR; ++ ret2_enabled = true; ++ break; ++ ++ case STM32_SMC_BSEC: ++ ret1 = bsec_main(x1, x2, x3, &ret2); ++ ret2_enabled = true; ++ break; ++ ++ case STM32_SMC_RCC: ++ ret1 = rcc_scv_handler(x1, x2, x3); ++ break; ++ ++ case STM32_SMC_RCC_CAL: ++ ret1 = rcc_cal_scv_handler(x1); ++ break; ++ ++ case STM32_SMC_PWR: ++ ret1 = pwr_scv_handler(x1, x2, x3); ++ break; ++ ++ case STM32_SMC_SR_MODE: ++ ret1 = sr_mode_scv_handler(x1, x2); ++ break; ++ ++ case STM32_SMC_PD_DOMAIN: ++ ret1 = pm_domain_scv_handler(x1, x2); ++ break; ++ ++ default: ++ WARN("Unimplemented STM32MP1 Service Call: 0x%x\n", smc_fid); ++ ret1 = SMC_UNK; ++ break; ++ } ++ ++ if (ret_uid) { ++ SMC_UUID_RET(handle, stm32_sip_svc_uid); ++ } ++ ++ if (ret2_enabled) { ++ SMC_RET2(handle, ret1, ret2); ++ } ++ ++ SMC_RET1(handle, ret1); ++} ++ ++/* Register Standard Service Calls as runtime service */ ++DECLARE_RT_SVC(stm32mp1_sip_svc, ++ OEN_SIP_START, ++ OEN_SIP_END, ++ SMC_TYPE_FAST, ++ stm32mp1_svc_setup, ++ stm32mp1_svc_smc_handler ++); +diff --git a/plat/st/stm32mp1/sp_min/sp_min-stm32mp1.mk b/plat/st/stm32mp1/sp_min/sp_min-stm32mp1.mk +index 9fde153..322d389 100644 +--- a/plat/st/stm32mp1/sp_min/sp_min-stm32mp1.mk ++++ b/plat/st/stm32mp1/sp_min/sp_min-stm32mp1.mk +@@ -7,8 +7,15 @@ + SP_MIN_WITH_SECURE_FIQ := 1 + + BL32_SOURCES += plat/common/aarch32/platform_mp_stack.S \ ++ drivers/st/etzpc/etzpc.c \ ++ drivers/st/rng/stm32_rng.c \ ++ drivers/st/rtc/stm32_rtc.c \ ++ drivers/st/tamper/stm32_tamp.c \ ++ drivers/st/timer/stm32_timer.c \ + plat/st/stm32mp1/sp_min/sp_min_setup.c \ ++ plat/st/stm32mp1/stm32mp1_low_power.c \ + plat/st/stm32mp1/stm32mp1_pm.c \ ++ plat/st/stm32mp1/stm32mp1_power_config.c \ + plat/st/stm32mp1/stm32mp1_topology.c + # Generic GIC v2 + BL32_SOURCES += drivers/arm/gic/common/gic_common.c \ +@@ -19,3 +26,10 @@ BL32_SOURCES += drivers/arm/gic/common/gic_common.c \ + + # Generic PSCI + BL32_SOURCES += plat/common/plat_psci_common.c ++ ++# stm32mp1 specific services ++BL32_SOURCES += plat/st/stm32mp1/services/bsec_svc.c \ ++ plat/st/stm32mp1/services/low_power_svc.c \ ++ plat/st/stm32mp1/services/pwr_svc.c \ ++ plat/st/stm32mp1/services/rcc_svc.c \ ++ plat/st/stm32mp1/services/stm32mp1_svc_setup.c +diff --git a/plat/st/stm32mp1/sp_min/sp_min_setup.c b/plat/st/stm32mp1/sp_min/sp_min_setup.c +index 56598c8..e8dc409 100644 +--- a/plat/st/stm32mp1/sp_min/sp_min_setup.c ++++ b/plat/st/stm32mp1/sp_min/sp_min_setup.c +@@ -7,19 +7,32 @@ + #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 +@@ -30,22 +43,107 @@ + ******************************************************************************/ + static entry_point_info_t bl33_image_ep_info; + ++static struct console_stm32 console; ++ ++static struct stm32_tamp_int int_tamp[PLAT_MAX_TAMP_INT] = { ++ TAMP_UNUSED, ++ TAMP_UNUSED, ++ TAMP_UNUSED, ++ TAMP_UNUSED, ++ TAMP_UNUSED, ++}; ++ ++static struct stm32_tamp_ext ext_tamp[PLAT_MAX_TAMP_EXT] = { ++ TAMP_UNUSED, ++ TAMP_UNUSED, ++ TAMP_UNUSED, ++}; ++ ++static void tzc_it_handler(void) ++{ ++ ERROR("No IT handler in ARM tzc400 driver\n"); ++} ++ ++static void stm32_sgi1_it_handler(void) ++{ ++ uint32_t id; ++ ++ gicv2_end_of_interrupt(ARM_IRQ_SEC_SGI_1); ++ ++ do { ++ id = plat_ic_get_pending_interrupt_id(); ++ ++ if (id <= MAX_SPI_ID) { ++ gicv2_end_of_interrupt(id); ++ ++ plat_ic_disable_interrupt(id); ++ } ++ } while (id <= MAX_SPI_ID); ++ ++ ++ isb(); ++ dsb(); ++ ++ /* Flush L1/L2 data caches */ ++ write_sctlr(read_sctlr() & ~SCTLR_C_BIT); ++ dcsw_op_all(DC_OP_CISW); ++ ++ for ( ; ; ) { ++ wfi(); ++ } ++} ++ + /******************************************************************************* + * Interrupt handler for FIQ (secure IRQ) + ******************************************************************************/ + void sp_min_plat_fiq_handler(uint32_t id) + { +- switch (id) { ++ uint32_t value = 0; ++ ++ switch (id & INT_ID_MASK) { ++ case ARM_IRQ_SEC_PHY_TIMER: ++ case STM32MP1_IRQ_MCU_SEV: ++ case STM32MP1_IRQ_RCC_WAKEUP: ++ stm32mp1_rcc_it_handler(id); ++ break; + case STM32MP1_IRQ_TZC400: +- ERROR("STM32MP1_IRQ_TZC400 generated\n"); ++ tzc400_init(STM32MP1_TZC_BASE); ++ tzc400_it_handler(); + panic(); + break; ++ case STM32MP1_IRQ_TAMPSERRS: ++ stm32_tamp_it_handler(); ++ break; ++ case ARM_IRQ_SEC_SGI_1: ++ stm32_sgi1_it_handler(); ++ break; ++ case STM32MP1_IRQ_IWDG1: ++ case STM32MP1_IRQ_IWDG2: ++ stm32_iwdg_it_handler(id); ++ break; + case STM32MP1_IRQ_AXIERRIRQ: + ERROR("STM32MP1_IRQ_AXIERRIRQ generated\n"); ++ tzc400_init(STM32MP1_TZC_BASE); ++ __asm__("mrc p15, 1, %0, c9, c0, 3" : "=r" (value)); ++ if (value) { ++ /* we have a pending IT clear it */ ++ value = 0; ++ __asm__("mcr p15, 1, %0, c9, c0, 3" :: "r" (value)); ++ } else { ++ ERROR("IRQ_AXIERRIRQ handle call w/o any flag set!!\n"); ++ } ++ ++ /* Check if FIQ has been generated due to TZC400 abort*/ ++ if (tzc400_is_pending_interrupt()) { ++ tzc_it_handler(); ++ } else { ++ ERROR("IRQ_AXIERRIRQ cause can't be detected"); ++ } ++ + panic(); + break; + default: +- ERROR("SECURE IT handler not define for it : %i", id); ++ ERROR("SECURE IT handler not define for it : %u", id); + break; + } + } +@@ -59,11 +157,54 @@ void sp_min_plat_fiq_handler(uint32_t id) + entry_point_info_t *sp_min_plat_get_bl33_ep_info(void) + { + entry_point_info_t *next_image_info; ++ uint32_t bkpr_core1_addr = ++ tamp_bkpr(BOOT_API_CORE1_BRANCH_ADDRESS_TAMP_BCK_REG_IDX); ++ uint32_t bkpr_core1_magic = ++ tamp_bkpr(BOOT_API_CORE1_MAGIC_NUMBER_TAMP_BCK_REG_IDX); + + next_image_info = &bl33_image_ep_info; + ++ /* ++ * PC is set to 0 when resetting after STANDBY ++ * The context should be restored, and the image information ++ * should be filled with what what was saved ++ */ + if (next_image_info->pc == 0U) { +- return NULL; ++ void *cpu_context; ++ uint32_t magic_nb, saved_pc; ++ ++ stm32mp_clk_enable(RTCAPB); ++ ++ magic_nb = mmio_read_32(bkpr_core1_magic); ++ saved_pc = mmio_read_32(bkpr_core1_addr); ++ ++ stm32mp_clk_disable(RTCAPB); ++ ++ if (stm32_restore_context() != 0) { ++ panic(); ++ } ++ ++ cpu_context = cm_get_context(NON_SECURE); ++ ++ next_image_info->spsr = read_ctx_reg(get_regs_ctx(cpu_context), ++ CTX_SPSR); ++ ++ /* PC should be retrieved in backup register if OK, else it can ++ * be retrieved from non-secure context ++ */ ++ if (magic_nb == BOOT_API_A7_CORE0_MAGIC_NUMBER) { ++ /* BL33 return address should be in DDR */ ++ if ((saved_pc < STM32MP_DDR_BASE) || ++ (saved_pc > (STM32MP_DDR_BASE + ++ (dt_get_ddr_size() - 1U)))) { ++ panic(); ++ } ++ ++ next_image_info->pc = saved_pc; ++ } else { ++ next_image_info->pc = ++ read_ctx_reg(get_regs_ctx(cpu_context), CTX_LR); ++ } + } + + return next_image_info; +@@ -75,6 +216,9 @@ entry_point_info_t *sp_min_plat_get_bl33_ep_info(void) + void sp_min_early_platform_setup2(u_register_t arg0, u_register_t arg1, + u_register_t arg2, u_register_t arg3) + { ++#if STM32MP_UART_PROGRAMMER ++ uint32_t boot_itf, boot_instance; ++#endif + struct dt_node_info dt_dev_info; + int result; + bl_params_t *params_from_bl2 = (bl_params_t *)arg0; +@@ -105,18 +249,78 @@ void sp_min_early_platform_setup2(u_register_t arg0, u_register_t arg1, + panic(); + } + ++ if (bsec_probe() != 0) { ++ panic(); ++ } ++ + if (stm32mp1_clk_probe() < 0) { + panic(); + } + ++ /* Initialize uart for console except if it is used by programmer */ + result = dt_get_stdout_uart_info(&dt_dev_info); ++#if STM32MP_UART_PROGRAMMER ++ stm32_get_boot_interface(&boot_itf, &boot_instance); + ++ if ((result > 0) && dt_dev_info.status && ++ !((boot_itf == BOOT_API_CTX_BOOT_INTERFACE_SEL_SERIAL_UART) && ++ (get_uart_address(boot_instance) == dt_dev_info.base))) { ++#else + if ((result > 0) && dt_dev_info.status) { +- if (console_init(dt_dev_info.base, 0, STM32MP1_UART_BAUDRATE) +- == 0) { ++#endif ++ if (console_stm32_register(dt_dev_info.base, 0, ++ STM32MP_UART_BAUDRATE, &console) == ++ 0) { + panic(); + } + } ++ ++ if (dt_pmic_status() > 0) { ++ initialize_pmic(); ++ } ++ ++ stm32mp1_init_lp_states(); ++} ++ ++/******************************************************************************* ++ * Set security setup in sp_min ++ ******************************************************************************/ ++void stm32mp1_sp_min_security_setup(void) ++{ ++ uint32_t filter_conf = 0; ++ uint32_t active_conf = 0; ++ int ret; ++ ++ if (etzpc_init() != 0) { ++ ERROR("ETZPC configuration issue\n"); ++ panic(); ++ } ++ ++ /* Init rtc driver */ ++ ret = stm32_rtc_init(); ++ if (ret < 0) { ++ WARN("RTC driver init error %i\n", ret); ++ } ++ ++ /* Init rng driver */ ++ ret = stm32_rng_init(); ++ if (ret < 0) { ++ WARN("RNG driver init error %i\n", ret); ++ } ++ ++ /* Init tamper */ ++ if (stm32_tamp_init() > 0) { ++ stm32_tamp_configure_internal(int_tamp, PLAT_MAX_TAMP_INT); ++ stm32_tamp_configure_external(ext_tamp, PLAT_MAX_TAMP_EXT, ++ filter_conf, active_conf); ++ ++ /* Enable timestamp for tamper */ ++ stm32_rtc_set_tamper_timestamp(); ++ } ++ ++ if (stm32_timer_init() == 0) { ++ stm32mp1_cal_init(); ++ } + } + + /******************************************************************************* +@@ -128,6 +332,16 @@ void sp_min_platform_setup(void) + BL_CODE_END - BL_CODE_BASE, + MT_CODE | MT_SECURE); + ++#if SEPARATE_CODE_AND_RODATA ++ mmap_add_region(BL_RO_DATA_BASE, BL_RO_DATA_BASE, ++ BL_RO_DATA_LIMIT - BL_RO_DATA_BASE, ++ MT_RO_DATA | MT_SECURE); ++#endif ++ ++ mmap_add_region(STM32MP_DDR_BASE, STM32MP_DDR_BASE, ++ dt_get_ddr_size() - STM32MP_DDR_S_SIZE, ++ MT_MEMORY | MT_RW | MT_NS); ++ + configure_mmu(); + + /* Initialize tzc400 after DDR initialization */ +@@ -136,8 +350,21 @@ void sp_min_platform_setup(void) + generic_delay_timer_init(); + + stm32mp1_gic_init(); ++ ++ /* Update security settings */ ++ stm32mp1_sp_min_security_setup(); ++ ++ if (stm32_iwdg_init() < 0) { ++ panic(); ++ } ++ ++ stm32mp1_driver_init_late(); + } + + void sp_min_plat_arch_setup(void) + { + } ++ ++void sp_min_plat_runtime_setup(void) ++{ ++} +diff --git a/plat/st/stm32mp1/stm32mp1.ld.S b/plat/st/stm32mp1/stm32mp1.ld.S +index 0d7a8bb..a9cc26b 100644 +--- a/plat/st/stm32mp1/stm32mp1.ld.S ++++ b/plat/st/stm32mp1/stm32mp1.ld.S +@@ -4,8 +4,9 @@ + * SPDX-License-Identifier: BSD-3-Clause + */ + +-#ifndef __STM32MP1_LD_S__ +-#define __STM32MP1_LD_S__ ++#ifndef STM32MP1_LD_S ++#define STM32MP1_LD_S ++ + #include + #include + +@@ -16,7 +17,7 @@ ENTRY(__BL2_IMAGE_START__) + + MEMORY { + HEADER (rw) : ORIGIN = 0x00000000, LENGTH = 0x3000 +- RAM (rwx) : ORIGIN = STM32MP1_BINARY_BASE, LENGTH = STM32MP1_BINARY_SIZE ++ RAM (rwx) : ORIGIN = STM32MP_BINARY_BASE, LENGTH = STM32MP_BINARY_SIZE + } + + SECTIONS +@@ -31,7 +32,7 @@ SECTIONS + __HEADER_END__ = .; + } >HEADER + +- . = STM32MP1_BINARY_BASE; ++ . = STM32MP_BINARY_BASE; + .data . : { + . = ALIGN(PAGE_SIZE); + __DATA_START__ = .; +@@ -42,7 +43,7 @@ SECTIONS + * The strongest and only alignment contraint is MMU 4K page. + * Indeed as images below will be removed, 4K pages will be re-used. + */ +- . = ( STM32MP1_DTB_BASE - STM32MP1_BINARY_BASE ); ++ . = ( STM32MP_DTB_BASE - STM32MP_BINARY_BASE ); + __DTB_IMAGE_START__ = .; + *(.dtb_image*) + __DTB_IMAGE_END__ = .; +@@ -52,20 +53,22 @@ SECTIONS + * The strongest and only alignment contraint is MMU 4K page. + * Indeed as images below will be removed, 4K pages will be re-used. + */ +- . = ( STM32MP1_BL2_BASE - STM32MP1_BINARY_BASE ); ++ . = ( STM32MP_BL2_BASE - STM32MP_BINARY_BASE ); + __BL2_IMAGE_START__ = .; + *(.bl2_image*) + __BL2_IMAGE_END__ = .; + ++#ifndef AARCH32_SP_OPTEE + /* + * bl32 will be settled by bl2. + * The strongest and only alignment constraint is 8 words to simplify + * memraise8 assembly code. + */ +- . = ( STM32MP1_BL32_BASE - STM32MP1_BINARY_BASE ); ++ . = ( STM32MP_BL32_BASE - STM32MP_BINARY_BASE ); + __BL32_IMAGE_START__ = .; + *(.bl32_image*) + __BL32_IMAGE_END__ = .; ++#endif + + __DATA_END__ = .; + } >RAM +@@ -73,4 +76,4 @@ SECTIONS + __TF_END__ = .; + + } +-#endif /*__STM32MP1_LD_S__*/ ++#endif /* STM32MP1_LD_S */ +diff --git a/plat/st/stm32mp1/stm32mp1_common.c b/plat/st/stm32mp1/stm32mp1_common.c +deleted file mode 100644 +index 7d84da1..0000000 +--- a/plat/st/stm32mp1/stm32mp1_common.c ++++ /dev/null +@@ -1,101 +0,0 @@ +-/* +- * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. +- * +- * SPDX-License-Identifier: BSD-3-Clause +- */ +- +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +- +-#define MAP_SRAM MAP_REGION_FLAT(STM32MP1_SRAM_BASE, \ +- STM32MP1_SRAM_SIZE, \ +- MT_MEMORY | \ +- MT_RW | \ +- MT_SECURE | \ +- MT_EXECUTE_NEVER) +- +-#define MAP_DEVICE1 MAP_REGION_FLAT(STM32MP1_DEVICE1_BASE, \ +- STM32MP1_DEVICE1_SIZE, \ +- MT_DEVICE | \ +- MT_RW | \ +- MT_SECURE | \ +- MT_EXECUTE_NEVER) +- +-#define MAP_DEVICE2 MAP_REGION_FLAT(STM32MP1_DEVICE2_BASE, \ +- STM32MP1_DEVICE2_SIZE, \ +- MT_DEVICE | \ +- MT_RW | \ +- MT_SECURE | \ +- MT_EXECUTE_NEVER) +- +-#define MAP_DDR MAP_REGION_FLAT(STM32MP1_DDR_BASE, \ +- STM32MP1_DDR_MAX_SIZE, \ +- MT_MEMORY | \ +- MT_RW | \ +- MT_SECURE | \ +- MT_EXECUTE_NEVER) +- +-#define MAP_DDR_NS MAP_REGION_FLAT(STM32MP1_DDR_BASE, \ +- STM32MP1_DDR_MAX_SIZE, \ +- MT_MEMORY | \ +- MT_RW | \ +- MT_NS | \ +- MT_EXECUTE_NEVER) +- +-#if defined(IMAGE_BL2) +-static const mmap_region_t stm32mp1_mmap[] = { +- MAP_SRAM, +- MAP_DEVICE1, +- MAP_DEVICE2, +- MAP_DDR, +- {0} +-}; +-#endif +-#if defined(IMAGE_BL32) +-static const mmap_region_t stm32mp1_mmap[] = { +- MAP_SRAM, +- MAP_DEVICE1, +- MAP_DEVICE2, +- MAP_DDR_NS, +- {0} +-}; +-#endif +- +-void configure_mmu(void) +-{ +- mmap_add(stm32mp1_mmap); +- init_xlat_tables(); +- +- enable_mmu_svc_mon(0); +-} +- +-uintptr_t plat_get_ns_image_entrypoint(void) +-{ +- return BL33_BASE; +-} +- +-unsigned int plat_get_syscnt_freq2(void) +-{ +- return read_cntfrq_el0(); +-} +- +-/* Functions to save and get boot context address given by ROM code */ +-static uintptr_t boot_ctx_address; +- +-void stm32mp1_save_boot_ctx_address(uintptr_t address) +-{ +- boot_ctx_address = address; +-} +- +-uintptr_t stm32mp1_get_boot_ctx_address(void) +-{ +- return boot_ctx_address; +-} +diff --git a/plat/st/stm32mp1/stm32mp1_context.c b/plat/st/stm32mp1/stm32mp1_context.c +index 245fd17..8dc1146 100644 +--- a/plat/st/stm32mp1/stm32mp1_context.c ++++ b/plat/st/stm32mp1/stm32mp1_context.c +@@ -4,39 +4,235 @@ + * SPDX-License-Identifier: BSD-3-Clause + */ + ++#include ++#include ++#include ++#include + #include + #include + #include + #include ++#include ++#include + #include + #include ++#include ++#include ++#include ++#include + + #define TAMP_BOOT_ITF_BACKUP_REG_ID U(20) + #define TAMP_BOOT_ITF_MASK U(0x0000FF00) + #define TAMP_BOOT_ITF_SHIFT 8 + ++#define TRAINING_AREA_SIZE 64 ++ ++#ifdef AARCH32_SP_OPTEE ++/* OPTEE_MAILBOX_MAGIC relates to struct backup_data_s as defined */ ++#define OPTEE_MAILBOX_MAGIC_V1 0x01 ++#define OPTEE_MAILBOX_MAGIC ((OPTEE_MAILBOX_MAGIC_V1 << 16) + \ ++ TRAINING_AREA_SIZE) ++#endif ++ ++struct backup_data_s { ++#ifdef AARCH32_SP_OPTEE ++ uint32_t magic; ++ uint32_t core0_resume_hint; ++ uint32_t zq0cr0_zdata; ++ uint8_t ddr_training_backup[TRAINING_AREA_SIZE]; ++#else ++ smc_ctx_t saved_smc_context[PLATFORM_CORE_COUNT]; ++ cpu_context_t saved_cpu_context[PLATFORM_CORE_COUNT]; ++ uint32_t zq0cr0_zdata; ++ struct stm32_rtc_calendar rtc; ++ uint8_t ddr_training_backup[TRAINING_AREA_SIZE]; ++#endif ++}; ++ ++#ifdef AARCH32_SP_OPTEE ++uint32_t stm32_pm_get_optee_ep(void) ++{ ++ struct backup_data_s *backup_data; ++ uint32_t ep; ++ ++ stm32mp_clk_enable(BKPSRAM); ++ ++ /* Context & Data to be saved at the beginning of Backup SRAM */ ++ backup_data = (struct backup_data_s *)STM32MP_BACKUP_RAM_BASE; ++ ++ if (backup_data->magic != OPTEE_MAILBOX_MAGIC) { ++ panic(); ++ } ++ ++ ep = backup_data->core0_resume_hint; ++ ++ stm32mp_clk_disable(BKPSRAM); ++ ++ return ep; ++} ++#else /*AARCH32_SP_OPTEE*/ ++void stm32_clean_context(void) ++{ ++ stm32mp_clk_enable(BKPSRAM); ++ ++ zeromem((void *)STM32MP_BACKUP_RAM_BASE, sizeof(struct backup_data_s)); ++ ++ stm32mp_clk_disable(BKPSRAM); ++} ++ ++int stm32_save_context(uint32_t zq0cr0_zdata) ++{ ++ void *smc_context; ++ void *cpu_context; ++ struct backup_data_s *backup_data; ++ ++ stm32mp_clk_enable(BKPSRAM); ++ ++ /* Context & Data to be saved at the beginning of Backup SRAM */ ++ backup_data = (struct backup_data_s *)STM32MP_BACKUP_RAM_BASE; ++ ++ /* Retrieve smc context struct address */ ++ smc_context = smc_get_ctx(NON_SECURE); ++ ++ /* Retrieve smc context struct address */ ++ cpu_context = cm_get_context(NON_SECURE); ++ ++ /* Save context in Backup SRAM */ ++ memcpy(&backup_data->saved_smc_context[0], smc_context, ++ sizeof(smc_ctx_t) * PLATFORM_CORE_COUNT); ++ memcpy(&backup_data->saved_cpu_context[0], cpu_context, ++ sizeof(cpu_context_t) * PLATFORM_CORE_COUNT); ++ ++ backup_data->zq0cr0_zdata = zq0cr0_zdata; ++ ++ stm32_rtc_get_calendar(&backup_data->rtc); ++ ++ stm32mp_clk_disable(BKPSRAM); ++ ++ return 0; ++} ++ ++int stm32_restore_context(void) ++{ ++ void *smc_context; ++ void *cpu_context; ++ struct backup_data_s *backup_data; ++ struct stm32_rtc_calendar current_calendar; ++ unsigned long long stdby_time_in_ms; ++ ++ stm32mp_clk_enable(BKPSRAM); ++ ++ /* Context & Data to be saved at the beginning of Backup SRAM */ ++ backup_data = (struct backup_data_s *)STM32MP_BACKUP_RAM_BASE; ++ ++ /* Retrieve smc context struct address */ ++ smc_context = smc_get_ctx(NON_SECURE); ++ ++ /* Retrieve smc context struct address */ ++ cpu_context = cm_get_context(NON_SECURE); ++ ++ /* Restore data from Backup SRAM */ ++ memcpy(smc_context, backup_data->saved_smc_context, ++ sizeof(smc_ctx_t) * PLATFORM_CORE_COUNT); ++ memcpy(cpu_context, backup_data->saved_cpu_context, ++ sizeof(cpu_context_t) * PLATFORM_CORE_COUNT); ++ ++ /* update STGEN counter with standby mode length */ ++ stm32_rtc_get_calendar(¤t_calendar); ++ stdby_time_in_ms = stm32_rtc_diff_calendar(¤t_calendar, ++ &backup_data->rtc); ++ stm32mp1_stgen_increment(stdby_time_in_ms); ++ ++ stm32mp_clk_disable(BKPSRAM); ++ ++ return 0; ++} ++#endif /*AARCH32_SP_OPTEE*/ ++ ++uint32_t stm32_get_zdata_from_context(void) ++{ ++ struct backup_data_s *backup_data; ++ uint32_t zdata; ++ ++ stm32mp_clk_enable(BKPSRAM); ++ ++ backup_data = (struct backup_data_s *)STM32MP_BACKUP_RAM_BASE; ++ ++ zdata = (backup_data->zq0cr0_zdata >> DDRPHYC_ZQ0CRN_ZDATA_SHIFT) & ++ DDRPHYC_ZQ0CRN_ZDATA_MASK; ++ ++ stm32mp_clk_disable(BKPSRAM); ++ ++ return zdata; ++} ++ + int stm32_save_boot_interface(uint32_t interface, uint32_t instance) + { +- uint32_t tamp_clk_off = 0; + uint32_t bkpr_itf_idx = tamp_bkpr(TAMP_BOOT_ITF_BACKUP_REG_ID); + +- if (!stm32mp1_clk_is_enabled(RTCAPB)) { +- tamp_clk_off = 1; +- if (stm32mp1_clk_enable(RTCAPB) != 0) { +- return -EINVAL; +- } +- } ++ stm32mp_clk_enable(RTCAPB); + + mmio_clrsetbits_32(bkpr_itf_idx, + TAMP_BOOT_ITF_MASK, + ((interface << 4) | (instance & 0xFU)) << + TAMP_BOOT_ITF_SHIFT); + +- if (tamp_clk_off != 0U) { +- if (stm32mp1_clk_disable(RTCAPB) != 0) { +- return -EINVAL; +- } +- } ++ stm32mp_clk_disable(RTCAPB); + + return 0; + } ++ ++int stm32_get_boot_interface(uint32_t *interface, uint32_t *instance) ++{ ++ uint32_t backup_reg_itf; ++ uint32_t bkpr_itf_idx = tamp_bkpr(TAMP_BOOT_ITF_BACKUP_REG_ID); ++ ++ stm32mp_clk_enable(RTCAPB); ++ ++ backup_reg_itf = (mmio_read_32(bkpr_itf_idx) & ++ TAMP_BOOT_ITF_MASK) >> TAMP_BOOT_ITF_SHIFT; ++ ++ stm32mp_clk_disable(RTCAPB); ++ ++ *interface = backup_reg_itf >> 4; ++ *instance = backup_reg_itf & 0xFU; ++ ++ return 0; ++} ++ ++/* ++ * 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, and will be restored after ++ */ ++void stm32_save_ddr_training_area(void) ++{ ++ struct backup_data_s *backup_data; ++ ++ stm32mp_clk_enable(BKPSRAM); ++ ++ backup_data = (struct backup_data_s *)STM32MP_BACKUP_RAM_BASE; ++ ++ memcpy(&backup_data->ddr_training_backup, ++ (const uint32_t *)STM32MP_DDR_BASE, ++ TRAINING_AREA_SIZE); ++ dsb(); ++ ++ stm32mp_clk_disable(BKPSRAM); ++} ++ ++void stm32_restore_ddr_training_area(void) ++{ ++ struct backup_data_s *backup_data; ++ ++ stm32mp_clk_enable(BKPSRAM); ++ ++ backup_data = (struct backup_data_s *)STM32MP_BACKUP_RAM_BASE; ++ ++ memcpy((uint32_t *)STM32MP_DDR_BASE, ++ &backup_data->ddr_training_backup, ++ TRAINING_AREA_SIZE); ++ dsb(); ++ ++ stm32mp_clk_disable(BKPSRAM); ++} +diff --git a/plat/st/stm32mp1/stm32mp1_dbgmcu.c b/plat/st/stm32mp1/stm32mp1_dbgmcu.c +new file mode 100644 +index 0000000..716f7d8 +--- /dev/null ++++ b/plat/st/stm32mp1/stm32mp1_dbgmcu.c +@@ -0,0 +1,153 @@ ++/* ++ * Copyright (c) 2016-2018, STMicroelectronics - All Rights Reserved ++ * ++ * SPDX-License-Identifier: BSD-3-Clause ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define DBGMCU_IDC 0x0U ++#define IDC_DEV_ID_MASK GENMASK(11, 0) ++#define DBGMCU_APB4FZ1 0x2CU ++#define DBGMCU_APB4FZ1_IWDG2 BIT(2) ++ ++#define TAMP_DBG_BACKUP_REG_ID 20 ++#define TAMP_DBG_DEBUG BIT(16) ++ ++static uintptr_t get_rcc_base(void) ++{ ++ /* This is called before stm32mp_rcc_base() is available */ ++ return RCC_BASE; ++} ++ ++static int stm32mp1_dbgmcu_init(void) ++{ ++ uint32_t dbg_conf; ++ uintptr_t rcc_base = get_rcc_base(); ++ ++ dbg_conf = bsec_read_debug_conf(); ++ ++ if ((dbg_conf & BSEC_DBGSWGEN) == 0U) { ++ uint32_t result = bsec_write_debug_conf(dbg_conf | ++ BSEC_DBGSWGEN); ++ ++ if (result != BSEC_OK) { ++ ERROR("Error enabling DBGSWGEN\n"); ++ return (int)result; ++ } ++ } ++ ++ if ((mmio_read_32(rcc_base + RCC_DBGCFGR) & RCC_DBGCFGR_DBGCKEN) == ++ 0U) { ++ mmio_setbits_32(rcc_base + RCC_DBGCFGR, RCC_DBGCFGR_DBGCKEN); ++ } ++ ++ return 0; ++} ++ ++#if STM32MP1_DEBUG_ENABLE ++int stm32mp1_dbgmcu_boot_debug_info(void) ++{ ++ uint32_t backup_reg_dbg; ++ ++ stm32mp_clk_enable(RTCAPB); ++ ++ backup_reg_dbg = (mmio_read_32(tamp_bkpr(TAMP_DBG_BACKUP_REG_ID)) ++ & TAMP_DBG_DEBUG); ++ ++ stm32mp_clk_disable(RTCAPB); ++ ++ if (backup_reg_dbg != 0U) { ++ return 1; ++ } ++ ++ return 0; ++} ++ ++int stm32mp1_dbgmcu_clear_boot_info(void) ++{ ++ stm32mp_clk_enable(RTCAPB); ++ ++ mmio_clrbits_32(tamp_bkpr(TAMP_DBG_BACKUP_REG_ID), ++ TAMP_DBG_DEBUG); ++ ++ stm32mp_clk_disable(RTCAPB); ++ ++ return 0; ++} ++ ++uint32_t stm32mp1_dbgmcu_is_debug_on(void) ++{ ++ uint32_t dbg_conf; ++ ++ dbg_conf = bsec_read_debug_conf(); ++ ++ return (dbg_conf & (BSEC_SPIDEN | BSEC_SPINDEN)); ++} ++ ++#if LOG_LEVEL >= LOG_LEVEL_VERBOSE ++void stm32mp1_dbgmcu_hexdump8(uint8_t *buf, uint32_t len) ++{ ++ uint32_t i; ++ ++ VERBOSE(" "); ++ for (i = 0; i < len; i++) { ++ printf("%02x ", buf[i]); ++ if (((i + 1) % 16) == 0) { ++ if ((i + 1) < len) { ++ printf("\n"); ++ VERBOSE(" "); ++ } ++ } else if (((i + 1) % 8) == 0) { ++ printf(" "); ++ } ++ } ++ printf("\n"); ++} ++#endif ++#endif ++ ++uint32_t stm32mp1_dbgmcu_get_chip_version(void) ++{ ++ if (stm32mp1_dbgmcu_init() == 0) { ++ return (mmio_read_32(DBGMCU_BASE + DBGMCU_IDC) >> 16); ++ } ++ ++ return 0; ++} ++ ++uint32_t stm32mp1_dbgmcu_get_chip_dev_id(void) ++{ ++ if (stm32mp1_dbgmcu_init() == 0) { ++ return (mmio_read_32(DBGMCU_BASE + DBGMCU_IDC) & ++ IDC_DEV_ID_MASK); ++ } ++ ++ return 0; ++} ++ ++int stm32mp1_dbgmcu_freeze_iwdg2(void) ++{ ++ if (stm32mp1_dbgmcu_init() == 0) { ++ uint32_t dbg_conf = bsec_read_debug_conf(); ++ ++ if (((dbg_conf & BSEC_SPIDEN) != 0U) || ++ ((dbg_conf & BSEC_SPINDEN) != 0U)) { ++ mmio_setbits_32(DBGMCU_BASE + DBGMCU_APB4FZ1, ++ DBGMCU_APB4FZ1_IWDG2); ++ } ++ ++ return 0; ++ } ++ ++ return -EPERM; ++} +diff --git a/plat/st/stm32mp1/stm32mp1_def.h b/plat/st/stm32mp1/stm32mp1_def.h +index bb3fecf..a6b1a7b 100644 +--- a/plat/st/stm32mp1/stm32mp1_def.h ++++ b/plat/st/stm32mp1/stm32mp1_def.h +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. ++ * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +@@ -7,84 +7,206 @@ + #ifndef STM32MP1_DEF_H + #define STM32MP1_DEF_H + ++#ifndef __ASSEMBLY__ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#endif + #include + #include + #include + ++#define AUTHENTICATE_BL33 ++ ++/******************************************************************************* ++ * CHIP ID ++ ******************************************************************************/ ++#define STM32MP157C_PART_NB U(0x05000000) ++#define STM32MP157A_PART_NB U(0x05000001) ++#define STM32MP153C_PART_NB U(0x05000024) ++#define STM32MP153A_PART_NB U(0x05000025) ++#define STM32MP151C_PART_NB U(0x0500002E) ++#define STM32MP151A_PART_NB U(0x0500002F) ++ ++#define STM32MP1_REV_A U(0x1000) ++#define STM32MP1_REV_B U(0x2000) ++ ++/******************************************************************************* ++ * PACKAGE ID ++ ******************************************************************************/ ++#define PKG_AA_LBGA448 U(4) ++#define PKG_AB_LBGA354 U(3) ++#define PKG_AC_TFBGA361 U(2) ++#define PKG_AD_TFBGA257 U(1) ++ ++/******************************************************************************* ++ * BOOT PARAM ++ ******************************************************************************/ ++#define BOOT_PARAM_ADDR U(0x2FFC0078) ++ + /******************************************************************************* + * STM32MP1 memory map related constants + ******************************************************************************/ ++#define STM32MP_ROM_BASE U(0x00000000) ++#define STM32MP_ROM_SIZE U(0x00020000) ++ ++#define STM32MP_SYSRAM_BASE U(0x2FFC0000) ++#define STM32MP_SYSRAM_SIZE U(0x00040000) ++ ++/* 384 Ko (128 x 3) Non secure from MCU available for TF*/ ++#define STM32MP_SRAM_MCU_BASE U(0x30000000) ++#define STM32MP_SRAM_MCU_SIZE U(0x00060000) + +-#define STM32MP1_SRAM_BASE U(0x2FFC0000) +-#define STM32MP1_SRAM_SIZE U(0x00040000) ++#define STM32MP_RETRAM_BASE U(0x38000000) ++#define STM32MP_RETRAM_SIZE U(0x00010000) ++ ++#define STM32MP_BACKUP_RAM_BASE U(0x54000000) ++#define STM32MP_BACKUP_RAM_SIZE U(0x00001000) + + /* DDR configuration */ +-#define STM32MP1_DDR_BASE U(0xC0000000) +-#define STM32MP1_DDR_SIZE_DFLT U(0x20000000) /* 512 MB */ +-#define STM32MP1_DDR_MAX_SIZE U(0x40000000) /* Max 1GB */ +-#define STM32MP1_DDR_SPEED_DFLT 528 ++#define STM32MP_DDR_BASE U(0xC0000000) ++#define STM32MP_DDR_MAX_SIZE U(0x40000000) /* Max 1GB */ ++#ifdef AARCH32_SP_OPTEE ++#define STM32MP_DDR_S_SIZE U(0x02000000) /* 32 MB */ ++#define STM32MP_DDR_SHMEM_SIZE U(0x00200000) /* 2 MB */ ++#else ++#define STM32MP_DDR_S_SIZE U(0) /* DDR is non secure */ ++#endif + + /* DDR power initializations */ + #ifndef __ASSEMBLY__ + enum ddr_type { + STM32MP_DDR3, + STM32MP_LPDDR2, ++ STM32MP_LPDDR3, + }; + #endif + + /* Section used inside TF binaries */ +-#define STM32MP1_PARAM_LOAD_SIZE U(0x00002400) /* 9 Ko for param */ ++#define STM32MP_PARAM_LOAD_SIZE U(0x00002400) /* 9 Ko for param */ + /* 256 Octets reserved for header */ +-#define STM32MP1_HEADER_SIZE U(0x00000100) ++#define STM32MP_HEADER_SIZE U(0x00000100) + +-#define STM32MP1_BINARY_BASE (STM32MP1_SRAM_BASE + \ +- STM32MP1_PARAM_LOAD_SIZE + \ +- STM32MP1_HEADER_SIZE) ++#define STM32MP_BINARY_BASE (STM32MP_SYSRAM_BASE + \ ++ STM32MP_PARAM_LOAD_SIZE + \ ++ STM32MP_HEADER_SIZE) + +-#define STM32MP1_BINARY_SIZE (STM32MP1_SRAM_SIZE - \ +- (STM32MP1_PARAM_LOAD_SIZE + \ +- STM32MP1_HEADER_SIZE)) ++#define STM32MP_BINARY_SIZE (STM32MP_SYSRAM_SIZE - \ ++ (STM32MP_PARAM_LOAD_SIZE + \ ++ STM32MP_HEADER_SIZE)) + ++#ifdef AARCH32_SP_OPTEE ++#define STM32MP_BL32_SIZE U(0) ++ ++#define STM32MP_OPTEE_BASE STM32MP_SYSRAM_BASE ++ ++#define STM32MP_OPTEE_SIZE (STM32MP_DTB_BASE - \ ++ STM32MP_OPTEE_BASE) ++#else + #if STACK_PROTECTOR_ENABLED +-#define STM32MP1_BL32_SIZE U(0x00012000) /* 72 Ko for BL32 */ ++#define STM32MP_BL32_SIZE U(0x00011000) /* 68 Ko for BL32 */ + #else +-#define STM32MP1_BL32_SIZE U(0x00011000) /* 68 Ko for BL32 */ ++#define STM32MP_BL32_SIZE U(0x00010000) /* 64 Ko for BL32 */ ++#endif + #endif + +-#define STM32MP1_BL32_BASE (STM32MP1_SRAM_BASE + \ +- STM32MP1_SRAM_SIZE - \ +- STM32MP1_BL32_SIZE) ++#define STM32MP_BL32_BASE (STM32MP_SYSRAM_BASE + \ ++ STM32MP_SYSRAM_SIZE - \ ++ STM32MP_BL32_SIZE) + ++#ifdef AARCH32_SP_OPTEE + #if STACK_PROTECTOR_ENABLED +-#define STM32MP1_BL2_SIZE U(0x00015000) /* 84 Ko for BL2 */ ++#define STM32MP_BL2_SIZE U(0x00019000) /* 100 Ko for BL2 */ + #else +-#define STM32MP1_BL2_SIZE U(0x00013000) /* 76 Ko for BL2 */ ++#define STM32MP_BL2_SIZE U(0x00017000) /* 92 Ko for BL2 */ ++#endif ++#else ++#if STACK_PROTECTOR_ENABLED ++#define STM32MP_BL2_SIZE U(0x00018000) /* 96 Ko for BL2 */ ++#else ++#define STM32MP_BL2_SIZE U(0x00016000) /* 88 Ko for BL2 */ ++#endif + #endif + +-#define STM32MP1_BL2_BASE (STM32MP1_BL32_BASE - \ +- STM32MP1_BL2_SIZE) ++#define STM32MP_BL2_BASE (STM32MP_BL32_BASE - \ ++ STM32MP_BL2_SIZE) + +-/* BL2 and BL32/sp_min require 5 tables */ +-#define MAX_XLAT_TABLES 5 ++/* BL2 and BL32/sp_min require 7 tables */ ++#define MAX_XLAT_TABLES U(7) /* 28 Ko for mapping */ + + /* + * MAX_MMAP_REGIONS is usually: + * BL stm32mp1_mmap size + mmap regions in *_plat_arch_setup + */ + #if defined(IMAGE_BL2) ++ #if (defined STM32MP_USB) ++ #define MAX_MMAP_REGIONS 12 ++ #else + #define MAX_MMAP_REGIONS 11 ++ #endif + #endif + #if defined(IMAGE_BL32) +- #define MAX_MMAP_REGIONS 6 ++ #define MAX_MMAP_REGIONS 6 + #endif + ++#define XLAT_TABLE_OCTETSIZE U(0x1000) ++#define PLAT_XLAT_SIZE (MAX_XLAT_TABLES * \ ++ XLAT_TABLE_OCTETSIZE) ++ ++#define PLAT_XLAT_BASE (STM32MP_BL2_BASE - \ ++ PLAT_XLAT_SIZE) ++ ++/* ++ * Uncomment this to get the xlat tables back in each binary image ++ * (xlat_table sections in .lds) ++ * ++ * #undef PLAT_XLAT_BASE ++ */ ++ + /* DTB initialization value */ +-#define STM32MP1_DTB_SIZE U(0x00004000) /* 16Ko for DTB */ ++#define STM32MP_DTB_SIZE U(0x00005000) /* 20Ko for DTB */ ++ ++#define STM32MP_DTB_BASE (PLAT_XLAT_BASE - \ ++ STM32MP_DTB_SIZE) + +-#define STM32MP1_DTB_BASE (STM32MP1_BL2_BASE - \ +- STM32MP1_DTB_SIZE) ++#define STM32MP_BL33_BASE (STM32MP_DDR_BASE + U(0x100000)) + +-#define STM32MP1_BL33_BASE (STM32MP1_DDR_BASE + U(0x100000)) ++/* Define Temporary Stack size use during low power mode */ ++#define STM32MP_INT_STACK_SIZE 0x400 ++ ++/******************************************************************************* ++ * STM32MP1 RAW partition offset for MTD devices ++ ******************************************************************************/ ++#define STM32MP_NOR_BL33_OFFSET U(0x00080000) ++#ifdef AARCH32_SP_OPTEE ++#define STM32MP_NOR_TEEH_OFFSET U(0x00280000) ++#define STM32MP_NOR_TEED_OFFSET U(0x002C0000) ++#define STM32MP_NOR_TEEX_OFFSET U(0x00300000) ++#endif ++ ++#define STM32MP_NAND_BL33_OFFSET U(0x00200000) ++#ifdef AARCH32_SP_OPTEE ++#define STM32MP_NAND_TEEH_OFFSET U(0x00400000) ++#define STM32MP_NAND_TEED_OFFSET U(0x00480000) ++#define STM32MP_NAND_TEEX_OFFSET U(0x00500000) ++#endif + + /******************************************************************************* + * STM32MP1 device/io map related constants (used for MMU) +@@ -106,6 +228,60 @@ enum ddr_type { + #define PWR_BASE U(0x50001000) + + /******************************************************************************* ++ * STM32MP1 EXTI ++ ******************************************************************************/ ++#define EXTI_BASE U(0x5000D000) ++#define EXTI_TZENR1 U(0x14) ++#define EXTI_RPR3 U(0x4C) ++#define EXTI_FPR3 U(0x50) ++#define EXTI_C1IMR1 U(0x80) ++#define EXTI_C2IMR1 U(0xC0) ++#define EXTI_C2IMR2 U(0xD0) ++#define EXTI_C2IMR3 U(0xE0) ++#define EXTI_TZENR1_TZEN18 BIT(18) ++#define EXTI_IMR1_IM18 BIT(18) ++#define EXTI_RPR3_RPIF65 BIT(1) ++#define EXTI_FPR3_FPIF65 BIT(1) ++ ++/******************************************************************************* ++ * STM32MP1 RTC ++ ******************************************************************************/ ++#define RTC_BASE U(0x5C004000) ++ ++/******************************************************************************* ++ * STM32MP1 GPIO ++ ******************************************************************************/ ++#define GPIOA_BASE U(0x50002000) ++#define GPIOB_BASE U(0x50003000) ++#define GPIOC_BASE U(0x50004000) ++#define GPIOD_BASE U(0x50005000) ++#define GPIOE_BASE U(0x50006000) ++#define GPIOF_BASE U(0x50007000) ++#define GPIOG_BASE U(0x50008000) ++#define GPIOH_BASE U(0x50009000) ++#define GPIOI_BASE U(0x5000A000) ++#define GPIOJ_BASE U(0x5000B000) ++#define GPIOK_BASE U(0x5000C000) ++#define GPIOZ_BASE U(0x54004000) ++#define GPIO_BANK_OFFSET U(0x1000) ++ ++/* Bank IDs used in GPIO driver API */ ++#define GPIO_BANK_A U(0) ++#define GPIO_BANK_B U(1) ++#define GPIO_BANK_C U(2) ++#define GPIO_BANK_D U(3) ++#define GPIO_BANK_E U(4) ++#define GPIO_BANK_F U(5) ++#define GPIO_BANK_G U(6) ++#define GPIO_BANK_H U(7) ++#define GPIO_BANK_I U(8) ++#define GPIO_BANK_J U(9) ++#define GPIO_BANK_K U(10) ++#define GPIO_BANK_Z U(25) ++ ++#define STM32MP_GPIOZ_PIN_MAX_COUNT 8 ++ ++/******************************************************************************* + * STM32MP1 UART + ******************************************************************************/ + #define USART1_BASE U(0x5C000000) +@@ -116,16 +292,31 @@ enum ddr_type { + #define USART6_BASE U(0x44003000) + #define UART7_BASE U(0x40018000) + #define UART8_BASE U(0x40019000) +-#define STM32MP1_DEBUG_USART_BASE UART4_BASE +-#define STM32MP1_UART_BAUDRATE 115200 ++#define STM32MP_UART_BAUDRATE U(115200) ++ ++/* For UART crash console */ ++#define STM32MP_DEBUG_USART_BASE UART4_BASE ++/* UART4 on HSI@64MHz, TX on GPIOG11 Alternate 6 */ ++#define STM32MP_DEBUG_USART_CLK_FRQ 64000000 ++#define DEBUG_UART_TX_GPIO_BANK_ADDRESS GPIOG_BASE ++#define DEBUG_UART_TX_GPIO_BANK_CLK_REG RCC_MP_AHB4ENSETR ++#define DEBUG_UART_TX_GPIO_BANK_CLK_EN RCC_MP_AHB4ENSETR_GPIOGEN ++#define DEBUG_UART_TX_GPIO_PORT 11 ++#define DEBUG_UART_TX_GPIO_ALTERNATE 6 ++#define DEBUG_UART_TX_CLKSRC_REG RCC_UART24CKSELR ++#define DEBUG_UART_TX_CLKSRC RCC_UART24CKSELR_HSI ++#define DEBUG_UART_TX_EN_REG RCC_MP_APB1ENSETR ++#define DEBUG_UART_TX_EN RCC_MP_APB1ENSETR_UART4EN + + /******************************************************************************* +- * STM32MP1 GIC-400 ++ * STM32MP1 TZPC + ******************************************************************************/ +-#define STM32MP1_GICD_BASE U(0xA0021000) +-#define STM32MP1_GICC_BASE U(0xA0022000) +-#define STM32MP1_GICH_BASE U(0xA0024000) +-#define STM32MP1_GICV_BASE U(0xA0026000) ++#define STM32MP1_ETZPC_BASE U(0x5C007000) ++#define STM32MP1_ETZPC_SIZE U(0x000003FF) ++ ++#define STM32MP1_ETZPC_TZMA_ROM_ID U(0) ++/*SYSRAM internal RAM*/ ++#define STM32MP1_ETZPC_TZMA_RAM_ID U(1) + + /******************************************************************************* + * STM32MP1 TZC (TZ400) +@@ -133,6 +324,7 @@ enum ddr_type { + #define STM32MP1_TZC_BASE U(0x5C006000) + + #define STM32MP1_TZC_A7_ID U(0) ++#define STM32MP1_TZC_M4_ID U(1) + #define STM32MP1_TZC_LCD_ID U(3) + #define STM32MP1_TZC_GPU_ID U(4) + #define STM32MP1_TZC_MDMA_ID U(5) +@@ -143,28 +335,117 @@ enum ddr_type { + #define STM32MP1_TZC_ETH_ID U(10) + #define STM32MP1_TZC_DAP_ID U(15) + +-#define STM32MP1_MEMORY_NS 0 +-#define STM32MP1_MEMORY_SECURE 1 +- +-#define STM32MP1_FILTER_BIT_ALL 3 ++#define STM32MP1_FILTER_BIT_ALL U(3) + + /******************************************************************************* + * STM32MP1 SDMMC + ******************************************************************************/ +-#define STM32MP1_SDMMC1_BASE U(0x58005000) +-#define STM32MP1_SDMMC2_BASE U(0x58007000) +-#define STM32MP1_SDMMC3_BASE U(0x48004000) ++#define STM32MP_SDMMC1_BASE U(0x58005000) ++#define STM32MP_SDMMC2_BASE U(0x58007000) ++#define STM32MP_SDMMC3_BASE U(0x48004000) + +-#define STM32MP1_SD_INIT_FREQ 400000 /*400 KHz*/ +-#define STM32MP1_SD_NORMAL_SPEED_MAX_FREQ 25000000 /*25 MHz*/ +-#define STM32MP1_SD_HIGH_SPEED_MAX_FREQ 50000000 /*50 MHz*/ +-#define STM32MP1_EMMC_INIT_FREQ STM32MP1_SD_INIT_FREQ +-#define STM32MP1_EMMC_NORMAL_SPEED_MAX_FREQ 26000000 /*26 MHz*/ +-#define STM32MP1_EMMC_HIGH_SPEED_MAX_FREQ 52000000 /*52 MHz*/ ++#define STM32MP_MMC_INIT_FREQ U(400000) /*400 KHz*/ ++#define STM32MP_SD_NORMAL_SPEED_MAX_FREQ U(25000000) /*25 MHz*/ ++#define STM32MP_SD_HIGH_SPEED_MAX_FREQ U(50000000) /*50 MHz*/ ++#define STM32MP_EMMC_NORMAL_SPEED_MAX_FREQ U(26000000) /*26 MHz*/ ++#define STM32MP_EMMC_HIGH_SPEED_MAX_FREQ U(52000000) /*52 MHz*/ ++ ++/******************************************************************************* ++ * STM32MP1 QSPI ++ ******************************************************************************/ ++#define STM32MP1_QSPI1_BASE U(0x58003000) ++ ++/******************************************************************************* ++ * STM32MP1 BSEC / OTP ++ ******************************************************************************/ ++#define STM32MP1_BSEC_BASE U(0x5C005000) ++#define STM32MP1_OTP_MAX_ID 0x5FU ++#define STM32MP1_UPPER_OTP_START 0x20U ++ ++#define OTP_MAX_SIZE (STM32MP1_OTP_MAX_ID + 1U) ++ ++/* OTP offsets */ ++#define DATA0_OTP U(0) ++#define PART_NUMBER_OTP U(1) ++#define MONOTONIC_OTP U(4) ++#define NAND_OTP U(9) ++#define UID0_OTP U(13) ++#define UID1_OTP U(14) ++#define UID2_OTP U(15) ++#define PACKAGE_OTP U(16) ++#define HW2_OTP U(18) /* HW watchdog OTP */ ++#define BOARD_OTP U(59) ++ ++/* OTP mask */ ++/* DATA0 */ ++#define DATA0_OTP_SECURED BIT(6) ++ ++/* PART NUMBER */ ++#define PART_SHIFT 0 ++#define PART_MASK GENMASK_32(7, 0) ++ ++/* PACKAGE */ ++#define PKG_SHIFT 27 ++#define PKG_MASK GENMASK_32(29, 27) ++ ++/* IWDG OTP */ ++#define IWDG_HW_POS 3 ++#define IWDG_FZ_STOP_POS 5 ++#define IWDG_FZ_STANDBY_POS 7 ++ ++/* NAND OTP */ ++/* NAND parameter storage flag */ ++#define NAND_PARAM_STORED_IN_OTP U(0x80000000) ++ ++/* NAND page size in bytes */ ++#define NAND_PAGE_SIZE_OFFSET 29 ++#define NAND_PAGE_SIZE_MASK U(0x60000000) ++#define NAND_PAGE_SIZE_2K 0 ++#define NAND_PAGE_SIZE_4K 1 ++#define NAND_PAGE_SIZE_8K 2 ++ ++/* NAND block size in pages */ ++#define NAND_BLOCK_SIZE_OFFSET 27 ++#define NAND_BLOCK_SIZE_MASK U(0x18000000) ++#define NAND_BLOCK_SIZE_64_PAGES 0 ++#define NAND_BLOCK_SIZE_128_PAGES 1 ++#define NAND_BLOCK_SIZE_256_PAGES 2 ++ ++/* NAND number of block (in unit of 256 blocs) */ ++#define NAND_BLOCK_NB_OFFSET 19 ++#define NAND_BLOCK_NB_MASK U(0x07F80000) ++#define NAND_BLOCK_NB_UNIT U(256) ++ ++/* NAND bus width in bits */ ++#define NAND_WIDTH_OFFSET 18 ++#define NAND_WIDTH_MASK 0x00040000 ++ ++/* NAND number of ECC bits per 512 bytes */ ++#define NAND_ECC_BIT_NB_OFFSET 16 ++#define NAND_ECC_BIT_NB_MASK U(0x00030000) ++#define NAND_ECC_BIT_NB_UNSET 0 ++#define NAND_ECC_BIT_NB_1_BITS 1 ++#define NAND_ECC_BIT_NB_4_BITS 2 ++#define NAND_ECC_BIT_NB_8_BITS 3 ++ ++#define MAX_MONOTONIC_VALUE 32 ++ ++/******************************************************************************* ++ * STM32MP1 FMC ++ ******************************************************************************/ ++#define STM32MP_FMC_BASE U(0x58002000) ++ ++/******************************************************************************* ++ * STM32MP1 HASH ++ ******************************************************************************/ ++#define HASH1_BASE U(0x54002000) ++#define HASH_BASE HASH1_BASE + + /******************************************************************************* + * STM32MP1 TAMP + ******************************************************************************/ ++#define PLAT_MAX_TAMP_INT U(5) ++#define PLAT_MAX_TAMP_EXT U(3) + #define TAMP_BASE U(0x5C00A000) + #define TAMP_BKP_REGISTER_BASE (TAMP_BASE + U(0x100)) + +@@ -174,6 +455,10 @@ static inline uint32_t tamp_bkpr(uint32_t idx) + return TAMP_BKP_REGISTER_BASE + (idx << 2); + } + #endif ++/******************************************************************************* ++ * STM32MP1 USB ++ ******************************************************************************/ ++#define USB_OTG_BASE U(0x49000000) + + /******************************************************************************* + * STM32MP1 DDRCTRL +@@ -186,8 +471,60 @@ static inline uint32_t tamp_bkpr(uint32_t idx) + #define DDRPHYC_BASE U(0x5A004000) + + /******************************************************************************* +- * STM32MP1 I2C4 ++ * STM32MP1 IWDG ++ ******************************************************************************/ ++#define IWDG_MAX_INSTANCE U(2) ++#define IWDG1_INST U(0) ++#define IWDG2_INST U(1) ++ ++#define IWDG1_BASE U(0x5C003000) ++#define IWDG2_BASE U(0x5A002000) ++ ++/******************************************************************************* ++ * STM32MP1 I2C + ******************************************************************************/ + #define I2C4_BASE U(0x5C002000) ++#define I2C6_BASE U(0x5C009000) ++ ++/******************************************************************************* ++ * STM32MP1 DBGMCU ++ ******************************************************************************/ ++#define DBGMCU_BASE U(0x50081000) ++ ++/******************************************************************************* ++ * STM32MP1 SPI ++ ******************************************************************************/ ++#define SPI6_BASE U(0x5C001000) ++ ++/******************************************************************************* ++ * STM32MP1 RNG ++ ******************************************************************************/ ++#define RNG1_BASE U(0x54003000) ++ ++/******************************************************************************* ++ * STM32MP1 CRYP ++ ******************************************************************************/ ++#define CRYP1_BASE U(0x54001000) ++ ++/******************************************************************************* ++ * STM32MP1 TIMERS ++ ******************************************************************************/ ++#define TIM12_BASE U(0x40006000) ++#define TIM15_BASE U(0x44006000) ++#define TIM_MAX_INSTANCE U(2) ++ ++/******************************************************************************* ++ * DEBUG ++ ******************************************************************************/ ++/*#define ICACHE_OFF*/ ++/*#define DCACHE_OFF*/ ++/*#define MMU_OFF*/ ++ ++/******************************************************************************* ++ * Device Tree defines ++ ******************************************************************************/ ++#define DT_PWR_COMPAT "st,stm32mp1-pwr" ++#define DT_RCC_CLK_COMPAT "st,stm32mp1-rcc" ++#define DT_SYSCFG_COMPAT "st,stm32mp157-syscfg" + + #endif /* STM32MP1_DEF_H */ +diff --git a/plat/st/stm32mp1/stm32mp1_dt.c b/plat/st/stm32mp1/stm32mp1_dt.c +deleted file mode 100644 +index bde968a..0000000 +--- a/plat/st/stm32mp1/stm32mp1_dt.c ++++ /dev/null +@@ -1,476 +0,0 @@ +-/* +- * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. +- * +- * SPDX-License-Identifier: BSD-3-Clause +- */ +- +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +- +-#define DT_GPIO_BANK_SHIFT 12 +-#define DT_GPIO_BANK_MASK 0x1F000U +-#define DT_GPIO_PIN_SHIFT 8 +-#define DT_GPIO_PIN_MASK 0xF00U +-#define DT_GPIO_MODE_MASK 0xFFU +- +-static int fdt_checked; +- +-static void *fdt = (void *)(uintptr_t)STM32MP1_DTB_BASE; +- +-/******************************************************************************* +- * This function gets the pin settings from DT information. +- * When analyze and parsing is done, set the GPIO registers. +- * Return 0 on success, else return a negative FDT_ERR_xxx error code. +- ******************************************************************************/ +-static int dt_set_gpio_config(int node) +-{ +- const fdt32_t *cuint, *slewrate; +- int len, pinctrl_node, pinctrl_subnode; +- uint32_t i; +- uint32_t speed = GPIO_SPEED_LOW; +- uint32_t pull = GPIO_NO_PULL; +- +- 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 { +- VERBOSE("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 ... 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; +- } +- +- fdt_for_each_subnode(pinctrl_subnode, fdt, pinctrl_node) { +- uint32_t bank_offset; +- const fdt32_t *cuint2; +- +- if (fdt_getprop(fdt, pinctrl_subnode, +- "gpio-controller", NULL) == NULL) { +- continue; +- } +- +- cuint2 = fdt_getprop(fdt, pinctrl_subnode, "reg", NULL); +- if (cuint2 == NULL) { +- continue; +- } +- +- if (bank == GPIO_BANK_Z) { +- bank_offset = 0; +- } else { +- bank_offset = bank * STM32_GPIO_BANK_OFFSET; +- } +- +- if (fdt32_to_cpu(*cuint2) == bank_offset) { +- int clk_id = fdt_get_clock_id(pinctrl_subnode); +- +- if (clk_id < 0) { +- return -FDT_ERR_NOTFOUND; +- } +- +- if (stm32mp1_clk_enable((unsigned long)clk_id) < +- 0) { +- return -FDT_ERR_BADVALUE; +- } +- +- break; +- } +- } +- +- set_gpio(bank, pin, mode, speed, pull, alternate); +- } +- +- return 0; +-} +- +-/******************************************************************************* +- * This function checks device tree file with its header. +- * Returns 0 if success, and a negative value else. +- ******************************************************************************/ +-int dt_open_and_check(void) +-{ +- int ret = fdt_check_header(fdt); +- +- if (ret == 0) { +- fdt_checked = 1; +- } +- +- return ret; +-} +- +-/******************************************************************************* +- * This function gets the address of the DT. +- * If DT is OK, fdt_addr is filled with DT address. +- * Returns 1 if success, 0 otherwise. +- ******************************************************************************/ +-int fdt_get_address(void **fdt_addr) +-{ +- if (fdt_checked == 1) { +- *fdt_addr = fdt; +- } +- +- return fdt_checked; +-} +- +-/******************************************************************************* +- * This function check the presence of a node (generic use of fdt library). +- * Returns true if present, false else. +- ******************************************************************************/ +-bool fdt_check_node(int node) +-{ +- int len; +- const char *cchar; +- +- cchar = fdt_get_name(fdt, node, &len); +- +- return (cchar != NULL) && (len >= 0); +-} +- +-/******************************************************************************* +- * This function check the status of a node (generic use of fdt library). +- * Returns true if "okay" or missing, false else. +- ******************************************************************************/ +-bool fdt_check_status(int node) +-{ +- int len; +- const char *cchar; +- +- cchar = fdt_getprop(fdt, node, "status", &len); +- if (cchar == NULL) { +- return true; +- } +- +- return strncmp(cchar, "okay", (size_t)len) == 0; +-} +- +-/******************************************************************************* +- * This function check the secure-status of a node (generic use of fdt library). +- * Returns true if "okay" or missing, false else. +- ******************************************************************************/ +-bool fdt_check_secure_status(int node) +-{ +- int len; +- const char *cchar; +- +- cchar = fdt_getprop(fdt, node, "secure-status", &len); +- if (cchar == NULL) { +- return true; +- } +- +- return strncmp(cchar, "okay", (size_t)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(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(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 pin settings from DT information. +- * When analyze and parsing is done, set the GPIO registers. +- * Returns 0 if success, and a negative value else. +- ******************************************************************************/ +-int dt_set_pinctrl_config(int node) +-{ +- const fdt32_t *cuint; +- int lenp = 0; +- uint32_t i; +- +- if (!fdt_check_status(node)) { +- return -FDT_ERR_NOTFOUND; +- } +- +- cuint = fdt_getprop(fdt, node, "pinctrl-0", &lenp); +- if (cuint == NULL) { +- return -FDT_ERR_NOTFOUND; +- } +- +- for (i = 0; i < ((uint32_t)lenp / 4U); i++) { +- int phandle_node, phandle_subnode; +- +- phandle_node = +- fdt_node_offset_by_phandle(fdt, fdt32_to_cpu(*cuint)); +- if (phandle_node < 0) { +- return -FDT_ERR_NOTFOUND; +- } +- +- fdt_for_each_subnode(phandle_subnode, fdt, phandle_node) { +- int ret = dt_set_gpio_config(phandle_subnode); +- +- if (ret < 0) { +- return ret; +- } +- } +- +- cuint++; +- } +- +- return 0; +-} +- +-/******************************************************************************* +- * This function gets the stdout pin configuration information from the DT. +- * And then calls the sub-function to treat it and set GPIO registers. +- * Returns 0 if success, and a negative value else. +- ******************************************************************************/ +-int dt_set_stdout_pinctrl(void) +-{ +- int node; +- +- node = dt_get_stdout_node_offset(); +- if (node < 0) { +- return -FDT_ERR_NOTFOUND; +- } +- +- return dt_set_pinctrl_config(node); +-} +- +-/******************************************************************************* +- * This function fills the generic information from a given node. +- ******************************************************************************/ +-void dt_fill_device_info(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_check_status(node); +- info->sec_status = fdt_check_secure_status(node); +-} +- +-/******************************************************************************* +- * This function retrieve the generic information from DT. +- * Returns node if success, and a negative value else. +- ******************************************************************************/ +-int dt_get_node(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; +- } +- +- dt_fill_device_info(info, node); +- +- return node; +-} +- +-/******************************************************************************* +- * This function gets the UART instance info of stdout from the DT. +- * Returns node if success, and a negative value else. +- ******************************************************************************/ +-int dt_get_stdout_uart_info(struct dt_node_info *info) +-{ +- int node; +- +- node = dt_get_stdout_node_offset(); +- if (node < 0) { +- return -FDT_ERR_NOTFOUND; +- } +- +- dt_fill_device_info(info, node); +- +- return node; +-} +- +-/******************************************************************************* +- * This function gets the stdout path node. +- * It reads the value indicated inside the device tree. +- * Returns node if success, and a negative value else. +- ******************************************************************************/ +-int dt_get_stdout_node_offset(void) +-{ +- int node; +- const char *cchar; +- +- 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 dt_get_ddr_size(void) +-{ +- int node; +- +- node = fdt_node_offset_by_compatible(fdt, -1, DT_DDR_COMPAT); +- if (node < 0) { +- INFO("%s: Cannot read DDR node in DT\n", __func__); +- return STM32MP1_DDR_SIZE_DFLT; +- } +- +- return fdt_read_uint32_default(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 *dt_get_board_model(void) +-{ +- int node = fdt_path_offset(fdt, "/"); +- +- if (node < 0) { +- return NULL; +- } +- +- return (const char *)fdt_getprop(fdt, node, "model", NULL); +-} +diff --git a/plat/st/stm32mp1/stm32mp1_gic.c b/plat/st/stm32mp1/stm32mp1_gic.c +index 11eb0a3..498093d 100644 +--- a/plat/st/stm32mp1/stm32mp1_gic.c ++++ b/plat/st/stm32mp1/stm32mp1_gic.c +@@ -4,13 +4,21 @@ + * SPDX-License-Identifier: BSD-3-Clause + */ + ++#include + #include ++#include + #include ++#include + #include + #include ++#include ++#include + #include + +-#include ++struct stm32_gic_instance { ++ uint32_t cells; ++ uint32_t phandle_node; ++}; + + /****************************************************************************** + * On a GICv2 system, the Group 1 secure interrupts are treated as Group 0 +@@ -21,19 +29,114 @@ static const interrupt_prop_t stm32mp1_interrupt_props[] = { + PLATFORM_G0_PROPS(GICV2_INTR_GROUP0) + }; + +-static unsigned int target_mask_array[PLATFORM_CORE_COUNT]; ++/* Fix target_mask_array as secondary core is not able to initialize it */ ++static unsigned int target_mask_array[PLATFORM_CORE_COUNT] = {1, 2}; + +-static const gicv2_driver_data_t platform_gic_data = { +- .gicd_base = STM32MP1_GICD_BASE, +- .gicc_base = STM32MP1_GICC_BASE, ++static gicv2_driver_data_t platform_gic_data = { + .interrupt_props = stm32mp1_interrupt_props, + .interrupt_props_num = ARRAY_SIZE(stm32mp1_interrupt_props), + .target_masks = target_mask_array, + .target_masks_num = ARRAY_SIZE(target_mask_array), + }; + ++static struct stm32_gic_instance stm32_gic; ++ ++static uint32_t enable_gic_interrupt(const fdt32_t *array) ++{ ++ unsigned int id, cfg; ++ ++ switch (fdt32_to_cpu(*array)) { ++ case GIC_SPI: ++ id = MIN_SPI_ID; ++ break; ++ ++ case GIC_PPI: ++ id = MIN_PPI_ID; ++ break; ++ ++ default: ++ id = MIN_SGI_ID; ++ break; ++ } ++ ++ id += fdt32_to_cpu(*(array + 1)); ++ cfg = (fdt32_to_cpu(*(array + 2)) < IRQ_TYPE_LEVEL_HIGH) ? ++ GIC_INTR_CFG_EDGE : GIC_INTR_CFG_LEVEL; ++ ++ if ((id >= MIN_SPI_ID) && (id <= MAX_SPI_ID)) { ++ VERBOSE("Enable IT %i\n", id); ++ gicv2_set_interrupt_type(id, GICV2_INTR_GROUP0); ++ gicv2_set_interrupt_priority(id, STM32MP1_IRQ_SEC_SPI_PRIO); ++ gicv2_set_spi_routing(id, STM32MP_PRIMARY_CPU); ++ gicv2_interrupt_set_cfg(id, cfg); ++ gicv2_enable_interrupt(id); ++ } ++ ++ return id; ++} ++ ++static void find_next_interrupt(const fdt32_t **array) ++{ ++ int node; ++ const fdt32_t *cuint; ++ void *fdt; ++ ++ assert(fdt32_to_cpu(**array) != stm32_gic.phandle_node); ++ ++ if (fdt_get_address(&fdt) == 0) { ++ panic(); ++ } ++ ++ node = fdt_node_offset_by_phandle(fdt, fdt32_to_cpu(**array)); ++ if (node < 0) { ++ panic(); ++ } ++ ++ cuint = fdt_getprop(fdt, node, "#interrupt-cells", NULL); ++ if (cuint == NULL) { ++ panic(); ++ } ++ ++ *array += fdt32_to_cpu(*cuint) + 1; ++} ++ + void stm32mp1_gic_init(void) + { ++ int node; ++ void *fdt; ++ const fdt32_t *cuint; ++ struct dt_node_info dt_gic; ++ ++ if (fdt_get_address(&fdt) == 0) { ++ panic(); ++ } ++ ++ node = dt_get_node(&dt_gic, -1, "arm,cortex-a7-gic"); ++ if (node < 0) { ++ panic(); ++ } ++ ++ platform_gic_data.gicd_base = dt_gic.base; ++ ++ cuint = fdt_getprop(fdt, node, "reg", NULL); ++ if (cuint == NULL) { ++ panic(); ++ } ++ ++ platform_gic_data.gicc_base = fdt32_to_cpu(*(cuint + 2)); ++ ++ cuint = fdt_getprop(fdt, node, "#interrupt-cells", NULL); ++ if (cuint == NULL) { ++ panic(); ++ } ++ ++ stm32_gic.cells = fdt32_to_cpu(*cuint); ++ ++ stm32_gic.phandle_node = fdt_get_phandle(fdt, node); ++ if (stm32_gic.phandle_node == 0U) { ++ panic(); ++ } ++ + gicv2_driver_init(&platform_gic_data); + gicv2_distif_init(); + +@@ -46,3 +149,63 @@ void stm32mp1_gic_pcpu_init(void) + gicv2_set_pe_target_mask(plat_my_core_pos()); + gicv2_cpuif_enable(); + } ++ ++int stm32_gic_enable_spi(int node, const char *name) ++{ ++ const fdt32_t *cuint; ++ void *fdt; ++ int res, len; ++ int index = -1; ++ int i = 0; ++ int id = -1; ++ bool extended; ++ const fdt32_t *t_array, *max; ++ ++ if (fdt_get_address(&fdt) == 0) { ++ panic(); ++ } ++ ++ cuint = fdt_getprop(fdt, node, "interrupt-parent", NULL); ++ if (cuint != NULL) { ++ if (stm32_gic.phandle_node != fdt32_to_cpu(*cuint)) { ++ return -FDT_ERR_NOTFOUND; ++ } ++ } ++ ++ if (name != NULL) { ++ index = fdt_stringlist_search(fdt, node, "interrupt-names", ++ name); ++ if (index < 0) { ++ return index; ++ } ++ } ++ ++ res = fdt_get_interrupt(node, &t_array, &len, &extended); ++ if (res < 0) { ++ return res; ++ } ++ ++ max = t_array + (len / sizeof(uint32_t)); ++ ++ while ((t_array < max) && ((i <= index) || (index == -1))) { ++ if (!extended) { ++ if ((index == -1) || (i == index)) { ++ id = enable_gic_interrupt(t_array); ++ } ++ t_array += stm32_gic.cells; ++ } else { ++ if (fdt32_to_cpu(*t_array) == stm32_gic.phandle_node) { ++ t_array++; ++ if ((index == -1) || (i == index)) { ++ id = enable_gic_interrupt(t_array); ++ } ++ t_array += stm32_gic.cells; ++ } else { ++ find_next_interrupt(&t_array); ++ } ++ } ++ i++; ++ } ++ ++ return id; ++} +diff --git a/plat/st/stm32mp1/stm32mp1_helper.S b/plat/st/stm32mp1/stm32mp1_helper.S +index b0ea0d8..1adaaee 100644 +--- a/plat/st/stm32mp1/stm32mp1_helper.S ++++ b/plat/st/stm32mp1/stm32mp1_helper.S +@@ -8,17 +8,20 @@ + #include + #include + #include ++#include + #include + #include + +-#define GPIO_BANK_G_ADDRESS 0x50008000 +-#define GPIO_TX_PORT 11 +-#define GPIO_TX_SHIFT (GPIO_TX_PORT << 1) +-#define GPIO_TX_ALT_SHIFT ((GPIO_TX_PORT - GPIO_ALT_LOWER_LIMIT) << 2) +-#define STM32MP1_HSI_CLK 64000000 ++#define GPIO_TX_SHIFT (DEBUG_UART_TX_GPIO_PORT << 1) ++#define GPIO_TX_ALT_SHIFT ((DEBUG_UART_TX_GPIO_PORT - GPIO_ALT_LOWER_LIMIT) << 2) + + .globl platform_mem_init + .globl plat_report_exception ++#if AARCH32_EXCEPTION_DEBUG ++ .globl plat_report_undef_inst ++ .globl plat_report_prefetch_abort ++ .globl plat_report_data_abort ++#endif + .globl plat_get_my_entrypoint + .globl plat_secondary_cold_boot_setup + .globl plat_reset_handler +@@ -28,6 +31,7 @@ + .globl plat_crash_console_flush + .globl plat_crash_console_putc + .globl plat_panic_handler ++ .globl wfi_svc_int_enable + + func platform_mem_init + /* Nothing to do, don't need to init SYSRAM */ +@@ -35,9 +39,138 @@ func platform_mem_init + endfunc platform_mem_init + + func plat_report_exception ++#if DEBUG ++ mov r8, lr ++ ++ /* Test if an abort occurred */ ++ cmp r0, #MODE32_abt ++ bne undef_inst_lbl ++ ldr r4, =abort_str ++ bl asm_print_str ++ b print_excpetion_info ++ ++undef_inst_lbl: ++ /* Test for an undefined instruction */ ++ cmp r0, #MODE32_und ++ bne other_excpetion_lbl ++ ldr r4, =undefined_str ++ bl asm_print_str ++ b print_excpetion_info ++ ++other_excpetion_lbl: ++ /* Other exceptions */ ++ mov r9, r0 ++ ldr r4, =exception_start_str ++ bl asm_print_str ++ mov r4, r9 ++ bl asm_print_hex ++ ldr r4, =exception_end_str ++ bl asm_print_str ++ ++print_excpetion_info: ++ mrs r4, lr_svc ++ sub r4, r4, #4 ++ bl asm_print_hex ++ ++ ldr r4, =end_error_str ++ bl asm_print_str ++ ++ bx r8 ++#else + bx lr ++#endif + endfunc plat_report_exception + ++#if AARCH32_EXCEPTION_DEBUG ++func plat_report_undef_inst ++#if DEBUG ++ mov r8, lr ++ ++ mov r9, r0 ++ ++ ldr r4, =undefined_str ++ bl asm_print_str ++ ++ mov r4, r9 ++ sub r4, r4, #4 ++ bl asm_print_hex ++ ++ ldr r4, =end_error_str ++ bl asm_print_str ++ ++ bx r8 ++#else ++ bx lr ++#endif ++endfunc plat_report_undef_inst ++ ++func plat_report_prefetch_abort ++#if DEBUG ++ mov r8, lr ++ mov r9, r0 ++ ++ ldr r4, =prefetch_abort_str ++ bl asm_print_str ++ ++ mov r4, r9 ++ sub r4, r4, #4 ++ bl asm_print_hex ++ ++ ldr r4, =ifsr_str ++ bl asm_print_str ++ ++ ldcopr r4, IFSR ++ bl asm_print_hex ++ ++ ldr r4, =ifar_str ++ bl asm_print_str ++ ++ ldcopr r4, IFAR ++ bl asm_print_hex ++ ++ ldr r4, =end_error_str ++ bl asm_print_str ++ ++ bx r8 ++#else ++ bx lr ++#endif ++endfunc plat_report_prefetch_abort ++ ++func plat_report_data_abort ++#if DEBUG ++ mov r8, lr ++ mov r9, r0 ++ ++ ldr r4, =data_abort_str ++ bl asm_print_str ++ ++ mov r4, r9 ++ sub r4, r4, #8 ++ bl asm_print_hex ++ ++ ldr r4, =dfsr_str ++ bl asm_print_str ++ ++ ldcopr r4, DFSR ++ bl asm_print_hex ++ ++ ldr r4, =dfar_str ++ bl asm_print_str ++ ++ ldcopr r4, DFAR ++ bl asm_print_hex ++ ++ ldr r4, =end_error_str ++ bl asm_print_str ++ ++ bx r8 ++#else ++ bx lr ++#endif ++endfunc plat_report_data_abort ++#endif ++ + func plat_reset_handler + bx lr + endfunc plat_reset_handler +@@ -76,7 +209,7 @@ func plat_is_my_cpu_primary + ldcopr r0, MPIDR + ldr r1, =(MPIDR_CLUSTER_MASK | MPIDR_CPU_MASK) + and r0, r1 +- cmp r0, #STM32MP1_PRIMARY_CPU ++ cmp r0, #STM32MP_PRIMARY_CPU + moveq r0, #1 + movne r0, #0 + bx lr +@@ -111,13 +244,13 @@ endfunc plat_my_core_pos + * --------------------------------------------- + */ + func plat_crash_console_init +- /* Enable GPIOs for UART4 TX */ +- ldr r1, =(RCC_BASE + RCC_MP_AHB4ENSETR) ++ /* Enable GPIOs for UART TX */ ++ ldr r1, =(RCC_BASE + DEBUG_UART_TX_GPIO_BANK_CLK_REG) + ldr r2, [r1] +- /* Configure GPIO G11 */ +- orr r2, r2, #RCC_MP_AHB4ENSETR_GPIOGEN ++ /* Configure GPIO */ ++ orr r2, r2, #DEBUG_UART_TX_GPIO_BANK_CLK_EN + str r2, [r1] +- ldr r1, =GPIO_BANK_G_ADDRESS ++ ldr r1, =DEBUG_UART_TX_GPIO_BANK_ADDRESS + /* Set GPIO mode alternate */ + ldr r2, [r1, #GPIO_MODE_OFFSET] + bic r2, r2, #(GPIO_MODE_MASK << GPIO_TX_SHIFT) +@@ -131,25 +264,24 @@ func plat_crash_console_init + ldr r2, [r1, #GPIO_PUPD_OFFSET] + bic r2, r2, #(GPIO_PULL_MASK << GPIO_TX_SHIFT) + str r2, [r1, #GPIO_PUPD_OFFSET] +- /* Set alternate AF6 */ ++ /* Set alternate */ + ldr r2, [r1, #GPIO_AFRH_OFFSET] + bic r2, r2, #(GPIO_ALTERNATE_MASK << GPIO_TX_ALT_SHIFT) +- orr r2, r2, #(GPIO_ALTERNATE_6 << GPIO_TX_ALT_SHIFT) ++ orr r2, r2, #(DEBUG_UART_TX_GPIO_ALTERNATE << GPIO_TX_ALT_SHIFT) + str r2, [r1, #GPIO_AFRH_OFFSET] +- +- /* Enable UART clock, with HSI source */ +- ldr r1, =(RCC_BASE + RCC_UART24CKSELR) +- mov r2, #RCC_UART24CKSELR_HSI ++ /* Enable UART clock, with its source */ ++ ldr r1, =(RCC_BASE + DEBUG_UART_TX_CLKSRC_REG) ++ mov r2, #DEBUG_UART_TX_CLKSRC + str r2, [r1] +- ldr r1, =(RCC_BASE + RCC_MP_APB1ENSETR) ++ ldr r1, =(RCC_BASE + DEBUG_UART_TX_EN_REG) + ldr r2, [r1] +- orr r2, r2, #RCC_MP_APB1ENSETR_UART4EN ++ orr r2, r2, #DEBUG_UART_TX_EN + str r2, [r1] + +- ldr r0, =STM32MP1_DEBUG_USART_BASE +- ldr r1, =STM32MP1_HSI_CLK +- ldr r2, =STM32MP1_UART_BAUDRATE +- b console_core_init ++ ldr r0, =STM32MP_DEBUG_USART_BASE ++ ldr r1, =STM32MP_DEBUG_USART_CLK_FRQ ++ ldr r2, =STM32MP_UART_BAUDRATE ++ b console_stm32_core_init + endfunc plat_crash_console_init + + /* --------------------------------------------- +@@ -159,8 +291,8 @@ endfunc plat_crash_console_init + * --------------------------------------------- + */ + func plat_crash_console_flush +- ldr r1, =STM32MP1_DEBUG_USART_BASE +- b console_core_flush ++ ldr r1, =STM32MP_DEBUG_USART_BASE ++ b console_stm32_core_flush + endfunc plat_crash_console_flush + + /* --------------------------------------------- +@@ -175,6 +307,68 @@ endfunc plat_crash_console_flush + * --------------------------------------------- + */ + func plat_crash_console_putc +- ldr r1, =STM32MP1_DEBUG_USART_BASE +- b console_core_putc ++ ldr r1, =STM32MP_DEBUG_USART_BASE ++ b console_stm32_core_putc + endfunc plat_crash_console_putc ++ ++ /* ----------------------------------------------------- ++ * void plat_panic_handler(void) __dead2; ++ * Report exception + endless loop. ++ * ----------------------------------------------------- ++ */ ++func plat_panic_handler ++ mrs r0, cpsr ++ and r0, #MODE32_MASK ++ bl plat_report_exception ++ b . ++endfunc plat_panic_handler ++ ++#if DEBUG ++.section .rodata.rev_err_str, "aS" ++abort_str: ++ .asciz "\nAbort at: 0x" ++#if AARCH32_EXCEPTION_DEBUG ++prefetch_abort_str: ++ .asciz "\nPrefetch Abort at: 0x" ++data_abort_str: ++ .asciz "\nData Abort at: 0x" ++#endif ++undefined_str: ++ .asciz "\nUndefined instruction at: 0x" ++exception_start_str: ++ .asciz "\nException mode=0x" ++exception_end_str: ++ .asciz " at: 0x" ++#if AARCH32_EXCEPTION_DEBUG ++dfsr_str: ++ .asciz " DFSR = 0x" ++dfar_str: ++ .asciz " DFAR = 0x" ++ifsr_str: ++ .asciz " IFSR = 0x" ++ifar_str: ++ .asciz " IFAR = 0x" ++#endif ++end_error_str: ++ .asciz "\n\r" ++#endif ++ ++func wfi_svc_int_enable ++ push {r4,r8,lr} ++ ldcopr r4, SCR ++ mov r8, sp ++ mov sp, r0 ++ add r0, r0, #STM32MP_INT_STACK_SIZE ++ str r0, [sp, #SMC_CTX_SP_MON] ++ str r4, [sp, #SMC_CTX_SCR] ++ cps #MODE32_svc ++ cpsie af ++ isb ++ dsb ++ wfi ++ cpsid af ++ cps #MODE32_mon ++ mov sp, r8 ++ pop {r4,r8,lr} ++ bx lr ++endfunc wfi_svc_int_enable +diff --git a/plat/st/stm32mp1/stm32mp1_helper_dbg.S b/plat/st/stm32mp1/stm32mp1_helper_dbg.S +new file mode 100644 +index 0000000..32a86fb +--- /dev/null ++++ b/plat/st/stm32mp1/stm32mp1_helper_dbg.S +@@ -0,0 +1,227 @@ ++/* ++ * Copyright (c) 2019, STMicroelectronics - All Rights Reserved ++ * ++ * SPDX-License-Identifier: BSD-3-Clause ++ */ ++ ++/***************************************************************************** ++ * This file is only needed for current Soc revision which has a limitation on ++ * debug reset halt. This can be removed when using the Soc revision that ++ * fixes the limitation. Anyway, this source code identifies the Soc revision ++ * and is only executed if it corresponds, so it can be kept on other ++ * revisions without any consequence. ++ ****************************************************************************/ ++ ++/***************************************************************************** ++ * This file has been intentionally transformed in order to use only ASM ++ * standard macros and instructions. It could then be easily back-ported to ++ * other pieces of software. ++ ****************************************************************************/ ++ ++#define BIT_(nr) ((1) << (nr)) ++ ++#define BSEC_BASE 0x5C005000 ++#define BSEC_OTP_DATA_OFF (BSEC_BASE + 0x200) ++#define BSEC_OTP_DATA0 BSEC_OTP_DATA_OFF ++#define BSEC_OTP_DATA0_CLOSED BIT_(6) ++ ++#define DBGMCU_BASE 0x50081000 ++#define DBGMCU_IDC 0x00 ++#define DBGMCU_IDC_REV_ID_DEV_ID_MSK 0xFFFF0FFF ++#define DBGMCU_IDC_REV_ID_DEV_ID_VALUE 0x20000500 ++ ++#define RCC_BASE 0x50000000 ++#define RCC_MP_APB5ENSETR 0x208 ++#define RCC_MP_APB5ENSETR_RTCAPBEN BIT_(8) ++#define RCC_DBGCFGR 0x80C ++#define RCC_DBGCFGR_DBGCKEN BIT_(8) ++ ++#define PWR_BASE 0x50001000 ++#define PWR_CR1 0x00 ++#define PWR_CR1_DBP BIT_(8) ++ ++#define TAMP_BASE 0x5C00A000 ++#define TAMP_BKP_REGISTER_BASE TAMP_BASE + 0x100 ++#define TAMP_BKP_REGISTER_20 TAMP_BKP_REGISTER_BASE + (20 << 2) ++ ++#define CA7_DBG0_BASE 0x500D0000 ++#define DBG_DSCR 0x88 ++#define DBG_DSCR_HDBGEN BIT_(14) ++ ++#define FSBL_ENTRYPOINT bl2_entrypoint ++ ++ .globl plat_dbg_attach_loop ++ ++ ++plat_dbg_attach_loop: ++ /* ++ * This function is the first call of FSBL_ENTRYPOINT. ++ * Boot rom parameters are stored in r0..r3, so we mustn't use them ++ * here. And because they are saved in r9..r12 just after the ++ * execution of this function, we should only use these registers. ++ * By this way, debug will be done in conditions closed to the initial ++ * context. ++ */ ++ ++ /* ++ * Check Sec Close bit in OTP (word 0 bit 6). If enabled, do not allow ++ * debug session and exit function. ++ */ ++ ldr r12, =BSEC_OTP_DATA0 ++ ldr r12, [r12] ++ ands r11, r12, #BSEC_OTP_DATA0_CLOSED ++ bne func_exit ++ ++ /* ++ * Enable DBGMCU clock (only if not done). ++ * Initial register content will be saved in r10. ++ * So r10 mustn't be used before restore part. ++ */ ++ ldr r12, =(RCC_BASE + RCC_DBGCFGR) ++ ldr r10, [r12] ++ tst r10, #RCC_DBGCFGR_DBGCKEN ++ bne dbgmcu_clk_enabled ++ orr r11, r10, #RCC_DBGCFGR_DBGCKEN ++ str r11, [r12] ++ ++ /* Get SoC revision ID and device ID in r11 */ ++dbgmcu_clk_enabled: ++ ldr r12, =(DBGMCU_BASE + DBGMCU_IDC) ++ ldr r12, [r12] ++ and r11, r12, #DBGMCU_IDC_REV_ID_DEV_ID_MSK ++ ++ /* Restore initial RCC_DBGCFGR content saved in r10 */ ++ ldr r12, =(RCC_BASE + RCC_DBGCFGR) ++ str r10, [r12] ++ ++ /* ++ * Check SoC revision ID and device ID in r11, ++ * exit if different from REV_ID_DEV_ID_VALUE ++ */ ++ ldr r12, =(DBGMCU_IDC_REV_ID_DEV_ID_VALUE) ++ teq r11, r12 ++ bne func_exit ++ ++ /* ++ * Enable RTC clock before reading tamper (only if not done). ++ * Initial register content will be saved in r10. ++ * So r10 mustn't be used before restore part. ++ */ ++ ldr r12, =(RCC_BASE + RCC_MP_APB5ENSETR) ++ ldr r10, [r12] ++ tst r10, #RCC_MP_APB5ENSETR_RTCAPBEN ++ bne rtc_clk_enabled ++ orr r11, r10, #RCC_MP_APB5ENSETR_RTCAPBEN ++ str r11, [r12] ++ ++rtc_clk_enabled: ++ /* ++ * Disable the backup domain write protection (only if not done). ++ * Initial register content will be saved in r9. ++ * So r9 mustn't be used before restore part. ++ */ ++ ldr r12, =(PWR_BASE + PWR_CR1) ++ ldr r9, [r12] ++ tst r9, #PWR_CR1_DBP ++ bne poll_dbp ++ orr r11, r9, #PWR_CR1_DBP ++ str r11, [r12] ++poll_dbp: ++ /* poll loop to ensure write is effective */ ++ ldr r11, [r12] ++ tst r11, #PWR_CR1_DBP ++ beq poll_dbp ++ ++ /* ++ * Clear bit 16 of TAMPER backup register 20 (only if set). ++ * Firstly read the register value. ++ * - If bit = 0, r11 = 0 after 'ands' operation. Next step is to ++ * restore RCC_MP_APB5ENSETR and PWR_CR1 contents and exit. ++ * - If bit = 1, r11 != 0 after 'ands' operation, but could be ++ * equal to 0 after 'bic' operation. Here, after clearing the bit, ++ * r11 has to be set to a non-zero value. Next step is to restore ++ * register contents and continue. ++ * ++ * So r11 mustn't be used in restore part, to keep this information ++ * for the next step, i.e. decide to continue execution (r11 = 1) or ++ * exit function (r11 = 0). ++ */ ++ ldr r12, =(TAMP_BKP_REGISTER_20) ++ ldr r11, [r12] ++ ands r11, r11, #(BIT_(16)) ++ beq restore_reg ++ ldr r11, [r12] ++ bic r11, #(BIT_(16)) ++ str r11, [r12] ++ ldr r11, =(1) ++ ++restore_reg: ++ /* Restore initial RCC_MP_APB5ENSETR content saved in r10 */ ++ ldr r12, =(RCC_BASE + RCC_MP_APB5ENSETR) ++ str r10, [r12] ++ ++ /* Restore initial PWR_CR1 content saved in r9 */ ++ ldr r12, =(PWR_BASE + PWR_CR1) ++ str r9, [r12] ++poll_cr1: ++ /* poll loop to ensure write is effective */ ++ ldr r12, =(PWR_BASE + PWR_CR1) ++ ldr r12, [r12] ++ teq r12, r9 ++ bne poll_cr1 ++ ++ /* ++ * Exit if bit 16 of TAMPER backup register 20 has been cleared. ++ * Information is saved in r11 register. ++ */ ++ teq r11, #0 ++ beq func_exit ++ ++ /* Get time counter frequency */ ++ mrc 15, 0, r12, cr14, cr0, 0 ++ /* Get current time counter value, save it in r11 as start value */ ++ mrrc 15, 0, r11, r10, cr14 ++ /* ++ * Compute (current time + 1 second) counter value, save it in r12 as ++ * end value. ++ */ ++ add r12, r12, r11 ++ ++loop: ++ /* ++ * Read CA7_DBG0 DBG_DSCR HDBGEN bit value. ++ * If set, put a software breakpoint and branch to FSBL_ENTRYPOINT. ++ * If cleared, continue and check loop time expiry ++ */ ++ ldr r10, =(CA7_DBG0_BASE + DBG_DSCR) ++ ldr r10, [r10] ++ tst r10, #DBG_DSCR_HDBGEN ++ beq loop_continue ++ /* Set a software breakpoint (ID 5) */ ++ bkpt 5 ++ /* Jump to entrypoint */ ++ b FSBL_ENTRYPOINT ++loop_continue: ++ /* ++ * Check 1 second expiry by using r11 and r12 saved values. ++ * Get current time counter value, save it in r10 as current value. ++ */ ++ mrrc 15, 0, r10, r9, cr14 ++ /* Check if MSB 64-bit increment done between start and end values */ ++ cmp r12, r11 ++ bmi msb_incr ++ /* No increment, simply check if current < end, exit if yes */ ++ cmp r12, r10 ++ bmi func_exit ++ b loop ++msb_incr: ++ /* ++ * Increment happened between start and end, here we need to check if ++ * (current > end) && (current < start). Exit if yes. ++ */ ++ cmp r12, r10 ++ bpl loop ++ cmp r11, r10 ++ bmi loop ++func_exit: ++ bx lr +diff --git a/plat/st/stm32mp1/stm32mp1_low_power.c b/plat/st/stm32mp1/stm32mp1_low_power.c +new file mode 100644 +index 0000000..de9035c +--- /dev/null ++++ b/plat/st/stm32mp1/stm32mp1_low_power.c +@@ -0,0 +1,311 @@ ++/* ++ * Copyright (c) 2017-2018, STMicroelectronics - All Rights Reserved ++ * ++ * SPDX-License-Identifier: BSD-3-Clause ++ */ ++ ++#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 ++ ++static unsigned int gicc_pmr; ++static struct stm32_rtc_calendar sleep_time, current_calendar; ++static unsigned long long stdby_time_in_ms; ++static bool enter_cstop_done; ++static uint8_t int_stack[STM32MP_INT_STACK_SIZE]; ++ ++extern void wfi_svc_int_enable(uintptr_t stack_addr); ++ ++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 = PWR_MPUCR_CSSF, ++ .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", ++ }, ++}; ++ ++#define GICC_PMR_PRIORITY_8 U(0x8) ++ ++void stm32_apply_pmic_suspend_config(uint32_t mode) ++{ ++ const char *node_name = config_pwr[mode].regul_suspend_node_name; ++ ++ assert(mode < ARRAY_SIZE(config_pwr)); ++ ++ if (node_name != NULL) { ++ if (!initialize_pmic_i2c()) { ++ panic(); ++ } ++ ++ if (dt_pmic_set_lp_config(node_name) != 0) { ++ panic(); ++ } ++ ++ if (dt_pmic_configure_boot_on_regulators() != 0) { ++ panic(); ++ } ++ } ++} ++ ++/* ++ * stm32_enter_cstop - Prepare CSTOP mode ++ * ++ * @mode - Target low power mode ++ * @nsec_addr - Non secure resume entry point ++ * Return 0 if succeed to suspend, non 0 else. ++ */ ++static void enter_cstop(uint32_t mode, uint32_t nsec_addr) ++{ ++ uint32_t zq0cr0_zdata; ++ uint32_t bkpr_core1_addr = ++ tamp_bkpr(BOOT_API_CORE1_BRANCH_ADDRESS_TAMP_BCK_REG_IDX); ++ uint32_t bkpr_core1_magic = ++ tamp_bkpr(BOOT_API_CORE1_MAGIC_NUMBER_TAMP_BCK_REG_IDX); ++ uint32_t pwr_cr1 = config_pwr[mode].pwr_cr1; ++ uintptr_t pwr_base = stm32mp_pwr_base(); ++ uintptr_t rcc_base = stm32mp_rcc_base(); ++ ++ dcsw_op_all(DC_OP_CISW); ++ ++ stm32_clean_context(); ++ ++ if (mode == STM32_PM_CSTOP_ALLOW_STANDBY_DDR_SR) { ++ /* ++ * The first 64 bytes of DDR need to be saved for DDR DQS ++ * training ++ */ ++ stm32_save_ddr_training_area(); ++ } ++ ++ if (dt_pmic_status() > 0) { ++ stm32_apply_pmic_suspend_config(mode); ++ ++ if (mode == STM32_PM_CSTOP_ALLOW_LP_STOP) { ++ pwr_cr1 |= PWR_CR1_LPCFG; ++ } ++ } ++ ++ /* 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, PWR_MPUCR_MASK, ++ config_pwr[mode].pwr_mpucr); ++ mmio_clrsetbits_32(pwr_base + PWR_CR1, 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); ++ ++ gicc_pmr = plat_ic_set_priority_mask(GICC_PMR_PRIORITY_8); ++ ++ /* ++ * Set DDR in Self-refresh, even if no return address is given. ++ * This is also the procedure awaited when switching off power supply. ++ */ ++ if (ddr_standby_sr_entry(&zq0cr0_zdata) != 0) { ++ return; ++ } ++ ++ stm32mp_clk_enable(RTCAPB); ++ ++ mmio_write_32(bkpr_core1_addr, 0); ++ mmio_write_32(bkpr_core1_magic, 0); ++ ++ if (mode == STM32_PM_CSTOP_ALLOW_STANDBY_DDR_SR) { ++ ++ /* ++ * Save non-secure world entrypoint after standby in Backup ++ * register ++ */ ++ mmio_write_32(bkpr_core1_addr, nsec_addr); ++ mmio_write_32(bkpr_core1_magic, ++ BOOT_API_A7_CORE0_MAGIC_NUMBER); ++ ++ if (stm32_save_context(zq0cr0_zdata) != 0) { ++ panic(); ++ } ++ } ++ ++ stm32mp_clk_disable(RTCAPB); ++ ++ stm32_rtc_get_calendar(&sleep_time); ++ ++ enter_cstop_done = true; ++} ++ ++/* ++ * stm32_exit_cstop - Exit from CSTOP mode ++ */ ++void stm32_exit_cstop(void) ++{ ++ uintptr_t rcc_base = stm32mp_rcc_base(); ++ ++ if (!enter_cstop_done) { ++ return; ++ } ++ ++ enter_cstop_done = false; ++ ++ if (ddr_sw_self_refresh_exit() != 0) { ++ panic(); ++ } ++ ++ plat_ic_set_priority_mask(gicc_pmr); ++ ++ /* Disable RCC Wake-up */ ++ mmio_clrbits_32(rcc_base + RCC_MP_CIER, RCC_MP_CIFR_WKUPF); ++ ++ /* Disable STOP request */ ++ mmio_setbits_32(rcc_base + RCC_MP_SREQCLRR, ++ RCC_MP_SREQSETR_STPREQ_P0 | RCC_MP_SREQSETR_STPREQ_P1); ++ ++ dsb(); ++ isb(); ++ ++ /* Update STGEN counter with low power mode duration */ ++ stm32_rtc_get_calendar(¤t_calendar); ++ ++ stdby_time_in_ms = stm32_rtc_diff_calendar(¤t_calendar, ++ &sleep_time); ++ ++ stm32mp1_stgen_increment(stdby_time_in_ms); ++} ++ ++static void enter_shutdown(void) ++{ ++ if (dt_pmic_status() > 0) { ++ if (!initialize_pmic_i2c()) { ++ panic(); ++ } ++ ++ stpmic1_switch_off(); ++ ++ udelay(100); ++ ++ /* Shouldn't be reached */ ++ panic(); ++ } ++} ++ ++static void enter_csleep(void) ++{ ++ uintptr_t pwr_base = stm32mp_pwr_base(); ++ ++ mmio_clrsetbits_32(pwr_base + PWR_MPUCR, PWR_MPUCR_MASK, ++ config_pwr[STM32_PM_CSLEEP_RUN].pwr_mpucr); ++ mmio_clrsetbits_32(pwr_base + PWR_CR1, PWR_CR1_MASK, ++ config_pwr[STM32_PM_CSLEEP_RUN].pwr_cr1); ++ ++ stm32_pwr_down_wfi(); ++} ++ ++void stm32_enter_low_power(uint32_t mode, uint32_t nsec_addr) ++{ ++ switch (mode) { ++ case STM32_PM_SHUTDOWN: ++ enter_shutdown(); ++ break; ++ ++ case STM32_PM_CSLEEP_RUN: ++ enter_csleep(); ++ break; ++ ++ default: ++ enter_cstop(mode, nsec_addr); ++ break; ++ } ++} ++ ++void stm32_pwr_down_wfi(void) ++{ ++ uint32_t interrupt = GIC_SPURIOUS_INTERRUPT; ++ ++ stm32mp1_rcc_set_wakeup(false); ++ ++ while (interrupt == GIC_SPURIOUS_INTERRUPT && ++ !stm32mp1_rcc_get_wakeup()) { ++ wfi_svc_int_enable((uintptr_t)&int_stack[0]); ++ ++ interrupt = gicv2_acknowledge_interrupt(); ++ ++ if (interrupt != GIC_SPURIOUS_INTERRUPT) { ++ gicv2_end_of_interrupt(interrupt); ++ } ++ ++ stm32_iwdg_refresh(IWDG2_INST); ++ } ++} +diff --git a/plat/st/stm32mp1/stm32mp1_pm.c b/plat/st/stm32mp1/stm32mp1_pm.c +index e24af0e..20a2f5c 100644 +--- a/plat/st/stm32mp1/stm32mp1_pm.c ++++ b/plat/st/stm32mp1/stm32mp1_pm.c +@@ -7,7 +7,9 @@ + #include + #include + #include ++#include + #include ++#include + #include + #include + #include +@@ -16,14 +18,16 @@ + #include + #include + #include +-#include ++#include ++#include ++#include + #include + #include ++#include + +-static uint32_t stm32_sec_entrypoint; ++static uintptr_t stm32_sec_entrypoint; + static uint32_t cntfrq_core0; +- +-#define SEND_SECURE_IT_TO_CORE_1 0x20000U ++static uintptr_t saved_entrypoint; + + /******************************************************************************* + * STM32MP1 handler called when a CPU is about to enter standby. +@@ -39,6 +43,7 @@ static void stm32_cpu_standby(plat_local_state_t cpu_state) + * Enter standby state + * dsb is good practice before using wfi to enter low power states + */ ++ isb(); + dsb(); + while (interrupt == GIC_SPURIOUS_INTERRUPT) { + wfi(); +@@ -56,33 +61,43 @@ static void stm32_cpu_standby(plat_local_state_t cpu_state) + /******************************************************************************* + * STM32MP1 handler called when a power domain is about to be turned on. The + * mpidr determines the CPU to be turned on. +- * call by core 0 to activate core 1 ++ * call by core 0 to activate core 1 + ******************************************************************************/ + static int stm32_pwr_domain_on(u_register_t mpidr) + { + unsigned long current_cpu_mpidr = read_mpidr_el1(); +- uint32_t tamp_clk_off = 0; + uint32_t bkpr_core1_addr = + tamp_bkpr(BOOT_API_CORE1_BRANCH_ADDRESS_TAMP_BCK_REG_IDX); + uint32_t bkpr_core1_magic = + tamp_bkpr(BOOT_API_CORE1_MAGIC_NUMBER_TAMP_BCK_REG_IDX); ++ int result; ++ ++ result = stm32mp_is_single_core(); ++ if (result < 0) { ++ return PSCI_E_INTERN_FAIL; ++ } ++ ++ if (result == 1) { ++ return PSCI_E_INTERN_FAIL; ++ } + + if (mpidr == current_cpu_mpidr) { + return PSCI_E_INVALID_PARAMS; + } + +- if ((stm32_sec_entrypoint < STM32MP1_SRAM_BASE) || +- (stm32_sec_entrypoint > (STM32MP1_SRAM_BASE + +- (STM32MP1_SRAM_SIZE - 1)))) { ++ /* Need to send additional IT 0 after individual core 1 reset */ ++ gicv2_raise_sgi(ARM_IRQ_NON_SEC_SGI_0, STM32MP_SECONDARY_CPU); ++ ++ /* Wait for this IT to be acknowledged by ROM code. */ ++ udelay(10); ++ ++ if ((stm32_sec_entrypoint < STM32MP_SYSRAM_BASE) || ++ (stm32_sec_entrypoint > (STM32MP_SYSRAM_BASE + ++ (STM32MP_SYSRAM_SIZE - 1)))) { + return PSCI_E_INVALID_ADDRESS; + } + +- if (!stm32mp1_clk_is_enabled(RTCAPB)) { +- tamp_clk_off = 1; +- if (stm32mp1_clk_enable(RTCAPB) != 0) { +- panic(); +- } +- } ++ stm32mp_clk_enable(RTCAPB); + + cntfrq_core0 = read_cntfrq_el0(); + +@@ -92,15 +107,10 @@ static int stm32_pwr_domain_on(u_register_t mpidr) + /* Write magic number in backup register */ + mmio_write_32(bkpr_core1_magic, BOOT_API_A7_CORE1_MAGIC_NUMBER); + +- if (tamp_clk_off != 0U) { +- if (stm32mp1_clk_disable(RTCAPB) != 0) { +- panic(); +- } +- } ++ stm32mp_clk_disable(RTCAPB); + + /* Generate an IT to core 1 */ +- mmio_write_32(STM32MP1_GICD_BASE + GICD_SGIR, +- SEND_SECURE_IT_TO_CORE_1 | ARM_IRQ_SEC_SGI_0); ++ gicv2_raise_sgi(ARM_IRQ_SEC_SGI_0, STM32MP_SECONDARY_CPU); + + return PSCI_E_SUCCESS; + } +@@ -120,7 +130,9 @@ static void stm32_pwr_domain_off(const psci_power_state_t *target_state) + ******************************************************************************/ + static void stm32_pwr_domain_suspend(const psci_power_state_t *target_state) + { +- /* Nothing to do, power domain is not disabled */ ++ uint32_t soc_mode = stm32mp1_get_lp_soc_mode(PSCI_MODE_SYSTEM_SUSPEND); ++ ++ stm32_enter_low_power(soc_mode, saved_entrypoint); + } + + /******************************************************************************* +@@ -147,22 +159,63 @@ static void stm32_pwr_domain_suspend_finish(const psci_power_state_t + /* Nothing to do, power domain is not disabled */ + } + ++/******************************************************************************* ++ * STM32MP1 handler called when a core tries to power itself down. If this ++ * call is made by core 0, it is a return from stop mode. In this case, we ++ * should restore previous context and jump to secure entrypoint. ++ ******************************************************************************/ + static void __dead2 stm32_pwr_domain_pwr_down_wfi(const psci_power_state_t + *target_state) + { +- ERROR("stm32mpu1 Power Down WFI: operation not handled.\n"); ++ if (MPIDR_AFFLVL0_VAL(read_mpidr_el1()) == STM32MP_PRIMARY_CPU) { ++ void (*warm_entrypoint)(void) = ++ (void (*)(void))stm32_sec_entrypoint; ++ ++ stm32_pwr_down_wfi(); ++ ++ stm32_exit_cstop(); ++ ++ disable_mmu_icache_secure(); ++ ++ warm_entrypoint(); ++ } ++ ++ mmio_write_32(stm32mp_rcc_base() + RCC_MP_GRSTCSETR, ++ RCC_MP_GRSTCSETR_MPUP1RST); ++ ++ /* wfi is required for an auto-reset */ ++ isb(); ++ dsb(); ++ wfi(); ++ ++ /* This shouldn't be reached */ + panic(); + } + + static void __dead2 stm32_system_off(void) + { +- ERROR("stm32mpu1 System Off: operation not handled.\n"); ++ uint32_t soc_mode = stm32mp1_get_lp_soc_mode(PSCI_MODE_SYSTEM_OFF); ++ ++ if (stm32mp_is_single_core() == 0) { ++ /* Prepare Core 1 reset */ ++ mmio_setbits_32(stm32mp_rcc_base() + RCC_MP_GRSTCSETR, ++ RCC_MP_GRSTCSETR_MPUP1RST); ++ /* Send IT to core 1 to put itself in WFI */ ++ gicv2_raise_sgi(ARM_IRQ_SEC_SGI_1, STM32MP_SECONDARY_CPU); ++ } ++ ++ stm32_enter_low_power(soc_mode, 0); ++ ++ stm32_pwr_down_wfi(); ++ ++ /* This shouldn't be reached */ + panic(); + } + + static void __dead2 stm32_system_reset(void) + { +- mmio_setbits_32(RCC_BASE + RCC_MP_GRSTCSETR, RCC_MP_GRSTCSETR_MPSYSRST); ++ mmio_setbits_32(stm32mp_rcc_base() + RCC_MP_GRSTCSETR, ++ RCC_MP_GRSTCSETR_MPSYSRST); + + /* Loop in case system reset is not immediately caught */ + for ( ; ; ) { +@@ -196,10 +249,12 @@ static int stm32_validate_power_state(unsigned int power_state, + static int stm32_validate_ns_entrypoint(uintptr_t entrypoint) + { + /* The non-secure entry point must be in DDR */ +- if (entrypoint < STM32MP1_DDR_BASE) { ++ if (entrypoint < STM32MP_DDR_BASE) { + return PSCI_E_INVALID_ADDRESS; + } + ++ saved_entrypoint = entrypoint; ++ + return PSCI_E_SUCCESS; + } + +@@ -223,6 +278,12 @@ static int stm32_node_hw_state(u_register_t target_cpu, + return (int)HW_ON; + } + ++static void stm32_get_sys_suspend_power_state(psci_power_state_t *req_state) ++{ ++ req_state->pwr_domain_state[0] = ARM_LOCAL_STATE_OFF; ++ req_state->pwr_domain_state[1] = ARM_LOCAL_STATE_OFF; ++} ++ + /******************************************************************************* + * Export the platform handlers. The ARM Standard platform layer will take care + * of registering the handlers with PSCI. +@@ -239,7 +300,8 @@ static const plat_psci_ops_t stm32_psci_ops = { + .system_reset = stm32_system_reset, + .validate_power_state = stm32_validate_power_state, + .validate_ns_entrypoint = stm32_validate_ns_entrypoint, +- .get_node_hw_state = stm32_node_hw_state ++ .get_node_hw_state = stm32_node_hw_state, ++ .get_sys_suspend_power_state = stm32_get_sys_suspend_power_state, + }; + + /******************************************************************************* +diff --git a/plat/st/stm32mp1/stm32mp1_power_config.c b/plat/st/stm32mp1/stm32mp1_power_config.c +new file mode 100644 +index 0000000..ec7ecb1 +--- /dev/null ++++ b/plat/st/stm32mp1/stm32mp1_power_config.c +@@ -0,0 +1,193 @@ ++/* ++ * Copyright (c) 2017-2018, STMicroelectronics - All Rights Reserved ++ * ++ * SPDX-License-Identifier: BSD-3-Clause ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define DT_PWR_COMPAT "st,stm32mp1-pwr" ++#define SYSTEM_SUSPEND_SUPPORTED_MODES "system_suspend_supported_soc_modes" ++#define SYSTEM_OFF_MODE "system_off_soc_mode" ++ ++static uint32_t deepest_system_suspend_mode; ++static uint32_t system_off_mode; ++static uint8_t stm32mp1_supported_soc_modes[STM32_PM_MAX_SOC_MODE]; ++ ++static int dt_get_pwr_node(void *fdt) ++{ ++ return fdt_node_offset_by_compatible(fdt, -1, DT_PWR_COMPAT); ++} ++ ++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(pwr_node, SYSTEM_SUSPEND_SUPPORTED_MODES, ++ &supported[0], count) < 0) { ++ ERROR("PWR DT\n"); ++ panic(); ++ } ++ ++ for (i = 0; i < count; i++) { ++ if (supported[i] >= STM32_PM_MAX_SOC_MODE) { ++ ERROR("Invalid mode\n"); ++ panic(); ++ } ++ stm32mp1_supported_soc_modes[supported[i]] = 1U; ++ } ++ ++ /* Initialize to deepest possible mode */ ++ for (i = STM32_PM_MAX_SOC_MODE - 1U; i != STM32_PM_CSLEEP_RUN; i--) { ++ if (stm32mp1_supported_soc_modes[i] == 1U) { ++ deepest_system_suspend_mode = i; ++ break; ++ } ++ } ++} ++ ++static int dt_fill_lp_state(uint32_t *lp_state_config, const char *lp_state) ++{ ++ int pwr_node; ++ void *fdt; ++ const fdt32_t *cuint; ++ ++ if (fdt_get_address(&fdt) == 0) { ++ return -ENOENT; ++ } ++ ++ pwr_node = dt_get_pwr_node(fdt); ++ if (pwr_node < 0) { ++ return -FDT_ERR_NOTFOUND; ++ } ++ ++ cuint = fdt_getprop(fdt, pwr_node, lp_state, NULL); ++ if (cuint == NULL) { ++ return -FDT_ERR_NOTFOUND; ++ } ++ ++ *lp_state_config = fdt32_to_cpu(*cuint); ++ ++ save_supported_mode(fdt, pwr_node); ++ ++ return 0; ++} ++ ++void stm32mp1_init_lp_states(void) ++{ ++ if (dt_fill_lp_state(&system_off_mode, SYSTEM_OFF_MODE) < 0) { ++ ERROR("Node %s not found\n", SYSTEM_OFF_MODE); ++ panic(); ++ } ++} ++ ++/* Init with all domains ON */ ++static bool pm_dom[STM32MP1_PD_MAX_PM_DOMAIN] = { ++ [STM32MP1_PD_VSW] = false, ++ [STM32MP1_PD_CORE_RET] = false, ++ [STM32MP1_PD_CORE] = false ++}; ++ ++static bool stm32mp1_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 &= 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 -EINVAL; ++ } ++ ++ pm_dom[domain] = status; ++ ++ return 0; ++} ++ ++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] == 1U; ++} ++ ++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_system_suspend_mode; ++ ++ if ((mode == STM32_PM_CSTOP_ALLOW_STANDBY_DDR_SR) && ++ ((!stm32mp1_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) && ++ ((!stm32mp1_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 -EINVAL; ++ } ++ ++ if (psci_mode == PSCI_MODE_SYSTEM_SUSPEND) { ++ deepest_system_suspend_mode = soc_mode; ++ } ++ ++ if (psci_mode == PSCI_MODE_SYSTEM_OFF) { ++ system_off_mode = soc_mode; ++ } ++ ++ return 0; ++} +diff --git a/plat/st/stm32mp1/stm32mp1_private.c b/plat/st/stm32mp1/stm32mp1_private.c +new file mode 100644 +index 0000000..c1f4c82 +--- /dev/null ++++ b/plat/st/stm32mp1/stm32mp1_private.c +@@ -0,0 +1,379 @@ ++/* ++ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. ++ * ++ * SPDX-License-Identifier: BSD-3-Clause ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define MAP_ROM MAP_REGION_FLAT(STM32MP_ROM_BASE, \ ++ STM32MP_ROM_SIZE, \ ++ MT_MEMORY | \ ++ MT_RO | \ ++ MT_SECURE | \ ++ MT_EXECUTE) ++ ++#define MAP_SRAM MAP_REGION_FLAT(STM32MP_SYSRAM_BASE, \ ++ STM32MP_SYSRAM_SIZE, \ ++ MT_MEMORY | \ ++ MT_RW | \ ++ MT_SECURE | \ ++ MT_EXECUTE_NEVER) ++ ++#define MAP_SRAM_MCU MAP_REGION_FLAT(STM32MP_SRAM_MCU_BASE, \ ++ STM32MP_SRAM_MCU_SIZE, \ ++ MT_MEMORY | \ ++ MT_RW | \ ++ MT_NS | \ ++ MT_EXECUTE_NEVER) ++ ++#define MAP_RETRAM MAP_REGION_FLAT(STM32MP_RETRAM_BASE, \ ++ STM32MP_RETRAM_SIZE, \ ++ MT_MEMORY | \ ++ MT_RW | \ ++ MT_NS | \ ++ MT_EXECUTE_NEVER) ++ ++#define MAP_DEVICE1 MAP_REGION_FLAT(STM32MP1_DEVICE1_BASE, \ ++ STM32MP1_DEVICE1_SIZE, \ ++ MT_DEVICE | \ ++ MT_RW | \ ++ MT_SECURE | \ ++ MT_EXECUTE_NEVER) ++ ++#define MAP_DEVICE2 MAP_REGION_FLAT(STM32MP1_DEVICE2_BASE, \ ++ STM32MP1_DEVICE2_SIZE, \ ++ MT_DEVICE | \ ++ MT_RW | \ ++ MT_SECURE | \ ++ MT_EXECUTE_NEVER) ++ ++#if defined(IMAGE_BL2) ++static const mmap_region_t stm32mp1_mmap[] = { ++ MAP_ROM, ++ MAP_SRAM, ++#if defined(STM32MP_USB) ++ MAP_SRAM_MCU, ++#endif ++ MAP_DEVICE1, ++ MAP_DEVICE2, ++ {0} ++}; ++#endif ++#if defined(IMAGE_BL32) ++static const mmap_region_t stm32mp1_mmap[] = { ++ MAP_ROM, ++ MAP_SRAM, ++ MAP_DEVICE1, ++ MAP_DEVICE2, ++ {0} ++}; ++#endif ++ ++void configure_mmu(void) ++{ ++#ifndef MMU_OFF ++ unsigned int flags = 0; ++ ++ mmap_add(stm32mp1_mmap); ++ init_xlat_tables(); ++#ifdef DCACHE_OFF ++ flags |= DISABLE_DCACHE; ++#endif ++ enable_mmu_svc_mon(flags); ++#endif ++} ++ ++#if STM32MP_UART_PROGRAMMER ++/* ++ * UART Management ++ */ ++static const uintptr_t stm32mp1_uart_addresses[8] = { ++ USART1_BASE, ++ USART2_BASE, ++ USART3_BASE, ++ UART4_BASE, ++ UART5_BASE, ++ USART6_BASE, ++ UART7_BASE, ++ UART8_BASE, ++}; ++ ++uintptr_t get_uart_address(uint32_t instance_nb) ++{ ++ if (!instance_nb || instance_nb > ARRAY_SIZE(stm32mp1_uart_addresses)) ++ return 0; ++ ++ return stm32mp1_uart_addresses[instance_nb - 1]; ++} ++#endif ++ ++void __dead2 stm32mp_plat_reset(int cpu) ++{ ++ uint32_t reg = RCC_MP_GRSTCSETR_MPUP0RST; ++ ++ if (stm32mp_is_single_core() == 0) { ++ unsigned int sec_cpu = (cpu == STM32MP_PRIMARY_CPU) ? ++ STM32MP_SECONDARY_CPU : STM32MP_PRIMARY_CPU; ++ ++ gicv2_raise_sgi(ARM_IRQ_SEC_SGI_1, sec_cpu); ++ reg |= RCC_MP_GRSTCSETR_MPUP1RST; ++ } ++ ++ mmio_write_32(stm32mp_rcc_base() + RCC_MP_GRSTCSETR, reg); ++ ++ isb(); ++ dsb(); ++ ++ /* Flush L1/L2 data caches */ ++ write_sctlr(read_sctlr() & ~SCTLR_C_BIT); ++ dcsw_op_all(DC_OP_CISW); ++ ++ for ( ; ; ) { ++ wfi(); ++ } ++} ++ ++static uint32_t get_part_number(void) ++{ ++ uint32_t part_number = 0; ++ ++ if (bsec_shadow_read_otp(&part_number, PART_NUMBER_OTP) != BSEC_OK) { ++ ERROR("BSEC: PART_NUMBER_OTP Error\n"); ++ return -1; ++ } ++ ++ part_number = (part_number & PART_MASK) >> PART_SHIFT; ++ ++ return (part_number | (stm32mp1_dbgmcu_get_chip_dev_id() << 16)); ++} ++ ++static uint32_t get_cpu_package(void) ++{ ++ uint32_t package = 0; ++ ++ if (bsec_shadow_read_otp(&package, PACKAGE_OTP) != BSEC_OK) { ++ ERROR("BSEC: PART_NUMBER_OTP Error\n"); ++ return -1; ++ } ++ ++ return ((package & PKG_MASK) >> PKG_SHIFT); ++} ++ ++void stm32mp_print_cpuinfo(void) ++{ ++ const char *cpu_s, *cpu_r, *pkg; ++ ++ /* MPUs Part Numbers */ ++ switch (get_part_number()) { ++ case STM32MP157C_PART_NB: ++ cpu_s = "157C"; ++ break; ++ case STM32MP157A_PART_NB: ++ cpu_s = "157A"; ++ break; ++ case STM32MP153C_PART_NB: ++ cpu_s = "153C"; ++ break; ++ case STM32MP153A_PART_NB: ++ cpu_s = "153A"; ++ break; ++ case STM32MP151C_PART_NB: ++ cpu_s = "151C"; ++ break; ++ case STM32MP151A_PART_NB: ++ cpu_s = "151A"; ++ break; ++ default: ++ cpu_s = "????"; ++ break; ++ } ++ ++ /* Package */ ++ switch (get_cpu_package()) { ++ case PKG_AA_LBGA448: ++ pkg = "AA"; ++ break; ++ case PKG_AB_LBGA354: ++ pkg = "AB"; ++ break; ++ case PKG_AC_TFBGA361: ++ pkg = "AC"; ++ break; ++ case PKG_AD_TFBGA257: ++ pkg = "AD"; ++ break; ++ default: ++ pkg = "??"; ++ break; ++ } ++ ++ /* REVISION */ ++ switch (stm32mp1_dbgmcu_get_chip_version()) { ++ case STM32MP1_REV_A: ++ cpu_r = "A"; ++ break; ++ case STM32MP1_REV_B: ++ cpu_r = "B"; ++ break; ++ default: ++ cpu_r = "?"; ++ break; ++ } ++ ++ NOTICE("CPU: STM32MP%s%s Rev.%s\n", cpu_s, pkg, cpu_r); ++} ++ ++void stm32mp_print_boardinfo(void) ++{ ++ uint32_t board; ++ int res = 0; ++ ++ if (bsec_shadow_read_otp(&board, BOARD_OTP) != BSEC_OK) { ++ ERROR("BSEC: PART_NUMBER_OTP Error\n"); ++ res = -1; ++ } ++ ++ if ((res == 0) && (board != 0U)) { ++ char rev[1]; ++ ++ *rev = ((board >> 8) & 0xF) - 1 + 'A'; ++ NOTICE("Board: MB%04x Var%d Rev.%s-%02d\n", ++ board >> 16, ++ (board >> 12) & 0xF, ++ rev, ++ board & 0xF); ++ } ++} ++ ++/* ++ * This function determines if one single core is presently running. This is ++ * done by OTP read. ++ * Returns 1 if yes, 0 if more that one core is running, -1 if error. ++ */ ++int stm32mp_is_single_core(void) ++{ ++ uint32_t part_number = get_part_number(); ++ ++ /* STM32MP151x is a single core */ ++ if ((part_number == STM32MP151A_PART_NB) || ++ (part_number == STM32MP151C_PART_NB)) { ++ return 1; ++ } ++ ++ return 0; ++} ++ ++uint8_t stm32_iwdg_get_instance(uintptr_t base) ++{ ++ switch (base) { ++ case IWDG1_BASE: ++ return IWDG1_INST; ++ case IWDG2_BASE: ++ return IWDG2_INST; ++ default: ++ panic(); ++ } ++} ++ ++uint32_t stm32_iwdg_get_otp_config(uintptr_t base) ++{ ++ uint8_t idx; ++ uint32_t iwdg_cfg = 0; ++ uint32_t otp_value; ++ ++#if defined(IMAGE_BL2) ++ if (bsec_shadow_read_otp(&otp_value, HW2_OTP) != BSEC_OK) { ++ panic(); ++ } ++#elif defined(IMAGE_BL32) ++ if (bsec_read_otp(&otp_value, HW2_OTP) != BSEC_OK) { ++ panic(); ++ } ++#endif ++ ++ idx = stm32_iwdg_get_instance(base); ++ ++ if ((otp_value & BIT(idx + IWDG_HW_POS)) != 0U) { ++ iwdg_cfg |= IWDG_HW_ENABLED; ++ } ++ ++ if ((otp_value & BIT(idx + IWDG_FZ_STOP_POS)) == 0U) { ++ iwdg_cfg |= IWDG_ENABLE_ON_STOP; ++ } ++ ++ if ((otp_value & BIT(idx + IWDG_FZ_STANDBY_POS)) == 0U) { ++ iwdg_cfg |= IWDG_ENABLE_ON_STANDBY; ++ } ++ ++ return iwdg_cfg; ++} ++ ++#if defined(IMAGE_BL2) ++uint32_t stm32_iwdg_shadow_update(uintptr_t base, uint32_t flags) ++{ ++ uint32_t idx; ++ uint32_t otp; ++ uint32_t result; ++ ++ if (bsec_shadow_read_otp(&otp, HW2_OTP) != BSEC_OK) { ++ panic(); ++ } ++ ++ idx = stm32_iwdg_get_instance(base); ++ ++ if ((flags & IWDG_ENABLE_ON_STOP) != 0) { ++ otp |= BIT(idx + IWDG_FZ_STOP_POS); ++ } ++ ++ if ((flags & IWDG_ENABLE_ON_STANDBY) != 0) { ++ otp |= BIT(idx + IWDG_FZ_STANDBY_POS); ++ } ++ ++ result = bsec_write_otp(otp, HW2_OTP); ++ if (result != BSEC_OK) { ++ return result; ++ } ++ ++ /* Sticky lock OTP_IWDG (read and write) */ ++ if (!bsec_write_sr_lock(HW2_OTP, 1U) || ++ !bsec_write_sw_lock(HW2_OTP, 1U)) { ++ return BSEC_LOCK_FAIL; ++ } ++ ++ return BSEC_OK; ++} ++#endif ++ ++/* ++ * 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(); ++ } ++} +diff --git a/plat/st/stm32mp1/stm32mp1_security.c b/plat/st/stm32mp1/stm32mp1_security.c +index e783c14..8dfbe71 100644 +--- a/plat/st/stm32mp1/stm32mp1_security.c ++++ b/plat/st/stm32mp1/stm32mp1_security.c +@@ -8,10 +8,10 @@ + #include + #include + #include +-#include +-#include ++#include + #include + #include ++#include + #include + #include "platform_def.h" + +@@ -22,13 +22,63 @@ + static void init_tzc400(void) + { + unsigned long long region_base, region_top; +- unsigned long long ddr_base = STM32MP1_DDR_BASE; ++ unsigned long long ddr_base = STM32MP_DDR_BASE; + unsigned long long ddr_size = (unsigned long long)dt_get_ddr_size(); + + tzc400_init(STM32MP1_TZC_BASE); + + tzc400_disable_filters(); + ++#ifdef AARCH32_SP_OPTEE ++ /* Region 1 set to cover all non-secure DRAM at 0xC000_0000. Apply the ++ * same configuration to all filters in the TZC. ++ */ ++ region_base = ddr_base; ++ region_top = ddr_base + (ddr_size - STM32MP_DDR_S_SIZE - 1U); ++ tzc400_configure_region(STM32MP1_FILTER_BIT_ALL, 1, ++ region_base, ++ region_top, ++ 0, ++ TZC_REGION_ACCESS_RDWR(STM32MP1_TZC_A7_ID) | ++ TZC_REGION_ACCESS_RDWR(STM32MP1_TZC_GPU_ID) | ++ TZC_REGION_ACCESS_RDWR(STM32MP1_TZC_LCD_ID) | ++ TZC_REGION_ACCESS_RDWR(STM32MP1_TZC_MDMA_ID) | ++ TZC_REGION_ACCESS_RDWR(STM32MP1_TZC_M4_ID) | ++ TZC_REGION_ACCESS_RDWR(STM32MP1_TZC_DMA_ID) | ++ TZC_REGION_ACCESS_RDWR(STM32MP1_TZC_USB_HOST_ID) | ++ TZC_REGION_ACCESS_RDWR(STM32MP1_TZC_USB_OTG_ID) | ++ TZC_REGION_ACCESS_RDWR(STM32MP1_TZC_SDMMC_ID) | ++ TZC_REGION_ACCESS_RDWR(STM32MP1_TZC_ETH_ID) | ++ TZC_REGION_ACCESS_RDWR(STM32MP1_TZC_DAP_ID)); ++ ++ /* Region 2 set to cover all secure DRAM. */ ++ region_base = ddr_base + (ddr_size - STM32MP_DDR_S_SIZE); ++ region_top = ddr_base + (ddr_size - STM32MP_DDR_SHMEM_SIZE - 1U); ++ tzc400_configure_region(STM32MP1_FILTER_BIT_ALL, 2, ++ region_base, ++ region_top, ++ TZC_REGION_S_RDWR, ++ 0); ++ ++ /* Region 3 set to cover non-secure shared memory DRAM. */ ++ region_base = ddr_base + (ddr_size - STM32MP_DDR_SHMEM_SIZE); ++ region_top = ddr_base + (ddr_size - 1U); ++ tzc400_configure_region(STM32MP1_FILTER_BIT_ALL, 3, ++ region_base, ++ region_top, ++ 0, ++ TZC_REGION_ACCESS_RDWR(STM32MP1_TZC_A7_ID) | ++ TZC_REGION_ACCESS_RDWR(STM32MP1_TZC_GPU_ID) | ++ TZC_REGION_ACCESS_RDWR(STM32MP1_TZC_LCD_ID) | ++ TZC_REGION_ACCESS_RDWR(STM32MP1_TZC_MDMA_ID) | ++ TZC_REGION_ACCESS_RDWR(STM32MP1_TZC_M4_ID) | ++ TZC_REGION_ACCESS_RDWR(STM32MP1_TZC_DMA_ID) | ++ TZC_REGION_ACCESS_RDWR(STM32MP1_TZC_USB_HOST_ID) | ++ TZC_REGION_ACCESS_RDWR(STM32MP1_TZC_USB_OTG_ID) | ++ TZC_REGION_ACCESS_RDWR(STM32MP1_TZC_SDMMC_ID) | ++ TZC_REGION_ACCESS_RDWR(STM32MP1_TZC_ETH_ID) | ++ TZC_REGION_ACCESS_RDWR(STM32MP1_TZC_DAP_ID)); ++#else + /* Region 1 set to cover all DRAM at 0xC000_0000. Apply the + * same configuration to all filters in the TZC. + */ +@@ -42,12 +92,14 @@ static void init_tzc400(void) + TZC_REGION_ACCESS_RDWR(STM32MP1_TZC_GPU_ID) | + TZC_REGION_ACCESS_RDWR(STM32MP1_TZC_LCD_ID) | + TZC_REGION_ACCESS_RDWR(STM32MP1_TZC_MDMA_ID) | ++ TZC_REGION_ACCESS_RDWR(STM32MP1_TZC_M4_ID) | + TZC_REGION_ACCESS_RDWR(STM32MP1_TZC_DMA_ID) | + TZC_REGION_ACCESS_RDWR(STM32MP1_TZC_USB_HOST_ID) | + TZC_REGION_ACCESS_RDWR(STM32MP1_TZC_USB_OTG_ID) | + TZC_REGION_ACCESS_RDWR(STM32MP1_TZC_SDMMC_ID) | + TZC_REGION_ACCESS_RDWR(STM32MP1_TZC_ETH_ID) | + TZC_REGION_ACCESS_RDWR(STM32MP1_TZC_DAP_ID)); ++#endif + + /* Raise an exception if a NS device tries to access secure memory */ + tzc400_set_action(TZC_ACTION_ERR); +@@ -62,30 +114,8 @@ static void init_tzc400(void) + ******************************************************************************/ + static void early_init_tzc400(void) + { +- uint32_t rstsr, rst_standby; +- +- rstsr = mmio_read_32(RCC_BASE + RCC_MP_RSTSCLRR); +- +- /* No warning if return from (C)STANDBY */ +- rst_standby = rstsr & +- (RCC_MP_RSTSCLRR_STDBYRSTF | RCC_MP_RSTSCLRR_CSTDBYRSTF); +- +- if (stm32mp1_clk_is_enabled(TZC1) && (rst_standby == 0U)) { +- WARN("TZC400 port 1 clock already enable\n"); +- } +- +- if (stm32mp1_clk_is_enabled(TZC2) && (rst_standby == 0U)) { +- WARN("TZC400 port 2 clock already enable\n"); +- } +- +- if (stm32mp1_clk_enable(TZC1) != 0) { +- ERROR("Cannot enable TZC1 clock\n"); +- panic(); +- } +- if (stm32mp1_clk_enable(TZC2) != 0) { +- ERROR("Cannot enable TZC2 clock\n"); +- panic(); +- } ++ stm32mp_clk_enable(TZC1); ++ stm32mp_clk_enable(TZC2); + + tzc400_init(STM32MP1_TZC_BASE); + +@@ -96,10 +126,11 @@ static void early_init_tzc400(void) + * same configuration to all filters in the TZC. + */ + tzc400_configure_region(STM32MP1_FILTER_BIT_ALL, 1, +- STM32MP1_DDR_BASE, +- STM32MP1_DDR_BASE + +- (STM32MP1_DDR_MAX_SIZE - 1U), ++ STM32MP_DDR_BASE, ++ STM32MP_DDR_BASE + ++ (STM32MP_DDR_MAX_SIZE - 1U), + TZC_REGION_S_RDWR, ++ TZC_REGION_ACCESS_RDWR(STM32MP1_TZC_A7_ID) | + TZC_REGION_ACCESS_RDWR(STM32MP1_TZC_SDMMC_ID)); + + /* Raise an exception if a NS device tries to access secure memory */ +diff --git a/plat/st/stm32mp1/stm32mp1_shared_resources.c b/plat/st/stm32mp1/stm32mp1_shared_resources.c +new file mode 100644 +index 0000000..2c95de0 +--- /dev/null ++++ b/plat/st/stm32mp1/stm32mp1_shared_resources.c +@@ -0,0 +1,833 @@ ++// SPDX-License-Identifier: BSD-3-Clause ++/* ++ * Copyright (c) 2017-2018, STMicroelectronics ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static bool registering_locked; ++static int8_t gpioz_nbpin = -1; ++ ++/* ++ * 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 stm32mp_clk_enable(unsigned long id) ++{ ++ if (registering_locked) { ++ if (stm32mp1_clock_is_non_secure(id)) { ++ assert(stm32mp1_clk_get_refcount(id) == 0U); ++ ++ if (stm32mp1_clk_is_enabled(id)) { ++ return; ++ } ++ } ++ } ++ ++ stm32mp1_clk_enable_secure(id); ++} ++ ++void stm32mp_clk_disable(unsigned long id) ++{ ++ if (registering_locked) { ++ if (stm32mp1_clock_is_non_secure(id)) { ++ if (stm32mp1_clk_get_refcount(id) == 0U) { ++ 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, 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]; ++ ++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]; ++} ++ ++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_DDRCTRL_ID, "DDRCTRL"), ++ SHRES2DECPROT(SHRES_INVALID, STM32MP1_ETZPC_DDRPHYC_ID, "DDRPHY"), ++}; ++ ++static unsigned int decprot2shres(unsigned int decprot_id) ++{ ++ uint32_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; ++ } ++ } ++ ++ VERBOSE("No shared resource %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; ++ } ++ } ++ ++ ERROR("Invalid ID %u", decprot_id); ++ panic(); ++} ++ ++static unsigned int get_gpioz_nbpin(void) ++{ ++ if (gpioz_nbpin < 0) { ++ gpioz_nbpin = (int8_t)fdt_get_gpioz_nbpins_from_dt(); ++ assert((gpioz_nbpin == 0) || ++ (gpioz_nbpin == STM32MP_GPIOZ_PIN_MAX_COUNT)); ++ } ++ ++ return (unsigned int)gpioz_nbpin; ++} ++ ++static bool shareable_resource(unsigned int id) ++{ ++ switch (id) { ++ default: ++ /* Currently no shareable resource */ ++ 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) { ++ if (shres_state[id] == state) { ++ return; ++ } ++ ++ panic(); ++ } ++ ++ if ((state == SHRES_SHARED && !shareable_resource(id)) || ++ ((shres_state[id] != SHRES_UNREGISTERED) && ++ (shres_state[id] != state))) { ++ VERBOSE("Cannot change %s from %s to %s\n", ++ shres2str_id(id), ++ shres2str_state(shres_state[id]), ++ shres2str_state(state)); ++ panic(); ++ } ++ ++ shres_state[id] = (uint8_t)state; ++ ++ if (shres_state[id] == SHRES_UNREGISTERED) { ++ VERBOSE("Register %s as %s\n", ++ shres2str_id(id), shres2str_state(state)); ++ } ++ ++ switch (id) { ++ case STM32MP1_SHRES_GPIOZ(0) ... STM32MP1_SHRES_GPIOZ(7): ++ if ((id - STM32MP1_SHRES_GPIOZ(0)) >= get_gpioz_nbpin()) { ++ ERROR("Invalid GPIO pin %u, %u pin(s) available\n", ++ id - STM32MP1_SHRES_GPIOZ(0), ++ get_gpioz_nbpin()); ++ panic(); ++ } ++ break; ++ default: ++ break; ++ } ++ ++ /* Explore clock tree to lock dependencies */ ++ if ((state == SHRES_SECURE) || (state == SHRES_SHARED)) { ++ switch (id) { ++ case STM32MP1_SHRES_GPIOZ(0) ... STM32MP1_SHRES_GPIOZ(7): ++ stm32mp1_register_clock_parents_secure(GPIOZ); ++ break; ++ case STM32MP1_SHRES_IWDG1: ++ stm32mp1_register_clock_parents_secure(IWDG1); ++ break; ++ case STM32MP1_SHRES_USART1: ++ stm32mp1_register_clock_parents_secure(USART1_K); ++ break; ++ case STM32MP1_SHRES_SPI6: ++ stm32mp1_register_clock_parents_secure(SPI6_K); ++ break; ++ case STM32MP1_SHRES_I2C4: ++ stm32mp1_register_clock_parents_secure(I2C4_K); ++ break; ++ case STM32MP1_SHRES_RNG1: ++ stm32mp1_register_clock_parents_secure(RNG1_K); ++ break; ++ case STM32MP1_SHRES_HASH1: ++ stm32mp1_register_clock_parents_secure(HASH1); ++ break; ++ case STM32MP1_SHRES_CRYP1: ++ stm32mp1_register_clock_parents_secure(CRYP1); ++ break; ++ case STM32MP1_SHRES_I2C6: ++ stm32mp1_register_clock_parents_secure(I2C6_K); ++ break; ++ case STM32MP1_SHRES_RTC: ++ stm32mp1_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); ++ stm32mp1_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); ++ stm32mp1_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); ++ stm32mp1_register_clock_parents_secure(PLL3); ++ break; ++ default: ++ /* No expected resource dependency */ ++ break; ++ } ++ } ++} ++ ++static bool stm32mp1_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; ++ } ++} ++ ++/* Register resource by ID */ ++void stm32mp1_register_secure_periph(unsigned int id) ++{ ++ register_periph(id, SHRES_SECURE); ++} ++ ++void stm32mp1_register_shared_periph(unsigned int id) ++{ ++ register_periph(id, SHRES_SHARED); ++} ++ ++void stm32mp1_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; ++ ++ 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: ++ case USART2_BASE: ++ case USART3_BASE: ++ case UART4_BASE: ++ case UART5_BASE: ++ case USART6_BASE: ++ case UART7_BASE: ++ case UART8_BASE: ++ case IWDG2_BASE: ++ /* Allow drivers to register some non secure resources */ ++ VERBOSE("IO for non secure resource 0x%x\n", ++ (unsigned int)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: ++ ERROR("GPIO bank %u cannot be secured\n", 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 stm32mp1_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(); ++ } ++ ++ id_shres = decprot2shres(id); ++ if (id_shres == SHRES_INVALID) { ++ if (state == SHRES_SECURE) { ++ panic(); ++ } ++ } else { ++ register_periph(id_shres, state); ++ } ++} ++ ++/* Get resource state: these accesses lock the registering support */ ++static void lock_registering(void) ++{ ++ registering_locked = true; ++} ++ ++bool stm32mp1_periph_is_shared(unsigned long id) ++{ ++ lock_registering(); ++ ++ return shres_state[id] == SHRES_SHARED; ++} ++ ++bool stm32mp1_periph_is_non_secure(unsigned long id) ++{ ++ lock_registering(); ++ ++ return shres_state[id] == SHRES_NON_SECURE; ++} ++ ++bool stm32mp1_periph_is_secure(unsigned long id) ++{ ++ lock_registering(); ++ ++ return shres_state[id] == SHRES_SECURE; ++} ++ ++bool stm32mp1_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 = 0U; i < get_gpioz_nbpin(); i++) { ++ if (stm32mp1_periph_is_non_secure(STM32MP1_SHRES_GPIOZ(i)) || ++ stm32mp1_periph_is_unregistered(STM32MP1_SHRES_GPIOZ(i))) { ++ non_secure++; ++ } ++ } ++ ++ return (non_secure != 0) && (non_secure < get_gpioz_nbpin()); ++} ++ ++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 = 0U; i < get_gpioz_nbpin(); i++) { ++ if (stm32mp1_periph_is_non_secure(STM32MP1_SHRES_GPIOZ(i)) || ++ stm32mp1_periph_is_unregistered(STM32MP1_SHRES_GPIOZ(i))) { ++ non_secure++; ++ } ++ } ++ ++ return non_secure == get_gpioz_nbpin(); ++} ++ ++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 = 0U; i < get_gpioz_nbpin(); i++) { ++ if (stm32mp1_periph_is_secure(STM32MP1_SHRES_GPIOZ(i))) { ++ secure++; ++ } ++ } ++ ++ return secure == get_gpioz_nbpin(); ++} ++ ++bool stm32mp1_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 stm32mp1_clock_is_shared(unsigned long clock_id) ++{ ++ lock_registering(); ++ ++ switch (clock_id) { ++ case GPIOZ: ++ if (get_gpioz_nbpin() > 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 stm32mp1_clock_is_non_secure(unsigned long clock_id) ++{ ++ unsigned int shres_id; ++ ++ lock_registering(); ++ ++ if (stm32mp1_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 stm32mp1_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) ... STM32MP1_SHRES_GPIOZ(7): ++ assert((id - STM32MP1_SHRES_GPIOZ(0)) < get_gpioz_nbpin()); ++ return TZPC_DECPROT_NS_RW; ++ default: ++ if (stm32mp1_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) { ++ WARN("ETZPC: %s (%d) could be non secure\n", ++ decprot2str(id), id); ++ } ++ return true; ++ ++ case TZPC_DECPROT_S_RW: ++ ERROR("ETZPC: %s (%d) expected secure but DECPROT = %d\n", ++ 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_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) { ++ panic(); ++ } ++} ++ ++static void check_rcc_secure_configuration(void) ++{ ++ uint32_t n; ++ uint32_t error = 0; ++ bool mckprot = stm32mp1_rcc_is_mckprot(); ++ bool secure = stm32mp1_rcc_is_secure(); ++ ++ stm32mp1_rcc_init_late(); ++ ++ for (n = 0; n < ARRAY_SIZE(shres_state); n++) { ++ if ((shres_state[n] == SHRES_SECURE) || ++ (shres_state[n] == SHRES_SHARED)) { ++ if ((stm32mp1_mckprot_resource(n) && (!mckprot)) || ++ !secure) { ++ ERROR("RCC %s MCKPROT %s and %s (%u) secure\n", ++ secure ? "secure" : "non secure", ++ mckprot ? "set" : "not set", ++ shres2str_id(n), n); ++ error++; ++ } ++ } ++ } ++ ++ if (error != 0U) { ++ panic(); ++ } ++} ++ ++static void check_gpio_secure_configuration(void) ++{ ++ uint32_t pin; ++ ++ for (pin = 0U; pin < get_gpioz_nbpin(); pin++) { ++ bool secure = ++ stm32mp1_periph_is_secure(STM32MP1_SHRES_GPIOZ(pin)); ++ ++ set_gpio_secure_cfg(GPIO_BANK_Z, pin, secure); ++ } ++} ++ ++void stm32mp1_driver_init_late(void) ++{ ++ uint32_t __unused id; ++ ++ registering_locked = true; ++ ++#if LOG_LEVEL >= LOG_LEVEL_INFO ++ for (id = 0; id < STM32MP1_SHRES_COUNT; id++) { ++ uint8_t *state = &shres_state[id]; ++ ++ /* Display only the secure and shared resources */ ++ if ((*state == SHRES_NON_SECURE) || ++ ((*state == SHRES_UNREGISTERED))) { ++ continue; ++ } ++ ++ INFO("stm32mp %s (%u): %s\n", ++ shres2str_id(id), id, ++ *state == SHRES_SECURE ? "Secure only" : ++ *state == SHRES_SHARED ? "Shared" : ++ *state == SHRES_NON_SECURE ? "Non secure" : ++ *state == SHRES_UNREGISTERED ? "Unregistered" : ++ ""); ++ } ++#endif ++ ++ stm32mp1_update_earlyboot_clocks_state(); ++ ++ check_rcc_secure_configuration(); ++ check_etzpc_secure_configuration(); ++ check_gpio_secure_configuration(); ++} ++ +diff --git a/plat/st/stm32mp1/stm32mp1_syscfg.c b/plat/st/stm32mp1/stm32mp1_syscfg.c +new file mode 100644 +index 0000000..3eb9893 +--- /dev/null ++++ b/plat/st/stm32mp1/stm32mp1_syscfg.c +@@ -0,0 +1,144 @@ ++/* ++ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved. ++ * ++ * SPDX-License-Identifier: BSD-3-Clause ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* ++ * SYSCFG REGISTER OFFSET (base relative) ++ */ ++#define SYSCFG_BOOTR 0x00U ++#define SYSCFG_IOCTRLSETR 0x18U ++#define SYSCFG_ICNR 0x1CU ++#define SYSCFG_CMPCR 0x20U ++#define SYSCFG_CMPENSETR 0x24U ++ ++/* ++ * SYSCFG_BOOTR Register ++ */ ++#define SYSCFG_BOOTR_BOOT_MASK GENMASK(2, 0) ++#define SYSCFG_BOOTR_BOOTPD_SHIFT 4 ++/* ++ * SYSCFG_IOCTRLSETR Register ++ */ ++#define SYSCFG_IOCTRLSETR_HSLVEN_TRACE BIT(0) ++#define SYSCFG_IOCTRLSETR_HSLVEN_QUADSPI BIT(1) ++#define SYSCFG_IOCTRLSETR_HSLVEN_ETH BIT(2) ++#define SYSCFG_IOCTRLSETR_HSLVEN_SDMMC BIT(3) ++#define SYSCFG_IOCTRLSETR_HSLVEN_SPI BIT(4) ++ ++/* ++ * SYSCFG_ICNR Register ++ */ ++#define SYSCFG_ICNR_AXI_M9 BIT(9) ++ ++/* ++ * SYSCFG_CMPCR Register ++ */ ++#define SYSCFG_CMPCR_SW_CTRL BIT(1) ++#define SYSCFG_CMPCR_READY BIT(8) ++ ++/* ++ * SYSCFG_CMPENSETR Register ++ */ ++#define SYSCFG_CMPENSETR_MPU_EN BIT(0) ++ ++#define PRODUCT_BELOW_2V5 BIT(13) ++ ++void stm32mp1_syscfg_init(void) ++{ ++ uint32_t bootr; ++ uint32_t otp = 0; ++ uint32_t vdd_voltage; ++ uintptr_t syscfg_base = dt_get_syscfg_base(); ++ ++ /* ++ * Interconnect update : select master using the port 1. ++ * LTDC = AXI_M9. ++ */ ++ mmio_write_32(syscfg_base + SYSCFG_ICNR, SYSCFG_ICNR_AXI_M9); ++ VERBOSE("[0x%x] SYSCFG.icnr = 0x%08x (LTDC)\n", ++ (uint32_t)syscfg_base + SYSCFG_ICNR, ++ mmio_read_32(syscfg_base + SYSCFG_ICNR)); ++ ++ /* Disable Pull-Down for boot pin connected to VDD */ ++ bootr = mmio_read_32(syscfg_base + SYSCFG_BOOTR); ++ bootr &= ~(SYSCFG_BOOTR_BOOT_MASK << SYSCFG_BOOTR_BOOTPD_SHIFT); ++ bootr |= (bootr & SYSCFG_BOOTR_BOOT_MASK) << SYSCFG_BOOTR_BOOTPD_SHIFT; ++ mmio_write_32(syscfg_base + SYSCFG_BOOTR, bootr); ++ VERBOSE("[0x%x] SYSCFG.bootr = 0x%08x\n", ++ (uint32_t)syscfg_base + SYSCFG_BOOTR, ++ mmio_read_32(syscfg_base + SYSCFG_BOOTR)); ++ ++ /* ++ * High Speed Low Voltage Pad mode Enable for SPI, SDMMC, ETH, QSPI ++ * and TRACE. Needed above ~50MHz and conditioned by AFMUX selection. ++ * The customer will have to disable this for low frequencies ++ * or if AFMUX is selected but the function not used, typically for ++ * TRACE. Otherwise, impact on power consumption. ++ * ++ * WARNING: ++ * Enabling High Speed mode while VDD > 2.7V ++ * with the OTP product_below_2v5 (OTP 18, BIT 13) ++ * erroneously set to 1 can damage the IC! ++ * => TF-A sets the register only if VDD < 2.7V (in DT) ++ * but this value needs to be consistent with board design. ++ */ ++ if (bsec_read_otp(&otp, HW2_OTP) != BSEC_OK) { ++ otp = otp & PRODUCT_BELOW_2V5; ++ } ++ ++ /* Get VDD = pwr-supply */ ++ vdd_voltage = dt_get_pwr_vdd_voltage(); ++ VERBOSE("VDD regulator voltage = %d\n", vdd_voltage); ++ ++ /* Check if VDD is Low Voltage */ ++ if (vdd_voltage == 0U) { ++ INFO("VDD unknown"); ++ } else if (vdd_voltage < 2700000U) { ++ mmio_write_32(syscfg_base + SYSCFG_IOCTRLSETR, ++ SYSCFG_IOCTRLSETR_HSLVEN_TRACE | ++ SYSCFG_IOCTRLSETR_HSLVEN_QUADSPI | ++ SYSCFG_IOCTRLSETR_HSLVEN_ETH | ++ SYSCFG_IOCTRLSETR_HSLVEN_SDMMC | ++ SYSCFG_IOCTRLSETR_HSLVEN_SPI); ++ ++ if (otp == 0U) { ++ INFO("Product_below_2v5=0: HSLVEN protected by HW\n"); ++ } ++ } else { ++ if (otp != 0U) { ++ INFO("Product_below_2v5=1: HSLVEN update is\n"); ++ INFO(" destructive, no update as VDD>2.7V\n"); ++ } ++ } ++ ++ VERBOSE("[0x%x] SYSCFG.IOCTRLSETR = 0x%08x\n", ++ (uint32_t)syscfg_base + SYSCFG_IOCTRLSETR, ++ mmio_read_32(syscfg_base + SYSCFG_IOCTRLSETR)); ++ ++ /* ++ * Activate automatic I/O compensation. ++ * Warning: need to ensure CSI enabled and ready in clock driver. ++ */ ++ mmio_write_32(syscfg_base + SYSCFG_CMPENSETR, SYSCFG_CMPENSETR_MPU_EN); ++ ++ while ((mmio_read_32(syscfg_base + SYSCFG_CMPCR) & ++ SYSCFG_CMPCR_READY) != 0U) { ++ ; ++ } ++ ++ mmio_clrbits_32(syscfg_base + SYSCFG_CMPCR, SYSCFG_CMPCR_SW_CTRL); ++ ++ VERBOSE("[0x%x] SYSCFG.cmpcr = 0x%08x\n", ++ (uint32_t)syscfg_base + SYSCFG_CMPCR, ++ mmio_read_32(syscfg_base + SYSCFG_CMPCR)); ++} +diff --git a/plat/st/stm32mp1/stm32mp1_usb_desc.c b/plat/st/stm32mp1/stm32mp1_usb_desc.c +new file mode 100644 +index 0000000..410cfa1 +--- /dev/null ++++ b/plat/st/stm32mp1/stm32mp1_usb_desc.c +@@ -0,0 +1,401 @@ ++/* ++ * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved. ++ * ++ * SPDX-License-Identifier: BSD-3-Clause ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* USB Standard Device Descriptor */ ++static const uint8_t usb_stm32mp1_desc[USB_LEN_DEV_DESC] = { ++ USB_LEN_DEV_DESC, /* bLength */ ++ USB_DESC_TYPE_DEVICE, /* bDescriptorType */ ++ 0x00, /* bcdUSB */ ++ 0x02, /* version */ ++ 0x00, /* bDeviceClass */ ++ 0x00, /* bDeviceSubClass */ ++ 0x00, /* bDeviceProtocol */ ++ USB_MAX_EP0_SIZE, /* bMaxPacketSize */ ++ LOBYTE(USBD_VID), /* idVendor */ ++ HIBYTE(USBD_VID), /* idVendor */ ++ LOBYTE(USBD_PID), /* idVendor */ ++ HIBYTE(USBD_PID), /* idVendor */ ++ 0x00, /* bcdDevice rel. 2.00 */ ++ 0x02, ++ USBD_IDX_MFC_STR, /* Index of manufacturer string */ ++ USBD_IDX_PRODUCT_STR, /* Index of product string */ ++ USBD_IDX_SERIAL_STR, /* Index of serial number string */ ++ USBD_MAX_NUM_CONFIGURATION /* bNumConfigurations */ ++}; /* USB_DeviceDescriptor */ ++ ++/* USB Standard String Descriptor */ ++static const uint8_t usb_stm32mp1_lang_id_desc[USB_LEN_LANGID_STR_DESC] = { ++ USB_LEN_LANGID_STR_DESC, ++ USB_DESC_TYPE_STRING, ++ LOBYTE(USBD_LANGID_STRING), ++ HIBYTE(USBD_LANGID_STRING), ++}; ++ ++/* USB Standard Device Descriptor */ ++static const uint8_t ++usbd_stm32mp1_qualifier_desc[USB_LEN_DEV_QUALIFIER_DESC] = { ++ USB_LEN_DEV_QUALIFIER_DESC, ++ USB_DESC_TYPE_DEVICE_QUALIFIER, ++ 0x00, ++ 0x02, ++ 0x00, ++ 0x00, ++ 0x00, ++ 0x40, ++ 0x01, ++ 0x00, ++}; ++ ++static uint8_t usb_stm32mp1_serial[USB_SIZ_STRING_SERIAL + 1] = { ++ USB_SIZ_STRING_SERIAL, ++ USB_DESC_TYPE_STRING, ++}; ++ ++/* USB DFU device Configuration Descriptor */ ++static uint8_t usb_stm32mp1_config_desc[USB_DFU_CONFIG_DESC_SIZ] = { ++ 0x09, /* bLength: Configuation Descriptor size */ ++ USB_DESC_TYPE_CONFIGURATION, /* bDescriptorType: Configuration */ ++ USB_DFU_CONFIG_DESC_SIZ, ++ /* wTotalLength: Bytes returned */ ++ 0x00, ++ 0x01,/* bNumInterfaces: 1 interface*/ ++ 0x01,/* bConfigurationValue: Configuration value*/ ++ 0x02,/* iConfiguration: Index of string descriptor ++ * describing the configuration ++ */ ++ 0xC0,/* bmAttributes: bus powered and Supprts Remote Wakeup */ ++ 0x32,/* MaxPower 100 mA: this current is used for detecting Vbus */ ++ /* 09 */ ++ ++ /* Descriptor of DFU interface 0 Alternate setting 0 */ ++ USBD_DFU_IF_DESC(0), /* This interface is mandatory for all devices */ ++ ++ /* Descriptor of DFU interface 0 Alternate setting 1 */ ++ USBD_DFU_IF_DESC(1), ++ ++ /* Descriptor of DFU interface 0 Alternate setting 2 */ ++ USBD_DFU_IF_DESC(2), ++ ++ /* Descriptor of DFU interface 0 Alternate setting 3 */ ++ USBD_DFU_IF_DESC(3), ++ ++ /* Descriptor of DFU interface 0 Alternate setting 4 */ ++ USBD_DFU_IF_DESC(4), ++ ++ /* Descriptor of DFU interface 0 Alternate setting 5 */ ++ USBD_DFU_IF_DESC(5), ++ ++ /* DFU Functional Descriptor */ ++ 0x09,/* blength = 9 Bytes */ ++ DFU_DESCRIPTOR_TYPE,/* DFU Functional Descriptor*/ ++ DFU_BM_ATTRIBUTE,/* bmAttribute ++ * bitCanDnload = 1 (bit 0) ++ * bitCanUpload = 1 (bit 1) ++ * bitManifestationTolerant = 1 (bit 2) ++ * bitWillDetach = 1 (bit 3) ++ * Reserved (bit4-6) ++ * bitAcceleratedST = 0 (bit 7) ++ */ ++ 0xFF,/* DetachTimeOut = 255 ms */ ++ 0x00, ++ /* WARNING: In DMA mode the multiple MPS packets feature ++ * is still not supported ==> In this case, ++ * when using DMA USBD_DFU_XFER_SIZE should be set ++ * to 64 in usbd_conf.h ++ */ ++ TRANSFER_SIZE_BYTES(USBD_DFU_XFER_SIZE),/* TransferSize = 1024 Byte*/ ++ ((USB_DFU_VERSION >> 0) & 0xFF), /* bcdDFUVersion*/ ++ ((USB_DFU_VERSION >> 8) & 0xFF) ++}; ++ ++static uint8_t usb_local_string_dec[USBD_MAX_STR_DESC_SIZ]; ++ ++/* ++ * Convert Hex 32Bits value into char ++ * value: value to convert ++ * pbuf: pointer to the buffer ++ * len: buffer length ++ */ ++static void int_to_unicode(uint32_t value, uint8_t *pbuf, uint8_t len) ++{ ++ uint8_t idx = 0; ++ ++ for (idx = 0; idx < len; idx++) { ++ if (((value >> 28)) < 0xA) ++ pbuf[2 * idx] = (value >> 28) + '0'; ++ else ++ pbuf[2 * idx] = (value >> 28) + 'A' - 10; ++ value = value << 4; ++ pbuf[(2 * idx) + 1] = 0; ++ } ++} ++ ++/* ++ * Create the serial number string descriptor ++ */ ++static void update_serial_num_string(void) ++{ ++ /* serial number is set to 0*/ ++ uint8_t i; ++ uint32_t deviceserial[3] = {0, 0, 0}; ++ ++ for (i = 0; i < 3; i++) { ++ if (bsec_shadow_read_otp(&deviceserial[i], i + UID0_OTP) != ++ BSEC_OK) { ++ ERROR("BSEC: UID%d Error\n", i); ++ return; ++ } ++ } ++ ++ int_to_unicode(deviceserial[0], (uint8_t *)&usb_stm32mp1_serial[2], 8); ++ int_to_unicode(deviceserial[1], (uint8_t *)&usb_stm32mp1_serial[18], 8); ++ int_to_unicode(deviceserial[2], (uint8_t *)&usb_stm32mp1_serial[34], 8); ++} ++ ++/* ++ * usb_get_qualifier_desc ++ * return Device Qualifier descriptor ++ * param : length : pointer data length ++ * return : pointer to descriptor buffer ++ */ ++static uint8_t *stm32mp1_get_qualifier_desc(uint16_t *length) ++{ ++ *length = sizeof(usbd_stm32mp1_qualifier_desc); ++ return (uint8_t *)usbd_stm32mp1_qualifier_desc; ++} ++ ++/* ++ * stm32mp1_get_dfu_desc ++ * return Device Qualifier descriptor ++ * param : length : pointer data length ++ * return : pointer to descriptor buffer ++ */ ++static uint8_t *stm32mp1_get_dfu_desc(uint16_t *len) ++{ ++ *len = USB_DFU_DESC_SIZ; ++ return ((uint8_t *)usb_stm32mp1_config_desc + (9 * 7)); ++} ++ ++/* ++ * stm32mp1_get_config_desc ++ * return configuration descriptor ++ * param : speed : current device speed ++ * param : length : pointer data length ++ * return : pointer to descriptor buffer ++ */ ++static uint8_t *stm32mp1_get_config_desc(uint16_t *length) ++{ ++ *length = sizeof(usb_stm32mp1_config_desc); ++ return (uint8_t *)usb_stm32mp1_config_desc; ++} ++ ++/* ++ * stm32mp1_get_string ++ * Convert Ascii string into unicode one ++ * param : desc : descriptor buffer ++ * param : unicode : Formatted string buffer (unicode) ++ * param : len : descriptor length ++ * return : None ++ */ ++static void stm32mp1_get_string(uint8_t *desc, uint8_t *unicode, uint16_t *len) ++{ ++ uint8_t idx = 0; ++ ++ if (!desc) ++ return; ++ ++ *len = strlen((char *)desc) * 2 + 2; ++ unicode[idx++] = *len; ++ unicode[idx++] = USB_DESC_TYPE_STRING; ++ ++ while (*desc != '\0') { ++ unicode[idx++] = *desc++; ++ unicode[idx++] = 0x00; ++ } ++} ++ ++/* ++ * stm32mp1_device_desc ++ * Returns the device descriptor. ++ * length: Pointer to data length variable ++ * return : Pointer to descriptor buffer ++ */ ++static uint8_t *stm32mp1_device_desc(uint16_t *length) ++{ ++ *length = sizeof(usb_stm32mp1_desc); ++ return (uint8_t *)usb_stm32mp1_desc; ++} ++ ++/* ++ * stm32mp1_lang_id_desc ++ * Returns the LangID string descriptor. ++ * speed: Current device speed ++ * length: Pointer to data length variable ++ * return : Pointer to descriptor buffer ++ */ ++static uint8_t *stm32mp1_lang_id_desc(uint16_t *length) ++{ ++ *length = sizeof(usb_stm32mp1_lang_id_desc); ++ ++ return (uint8_t *)usb_stm32mp1_lang_id_desc; ++} ++ ++/* ++ * stm32mp1_product_desc ++ * Returns the product string descriptor. ++ * length: Pointer to data length variable ++ * return : Pointer to descriptor buffer ++ */ ++static uint8_t *stm32mp1_product_desc(uint16_t *length) ++{ ++ stm32mp1_get_string((uint8_t *)USBD_PRODUCT_HS_STRING, ++ usb_local_string_dec, length); ++ ++ return usb_local_string_dec; ++} ++ ++/* ++ * stm32mp1_manufacturer_desc ++ * Returns the manufacturer string descriptor. ++ * length: Pointer to data length variable ++ * return : Pointer to descriptor buffer ++ */ ++static uint8_t *stm32mp1_manufacturer_desc(uint16_t *length) ++{ ++ stm32mp1_get_string((uint8_t *)USBD_MANUFACTURER_STRING, ++ usb_local_string_dec, length); ++ ++ return usb_local_string_dec; ++} ++ ++/* ++ * stm32mp1_serial_desc ++ * Returns the serial number string descriptor. ++ * length: Pointer to data length variable ++ * return : Pointer to descriptor buffer ++ */ ++static uint8_t *stm32mp1_serial_desc(uint16_t *length) ++{ ++ *length = USB_SIZ_STRING_SERIAL; ++ ++ /* Update the serial number string descriptor ++ * with the data from the unique ID ++ */ ++ update_serial_num_string(); ++ ++ return (uint8_t *)usb_stm32mp1_serial; ++} ++ ++/* ++ * stm32mp1_Config_desc ++ * Returns the configuration string descriptor. ++ * length: Pointer to data length variable ++ * return : Pointer to descriptor buffer ++ */ ++static uint8_t *stm32mp1_config_desc(uint16_t *length) ++{ ++ stm32mp1_get_string((uint8_t *)USBD_CONFIGURATION_HS_STRING, ++ usb_local_string_dec, length); ++ ++ return usb_local_string_dec; ++} ++ ++/* ++ * stm32mp1_interface_desc ++ * Returns the interface string descriptor. ++ * length : Pointer to data length variable ++ * return : Pointer to descriptor buffer ++ */ ++static uint8_t *stm32mp1_interface_desc(uint16_t *length) ++{ ++ stm32mp1_get_string((uint8_t *)USBD_INTERFACE_HS_STRING, ++ usb_local_string_dec, length); ++ ++ return usb_local_string_dec; ++} ++ ++/* ++ * stm32mp1_get_usr_desc ++ * Manages the transfer of memory interfaces string descriptors. ++ * param : index: descriptor index ++ * param : length : pointer data length ++ * return : pointer to the descriptor table or NULL if the descriptor ++ * is not supported. ++ */ ++static uint8_t *stm32mp1_get_usr_desc(uint8_t index, uint16_t *length) ++{ ++ uint8_t *ret; ++ ++ if (index > (USBD_IDX_INTERFACE_STR + USBD_DESC_MAX_ITF_NUM)) ++ return NULL; ++ ++ switch (index) { ++ case 6: ++ stm32mp1_get_string((uint8_t *)"@Partition0 /0x00/1*256Ke", ++ usb_local_string_dec, length); ++ ret = usb_local_string_dec; ++ break; ++ case 7: ++ stm32mp1_get_string((uint8_t *)"@FSBL /0x01/1*1Me", ++ usb_local_string_dec, length); ++ ret = usb_local_string_dec; ++ break; ++ case 8: ++ stm32mp1_get_string((uint8_t *)"@Partition2 /0x02/1*1Me", ++ usb_local_string_dec, length); ++ ret = usb_local_string_dec; ++ break; ++ case 9: ++ stm32mp1_get_string((uint8_t *)"@Partition3 /0x03/1*16Me", ++ usb_local_string_dec, length); ++ ret = usb_local_string_dec; ++ break; ++ case 10: ++ stm32mp1_get_string((uint8_t *)"@Partition4 /0x04/1*16Me", ++ usb_local_string_dec, length); ++ ret = usb_local_string_dec; ++ break; ++ case 11: ++ stm32mp1_get_string((uint8_t *)"@virtual /0xF1/1*512Ba", ++ usb_local_string_dec, length); ++ ret = usb_local_string_dec; ++ break; ++ default: ++ ret = NULL; ++ break; ++ } ++ ++ return ret; ++} ++ ++static const usb_desc_t dfu_desc = { ++ .get_device_desc = stm32mp1_device_desc, ++ .get_lang_id_desc = stm32mp1_lang_id_desc, ++ .get_manufacturer_desc = stm32mp1_manufacturer_desc, ++ .get_product_desc = stm32mp1_product_desc, ++ .get_configuration_desc = stm32mp1_config_desc, ++ .get_serial_desc = stm32mp1_serial_desc, ++ .get_interface_desc = stm32mp1_interface_desc, ++ .get_usr_desc = stm32mp1_get_usr_desc, ++ .get_hs_config_desc = stm32mp1_get_config_desc, ++ .get_fs_config_desc = stm32mp1_get_config_desc, ++ .get_other_speed_config_desc = stm32mp1_get_config_desc, ++ .get_device_qualifier_desc = stm32mp1_get_qualifier_desc, ++ .get_dfu_desc = stm32mp1_get_dfu_desc ++}; ++ ++void stm32mp_usb_init_desc(usb_handle_t *pdev) ++{ ++ register_platform(pdev, &dfu_desc); ++} +diff --git a/tools/cert_create/Makefile b/tools/cert_create/Makefile +index 7b10e3e..c03629a 100644 +--- a/tools/cert_create/Makefile ++++ b/tools/cert_create/Makefile +@@ -1,5 +1,5 @@ + # +-# Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved. ++# Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. + # + # SPDX-License-Identifier: BSD-3-Clause + # +@@ -22,7 +22,7 @@ OBJECTS := src/cert.o \ + src/tbbr/tbb_ext.o \ + src/tbbr/tbb_key.o + +-CFLAGS := -Wall -std=c99 ++HOSTCCFLAGS := -Wall -std=c99 + + MAKE_HELPERS_DIRECTORY := ../../make_helpers/ + include ${MAKE_HELPERS_DIRECTORY}build_macros.mk +@@ -46,9 +46,9 @@ endif + endif + + ifeq (${DEBUG},1) +- CFLAGS += -g -O0 -DDEBUG -DLOG_LEVEL=40 ++ HOSTCCFLAGS += -g -O0 -DDEBUG -DLOG_LEVEL=40 + else +- CFLAGS += -O2 -DLOG_LEVEL=20 ++ HOSTCCFLAGS += -O2 -DLOG_LEVEL=20 + endif + ifeq (${V},0) + Q := @ +@@ -57,7 +57,7 @@ else + endif + + $(eval $(call add_define,USE_TBBR_DEFS)) +-CFLAGS += ${DEFINES} ++HOSTCCFLAGS += ${DEFINES} + + # Make soft links and include from local directory otherwise wrong headers + # could get pulled in from firmware tree. +@@ -72,15 +72,15 @@ HOSTCC ?= gcc + all: clean ${BINARY} + + ${BINARY}: ${OBJECTS} Makefile +- @echo " LD $@" ++ @echo " HOSTLD $@" + @echo 'const char build_msg[] = "Built : "__TIME__", "__DATE__; \ + const char platform_msg[] = "${PLAT_MSG}";' | \ +- ${HOSTCC} -c ${CFLAGS} -xc - -o src/build_msg.o ++ ${HOSTCC} -c ${HOSTCCFLAGS} -xc - -o src/build_msg.o + ${Q}${HOSTCC} src/build_msg.o ${OBJECTS} ${LIB_DIR} ${LIB} -o $@ + + %.o: %.c +- @echo " CC $<" +- ${Q}${HOSTCC} -c ${CFLAGS} ${INC_DIR} $< -o $@ ++ @echo " HOSTCC $<" ++ ${Q}${HOSTCC} -c ${HOSTCCFLAGS} ${INC_DIR} $< -o $@ + + clean: + $(call SHELL_DELETE_ALL, src/build_msg.o ${OBJECTS}) +diff --git a/tools/doimage/Makefile b/tools/doimage/Makefile +index bc74369..9f0d89d 100644 +--- a/tools/doimage/Makefile ++++ b/tools/doimage/Makefile +@@ -7,11 +7,11 @@ + PROJECT = doimage + OBJECTS = doimage.o + +-CFLAGS = -Wall -Werror ++HOSTCCFLAGS = -Wall -Werror + ifeq (${DEBUG},1) +- CFLAGS += -g -O0 -DDEBUG ++ HOSTCCFLAGS += -g -O0 -DDEBUG + else +- CFLAGS += -O2 ++ HOSTCCFLAGS += -O2 + endif + + ifeq (${MARVELL_SECURE_BOOT},1) +@@ -19,13 +19,13 @@ DOIMAGE_CC_FLAGS := -DCONFIG_MVEBU_SECURE_BOOT + DOIMAGE_LD_FLAGS := -lconfig -lmbedtls -lmbedcrypto -lmbedx509 + endif + +-CFLAGS += ${DOIMAGE_CC_FLAGS} ++HOSTCCFLAGS += ${DOIMAGE_CC_FLAGS} + + # Make soft links and include from local directory otherwise wrong headers + # could get pulled in from firmware tree. + INCLUDE_PATHS = -I. + +-CC := gcc ++HOSTCC ?= gcc + RM := rm -rf + + .PHONY: all clean +@@ -33,15 +33,15 @@ RM := rm -rf + all: ${PROJECT} + + ${PROJECT}: ${OBJECTS} Makefile +- @echo " LD $@" +- ${Q}${CC} ${OBJECTS} ${DOIMAGE_LD_FLAGS} -o $@ ++ @echo " HOSTLD $@" ++ ${Q}${HOSTCC} ${OBJECTS} ${DOIMAGE_LD_FLAGS} -o $@ + @echo + @echo "Built $@ successfully" + @echo + +-%.o: %.c %.h Makefile +- @echo " CC $<" +- ${Q}${CC} -c ${CFLAGS} ${INCLUDE_PATHS} $< -o $@ ++%.o: %.c Makefile ++ @echo " HOSTCC $<" ++ ${Q}${HOSTCC} -c ${HOSTCCFLAGS} ${INCLUDE_PATHS} $< -o $@ + + clean: + ${Q}${RM} ${PROJECT} +diff --git a/tools/fiptool/Makefile b/tools/fiptool/Makefile +index 9bdafe0..ef35014 100644 +--- a/tools/fiptool/Makefile ++++ b/tools/fiptool/Makefile +@@ -1,5 +1,5 @@ + # +-# Copyright (c) 2014-2017, ARM Limited and Contributors. All rights reserved. ++# Copyright (c) 2014-2018, ARM Limited and Contributors. All rights reserved. + # + # SPDX-License-Identifier: BSD-3-Clause + # +@@ -13,11 +13,11 @@ OBJECTS := fiptool.o tbbr_config.o + V ?= 0 + + override CPPFLAGS += -D_GNU_SOURCE -D_XOPEN_SOURCE=700 +-CFLAGS := -Wall -Werror -pedantic -std=c99 ++HOSTCCFLAGS := -Wall -Werror -pedantic -std=c99 + ifeq (${DEBUG},1) +- CFLAGS += -g -O0 -DDEBUG ++ HOSTCCFLAGS += -g -O0 -DDEBUG + else +- CFLAGS += -O2 ++ HOSTCCFLAGS += -O2 + endif + LDLIBS := -lcrypto + +@@ -36,15 +36,15 @@ HOSTCC ?= gcc + all: ${PROJECT} + + ${PROJECT}: ${OBJECTS} Makefile +- @echo " LD $@" ++ @echo " HOSTLD $@" + ${Q}${HOSTCC} ${OBJECTS} -o $@ ${LDLIBS} + @${ECHO_BLANK_LINE} + @echo "Built $@ successfully" + @${ECHO_BLANK_LINE} + + %.o: %.c %.h Makefile +- @echo " CC $<" +- ${Q}${HOSTCC} -c ${CPPFLAGS} ${CFLAGS} ${INCLUDE_PATHS} $< -o $@ ++ @echo " HOSTCC $<" ++ ${Q}${HOSTCC} -c ${CPPFLAGS} ${HOSTCCFLAGS} ${INCLUDE_PATHS} $< -o $@ + + clean: + $(call SHELL_DELETE_ALL, ${PROJECT} ${OBJECTS}) +diff --git a/tools/stm32image/Makefile b/tools/stm32image/Makefile +index 80dfbec..9c9b7b5 100644 +--- a/tools/stm32image/Makefile ++++ b/tools/stm32image/Makefile +@@ -12,12 +12,12 @@ PROJECT := stm32image${BIN_EXT} + OBJECTS := stm32image.o + V := 0 + +-override CPPFLAGS += -D_GNU_SOURCE +-CFLAGS := -Wall -Werror -pedantic -std=c99 ++HOSTCCFLAGS := -Wall -Werror -pedantic -std=c99 -D_GNU_SOURCE ++ + ifeq (${DEBUG},1) +- CFLAGS += -g -O0 -DDEBUG ++ HOSTCCFLAGS += -g -O0 -DDEBUG + else +- CFLAGS += -O2 ++ HOSTCCFLAGS += -O2 + endif + + ifeq (${V},0) +@@ -26,22 +26,22 @@ else + Q := + endif + +-CC := gcc ++HOSTCC := gcc + + .PHONY: all clean distclean + + all: ${PROJECT} + + ${PROJECT}: ${OBJECTS} Makefile +- @echo " LD $@" +- ${Q}${CC} ${OBJECTS} -o $@ ++ @echo " HOSTLD $@" ++ ${Q}${HOSTCC} ${OBJECTS} -o $@ + @${ECHO_BLANK_LINE} + @echo "Built $@ successfully" + @${ECHO_BLANK_LINE} + +-%.o: %.c %.h Makefile +- @echo " CC $<" +- ${Q}${CC} -c ${CFLAGS} $< -o $@ ++%.o: %.c Makefile ++ @echo " HOSTCC $<" ++ ${Q}${HOSTCC} -c ${HOSTCCFLAGS} $< -o $@ + + clean: + $(call SHELL_DELETE_ALL, ${PROJECT} ${OBJECTS}) +diff --git a/tools/stm32image/stm32image.c b/tools/stm32image/stm32image.c +index 2607928..41024e2 100644 +--- a/tools/stm32image/stm32image.c ++++ b/tools/stm32image/stm32image.c +@@ -22,7 +22,7 @@ + #define VER_MINOR 1 + #define VER_VARIANT 0 + #define HEADER_VERSION_V1 0x1 +-#define TF_BINARY_TYPE 0x0 ++#define TF_BINARY_TYPE 0x10 + + /* Default option : bit0 => no signature */ + #define HEADER_DEFAULT_OPTION (__cpu_to_le32(0x00000001)) +-- +2.7.4 + diff --git a/recipes-bsp/trusted-firmware-a/tf-a-stm32mp/README.HOW_TO.txt b/recipes-bsp/trusted-firmware-a/tf-a-stm32mp/README.HOW_TO.txt new file mode 100644 index 0000000..ddb6dee --- /dev/null +++ b/recipes-bsp/trusted-firmware-a/tf-a-stm32mp/README.HOW_TO.txt @@ -0,0 +1,119 @@ +Compilation of TF-A (Trusted Firmware-A): +1. Pre-requisite +2. Initialise cross-compilation via SDK +3. Prepare tf-a source code +4. Management of tf-a source code +5. Compile tf-a source code +6. Update software on board + +1. Pre-requisite: +----------------- +OpenSTLinux SDK must be installed. + +For tf-a build you need to install: +- 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-cortexa9hf-neon-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 tf-a 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 tf-a 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 tf-a source code: +----------------------------------- +If you like to have a better management of change made on tf-a source, you +can use git: + $> cd + $> test -d .git || git init . && git add . && git commit -m "tf-a source code" && git gc + $> git checkout -b WORKING + $> for p in `ls -1 /*.patch`; do git am $p; done + +NB: you can use directly the source from the community: + URL: git://github.com/ARM-software/arm-trusted-firmware.git + Branch: ##GIT_BRANCH## + Revision: ##GIT_SRCREV## + + $> git clone git://github.com/ARM-software/arm-trusted-firmware.git -b ##GIT_BRANCH## + $> cd + $> git checkout -b WORKING ##GIT_SRCREV## + $> for p in `ls -1 /*.patch`; do git am $p; done + +5. Build tf-a source code: +-------------------------------- +To compile tf-a source code + $> cd + $> make -f $PWD/../Makefile.sdk all +or for a specific config : + $> make -f $PWD/../Makefile.sdk TFA_DEVICETREE=stm32mp157c-ev1 TF_A_CONFIG=trusted ELF_DEBUG_ENABLE='1' all + +NB: TFA_DEVICETREE flag must be set to switch to correct board configuration. + +6. Update software on board: +---------------------------- +6.1. partitioning of binaries: +----------------------------- +TF-A build provide a binary named "tf-a-*.stm32" which MUST be copied on a +dedicated partition named "fsbl1" + +6.2. Update via SDCARD: +----------------------- +Copy the binary (tf-a-*.stm32) on the dedicated partition, on SDCARD/USB disk +the partition "fsbl1" are the partition 1: + - SDCARD: /dev/mmcblkXp1 (where X is the instance number) + - SDCARD via USB reader: /dev/sdX1 (where X is the instance number) + $> dd if= of=/dev/ bs=1M conv=fdatasync + +FAQ: to found the partition associated to a specific label, just plug the +SDCARD/USB disk on your PC and call the following command: + $> ls -l /dev/disk/by-partlabel/ +total 0 +lrwxrwxrwx 1 root root 10 Jan 17 17:38 bootfs -> ../../mmcblk0p4 +lrwxrwxrwx 1 root root 10 Jan 17 17:38 fsbl1 -> ../../mmcblk0p1 ➔ FSBL (TF-A) +lrwxrwxrwx 1 root root 10 Jan 17 17:38 fsbl2 -> ../../mmcblk0p2 ➔ FSBL backup (TF-A backup – same content as FSBL) +lrwxrwxrwx 1 root root 10 Jan 17 17:38 rootfs -> ../../mmcblk0p5 +lrwxrwxrwx 1 root root 10 Jan 17 17:38 ssbl -> ../../mmcblk0p3 ➔ SSBL (U-Boot) +lrwxrwxrwx 1 root root 10 Jan 17 17:38 userfs -> ../../mmcblk0p6 + +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 put tf-a-*.stm32 on SDCARD/USB disk diff --git a/recipes-bsp/trusted-firmware-a/tf-a-stm32mp_2.0.bb b/recipes-bsp/trusted-firmware-a/tf-a-stm32mp_2.0.bb new file mode 100644 index 0000000..2dd9a44 --- /dev/null +++ b/recipes-bsp/trusted-firmware-a/tf-a-stm32mp_2.0.bb @@ -0,0 +1,33 @@ +SUMMARY = "Trusted Firmware-A for STM32MP1" +SECTION = "bootloaders" +LICENSE = "BSD-3-Clause" +LIC_FILES_CHKSUM = "file://license.rst;md5=e927e02bca647e14efd87e9e914b2443" + +SRC_URI = "https://github.com/ARM-software/arm-trusted-firmware/archive/v${PV}.tar.gz" +SRC_URI[md5sum] = "21038abbf572c273fa87d296bcd5dad2" +SRC_URI[sha256sum] = "7d699a1683bb7a5909de37b6eb91b6e38db32cd6fc5ae48a08eb0718d6504ae4" + +SRC_URI += " \ + file://0001-st-update-r1.patch \ + " + +PV = "2.0" + +S = "${WORKDIR}/arm-trusted-firmware-${PV}" + +require tf-a-stm32mp-common.inc + +# --------------------------------- +# Configure devupstream class usage +# --------------------------------- +BBCLASSEXTEND = "devupstream:target" + +SRC_URI_class-devupstream = "git://github.com/STMicroelectronics/arm-trusted-firmware.git;protocol=https;branch=v2.0-stm32mp" +SRCREV_class-devupstream = "d0233623681124a85b069f97a447d7edb1cc1c02" + +# --------------------------------- +# 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)}"