meta-st-stm32mp/recipes-bsp/trusted-firmware-a/tf-a-stm32mp/0001-st-update-v2.2-r2.0.0....

44919 lines
1.2 MiB
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

From 334224a627331b7278c8bc71c10b32da2db14194 Mon Sep 17 00:00:00 2001
From: Christophe Priouzeau <christophe.priouzeau@st.com>
Date: Tue, 9 Jun 2020 11:44:18 +0200
Subject: [PATCH] st-update-v2.2-r2.0.0
---
CONTRIBUTING.md | 30 +
Makefile | 2 +
bl1/aarch32/bl1_entrypoint.S | 9 +
bl2/aarch32/bl2_el3_exceptions.S | 9 +
bl2/aarch32/bl2_entrypoint.S | 9 +
bl2/bl2_image_load_v2.c | 14 +-
bl2u/aarch32/bl2u_entrypoint.S | 9 +
bl32/sp_min/aarch32/entrypoint.S | 9 +
common/aarch32/debug.S | 54 +-
common/bl_common.c | 2 +-
docs/devicetree/bindings/arm/secure.txt | 53 +
.../bindings/clock/st,stm32mp1-rcc.txt | 488 ++++
docs/devicetree/bindings/i2c/i2c-stm32.txt | 54 +
.../memory-controllers/st,stm32mp1-ddr.txt | 301 +++
docs/devicetree/bindings/mmc/mmci.txt | 72 +
.../bindings/mmc/st,stm32-sdmmc2.txt | 22 +
.../bindings/power/st,stm32mp1-pwr.txt | 42 +
docs/devicetree/bindings/power/st,stpmic1.txt | 94 +
.../bindings/reset/st,stm32mp1-rcc.txt | 6 +
docs/devicetree/bindings/rng/st,stm32-rng.txt | 23 +
.../bindings/serial/st,stm32-usart.txt | 88 +
.../bindings/soc/st,stm32-etzpc.txt | 56 +
.../bindings/soc/st,stm32-romem.txt | 74 +
.../bindings/soc/st,stm32-stgen.txt | 18 +
.../devicetree/bindings/soc/st,stm32-tamp.txt | 22 +
.../bindings/watchdog/st,stm32-iwdg.txt | 28 +
docs/getting_started/porting-guide.rst | 30 +
docs/plat/stm32mp1.rst | 23 +-
drivers/arm/tzc/tzc400.c | 151 +-
.../intel/soc/stratix10/io/s10_memmap_qspi.c | 18 +-
drivers/io/io_block.c | 60 +-
drivers/io/io_fip.c | 6 +-
drivers/io/io_memmap.c | 30 +-
drivers/io/io_mtd.c | 248 ++
drivers/io/io_semihosting.c | 6 +-
drivers/io/io_storage.c | 2 +-
drivers/mmc/mmc.c | 67 +-
drivers/mtd/nand/core.c | 118 +
drivers/mtd/nand/raw_nand.c | 446 ++++
drivers/mtd/nand/spi_nand.c | 320 +++
drivers/mtd/nor/spi_nor.c | 387 +++
drivers/mtd/spi-mem/spi_mem.c | 288 +++
drivers/renesas/rcar/io/io_emmcdrv.c | 20 +-
drivers/renesas/rcar/io/io_memdrv.c | 19 +-
drivers/st/bsec/{bsec.c => bsec2.c} | 460 ++--
drivers/st/clk/stm32mp1_calib.c | 529 +++++
drivers/st/clk/stm32mp1_clk.c | 2105 ++++++++++++++---
drivers/st/clk/stm32mp_clkfunc.c | 237 +-
drivers/st/crypto/stm32_hash.c | 15 +-
drivers/st/ddr/stm32mp1_ddr.c | 308 ++-
drivers/st/ddr/stm32mp1_ddr_helpers.c | 572 ++++-
drivers/st/ddr/stm32mp1_ram.c | 133 +-
drivers/st/etzpc/etzpc.c | 310 +++
drivers/st/fmc/stm32_fmc2_nand.c | 883 +++++++
drivers/st/gpio/stm32_gpio.c | 8 +
drivers/st/i2c/stm32_i2c.c | 441 +++-
drivers/st/io/io_mmc.c | 26 +-
drivers/st/io/io_programmer_st_usb.c | 381 +++
drivers/st/io/io_stm32image.c | 205 +-
drivers/st/iwdg/stm32_iwdg.c | 140 ++
drivers/st/mmc/stm32_sdmmc2.c | 127 +-
drivers/st/pmic/stm32mp_pmic.c | 522 +++-
drivers/st/pmic/stpmic1.c | 116 +-
.../st/regulator/stm32mp_dummy_regulator.c | 27 +
drivers/st/regulator/stm32mp_regulator.c | 38 +
drivers/st/reset/stm32mp1_reset.c | 44 +-
drivers/st/rng/stm32_rng.c | 188 ++
drivers/st/rtc/stm32_rtc.c | 479 ++++
drivers/st/scmi-msg/base.c | 202 ++
drivers/st/scmi-msg/base.h | 75 +
drivers/st/scmi-msg/clock.c | 388 +++
drivers/st/scmi-msg/clock.h | 150 ++
drivers/st/scmi-msg/common.h | 136 ++
drivers/st/scmi-msg/entry.c | 63 +
drivers/st/scmi-msg/reset_domain.c | 202 ++
drivers/st/scmi-msg/reset_domain.h | 122 +
drivers/st/scmi-msg/smt.c | 206 ++
drivers/st/spi/stm32_qspi.c | 507 ++++
drivers/st/tamper/stm32_tamp.c | 377 +++
drivers/st/timer/stm32_timer.c | 316 +++
drivers/st/uart/aarch32/stm32_console.S | 23 +-
drivers/st/uart/io_programmer_uart.c | 587 +++++
drivers/st/uart/stm32mp1xx_hal_uart.c | 801 +++++++
drivers/st/usb_dwc2/usb_dwc2.c | 859 +++++++
fdts/stm32mp15-ddr.dtsi | 2 +
fdts/stm32mp15-ddr3-1x4Gb-1066-binG.dtsi | 49 +-
fdts/stm32mp15-ddr3-2x4Gb-1066-binG.dtsi | 49 +-
fdts/stm32mp15-pinctrl.dtsi | 292 +++
fdts/stm32mp151.dtsi | 683 ++++++
fdts/stm32mp153.dtsi | 20 +
fdts/stm32mp157-pinctrl.dtsi | 348 ---
fdts/stm32mp157.dtsi | 7 +
fdts/stm32mp157a-avenger96.dts | 255 +-
fdts/stm32mp157a-dk1.dts | 308 +--
fdts/stm32mp157a-ed1.dts | 46 +
fdts/stm32mp157a-ev1.dts | 23 +
fdts/stm32mp157c-dk2.dts | 41 +-
fdts/stm32mp157c-ed1.dts | 316 +--
fdts/stm32mp157c-ev1.dts | 51 +-
fdts/stm32mp157c-security.dtsi | 41 -
fdts/stm32mp157c.dtsi | 366 ---
fdts/stm32mp157caa-pinctrl.dtsi | 90 -
fdts/stm32mp157cac-pinctrl.dtsi | 78 -
fdts/stm32mp157d-dk1.dts | 49 +
fdts/stm32mp157d-ed1.dts | 46 +
fdts/stm32mp157d-ev1.dts | 22 +
fdts/stm32mp157f-dk2.dts | 55 +
fdts/stm32mp157f-ed1.dts | 51 +
fdts/stm32mp157f-ev1.dts | 22 +
fdts/stm32mp15xa.dtsi | 13 +
fdts/stm32mp15xc.dtsi | 21 +
fdts/stm32mp15xd.dtsi | 19 +
fdts/stm32mp15xf.dtsi | 21 +
fdts/stm32mp15xx-dkx.dtsi | 470 ++++
fdts/stm32mp15xx-edx.dtsi | 479 ++++
fdts/stm32mp15xx-evx.dtsi | 71 +
fdts/stm32mp15xxaa-pinctrl.dtsi | 86 +
fdts/stm32mp15xxab-pinctrl.dtsi | 57 +
fdts/stm32mp15xxac-pinctrl.dtsi | 74 +
fdts/stm32mp15xxad-pinctrl.dtsi | 57 +
include/arch/aarch32/arch.h | 18 +-
include/arch/aarch32/arch_helpers.h | 4 +
include/arch/aarch32/el3_common_macros.S | 10 +-
include/arch/aarch64/arch.h | 6 +-
include/common/confine_array_index.h | 145 ++
include/common/speculation_barrier.h | 508 ++++
include/drivers/arm/tzc400.h | 39 +-
include/drivers/io/io_driver.h | 2 +-
include/drivers/io/io_mtd.h | 59 +
include/drivers/io/io_storage.h | 7 +-
include/drivers/mmc.h | 27 +-
include/drivers/nand.h | 55 +
include/drivers/raw_nand.h | 188 ++
include/drivers/spi_mem.h | 130 +
include/drivers/spi_nand.h | 49 +
include/drivers/spi_nor.h | 58 +
include/drivers/st/bsec.h | 152 +-
include/drivers/st/bsec2_reg.h | 98 +
include/drivers/st/etzpc.h | 32 +
include/drivers/st/io_programmer.h | 51 +
include/drivers/st/io_programmer_st_usb.h | 12 +
include/drivers/st/io_stm32image.h | 2 +-
include/drivers/st/io_uart.h | 12 +
include/drivers/st/scmi-msg.h | 207 ++
include/drivers/st/scmi.h | 29 +
include/drivers/st/stm32_fmc2_nand.h | 12 +
include/drivers/st/stm32_i2c.h | 41 +-
include/drivers/st/stm32_iwdg.h | 1 +
include/drivers/st/stm32_qspi.h | 12 +
include/drivers/st/stm32_rng.h | 13 +
include/drivers/st/stm32_rtc.h | 78 +
include/drivers/st/stm32_sdmmc2.h | 2 +
include/drivers/st/stm32_tamp.h | 163 ++
include/drivers/st/stm32_timer.h | 21 +
include/drivers/st/stm32mp1_calib.h | 20 +
include/drivers/st/stm32mp1_clk.h | 56 +-
include/drivers/st/stm32mp1_ddr.h | 7 +-
include/drivers/st/stm32mp1_ddr_helpers.h | 19 +-
include/drivers/st/stm32mp1_ddr_regs.h | 2 +
include/drivers/st/stm32mp1_pwr.h | 21 +-
include/drivers/st/stm32mp1_rcc.h | 29 +-
include/drivers/st/stm32mp1xx_hal.h | 204 ++
include/drivers/st/stm32mp1xx_hal_uart.h | 1586 +++++++++++++
include/drivers/st/stm32mp1xx_hal_uart_ex.h | 88 +
include/drivers/st/stm32mp_clkfunc.h | 16 +-
include/drivers/st/stm32mp_dummy_regulator.h | 14 +
include/drivers/st/stm32mp_pmic.h | 41 +-
include/drivers/st/stm32mp_regulator.h | 31 +
include/drivers/st/stm32mp_reset.h | 39 +-
include/drivers/st/stpmic1.h | 29 +-
include/drivers/st/usb_dwc2.h | 443 ++++
include/dt-bindings/clock/stm32mp1-clks.h | 35 +-
include/dt-bindings/pinctrl/stm32-pinfunc.h | 9 +-
include/dt-bindings/power/stm32mp1-power.h | 19 +
include/dt-bindings/reset/stm32mp1-resets.h | 13 +
include/dt-bindings/soc/st,stm32-etzpc.h | 107 +
include/lib/optee_utils.h | 1 +
include/lib/usb/usb_core.h | 353 +++
include/lib/usb/usb_st_dfu.h | 116 +
include/lib/utils_def.h | 19 +
.../lib/xlat_tables/xlat_tables_v2_helpers.h | 41 +-
include/plat/common/platform.h | 7 +-
lib/compiler-rt/builtins/arm/aeabi_ldivmod.S | 46 +
lib/compiler-rt/builtins/divdi3.c | 29 +
lib/compiler-rt/builtins/divmoddi4.c | 25 +
lib/compiler-rt/builtins/popcountdi2.c | 36 +
lib/compiler-rt/builtins/popcountsi2.c | 33 +
lib/compiler-rt/compiler-rt.mk | 14 +-
lib/optee/optee_utils.c | 30 +
lib/usb/usb_core.c | 733 ++++++
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/defaults.mk | 3 +
plat/common/aarch32/platform_helpers.S | 34 +
plat/common/plat_bl_common.c | 2 +-
plat/st/common/bl2_io_storage.c | 434 +++-
plat/st/common/include/stm32mp_auth.h | 19 -
plat/st/common/include/stm32mp_common.h | 37 +-
plat/st/common/include/stm32mp_dt.h | 20 +-
.../st/common/include/stm32mp_shres_helpers.h | 65 +-
plat/st/common/stm32_gic.c | 223 ++
plat/st/common/stm32mp_auth.c | 90 -
plat/st/common/stm32mp_common.c | 148 +-
plat/st/common/stm32mp_cot.c | 114 +
plat/st/common/stm32mp_crypto_lib.c | 174 ++
plat/st/common/stm32mp_dt.c | 432 +++-
plat/st/common/stm32mp_img_parser_lib.c | 75 +
plat/st/common/stm32mp_shres_helpers.c | 63 +
plat/st/common/stm32mp_trusted_boot.c | 76 +
plat/st/stm32mp1/bl2_plat_setup.c | 374 ++-
plat/st/stm32mp1/include/boot_api.h | 286 ++-
plat/st/stm32mp1/include/platform_def.h | 15 +
.../stm32mp1/include/stm32mp1_boot_device.h | 18 +
plat/st/stm32mp1/include/stm32mp1_context.h | 20 +-
plat/st/stm32mp1/include/stm32mp1_low_power.h | 19 +
.../stm32mp1/include/stm32mp1_power_config.h | 28 +
plat/st/stm32mp1/include/stm32mp1_private.h | 19 +-
.../include/stm32mp1_shared_resources.h | 132 ++
plat/st/stm32mp1/include/stm32mp1_smc.h | 148 +-
plat/st/stm32mp1/include/stm32mp1_usb_desc.h | 55 +
plat/st/stm32mp1/include/usb_ctx.h | 17 +
plat/st/stm32mp1/plat_image_load.c | 68 +-
plat/st/stm32mp1/platform.mk | 141 +-
plat/st/stm32mp1/services/bsec_svc.c | 466 +++-
plat/st/stm32mp1/services/low_power_svc.c | 22 +
plat/st/stm32mp1/services/low_power_svc.h | 14 +
plat/st/stm32mp1/services/pwr_svc.c | 102 +
plat/st/stm32mp1/services/pwr_svc.h | 12 +
plat/st/stm32mp1/services/rcc_svc.c | 172 ++
plat/st/stm32mp1/services/rcc_svc.h | 14 +
.../st/stm32mp1/services/stm32mp1_svc_setup.c | 38 +-
plat/st/stm32mp1/sp_min/sp_min-stm32mp1.mk | 24 +-
plat/st/stm32mp1/sp_min/sp_min_setup.c | 318 ++-
plat/st/stm32mp1/stm32mp1_boot_device.c | 168 ++
plat/st/stm32mp1/stm32mp1_context.c | 391 ++-
plat/st/stm32mp1/stm32mp1_dbgmcu.c | 36 +-
plat/st/stm32mp1/stm32mp1_def.h | 304 ++-
plat/st/stm32mp1/stm32mp1_gic.c | 92 -
plat/st/stm32mp1/stm32mp1_helper.S | 220 +-
plat/st/stm32mp1/stm32mp1_low_power.c | 346 +++
plat/st/stm32mp1/stm32mp1_pm.c | 96 +-
plat/st/stm32mp1/stm32mp1_power_config.c | 187 ++
plat/st/stm32mp1/stm32mp1_private.c | 534 ++++-
plat/st/stm32mp1/stm32mp1_scmi.c | 582 +++++
plat/st/stm32mp1/stm32mp1_security.c | 7 +-
plat/st/stm32mp1/stm32mp1_shared_resources.c | 743 ++++++
plat/st/stm32mp1/stm32mp1_syscfg.c | 63 +-
plat/st/stm32mp1/stm32mp1_usb_desc.c | 418 ++++
tools/stm32image/stm32image.c | 46 +-
252 files changed, 34319 insertions(+), 3715 deletions(-)
create mode 100644 CONTRIBUTING.md
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/memory-controllers/st,stm32mp1-ddr.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/io/io_mtd.c
create mode 100644 drivers/mtd/nand/core.c
create mode 100644 drivers/mtd/nand/raw_nand.c
create mode 100644 drivers/mtd/nand/spi_nand.c
create mode 100644 drivers/mtd/nor/spi_nor.c
create mode 100644 drivers/mtd/spi-mem/spi_mem.c
rename drivers/st/bsec/{bsec.c => bsec2.c} (65%)
create mode 100644 drivers/st/clk/stm32mp1_calib.c
create mode 100644 drivers/st/etzpc/etzpc.c
create mode 100644 drivers/st/fmc/stm32_fmc2_nand.c
create mode 100644 drivers/st/io/io_programmer_st_usb.c
create mode 100644 drivers/st/regulator/stm32mp_dummy_regulator.c
create mode 100644 drivers/st/regulator/stm32mp_regulator.c
create mode 100644 drivers/st/rng/stm32_rng.c
create mode 100644 drivers/st/rtc/stm32_rtc.c
create mode 100644 drivers/st/scmi-msg/base.c
create mode 100644 drivers/st/scmi-msg/base.h
create mode 100644 drivers/st/scmi-msg/clock.c
create mode 100644 drivers/st/scmi-msg/clock.h
create mode 100644 drivers/st/scmi-msg/common.h
create mode 100644 drivers/st/scmi-msg/entry.c
create mode 100644 drivers/st/scmi-msg/reset_domain.c
create mode 100644 drivers/st/scmi-msg/reset_domain.h
create mode 100644 drivers/st/scmi-msg/smt.c
create mode 100644 drivers/st/spi/stm32_qspi.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-pinctrl.dtsi
create mode 100644 fdts/stm32mp151.dtsi
create mode 100644 fdts/stm32mp153.dtsi
delete mode 100644 fdts/stm32mp157-pinctrl.dtsi
create mode 100644 fdts/stm32mp157.dtsi
create mode 100644 fdts/stm32mp157a-ed1.dts
create mode 100644 fdts/stm32mp157a-ev1.dts
delete mode 100644 fdts/stm32mp157c-security.dtsi
delete mode 100644 fdts/stm32mp157c.dtsi
delete mode 100644 fdts/stm32mp157caa-pinctrl.dtsi
delete mode 100644 fdts/stm32mp157cac-pinctrl.dtsi
create mode 100644 fdts/stm32mp157d-dk1.dts
create mode 100644 fdts/stm32mp157d-ed1.dts
create mode 100644 fdts/stm32mp157d-ev1.dts
create mode 100644 fdts/stm32mp157f-dk2.dts
create mode 100644 fdts/stm32mp157f-ed1.dts
create mode 100644 fdts/stm32mp157f-ev1.dts
create mode 100644 fdts/stm32mp15xa.dtsi
create mode 100644 fdts/stm32mp15xc.dtsi
create mode 100644 fdts/stm32mp15xd.dtsi
create mode 100644 fdts/stm32mp15xf.dtsi
create mode 100644 fdts/stm32mp15xx-dkx.dtsi
create mode 100644 fdts/stm32mp15xx-edx.dtsi
create mode 100644 fdts/stm32mp15xx-evx.dtsi
create mode 100644 fdts/stm32mp15xxaa-pinctrl.dtsi
create mode 100644 fdts/stm32mp15xxab-pinctrl.dtsi
create mode 100644 fdts/stm32mp15xxac-pinctrl.dtsi
create mode 100644 fdts/stm32mp15xxad-pinctrl.dtsi
create mode 100644 include/common/confine_array_index.h
create mode 100644 include/common/speculation_barrier.h
create mode 100644 include/drivers/io/io_mtd.h
create mode 100644 include/drivers/nand.h
create mode 100644 include/drivers/raw_nand.h
create mode 100644 include/drivers/spi_mem.h
create mode 100644 include/drivers/spi_nand.h
create mode 100644 include/drivers/spi_nor.h
create mode 100644 include/drivers/st/bsec2_reg.h
create mode 100644 include/drivers/st/etzpc.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_uart.h
create mode 100644 include/drivers/st/scmi-msg.h
create mode 100644 include/drivers/st/scmi.h
create mode 100644 include/drivers/st/stm32_fmc2_nand.h
create mode 100644 include/drivers/st/stm32_qspi.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_tamp.h
create mode 100644 include/drivers/st/stm32_timer.h
create mode 100644 include/drivers/st/stm32mp1_calib.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_dummy_regulator.h
create mode 100644 include/drivers/st/stm32mp_regulator.h
create mode 100644 include/drivers/st/usb_dwc2.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/arm/aeabi_ldivmod.S
create mode 100644 lib/compiler-rt/builtins/divdi3.c
create mode 100644 lib/compiler-rt/builtins/divmoddi4.c
create mode 100644 lib/compiler-rt/builtins/popcountdi2.c
create mode 100644 lib/compiler-rt/builtins/popcountsi2.c
create mode 100644 lib/usb/usb_core.c
create mode 100644 lib/usb/usb_st_dfu.c
delete mode 100644 plat/st/common/include/stm32mp_auth.h
create mode 100644 plat/st/common/stm32_gic.c
delete mode 100644 plat/st/common/stm32mp_auth.c
create mode 100644 plat/st/common/stm32mp_cot.c
create mode 100644 plat/st/common/stm32mp_crypto_lib.c
create mode 100644 plat/st/common/stm32mp_img_parser_lib.c
create mode 100644 plat/st/common/stm32mp_shres_helpers.c
create mode 100644 plat/st/common/stm32mp_trusted_boot.c
create mode 100644 plat/st/stm32mp1/include/stm32mp1_boot_device.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_usb_desc.h
create mode 100644 plat/st/stm32mp1/include/usb_ctx.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/stm32mp1_boot_device.c
delete mode 100644 plat/st/stm32mp1/stm32mp1_gic.c
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_scmi.c
create mode 100644 plat/st/stm32mp1/stm32mp1_shared_resources.c
create mode 100644 plat/st/stm32mp1/stm32mp1_usb_desc.c
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 000000000..3d1bacd78
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,30 @@
+# Contributing guide
+
+This document serves as a checklist before contributing to this repository. It includes links to read up on if topics are unclear to you.
+
+This guide mainly focuses on the proper use of Git.
+
+## 1. Issues
+
+STM32MPU projects do not activate "Github issues" feature for the time being. If you need to report an issue or question about this project deliverables, you can report them using [ ST Support Center ](https://my.st.com/ols#/ols/newrequest) or [ ST Community MPU Forum ](https://community.st.com/s/topic/0TO0X0000003u2AWAQ/stm32-mpus).
+
+## 2. Pull Requests
+
+STMicrolectronics is happy to receive contributions from the community, based on an initial Contributor License Agreement (CLA) procedure.
+
+* If you are an individual writing original source code and you are sure **you own the intellectual property**, then you need to sign an Individual CLA (https://cla.st.com).
+* If you work for a company that wants also to allow you to contribute with your work, your company needs to provide a Corporate CLA (https://cla.st.com) mentioning your GitHub account name.
+* If you are not sure that a CLA (Individual or Corporate) has been signed for your GitHub account you can check here (https://cla.st.com).
+
+Please note that:
+* The Corporate CLA will always take precedence over the Individual CLA.
+* One CLA submission is sufficient, for any project proposed by STMicroelectronics.
+
+__How to proceed__
+
+* We recommend to fork the project in your GitHub account to further develop your contribution. Please use the latest commit version.
+* Please, submit one Pull Request for one new feature or proposal. This will ease the analysis and final merge if accepted.
+
+__Note__
+
+Merge will not be done directly in GitHub but it will need first to follow internal integration process before public deliver in a standard release. The Pull request will stay open until it is merged and delivered.
diff --git a/Makefile b/Makefile
index 721246d51..864eda7fc 100644
--- a/Makefile
+++ b/Makefile
@@ -700,6 +700,7 @@ $(eval $(call assert_boolean,BL2_AT_EL3))
$(eval $(call assert_boolean,BL2_IN_XIP_MEM))
$(eval $(call assert_boolean,BL2_INV_DCACHE))
$(eval $(call assert_boolean,USE_SPINLOCK_CAS))
+$(eval $(call assert_boolean,AARCH32_EXCEPTION_DEBUG))
$(eval $(call assert_numeric,ARM_ARCH_MAJOR))
$(eval $(call assert_numeric,ARM_ARCH_MINOR))
@@ -766,6 +767,7 @@ $(eval $(call add_define,BL2_AT_EL3))
$(eval $(call add_define,BL2_IN_XIP_MEM))
$(eval $(call add_define,BL2_INV_DCACHE))
$(eval $(call add_define,USE_SPINLOCK_CAS))
+$(eval $(call add_define,AARCH32_EXCEPTION_DEBUG))
ifeq (${SANITIZE_UB},trap)
$(eval $(call add_define,MONITOR_TRAPS))
diff --git a/bl1/aarch32/bl1_entrypoint.S b/bl1/aarch32/bl1_entrypoint.S
index 6a155660b..e7e72049c 100644
--- a/bl1/aarch32/bl1_entrypoint.S
+++ b/bl1/aarch32/bl1_entrypoint.S
@@ -21,10 +21,19 @@
*/
vector_base bl1_vector_table
b bl1_entrypoint
+#if AARCH32_EXCEPTION_DEBUG
+ b report_undef_inst /* Undef */
+#else
b report_exception /* Undef */
+#endif
b bl1_aarch32_smc_handler /* SMC 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_el3_exceptions.S b/bl2/aarch32/bl2_el3_exceptions.S
index 087b6656d..dff4e36a4 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 102fd2f51..bfd721ca1 100644
--- a/bl2/aarch32/bl2_entrypoint.S
+++ b/bl2/aarch32/bl2_entrypoint.S
@@ -14,10 +14,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 dd53e1d2b..e89033b96 100644
--- a/bl2/bl2_image_load_v2.c
+++ b/bl2/bl2_image_load_v2.c
@@ -71,17 +71,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/bl2u/aarch32/bl2u_entrypoint.S b/bl2u/aarch32/bl2u_entrypoint.S
index 6391f537c..426176d98 100644
--- a/bl2u/aarch32/bl2u_entrypoint.S
+++ b/bl2u/aarch32/bl2u_entrypoint.S
@@ -14,10 +14,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 0a684754c..c4a6e8e83 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 f50635691..a058645e3 100644
--- a/common/aarch32/debug.S
+++ b/common/aarch32/debug.S
@@ -7,9 +7,16 @@
#include <arch.h>
#include <asm_macros.S>
+ .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/common/bl_common.c b/common/bl_common.c
index e6f98029e..7f2342499 100644
--- a/common/bl_common.c
+++ b/common/bl_common.c
@@ -215,7 +215,7 @@ int load_auth_image(unsigned int image_id, image_info_t *image_data)
do {
err = load_auth_image_internal(image_id, image_data, 0);
- } while ((err != 0) && (plat_try_next_boot_source() != 0));
+ } while ((err != 0) && (plat_try_next_boot_source(image_id) != 0));
return err;
}
diff --git a/docs/devicetree/bindings/arm/secure.txt b/docs/devicetree/bindings/arm/secure.txt
new file mode 100644
index 000000000..e31303fb2
--- /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 000000000..a082706ee
--- /dev/null
+++ b/docs/devicetree/bindings/clock/st,stm32mp1-rcc.txt
@@ -0,0 +1,488 @@
+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.
+- secure-interrupts: Should contain a interrupt line to the wake-up of
+ processor (CSTOP).
+- secure-status: Relates to RCC TZ_ENABLE configuration to restrict RCC access.
+
+Example:
+ rcc: rcc@50000000 {
+ compatible = "st,stm32mp1-rcc", "syscon";
+ reg = <0x50000000 0x1000>;
+ #clock-cells = <1>;
+ #reset-cells = <1>;
+ interrupts = <GIC_SPI 5 IRQ_TYPE_LEVEL_HIGH>;
+ secure-interrupts = <GIC_SPI 145 IRQ_TYPE_LEVEL_HIGH>;
+ };
+
+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
+==========================================================
+
+- st,clksrc : The clock sources configuration array in a platform specific
+ order.
+
+ 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_<NAME>_<SOURCE>
+ 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
+===============================================
+
+- st,clkdiv : The clock main dividers value specified in an array
+ in a platform specific order.
+
+ When used, it shall describe the whole clock dividers tree.
+
+ 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*/
+ >;
+
+Optional Properties:
+Defining peripherals kernel clock tree distribution with property st,pkcs
+=========================================================================
+
+- st,pkcs : used to configure the peripherals kernel clock selection.
+
+ The property is a list of peripheral kernel clock source identifiers defined
+ by macros CLK_<KERNEL-CLOCK>_<PARENT-CLOCK> 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
+ >;
+
+Defining peripheral PLL frequencies
+========================================================
+
+- children for a PLL static configuration with "st,stm32mp1-pll" compatible
+
+ Each PLL children nodes for PLL1 to PLL4 (see ref manual for details)
+ are listed with associated reg 0 to 3.
+ PLLx is off when the associated node is absent or deactivated.
+
+ Here are the available properties for each PLL node:
+ - compatible: should be "st,stm32mp1-pll"
+
+ - reg: index of the pll instance
+
+ - 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 {
+ compatible = "st,stm32mp1-pll";
+ reg = <0>;
+ cfg = <1 53 0 0 0 1>;
+ frac = <0x810>;
+ };
+ st,pll@1 {
+ compatible = "st,stm32mp1-pll";
+ reg = <1>;
+ cfg = <1 43 1 0 0 PQR(0,1,1)>;
+ csg = <10 20 1>;
+ };
+ st,pll@2 {
+ compatible = "st,stm32mp1-pll";
+ reg = <2>;
+ cfg = <2 85 3 13 3 0>;
+ csg = <10 20 SSCG_MODE_CENTER_SPREAD>;
+ };
+ st,pll@3 {
+ compatible = "st,stm32mp1-pll";
+ reg = <3>;
+ cfg = <2 78 4 7 9 3>;
+ };
+
+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 and not disabled
+ (node with status="disabled"),
+ - disable HSI oscillator if the node is absent (always activated by bootrom)
+ and not disabled (node with status="disabled").
+
+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 = <LSEDRV_LOWEST>;
+ };
+ };
+
+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 secure 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 = <GIC_SPI 144 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 145 IRQ_TYPE_LEVEL_HIGH>;
+ secure-interrupt-names = "mcu_sev", "wakeup";
+ };
+
+
+Example of clock tree initialization
+====================================
+
+/ {
+ clocks {
+ clk_hse: clk-hse {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <24000000>;
+ st,digbypass;
+ };
+
+ clk_hsi: clk-hsi {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <64000000>;
+ };
+
+ clk_lse: clk-lse {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <32768>;
+ };
+
+ clk_lsi: clk-lsi {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <32000>;
+ };
+
+ clk_csi: clk-csi {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <4000000>;
+ };
+ };
+
+ soc {
+
+ rcc: rcc@50000000 {
+ compatible = "st,stm32mp1-rcc", "syscon";
+ reg = <0x50000000 0x1000>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ #clock-cells = <1>;
+ #reset-cells = <1>;
+ interrupts = <GIC_SPI 5 IRQ_TYPE_LEVEL_HIGH>;
+ secure-interrupts = <GIC_SPI 145 IRQ_TYPE_LEVEL_HIGH>;
+ secure-interrupt-names = "wakeup";
+ secure-status = "okay";
+
+ 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 {
+ compatible = "st,stm32mp1-pll";
+ reg = <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 {
+ compatible = "st,stm32mp1-pll";
+ reg = <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 {
+ compatible = "st,stm32mp1-pll";
+ reg = <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 {
+ compatible = "st,stm32mp1-pll";
+ reg = <3>;
+ cfg = <3 98 5 7 7 PQR(1,1,1)>;
+ };
+ };
+ };
+};
diff --git a/docs/devicetree/bindings/i2c/i2c-stm32.txt b/docs/devicetree/bindings/i2c/i2c-stm32.txt
new file mode 100644
index 000000000..68aefa6dc
--- /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/memory-controllers/st,stm32mp1-ddr.txt b/docs/devicetree/bindings/memory-controllers/st,stm32mp1-ddr.txt
new file mode 100644
index 000000000..ac6a7df43
--- /dev/null
+++ b/docs/devicetree/bindings/memory-controllers/st,stm32mp1-ddr.txt
@@ -0,0 +1,301 @@
+ST,stm32mp1 DDR3/LPDDR2/LPDDR3 Controller (DDRCTRL and DDRPHYC)
+
+--------------------
+Required properties:
+--------------------
+- compatible : Should be "st,stm32mp1-ddr"
+- reg : controleur (DDRCTRL) and phy (DDRPHYC) base address
+- clocks : controller clocks handle
+- clock-names : associated controller clock names
+ the "ddrphyc" clock is used to check the DDR frequency
+ at phy level according the expected value in "mem-speed" field
+
+the next attributes are DDR parameters, they are generated by DDR tools
+included in STM32 Cube tool
+
+info attributes:
+----------------
+- st,mem-name : name for DDR configuration, simple string for information
+- st,mem-speed : DDR expected speed for the setting in kHz
+- st,mem-size : DDR mem size in byte
+
+
+controlleur attributes:
+-----------------------
+- st,ctl-reg : controleur values depending of the DDR type
+ (DDR3/LPDDR2/LPDDR3)
+ for STM32MP15x: 25 values are requested in this order
+ MSTR
+ MRCTRL0
+ MRCTRL1
+ DERATEEN
+ DERATEINT
+ PWRCTL
+ PWRTMG
+ HWLPCTL
+ RFSHCTL0
+ RFSHCTL3
+ CRCPARCTL0
+ ZQCTL0
+ DFITMG0
+ DFITMG1
+ DFILPCFG0
+ DFIUPD0
+ DFIUPD1
+ DFIUPD2
+ DFIPHYMSTR
+ ODTMAP
+ DBG0
+ DBG1
+ DBGCMD
+ POISONCFG
+ PCCFG
+
+- st,ctl-timing : controleur values depending of frequency and timing parameter
+ of DDR
+ for STM32MP15x: 12 values are requested in this order
+ RFSHTMG
+ DRAMTMG0
+ DRAMTMG1
+ DRAMTMG2
+ DRAMTMG3
+ DRAMTMG4
+ DRAMTMG5
+ DRAMTMG6
+ DRAMTMG7
+ DRAMTMG8
+ DRAMTMG14
+ ODTCFG
+
+- st,ctl-map : controleur values depending of address mapping
+ for STM32MP15x: 9 values are requested in this order
+ ADDRMAP1
+ ADDRMAP2
+ ADDRMAP3
+ ADDRMAP4
+ ADDRMAP5
+ ADDRMAP6
+ ADDRMAP9
+ ADDRMAP10
+ ADDRMAP11
+
+- st,ctl-perf : controleur values depending of performance and scheduling
+ for STM32MP15x: 17 values are requested in this order
+ SCHED
+ SCHED1
+ PERFHPR1
+ PERFLPR1
+ PERFWR1
+ PCFGR_0
+ PCFGW_0
+ PCFGQOS0_0
+ PCFGQOS1_0
+ PCFGWQOS0_0
+ PCFGWQOS1_0
+ PCFGR_1
+ PCFGW_1
+ PCFGQOS0_1
+ PCFGQOS1_1
+ PCFGWQOS0_1
+ PCFGWQOS1_1
+
+phyc attributes:
+----------------
+- st,phy-reg : phy values depending of the DDR type (DDR3/LPDDR2/LPDDR3)
+ for STM32MP15x: 11 values are requested in this order
+ PGCR
+ ACIOCR
+ DXCCR
+ DSGCR
+ DCR
+ ODTCR
+ ZQ0CR1
+ DX0GCR
+ DX1GCR
+ DX2GCR
+ DX3GCR
+
+- st,phy-timing : phy values depending of frequency and timing parameter of DDR
+ for STM32MP15x: 10 values are requested in this order
+ PTR0
+ PTR1
+ PTR2
+ DTPR0
+ DTPR1
+ DTPR2
+ MR0
+ MR1
+ MR2
+ MR3
+
+- st,phy-cal : phy cal depending of calibration or tuning of DDR
+ This parameter is optional; when it is absent the built-in PHY
+ calibration is done.
+ for STM32MP15x: 12 values are requested in this order
+ DX0DLLCR
+ DX0DQTR
+ DX0DQSTR
+ DX1DLLCR
+ DX1DQTR
+ DX1DQSTR
+ DX2DLLCR
+ DX2DQTR
+ DX2DQSTR
+ DX3DLLCR
+ DX3DQTR
+ DX3DQSTR
+
+Example:
+
+/ {
+ soc {
+ u-boot,dm-spl;
+
+ ddr: ddr@0x5A003000{
+ u-boot,dm-spl;
+ u-boot,dm-pre-reloc;
+
+ compatible = "st,stm32mp1-ddr";
+
+ reg = <0x5A003000 0x550
+ 0x5A004000 0x234>;
+
+ clocks = <&rcc_clk AXIDCG>,
+ <&rcc_clk DDRC1>,
+ <&rcc_clk DDRC2>,
+ <&rcc_clk DDRPHYC>,
+ <&rcc_clk DDRCAPB>,
+ <&rcc_clk DDRPHYCAPB>;
+
+ clock-names = "axidcg",
+ "ddrc1",
+ "ddrc2",
+ "ddrphyc",
+ "ddrcapb",
+ "ddrphycapb";
+
+ st,mem-name = "DDR3 2x4Gb 533MHz";
+ st,mem-speed = <533000>;
+ st,mem-size = <0x40000000>;
+
+ st,ctl-reg = <
+ 0x00040401 /*MSTR*/
+ 0x00000010 /*MRCTRL0*/
+ 0x00000000 /*MRCTRL1*/
+ 0x00000000 /*DERATEEN*/
+ 0x00800000 /*DERATEINT*/
+ 0x00000000 /*PWRCTL*/
+ 0x00400010 /*PWRTMG*/
+ 0x00000000 /*HWLPCTL*/
+ 0x00210000 /*RFSHCTL0*/
+ 0x00000000 /*RFSHCTL3*/
+ 0x00000000 /*CRCPARCTL0*/
+ 0xC2000040 /*ZQCTL0*/
+ 0x02050105 /*DFITMG0*/
+ 0x00000202 /*DFITMG1*/
+ 0x07000000 /*DFILPCFG0*/
+ 0xC0400003 /*DFIUPD0*/
+ 0x00000000 /*DFIUPD1*/
+ 0x00000000 /*DFIUPD2*/
+ 0x00000000 /*DFIPHYMSTR*/
+ 0x00000001 /*ODTMAP*/
+ 0x00000000 /*DBG0*/
+ 0x00000000 /*DBG1*/
+ 0x00000000 /*DBGCMD*/
+ 0x00000000 /*POISONCFG*/
+ 0x00000010 /*PCCFG*/
+ >;
+
+ st,ctl-timing = <
+ 0x0080008A /*RFSHTMG*/
+ 0x121B2414 /*DRAMTMG0*/
+ 0x000D041B /*DRAMTMG1*/
+ 0x0607080E /*DRAMTMG2*/
+ 0x0050400C /*DRAMTMG3*/
+ 0x07040407 /*DRAMTMG4*/
+ 0x06060303 /*DRAMTMG5*/
+ 0x02020002 /*DRAMTMG6*/
+ 0x00000202 /*DRAMTMG7*/
+ 0x00001005 /*DRAMTMG8*/
+ 0x000D041B /*DRAMTMG1*/4
+ 0x06000600 /*ODTCFG*/
+ >;
+
+ st,ctl-map = <
+ 0x00080808 /*ADDRMAP1*/
+ 0x00000000 /*ADDRMAP2*/
+ 0x00000000 /*ADDRMAP3*/
+ 0x00001F1F /*ADDRMAP4*/
+ 0x07070707 /*ADDRMAP5*/
+ 0x0F070707 /*ADDRMAP6*/
+ 0x00000000 /*ADDRMAP9*/
+ 0x00000000 /*ADDRMAP10*/
+ 0x00000000 /*ADDRMAP11*/
+ >;
+
+ st,ctl-perf = <
+ 0x00001201 /*SCHED*/
+ 0x00001201 /*SCHED*/1
+ 0x01000001 /*PERFHPR1*/
+ 0x08000200 /*PERFLPR1*/
+ 0x08000400 /*PERFWR1*/
+ 0x00010000 /*PCFGR_0*/
+ 0x00000000 /*PCFGW_0*/
+ 0x02100B03 /*PCFGQOS0_0*/
+ 0x00800100 /*PCFGQOS1_0*/
+ 0x01100B03 /*PCFGWQOS0_0*/
+ 0x01000200 /*PCFGWQOS1_0*/
+ 0x00010000 /*PCFGR_1*/
+ 0x00000000 /*PCFGW_1*/
+ 0x02100B03 /*PCFGQOS0_1*/
+ 0x00800000 /*PCFGQOS1_1*/
+ 0x01100B03 /*PCFGWQOS0_1*/
+ 0x01000200 /*PCFGWQOS1_1*/
+ >;
+
+ st,phy-reg = <
+ 0x01442E02 /*PGCR*/
+ 0x10400812 /*ACIOCR*/
+ 0x00000C40 /*DXCCR*/
+ 0xF200001F /*DSGCR*/
+ 0x0000000B /*DCR*/
+ 0x00010000 /*ODTCR*/
+ 0x0000007B /*ZQ0CR1*/
+ 0x0000CE81 /*DX0GCR*/
+ 0x0000CE81 /*DX1GCR*/
+ 0x0000CE81 /*DX2GCR*/
+ 0x0000CE81 /*DX3GCR*/
+ >;
+
+ st,phy-timing = <
+ 0x0022A41B /*PTR0*/
+ 0x047C0740 /*PTR1*/
+ 0x042D9C80 /*PTR2*/
+ 0x369477D0 /*DTPR0*/
+ 0x098A00D8 /*DTPR1*/
+ 0x10023600 /*DTPR2*/
+ 0x00000830 /*MR0*/
+ 0x00000000 /*MR1*/
+ 0x00000208 /*MR2*/
+ 0x00000000 /*MR3*/
+ >;
+
+ st,phy-cal = <
+ 0x40000000 /*DX0DLLCR*/
+ 0xFFFFFFFF /*DX0DQTR*/
+ 0x3DB02000 /*DX0DQSTR*/
+ 0x40000000 /*DX1DLLCR*/
+ 0xFFFFFFFF /*DX1DQTR*/
+ 0x3DB02000 /*DX1DQSTR*/
+ 0x40000000 /*DX2DLLCR*/
+ 0xFFFFFFFF /*DX2DQTR*/
+ 0x3DB02000 /*DX2DQSTR*/
+ 0x40000000 /*DX3DLLCR*/
+ 0xFFFFFFFF /*DX3DQTR*/
+ 0x3DB02000 /*DX3DQSTR*/
+ >;
+
+ status = "okay";
+ };
+ };
+};
diff --git a/docs/devicetree/bindings/mmc/mmci.txt b/docs/devicetree/bindings/mmc/mmci.txt
new file mode 100644
index 000000000..6d3c626e0
--- /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 000000000..51576a384
--- /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 000000000..bd56e1946
--- /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 = <STM32_PM_CSTOP_ALLOW_STANDBY_DDR_OFF>;
+};
diff --git a/docs/devicetree/bindings/power/st,stpmic1.txt b/docs/devicetree/bindings/power/st,stpmic1.txt
new file mode 100644
index 000000000..83307d23b
--- /dev/null
+++ b/docs/devicetree/bindings/power/st,stpmic1.txt
@@ -0,0 +1,94 @@
+* 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
+
+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>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+
+ onkey {
+ compatible = "st,stpmic1-onkey";
+ interrupts = <IT_PONKEY_F 0>,<IT_PONKEY_R 1>;
+ 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 000000000..b4edaf7c7
--- /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 000000000..3c613d791
--- /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 000000000..08b499045
--- /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 000000000..a2ac263ce
--- /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 000000000..c430fb84d
--- /dev/null
+++ b/docs/devicetree/bindings/soc/st,stm32-romem.txt
@@ -0,0 +1,74 @@
+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.
+
+Optional-properties:
+- "st,non-secure-otp" specifies that the OTP can be accessed by non-secure
+ world through secure world services. Only useful for upper OTPs. This
+ property mandates 32-bit granularity of the related nvmem area, that is
+ offset and length are both multiple of 4.
+
+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>;
+ };
+ ...
+ };
+
+Example on stm32mp1:
+ bsec: nvmem@5c005000 {
+ ...
+ mac_addr: mac_addr@e4 {
+ reg = <0xe4 0x8>;
+ st,non-secure-otp;
+ };
+ ...
+ };
+
+The nvmem_layout node gathers all nvmem platform-dependent layout information,
+including OTP names and phandles, in order to allow easy accesses for data
+consumers, using pre-defined string in nvmem-cell-names property.
+
+Required properties:
+- compatible: "st,stm32-nvmem-layout"
+- nvmem-cells and nvmem-cell-names, as described in nvmem.txt.
+
+Example on stm32mp1:
+ nvmem_layout: nvmem_layout@0 {
+ compatible = "st,stm32-nvmem-layout";
+ nvmem-cells = <&part_number_otp>,
+ ...
+ ;
+ nvmem-cell-names = "part_number_otp",
+ ...
+ ;
+ };
+
+ bsec: nvmem@5c005000 {
+ ...
+ part_number_otp: part_number_otp@4 {
+ reg = <0x4 0x1>;
+ };
+ ...
+ };
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 000000000..dbd962ebc
--- /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 000000000..4d21c6b8a
--- /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 000000000..2453603a1
--- /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/getting_started/porting-guide.rst b/docs/getting_started/porting-guide.rst
index 9cca75e92..e2db1bf9a 100644
--- a/docs/getting_started/porting-guide.rst
+++ b/docs/getting_started/porting-guide.rst
@@ -481,6 +481,36 @@ constants must also be defined:
Defines the total size of the physical address space in bytes. For example,
for a 32 bit physical address space, this value should be ``(1ULL << 32)``.
+If the platform port uses the translation table library code, the following
+constants can be defined:
+
+- **#define : PLAT\_BASE\_XLAT\_BASE**
+
+ Defines the identity map base address of the translation level 1 base table
+ which memory location is common to all BLs. This feature is useful only for
+ AArch32 only architectures where all BL do share the very same MMU resources
+ since all core modes rely on a single MMU support contrary to AArch64 aware
+ architectures where EL3 and secure EL1 each rely on their specific MMU
+ configuration resources.
+
+- **#define : PLAT\_BASE\_XLAT\_SIZE**
+
+ Defines the byte size reserved for translation level 1 base table
+ **PLAT\_BASE\_XLAT\_BASE**.
+
+- **#define : PLAT\_XLAT\_BASE**
+
+ Defines the identity map base address of the translation table array which
+ is common to all BLs. This feature is useful only for AArch32 only
+ architectures where all BL do share the very same MMU resources since
+ all core modes rely on a single MMU support contrary to AArch64 aware
+ architectures where EL3 and secure EL1 each rely on their specific MMU
+ configuration resources.
+
+- **#define : PLAT\_XLAT\_SIZE**
+
+ Defines the byte size reserved for translation tables **PLAT\__XLAT\_BASE**.
+
If the platform port uses the IO storage framework, the following constants
must also be defined:
diff --git a/docs/plat/stm32mp1.rst b/docs/plat/stm32mp1.rst
index 88251d6af..2c372a6a3 100644
--- a/docs/plat/stm32mp1.rst
+++ b/docs/plat/stm32mp1.rst
@@ -76,21 +76,34 @@ ROM code -> BL2 (compiled with BL2_AT_EL3) -> OP-TEE -> BL33 (U-Boot)
Build Instructions
------------------
+Boot media(s) supported by BL2 must be specified in the build command.
+Available storage medias are:
+- ``STM32MP_SDMMC``
+- ``STM32MP_EMMC``
+- ``STM32MP_RAW_NAND``
+- ``STM32MP_SPI_NAND``
+- ``STM32MP_SPI_NOR``
-To build with SP_min:
+To build with SP_min and support for all bootable devices:
.. code:: bash
- make CROSS_COMPILE=arm-linux-gnueabihf- PLAT=stm32mp1 ARCH=aarch32 ARM_ARCH_MAJOR=7 AARCH32_SP=sp_min DTB_FILE_NAME=stm32mp157c-ev1.dtb
+ make CROSS_COMPILE=arm-linux-gnueabihf- PLAT=stm32mp1 ARCH=aarch32 ARM_ARCH_MAJOR=7 AARCH32_SP=sp_min STM32MP_SDMMC=1 STM32MP_EMMC=1 STM32MP_RAW_NAND=1 STM32MP_SPI_NAND=1
+ STM32MP_SPI_NOR=1 DTB_FILE_NAME=stm32mp157c-ev1.dtb
cd <u-boot_directory>
make stm32mp15_trusted_defconfig
make DEVICE_TREE=stm32mp157c-ev1 all
-To build TF-A with with Op-TEE support:
-
+To build TF-A with OP-TEE support for all bootable devices:
.. code:: bash
- make CROSS_COMPILE=arm-linux-gnueabihf- PLAT=stm32mp1 ARCH=aarch32 ARM_ARCH_MAJOR=7 AARCH32_SP=optee
+ make CROSS_COMPILE=arm-linux-gnueabihf- PLAT=stm32mp1 ARCH=aarch32 ARM_ARCH_MAJOR=7 AARCH32_SP=optee STM32MP_SDMMC=1 STM32MP_EMMC=1 STM32MP_RAW_NAND=1 STM32MP_SPI_NAND=1 STM32MP_SPI_NOR=1 DTB_FILE_NAME=stm32mp157c-ev1.dtb
+ cd <optee_directory>
+ make CROSS_COMPILE=arm-linux-gnueabihf- ARCH=arm PLATFORM=stm32mp1 CFG_EMBED_DTB_SOURCE_FILE=stm32mp157c-ev1.dts
+ cd <u-boot_directory>
+ make stm32mp15_optee_defconfig
+ make DEVICE_TREE=stm32mp157c-ev1 all
+
The following build options are supported:
diff --git a/drivers/arm/tzc/tzc400.c b/drivers/arm/tzc/tzc400.c
index 50d670139..801cf3046 100644
--- a/drivers/arm/tzc/tzc400.c
+++ b/drivers/arm/tzc/tzc400.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2016-2020, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -60,7 +60,6 @@ static inline void _tzc400_write_gate_keeper(uintptr_t base, unsigned int val)
GATE_KEEPER_OS_SHIFT) & \
GATE_KEEPER_OS_MASK)
-
/* Define common core functions used across different TZC peripherals. */
DEFINE_TZC_COMMON_WRITE_ACTION(400, 400)
DEFINE_TZC_COMMON_WRITE_REGION_BASE(400, 400)
@@ -70,8 +69,50 @@ DEFINE_TZC_COMMON_WRITE_REGION_ID_ACCESS(400, 400)
DEFINE_TZC_COMMON_CONFIGURE_REGION0(400)
DEFINE_TZC_COMMON_CONFIGURE_REGION(400)
-static unsigned int _tzc400_get_gate_keeper(uintptr_t base,
- unsigned int filter)
+static inline void tzc400_clear_it(long base, uint32_t filter)
+{
+ mmio_write_32(base + INT_CLEAR, 1U << filter);
+}
+
+static inline uint32_t tzc400_get_int_by_filter(long base, uint32_t filter)
+{
+ return (mmio_read_32(base + INT_STATUS) & (1U << filter));
+}
+
+#if DEBUG
+static long tzc400_get_fail_address(long base, uint32_t filter)
+{
+ long fail_address;
+
+ if (filter != 0U) {
+ fail_address = mmio_read_32(base + FAIL_ADDRESS_LOW_OFF +
+ FILTER_OFFSET);
+#ifdef __aarch64__
+ fail_address += mmio_read_32(base + FAIL_ADDRESS_HIGH_OFF +
+ FILTER_OFFSET) << 32;
+#endif
+ } else {
+ fail_address = mmio_read_32(base + FAIL_ADDRESS_LOW_OFF);
+#ifdef __aarch64__
+ fail_address +=
+ mmio_read_32(base + FAIL_ADDRESS_HIGH_OFF) << 32;
+#endif
+ }
+
+ return fail_address;
+}
+#endif
+
+static inline uint32_t tzc400_get_fail_control(long base, uint32_t filter)
+{
+ if (filter != 0U) {
+ 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)
{
unsigned int open_status;
@@ -81,9 +122,8 @@ static unsigned int _tzc400_get_gate_keeper(uintptr_t base,
}
/* This function is not MP safe. */
-static void _tzc400_set_gate_keeper(uintptr_t base,
- unsigned int filter,
- int val)
+static void _tzc400_set_gate_keeper(uintptr_t base, unsigned int filter,
+ int val)
{
unsigned int open_status;
@@ -151,7 +191,7 @@ void tzc400_init(uintptr_t base)
* changed. This function only changes the access permissions.
*/
void tzc400_configure_region0(unsigned int sec_attr,
- unsigned int ns_device_access)
+ unsigned int ns_device_access)
{
assert(tzc400.base != 0U);
assert(sec_attr <= TZC_REGION_S_RDWR);
@@ -168,11 +208,11 @@ void tzc400_configure_region0(unsigned int sec_attr,
* for this region (see comment for that function).
*/
void tzc400_configure_region(unsigned int filters,
- unsigned int region,
- unsigned long long region_base,
- unsigned long long region_top,
- unsigned int sec_attr,
- unsigned int nsaid_permissions)
+ unsigned int region,
+ unsigned long long region_base,
+ unsigned long long region_top,
+ unsigned int sec_attr,
+ unsigned int nsaid_permissions)
{
assert(tzc400.base != 0U);
@@ -185,7 +225,7 @@ void tzc400_configure_region(unsigned int filters,
* the max and expected case.
*/
assert((region_top <= (UINT64_MAX >> (64U - tzc400.addr_width))) &&
- (region_base < region_top));
+ (region_base < region_top));
/* region_base and (region_top + 1) must be 4KB aligned */
assert(((region_base | (region_top + 1U)) & (4096U - 1U)) == 0U);
@@ -193,8 +233,7 @@ void tzc400_configure_region(unsigned int filters,
assert(sec_attr <= TZC_REGION_S_RDWR);
_tzc400_configure_region(tzc400.base, filters, region, region_base,
- region_top,
- sec_attr, nsaid_permissions);
+ region_top, sec_attr, nsaid_permissions);
}
void tzc400_enable_filters(void)
@@ -217,8 +256,8 @@ void tzc400_enable_filters(void)
* See the 'ARM (R) CoreLink TM TZC-400 TrustZone (R)
* Address Space Controller' Technical Reference Manual.
*/
- ERROR("TZC-400 : Filter %d Gatekeeper already"
- " enabled.\n", filter);
+ ERROR("TZC-400: Filter %d Gatekeeper already enabled\n",
+ filter);
panic();
}
_tzc400_set_gate_keeper(tzc400.base, filter, 1);
@@ -238,3 +277,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 != 0U);
+ for (filter = 0U; filter < tzc400.num_filters; filter++) {
+ mmio_write_32(tzc400.base + INT_CLEAR, 1U << filter);
+ }
+}
+
+int tzc400_is_pending_interrupt(void)
+{
+ unsigned int filter;
+
+ assert(tzc400.base != 0U);
+ for (filter = 0U; filter < tzc400.num_filters; filter++) {
+ if (mmio_read_32(tzc400.base + INT_STATUS) & (1U << filter)) {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+void tzc400_it_handler(void)
+{
+ uint32_t filter;
+ uint32_t filter_it_pending = tzc400.num_filters;
+ uint32_t control_fail;
+#if DEBUG
+ long address_fail;
+#endif
+
+ assert(tzc400.base != 0U);
+
+ /* first display information conerning the fault access */
+ for (filter = 0U; (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("\tNon-Secure\n");
+ } else {
+ ERROR("\tSecure\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/intel/soc/stratix10/io/s10_memmap_qspi.c b/drivers/intel/soc/stratix10/io/s10_memmap_qspi.c
index a0fc034d8..dcd199148 100644
--- a/drivers/intel/soc/stratix10/io/s10_memmap_qspi.c
+++ b/drivers/intel/soc/stratix10/io/s10_memmap_qspi.c
@@ -26,9 +26,9 @@ typedef struct {
* valid.
*/
int in_use;
- uintptr_t base;
- size_t file_pos;
- size_t size;
+ uintptr_t base;
+ unsigned long long file_pos;
+ unsigned long long size;
} file_state_t;
static file_state_t current_file = {0};
@@ -44,7 +44,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);
@@ -131,7 +131,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;
@@ -143,7 +144,8 @@ static int memmap_block_seek(io_entity_t *entity, int mode, ssize_t offset)
fp = (file_state_t *) entity->info;
/* Assert that new file position is valid */
- assert((offset >= 0) && (offset < fp->size));
+ assert((offset >= 0) &&
+ ((unsigned long long)offset < fp->size));
/* Reset file position */
fp->file_pos = offset;
@@ -171,7 +173,7 @@ static int memmap_block_read(io_entity_t *entity, uintptr_t buffer,
size_t length, size_t *length_read)
{
file_state_t *fp;
- size_t pos_after;
+ unsigned long long pos_after;
assert(entity != NULL);
assert(length_read != NULL);
@@ -198,7 +200,7 @@ static int memmap_block_write(io_entity_t *entity, const uintptr_t buffer,
size_t length, size_t *length_written)
{
file_state_t *fp;
- size_t pos_after;
+ unsigned long long pos_after;
assert(entity != NULL);
assert(length_written != NULL);
diff --git a/drivers/io/io_block.c b/drivers/io/io_block.c
index f190a4307..5d45c2f17 100644
--- a/drivers/io/io_block.c
+++ b/drivers/io/io_block.c
@@ -19,17 +19,17 @@
typedef struct {
io_block_dev_spec_t *dev_spec;
uintptr_t base;
- size_t file_pos;
- size_t size;
+ unsigned long long file_pos;
+ unsigned long long size;
} block_dev_state_t;
-#define is_power_of_2(x) ((x != 0) && ((x & (x - 1)) == 0))
+#define is_power_of_2(x) (((x) != 0U) && (((x) & ((x) - 1U)) == 0U))
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,
@@ -148,21 +148,21 @@ 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;
assert(entity->info != (uintptr_t)NULL);
cur = (block_dev_state_t *)entity->info;
- assert((offset >= 0) && (offset < cur->size));
+ assert((offset >= 0) && ((unsigned long long)offset < cur->size));
switch (mode) {
case IO_SEEK_SET:
- cur->file_pos = offset;
+ cur->file_pos = (unsigned long long)offset;
break;
case IO_SEEK_CUR:
- cur->file_pos += offset;
+ cur->file_pos += (unsigned long long)offset;
break;
default:
return -EINVAL;
@@ -270,7 +270,7 @@ static int block_read(io_entity_t *entity, uintptr_t buffer, size_t length,
buf = &(cur->dev_spec->buffer);
block_size = cur->dev_spec->block_size;
assert((length <= cur->size) &&
- (length > 0) &&
+ (length > 0U) &&
(ops->read != 0));
/*
@@ -279,7 +279,7 @@ static int block_read(io_entity_t *entity, uintptr_t buffer, size_t length,
* on the low level driver.
*/
count = 0;
- for (left = length; left > 0; left -= nbytes) {
+ for (left = length; left > 0U; left -= nbytes) {
/*
* We must only request operations aligned to the block
* size. Therefore if file_pos is not block-aligned,
@@ -288,7 +288,7 @@ static int block_read(io_entity_t *entity, uintptr_t buffer, size_t length,
* similarly, the number of bytes requested must be a
* block size multiple
*/
- skip = cur->file_pos & (block_size - 1);
+ skip = cur->file_pos & (block_size - 1U);
/*
* Calculate the block number containing file_pos
@@ -296,7 +296,7 @@ static int block_read(io_entity_t *entity, uintptr_t buffer, size_t length,
*/
lba = (cur->file_pos + cur->base) / block_size;
- if (skip + left > buf->length) {
+ if ((skip + left) > buf->length) {
/*
* The underlying read buffer is too small to
* read all the required data - limit to just
@@ -311,7 +311,8 @@ static int block_read(io_entity_t *entity, uintptr_t buffer, size_t length,
* block size.
*/
request = skip + left;
- request = (request + (block_size - 1)) & ~(block_size - 1);
+ request = (request + (block_size - 1U)) &
+ ~(block_size - 1U);
}
request = ops->read(lba, buf->offset, request);
@@ -330,7 +331,7 @@ static int block_read(io_entity_t *entity, uintptr_t buffer, size_t length,
* the read data when copying to the user buffer.
*/
nbytes = request - skip;
- padding = (nbytes > left) ? nbytes - left : 0;
+ padding = (nbytes > left) ? nbytes - left : 0U;
nbytes -= padding;
memcpy((void *)(buffer + count),
@@ -381,7 +382,7 @@ static int block_write(io_entity_t *entity, const uintptr_t buffer,
buf = &(cur->dev_spec->buffer);
block_size = cur->dev_spec->block_size;
assert((length <= cur->size) &&
- (length > 0) &&
+ (length > 0U) &&
(ops->read != 0) &&
(ops->write != 0));
@@ -391,7 +392,7 @@ static int block_write(io_entity_t *entity, const uintptr_t buffer,
* on the low level driver.
*/
count = 0;
- for (left = length; left > 0; left -= nbytes) {
+ for (left = length; left > 0U; left -= nbytes) {
/*
* We must only request operations aligned to the block
* size. Therefore if file_pos is not block-aligned,
@@ -400,7 +401,7 @@ static int block_write(io_entity_t *entity, const uintptr_t buffer,
* similarly, the number of bytes requested must be a
* block size multiple
*/
- skip = cur->file_pos & (block_size - 1);
+ skip = cur->file_pos & (block_size - 1U);
/*
* Calculate the block number containing file_pos
@@ -408,7 +409,7 @@ static int block_write(io_entity_t *entity, const uintptr_t buffer,
*/
lba = (cur->file_pos + cur->base) / block_size;
- if (skip + left > buf->length) {
+ if ((skip + left) > buf->length) {
/*
* The underlying read buffer is too small to
* read all the required data - limit to just
@@ -423,7 +424,8 @@ static int block_write(io_entity_t *entity, const uintptr_t buffer,
* block size.
*/
request = skip + left;
- request = (request + (block_size - 1)) & ~(block_size - 1);
+ request = (request + (block_size - 1U)) &
+ ~(block_size - 1U);
}
/*
@@ -432,7 +434,7 @@ static int block_write(io_entity_t *entity, const uintptr_t buffer,
* of the current request.
*/
nbytes = request - skip;
- padding = (nbytes > left) ? nbytes - left : 0;
+ padding = (nbytes > left) ? nbytes - left : 0U;
nbytes -= padding;
/*
@@ -440,14 +442,14 @@ static int block_write(io_entity_t *entity, const uintptr_t buffer,
* some content and it means that we have to read before
* writing
*/
- if (skip > 0 || padding > 0) {
+ if ((skip > 0U) || (padding > 0U)) {
request = ops->read(lba, buf->offset, request);
/*
* The read may return size less than
* requested. Round down to the nearest block
* boundary
*/
- request &= ~(block_size-1);
+ request &= ~(block_size - 1U);
if (request <= skip) {
/*
* We couldn't read enough bytes to jump over
@@ -458,7 +460,7 @@ static int block_write(io_entity_t *entity, const uintptr_t buffer,
return -EIO;
}
nbytes = request - skip;
- padding = (nbytes > left) ? nbytes - left : 0;
+ padding = (nbytes > left) ? nbytes - left : 0U;
nbytes -= padding;
}
@@ -477,7 +479,7 @@ static int block_write(io_entity_t *entity, const uintptr_t buffer,
* buffer
*/
nbytes = request - skip;
- padding = (nbytes > left) ? nbytes - left : 0;
+ padding = (nbytes > left) ? nbytes - left : 0U;
nbytes -= padding;
cur->file_pos += nbytes;
@@ -505,7 +507,7 @@ static int block_dev_open(const uintptr_t dev_spec, io_dev_info_t **dev_info)
assert(dev_info != NULL);
result = allocate_dev_info(&info);
- if (result)
+ if (result != 0)
return -ENOENT;
cur = (block_dev_state_t *)info->info;
@@ -513,10 +515,10 @@ static int block_dev_open(const uintptr_t dev_spec, io_dev_info_t **dev_info)
cur->dev_spec = (io_block_dev_spec_t *)dev_spec;
buffer = &(cur->dev_spec->buffer);
block_size = cur->dev_spec->block_size;
- assert((block_size > 0) &&
- (is_power_of_2(block_size) != 0) &&
- ((buffer->offset % block_size) == 0) &&
- ((buffer->length % block_size) == 0));
+ assert((block_size > 0U) &&
+ (is_power_of_2(block_size) != 0U) &&
+ ((buffer->offset % block_size) == 0U) &&
+ ((buffer->length % block_size) == 0U));
*dev_info = info; /* cast away const */
(void)block_size;
diff --git a/drivers/io/io_fip.c b/drivers/io/io_fip.c
index 544b37dbe..5d49fffaa 100644
--- a/drivers/io/io_fip.c
+++ b/drivers/io/io_fip.c
@@ -304,7 +304,8 @@ static int fip_file_open(io_dev_info_t *dev_info, const uintptr_t spec,
}
/* Seek past the FIP header into the Table of Contents */
- result = io_seek(backend_handle, IO_SEEK_SET, sizeof(fip_toc_header_t));
+ result = io_seek(backend_handle, IO_SEEK_SET,
+ (signed long long)sizeof(fip_toc_header_t));
if (result != 0) {
WARN("fip_file_open: failed to seek\n");
result = -ENOENT;
@@ -389,7 +390,8 @@ static int fip_file_read(io_entity_t *entity, uintptr_t buffer, size_t length,
/* Seek to the position in the FIP where the payload lives */
file_offset = fp->entry.offset_address + fp->file_pos;
- result = io_seek(backend_handle, IO_SEEK_SET, file_offset);
+ result = io_seek(backend_handle, IO_SEEK_SET,
+ (signed long long)file_offset);
if (result != 0) {
WARN("fip_file_read: failed to seek\n");
result = -ENOENT;
diff --git a/drivers/io/io_memmap.c b/drivers/io/io_memmap.c
index 96590b6c0..eed50cc08 100644
--- a/drivers/io/io_memmap.c
+++ b/drivers/io/io_memmap.c
@@ -23,10 +23,10 @@ typedef struct {
/* Use the 'in_use' flag as any value for base and file_pos could be
* valid.
*/
- int in_use;
- uintptr_t base;
- size_t file_pos;
- size_t size;
+ int in_use;
+ uintptr_t base;
+ unsigned long long file_pos;
+ unsigned long long size;
} file_state_t;
static file_state_t current_file = {0};
@@ -42,7 +42,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);
@@ -129,7 +129,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;
@@ -141,10 +142,11 @@ static int memmap_block_seek(io_entity_t *entity, int mode, ssize_t offset)
fp = (file_state_t *) entity->info;
/* Assert that new file position is valid */
- assert((offset >= 0) && (offset < fp->size));
+ assert((offset >= 0) &&
+ ((unsigned long long)offset < fp->size));
/* Reset file position */
- fp->file_pos = offset;
+ fp->file_pos = (unsigned long long)offset;
result = 0;
}
@@ -158,7 +160,7 @@ static int memmap_block_len(io_entity_t *entity, size_t *length)
assert(entity != NULL);
assert(length != NULL);
- *length = ((file_state_t *)entity->info)->size;
+ *length = (size_t)((file_state_t *)entity->info)->size;
return 0;
}
@@ -169,7 +171,7 @@ static int memmap_block_read(io_entity_t *entity, uintptr_t buffer,
size_t length, size_t *length_read)
{
file_state_t *fp;
- size_t pos_after;
+ unsigned long long pos_after;
assert(entity != NULL);
assert(length_read != NULL);
@@ -180,7 +182,8 @@ static int memmap_block_read(io_entity_t *entity, uintptr_t buffer,
pos_after = fp->file_pos + length;
assert((pos_after >= fp->file_pos) && (pos_after <= fp->size));
- memcpy((void *)buffer, (void *)(fp->base + fp->file_pos), length);
+ memcpy((void *)buffer,
+ (void *)((uintptr_t)(fp->base + fp->file_pos)), length);
*length_read = length;
@@ -196,7 +199,7 @@ static int memmap_block_write(io_entity_t *entity, const uintptr_t buffer,
size_t length, size_t *length_written)
{
file_state_t *fp;
- size_t pos_after;
+ unsigned long long pos_after;
assert(entity != NULL);
assert(length_written != NULL);
@@ -207,7 +210,8 @@ static int memmap_block_write(io_entity_t *entity, const uintptr_t buffer,
pos_after = fp->file_pos + length;
assert((pos_after >= fp->file_pos) && (pos_after <= fp->size));
- memcpy((void *)(fp->base + fp->file_pos), (void *)buffer, length);
+ memcpy((void *)((uintptr_t)(fp->base + fp->file_pos)),
+ (void *)buffer, length);
*length_written = length;
diff --git a/drivers/io/io_mtd.c b/drivers/io/io_mtd.c
new file mode 100644
index 000000000..7575fa250
--- /dev/null
+++ b/drivers/io/io_mtd.c
@@ -0,0 +1,248 @@
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+
+#include <platform_def.h>
+
+#include <common/debug.h>
+#include <drivers/io/io_driver.h>
+#include <drivers/io/io_mtd.h>
+#include <lib/utils.h>
+
+typedef struct {
+ io_mtd_dev_spec_t *dev_spec;
+ uintptr_t base;
+ unsigned long long offset; /* Offset in bytes */
+ unsigned long long size; /* Size of device in bytes */
+} mtd_dev_state_t;
+
+io_type_t device_type_mtd(void);
+
+static int mtd_open(io_dev_info_t *dev_info, const uintptr_t spec,
+ io_entity_t *entity);
+static int mtd_seek(io_entity_t *entity, int mode, signed long long offset);
+static int mtd_read(io_entity_t *entity, uintptr_t buffer, size_t length,
+ size_t *length_read);
+static int mtd_close(io_entity_t *entity);
+static int mtd_dev_open(const uintptr_t dev_spec, io_dev_info_t **dev_info);
+static int mtd_dev_close(io_dev_info_t *dev_info);
+
+static const io_dev_connector_t mtd_dev_connector = {
+ .dev_open = mtd_dev_open
+};
+
+static const io_dev_funcs_t mtd_dev_funcs = {
+ .type = device_type_mtd,
+ .open = mtd_open,
+ .seek = mtd_seek,
+ .read = mtd_read,
+ .close = mtd_close,
+ .dev_close = mtd_dev_close,
+};
+
+static mtd_dev_state_t state_pool[MAX_IO_MTD_DEVICES];
+static io_dev_info_t dev_info_pool[MAX_IO_MTD_DEVICES];
+
+io_type_t device_type_mtd(void)
+{
+ return IO_TYPE_MTD;
+}
+
+/* Locate a MTD state in the pool, specified by address */
+static int find_first_mtd_state(const io_mtd_dev_spec_t *dev_spec,
+ unsigned int *index_out)
+{
+ unsigned int index;
+ int result = -ENOENT;
+
+ for (index = 0U; index < MAX_IO_MTD_DEVICES; index++) {
+ /* dev_spec is used as identifier since it's unique */
+ if (state_pool[index].dev_spec == dev_spec) {
+ result = 0;
+ *index_out = index;
+ break;
+ }
+ }
+
+ return result;
+}
+
+/* Allocate a device info from the pool */
+static int allocate_dev_info(io_dev_info_t **dev_info)
+{
+ unsigned int index = 0U;
+ int result;
+
+ result = find_first_mtd_state(NULL, &index);
+ if (result != 0) {
+ return -ENOMEM;
+ }
+
+ dev_info_pool[index].funcs = &mtd_dev_funcs;
+ dev_info_pool[index].info = (uintptr_t)&state_pool[index];
+ *dev_info = &dev_info_pool[index];
+
+ return 0;
+}
+
+/* Release a device info from the pool */
+static int free_dev_info(io_dev_info_t *dev_info)
+{
+ int result;
+ unsigned int index = 0U;
+ mtd_dev_state_t *state;
+
+ state = (mtd_dev_state_t *)dev_info->info;
+ result = find_first_mtd_state(state->dev_spec, &index);
+ if (result != 0) {
+ return result;
+ }
+
+ zeromem(state, sizeof(mtd_dev_state_t));
+ zeromem(dev_info, sizeof(io_dev_info_t));
+
+ return 0;
+}
+
+static int mtd_open(io_dev_info_t *dev_info, const uintptr_t spec,
+ io_entity_t *entity)
+{
+ mtd_dev_state_t *cur;
+
+ assert((dev_info->info != 0UL) && (entity->info == 0UL));
+
+ cur = (mtd_dev_state_t *)dev_info->info;
+ entity->info = (uintptr_t)cur;
+ cur->offset = 0U;
+
+ return 0;
+}
+
+/* Seek to a specific position using offset */
+static int mtd_seek(io_entity_t *entity, int mode, signed long long offset)
+{
+ mtd_dev_state_t *cur;
+
+ assert((entity->info != (uintptr_t)NULL) && (offset >= 0));
+
+ cur = (mtd_dev_state_t *)entity->info;
+
+ switch (mode) {
+ case IO_SEEK_SET:
+ if ((offset >= 0) &&
+ ((unsigned long long)offset >= cur->size)) {
+ return -EINVAL;
+ }
+
+ cur->offset = offset;
+ break;
+ case IO_SEEK_CUR:
+ if (((cur->offset + (unsigned long long)offset) >=
+ cur->size) ||
+ ((cur->offset + (unsigned long long)offset) <
+ cur->offset)) {
+ return -EINVAL;
+ }
+
+ cur->offset += (unsigned long long)offset;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int mtd_read(io_entity_t *entity, uintptr_t buffer, size_t length,
+ size_t *out_length)
+{
+ mtd_dev_state_t *cur;
+ io_mtd_ops_t *ops;
+ int ret;
+
+ assert(entity->info != (uintptr_t)NULL);
+ assert((length > 0U) && (buffer != (uintptr_t)NULL));
+
+ cur = (mtd_dev_state_t *)entity->info;
+ ops = &cur->dev_spec->ops;
+ assert(ops->read != NULL);
+
+ VERBOSE("Read at %llx into %lx, length %zi\n",
+ cur->offset, buffer, length);
+ if ((cur->offset + length) > cur->dev_spec->device_size) {
+ return -EINVAL;
+ }
+
+ ret = ops->read(cur->offset, buffer, length, out_length);
+ if (ret < 0) {
+ return ret;
+ }
+
+ assert(*out_length == length);
+ cur->offset += *out_length;
+
+ return 0;
+}
+
+static int mtd_close(io_entity_t *entity)
+{
+ entity->info = (uintptr_t)NULL;
+
+ return 0;
+}
+
+static int mtd_dev_open(const uintptr_t dev_spec, io_dev_info_t **dev_info)
+{
+ mtd_dev_state_t *cur;
+ io_dev_info_t *info;
+ io_mtd_ops_t *ops;
+ int result;
+
+ result = allocate_dev_info(&info);
+ if (result != 0) {
+ return -ENOENT;
+ }
+
+ cur = (mtd_dev_state_t *)info->info;
+ cur->dev_spec = (io_mtd_dev_spec_t *)dev_spec;
+ *dev_info = info;
+ ops = &(cur->dev_spec->ops);
+ if (ops->init != NULL) {
+ result = ops->init(&cur->dev_spec->device_size,
+ &cur->dev_spec->erase_size);
+ }
+
+ if (result == 0) {
+ cur->size = cur->dev_spec->device_size;
+ } else {
+ cur->size = 0ULL;
+ }
+
+ return result;
+}
+
+static int mtd_dev_close(io_dev_info_t *dev_info)
+{
+ return free_dev_info(dev_info);
+}
+
+/* Exported functions */
+
+/* Register the MTD driver in the IO abstraction */
+int register_io_dev_mtd(const io_dev_connector_t **dev_con)
+{
+ int result;
+
+ result = io_register_device(&dev_info_pool[0]);
+ if (result == 0) {
+ *dev_con = &mtd_dev_connector;
+ }
+
+ return result;
+}
diff --git a/drivers/io/io_semihosting.c b/drivers/io/io_semihosting.c
index 23d09c118..4ceddc6cc 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;
@@ -98,7 +98,7 @@ static int sh_file_seek(io_entity_t *entity, int mode, ssize_t offset)
file_handle = (long)entity->info;
- sh_result = semihosting_file_seek(file_handle, offset);
+ sh_result = semihosting_file_seek(file_handle, (ssize_t)offset);
return (sh_result == 0) ? 0 : -ENOENT;
}
diff --git a/drivers/io/io_storage.c b/drivers/io/io_storage.c
index e444f87f7..b8c1d6479 100644
--- a/drivers/io/io_storage.c
+++ b/drivers/io/io_storage.c
@@ -237,7 +237,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 b5f6a10d3..42243ea09 100644
--- a/drivers/mmc/mmc.c
+++ b/drivers/mmc/mmc.c
@@ -25,6 +25,7 @@
static const struct mmc_ops *ops;
static unsigned int mmc_ocr_value;
static struct mmc_csd_emmc mmc_csd;
+static struct sd_switch_status sd_switch_func_status;
static unsigned char mmc_ext_csd[512] __aligned(16);
static unsigned int mmc_flags;
static struct mmc_device_info *mmc_dev_info;
@@ -44,6 +45,11 @@ static bool is_cmd23_enabled(void)
return ((mmc_flags & MMC_FLAG_CMD23) != 0U);
}
+static bool is_sd_cmd6_enabled(void)
+{
+ return ((mmc_flags & MMC_FLAG_SD_CMD6) != 0U);
+}
+
static int mmc_send_cmd(unsigned int idx, unsigned int arg,
unsigned int r_type, unsigned int *r_data)
{
@@ -327,6 +333,33 @@ static int mmc_fill_device_info(void)
return 0;
}
+static int sd_switch(unsigned char mode, unsigned char group,
+ unsigned char func)
+{
+ unsigned int group_shift = (group - 1U) * 4U;
+ unsigned int group_mask = GENMASK(group_shift + 3U, group_shift);
+ unsigned int arg;
+ int ret = 0;
+
+ ret = ops->prepare(0, (uintptr_t)&sd_switch_func_status,
+ sizeof(sd_switch_func_status));
+ if (ret != 0) {
+ return ret;
+ }
+
+ /* MMC CMD6: SWITCH_FUNC */
+ arg = (mode << 31) | GENMASK(23, 0);
+ arg &= ~group_mask;
+ arg |= func << group_shift;
+ ret = mmc_send_cmd(MMC_CMD(6), arg, MMC_RESPONSE_R1, NULL);
+ if (ret != 0) {
+ return ret;
+ }
+
+ return ops->read(0, (uintptr_t)&sd_switch_func_status,
+ sizeof(sd_switch_func_status));
+}
+
static int sd_send_op_cond(void)
{
int n;
@@ -494,7 +527,39 @@ static int mmc_enumerate(unsigned int clk, unsigned int bus_width)
return ret;
}
- return mmc_fill_device_info();
+ ret = mmc_fill_device_info();
+ if (ret != 0) {
+ return ret;
+ }
+
+ if (is_sd_cmd6_enabled() &&
+ (mmc_dev_info->mmc_dev_type == MMC_IS_SD_HC)) {
+ /* Try to switch to High Speed Mode */
+ ret = sd_switch(SD_SWITCH_FUNC_CHECK, 1U, 1U);
+ if (ret != 0) {
+ return ret;
+ }
+
+ if ((sd_switch_func_status.support_g1 & BIT(9)) == 0U) {
+ /* High speed not supported, keep default speed */
+ return 0;
+ }
+
+ ret = sd_switch(SD_SWITCH_FUNC_SWITCH, 1U, 1U);
+ if (ret != 0) {
+ return ret;
+ }
+
+ if ((sd_switch_func_status.sel_g2_g1 & 0x1U) == 0U) {
+ /* Cannot switch to high speed, keep default speed */
+ return 0;
+ }
+
+ mmc_dev_info->max_bus_freq = 50000000U;
+ ret = ops->set_ios(clk, bus_width);
+ }
+
+ return ret;
}
size_t mmc_read_blocks(int lba, uintptr_t buf, size_t size)
diff --git a/drivers/mtd/nand/core.c b/drivers/mtd/nand/core.c
new file mode 100644
index 000000000..44b001e35
--- /dev/null
+++ b/drivers/mtd/nand/core.c
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2019, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <stddef.h>
+
+#include <platform_def.h>
+
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <drivers/nand.h>
+#include <lib/utils.h>
+
+/*
+ * Define a single nand_device used by specific NAND frameworks.
+ */
+static struct nand_device nand_dev;
+static uint8_t scratch_buff[PLATFORM_MTD_MAX_PAGE_SIZE];
+
+int nand_read(unsigned int offset, uintptr_t buffer, size_t length,
+ size_t *length_read)
+{
+ unsigned int block = offset / nand_dev.block_size;
+ unsigned int end_block = (offset + length - 1U) / nand_dev.block_size;
+ unsigned int page_start =
+ (offset % nand_dev.block_size) / nand_dev.page_size;
+ unsigned int nb_pages = nand_dev.block_size / nand_dev.page_size;
+ unsigned int start_offset = offset % nand_dev.page_size;
+ unsigned int page;
+ unsigned int bytes_read;
+ int is_bad;
+ int ret;
+
+ VERBOSE("Block %u - %u, page_start %u, nb %u, length %zu, offset %u\n",
+ block, end_block, page_start, nb_pages, length, offset);
+
+ *length_read = 0UL;
+
+ if (((start_offset != 0U) || (length % nand_dev.page_size) != 0U) &&
+ (sizeof(scratch_buff) < nand_dev.page_size)) {
+ return -EINVAL;
+ }
+
+ while (block <= end_block) {
+ is_bad = nand_dev.mtd_block_is_bad(block);
+ if (is_bad < 0) {
+ return is_bad;
+ }
+
+ if (is_bad == 1) {
+ /* Skip the block */
+ uint32_t max_block =
+ nand_dev.size / nand_dev.block_size;
+
+ block++;
+ end_block++;
+ if ((block < max_block) && (end_block < max_block)) {
+ continue;
+ }
+
+ return -EIO;
+ }
+
+ for (page = page_start; page < nb_pages; page++) {
+ if ((start_offset != 0U) ||
+ (length < nand_dev.page_size)) {
+ ret = nand_dev.mtd_read_page(
+ &nand_dev,
+ (block * nb_pages) + page,
+ (uintptr_t)scratch_buff);
+ if (ret != 0) {
+ return ret;
+ }
+
+ bytes_read = MIN((size_t)(nand_dev.page_size -
+ start_offset),
+ length);
+
+ memcpy((uint8_t *)buffer,
+ scratch_buff + start_offset,
+ bytes_read);
+
+ start_offset = 0U;
+ } else {
+ ret = nand_dev.mtd_read_page(&nand_dev,
+ (block * nb_pages) + page,
+ buffer);
+ if (ret != 0) {
+ return ret;
+ }
+
+ bytes_read = nand_dev.page_size;
+ }
+
+ length -= bytes_read;
+ buffer += bytes_read;
+ *length_read += bytes_read;
+
+ if (length == 0U) {
+ break;
+ }
+ }
+
+ page_start = 0U;
+ block++;
+ }
+
+ return 0;
+}
+
+struct nand_device *get_nand_device(void)
+{
+ return &nand_dev;
+}
diff --git a/drivers/mtd/nand/raw_nand.c b/drivers/mtd/nand/raw_nand.c
new file mode 100644
index 000000000..48131fcb2
--- /dev/null
+++ b/drivers/mtd/nand/raw_nand.c
@@ -0,0 +1,446 @@
+/*
+ * Copyright (c) 2019, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <stddef.h>
+
+#include <platform_def.h>
+
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <drivers/raw_nand.h>
+#include <lib/utils.h>
+
+#define ONFI_SIGNATURE_ADDR 0x20U
+
+/* CRC calculation */
+#define CRC_POLYNOM 0x8005U
+#define CRC_INIT_VALUE 0x4F4EU
+
+/* Status register */
+#define NAND_STATUS_READY BIT(6)
+
+#define SZ_128M 0x08000000U
+#define SZ_512 0x200U
+
+static struct rawnand_device rawnand_dev;
+
+#pragma weak plat_get_raw_nand_data
+int plat_get_raw_nand_data(struct rawnand_device *device)
+{
+ return 0;
+}
+
+static int nand_send_cmd(uint8_t cmd, unsigned int tim)
+{
+ struct nand_req req;
+
+ zeromem(&req, sizeof(struct nand_req));
+ req.nand = rawnand_dev.nand_dev;
+ req.type = NAND_REQ_CMD | cmd;
+ req.inst_delay = tim;
+
+ return rawnand_dev.ops->exec(&req);
+}
+
+static int nand_send_addr(uint8_t addr, unsigned int tim)
+{
+ struct nand_req req;
+
+ zeromem(&req, sizeof(struct nand_req));
+ req.nand = rawnand_dev.nand_dev;
+ req.type = NAND_REQ_ADDR;
+ req.addr = &addr;
+ req.inst_delay = tim;
+
+ return rawnand_dev.ops->exec(&req);
+}
+
+static int nand_send_wait(unsigned int delay, unsigned int tim)
+{
+ struct nand_req req;
+
+ zeromem(&req, sizeof(struct nand_req));
+ req.nand = rawnand_dev.nand_dev;
+ req.type = NAND_REQ_WAIT;
+ req.inst_delay = tim;
+ req.delay_ms = delay;
+
+ return rawnand_dev.ops->exec(&req);
+}
+
+
+static int nand_read_data(uint8_t *data, unsigned int length, bool use_8bit)
+{
+ struct nand_req req;
+
+ zeromem(&req, sizeof(struct nand_req));
+ req.nand = rawnand_dev.nand_dev;
+ req.type = NAND_REQ_DATAIN | (use_8bit ? NAND_REQ_BUS_WIDTH_8 : 0U);
+ req.addr = data;
+ req.length = length;
+
+ return rawnand_dev.ops->exec(&req);
+}
+
+int nand_change_read_column_cmd(unsigned int offset, uintptr_t buffer,
+ unsigned int len)
+{
+ int ret;
+ uint8_t addr[2];
+ unsigned int i;
+
+ ret = nand_send_cmd(NAND_CMD_CHANGE_1ST, 0U);
+ if (ret != 0) {
+ return ret;
+ }
+
+ if (rawnand_dev.nand_dev->buswidth == NAND_BUS_WIDTH_16) {
+ offset /= 2U;
+ }
+
+ addr[0] = offset;
+ addr[1] = offset >> 8;
+
+ for (i = 0; i < 2U; i++) {
+ ret = nand_send_addr(addr[i], 0U);
+ if (ret != 0) {
+ return ret;
+ }
+ }
+
+ ret = nand_send_cmd(NAND_CMD_CHANGE_2ND, NAND_TCCS_MIN);
+ if (ret != 0) {
+ return ret;
+ }
+
+ return nand_read_data((uint8_t *)buffer, len, false);
+}
+
+int nand_read_page_cmd(unsigned int page, unsigned int offset,
+ uintptr_t buffer, unsigned int len)
+{
+ uint8_t addr[5];
+ uint8_t i = 0U;
+ uint8_t j;
+ int ret;
+
+ VERBOSE(">%s page %u offset %u buffer 0x%lx\n", __func__, page, offset,
+ buffer);
+
+ if (rawnand_dev.nand_dev->buswidth == NAND_BUS_WIDTH_16) {
+ offset /= 2U;
+ }
+
+ addr[i++] = offset;
+ addr[i++] = offset >> 8;
+
+ addr[i++] = page;
+ addr[i++] = page >> 8;
+ if (rawnand_dev.nand_dev->size > SZ_128M) {
+ addr[i++] = page >> 16;
+ }
+
+ ret = nand_send_cmd(NAND_CMD_READ_1ST, 0U);
+ if (ret != 0) {
+ return ret;
+ }
+
+ for (j = 0U; j < i; j++) {
+ ret = nand_send_addr(addr[j], 0U);
+ if (ret != 0) {
+ return ret;
+ }
+ }
+
+ ret = nand_send_cmd(NAND_CMD_READ_2ND, NAND_TWB_MAX);
+ if (ret != 0) {
+ return ret;
+ }
+
+ ret = nand_send_wait(PSEC_TO_MSEC(NAND_TR_MAX), NAND_TRR_MIN);
+ if (ret != 0) {
+ return ret;
+ }
+
+ if (buffer != 0U) {
+ ret = nand_read_data((uint8_t *)buffer, len, false);
+ }
+
+ return ret;
+}
+
+static int nand_status(uint8_t *status)
+{
+ int ret;
+
+ ret = nand_send_cmd(NAND_CMD_STATUS, NAND_TWHR_MIN);
+ if (ret != 0) {
+ return ret;
+ }
+
+ if (status != NULL) {
+ ret = nand_read_data(status, 1U, true);
+ }
+
+ return ret;
+}
+
+int nand_wait_ready(unsigned long delay)
+{
+ uint8_t status;
+ int ret;
+ uint64_t timeout;
+
+ /* Wait before reading status */
+ udelay(1);
+
+ ret = nand_status(NULL);
+ if (ret != 0) {
+ return ret;
+ }
+
+ timeout = timeout_init_us(delay);
+ while (!timeout_elapsed(timeout)) {
+ ret = nand_read_data(&status, 1U, true);
+ if (ret != 0) {
+ return ret;
+ }
+
+ if ((status & NAND_STATUS_READY) != 0U) {
+ return nand_send_cmd(NAND_CMD_READ_1ST, 0U);
+ }
+
+ udelay(10);
+ }
+
+ return -ETIMEDOUT;
+}
+
+#if NAND_ONFI_DETECT
+static uint16_t nand_check_crc(uint16_t crc, uint8_t *data_in,
+ unsigned int data_len)
+{
+ uint32_t i;
+ uint32_t j;
+ uint32_t bit;
+
+ for (i = 0U; i < data_len; i++) {
+ uint8_t cur_param = *data_in++;
+
+ for (j = BIT(7); j != 0U; j >>= 1) {
+ bit = crc & BIT(15);
+ crc <<= 1;
+
+ if ((cur_param & j) != 0U) {
+ bit ^= BIT(15);
+ }
+
+ if (bit != 0U) {
+ crc ^= CRC_POLYNOM;
+ }
+ }
+
+ crc &= GENMASK(15, 0);
+ }
+
+ return crc;
+}
+
+static int nand_read_id(uint8_t addr, uint8_t *id, unsigned int size)
+{
+ int ret;
+
+ ret = nand_send_cmd(NAND_CMD_READID, 0U);
+ if (ret != 0) {
+ return ret;
+ }
+
+ ret = nand_send_addr(addr, NAND_TWHR_MIN);
+ if (ret != 0) {
+ return ret;
+ }
+
+ return nand_read_data(id, size, true);
+}
+
+static int nand_reset(void)
+{
+ int ret;
+
+ ret = nand_send_cmd(NAND_CMD_RESET, NAND_TWB_MAX);
+ if (ret != 0) {
+ return ret;
+ }
+
+ return nand_send_wait(PSEC_TO_MSEC(NAND_TRST_MAX), 0U);
+}
+
+static int nand_read_param_page(void)
+{
+ struct nand_param_page page;
+ uint8_t addr = 0U;
+ int ret;
+
+ ret = nand_send_cmd(NAND_CMD_READ_PARAM_PAGE, 0U);
+ if (ret != 0) {
+ return ret;
+ }
+
+ ret = nand_send_addr(addr, NAND_TWB_MAX);
+ if (ret != 0) {
+ return ret;
+ }
+
+ ret = nand_send_wait(PSEC_TO_MSEC(NAND_TR_MAX), NAND_TRR_MIN);
+ if (ret != 0) {
+ return ret;
+ }
+
+ ret = nand_read_data((uint8_t *)&page, sizeof(page), true);
+ if (ret != 0) {
+ return ret;
+ }
+
+ if (strncmp((char *)&page.page_sig, "ONFI", 4) != 0) {
+ WARN("Error ONFI detection\n");
+ return -EINVAL;
+ }
+
+ if (nand_check_crc(CRC_INIT_VALUE, (uint8_t *)&page, 254U) !=
+ page.crc16) {
+ WARN("Error reading param\n");
+ return -EINVAL;
+ }
+
+ if ((page.features & ONFI_FEAT_BUS_WIDTH_16) != 0U) {
+ rawnand_dev.nand_dev->buswidth = NAND_BUS_WIDTH_16;
+ } else {
+ rawnand_dev.nand_dev->buswidth = NAND_BUS_WIDTH_8;
+ }
+
+ rawnand_dev.nand_dev->block_size = page.num_pages_per_blk *
+ page.bytes_per_page;
+ rawnand_dev.nand_dev->page_size = page.bytes_per_page;
+ rawnand_dev.nand_dev->size = page.num_pages_per_blk *
+ page.bytes_per_page *
+ page.num_blk_in_lun * page.num_lun;
+
+ if (page.nb_ecc_bits != GENMASK_32(7, 0)) {
+ rawnand_dev.nand_dev->ecc.max_bit_corr = page.nb_ecc_bits;
+ rawnand_dev.nand_dev->ecc.size = SZ_512;
+ }
+
+ VERBOSE("Page size %u, block_size %u, Size %llu, ecc %u, buswidth %u\n",
+ rawnand_dev.nand_dev->page_size,
+ rawnand_dev.nand_dev->block_size, rawnand_dev.nand_dev->size,
+ rawnand_dev.nand_dev->ecc.max_bit_corr,
+ rawnand_dev.nand_dev->buswidth);
+
+ return 0;
+}
+
+static int detect_onfi(void)
+{
+ int ret;
+ char id[4];
+
+ ret = nand_reset();
+ if (ret != 0) {
+ return ret;
+ }
+
+ ret = nand_read_id(ONFI_SIGNATURE_ADDR, (uint8_t *)id, sizeof(id));
+ if (ret != 0) {
+ return ret;
+ }
+
+ if (strncmp(id, "ONFI", sizeof(id)) != 0) {
+ WARN("NAND Non ONFI detected\n");
+ return -ENODEV;
+ }
+
+ return nand_read_param_page();
+}
+#endif
+
+static int nand_mtd_block_is_bad(unsigned int block)
+{
+ unsigned int nbpages_per_block = rawnand_dev.nand_dev->block_size /
+ rawnand_dev.nand_dev->page_size;
+ uint8_t bbm_marker[2];
+ uint8_t page;
+ int ret;
+
+ for (page = 0U; page < 2U; page++) {
+ ret = nand_read_page_cmd(block * nbpages_per_block,
+ rawnand_dev.nand_dev->page_size,
+ (uintptr_t)bbm_marker,
+ sizeof(bbm_marker));
+ if (ret != 0) {
+ return ret;
+ }
+
+ if ((bbm_marker[0] != GENMASK_32(7, 0)) ||
+ (bbm_marker[1] != GENMASK_32(7, 0))) {
+ WARN("Block %u is bad\n", block);
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+static int nand_mtd_read_page_raw(struct nand_device *nand, unsigned int page,
+ uintptr_t buffer)
+{
+ return nand_read_page_cmd(page, 0U, buffer,
+ rawnand_dev.nand_dev->page_size);
+}
+
+void nand_raw_ctrl_init(const struct nand_ctrl_ops *ops)
+{
+ rawnand_dev.ops = ops;
+}
+
+int nand_raw_init(unsigned long long *size, unsigned int *erase_size)
+{
+ rawnand_dev.nand_dev = get_nand_device();
+ if (rawnand_dev.nand_dev == NULL) {
+ return -EINVAL;
+ }
+
+ rawnand_dev.nand_dev->mtd_block_is_bad = nand_mtd_block_is_bad;
+ rawnand_dev.nand_dev->mtd_read_page = nand_mtd_read_page_raw;
+ rawnand_dev.nand_dev->ecc.mode = NAND_ECC_NONE;
+
+ if ((rawnand_dev.ops->setup == NULL) ||
+ (rawnand_dev.ops->exec == NULL)) {
+ return -ENODEV;
+ }
+
+#if NAND_ONFI_DETECT
+ if (detect_onfi() != 0) {
+ WARN("Detect ONFI failed\n");
+ }
+#endif
+
+ if (plat_get_raw_nand_data(&rawnand_dev) != 0) {
+ return -EINVAL;
+ }
+
+ assert((rawnand_dev.nand_dev->page_size != 0U) &&
+ (rawnand_dev.nand_dev->block_size != 0U) &&
+ (rawnand_dev.nand_dev->size != 0U));
+
+ *size = rawnand_dev.nand_dev->size;
+ *erase_size = rawnand_dev.nand_dev->block_size;
+
+ rawnand_dev.ops->setup(rawnand_dev.nand_dev);
+
+ return 0;
+}
diff --git a/drivers/mtd/nand/spi_nand.c b/drivers/mtd/nand/spi_nand.c
new file mode 100644
index 000000000..d01a11963
--- /dev/null
+++ b/drivers/mtd/nand/spi_nand.c
@@ -0,0 +1,320 @@
+/*
+ * Copyright (c) 2019, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <stddef.h>
+
+#include <platform_def.h>
+
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <drivers/spi_nand.h>
+#include <lib/utils.h>
+
+#define SPI_NAND_MAX_ID_LEN 4U
+#define DELAY_US_400MS 400000U
+#define MACRONIX_ID 0xC2U
+
+static struct spinand_device spinand_dev;
+
+#pragma weak plat_get_spi_nand_data
+int plat_get_spi_nand_data(struct spinand_device *device)
+{
+ return 0;
+}
+
+static int spi_nand_reg(bool read_reg, uint8_t reg, uint8_t *val,
+ enum spi_mem_data_dir dir)
+{
+ struct spi_mem_op op;
+
+ zeromem(&op, sizeof(struct spi_mem_op));
+ if (read_reg) {
+ op.cmd.opcode = SPI_NAND_OP_GET_FEATURE;
+ } else {
+ op.cmd.opcode = SPI_NAND_OP_SET_FEATURE;
+ }
+
+ op.cmd.buswidth = SPI_MEM_BUSWIDTH_1_LINE;
+ op.addr.val = reg;
+ op.addr.nbytes = 1U;
+ op.addr.buswidth = SPI_MEM_BUSWIDTH_1_LINE;
+ op.data.buswidth = SPI_MEM_BUSWIDTH_1_LINE;
+ op.data.dir = dir;
+ op.data.nbytes = 1U;
+ op.data.buf = val;
+
+ return spi_mem_exec_op(&op);
+}
+
+static int spi_nand_read_reg(uint8_t reg, uint8_t *val)
+{
+ return spi_nand_reg(true, reg, val, SPI_MEM_DATA_IN);
+}
+
+static int spi_nand_write_reg(uint8_t reg, uint8_t val)
+{
+ return spi_nand_reg(false, reg, &val, SPI_MEM_DATA_OUT);
+}
+
+static int spi_nand_update_cfg(uint8_t mask, uint8_t val)
+{
+ int ret;
+ uint8_t cfg = spinand_dev.cfg_cache;
+
+ cfg &= ~mask;
+ cfg |= val;
+
+ if (cfg == spinand_dev.cfg_cache) {
+ return 0;
+ }
+
+ ret = spi_nand_write_reg(SPI_NAND_REG_CFG, cfg);
+ if (ret == 0) {
+ spinand_dev.cfg_cache = cfg;
+ }
+
+ return ret;
+}
+
+static int spi_nand_ecc_enable(bool enable)
+{
+ return spi_nand_update_cfg(SPI_NAND_CFG_ECC_EN,
+ enable ? SPI_NAND_CFG_ECC_EN : 0U);
+}
+
+static int spi_nand_quad_enable(uint8_t manufacturer_id)
+{
+ bool enable = false;
+
+ if (manufacturer_id != MACRONIX_ID) {
+ return 0;
+ }
+
+ if (spinand_dev.spi_read_cache_op.data.buswidth ==
+ SPI_MEM_BUSWIDTH_4_LINE) {
+ enable = true;
+ }
+
+ return spi_nand_update_cfg(SPI_NAND_CFG_QE,
+ enable ? SPI_NAND_CFG_QE : 0U);
+}
+
+static int spi_nand_wait_ready(uint8_t *status)
+{
+ int ret;
+ uint64_t timeout = timeout_init_us(DELAY_US_400MS);
+
+ while (!timeout_elapsed(timeout)) {
+ ret = spi_nand_read_reg(SPI_NAND_REG_STATUS, status);
+ if (ret != 0) {
+ return ret;
+ }
+
+ VERBOSE("%s Status %x\n", __func__, *status);
+ if ((*status & SPI_NAND_STATUS_BUSY) == 0U) {
+ return 0;
+ }
+ }
+
+ return -ETIMEDOUT;
+}
+
+static int spi_nand_reset(void)
+{
+ struct spi_mem_op op;
+ uint8_t status;
+ int ret;
+
+ zeromem(&op, sizeof(struct spi_mem_op));
+ op.cmd.opcode = SPI_NAND_OP_RESET;
+ op.cmd.buswidth = SPI_MEM_BUSWIDTH_1_LINE;
+
+ ret = spi_mem_exec_op(&op);
+ if (ret != 0) {
+ return ret;
+ }
+
+ return spi_nand_wait_ready(&status);
+}
+
+static int spi_nand_read_id(uint8_t *id)
+{
+ struct spi_mem_op op;
+
+ zeromem(&op, sizeof(struct spi_mem_op));
+ op.cmd.opcode = SPI_NAND_OP_READ_ID;
+ op.cmd.buswidth = SPI_MEM_BUSWIDTH_1_LINE;
+ op.data.dir = SPI_MEM_DATA_IN;
+ op.data.nbytes = SPI_NAND_MAX_ID_LEN;
+ op.data.buf = id;
+ op.data.buswidth = SPI_MEM_BUSWIDTH_1_LINE;
+
+ return spi_mem_exec_op(&op);
+}
+
+static int spi_nand_load_page(unsigned int page)
+{
+ struct spi_mem_op op;
+ uint32_t block_nb = page / spinand_dev.nand_dev->block_size;
+ uint32_t page_nb = page - (block_nb * spinand_dev.nand_dev->page_size);
+ uint32_t nbpages_per_block = spinand_dev.nand_dev->block_size /
+ spinand_dev.nand_dev->page_size;
+ uint32_t block_sh = __builtin_ctz(nbpages_per_block) + 1U;
+
+ zeromem(&op, sizeof(struct spi_mem_op));
+ op.cmd.opcode = SPI_NAND_OP_LOAD_PAGE;
+ op.cmd.buswidth = SPI_MEM_BUSWIDTH_1_LINE;
+ op.addr.val = (block_nb << block_sh) | page_nb;
+ op.addr.nbytes = 3U;
+ op.addr.buswidth = SPI_MEM_BUSWIDTH_1_LINE;
+
+ return spi_mem_exec_op(&op);
+}
+
+static int spi_nand_read_from_cache(unsigned int page, unsigned int offset,
+ uint8_t *buffer, unsigned int len)
+{
+ uint32_t nbpages_per_block = spinand_dev.nand_dev->block_size /
+ spinand_dev.nand_dev->page_size;
+ uint32_t block_nb = page / nbpages_per_block;
+ uint32_t page_sh = __builtin_ctz(spinand_dev.nand_dev->page_size) + 1U;
+
+ spinand_dev.spi_read_cache_op.addr.val = offset;
+
+ if ((spinand_dev.nand_dev->nb_planes > 1U) && ((block_nb % 2U) == 1U)) {
+ spinand_dev.spi_read_cache_op.addr.val |= 1U << page_sh;
+ }
+
+ spinand_dev.spi_read_cache_op.data.buf = buffer;
+ spinand_dev.spi_read_cache_op.data.nbytes = len;
+
+ return spi_mem_exec_op(&spinand_dev.spi_read_cache_op);
+}
+
+static int spi_nand_read_page(unsigned int page, unsigned int offset,
+ uint8_t *buffer, unsigned int len,
+ bool ecc_enabled)
+{
+ uint8_t status;
+ int ret;
+
+ ret = spi_nand_ecc_enable(ecc_enabled);
+ if (ret != 0) {
+ return ret;
+ }
+
+ ret = spi_nand_load_page(page);
+ if (ret != 0) {
+ return ret;
+ }
+
+ ret = spi_nand_wait_ready(&status);
+ if (ret != 0) {
+ return ret;
+ }
+
+ ret = spi_nand_read_from_cache(page, offset, buffer, len);
+ if (ret != 0) {
+ return ret;
+ }
+
+ if (ecc_enabled && ((status & SPI_NAND_STATUS_ECC_UNCOR) != 0U)) {
+ return -EBADMSG;
+ }
+
+ return 0;
+}
+
+static int spi_nand_mtd_block_is_bad(unsigned int block)
+{
+ unsigned int nbpages_per_block = spinand_dev.nand_dev->block_size /
+ spinand_dev.nand_dev->page_size;
+ uint8_t bbm_marker[2];
+ int ret;
+
+ ret = spi_nand_read_page(block * nbpages_per_block,
+ spinand_dev.nand_dev->page_size,
+ bbm_marker, sizeof(bbm_marker), false);
+ if (ret != 0) {
+ return ret;
+ }
+
+ if ((bbm_marker[0] != GENMASK_32(7, 0)) ||
+ (bbm_marker[1] != GENMASK_32(7, 0))) {
+ WARN("Block %i is bad\n", block);
+ return 1;
+ }
+
+ return 0;
+}
+
+static int spi_nand_mtd_read_page(struct nand_device *nand, unsigned int page,
+ uintptr_t buffer)
+{
+ return spi_nand_read_page(page, 0, (uint8_t *)buffer,
+ spinand_dev.nand_dev->page_size, true);
+}
+
+int spi_nand_init(unsigned long long *size, unsigned int *erase_size)
+{
+ uint8_t id[SPI_NAND_MAX_ID_LEN];
+ int ret;
+
+ spinand_dev.nand_dev = get_nand_device();
+ if (spinand_dev.nand_dev == NULL) {
+ return -EINVAL;
+ }
+
+ spinand_dev.nand_dev->mtd_block_is_bad = spi_nand_mtd_block_is_bad;
+ spinand_dev.nand_dev->mtd_read_page = spi_nand_mtd_read_page;
+ spinand_dev.nand_dev->nb_planes = 1;
+
+ spinand_dev.spi_read_cache_op.cmd.opcode = SPI_NAND_OP_READ_FROM_CACHE;
+ spinand_dev.spi_read_cache_op.cmd.buswidth = SPI_MEM_BUSWIDTH_1_LINE;
+ spinand_dev.spi_read_cache_op.addr.nbytes = 2U;
+ spinand_dev.spi_read_cache_op.addr.buswidth = SPI_MEM_BUSWIDTH_1_LINE;
+ spinand_dev.spi_read_cache_op.dummy.nbytes = 1U;
+ spinand_dev.spi_read_cache_op.dummy.buswidth = SPI_MEM_BUSWIDTH_1_LINE;
+ spinand_dev.spi_read_cache_op.data.buswidth = SPI_MEM_BUSWIDTH_1_LINE;
+
+ if (plat_get_spi_nand_data(&spinand_dev) != 0) {
+ return -EINVAL;
+ }
+
+ ret = spi_nand_reset();
+ if (ret != 0) {
+ return ret;
+ }
+
+ ret = spi_nand_read_id(id);
+ if (ret != 0) {
+ return ret;
+ }
+
+ ret = spi_nand_read_reg(SPI_NAND_REG_CFG, &spinand_dev.cfg_cache);
+ if (ret != 0) {
+ return ret;
+ }
+
+ ret = spi_nand_quad_enable(id[0]);
+ if (ret != 0) {
+ return ret;
+ }
+
+ VERBOSE("SPI_NAND Detected ID 0x%x 0x%x\n", id[0], id[1]);
+
+ VERBOSE("Page size %i, Block size %i, size %lli\n",
+ spinand_dev.nand_dev->page_size,
+ spinand_dev.nand_dev->block_size,
+ spinand_dev.nand_dev->size);
+
+ *size = spinand_dev.nand_dev->size;
+ *erase_size = spinand_dev.nand_dev->block_size;
+
+ return 0;
+}
diff --git a/drivers/mtd/nor/spi_nor.c b/drivers/mtd/nor/spi_nor.c
new file mode 100644
index 000000000..2b4a5d87d
--- /dev/null
+++ b/drivers/mtd/nor/spi_nor.c
@@ -0,0 +1,387 @@
+/*
+ * Copyright (c) 2019, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <stddef.h>
+
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <drivers/spi_nor.h>
+#include <lib/utils.h>
+
+#define SR_WIP BIT(0) /* Write in progress */
+#define CR_QUAD_EN_SPAN BIT(1) /* Spansion Quad I/O */
+#define SR_QUAD_EN_MX BIT(6) /* Macronix Quad I/O */
+#define FSR_READY BIT(7) /* Device status, 0 = Busy, 1 = Ready */
+
+/* Defined IDs for supported memories */
+#define SPANSION_ID 0x01U
+#define MACRONIX_ID 0xC2U
+#define MICRON_ID 0x2CU
+
+#define BANK_SIZE 0x1000000U
+
+#define SPI_READY_TIMEOUT_US 40000U
+
+static struct nor_device nor_dev;
+
+#pragma weak plat_get_nor_data
+int plat_get_nor_data(struct nor_device *device)
+{
+ return 0;
+}
+
+static int spi_nor_reg(uint8_t reg, uint8_t *buf, size_t len,
+ enum spi_mem_data_dir dir)
+{
+ struct spi_mem_op op;
+
+ zeromem(&op, sizeof(struct spi_mem_op));
+ op.cmd.opcode = reg;
+ op.cmd.buswidth = SPI_MEM_BUSWIDTH_1_LINE;
+ op.data.buswidth = SPI_MEM_BUSWIDTH_1_LINE;
+ op.data.dir = dir;
+ op.data.nbytes = len;
+ op.data.buf = buf;
+
+ return spi_mem_exec_op(&op);
+}
+
+static inline int spi_nor_read_id(uint8_t *id)
+{
+ return spi_nor_reg(SPI_NOR_OP_READ_ID, id, 1U, SPI_MEM_DATA_IN);
+}
+
+static inline int spi_nor_read_cr(uint8_t *cr)
+{
+ return spi_nor_reg(SPI_NOR_OP_READ_CR, cr, 1U, SPI_MEM_DATA_IN);
+}
+
+static inline int spi_nor_read_sr(uint8_t *sr)
+{
+ return spi_nor_reg(SPI_NOR_OP_READ_SR, sr, 1U, SPI_MEM_DATA_IN);
+}
+
+static inline int spi_nor_read_fsr(uint8_t *fsr)
+{
+ return spi_nor_reg(SPI_NOR_OP_READ_FSR, fsr, 1U, SPI_MEM_DATA_IN);
+}
+
+static inline int spi_nor_write_en(void)
+{
+ return spi_nor_reg(SPI_NOR_OP_WREN, NULL, 0U, SPI_MEM_DATA_OUT);
+}
+
+/*
+ * Check if device is ready.
+ *
+ * Return 0 if ready, 1 if busy or a negative error code otherwise
+ */
+static int spi_nor_ready(void)
+{
+ uint8_t sr;
+ int ret;
+
+ ret = spi_nor_read_sr(&sr);
+ if (ret != 0) {
+ return ret;
+ }
+
+ if ((nor_dev.flags & SPI_NOR_USE_FSR) != 0U) {
+ uint8_t fsr;
+
+ ret = spi_nor_read_fsr(&fsr);
+ if (ret != 0) {
+ return ret;
+ }
+
+ return (((fsr & FSR_READY) != 0U) && ((sr & SR_WIP) == 0U)) ?
+ 0 : 1;
+ }
+
+ return (((sr & SR_WIP) != 0U) ? 1 : 0);
+}
+
+static int spi_nor_wait_ready(void)
+{
+ int ret;
+ uint64_t timeout = timeout_init_us(SPI_READY_TIMEOUT_US);
+
+ while (!timeout_elapsed(timeout)) {
+ ret = spi_nor_ready();
+ if (ret <= 0) {
+ return ret;
+ }
+ }
+
+ return -ETIMEDOUT;
+}
+
+static int spi_nor_macronix_quad_enable(void)
+{
+ uint8_t sr;
+ int ret;
+
+ ret = spi_nor_read_sr(&sr);
+ if (ret != 0) {
+ return ret;
+ }
+
+ if ((sr & SR_QUAD_EN_MX) == 0U) {
+ return 0;
+ }
+
+ ret = spi_nor_write_en();
+ if (ret != 0) {
+ return ret;
+ }
+
+ sr |= SR_QUAD_EN_MX;
+ ret = spi_nor_reg(SPI_NOR_OP_WRSR, &sr, 1, SPI_MEM_DATA_OUT);
+ if (ret != 0) {
+ return ret;
+ }
+
+ ret = spi_nor_wait_ready();
+ if (ret != 0) {
+ return ret;
+ }
+
+ ret = spi_nor_read_sr(&sr);
+ if ((ret != 0) || ((sr & SR_QUAD_EN_MX) == 0U)) {
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int spi_nor_write_sr_cr(uint8_t *sr_cr)
+{
+ int ret;
+
+ ret = spi_nor_write_en();
+ if (ret != 0) {
+ return ret;
+ }
+
+ ret = spi_nor_reg(SPI_NOR_OP_WRSR, sr_cr, 2, SPI_MEM_DATA_OUT);
+ if (ret != 0) {
+ return -EINVAL;
+ }
+
+ ret = spi_nor_wait_ready();
+ if (ret != 0) {
+ return ret;
+ }
+
+ return 0;
+}
+
+static int spi_nor_quad_enable(void)
+{
+ uint8_t sr_cr[2];
+ int ret;
+
+ ret = spi_nor_read_cr(&sr_cr[1]);
+ if (ret != 0) {
+ return ret;
+ }
+
+ if ((sr_cr[1] & CR_QUAD_EN_SPAN) != 0U) {
+ return 0;
+ }
+
+ sr_cr[1] |= CR_QUAD_EN_SPAN;
+ ret = spi_nor_read_sr(&sr_cr[0]);
+ if (ret != 0) {
+ return ret;
+ }
+
+ ret = spi_nor_write_sr_cr(sr_cr);
+ if (ret != 0) {
+ return ret;
+ }
+
+ ret = spi_nor_read_cr(&sr_cr[1]);
+ if ((ret != 0) || ((sr_cr[1] & CR_QUAD_EN_SPAN) == 0U)) {
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int spi_nor_clean_bar(void)
+{
+ int ret;
+
+ if (nor_dev.selected_bank == 0U) {
+ return 0;
+ }
+
+ nor_dev.selected_bank = 0U;
+
+ ret = spi_nor_write_en();
+ if (ret != 0) {
+ return ret;
+ }
+
+ return spi_nor_reg(nor_dev.bank_write_cmd, &nor_dev.selected_bank,
+ 1, SPI_MEM_DATA_OUT);
+}
+
+static int spi_nor_write_bar(uint32_t offset)
+{
+ uint8_t selected_bank = offset / BANK_SIZE;
+ int ret;
+
+ if (selected_bank == nor_dev.selected_bank) {
+ return 0;
+ }
+
+ ret = spi_nor_write_en();
+ if (ret != 0) {
+ return ret;
+ }
+
+ ret = spi_nor_reg(nor_dev.bank_write_cmd, &selected_bank,
+ 1, SPI_MEM_DATA_OUT);
+ if (ret != 0) {
+ return ret;
+ }
+
+ nor_dev.selected_bank = selected_bank;
+
+ return 0;
+}
+
+static int spi_nor_read_bar(void)
+{
+ uint8_t selected_bank = 0;
+ int ret;
+
+ ret = spi_nor_reg(nor_dev.bank_read_cmd, &selected_bank,
+ 1, SPI_MEM_DATA_IN);
+ if (ret != 0) {
+ return ret;
+ }
+
+ nor_dev.selected_bank = selected_bank;
+
+ return 0;
+}
+
+int spi_nor_read(unsigned int offset, uintptr_t buffer, size_t length,
+ size_t *length_read)
+{
+ size_t remain_len;
+ int ret;
+
+ *length_read = 0;
+ nor_dev.read_op.addr.val = offset;
+ nor_dev.read_op.data.buf = (void *)buffer;
+
+ VERBOSE("%s offset %i length %zu\n", __func__, offset, length);
+
+ while (length != 0U) {
+ if ((nor_dev.flags & SPI_NOR_USE_BANK) != 0U) {
+ ret = spi_nor_write_bar(nor_dev.read_op.addr.val);
+ if (ret != 0) {
+ return ret;
+ }
+
+ remain_len = (BANK_SIZE * (nor_dev.selected_bank + 1)) -
+ nor_dev.read_op.addr.val;
+ nor_dev.read_op.data.nbytes = MIN(length, remain_len);
+ } else {
+ nor_dev.read_op.data.nbytes = length;
+ }
+
+ ret = spi_mem_exec_op(&nor_dev.read_op);
+ if (ret != 0) {
+ spi_nor_clean_bar();
+ return ret;
+ }
+
+ length -= nor_dev.read_op.data.nbytes;
+ nor_dev.read_op.addr.val += nor_dev.read_op.data.nbytes;
+ nor_dev.read_op.data.buf += nor_dev.read_op.data.nbytes;
+ *length_read += nor_dev.read_op.data.nbytes;
+ }
+
+ if ((nor_dev.flags & SPI_NOR_USE_BANK) != 0U) {
+ ret = spi_nor_clean_bar();
+ if (ret != 0) {
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+int spi_nor_init(unsigned long long *size, unsigned int *erase_size)
+{
+ int ret = 0;
+ uint8_t id;
+
+ /* Default read command used */
+ nor_dev.read_op.cmd.opcode = SPI_NOR_OP_READ;
+ nor_dev.read_op.cmd.buswidth = SPI_MEM_BUSWIDTH_1_LINE;
+ nor_dev.read_op.addr.nbytes = 3U;
+ nor_dev.read_op.addr.buswidth = SPI_MEM_BUSWIDTH_1_LINE;
+ nor_dev.read_op.data.buswidth = SPI_MEM_BUSWIDTH_1_LINE;
+ nor_dev.read_op.data.dir = SPI_MEM_DATA_IN;
+
+ if (plat_get_nor_data(&nor_dev) != 0) {
+ return -EINVAL;
+ }
+
+ assert(nor_dev.size != 0);
+
+ if (nor_dev.size > BANK_SIZE) {
+ nor_dev.flags |= SPI_NOR_USE_BANK;
+ }
+
+ *size = nor_dev.size;
+
+ ret = spi_nor_read_id(&id);
+ if (ret != 0) {
+ return ret;
+ }
+
+ if ((nor_dev.flags & SPI_NOR_USE_BANK) != 0U) {
+ switch (id) {
+ case SPANSION_ID:
+ nor_dev.bank_read_cmd = SPINOR_OP_BRRD;
+ nor_dev.bank_write_cmd = SPINOR_OP_BRWR;
+ break;
+ default:
+ nor_dev.bank_read_cmd = SPINOR_OP_RDEAR;
+ nor_dev.bank_write_cmd = SPINOR_OP_WREAR;
+ break;
+ }
+ }
+
+ if (nor_dev.read_op.data.buswidth == 4U) {
+ switch (id) {
+ case MACRONIX_ID:
+ INFO("Enable Macronix quad support\n");
+ ret = spi_nor_macronix_quad_enable();
+ break;
+ case MICRON_ID:
+ break;
+ default:
+ ret = spi_nor_quad_enable();
+ break;
+ }
+ }
+
+ if ((ret == 0) && ((nor_dev.flags & SPI_NOR_USE_BANK) != 0U)) {
+ ret = spi_nor_read_bar();
+ }
+
+ return ret;
+}
diff --git a/drivers/mtd/spi-mem/spi_mem.c b/drivers/mtd/spi-mem/spi_mem.c
new file mode 100644
index 000000000..63ea7699b
--- /dev/null
+++ b/drivers/mtd/spi-mem/spi_mem.c
@@ -0,0 +1,288 @@
+/*
+ * Copyright (c) 2019, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <libfdt.h>
+
+#include <drivers/spi_mem.h>
+#include <lib/utils_def.h>
+
+#define SPI_MEM_DEFAULT_SPEED_HZ 100000U
+
+/*
+ * struct spi_slave - Representation of a SPI slave.
+ *
+ * @max_hz: Maximum speed for this slave in Hertz.
+ * @cs: ID of the chip select connected to the slave.
+ * @mode: SPI mode to use for this slave (see SPI mode flags).
+ * @ops: Ops defined by the bus.
+ */
+struct spi_slave {
+ unsigned int max_hz;
+ unsigned int cs;
+ unsigned int mode;
+ const struct spi_bus_ops *ops;
+};
+
+static struct spi_slave spi_slave;
+
+static bool spi_mem_check_buswidth_req(uint8_t buswidth, bool tx)
+{
+ switch (buswidth) {
+ case 1U:
+ return true;
+
+ case 2U:
+ if ((tx && (spi_slave.mode & (SPI_TX_DUAL | SPI_TX_QUAD)) !=
+ 0U) ||
+ (!tx && (spi_slave.mode & (SPI_RX_DUAL | SPI_RX_QUAD)) !=
+ 0U)) {
+ return true;
+ }
+ break;
+
+ case 4U:
+ if ((tx && (spi_slave.mode & SPI_TX_QUAD) != 0U) ||
+ (!tx && (spi_slave.mode & SPI_RX_QUAD) != 0U)) {
+ return true;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return false;
+}
+
+static bool spi_mem_supports_op(const struct spi_mem_op *op)
+{
+ if (!spi_mem_check_buswidth_req(op->cmd.buswidth, true)) {
+ return false;
+ }
+
+ if ((op->addr.nbytes != 0U) &&
+ !spi_mem_check_buswidth_req(op->addr.buswidth, true)) {
+ return false;
+ }
+
+ if ((op->dummy.nbytes != 0U) &&
+ !spi_mem_check_buswidth_req(op->dummy.buswidth, true)) {
+ return false;
+ }
+
+ if ((op->data.nbytes != 0U) &&
+ !spi_mem_check_buswidth_req(op->data.buswidth,
+ op->data.dir == SPI_MEM_DATA_OUT)) {
+ return false;
+ }
+
+ return true;
+}
+
+static int spi_mem_set_speed_mode(void)
+{
+ const struct spi_bus_ops *ops = spi_slave.ops;
+ int ret;
+
+ ret = ops->set_speed(spi_slave.max_hz);
+ if (ret != 0) {
+ VERBOSE("Cannot set speed (err=%d)\n", ret);
+ return ret;
+ }
+
+ ret = ops->set_mode(spi_slave.mode);
+ if (ret != 0) {
+ VERBOSE("Cannot set mode (err=%d)\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int spi_mem_check_bus_ops(const struct spi_bus_ops *ops)
+{
+ bool error = false;
+
+ if (ops->claim_bus == NULL) {
+ VERBOSE("Ops claim bus is not defined\n");
+ error = true;
+ }
+
+ if (ops->release_bus == NULL) {
+ VERBOSE("Ops release bus is not defined\n");
+ error = true;
+ }
+
+ if (ops->exec_op == NULL) {
+ VERBOSE("Ops exec op is not defined\n");
+ error = true;
+ }
+
+ if (ops->set_speed == NULL) {
+ VERBOSE("Ops set speed is not defined\n");
+ error = true;
+ }
+
+ if (ops->set_mode == NULL) {
+ VERBOSE("Ops set mode is not defined\n");
+ error = true;
+ }
+
+ return error ? -EINVAL : 0;
+}
+
+/*
+ * spi_mem_exec_op() - Execute a memory operation.
+ * @op: The memory operation to execute.
+ *
+ * This function first checks that @op is supported and then tries to execute
+ * it.
+ *
+ * Return: 0 in case of success, a negative error code otherwise.
+ */
+int spi_mem_exec_op(const struct spi_mem_op *op)
+{
+ const struct spi_bus_ops *ops = spi_slave.ops;
+ int ret;
+
+ VERBOSE("%s: cmd:%x mode:%d.%d.%d.%d addqr:%llx len:%x\n",
+ __func__, op->cmd.opcode, op->cmd.buswidth, op->addr.buswidth,
+ op->dummy.buswidth, op->data.buswidth,
+ op->addr.val, op->data.nbytes);
+
+ if (!spi_mem_supports_op(op)) {
+ WARN("Error in spi_mem_support\n");
+ return -ENOTSUP;
+ }
+
+ ret = ops->claim_bus(spi_slave.cs);
+ if (ret != 0) {
+ WARN("Error claim_bus\n");
+ return ret;
+ }
+
+ ret = ops->exec_op(op);
+
+ ops->release_bus();
+
+ return ret;
+}
+
+/*
+ * spi_mem_init_slave() - SPI slave device initialization.
+ * @fdt: Pointer to the device tree blob.
+ * @bus_node: Offset of the bus node.
+ * @ops: The SPI bus ops defined.
+ *
+ * This function first checks that @ops are supported and then tries to find
+ * a SPI slave device.
+ *
+ * Return: 0 in case of success, a negative error code otherwise.
+ */
+int spi_mem_init_slave(void *fdt, int bus_node, const struct spi_bus_ops *ops)
+{
+ int ret;
+ int mode = 0;
+ int nchips = 0;
+ int bus_subnode = 0;
+ const fdt32_t *cuint = NULL;
+
+ ret = spi_mem_check_bus_ops(ops);
+ if (ret != 0) {
+ return ret;
+ }
+
+ fdt_for_each_subnode(bus_subnode, fdt, bus_node) {
+ nchips++;
+ }
+
+ if (nchips != 1) {
+ ERROR("Only one SPI device is currently supported\n");
+ return -EINVAL;
+ }
+
+ fdt_for_each_subnode(bus_subnode, fdt, bus_node) {
+ /* Get chip select */
+ cuint = fdt_getprop(fdt, bus_subnode, "reg", NULL);
+ if (cuint == NULL) {
+ ERROR("Chip select not well defined\n");
+ return -EINVAL;
+ }
+ spi_slave.cs = fdt32_to_cpu(*cuint);
+
+ /* Get max slave frequency */
+ spi_slave.max_hz = SPI_MEM_DEFAULT_SPEED_HZ;
+ cuint = fdt_getprop(fdt, bus_subnode,
+ "spi-max-frequency", NULL);
+ if (cuint != NULL) {
+ spi_slave.max_hz = fdt32_to_cpu(*cuint);
+ }
+
+ /* Get mode */
+ if ((fdt_getprop(fdt, bus_subnode, "spi-cpol", NULL)) != NULL) {
+ mode |= SPI_CPOL;
+ }
+ if ((fdt_getprop(fdt, bus_subnode, "spi-cpha", NULL)) != NULL) {
+ mode |= SPI_CPHA;
+ }
+ if ((fdt_getprop(fdt, bus_subnode, "spi-cs-high", NULL)) !=
+ NULL) {
+ mode |= SPI_CS_HIGH;
+ }
+ if ((fdt_getprop(fdt, bus_subnode, "spi-3wire", NULL)) !=
+ NULL) {
+ mode |= SPI_3WIRE;
+ }
+ if ((fdt_getprop(fdt, bus_subnode, "spi-half-duplex", NULL)) !=
+ NULL) {
+ mode |= SPI_PREAMBLE;
+ }
+
+ /* Get dual/quad mode */
+ cuint = fdt_getprop(fdt, bus_subnode, "spi-tx-bus-width", NULL);
+ if (cuint != NULL) {
+ switch (fdt32_to_cpu(*cuint)) {
+ case 1U:
+ break;
+ case 2U:
+ mode |= SPI_TX_DUAL;
+ break;
+ case 4U:
+ mode |= SPI_TX_QUAD;
+ break;
+ default:
+ WARN("spi-tx-bus-width %d not supported\n",
+ fdt32_to_cpu(*cuint));
+ return -EINVAL;
+ }
+ }
+
+ cuint = fdt_getprop(fdt, bus_subnode, "spi-rx-bus-width", NULL);
+ if (cuint != NULL) {
+ switch (fdt32_to_cpu(*cuint)) {
+ case 1U:
+ break;
+ case 2U:
+ mode |= SPI_RX_DUAL;
+ break;
+ case 4U:
+ mode |= SPI_RX_QUAD;
+ break;
+ default:
+ WARN("spi-rx-bus-width %d not supported\n",
+ fdt32_to_cpu(*cuint));
+ return -EINVAL;
+ }
+ }
+
+ spi_slave.mode = mode;
+ spi_slave.ops = ops;
+ }
+
+ return spi_mem_set_speed_mode();
+}
diff --git a/drivers/renesas/rcar/io/io_emmcdrv.c b/drivers/renesas/rcar/io/io_emmcdrv.c
index 4b464fb3e..84240d260 100644
--- a/drivers/renesas/rcar/io/io_emmcdrv.c
+++ b/drivers/renesas/rcar/io/io_emmcdrv.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, Renesas Electronics Corporation. All rights reserved.
+ * Copyright (c) 2015-2019, Renesas Electronics Corporation. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -25,7 +25,7 @@ static int32_t emmcdrv_dev_close(io_dev_info_t *dev_info);
typedef struct {
uint32_t in_use;
uintptr_t base;
- ssize_t file_pos;
+ signed long long file_pos;
EMMC_PARTITION_ID partition;
} file_state_t;
@@ -39,7 +39,7 @@ static io_type_t device_type_emmcdrv(void)
}
static int32_t emmcdrv_block_seek(io_entity_t *entity, int32_t mode,
- ssize_t offset)
+ signed long long offset)
{
if (mode != IO_SEEK_SET)
return IO_FAIL;
@@ -59,12 +59,12 @@ static int32_t emmcdrv_block_read(io_entity_t *entity, uintptr_t buffer,
sector_add = current_file.file_pos >> EMMC_SECTOR_SIZE_SHIFT;
sector_num = (length + EMMC_SECTOR_SIZE - 1U) >> EMMC_SECTOR_SIZE_SHIFT;
- NOTICE("BL2: Load dst=0x%lx src=(p:%d)0x%lx(%d) len=0x%lx(%d)\n",
+ NOTICE("BL2: Load dst=0x%lx src=(p:%d)0x%llx(%d) len=0x%lx(%d)\n",
buffer,
current_file.partition, current_file.file_pos,
sector_add, length, sector_num);
- if (buffer + length - 1 <= UINT32_MAX)
+ if ((buffer + length - 1U) <= (uintptr_t)UINT32_MAX)
emmc_dma = LOADIMAGE_FLAGS_DMA_ENABLE;
if (emmc_read_sector((uint32_t *) buffer, sector_add, sector_num,
@@ -72,7 +72,7 @@ static int32_t emmcdrv_block_read(io_entity_t *entity, uintptr_t buffer,
result = IO_FAIL;
*length_read = length;
- fp->file_pos += length;
+ fp->file_pos += (signed long long)length;
return result;
}
@@ -82,7 +82,7 @@ static int32_t emmcdrv_block_open(io_dev_info_t *dev_info,
{
const io_drv_spec_t *block_spec = (io_drv_spec_t *) spec;
- if (current_file.in_use) {
+ if (current_file.in_use != 0U) {
WARN("mmc_block: Only one open spec at a time\n");
return IO_RESOURCES_EXHAUSTED;
}
@@ -103,9 +103,9 @@ static int32_t emmcdrv_block_open(io_dev_info_t *dev_info,
return IO_FAIL;
}
- if (PARTITION_ID_USER == block_spec->partition ||
- PARTITION_ID_BOOT_1 == block_spec->partition ||
- PARTITION_ID_BOOT_2 == block_spec->partition)
+ if ((PARTITION_ID_USER == block_spec->partition) ||
+ (PARTITION_ID_BOOT_1 == block_spec->partition) ||
+ (PARTITION_ID_BOOT_2 == block_spec->partition))
current_file.partition = block_spec->partition;
else
current_file.partition = emmcdrv_bootpartition;
diff --git a/drivers/renesas/rcar/io/io_memdrv.c b/drivers/renesas/rcar/io/io_memdrv.c
index 3f6b4c71b..7e8c1d3a6 100644
--- a/drivers/renesas/rcar/io/io_memdrv.c
+++ b/drivers/renesas/rcar/io/io_memdrv.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2018, Renesas Electronics Corporation. All rights reserved.
+ * Copyright (c) 2015-2019, Renesas Electronics Corporation. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -28,7 +28,7 @@ static int32_t memdrv_dev_close(io_dev_info_t *dev_info);
typedef struct {
uint32_t in_use;
uintptr_t base;
- ssize_t file_pos;
+ signed long long file_pos;
} file_state_t;
static file_state_t current_file = { 0 };
@@ -47,7 +47,7 @@ static int32_t memdrv_block_open(io_dev_info_t *dev_info, const uintptr_t spec,
* spec at a time. When we have dynamic memory we can malloc and set
* entity->info.
*/
- if (current_file.in_use)
+ if (current_file.in_use != 0U)
return IO_RESOURCES_EXHAUSTED;
/* File cursor offset for seek and incremental reads etc. */
@@ -61,7 +61,7 @@ static int32_t memdrv_block_open(io_dev_info_t *dev_info, const uintptr_t spec,
}
static int32_t memdrv_block_seek(io_entity_t *entity, int32_t mode,
- ssize_t offset)
+ signed long long offset)
{
if (mode != IO_SEEK_SET)
return IO_FAIL;
@@ -78,16 +78,17 @@ static int32_t memdrv_block_read(io_entity_t *entity, uintptr_t buffer,
fp = (file_state_t *) entity->info;
- NOTICE("BL2: dst=0x%lx src=0x%lx len=%ld(0x%lx)\n",
- buffer, fp->base + fp->file_pos, length, length);
+ NOTICE("BL2: dst=0x%lx src=0x%llx len=%ld(0x%lx)\n",
+ buffer, (unsigned long long)fp->base +
+ (unsigned long long)fp->file_pos, length, length);
- if (FLASH_MEMORY_SIZE < fp->file_pos + length) {
+ if (FLASH_MEMORY_SIZE < (fp->file_pos + (signed long long)length)) {
ERROR("BL2: check load image (source address)\n");
return IO_FAIL;
}
- rcar_dma_exec(buffer, fp->base + fp->file_pos, length);
- fp->file_pos += length;
+ rcar_dma_exec(buffer, fp->base + (uintptr_t)fp->file_pos, length);
+ fp->file_pos += (signed long long)length;
*cnt = length;
return IO_SUCCESS;
diff --git a/drivers/st/bsec/bsec.c b/drivers/st/bsec/bsec2.c
similarity index 65%
rename from drivers/st/bsec/bsec.c
rename to drivers/st/bsec/bsec2.c
index 01c369edc..9777e6721 100644
--- a/drivers/st/bsec/bsec.c
+++ b/drivers/st/bsec/bsec2.c
@@ -14,11 +14,12 @@
#include <arch_helpers.h>
#include <common/debug.h>
#include <drivers/st/bsec.h>
+#include <drivers/st/bsec2_reg.h>
#include <lib/mmio.h>
#include <lib/spinlock.h>
-#define BSEC_IP_VERSION_1_0 0x10
-#define BSEC_COMPAT "st,stm32mp15-bsec"
+#define BSEC_IP_VERSION_1_1 U(0x11)
+#define BSEC_IP_ID_2 U(0x100032)
#define OTP_ACCESS_SIZE (round_up(OTP_MAX_SIZE, __WORD_BIT) / __WORD_BIT)
@@ -48,7 +49,7 @@ static int bsec_get_dt_node(struct dt_node_info *info)
{
int node;
- node = dt_get_node(info, -1, BSEC_COMPAT);
+ node = dt_get_node(info, -1, DT_BSEC_COMPAT);
if (node < 0) {
return -FDT_ERR_NOTFOUND;
}
@@ -78,33 +79,59 @@ static int bsec_dt_otp_nsec_access(void *fdt, int bsec_node)
fdt_for_each_subnode(bsec_subnode, fdt, bsec_node) {
const fdt32_t *cuint;
- uint32_t reg;
+ uint32_t otp;
uint32_t i;
uint32_t size;
- uint8_t status;
+ uint32_t offset;
+ uint32_t length;
cuint = fdt_getprop(fdt, bsec_subnode, "reg", NULL);
if (cuint == NULL) {
panic();
}
- reg = fdt32_to_cpu(*cuint) / sizeof(uint32_t);
- if (reg < STM32MP1_UPPER_OTP_START) {
- continue;
+ offset = fdt32_to_cpu(*cuint);
+ cuint++;
+ length = fdt32_to_cpu(*cuint);
+
+ otp = offset / sizeof(uint32_t);
+
+ if (otp < STM32MP1_UPPER_OTP_START) {
+ unsigned int otp_end = round_up(offset + length,
+ sizeof(uint32_t)) /
+ sizeof(uint32_t);
+
+ if (otp_end > STM32MP1_UPPER_OTP_START) {
+ /*
+ * OTP crosses Lower/Upper boundary, consider
+ * only the upper part.
+ */
+ otp = STM32MP1_UPPER_OTP_START;
+ length -= (STM32MP1_UPPER_OTP_START *
+ sizeof(uint32_t)) - offset;
+ offset = STM32MP1_UPPER_OTP_START *
+ sizeof(uint32_t);
+
+ WARN("OTP crosses Lower/Upper boundary\n");
+ } else {
+ continue;
+ }
}
- status = fdt_get_status(bsec_subnode);
- if ((status & DT_NON_SECURE) == 0U) {
+ if ((fdt_getprop(fdt, bsec_subnode,
+ "st,non-secure-otp", NULL)) == NULL) {
continue;
}
- size = fdt32_to_cpu(*(cuint + 1)) / sizeof(uint32_t);
-
- if ((fdt32_to_cpu(*(cuint + 1)) % sizeof(uint32_t)) != 0) {
- size++;
+ if (((offset % sizeof(uint32_t)) != 0) ||
+ ((length % sizeof(uint32_t)) != 0)) {
+ ERROR("Unaligned non-secure OTP\n");
+ panic();
}
- for (i = reg; i < (reg + size); i++) {
+ size = length / sizeof(uint32_t);
+
+ for (i = otp; i < (otp + size); i++) {
enable_non_secure_access(i);
}
}
@@ -121,19 +148,30 @@ static uint32_t otp_bank_offset(uint32_t otp)
sizeof(uint32_t);
}
-static uint32_t bsec_check_error(uint32_t otp)
+/*
+ * bsec_check_error: check BSEC error status.
+ * otp: OTP number.
+ * check_disturbed: check only error (false),
+ * or error and disturbed status (true).
+ * return value: BSEC_OK if no error.
+ */
+static uint32_t bsec_check_error(uint32_t otp, bool check_disturbed)
{
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;
}
+ if (!check_disturbed) {
+ return BSEC_OK;
+ }
+
+ if ((mmio_read_32(bsec_base + BSEC_DISTURBED_OFF + bank) & bit) != 0U) {
+ return BSEC_DISTURBED;
+ }
+
return BSEC_OK;
}
@@ -158,6 +196,11 @@ uint32_t bsec_probe(void)
bsec_base = bsec_info.base;
+ if (((bsec_get_version() & BSEC_IPVR_MSK) != BSEC_IP_VERSION_1_1) ||
+ (bsec_get_id() != BSEC_IP_ID_2)) {
+ panic();
+ }
+
#if defined(IMAGE_BL32)
bsec_dt_otp_nsec_access(fdt, node);
#endif
@@ -251,6 +294,79 @@ uint32_t bsec_get_config(struct bsec_config *cfg)
return BSEC_OK;
}
+/*
+ * bsec_find_otp_name_in_dt: get OTP ID and length in DT.
+ * name: sub-node name to look up.
+ * otp: pointer to read OTP number or NULL.
+ * otp_len: pointer to read OTP length in bits or NULL.
+ * return value: BSEC_OK if no error.
+ */
+uint32_t bsec_find_otp_name_in_dt(const char *name, uint32_t *otp,
+ uint32_t *otp_len)
+{
+ void *fdt;
+ int node;
+ int index, len;
+ const fdt32_t *cuint;
+
+ if ((name == NULL) || (otp == NULL)) {
+ return BSEC_INVALID_PARAM;
+ }
+
+ if (fdt_get_address(&fdt) == 0) {
+ panic();
+ }
+
+ node = dt_get_node_by_compatible(DT_NVMEM_LAYOUT_COMPAT);
+ if (node < 0) {
+ return BSEC_ERROR;
+ }
+
+ index = fdt_stringlist_search(fdt, node, "nvmem-cell-names", name);
+ if (index < 0) {
+ return BSEC_ERROR;
+ }
+
+ cuint = fdt_getprop(fdt, node, "nvmem-cells", &len);
+ if (cuint == NULL) {
+ return BSEC_ERROR;
+ }
+
+ if ((index * (int)sizeof(uint32_t)) > len) {
+ return BSEC_ERROR;
+ }
+
+ cuint += index;
+
+ node = fdt_node_offset_by_phandle(fdt, fdt32_to_cpu(*cuint));
+ if (node < 0) {
+ ERROR("Malformed nvmem_layout node: ignored\n");
+ return BSEC_ERROR;
+ }
+
+ cuint = fdt_getprop(fdt, node, "reg", &len);
+ if ((cuint == NULL) || (len != (2 * (int)sizeof(uint32_t)))) {
+ ERROR("Malformed nvmem_layout node: ignored\n");
+ return BSEC_ERROR;
+ }
+
+ if (fdt32_to_cpu(*cuint) % sizeof(uint32_t)) {
+ ERROR("Misaligned nvmem_layout element: ignored\n");
+ return BSEC_ERROR;
+ }
+
+ if (otp != NULL) {
+ *otp = fdt32_to_cpu(*cuint) / sizeof(uint32_t);
+ }
+
+ if (otp_len != NULL) {
+ cuint++;
+ *otp_len = fdt32_to_cpu(*cuint) * CHAR_BIT;
+ }
+
+ return BSEC_OK;
+}
+
/*
* bsec_shadow_register: copy SAFMEM OTP to BSEC data.
* otp: OTP number.
@@ -259,14 +375,16 @@ uint32_t bsec_get_config(struct bsec_config *cfg)
uint32_t bsec_shadow_register(uint32_t otp)
{
uint32_t result;
+ bool value;
bool power_up = false;
- if (otp > STM32MP1_OTP_MAX_ID) {
- return BSEC_INVALID_PARAM;
+ result = bsec_read_sr_lock(otp, &value);
+ if (result != BSEC_OK) {
+ ERROR("BSEC: %u Sticky-read bit read Error %i\n", otp, result);
+ return result;
}
- /* Check if shadowing of OTP is locked */
- if (bsec_read_sr_lock(otp)) {
+ if (value) {
VERBOSE("BSEC: OTP %i is locked and will not be refreshed\n",
otp);
}
@@ -283,14 +401,13 @@ uint32_t bsec_shadow_register(uint32_t otp)
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);
+ result = bsec_check_error(otp, true);
bsec_unlock();
@@ -311,22 +428,14 @@ uint32_t bsec_shadow_register(uint32_t otp)
*/
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;
+ return BSEC_OK;
}
/*
@@ -338,24 +447,25 @@ uint32_t bsec_read_otp(uint32_t *val, uint32_t otp)
uint32_t bsec_write_otp(uint32_t val, uint32_t otp)
{
uint32_t result;
+ bool value;
- if (otp > STM32MP1_OTP_MAX_ID) {
- return BSEC_INVALID_PARAM;
+ result = bsec_read_sw_lock(otp, &value);
+ if (result != BSEC_OK) {
+ ERROR("BSEC: %u Sticky-write bit read Error %i\n", otp, result);
+ return result;
}
- /* Check if programming of OTP is locked */
- if (bsec_read_sw_lock(otp)) {
+ if (value) {
VERBOSE("BSEC: OTP %i is locked and write will be ignored\n",
otp);
}
+ /* Ensure integrity of each register access sequence */
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;
@@ -372,14 +482,23 @@ uint32_t bsec_program_otp(uint32_t val, uint32_t otp)
{
uint32_t result;
bool power_up = false;
+ bool sp_lock, perm_lock;
- if (otp > STM32MP1_OTP_MAX_ID) {
- return BSEC_INVALID_PARAM;
+ result = bsec_read_sp_lock(otp, &sp_lock);
+ if (result != BSEC_OK) {
+ ERROR("BSEC: %u Sticky-prog bit read Error %i\n", otp, result);
+ return result;
}
- /* Check if programming of OTP is locked */
- if (bsec_read_sp_lock(otp)) {
+ result = bsec_read_permanent_lock(otp, &perm_lock);
+ if (result != BSEC_OK) {
+ ERROR("BSEC: %u permanent bit read Error %i\n", otp, result);
+ return result;
+ }
+
+ if (sp_lock || perm_lock) {
WARN("BSEC: OTP locked, prog will be ignored\n");
+ return BSEC_PROG_FAIL;
}
if ((mmio_read_32(bsec_base + BSEC_OTP_LOCK_OFF) &
@@ -399,10 +518,8 @@ uint32_t bsec_program_otp(uint32_t val, uint32_t otp)
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) {
@@ -412,7 +529,7 @@ uint32_t bsec_program_otp(uint32_t val, uint32_t otp)
if ((bsec_get_status() & BSEC_MODE_PROGFAIL_MASK) != 0U) {
result = BSEC_PROG_FAIL;
} else {
- result = bsec_check_error(otp);
+ result = bsec_check_error(otp, true);
}
bsec_unlock();
@@ -464,10 +581,8 @@ uint32_t bsec_permanent_lock_otp(uint32_t otp)
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);
@@ -478,7 +593,7 @@ uint32_t bsec_permanent_lock_otp(uint32_t otp)
if ((bsec_get_status() & BSEC_MODE_PROGFAIL_MASK) != 0U) {
result = BSEC_PROG_FAIL;
} else {
- result = bsec_check_error(otp);
+ result = bsec_check_error(otp, false);
}
bsec_unlock();
@@ -493,7 +608,7 @@ uint32_t bsec_permanent_lock_otp(uint32_t otp)
}
/*
- * bsec_write_debug_conf: write value in debug feature
+ * 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.
@@ -517,7 +632,7 @@ uint32_t bsec_write_debug_conf(uint32_t val)
}
/*
- * bsec_read_debug_conf: read debug configuration.
+ * bsec_read_debug_conf: return debug configuration register value.
*/
uint32_t bsec_read_debug_conf(void)
{
@@ -533,7 +648,7 @@ uint32_t bsec_get_status(void)
}
/*
- * bsec_get_hw_conf: return hardware configuration.
+ * bsec_get_hw_conf: return hardware configuration register value.
*/
uint32_t bsec_get_hw_conf(void)
{
@@ -541,7 +656,7 @@ uint32_t bsec_get_hw_conf(void)
}
/*
- * bsec_get_version: return BSEC version.
+ * bsec_get_version: return BSEC version register value.
*/
uint32_t bsec_get_version(void)
{
@@ -549,7 +664,7 @@ uint32_t bsec_get_version(void)
}
/*
- * bsec_get_id: return BSEC ID.
+ * bsec_get_id: return BSEC ID register value.
*/
uint32_t bsec_get_id(void)
{
@@ -557,7 +672,7 @@ uint32_t bsec_get_id(void)
}
/*
- * bsec_get_magic_id: return BSEC magic number.
+ * bsec_get_magic_id: return BSEC magic number register value.
*/
uint32_t bsec_get_magic_id(void)
{
@@ -565,229 +680,178 @@ uint32_t bsec_get_magic_id(void)
}
/*
- * bsec_write_sr_lock: write shadow-read lock.
+ * bsec_set_sr_lock: set 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.
+ * return value: BSEC_OK if no error.
*/
-bool bsec_write_sr_lock(uint32_t otp, uint32_t value)
+uint32_t bsec_set_sr_lock(uint32_t otp)
{
- 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;
+ if (otp > STM32MP1_OTP_MAX_ID) {
+ return BSEC_INVALID_PARAM;
}
+ bsec_lock();
+ mmio_write_32(bsec_base + BSEC_SRLOCK_OFF + bank, otp_mask);
bsec_unlock();
- return result;
+ return BSEC_OK;
}
/*
* bsec_read_sr_lock: read shadow-read lock.
* otp: OTP number.
- * return: true if otp is locked, else false.
+ * value: read value (true or false).
+ * return value: BSEC_OK if no error.
*/
-bool bsec_read_sr_lock(uint32_t otp)
+uint32_t bsec_read_sr_lock(uint32_t otp, bool *value)
{
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);
+ uint32_t bank_value;
- return (bank_value & otp_mask) != 0U;
+ if (otp > STM32MP1_OTP_MAX_ID) {
+ return BSEC_INVALID_PARAM;
+ }
+
+ bank_value = mmio_read_32(bsec_base + BSEC_SRLOCK_OFF + bank);
+
+ *value = ((bank_value & otp_mask) != 0U);
+
+ return BSEC_OK;
}
/*
- * bsec_write_sw_lock: write shadow-write lock.
+ * bsec_set_sw_lock: set 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.
+ * return value: BSEC_OK if no error.
*/
-bool bsec_write_sw_lock(uint32_t otp, uint32_t value)
+uint32_t bsec_set_sw_lock(uint32_t otp)
{
- 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;
+ if (otp > STM32MP1_OTP_MAX_ID) {
+ return BSEC_INVALID_PARAM;
}
+ bsec_lock();
+ mmio_write_32(bsec_base + BSEC_SWLOCK_OFF + bank, otp_mask);
bsec_unlock();
- return result;
+ return BSEC_OK;
}
/*
* bsec_read_sw_lock: read shadow-write lock.
* otp: OTP number.
- * return: true if OTP is locked, else false.
+ * value: read value (true or false).
+ * return value: BSEC_OK if no error.
*/
-bool bsec_read_sw_lock(uint32_t otp)
+uint32_t bsec_read_sw_lock(uint32_t otp, bool *value)
{
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);
+ uint32_t bank_value;
- return (bank_value & otp_mask) != 0U;
+ if (otp > STM32MP1_OTP_MAX_ID) {
+ return BSEC_INVALID_PARAM;
+ }
+
+ bank_value = mmio_read_32(bsec_base + BSEC_SWLOCK_OFF + bank);
+
+ *value = ((bank_value & otp_mask) != 0U);
+
+ return BSEC_OK;
}
/*
- * bsec_write_sp_lock: write shadow-program lock.
+ * bsec_set_sp_lock: set 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.
+ * return value: BSEC_OK if no error.
*/
-bool bsec_write_sp_lock(uint32_t otp, uint32_t value)
+uint32_t bsec_set_sp_lock(uint32_t otp)
{
- 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;
+ if (otp > STM32MP1_OTP_MAX_ID) {
+ return BSEC_INVALID_PARAM;
}
+ bsec_lock();
+ mmio_write_32(bsec_base + BSEC_SPLOCK_OFF + bank, otp_mask);
bsec_unlock();
- return result;
+ return BSEC_OK;
}
/*
* bsec_read_sp_lock: read shadow-program lock.
* otp: OTP number.
- * return: true if OTP is locked, else false.
+ * value: read value (true or false).
+ * return value: BSEC_OK if no error.
*/
-bool bsec_read_sp_lock(uint32_t otp)
+uint32_t bsec_read_sp_lock(uint32_t otp, bool *value)
{
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);
+ uint32_t bank_value;
- return (bank_value & otp_mask) != 0U;
+ if (otp > STM32MP1_OTP_MAX_ID) {
+ return BSEC_INVALID_PARAM;
+ }
+
+ bank_value = mmio_read_32(bsec_base + BSEC_SPLOCK_OFF + bank);
+
+ *value = ((bank_value & otp_mask) != 0U);
+
+ return BSEC_OK;
}
/*
- * bsec_wr_lock: Read permanent lock status.
+ * bsec_read_permanent_lock: Read permanent lock status.
* otp: OTP number.
- * return: true if OTP is locked, else false.
+ * value: read value (true or false).
+ * return value: BSEC_OK if no error.
*/
-bool bsec_wr_lock(uint32_t otp)
+uint32_t bsec_read_permanent_lock(uint32_t otp, bool *value)
{
uint32_t bank = otp_bank_offset(otp);
- uint32_t lock_bit = BIT(otp & BSEC_OTP_MASK);
+ uint32_t otp_mask = BIT(otp & BSEC_OTP_MASK);
+ uint32_t bank_value;
- 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;
+ if (otp > STM32MP1_OTP_MAX_ID) {
+ return BSEC_INVALID_PARAM;
}
- return false;
+ bank_value = mmio_read_32(bsec_base + BSEC_WRLOCK_OFF + bank);
+
+ *value = ((bank_value & otp_mask) != 0U);
+
+ return BSEC_OK;
}
/*
- * 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.
+ * bsec_otp_lock: Lock Upper OTP or Global Programming or Debug Enable.
+ * service: Service to lock, see header file.
+ * return value: BSEC_OK if no error.
*/
-uint32_t bsec_otp_lock(uint32_t service, uint32_t value)
+uint32_t bsec_otp_lock(uint32_t service)
{
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);
+ mmio_write_32(reg, BIT(BSEC_LOCK_UPPER_OTP));
break;
case BSEC_LOCK_DEBUG:
- mmio_write_32(reg, value << BSEC_LOCK_DEBUG);
+ mmio_write_32(reg, BIT(BSEC_LOCK_DEBUG));
break;
case BSEC_LOCK_PROGRAM:
- mmio_write_32(reg, value << BSEC_LOCK_PROGRAM);
+ mmio_write_32(reg, BIT(BSEC_LOCK_PROGRAM));
break;
default:
return BSEC_INVALID_PARAM;
@@ -799,7 +863,7 @@ uint32_t bsec_otp_lock(uint32_t service, uint32_t value)
/*
* bsec_power_safmem: Activate or deactivate SAFMEM power.
* power: true to power up, false to power down.
- * return: BSEC_OK if succeed.
+ * return value: BSEC_OK if no error.
*/
static uint32_t bsec_power_safmem(bool power)
{
@@ -818,7 +882,6 @@ static uint32_t bsec_power_safmem(bool power)
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)) {
@@ -841,7 +904,7 @@ static uint32_t bsec_power_safmem(bool power)
}
/*
- * bsec_shadow_read_otp: Load OTP from SAFMEM and provide its value
+ * 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.
@@ -867,7 +930,7 @@ uint32_t bsec_shadow_read_otp(uint32_t *otp_value, uint32_t word)
/*
* bsec_check_nsec_access_rights: check non-secure access rights to target OTP.
* otp: OTP number.
- * return: BSEC_OK if authorized access.
+ * return value: BSEC_OK if authorized access.
*/
uint32_t bsec_check_nsec_access_rights(uint32_t otp)
{
@@ -877,11 +940,8 @@ uint32_t bsec_check_nsec_access_rights(uint32_t otp)
}
if (otp >= STM32MP1_UPPER_OTP_START) {
- /* Check if BSEC is in OTP-SECURED closed_device state. */
- if (stm32mp_is_closed_device()) {
- if (!non_secure_can_access(otp)) {
- return BSEC_ERROR;
- }
+ if (!non_secure_can_access(otp)) {
+ return BSEC_ERROR;
}
}
#endif
diff --git a/drivers/st/clk/stm32mp1_calib.c b/drivers/st/clk/stm32mp1_calib.c
new file mode 100644
index 000000000..b764c971c
--- /dev/null
+++ b/drivers/st/clk/stm32mp1_calib.c
@@ -0,0 +1,529 @@
+/*
+ * Copyright (C) 2019, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdint.h>
+#include <stdio.h>
+
+#include <libfdt.h>
+
+#include <platform_def.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <drivers/generic_delay_timer.h>
+#include <drivers/st/stm32_timer.h>
+#include <drivers/st/stm32mp_clkfunc.h>
+#include <lib/mmio.h>
+#include <lib/spinlock.h>
+#include <lib/utils_def.h>
+#include <plat/common/platform.h>
+
+#define TIMEOUT_10MS 10000
+#define CALIB_TIMEOUT TIMEOUT_10MS
+
+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_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];
+};
+
+/* RCC Wakeup status */
+static bool rcc_wakeup;
+
+/* 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
+};
+
+/* List of forbiden values for CSI */
+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 = 5,
+ .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 = 8,
+ .set_trim = csi_set_trim,
+ .get_trim = csi_get_trimed_cal,
+};
+
+static uint32_t timer_val;
+
+/*
+ * HSI Calibration part
+ */
+static int get_signed_value(uint8_t val)
+{
+ return ((int8_t)(val << 1)) >> 1;
+}
+
+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 = get_signed_value((uint8_t)utrim);
+
+ 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;
+
+ 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 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) / 1000);
+ unsigned long max = clk_cal->ref_freq +
+ ((clk_cal->ref_freq * clk_cal->freq_margin) / 1000);
+ int trim, new_trim;
+ unsigned long conv;
+ unsigned long min_conv = ULONG_MAX;
+ uint64_t start;
+
+ if ((freq >= min) && (freq <= max)) {
+ return;
+ }
+
+ trim = clk_cal->get_trim();
+ start = timeout_init_us(CALIB_TIMEOUT);
+ do {
+ if (freq < clk_cal->ref_freq) {
+ new_trim = trim_increase(clk_cal, trim);
+ } else {
+ new_trim = trim_decrease(clk_cal, trim);
+ }
+
+ clk_cal->set_trim(new_trim);
+ freq = clk_cal->get_freq();
+ if (freq == 0U) {
+ /* Calibration will be stopped */
+ clk_cal->ref_freq = 0U;
+ return;
+ }
+ conv = (clk_cal->ref_freq < freq) ?
+ freq - clk_cal->ref_freq : clk_cal->ref_freq - freq;
+ if (conv < min_conv) {
+ min_conv = conv;
+ trim = new_trim;
+ }
+
+ if (timeout_elapsed(start)) {
+ break;
+ }
+
+ } while (conv == min_conv);
+
+ clk_cal->set_trim(trim);
+ freq = clk_cal->get_freq();
+
+ if ((freq < min) || (freq > max)) {
+ ERROR("%s Calibration : Freq %lu, trim %i\n",
+ (clk_cal->set_trim == hsi_set_trim) ? "HSI" : "CSI",
+ freq, trim);
+#if DEBUG
+ /*
+ * Show the steps around the selected trim value
+ * to correct the margin if needed
+ */
+ new_trim = trim_decrease(clk_cal, trim);
+ clk_cal->set_trim(new_trim);
+ ERROR("%s Calibration : Freq %lu, trim %i\n",
+ (clk_cal->set_trim == hsi_set_trim) ?
+ "HSI" : "CSI", clk_cal->get_freq(), new_trim);
+
+ new_trim = trim_increase(clk_cal, trim);
+ clk_cal->set_trim(new_trim);
+ ERROR("%s Calibration : Freq %lu, trim %i\n",
+ (clk_cal->set_trim == hsi_set_trim) ?
+ "HSI" : "CSI", clk_cal->get_freq(), new_trim);
+#endif
+ }
+}
+
+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_calib_get_wakeup(void)
+{
+ return rcc_wakeup;
+}
+
+void stm32mp1_calib_set_wakeup(bool state)
+{
+ rcc_wakeup = state;
+}
+
+void stm32mp1_calib_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_calib_set_wakeup(true);
+ return;
+
+ case STM32MP1_IRQ_MCU_SEV:
+ stm32mp1_calib_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) {
+ rcc_calibration(&stm32mp1_clk_cal_hsi);
+ }
+
+ if (stm32mp1_clk_cal_csi.ref_freq != 0U) {
+ rcc_calibration(&stm32mp1_clk_cal_csi);
+ }
+
+ if (timer_val != 0U) {
+ write_cntp_tval(timer_val);
+ }
+}
+
+int stm32mp1_calib_start_hsi_cal(void)
+{
+ if (stm32mp1_clk_cal_hsi.ref_freq == 0U) {
+ return -ENOENT;
+ }
+
+ rcc_calibration(&stm32mp1_clk_cal_hsi);
+ return 0;
+}
+
+int stm32mp1_calib_start_csi_cal(void)
+{
+ if (stm32mp1_clk_cal_csi.ref_freq == 0U) {
+ return -ENOENT;
+ }
+
+ 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);
+ if (stm32mp1_clk_cal_hsi.get_freq == NULL) {
+ return;
+ }
+
+ 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);
+
+ 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);
+ if (stm32mp1_clk_cal_csi.get_freq == NULL) {
+ return;
+ }
+
+ 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);
+
+ rcc_calibration(&stm32mp1_clk_cal_csi);
+}
+
+void stm32mp1_calib_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_cntp_tval(timer_val);
+ write_cntp_ctl(BIT(0));
+ };
+
+ if (fdt_rcc_enable_it("mcu_sev") < 0) {
+ VERBOSE("No MCU calibration\n");
+ }
+}
diff --git a/drivers/st/clk/stm32mp1_clk.c b/drivers/st/clk/stm32mp1_clk.c
index 0cc87cc71..5efe343b8 100644
--- a/drivers/st/clk/stm32mp1_clk.c
+++ b/drivers/st/clk/stm32mp1_clk.c
@@ -1,11 +1,12 @@
/*
- * Copyright (C) 2018-2019, STMicroelectronics - All Rights Reserved
+ * Copyright (C) 2018-2020, STMicroelectronics - All Rights Reserved
*
* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
*/
#include <assert.h>
#include <errno.h>
+#include <limits.h>
#include <stdint.h>
#include <stdio.h>
@@ -17,7 +18,7 @@
#include <arch_helpers.h>
#include <common/debug.h>
#include <drivers/delay_timer.h>
-#include <drivers/generic_delay_timer.h>
+#include <drivers/st/stm32_timer.h>
#include <drivers/st/stm32mp_clkfunc.h>
#include <drivers/st/stm32mp1_clk.h>
#include <drivers/st/stm32mp1_rcc.h>
@@ -48,6 +49,19 @@ const char *stm32mp_osc_node_label[NB_OSC] = {
[_I2S_CKIN] = "i2s_ckin",
};
+/* PLL settings computation related definitions */
+#define POST_DIVM_MIN 8000000
+#define POST_DIVM_MAX 16000000
+#define DIVM_MIN 0
+#define DIVM_MAX 63
+#define DIVN_MIN 24
+#define DIVN_MAX 99
+#define DIVP_MIN 0
+#define DIVP_MAX 127
+#define FRAC_MAX 8192
+#define VCO_MIN 800000000
+#define VCO_MAX 1600000000
+
enum stm32mp1_parent_id {
/* Oscillators are defined in enum stm32mp_osc_id */
@@ -105,10 +119,62 @@ enum stm32mp1_parent_sel {
_MCUS_SEL,
_USBPHY_SEL,
_USBO_SEL,
+ _RTC_SEL,
+ _MPU_SEL,
+ _PER_SEL,
_PARENT_SEL_NB,
_UNKNOWN_SEL = 0xff,
};
+/* State the parent clock ID straight related to a clock */
+static const uint8_t parent_id_clock_id[_PARENT_NB] = {
+ [_HSE] = CK_HSE,
+ [_HSI] = CK_HSI,
+ [_CSI] = CK_CSI,
+ [_LSE] = CK_LSE,
+ [_LSI] = CK_LSI,
+ [_I2S_CKIN] = _UNKNOWN_ID,
+ [_USB_PHY_48] = _UNKNOWN_ID,
+ [_HSI_KER] = CK_HSI,
+ [_HSE_KER] = CK_HSE,
+ [_HSE_KER_DIV2] = CK_HSE_DIV2,
+ [_CSI_KER] = CK_CSI,
+ [_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] = CK_AXI,
+ [_PCLK1] = CK_AXI,
+ [_PCLK2] = CK_AXI,
+ [_PCLK3] = CK_AXI,
+ [_PCLK4] = CK_AXI,
+ [_PCLK5] = CK_AXI,
+ [_CK_PER] = CK_PER,
+ [_CK_MPU] = CK_MPU,
+ [_CK_MCU] = CK_MCU,
+};
+
+static unsigned int clock_id2parent_id(unsigned long id)
+{
+ unsigned int n = 0;
+
+ for (n = 0; n < ARRAY_SIZE(parent_id_clock_id); n++) {
+ if (parent_id_clock_id[n] == id) {
+ return n;
+ }
+ }
+
+ return _UNKNOWN_ID;
+}
+
enum stm32mp1_pll_id {
_PLL1,
_PLL2,
@@ -186,6 +252,7 @@ struct stm32mp1_clk_gate {
uint8_t bit;
uint8_t index;
uint8_t set_clr;
+ uint8_t secure;
uint8_t sel; /* Relates to enum stm32mp1_parent_sel */
uint8_t fixed; /* Relates to enum stm32mp1_parent_id */
};
@@ -210,46 +277,59 @@ struct stm32mp1_clk_pll {
enum stm32mp_osc_id refclk[REFCLK_SIZE];
};
+/* Compact structure of 32bit cells, copied raw when suspending */
+struct stm32mp1_pll_settings {
+ uint32_t valid_id;
+ uint32_t freq[PLAT_MAX_OPP_NB];
+ uint32_t volt[PLAT_MAX_OPP_NB];
+ uint32_t cfg[PLAT_MAX_OPP_NB][PLAT_MAX_PLLCFG_NB];
+ uint32_t frac[PLAT_MAX_OPP_NB];
+};
+
/* Clocks with selectable source and non set/clr register access */
-#define _CLK_SELEC(off, b, idx, s) \
+#define _CLK_SELEC(sec, off, b, idx, s) \
{ \
.offset = (off), \
.bit = (b), \
.index = (idx), \
.set_clr = 0, \
+ .secure = (sec), \
.sel = (s), \
.fixed = _UNKNOWN_ID, \
}
/* Clocks with fixed source and non set/clr register access */
-#define _CLK_FIXED(off, b, idx, f) \
+#define _CLK_FIXED(sec, off, b, idx, f) \
{ \
.offset = (off), \
.bit = (b), \
.index = (idx), \
.set_clr = 0, \
+ .secure = (sec), \
.sel = _UNKNOWN_SEL, \
.fixed = (f), \
}
/* Clocks with selectable source and set/clr register access */
-#define _CLK_SC_SELEC(off, b, idx, s) \
+#define _CLK_SC_SELEC(sec, off, b, idx, s) \
{ \
.offset = (off), \
.bit = (b), \
.index = (idx), \
.set_clr = 1, \
+ .secure = (sec), \
.sel = (s), \
.fixed = _UNKNOWN_ID, \
}
/* Clocks with fixed source and set/clr register access */
-#define _CLK_SC_FIXED(off, b, idx, f) \
+#define _CLK_SC_FIXED(sec, off, b, idx, f) \
{ \
.offset = (off), \
.bit = (b), \
.index = (idx), \
.set_clr = 1, \
+ .secure = (sec), \
.sel = _UNKNOWN_SEL, \
.fixed = (f), \
}
@@ -258,7 +338,8 @@ struct stm32mp1_clk_pll {
[_ ## _label ## _SEL] = { \
.offset = _rcc_selr, \
.src = _rcc_selr ## _ ## _label ## SRC_SHIFT, \
- .msk = _rcc_selr ## _ ## _label ## SRC_MASK, \
+ .msk = (_rcc_selr ## _ ## _label ## SRC_MASK) >> \
+ (_rcc_selr ## _ ## _label ## SRC_SHIFT), \
.parent = (_parents), \
.nb_parent = ARRAY_SIZE(_parents) \
}
@@ -280,95 +361,109 @@ struct stm32mp1_clk_pll {
.refclk[3] = (p4), \
}
-static const uint8_t stm32mp1_clks[][2] = {
- { CK_PER, _CK_PER },
- { CK_MPU, _CK_MPU },
- { CK_AXI, _ACLK },
- { CK_MCU, _CK_MCU },
- { CK_HSE, _HSE },
- { CK_CSI, _CSI },
- { CK_LSI, _LSI },
- { CK_LSE, _LSE },
- { CK_HSI, _HSI },
- { CK_HSE_DIV2, _HSE_KER_DIV2 },
-};
-
#define NB_GATES ARRAY_SIZE(stm32mp1_clk_gate)
+#define SEC 1
+#define N_S 0
+
static const struct stm32mp1_clk_gate stm32mp1_clk_gate[] = {
- _CLK_FIXED(RCC_DDRITFCR, 0, DDRC1, _ACLK),
- _CLK_FIXED(RCC_DDRITFCR, 1, DDRC1LP, _ACLK),
- _CLK_FIXED(RCC_DDRITFCR, 2, DDRC2, _ACLK),
- _CLK_FIXED(RCC_DDRITFCR, 3, DDRC2LP, _ACLK),
- _CLK_FIXED(RCC_DDRITFCR, 4, DDRPHYC, _PLL2_R),
- _CLK_FIXED(RCC_DDRITFCR, 5, DDRPHYCLP, _PLL2_R),
- _CLK_FIXED(RCC_DDRITFCR, 6, DDRCAPB, _PCLK4),
- _CLK_FIXED(RCC_DDRITFCR, 7, DDRCAPBLP, _PCLK4),
- _CLK_FIXED(RCC_DDRITFCR, 8, AXIDCG, _ACLK),
- _CLK_FIXED(RCC_DDRITFCR, 9, DDRPHYCAPB, _PCLK4),
- _CLK_FIXED(RCC_DDRITFCR, 10, DDRPHYCAPBLP, _PCLK4),
-
- _CLK_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_FIXED(RCC_MP_APB3ENSETR, 11, SYSCFG, _UNKNOWN_ID),
-
- _CLK_SC_SELEC(RCC_MP_APB4ENSETR, 8, DDRPERFM, _UNKNOWN_SEL),
- _CLK_SC_SELEC(RCC_MP_APB4ENSETR, 15, IWDG2, _UNKNOWN_SEL),
- _CLK_SC_SELEC(RCC_MP_APB4ENSETR, 16, USBPHY_K, _USBPHY_SEL),
-
- _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, _UART1_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),
+ _CLK_FIXED(SEC, RCC_DDRITFCR, 0, DDRC1, _ACLK),
+ _CLK_FIXED(SEC, RCC_DDRITFCR, 1, DDRC1LP, _ACLK),
+ _CLK_FIXED(SEC, RCC_DDRITFCR, 2, DDRC2, _ACLK),
+ _CLK_FIXED(SEC, RCC_DDRITFCR, 3, DDRC2LP, _ACLK),
+ _CLK_FIXED(SEC, RCC_DDRITFCR, 4, DDRPHYC, _PLL2_R),
+ _CLK_FIXED(SEC, RCC_DDRITFCR, 5, DDRPHYCLP, _PLL2_R),
+ _CLK_FIXED(SEC, RCC_DDRITFCR, 6, DDRCAPB, _PCLK4),
+ _CLK_FIXED(SEC, RCC_DDRITFCR, 7, DDRCAPBLP, _PCLK4),
+ _CLK_FIXED(SEC, RCC_DDRITFCR, 8, AXIDCG, _ACLK),
+ _CLK_FIXED(SEC, RCC_DDRITFCR, 9, DDRPHYCAPB, _PCLK4),
+ _CLK_FIXED(SEC, RCC_DDRITFCR, 10, DDRPHYCAPBLP, _PCLK4),
+
+#if defined(IMAGE_BL32)
+ _CLK_SC_FIXED(N_S, RCC_MP_APB1ENSETR, 6, TIM12_K, _PCLK1),
+#endif
+#if defined(IMAGE_BL2)
+ _CLK_SC_SELEC(N_S, RCC_MP_APB1ENSETR, 14, USART2_K, _UART24_SEL),
+ _CLK_SC_SELEC(N_S, RCC_MP_APB1ENSETR, 15, USART3_K, _UART35_SEL),
+ _CLK_SC_SELEC(N_S, RCC_MP_APB1ENSETR, 16, UART4_K, _UART24_SEL),
+ _CLK_SC_SELEC(N_S, RCC_MP_APB1ENSETR, 17, UART5_K, _UART35_SEL),
+ _CLK_SC_SELEC(N_S, RCC_MP_APB1ENSETR, 18, UART7_K, _UART78_SEL),
+ _CLK_SC_SELEC(N_S, RCC_MP_APB1ENSETR, 19, UART8_K, _UART78_SEL),
+#endif
+
+#if defined(IMAGE_BL32)
+ _CLK_SC_FIXED(N_S, RCC_MP_APB2ENSETR, 2, TIM15_K, _PCLK2),
+#endif
+#if defined(IMAGE_BL2)
+ _CLK_SC_SELEC(N_S, RCC_MP_APB2ENSETR, 13, USART6_K, _UART6_SEL),
+#endif
+
+ _CLK_SC_FIXED(N_S, RCC_MP_APB3ENSETR, 11, SYSCFG, _UNKNOWN_ID),
+
+#if defined(IMAGE_BL32)
+ _CLK_SC_SELEC(N_S, RCC_MP_APB4ENSETR, 0, LTDC_PX, _UNKNOWN_SEL),
+#endif
+ _CLK_SC_SELEC(N_S, RCC_MP_APB4ENSETR, 8, DDRPERFM, _UNKNOWN_SEL),
+ _CLK_SC_SELEC(N_S, RCC_MP_APB4ENSETR, 15, IWDG2, _UNKNOWN_SEL),
+ _CLK_SC_SELEC(N_S, RCC_MP_APB4ENSETR, 16, USBPHY_K, _USBPHY_SEL),
+
+ _CLK_SC_SELEC(SEC, RCC_MP_APB5ENSETR, 0, SPI6_K, _SPI6_SEL),
+ _CLK_SC_SELEC(SEC, RCC_MP_APB5ENSETR, 2, I2C4_K, _I2C46_SEL),
+ _CLK_SC_SELEC(SEC, RCC_MP_APB5ENSETR, 3, I2C6_K, _I2C46_SEL),
+ _CLK_SC_SELEC(SEC, RCC_MP_APB5ENSETR, 4, USART1_K, _UART1_SEL),
+ _CLK_SC_FIXED(SEC, RCC_MP_APB5ENSETR, 8, RTCAPB, _PCLK5),
+ _CLK_SC_FIXED(SEC, RCC_MP_APB5ENSETR, 11, TZC1, _PCLK5),
+ _CLK_SC_FIXED(SEC, RCC_MP_APB5ENSETR, 12, TZC2, _PCLK5),
+ _CLK_SC_FIXED(SEC, RCC_MP_APB5ENSETR, 13, TZPC, _PCLK5),
+ _CLK_SC_FIXED(SEC, RCC_MP_APB5ENSETR, 15, IWDG1, _PCLK5),
+ _CLK_SC_FIXED(SEC, RCC_MP_APB5ENSETR, 16, BSEC, _PCLK5),
+ _CLK_SC_SELEC(SEC, RCC_MP_APB5ENSETR, 20, STGEN_K, _STGEN_SEL),
+
+ _CLK_SELEC(SEC, RCC_BDCR, 20, RTC, _RTC_SEL),
+
+#if defined(IMAGE_BL32)
+ _CLK_SC_SELEC(N_S, RCC_MP_AHB2ENSETR, 0, DMA1, _UNKNOWN_SEL),
+ _CLK_SC_SELEC(N_S, RCC_MP_AHB2ENSETR, 1, DMA2, _UNKNOWN_SEL),
+ _CLK_SC_SELEC(N_S, RCC_MP_AHB2ENSETR, 8, USBO_K, _USBO_SEL),
+ _CLK_SC_SELEC(N_S, RCC_MP_AHB2ENSETR, 16, SDMMC3_K, _SDMMC3_SEL),
+#endif
+
+#if defined(IMAGE_BL2)
+ _CLK_SC_SELEC(N_S, RCC_MP_AHB4ENSETR, 0, GPIOA, _UNKNOWN_SEL),
+ _CLK_SC_SELEC(N_S, RCC_MP_AHB4ENSETR, 1, GPIOB, _UNKNOWN_SEL),
+ _CLK_SC_SELEC(N_S, RCC_MP_AHB4ENSETR, 2, GPIOC, _UNKNOWN_SEL),
+ _CLK_SC_SELEC(N_S, RCC_MP_AHB4ENSETR, 3, GPIOD, _UNKNOWN_SEL),
+ _CLK_SC_SELEC(N_S, RCC_MP_AHB4ENSETR, 4, GPIOE, _UNKNOWN_SEL),
+ _CLK_SC_SELEC(N_S, RCC_MP_AHB4ENSETR, 5, GPIOF, _UNKNOWN_SEL),
+ _CLK_SC_SELEC(N_S, RCC_MP_AHB4ENSETR, 6, GPIOG, _UNKNOWN_SEL),
+ _CLK_SC_SELEC(N_S, RCC_MP_AHB4ENSETR, 7, GPIOH, _UNKNOWN_SEL),
+ _CLK_SC_SELEC(N_S, RCC_MP_AHB4ENSETR, 8, GPIOI, _UNKNOWN_SEL),
+ _CLK_SC_SELEC(N_S, RCC_MP_AHB4ENSETR, 9, GPIOJ, _UNKNOWN_SEL),
+ _CLK_SC_SELEC(N_S, RCC_MP_AHB4ENSETR, 10, GPIOK, _UNKNOWN_SEL),
+#endif
+
+ _CLK_SC_FIXED(SEC, RCC_MP_AHB5ENSETR, 0, GPIOZ, _PCLK5),
+ _CLK_SC_FIXED(SEC, RCC_MP_AHB5ENSETR, 4, CRYP1, _PCLK5),
+ _CLK_SC_FIXED(SEC, RCC_MP_AHB5ENSETR, 5, HASH1, _PCLK5),
+ _CLK_SC_SELEC(SEC, RCC_MP_AHB5ENSETR, 6, RNG1_K, _RNG1_SEL),
+ _CLK_SC_FIXED(SEC, RCC_MP_AHB5ENSETR, 8, BKPSRAM, _PCLK5),
+
+#if defined(IMAGE_BL32)
+ _CLK_SC_FIXED(SEC, RCC_MP_TZAHB6ENSETR, 0, MDMA, _ACLK),
+ _CLK_SC_SELEC(N_S, RCC_MP_AHB6ENSETR, 5, GPU, _UNKNOWN_SEL),
+ _CLK_SC_FIXED(N_S, RCC_MP_AHB6ENSETR, 10, ETHMAC, _ACLK),
+#endif
+#if defined(IMAGE_BL2)
+ _CLK_SC_SELEC(N_S, RCC_MP_AHB6ENSETR, 12, FMC_K, _FMC_SEL),
+ _CLK_SC_SELEC(N_S, RCC_MP_AHB6ENSETR, 14, QSPI_K, _QSPI_SEL),
+#endif
+ _CLK_SC_SELEC(N_S, RCC_MP_AHB6ENSETR, 16, SDMMC1_K, _SDMMC12_SEL),
+ _CLK_SC_SELEC(N_S, RCC_MP_AHB6ENSETR, 17, SDMMC2_K, _SDMMC12_SEL),
+#if defined(IMAGE_BL32)
+ _CLK_SC_SELEC(N_S, RCC_MP_AHB6ENSETR, 24, USBH, _UNKNOWN_SEL),
+#endif
+
+ _CLK_SELEC(N_S, RCC_DBGCFGR, 8, CK_DBG, _UNKNOWN_SEL),
};
static const uint8_t i2c12_parents[] = {
@@ -423,12 +518,12 @@ 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 axiss_parents[] = {
+ _HSI, _HSE, _PLL2_P
};
-static const uint8_t mss_parents[] = {
- _HSI, _HSE, _CSI, _PLL3
+static const uint8_t mcuss_parents[] = {
+ _HSI, _HSE, _CSI, _PLL3_P
};
static const uint8_t usbphy_parents[] = {
@@ -439,6 +534,18 @@ static const uint8_t usbo_parents[] = {
_PLL4_R, _USB_PHY_48
};
+static const uint8_t rtc_parents[] = {
+ _UNKNOWN_ID, _LSE, _LSI, _HSE
+};
+
+static const uint8_t mpu_parents[] = {
+ _HSI, _HSE, _PLL1_P, _PLL1_P /* specific div */
+};
+
+static const uint8_t per_parents[] = {
+ _HSI, _HSE, _CSI,
+};
+
static const struct stm32mp1_clk_sel stm32mp1_clk_sel[_PARENT_SEL_NB] = {
_CLK_PARENT_SEL(I2C12, RCC_I2C12CKSELR, i2c12_parents),
_CLK_PARENT_SEL(I2C35, RCC_I2C35CKSELR, i2c35_parents),
@@ -447,6 +554,9 @@ static const struct stm32mp1_clk_sel stm32mp1_clk_sel[_PARENT_SEL_NB] = {
_CLK_PARENT_SEL(SPI6, RCC_SPI6CKSELR, spi6_parents),
_CLK_PARENT_SEL(UART1, RCC_UART1CKSELR, usart1_parents),
_CLK_PARENT_SEL(RNG1, RCC_RNG1CKSELR, rng1_parents),
+ _CLK_PARENT_SEL(RTC, RCC_BDCR, rtc_parents),
+ _CLK_PARENT_SEL(MPU, RCC_MPCKSELR, mpu_parents),
+ _CLK_PARENT_SEL(PER, RCC_CPERCKSELR, per_parents),
_CLK_PARENT_SEL(UART6, RCC_UART6CKSELR, uart6_parents),
_CLK_PARENT_SEL(UART24, RCC_UART24CKSELR, uart234578_parents),
_CLK_PARENT_SEL(UART35, RCC_UART35CKSELR, uart234578_parents),
@@ -455,14 +565,13 @@ static const struct stm32mp1_clk_sel stm32mp1_clk_sel[_PARENT_SEL_NB] = {
_CLK_PARENT_SEL(SDMMC3, RCC_SDMMC3CKSELR, sdmmc3_parents),
_CLK_PARENT_SEL(QSPI, RCC_QSPICKSELR, qspi_parents),
_CLK_PARENT_SEL(FMC, RCC_FMCCKSELR, fmc_parents),
- _CLK_PARENT_SEL(AXIS, RCC_ASSCKSELR, ass_parents),
- _CLK_PARENT_SEL(MCUS, RCC_MSSCKSELR, mss_parents),
+ _CLK_PARENT_SEL(AXIS, RCC_ASSCKSELR, axiss_parents),
+ _CLK_PARENT_SEL(MCUS, RCC_MSSCKSELR, mcuss_parents),
_CLK_PARENT_SEL(USBPHY, RCC_USBCKSELR, usbphy_parents),
_CLK_PARENT_SEL(USBO, RCC_USBCKSELR, usbo_parents),
};
/* Define characteristic of PLL according type */
-#define DIVN_MIN 24
static const struct stm32mp1_pll stm32mp1_pll[PLL_TYPE_NB] = {
[PLL_800] = {
.refclk_min = 4,
@@ -520,17 +629,90 @@ static const uint8_t stm32mp1_axi_div[8] = {
1, 2, 3, 4, 4, 4, 4, 4
};
+#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",
+ [_UART1_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",
+ [_AXIS_SEL] = "AXISS",
+ [_MCUS_SEL] = "MCUSS",
+ [_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 struct stm32mp1_pll_settings pll1_settings;
+static uint32_t current_opp_khz;
+static uint32_t pll3cr;
+static uint32_t pll4cr;
+static uint32_t mssckselr;
+static uint32_t mcudivr;
static const struct stm32mp1_clk_gate *gate_ref(unsigned int idx)
{
return &stm32mp1_clk_gate[idx];
}
+static bool gate_is_non_secure(const struct stm32mp1_clk_gate *gate)
+{
+ return gate->secure == N_S;
+}
+
static const struct stm32mp1_clk_sel *clk_sel_ref(unsigned int idx)
{
return &stm32mp1_clk_sel[idx];
@@ -559,15 +741,17 @@ static void stm32mp1_clk_unlock(struct spinlock *lock)
bool stm32mp1_rcc_is_secure(void)
{
uintptr_t rcc_base = stm32mp_rcc_base();
+ uint32_t mask = RCC_TZCR_TZEN;
- return (mmio_read_32(rcc_base + RCC_TZCR) & RCC_TZCR_TZEN) != 0;
+ return (mmio_read_32(rcc_base + RCC_TZCR) & mask) == mask;
}
bool stm32mp1_rcc_is_mckprot(void)
{
uintptr_t rcc_base = stm32mp_rcc_base();
+ uint32_t mask = RCC_TZCR_TZEN | RCC_TZCR_MCKPROT;
- return (mmio_read_32(rcc_base + RCC_TZCR) & RCC_TZCR_MCKPROT) != 0;
+ return (mmio_read_32(rcc_base + RCC_TZCR) & mask) == mask;
}
void stm32mp1_clk_rcc_regs_lock(void)
@@ -580,6 +764,28 @@ void stm32mp1_clk_rcc_regs_unlock(void)
stm32mp1_clk_unlock(&reg_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);
+
+ 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) {
@@ -617,17 +823,16 @@ static enum stm32mp1_parent_id stm32mp1_clk_get_fixed_parent(int i)
static int stm32mp1_clk_get_parent(unsigned long id)
{
const struct stm32mp1_clk_sel *sel;
- uint32_t j, p_sel;
+ uint32_t p_sel;
int i;
enum stm32mp1_parent_id p;
enum stm32mp1_parent_sel s;
uintptr_t rcc_base = stm32mp_rcc_base();
- for (j = 0U; j < ARRAY_SIZE(stm32mp1_clks); j++) {
- if (stm32mp1_clks[j][0] == id) {
- return (int)stm32mp1_clks[j][1];
- }
- }
+ /* Few non gateable clock have a static parent ID, find them */
+ i = (int)clock_id2parent_id(id);
+ if (i != _UNKNOWN_ID)
+ return i;
i = stm32mp1_clk_get_gated_id(id);
if (i < 0) {
@@ -648,8 +853,15 @@ static int stm32mp1_clk_get_parent(unsigned long id)
}
sel = clk_sel_ref(s);
- p_sel = (mmio_read_32(rcc_base + sel->offset) & sel->msk) >> sel->src;
+ p_sel = (mmio_read_32(rcc_base + sel->offset) &
+ (sel->msk << sel->src)) >> sel->src;
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];
}
@@ -750,9 +962,7 @@ static unsigned long get_clock_rate(int p)
reg = mmio_read_32(rcc_base + RCC_MPCKDIVR);
clkdiv = reg & RCC_MPUDIV_MASK;
- if (clkdiv != 0U) {
- clock /= stm32mp1_mpu_div[clkdiv];
- }
+ clock >>= stm32mp1_mpu_div[clkdiv];
break;
default:
break;
@@ -930,27 +1140,29 @@ static void __clk_enable(struct stm32mp1_clk_gate const *gate)
{
uintptr_t rcc_base = stm32mp_rcc_base();
+ VERBOSE("Enable clock %d\n", gate->index);
+
if (gate->set_clr != 0U) {
mmio_write_32(rcc_base + gate->offset, BIT(gate->bit));
} else {
- mmio_setbits_32(rcc_base + gate->offset, BIT(gate->bit));
+ 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();
+ VERBOSE("Disable clock %d\n", gate->index);
+
if (gate->set_clr != 0U) {
mmio_write_32(rcc_base + gate->offset + RCC_MP_ENCLRR_OFFSET,
BIT(gate->bit));
} else {
- mmio_clrbits_32(rcc_base + gate->offset, BIT(gate->bit));
+ 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)
@@ -960,57 +1172,119 @@ static bool __clk_is_enabled(struct stm32mp1_clk_gate const *gate)
return mmio_read_32(rcc_base + gate->offset) & BIT(gate->bit);
}
-unsigned int stm32mp1_clk_get_refcount(unsigned long id)
+/* Oscillators and PLLs are not gated at runtime */
+static bool clock_is_always_on(unsigned long id)
{
- int i = stm32mp1_clk_get_gated_id(id);
-
- if (i < 0) {
- panic();
+ CASSERT((CK_HSE == 0) &&
+ ((CK_HSE + 1) == CK_CSI) &&
+ ((CK_HSE + 2) == CK_LSI) &&
+ ((CK_HSE + 3) == CK_LSE) &&
+ ((CK_HSE + 4) == CK_HSI) &&
+ ((CK_HSE + 5) == CK_HSE_DIV2) &&
+ ((PLL1_P + 1) == PLL1_Q) &&
+ ((PLL1_P + 2) == PLL1_R) &&
+ ((PLL1_P + 3) == PLL2_P) &&
+ ((PLL1_P + 4) == PLL2_Q) &&
+ ((PLL1_P + 5) == PLL2_R) &&
+ ((PLL1_P + 6) == PLL3_P) &&
+ ((PLL1_P + 7) == PLL3_Q) &&
+ ((PLL1_P + 8) == PLL3_R),
+ assert_osc_and_pll_ids_are_contiguous);
+
+ if ((id <= CK_HSE_DIV2) || ((id >= PLL1_P) && (id <= PLL3_R)))
+ return true;
+
+ switch (id) {
+ case CK_AXI:
+ case CK_MPU:
+ case CK_MCU:
+ return true;
+ default:
+ return false;
}
-
- return gate_refcounts[i];
}
-void __stm32mp1_clk_enable(unsigned long id, bool secure)
+static void __stm32mp1_clk_enable(unsigned long id, bool with_refcnt)
{
const struct stm32mp1_clk_gate *gate;
- int i = stm32mp1_clk_get_gated_id(id);
- unsigned int *refcnt;
+ int i;
+
+ if (clock_is_always_on(id)) {
+ return;
+ }
+ i = stm32mp1_clk_get_gated_id(id);
if (i < 0) {
ERROR("Clock %d can't be enabled\n", (uint32_t)id);
panic();
}
gate = gate_ref(i);
- refcnt = &gate_refcounts[i];
+
+ if (!with_refcnt) {
+ __clk_enable(gate);
+ return;
+ }
+
+#if defined(IMAGE_BL32)
+ if (gate_is_non_secure(gate)) {
+ /* Enable non-secure clock w/o any refcounting */
+ __clk_enable(gate);
+ return;
+ }
+#endif
stm32mp1_clk_lock(&refcount_lock);
- if (stm32mp_incr_shrefcnt(refcnt, secure) != 0) {
+ if (gate_refcounts[i] == 0) {
__clk_enable(gate);
}
+ gate_refcounts[i]++;
+ if (gate_refcounts[i] == UINT_MAX) {
+ panic();
+ }
+
stm32mp1_clk_unlock(&refcount_lock);
}
-void __stm32mp1_clk_disable(unsigned long id, bool secure)
+static void __stm32mp1_clk_disable(unsigned long id, bool with_refcnt)
{
const struct stm32mp1_clk_gate *gate;
- int i = stm32mp1_clk_get_gated_id(id);
- unsigned int *refcnt;
+ int i;
+
+ if (clock_is_always_on(id)) {
+ return;
+ }
+ i = stm32mp1_clk_get_gated_id(id);
if (i < 0) {
ERROR("Clock %d can't be disabled\n", (uint32_t)id);
panic();
}
gate = gate_ref(i);
- refcnt = &gate_refcounts[i];
+
+ if (!with_refcnt) {
+ __clk_disable(gate);
+ return;
+ }
+
+#if defined(IMAGE_BL32)
+ if (gate_is_non_secure(gate)) {
+ /* Don't disable non-secure clocks */
+ return;
+ }
+#endif
stm32mp1_clk_lock(&refcount_lock);
- if (stm32mp_decr_shrefcnt(refcnt, secure) != 0) {
+ if (gate_refcounts[i] == 0) {
+ panic();
+ }
+ gate_refcounts[i]--;
+
+ if (gate_refcounts[i] == 0) {
__clk_disable(gate);
}
@@ -1027,10 +1301,25 @@ void stm32mp_clk_disable(unsigned long id)
__stm32mp1_clk_disable(id, true);
}
+void stm32mp1_clk_force_enable(unsigned long id)
+{
+ __stm32mp1_clk_enable(id, false);
+}
+
+void stm32mp1_clk_force_disable(unsigned long id)
+{
+ __stm32mp1_clk_disable(id, false);
+}
+
bool stm32mp_clk_is_enabled(unsigned long id)
{
- int i = stm32mp1_clk_get_gated_id(id);
+ int i;
+
+ if (clock_is_always_on(id)) {
+ return true;
+ }
+ i = stm32mp1_clk_get_gated_id(id);
if (i < 0) {
panic();
}
@@ -1163,6 +1452,13 @@ static void stm32mp1_hse_enable(bool bypass, bool digbyp, bool css)
if (css) {
mmio_write_32(rcc_base + RCC_OCENSETR, RCC_OCENR_HSECSSON);
}
+
+#if defined(STM32MP_USB) || defined(STM32MP_UART)
+ if ((mmio_read_32(rcc_base + RCC_OCENSETR) & RCC_OCENR_HSEBYP) &&
+ (!(digbyp || bypass))) {
+ panic();
+ }
+#endif
}
static void stm32mp1_csi_set(bool enable)
@@ -1359,11 +1655,8 @@ static int stm32mp1_pll_stop(enum stm32mp1_pll_id pll_id)
return 0;
}
-static void stm32mp1_pll_config_output(enum stm32mp1_pll_id pll_id,
- uint32_t *pllcfg)
+static uint32_t stm32mp1_pll_compute_pllxcfgr2(uint32_t *pllcfg)
{
- 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) &
@@ -1372,21 +1665,33 @@ static void stm32mp1_pll_config_output(enum stm32mp1_pll_id pll_id,
RCC_PLLNCFGR2_DIVQ_MASK;
value |= (pllcfg[PLLCFG_R] << RCC_PLLNCFGR2_DIVR_SHIFT) &
RCC_PLLNCFGR2_DIVR_MASK;
- mmio_write_32(rcc_base + pll->pllxcfgr2, value);
+
+ return value;
}
-static int stm32mp1_pll_config(enum stm32mp1_pll_id pll_id,
- uint32_t *pllcfg, uint32_t fracv)
+static void stm32mp1_pll_config_output(enum stm32mp1_pll_id pll_id,
+ uint32_t *pllcfg)
{
const struct stm32mp1_clk_pll *pll = pll_ref(pll_id);
+ uintptr_t rcc_base = stm32mp_rcc_base();
+ uint32_t value;
+
+ value = stm32mp1_pll_compute_pllxcfgr2(pllcfg);
+
+ mmio_write_32(rcc_base + pll->pllxcfgr2, value);
+}
+
+static int stm32mp1_pll_compute_pllxcfgr1(const struct stm32mp1_clk_pll *pll,
+ uint32_t *pllcfg, uint32_t *cfgr1)
+{
uintptr_t rcc_base = stm32mp_rcc_base();
enum stm32mp1_plltype type = pll->plltype;
unsigned long refclk;
uint32_t ifrge = 0;
- uint32_t src, value;
+ uint32_t src;
src = mmio_read_32(rcc_base + pll->rckxselr) &
- RCC_SELR_REFCLK_SRC_MASK;
+ RCC_SELR_REFCLK_SRC_MASK;
refclk = stm32mp1_clk_get_fixed(pll->refclk[src]) /
(pllcfg[PLLCFG_M] + 1U);
@@ -1400,23 +1705,39 @@ static int stm32mp1_pll_config(enum stm32mp1_pll_id pll_id,
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;
+ *cfgr1 = (pllcfg[PLLCFG_N] << RCC_PLLNCFGR1_DIVN_SHIFT) &
+ RCC_PLLNCFGR1_DIVN_MASK;
+ *cfgr1 |= (pllcfg[PLLCFG_M] << RCC_PLLNCFGR1_DIVM_SHIFT) &
+ RCC_PLLNCFGR1_DIVM_MASK;
+ *cfgr1 |= (ifrge << RCC_PLLNCFGR1_IFRGE_SHIFT) &
+ RCC_PLLNCFGR1_IFRGE_MASK;
+
+ return 0;
+}
+
+static int stm32mp1_pll_config(enum stm32mp1_pll_id pll_id,
+ uint32_t *pllcfg, uint32_t fracv)
+{
+ const struct stm32mp1_clk_pll *pll = pll_ref(pll_id);
+ uintptr_t rcc_base = stm32mp_rcc_base();
+ uint32_t value;
+ int ret;
+
+ ret = stm32mp1_pll_compute_pllxcfgr1(pll, pllcfg, &value);
+ if (ret != 0) {
+ return ret;
+ }
+
mmio_write_32(rcc_base + pll->pllxcfgr1, value);
/* Fractional configuration */
value = 0;
mmio_write_32(rcc_base + pll->pllxfracr, value);
+ /* Frac must be enabled only once its configuration is loaded */
value = fracv << RCC_PLLNFRACR_FRACV_SHIFT;
mmio_write_32(rcc_base + pll->pllxfracr, value);
-
- value |= RCC_PLLNFRACR_FRACLE;
- mmio_write_32(rcc_base + pll->pllxfracr, value);
+ mmio_setbits_32(rcc_base + pll->pllxfracr, RCC_PLLNFRACR_FRACLE);
stm32mp1_pll_config_output(pll_id, pllcfg);
@@ -1523,53 +1844,68 @@ static void stm32mp1_set_rtcsrc(unsigned int clksrc, bool lse_css)
}
}
-static void stm32mp1_stgen_config(void)
+unsigned long stm32mp_clk_timer_get_rate(unsigned long id)
{
- uintptr_t stgen;
- uint32_t cntfid0;
- unsigned long rate;
- unsigned long long counter;
+ unsigned long parent_rate;
+ uint32_t prescaler, timpre;
+ uintptr_t rcc_base = stm32mp_rcc_base();
- stgen = fdt_get_stgen_base();
- cntfid0 = mmio_read_32(stgen + CNTFID_OFF);
- rate = get_clock_rate(stm32mp1_clk_get_parent(STGEN_K));
+ parent_rate = stm32mp_clk_get_rate(id);
- if (cntfid0 == rate) {
- return;
+ 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;
}
- 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);
-
- write_cntfrq((u_register_t)rate);
+ if (!prescaler) {
+ return parent_rate;
+ }
- /* Need to update timer with new frequency */
- generic_delay_timer_init();
+ return parent_rate * (timpre + 1) * 2;
}
-void stm32mp1_stgen_increment(unsigned long long offset_in_ms)
+/*******************************************************************************
+ * 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)
{
- uintptr_t stgen;
- unsigned long long cnt;
-
- stgen = fdt_get_stgen_base();
+ unsigned long apb1_freq;
+ uint32_t rtc_freq;
+ uint32_t apb1_div;
+ uintptr_t rcc_base = stm32mp_rcc_base();
- cnt = ((unsigned long long)mmio_read_32(stgen + CNTCVU_OFF) << 32) |
- mmio_read_32(stgen + CNTCVL_OFF);
+ 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();
+ }
- cnt += (offset_in_ms * mmio_read_32(stgen + CNTFID_OFF)) / 1000U;
+ apb1_div = mmio_read_32(rcc_base + RCC_APB1DIVR) & RCC_APBXDIV_MASK;
+ apb1_freq = stm32mp_clk_get_rate(CK_MCU) >> apb1_div;
- mmio_clrbits_32(stgen + CNTCR_OFF, CNTCR_EN);
- mmio_write_32(stgen + CNTCVL_OFF, (uint32_t)cnt);
- mmio_write_32(stgen + CNTCVU_OFF, (uint32_t)(cnt >> 32));
- mmio_setbits_32(stgen + CNTCR_OFF, CNTCR_EN);
+ return apb1_freq < (rtc_freq * 7U);
}
static void stm32mp1_pkcs_config(uint32_t pkcs)
@@ -1586,96 +1922,673 @@ static void stm32mp1_pkcs_config(uint32_t pkcs)
mmio_clrsetbits_32(address, mask, value);
}
-int stm32mp1_clk_init(void)
+static bool clk_pll1_settings_are_valid(void)
{
- uintptr_t rcc_base = stm32mp_rcc_base();
- unsigned int clksrc[CLKSRC_NB];
- unsigned int clkdiv[CLKDIV_NB];
- unsigned int pllcfg[_PLL_NB][PLLCFG_NB];
- int plloff[_PLL_NB];
- int ret, len;
- enum stm32mp1_pll_id i;
- bool lse_css = false;
- bool pll3_preserve = false;
- bool pll4_preserve = false;
- bool pll4_bootrom = false;
- const fdt32_t *pkcs_cell;
+ return pll1_settings.valid_id == PLL1_SETTINGS_VALID_ID;
+}
- /* Check status field to disable security */
- if (!fdt_get_rcc_secure_status()) {
- mmio_write_32(rcc_base + RCC_TZCR, 0);
+int stm32mp1_round_opp_khz(uint32_t *freq_khz)
+{
+ unsigned int i;
+ uint32_t round_opp = 0U;
+
+ if (!clk_pll1_settings_are_valid()) {
+ /*
+ * No OPP table in DT, or an error occurred during PLL1
+ * settings computation, system can only work on current
+ * operating point, so return current CPU frequency.
+ */
+ *freq_khz = current_opp_khz;
+
+ return 0;
}
- ret = fdt_rcc_read_uint32_array("st,clksrc", clksrc,
- (uint32_t)CLKSRC_NB);
- if (ret < 0) {
- return -FDT_ERR_NOTFOUND;
+ for (i = 0; i < PLAT_MAX_OPP_NB; i++) {
+ if ((pll1_settings.freq[i] <= *freq_khz) &&
+ (pll1_settings.freq[i] > round_opp)) {
+ round_opp = pll1_settings.freq[i];
+ }
}
- ret = fdt_rcc_read_uint32_array("st,clkdiv", clkdiv,
- (uint32_t)CLKDIV_NB);
- if (ret < 0) {
- return -FDT_ERR_NOTFOUND;
+ *freq_khz = round_opp;
+
+ return 0;
+}
+
+/*
+ * Check if PLL1 can be configured on the fly.
+ * @result (-1) => config on the fly is not possible.
+ * (0) => config on the fly is possible.
+ * (+1) => same parameters, no need to reconfigure.
+ * Return value is 0 if no error.
+ */
+static int stm32mp1_is_pll_config_on_the_fly(enum stm32mp1_pll_id pll_id,
+ uint32_t *pllcfg, uint32_t fracv,
+ int *result)
+{
+ const struct stm32mp1_clk_pll *pll = pll_ref(pll_id);
+ uintptr_t rcc_base = stm32mp_rcc_base();
+ uint32_t fracr;
+ uint32_t value;
+ int ret;
+
+ ret = stm32mp1_pll_compute_pllxcfgr1(pll, pllcfg, &value);
+ if (ret != 0) {
+ return ret;
}
- for (i = (enum stm32mp1_pll_id)0; i < _PLL_NB; i++) {
- char name[12];
+ if (mmio_read_32(rcc_base + pll->pllxcfgr1) != value) {
+ /* Different DIVN/DIVM, can't config on the fly */
+ *result = -1;
+ return 0;
+ }
- snprintf(name, sizeof(name), "st,pll@%d", i);
- plloff[i] = fdt_rcc_subnode_offset(name);
+ *result = true;
- if (!fdt_check_node(plloff[i])) {
- continue;
- }
+ fracr = fracv << RCC_PLLNFRACR_FRACV_SHIFT;
+ fracr |= RCC_PLLNFRACR_FRACLE;
+ value = stm32mp1_pll_compute_pllxcfgr2(pllcfg);
- ret = fdt_read_uint32_array(plloff[i], "cfg",
- pllcfg[i], (int)PLLCFG_NB);
- if (ret < 0) {
- return -FDT_ERR_NOTFOUND;
- }
+ if ((mmio_read_32(rcc_base + pll->pllxfracr) == fracr) &&
+ (mmio_read_32(rcc_base + pll->pllxcfgr2) == value)) {
+ /* Same parameters, no need to config */
+ *result = 1;
+ } else {
+ *result = 0;
}
- stm32mp1_mco_csg(clksrc[CLKSRC_MCO1], clkdiv[CLKDIV_MCO1]);
- stm32mp1_mco_csg(clksrc[CLKSRC_MCO2], clkdiv[CLKDIV_MCO2]);
+ return 0;
+}
- /*
- * Switch ON oscillator found in device-tree.
- * Note: HSI already ON after BootROM stage.
- */
- if (stm32mp1_osc[_LSI] != 0U) {
- stm32mp1_lsi_set(true);
+static int stm32mp1_get_mpu_div(uint32_t freq_khz)
+{
+ unsigned long freq_pll1_p;
+ unsigned long div;
+
+ freq_pll1_p = get_clock_rate(_PLL1_P) / 1000UL;
+ if ((freq_pll1_p % freq_khz) != 0U) {
+ return -1;
}
- 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(bypass, digbyp, lsedrv);
+ div = freq_pll1_p / freq_khz;
+
+ switch (div) {
+ case 1UL:
+ case 2UL:
+ case 4UL:
+ case 8UL:
+ case 16UL:
+ return __builtin_ffs(div) - 1;
+ default:
+ return -1;
}
- if (stm32mp1_osc[_HSE] != 0U) {
- bool bypass, digbyp, 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);
+static int stm32mp1_pll1_config_from_opp_khz(uint32_t freq_khz)
+{
+ unsigned int i;
+ int ret;
+ int div;
+ int config_on_the_fly = -1;
+
+ for (i = 0; i < PLAT_MAX_OPP_NB; i++) {
+ if (pll1_settings.freq[i] == freq_khz) {
+ break;
+ }
}
- /*
- * 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(true);
- /* Come back to HSI */
- ret = stm32mp1_set_clksrc(CLK_MPU_HSI);
- if (ret != 0) {
- return ret;
+ if (i == PLAT_MAX_OPP_NB) {
+ return -ENXIO;
}
- ret = stm32mp1_set_clksrc(CLK_AXI_HSI);
+
+ div = stm32mp1_get_mpu_div(freq_khz);
+
+ switch (div) {
+ case -1:
+ break;
+ case 0:
+ return stm32mp1_set_clksrc(CLK_MPU_PLL1P);
+ default:
+ ret = stm32mp1_set_clkdiv(div, stm32mp_rcc_base() +
+ RCC_MPCKDIVR);
+ if (ret == 0) {
+ ret = stm32mp1_set_clksrc(CLK_MPU_PLL1P_DIV);
+ }
+ return ret;
+ }
+
+ ret = stm32mp1_is_pll_config_on_the_fly(_PLL1, &pll1_settings.cfg[i][0],
+ pll1_settings.frac[i],
+ &config_on_the_fly);
+ if (ret != 0) {
+ return ret;
+ }
+
+ if (config_on_the_fly == 1) {
+ /* No need to reconfigure, setup already OK */
+ return 0;
+ }
+
+ if (config_on_the_fly == -1) {
+ /* Switch to HSI and stop PLL1 before reconfiguration */
+ ret = stm32mp1_set_clksrc(CLK_MPU_HSI);
+ if (ret != 0) {
+ return ret;
+ }
+
+ ret = stm32mp1_pll_stop(_PLL1);
+ if (ret != 0) {
+ return ret;
+ }
+ }
+
+ ret = stm32mp1_pll_config(_PLL1, &pll1_settings.cfg[i][0],
+ pll1_settings.frac[i]);
+ if (ret != 0) {
+ return ret;
+ }
+
+ if (config_on_the_fly == -1) {
+ /* Start PLL1 and switch back to after reconfiguration */
+ stm32mp1_pll_start(_PLL1);
+
+ ret = stm32mp1_pll_output(_PLL1,
+ pll1_settings.cfg[i][PLLCFG_O]);
+ if (ret != 0) {
+ return ret;
+ }
+
+ ret = stm32mp1_set_clksrc(CLK_MPU_PLL1P);
+ if (ret != 0) {
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+int stm32mp1_set_opp_khz(uint32_t freq_khz)
+{
+ uintptr_t rcc_base = stm32mp_rcc_base();
+ uint32_t mpu_src;
+
+ if (freq_khz == current_opp_khz) {
+ /* OPP already set, nothing to do */
+ return 0;
+ }
+
+ if (!clk_pll1_settings_are_valid()) {
+ /*
+ * No OPP table in DT or an error occurred during PLL1
+ * settings computation, system can only work on current
+ * operating point so return error.
+ */
+ return -EACCES;
+ }
+
+ /* Check that PLL1 is MPU clock source */
+ mpu_src = mmio_read_32(rcc_base + RCC_MPCKSELR) & RCC_SELR_SRC_MASK;
+ if ((mpu_src != RCC_MPCKSELR_PLL) &&
+ (mpu_src != RCC_MPCKSELR_PLL_MPUDIV)) {
+ return -EPERM;
+ }
+
+ if (stm32mp1_pll1_config_from_opp_khz(freq_khz) != 0) {
+ /* Restore original value */
+ if (stm32mp1_pll1_config_from_opp_khz(current_opp_khz) != 0) {
+ ERROR("No CPU operating point can be set\n");
+ panic();
+ }
+
+ return -EIO;
+ }
+
+ current_opp_khz = freq_khz;
+
+ return 0;
+}
+
+static int clk_get_pll_settings_from_dt(int plloff, unsigned int *pllcfg,
+ uint32_t *fracv, uint32_t *csg,
+ bool *csg_set)
+{
+ int ret;
+
+ ret = fdt_read_uint32_array(plloff, "cfg", pllcfg, (uint32_t)PLLCFG_NB);
+ if (ret < 0) {
+ return -FDT_ERR_NOTFOUND;
+ }
+
+ *fracv = fdt_read_uint32_default(plloff, "frac", 0);
+
+ ret = fdt_read_uint32_array(plloff, "csg", csg, (uint32_t)PLLCSG_NB);
+
+ *csg_set = (ret == 0);
+
+ if (ret == -FDT_ERR_NOTFOUND) {
+ ret = 0;
+ }
+
+ return ret;
+}
+
+static int clk_compute_pll1_settings(unsigned long input_freq,
+ uint32_t freq_khz,
+ uint32_t *pllcfg, uint32_t *fracv)
+{
+ unsigned long long output_freq = freq_khz * 1000U;
+ unsigned long long freq;
+ unsigned long long vco;
+ int divm;
+ int divn;
+ int divp;
+ int frac;
+ int i;
+ unsigned int diff;
+ unsigned int best_diff = UINT_MAX;
+
+ /* Following parameters have always the same value */
+ pllcfg[PLLCFG_Q] = 0;
+ pllcfg[PLLCFG_R] = 0;
+ pllcfg[PLLCFG_O] = PQR(1, 0, 0);
+
+ for (divm = DIVM_MAX; divm >= DIVM_MIN; divm--) {
+ unsigned long post_divm = input_freq /
+ (unsigned long)(divm + 1);
+
+ if ((post_divm < POST_DIVM_MIN) ||
+ (post_divm > POST_DIVM_MAX)) {
+ continue;
+ }
+
+ for (divp = DIVP_MIN; divp <= DIVP_MAX; divp++) {
+
+ freq = output_freq * (divm + 1) * (divp + 1);
+
+ divn = (int)((freq / input_freq) - 1);
+ if ((divn < DIVN_MIN) || (divn > DIVN_MAX)) {
+ continue;
+ }
+
+ frac = (int)(((freq * FRAC_MAX) / input_freq) -
+ ((divn + 1) * FRAC_MAX));
+
+ /* 2 loops to refine the fractional part */
+ for (i = 2; i != 0; i--) {
+ if (frac > FRAC_MAX) {
+ break;
+ }
+
+ vco = (post_divm * (divn + 1)) +
+ ((post_divm * (unsigned long long)frac) /
+ FRAC_MAX);
+
+ if ((vco < (VCO_MIN / 2)) ||
+ (vco > (VCO_MAX / 2))) {
+ frac++;
+ continue;
+ }
+
+ freq = vco / (divp + 1);
+ if (output_freq < freq) {
+ diff = (unsigned int)(freq -
+ output_freq);
+ } else {
+ diff = (unsigned int)(output_freq -
+ freq);
+ }
+
+ if (diff < best_diff) {
+ pllcfg[PLLCFG_M] = divm;
+ pllcfg[PLLCFG_N] = divn;
+ pllcfg[PLLCFG_P] = divp;
+ *fracv = frac;
+
+ if (diff == 0) {
+ return 0;
+ }
+
+ best_diff = diff;
+ }
+
+ frac++;
+ }
+ }
+ }
+
+ if (best_diff == UINT_MAX) {
+ return -1;
+ }
+
+ return 0;
+}
+
+static int clk_get_pll1_settings(uint32_t clksrc, uint32_t freq_khz,
+ uint32_t *pllcfg, uint32_t *fracv)
+{
+ unsigned int i;
+
+ assert(pllcfg != NULL);
+ assert(fracv != NULL);
+
+ for (i = 0; i < PLAT_MAX_OPP_NB; i++) {
+ if (pll1_settings.freq[i] == freq_khz) {
+ break;
+ }
+ }
+
+ if (((i == PLAT_MAX_OPP_NB) && (pll1_settings.valid_id == 0U)) ||
+ ((i < PLAT_MAX_OPP_NB) &&
+ (pll1_settings.cfg[i][PLLCFG_O] == 0U))) {
+ unsigned long input_freq;
+
+ /*
+ * Either PLL1 settings structure is completely empty,
+ * or these settings are not yet computed: do it.
+ */
+ switch (clksrc) {
+ case CLK_PLL12_HSI:
+ input_freq = stm32mp_clk_get_rate(CK_HSI);
+ break;
+ case CLK_PLL12_HSE:
+ input_freq = stm32mp_clk_get_rate(CK_HSE);
+ break;
+ default:
+ panic();
+ }
+
+ return clk_compute_pll1_settings(input_freq, freq_khz, pllcfg,
+ fracv);
+ }
+
+ if ((i < PLAT_MAX_OPP_NB) &&
+ (pll1_settings.cfg[i][PLLCFG_O] != 0U)) {
+ /*
+ * Index is in range and PLL1 settings are computed:
+ * use content to answer to the request.
+ */
+ memcpy(pllcfg, &pll1_settings.cfg[i][0],
+ sizeof(uint32_t) * PLAT_MAX_PLLCFG_NB);
+ *fracv = pll1_settings.frac[i];
+
+ return 0;
+ }
+
+ return -1;
+}
+
+int stm32mp1_clk_get_maxfreq_opp(uint32_t *freq_khz,
+ uint32_t *voltage_mv)
+{
+ unsigned int i;
+ uint32_t freq = 0U;
+ uint32_t voltage = 0U;
+
+ assert(freq_khz != NULL);
+ assert(voltage_mv != NULL);
+
+ if (!clk_pll1_settings_are_valid()) {
+ return -1;
+ }
+
+ for (i = 0; i < PLAT_MAX_OPP_NB; i++) {
+ if (pll1_settings.freq[i] > freq) {
+ freq = pll1_settings.freq[i];
+ voltage = pll1_settings.volt[i];
+ }
+ }
+
+ if ((freq == 0U) || (voltage == 0U)) {
+ return -1;
+ }
+
+ *freq_khz = freq;
+ *voltage_mv = voltage;
+
+ return 0;
+}
+
+static int clk_save_current_pll1_settings(uint32_t buck1_voltage)
+{
+ const struct stm32mp1_clk_pll *pll = pll_ref(_PLL1);
+ uint32_t rcc_base = stm32mp_rcc_base();
+ uint32_t freq;
+ unsigned int i;
+
+ freq = udiv_round_nearest(stm32mp_clk_get_rate(CK_MPU), 1000L);
+
+ for (i = 0; i < PLAT_MAX_OPP_NB; i++) {
+ if (pll1_settings.freq[i] == freq) {
+ break;
+ }
+ }
+
+ if ((i == PLAT_MAX_OPP_NB) ||
+ ((pll1_settings.volt[i] != buck1_voltage) &&
+ (buck1_voltage != 0U))) {
+ return -1;
+ }
+
+ pll1_settings.cfg[i][PLLCFG_M] =
+ (mmio_read_32(rcc_base + pll->pllxcfgr1) &
+ RCC_PLLNCFGR1_DIVM_MASK) >> RCC_PLLNCFGR1_DIVM_SHIFT;
+
+ pll1_settings.cfg[i][PLLCFG_N] =
+ (mmio_read_32(rcc_base + pll->pllxcfgr1) &
+ RCC_PLLNCFGR1_DIVN_MASK) >> RCC_PLLNCFGR1_DIVN_SHIFT;
+
+ pll1_settings.cfg[i][PLLCFG_P] =
+ (mmio_read_32(rcc_base + pll->pllxcfgr2) &
+ RCC_PLLNCFGR2_DIVP_MASK) >> RCC_PLLNCFGR2_DIVP_SHIFT;
+
+ pll1_settings.cfg[i][PLLCFG_Q] =
+ (mmio_read_32(rcc_base + pll->pllxcfgr2) &
+ RCC_PLLNCFGR2_DIVQ_MASK) >> RCC_PLLNCFGR2_DIVQ_SHIFT;
+
+ pll1_settings.cfg[i][PLLCFG_R] =
+ (mmio_read_32(rcc_base + pll->pllxcfgr2) &
+ RCC_PLLNCFGR2_DIVR_MASK) >> RCC_PLLNCFGR2_DIVR_SHIFT;
+
+ pll1_settings.cfg[i][PLLCFG_O] =
+ mmio_read_32(rcc_base + pll->pllxcr) >>
+ RCC_PLLNCR_DIVEN_SHIFT;
+
+ pll1_settings.frac[i] =
+ (mmio_read_32(rcc_base + pll->pllxfracr) &
+ RCC_PLLNFRACR_FRACV_MASK) >> RCC_PLLNFRACR_FRACV_SHIFT;
+
+ return i;
+}
+
+static uint32_t stm32mp1_clk_get_pll1_current_clksrc(void)
+{
+ uint32_t value;
+ const struct stm32mp1_clk_pll *pll = pll_ref(_PLL1);
+ uint32_t rcc_base = stm32mp_rcc_base();
+
+ value = mmio_read_32(rcc_base + pll->rckxselr);
+
+ switch (value & RCC_SELR_REFCLK_SRC_MASK) {
+ case 0:
+ return CLK_PLL12_HSI;
+ case 1:
+ return CLK_PLL12_HSE;
+ default:
+ panic();
+ }
+}
+
+int stm32mp1_clk_compute_all_pll1_settings(uint32_t buck1_voltage)
+{
+ int i;
+ int ret;
+ int index;
+ uint32_t count = PLAT_MAX_OPP_NB;
+ uint32_t clksrc;
+
+ ret = dt_get_all_opp_freqvolt(&count, pll1_settings.freq,
+ pll1_settings.volt);
+ switch (ret) {
+ case 0:
+ break;
+ case -FDT_ERR_NOTFOUND:
+ VERBOSE("Cannot find OPP table in DT, use default settings.\n");
+ return 0;
+ default:
+ ERROR("Inconsistent OPP settings found in DT, ignored.\n");
+ return 0;
+ }
+
+ index = clk_save_current_pll1_settings(buck1_voltage);
+
+ clksrc = stm32mp1_clk_get_pll1_current_clksrc();
+
+ for (i = 0; i < (int)count; i++) {
+ if (i == index) {
+ continue;
+ }
+
+ ret = clk_get_pll1_settings(clksrc, pll1_settings.freq[i],
+ &pll1_settings.cfg[i][0],
+ &pll1_settings.frac[i]);
+ if (ret != 0) {
+ return ret;
+ }
+ }
+
+ pll1_settings.valid_id = PLL1_SETTINGS_VALID_ID;
+
+ return 0;
+}
+
+void stm32mp1_clk_lp_save_opp_pll1_settings(uint8_t *data, size_t size)
+{
+ if (size != sizeof(pll1_settings) || !clk_pll1_settings_are_valid()) {
+ panic();
+ }
+
+ memcpy(data, &pll1_settings, size);
+}
+
+void stm32mp1_clk_lp_load_opp_pll1_settings(uint8_t *data, size_t size)
+{
+ if (size != sizeof(pll1_settings)) {
+ panic();
+ }
+
+ memcpy(&pll1_settings, data, size);
+}
+
+int stm32mp1_clk_init(uint32_t pll1_freq_khz)
+{
+ uintptr_t rcc_base = stm32mp_rcc_base();
+ uint32_t pllfracv[_PLL_NB];
+ uint32_t pllcsg[_PLL_NB][PLLCSG_NB];
+ unsigned int clksrc[CLKSRC_NB];
+ unsigned int clkdiv[CLKDIV_NB];
+ unsigned int pllcfg[_PLL_NB][PLLCFG_NB];
+ int plloff[_PLL_NB];
+ int ret, len;
+ enum stm32mp1_pll_id i;
+ bool pllcsg_set[_PLL_NB];
+ bool pllcfg_valid[_PLL_NB];
+ bool lse_css = false;
+ 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_base + RCC_TZCR, 0);
+ }
+
+ ret = fdt_rcc_read_uint32_array("st,clksrc", clksrc,
+ (uint32_t)CLKSRC_NB);
+ if (ret < 0) {
+ return -FDT_ERR_NOTFOUND;
+ }
+
+ ret = fdt_rcc_read_uint32_array("st,clkdiv", clkdiv,
+ (uint32_t)CLKDIV_NB);
+ if (ret < 0) {
+ return -FDT_ERR_NOTFOUND;
+ }
+
+ for (i = (enum stm32mp1_pll_id)0; i < _PLL_NB; i++) {
+ char name[12];
+
+ snprintf(name, sizeof(name), "st,pll@%d", i);
+ plloff[i] = fdt_rcc_subnode_offset(name);
+
+ pllcfg_valid[i] = fdt_check_node(plloff[i]);
+ if (pllcfg_valid[i]) {
+ ret = clk_get_pll_settings_from_dt(plloff[i], pllcfg[i],
+ &pllfracv[i],
+ pllcsg[i],
+ &pllcsg_set[i]);
+ if (ret != 0) {
+ return ret;
+ }
+
+ continue;
+ }
+
+ if ((i == _PLL1) && (pll1_freq_khz != 0U)) {
+ ret = clk_get_pll1_settings(clksrc[CLKSRC_PLL12],
+ pll1_freq_khz,
+ pllcfg[i], &pllfracv[i]);
+ if (ret != 0) {
+ return ret;
+ }
+
+ pllcfg_valid[i] = true;
+ }
+ }
+
+ 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 (stm32mp1_osc[_LSI] != 0U) {
+ stm32mp1_lsi_set(true);
+ }
+ 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(bypass, digbyp, lsedrv);
+ }
+ if (stm32mp1_osc[_HSE] != 0U) {
+ bool bypass, digbyp, 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(true);
+
+ /* Come back to 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;
}
@@ -1695,6 +2608,12 @@ int stm32mp1_clk_init(void)
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 == _PLL3) && pll3_preserve) ||
@@ -1714,7 +2633,8 @@ int stm32mp1_clk_init(void)
if (ret != 0) {
return ret;
}
- stm32mp1_stgen_config();
+
+ stm32mp_stgen_config(stm32mp_clk_get_rate(STGEN_K));
}
/* Select DIV */
@@ -1776,15 +2696,12 @@ int stm32mp1_clk_init(void)
/* Configure and start PLLs */
for (i = (enum stm32mp1_pll_id)0; i < _PLL_NB; i++) {
- 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])) {
+ if (!pllcfg_valid[i]) {
continue;
}
@@ -1794,25 +2711,20 @@ int stm32mp1_clk_init(void)
continue;
}
- fracv = fdt_read_uint32_default(plloff[i], "frac", 0);
-
- ret = stm32mp1_pll_config(i, pllcfg[i], fracv);
+ ret = stm32mp1_pll_config(i, pllcfg[i], pllfracv[i]);
if (ret != 0) {
return ret;
}
- ret = fdt_read_uint32_array(plloff[i], "csg", csg,
- (uint32_t)PLLCSG_NB);
- if (ret == 0) {
- stm32mp1_pll_csg(i, csg);
- } else if (ret != -FDT_ERR_NOTFOUND) {
- return ret;
+
+ if (pllcsg_set[i]) {
+ stm32mp1_pll_csg(i, pllcsg[i]);
}
stm32mp1_pll_start(i);
}
/* Wait and start PLLs ouptut when ready */
for (i = (enum stm32mp1_pll_id)0; i < _PLL_NB; i++) {
- if (!fdt_check_node(plloff[i])) {
+ if (!pllcfg_valid[i]) {
continue;
}
@@ -1846,6 +2758,11 @@ int stm32mp1_clk_init(void)
if (pkcs_cell != NULL) {
bool ckper_disabled = false;
uint32_t j;
+ uint32_t usbreg_bootrom = 0U;
+
+ 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 = fdt32_to_cpu(pkcs_cell[j]);
@@ -1866,13 +2783,33 @@ int stm32mp1_clk_init(void)
if (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 (stm32mp1_osc[_HSI] == 0U) {
stm32mp1_hsi_set(false);
}
- stm32mp1_stgen_config();
+
+ stm32mp_stgen_config(stm32mp_clk_get_rate(STGEN_K));
/* Software Self-Refresh mode (SSR) during DDR initilialization */
mmio_clrsetbits_32(rcc_base + RCC_DDRITFCR,
@@ -1902,18 +2839,634 @@ static void stm32mp1_osc_init(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)
+{
+ return get_id_from_rcc_bit(offset, bit);
+}
+
+#ifdef IMAGE_BL32
+/*
+ * 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 = _AXIS_SEL;
+ break;
+ case _PLL1_P:
+ case _PLL1_Q:
+ case _PLL1_R:
+ pll_id = _PLL1;
+ break;
+ case _PLL2_P:
+ case _PLL2_Q:
+ case _PLL2_R:
+ pll_id = _PLL2;
+ break;
+ case _PLL3_P:
+ case _PLL3_Q:
+ case _PLL3_R:
+ pll_id = _PLL3;
+ break;
+ case _PLL4_P:
+ case _PLL4_Q:
+ case _PLL4_R:
+ pll_id = _PLL4;
+ break;
+ case _PCLK1:
+ case _PCLK2:
+ case _HCLK2:
+ case _HCLK6:
+ case _CK_PER:
+ case _CK_MPU:
+ case _CK_MCU:
+ case _USB_PHY_48:
+ /* We do not expected to access these */
+ panic();
+ break;
+ default:
+ /* Other parents have no parent */
+ return -1;
+ }
+
+ if (s != _UNKNOWN_SEL) {
+ const struct stm32mp1_clk_sel *sel = clk_sel_ref(s);
+ uintptr_t rcc_base = stm32mp_rcc_base();
+
+ p_sel = (mmio_read_32(rcc_base + sel->offset) >> sel->src) &
+ sel->msk;
+
+ if (p_sel < sel->nb_parent) {
+ return (int)sel->parent[p_sel];
+ }
+ } else {
+ const struct stm32mp1_clk_pll *pll = pll_ref(pll_id);
+ 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\n",
+ stm32mp1_clk_parent_name[parent_id]);
+#endif
+
+ return -1;
+}
+
+static void secure_parent_clocks(unsigned long parent_id)
+{
+ int grandparent_id;
+
+ switch (parent_id) {
+ case _PLL3_P:
+ case _PLL3_Q:
+ case _PLL3_R:
+ stm32mp_register_secure_periph(STM32MP1_SHRES_PLL3);
+ break;
+
+ /* These clocks are always secure when RCC is secure */
+ case _ACLK:
+ case _HCLK2:
+ case _HCLK6:
+ case _PCLK4:
+ case _PCLK5:
+ case _PLL1_P:
+ case _PLL1_Q:
+ case _PLL1_R:
+ case _PLL2_P:
+ case _PLL2_Q:
+ case _PLL2_R:
+ case _HSI:
+ case _HSI_KER:
+ case _LSI:
+ case _CSI:
+ case _CSI_KER:
+ case _HSE:
+ case _HSE_KER:
+ case _HSE_KER_DIV2:
+ case _LSE:
+ break;
+
+ default:
+#if LOG_LEVEL >= LOG_LEVEL_VERBOSE
+ VERBOSE("Cannot secure parent clock %s\n",
+ stm32mp1_clk_parent_name[parent_id]);
+#endif
+ 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:
+ case PLL2:
+ /* PLL1/PLL2 are always secure: nothing to do */
+ return;
+ case PLL3:
+ stm32mp_register_secure_periph(STM32MP1_SHRES_PLL3);
+ return;
+ 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) {
+ INFO("No parent for clock %lu\n", clock_id);
+ return;
+ }
+
+ secure_parent_clocks(parent_id);
+}
+#else
+void stm32mp1_register_clock_parents_secure(unsigned long clock_id)
+{
+}
+#endif /* IMAGE_BL32 */
+
+/*
+ * Sequence to save/restore the non-secure configuration.
+ * Restoring clocks and muxes need IPs to run on kernel clock
+ * hence on configuration is restored at resume, kernel clock
+ * should be disable: this mandates secure access.
+ *
+ * backup_mux*_cfg for the clock muxes.
+ * backup_clock_sc_cfg for the set/clear clock gating registers
+ * backup_clock_cfg for the regular full write registers
+ */
+
+struct backup_mux_cfg {
+ uint16_t offset;
+ uint8_t value;
+ uint8_t bit_len;
+};
+
+#define MUXCFG(_offset, _bit_len) \
+ { .offset = (_offset), .bit_len = (_bit_len) }
+
+static struct backup_mux_cfg backup_mux0_cfg[] = {
+ MUXCFG(RCC_SDMMC12CKSELR, 3),
+ MUXCFG(RCC_SPI2S23CKSELR, 3),
+ MUXCFG(RCC_SPI45CKSELR, 3),
+ MUXCFG(RCC_I2C12CKSELR, 3),
+ MUXCFG(RCC_I2C35CKSELR, 3),
+ MUXCFG(RCC_LPTIM23CKSELR, 3),
+ MUXCFG(RCC_LPTIM45CKSELR, 3),
+ MUXCFG(RCC_UART24CKSELR, 3),
+ MUXCFG(RCC_UART35CKSELR, 3),
+ MUXCFG(RCC_UART78CKSELR, 3),
+ MUXCFG(RCC_SAI1CKSELR, 3),
+ MUXCFG(RCC_ETHCKSELR, 2),
+ MUXCFG(RCC_I2C46CKSELR, 3),
+ MUXCFG(RCC_RNG2CKSELR, 2),
+ MUXCFG(RCC_SDMMC3CKSELR, 3),
+ MUXCFG(RCC_FMCCKSELR, 2),
+ MUXCFG(RCC_QSPICKSELR, 2),
+ MUXCFG(RCC_USBCKSELR, 2),
+ MUXCFG(RCC_SPDIFCKSELR, 2),
+ MUXCFG(RCC_SPI2S1CKSELR, 3),
+ MUXCFG(RCC_CECCKSELR, 2),
+ MUXCFG(RCC_LPTIM1CKSELR, 3),
+ MUXCFG(RCC_UART6CKSELR, 3),
+ MUXCFG(RCC_FDCANCKSELR, 2),
+ MUXCFG(RCC_SAI2CKSELR, 3),
+ MUXCFG(RCC_SAI3CKSELR, 3),
+ MUXCFG(RCC_SAI4CKSELR, 3),
+ MUXCFG(RCC_ADCCKSELR, 2),
+ MUXCFG(RCC_DSICKSELR, 1),
+ MUXCFG(RCC_CPERCKSELR, 2),
+ MUXCFG(RCC_RNG1CKSELR, 2),
+ MUXCFG(RCC_STGENCKSELR, 2),
+ MUXCFG(RCC_UART1CKSELR, 3),
+ MUXCFG(RCC_SPI6CKSELR, 3),
+};
+
+static struct backup_mux_cfg backup_mux4_cfg[] = {
+ MUXCFG(RCC_USBCKSELR, 1),
+};
+
+static void backup_mux_cfg(void)
+{
+ uintptr_t base = stm32mp_rcc_base();
+ struct backup_mux_cfg *cfg;
+ size_t i;
+
+ cfg = backup_mux0_cfg;
+ for (i = 0U; i < ARRAY_SIZE(backup_mux0_cfg); i++) {
+ cfg[i].value = mmio_read_32(base + cfg[i].offset) &
+ GENMASK_32(cfg[i].bit_len - 1U, 0U);
+ }
+
+ cfg = backup_mux4_cfg;
+ for (i = 0U; i < ARRAY_SIZE(backup_mux4_cfg); i++) {
+ cfg[i].value = mmio_read_32(base + cfg[i].offset) &
+ GENMASK_32(4U + cfg[i].bit_len - 1U, 4U);
+ }
+}
+
+static void restore_mux_cfg(void)
+{
+ uintptr_t base = stm32mp_rcc_base();
+ struct backup_mux_cfg *cfg;
+ size_t i;
+
+ cfg = backup_mux0_cfg;
+ for (i = 0U; i < ARRAY_SIZE(backup_mux0_cfg); i++) {
+ uint32_t mask = GENMASK_32(cfg[i].bit_len - 1U, 0U);
+ uint32_t value = cfg[i].value & mask;
+
+ mmio_clrsetbits_32(base + cfg[i].offset, mask, value);
+ }
+
+ cfg = backup_mux4_cfg;
+ for (i = 0U; i < ARRAY_SIZE(backup_mux4_cfg); i++) {
+ uint32_t mask = GENMASK_32(4U + cfg[i].bit_len - 1U, 4U);
+ uint32_t value = cfg[i].value & mask;
+
+ mmio_clrsetbits_32(base + cfg[i].offset, mask, value);
+ }
+}
+
+/* Structure is used for set/clear registers and for regular registers */
+struct backup_clock_cfg {
+ uint32_t offset;
+ uint32_t value;
+};
+
+static struct backup_clock_cfg backup_clock_sc_cfg[] = {
+ { .offset = RCC_MP_APB1ENSETR },
+ { .offset = RCC_MP_APB2ENSETR },
+ { .offset = RCC_MP_APB3ENSETR },
+ { .offset = RCC_MP_APB4ENSETR },
+ { .offset = RCC_MP_APB5ENSETR },
+ { .offset = RCC_MP_AHB2ENSETR },
+ { .offset = RCC_MP_AHB3ENSETR },
+ { .offset = RCC_MP_AHB4ENSETR },
+ { .offset = RCC_MP_AHB5ENSETR },
+ { .offset = RCC_MP_AHB6ENSETR },
+ { .offset = RCC_MP_MLAHBENSETR },
+};
+
+static struct backup_clock_cfg backup_clock_cfg[] = {
+ { .offset = RCC_MCO1CFGR },
+ { .offset = RCC_MCO2CFGR },
+ { .offset = RCC_PLL3CR },
+ { .offset = RCC_PLL4CR },
+ { .offset = RCC_PLL4CFGR2 },
+ { .offset = RCC_MCUDIVR },
+ { .offset = RCC_MSSCKSELR },
+};
+
+static void backup_sc_cfg(void)
+{
+ struct backup_clock_cfg *cfg = backup_clock_sc_cfg;
+ size_t count = ARRAY_SIZE(backup_clock_sc_cfg);
+ uintptr_t base = stm32mp_rcc_base();
+ size_t i;
+
+ for (i = 0U; i < count; i++) {
+ cfg[i].value = mmio_read_32(base + cfg[i].offset);
+ }
+}
+
+static void restore_sc_cfg(void)
+{
+ struct backup_clock_cfg *cfg = backup_clock_sc_cfg;
+ size_t count = ARRAY_SIZE(backup_clock_sc_cfg);
+ uintptr_t base = stm32mp_rcc_base();
+ size_t i;
+
+ for (i = 0U; i < count; i++) {
+ mmio_write_32(base + cfg[i].offset, cfg[i].value);
+ mmio_write_32(base + cfg[i].offset + RCC_MP_ENCLRR_OFFSET,
+ ~cfg[i].value);
+ }
+}
+
+static void backup_regular_cfg(void)
+{
+ struct backup_clock_cfg *cfg = backup_clock_cfg;
+ size_t count = ARRAY_SIZE(backup_clock_cfg);
+ uintptr_t base = stm32mp_rcc_base();
+ size_t i;
+
+ for (i = 0U; i < count; i++) {
+ cfg[i].value = mmio_read_32(base + cfg[i].offset);
+ }
+}
+
+static void restore_regular_cfg(void)
+{
+ struct backup_clock_cfg *cfg = backup_clock_cfg;
+ size_t count = ARRAY_SIZE(backup_clock_cfg);
+ uintptr_t base = stm32mp_rcc_base();
+ size_t i;
+
+ for (i = 0U; i < count; i++) {
+ mmio_write_32(base + cfg[i].offset, cfg[i].value);
+ }
+}
+
+static void disable_kernel_clocks(void)
+{
+ const uint32_t ker_mask = RCC_OCENR_HSIKERON |
+ RCC_OCENR_CSIKERON |
+ RCC_OCENR_HSEKERON;
+
+ /* Disable all ck_xxx_ker clocks */
+ mmio_write_32(stm32mp_rcc_base() + RCC_OCENCLRR, ker_mask);
+}
+
+static void enable_kernel_clocks(void)
+{
+ uintptr_t rcc_base = stm32mp_rcc_base();
+ uint32_t reg;
+ const uint32_t ker_mask = RCC_OCENR_HSIKERON |
+ RCC_OCENR_CSIKERON |
+ RCC_OCENR_HSEKERON;
+
+ /* Enable ck_xxx_ker clocks if ck_xxx was on */
+ reg = mmio_read_32(rcc_base + RCC_OCENSETR) << 1U;
+ mmio_write_32(rcc_base + RCC_OCENSETR, reg & ker_mask);
+}
+
+static void clear_rcc_reset_status(void)
+{
+ /* Clear reset status fields */
+ mmio_write_32(stm32mp_rcc_base() + RCC_MP_RSTSCLRR, 0U);
+}
+
+void save_clock_pm_context(void)
+{
+ size_t offset = 0U;
+
+ stm32mp1_pm_save_clock_cfg(offset,
+ (uint8_t *)backup_mux0_cfg,
+ sizeof(backup_mux0_cfg));
+ offset += sizeof(backup_mux0_cfg);
+
+ stm32mp1_pm_save_clock_cfg(offset,
+ (uint8_t *)backup_mux4_cfg,
+ sizeof(backup_mux4_cfg));
+ offset += sizeof(backup_mux4_cfg);
+
+ stm32mp1_pm_save_clock_cfg(offset,
+ (uint8_t *)backup_clock_sc_cfg,
+ sizeof(backup_clock_sc_cfg));
+ offset += sizeof(backup_clock_sc_cfg);
+
+ stm32mp1_pm_save_clock_cfg(offset,
+ (uint8_t *)backup_clock_cfg,
+ sizeof(backup_clock_cfg));
+ offset += sizeof(backup_clock_cfg);
+
+ stm32mp1_pm_save_clock_cfg(offset,
+ (uint8_t *)gate_refcounts,
+ sizeof(gate_refcounts));
+}
+
+void restore_clock_pm_context(void)
+{
+ size_t offset = 0U;
+
+ stm32mp1_pm_restore_clock_cfg(offset,
+ (uint8_t *)backup_mux0_cfg,
+ sizeof(backup_mux0_cfg));
+ offset += sizeof(backup_mux0_cfg);
+
+ stm32mp1_pm_restore_clock_cfg(offset,
+ (uint8_t *)backup_mux4_cfg,
+ sizeof(backup_mux4_cfg));
+ offset += sizeof(backup_mux4_cfg);
+
+ stm32mp1_pm_restore_clock_cfg(offset,
+ (uint8_t *)backup_clock_sc_cfg,
+ sizeof(backup_clock_sc_cfg));
+ offset += sizeof(backup_clock_sc_cfg);
+
+ stm32mp1_pm_restore_clock_cfg(offset,
+ (uint8_t *)backup_clock_cfg,
+ sizeof(backup_clock_cfg));
+ offset += sizeof(backup_clock_cfg);
+
+ stm32mp1_pm_restore_clock_cfg(offset,
+ (uint8_t *)gate_refcounts,
+ sizeof(gate_refcounts));
+}
+
+void stm32mp1_clock_suspend(void)
+{
+ backup_regular_cfg();
+ backup_sc_cfg();
+ backup_mux_cfg();
+ clear_rcc_reset_status();
+}
+
+void stm32mp1_clock_resume(void)
+{
+ unsigned int idx;
+
+ restore_mux_cfg();
+ restore_sc_cfg();
+ restore_regular_cfg();
+
+ /* Sync secure and shared clocks physical state on functional state */
+ for (idx = 0U; idx < NB_GATES; idx++) {
+ struct stm32mp1_clk_gate const *gate = gate_ref(idx);
+
+ if (gate_is_non_secure(gate)) {
+ continue;
+ }
+
+ if (gate_refcounts[idx] != 0U) {
+ VERBOSE("Resume clock %d enable\n", gate->index);
+ __clk_enable(gate);
+ } else {
+ VERBOSE("Resume clock %d disable\n", gate->index);
+ __clk_disable(gate);
+ }
+ }
+
+ disable_kernel_clocks();
+}
+
+void stm32mp1_clock_stopmode_save(void)
+{
+ uintptr_t rcc_base = stm32mp_rcc_base();
+
+ /* Save registers not restored after STOP mode */
+ pll3cr = mmio_read_32(rcc_base + RCC_PLL3CR);
+ pll4cr = mmio_read_32(rcc_base + RCC_PLL4CR);
+ mssckselr = mmio_read_32(rcc_base + RCC_MSSCKSELR);
+ mcudivr = mmio_read_32(rcc_base + RCC_MCUDIVR) & RCC_MCUDIV_MASK;
+ enable_kernel_clocks();
+}
+
+static bool pll_is_running(uint32_t pll_offset)
+{
+ uintptr_t pll_cr = stm32mp_rcc_base() + pll_offset;
+
+ return (mmio_read_32(pll_cr) & RCC_PLLNCR_PLLON) != 0U;
+}
+
+static bool pll_was_running(uint32_t saved_value)
+{
+ return (saved_value & RCC_PLLNCR_PLLON) != 0U;
+}
+
+int stm32mp1_clock_stopmode_resume(void)
+{
+ int res;
+ uintptr_t rcc_base = stm32mp_rcc_base();
+
+ if (pll_was_running(pll4cr) && !pll_is_running(RCC_PLL4CR)) {
+ stm32mp1_pll_start(_PLL4);
+ }
+
+ if (pll_was_running(pll3cr)) {
+ if (!pll_is_running(RCC_PLL3CR)) {
+ stm32mp1_pll_start(_PLL3);
+ }
+
+ res = stm32mp1_pll_output(_PLL3,
+ pll3cr >> RCC_PLLNCR_DIVEN_SHIFT);
+ if (res != 0) {
+ return res;
+ }
+ }
+
+ if (pll_was_running(pll4cr)) {
+ res = stm32mp1_pll_output(_PLL4,
+ pll4cr >> RCC_PLLNCR_DIVEN_SHIFT);
+ if (res != 0) {
+ return res;
+ }
+ }
+
+ /* Restore MCU clock src after PLL3 RDY */
+ mmio_write_32(rcc_base + RCC_MSSCKSELR, mssckselr);
+
+ /* Restore MCUDIV */
+ res = stm32mp1_set_clkdiv(mcudivr, rcc_base + RCC_MCUDIVR);
+ if (res != 0) {
+ return res;
+ }
+
+ disable_kernel_clocks();
+
+ return 0;
+}
+
+/* Sync secure clock refcount after all drivers probe/inits, */
+void stm32mp1_dump_clocks_state(void)
+{
+#if LOG_LEVEL >= LOG_LEVEL_VERBOSE
+ unsigned int idx;
+
+ /* 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)
{
- if (!stm32mp_is_single_core()) {
- stm32mp1_clk_enable_secure(RTCAPB);
+ unsigned int n;
+
+ for (n = 0U; n < ARRAY_SIZE(stm32mp1_clk_gate); n++) {
+ const struct stm32mp1_clk_gate *gate = gate_ref(n);
+
+ if (!gate_is_non_secure(gate))
+ stm32mp1_register_clock_parents_secure(gate->index);
}
+
+ /*
+ * Register secure clock parents and init a refcount for
+ * secure only resources that are not registered from a driver probe.
+ * - DDR controller and phy clocks.
+ * - TZC400, ETZPC and STGEN clocks.
+ * - RTCAPB clocks on multi-core
+ */
+ stm32mp_clk_enable(AXIDCG);
+
+ stm32mp_clk_enable(DDRC1);
+ stm32mp_clk_enable(DDRC1LP);
+ stm32mp_clk_enable(DDRC2);
+ stm32mp_clk_enable(DDRC2LP);
+ stm32mp_clk_enable(DDRCAPB);
+ stm32mp_clk_enable(DDRPHYC);
+ stm32mp_clk_enable(DDRPHYCLP);
+ stm32mp_clk_enable(DDRPHYCAPB);
+ stm32mp_clk_enable(DDRPHYCAPBLP);
+
+ stm32mp_clk_enable(TZPC);
+ stm32mp_clk_enable(TZC1);
+ stm32mp_clk_enable(TZC2);
+ stm32mp_clk_enable(STGEN_K);
+
+ stm32mp_clk_enable(RTCAPB);
}
int stm32mp1_clk_probe(void)
{
+ unsigned long freq_khz;
+
+ assert(PLLCFG_NB == PLAT_MAX_PLLCFG_NB);
+
stm32mp1_osc_init();
sync_earlyboot_clocks_state();
+ /* Save current CPU operating point value */
+ freq_khz = udiv_round_nearest(stm32mp_clk_get_rate(CK_MPU), 1000UL);
+ if (freq_khz > (unsigned long)UINT32_MAX) {
+ panic();
+ }
+
+ current_opp_khz = (uint32_t)freq_khz;
+
return 0;
}
diff --git a/drivers/st/clk/stm32mp_clkfunc.c b/drivers/st/clk/stm32mp_clkfunc.c
index 87c8e2b84..d3ea010ff 100644
--- a/drivers/st/clk/stm32mp_clkfunc.c
+++ b/drivers/st/clk/stm32mp_clkfunc.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019, STMicroelectronics - All Rights Reserved
+ * Copyright (c) 2017-2020, STMicroelectronics - All Rights Reserved
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -10,10 +10,13 @@
#include <platform_def.h>
+#include <arch_helpers.h>
+#include <drivers/generic_delay_timer.h>
#include <drivers/st/stm32_gpio.h>
#include <drivers/st/stm32mp_clkfunc.h>
+#include <lib/mmio.h>
-#define DT_STGEN_COMPAT "st,stm32-stgen"
+#define DT_UART_COMPAT "st,stm32h7-uart"
/*
* Get the frequency of an oscillator from its name in device tree.
@@ -44,7 +47,8 @@ int fdt_osc_read_freq(const char *name, uint32_t *freq)
return ret;
}
- if (strncmp(cchar, name, (size_t)ret) == 0) {
+ if ((strncmp(cchar, name, (size_t)ret) == 0) &&
+ (fdt_get_status(subnode) != DT_DISABLED)) {
const fdt32_t *cuint;
cuint = fdt_getprop(fdt, subnode, "clock-frequency",
@@ -158,39 +162,11 @@ uint32_t fdt_osc_read_uint32_default(enum stm32mp_osc_id osc_id,
/*
* Get the RCC node offset from the device tree
- * @param fdt: Device tree reference
* @return: Node offset or a negative value on error
*/
-int fdt_get_rcc_node(void *fdt)
+int fdt_get_rcc_node(void)
{
- return fdt_node_offset_by_compatible(fdt, -1, DT_RCC_CLK_COMPAT);
-}
-
-/*
- * Get the RCC base address from the device tree
- * @return: RCC address or 0 on error
- */
-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);
+ return dt_get_node_by_compatible(DT_RCC_CLK_COMPAT);
}
/*
@@ -204,13 +180,8 @@ 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);
+ node = fdt_get_rcc_node();
if (node < 0) {
return -FDT_ERR_NOTFOUND;
}
@@ -218,6 +189,24 @@ int fdt_rcc_read_uint32_array(const char *prop_name,
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;
+
+ node = fdt_get_rcc_node();
+ if (node < 0) {
+ return dflt_value;
+ }
+
+ return fdt_read_uint32_default(node, prop_name, dflt_value);
+}
+
/*
* Get the subnode offset in rcc-clk section from its name in device tree
* @param name: name of the RCC property
@@ -232,7 +221,7 @@ int fdt_rcc_subnode_offset(const char *name)
return -ENOENT;
}
- node = fdt_get_rcc_node(fdt);
+ node = fdt_get_rcc_node();
if (node < 0) {
return -FDT_ERR_NOTFOUND;
}
@@ -261,7 +250,7 @@ const fdt32_t *fdt_rcc_read_prop(const char *prop_name, int *lenp)
return NULL;
}
- node = fdt_get_rcc_node(fdt);
+ node = fdt_get_rcc_node();
if (node < 0) {
return NULL;
}
@@ -282,13 +271,8 @@ const fdt32_t *fdt_rcc_read_prop(const char *prop_name, int *lenp)
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);
+ node = fdt_get_rcc_node();
if (node < 0) {
return false;
}
@@ -297,30 +281,19 @@ bool fdt_get_rcc_secure_status(void)
}
/*
- * Get the stgen base address.
- * @return: address of stgen on success, and NULL value on failure.
+ * This function gets interrupt name.
+ * It reads the values indicated the enabling status.
+ * Returns 0 if success, and a negative value else.
*/
-uintptr_t fdt_get_stgen_base(void)
+int fdt_rcc_enable_it(const char *name)
{
- int node;
- const fdt32_t *cuint;
- void *fdt;
+ int node = fdt_get_rcc_node();
- if (fdt_get_address(&fdt) == 0) {
- return 0;
- }
-
- node = fdt_node_offset_by_compatible(fdt, -1, DT_STGEN_COMPAT);
if (node < 0) {
- return 0;
+ return -ENODEV;
}
- cuint = fdt_getprop(fdt, node, "reg", NULL);
- if (cuint == NULL) {
- return 0;
- }
-
- return fdt32_to_cpu(*cuint);
+ return stm32_gic_enable_spi(node, name);
}
/*
@@ -345,3 +318,137 @@ int fdt_get_clock_id(int node)
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)
+{
+ void *fdt;
+ int node;
+ int clk_id;
+
+ if (fdt_get_address(&fdt) == 0) {
+ return 0;
+ }
+
+ /* Check for UART nodes */
+ node = dt_match_instance_by_compatible(DT_UART_COMPAT, instance);
+ if (node < 0) {
+ return 0UL;
+ }
+
+ clk_id = fdt_get_clock_id(node);
+ if (clk_id < 0) {
+ return 0UL;
+ }
+
+ return stm32mp_clk_get_rate((unsigned long)clk_id);
+}
+
+/*******************************************************************************
+ * This function checks if PLL1 hard-coded settings have been defined in DT.
+ * Returns true if PLL1 node is found and enabled, false if not.
+ ******************************************************************************/
+bool fdt_is_pll1_predefined(void)
+{
+ return fdt_check_node(fdt_rcc_subnode_offset(DT_PLL1_NODE_NAME));
+}
+
+/*******************************************************************************
+ * This function configures and restores the STGEN counter depending on the
+ * connected clock.
+ ******************************************************************************/
+void stm32mp_stgen_config(unsigned long rate)
+{
+ uint32_t cntfid0;
+ unsigned long long counter;
+
+ cntfid0 = mmio_read_32(STGEN_BASE + CNTFID_OFF);
+
+ if (cntfid0 == rate) {
+ return;
+ }
+
+ mmio_clrbits_32(STGEN_BASE + CNTCR_OFF, CNTCR_EN);
+ counter = stm32mp_stgen_get_counter() * rate / cntfid0;
+
+ mmio_write_32(STGEN_BASE + CNTCVL_OFF, (uint32_t)counter);
+ mmio_write_32(STGEN_BASE + CNTCVU_OFF, (uint32_t)(counter >> 32));
+ mmio_write_32(STGEN_BASE + CNTFID_OFF, rate);
+ mmio_setbits_32(STGEN_BASE + CNTCR_OFF, CNTCR_EN);
+
+ write_cntfrq_el0((u_register_t)rate);
+
+ /* Need to update timer with new frequency */
+ generic_delay_timer_init();
+}
+
+/*******************************************************************************
+ * This function returns the STGEN counter value.
+ ******************************************************************************/
+unsigned long long stm32mp_stgen_get_counter(void)
+{
+ unsigned long long cnt;
+
+ cnt = mmio_read_32(STGEN_BASE + CNTCVU_OFF);
+ cnt <<= 32;
+ cnt |= mmio_read_32(STGEN_BASE + CNTCVL_OFF);
+
+ return cnt;
+}
+
+/*******************************************************************************
+ * This function restores the STGEN counter value.
+ * It takes a first input value as a counter backup value to be restored and a
+ * offset in ms to be added.
+ ******************************************************************************/
+void stm32mp_stgen_restore_counter(unsigned long long value,
+ unsigned long long offset_in_ms)
+{
+ unsigned long long cnt = value;
+
+ cnt += (offset_in_ms * mmio_read_32(STGEN_BASE + CNTFID_OFF)) / 1000U;
+
+ mmio_clrbits_32(STGEN_BASE + CNTCR_OFF, CNTCR_EN);
+ mmio_write_32(STGEN_BASE + CNTCVL_OFF, (uint32_t)cnt);
+ mmio_write_32(STGEN_BASE + CNTCVU_OFF, (uint32_t)(cnt >> 32));
+ mmio_setbits_32(STGEN_BASE + CNTCR_OFF, CNTCR_EN);
+}
diff --git a/drivers/st/crypto/stm32_hash.c b/drivers/st/crypto/stm32_hash.c
index f72787d33..fcc45fada 100644
--- a/drivers/st/crypto/stm32_hash.c
+++ b/drivers/st/crypto/stm32_hash.c
@@ -21,6 +21,8 @@
#include <lib/utils.h>
#include <plat/common/platform.h>
+#define TIMEOUT_US_1MS U(1000)
+
#define DT_HASH_COMPAT "st,stm32f756-hash"
#define HASH_CR 0x00U
@@ -251,6 +253,8 @@ int stm32_hash_final(uint8_t *digest)
mmio_clrsetbits_32(hash_base() + HASH_STR, HASH_STR_NBLW_MASK,
8U * stm32_remain.length);
zeromem(&stm32_remain, sizeof(stm32_remain));
+ } else {
+ mmio_clrbits_32(hash_base() + HASH_STR, HASH_STR_NBLW_MASK);
}
mmio_setbits_32(hash_base() + HASH_STR, HASH_STR_DCAL);
@@ -319,9 +323,16 @@ int stm32_hash_register(void)
stm32mp_clk_enable(stm32_hash.clock);
if (hash_info.reset >= 0) {
- stm32mp_reset_assert((unsigned long)hash_info.reset);
+ uint32_t reset = hash_info.reset;
+
+ if (stm32mp_reset_assert_to(reset, TIMEOUT_US_1MS)) {
+ panic();
+ }
+
udelay(20);
- stm32mp_reset_deassert((unsigned long)hash_info.reset);
+ if (stm32mp_reset_deassert_to(reset, TIMEOUT_US_1MS)) {
+ panic();
+ }
}
stm32mp_clk_disable(stm32_hash.clock);
diff --git a/drivers/st/ddr/stm32mp1_ddr.c b/drivers/st/ddr/stm32mp1_ddr.c
index 7d89d027e..db8247522 100644
--- a/drivers/st/ddr/stm32mp1_ddr.c
+++ b/drivers/st/ddr/stm32mp1_ddr.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2018-2019, STMicroelectronics - All Rights Reserved
+ * Copyright (C) 2018-2020, STMicroelectronics - All Rights Reserved
*
* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
*/
@@ -29,6 +29,7 @@ struct reg_desc {
#define INVALID_OFFSET 0xFFU
+#define TIMESLOT_US_1US 1U
#define TIMEOUT_US_1S 1000000U
#define DDRCTL_REG(x, y) \
@@ -45,8 +46,22 @@ struct reg_desc {
.par_offset = offsetof(struct y, x) \
}
+/*
+ * PARAMETERS: value get from device tree :
+ * size / order need to be aligned with binding
+ * modification NOT ALLOWED !!!
+ */
+#define DDRCTL_REG_REG_SIZE 25 /* st,ctl-reg */
+#define DDRCTL_REG_TIMING_SIZE 12 /* st,ctl-timing */
+#define DDRCTL_REG_MAP_SIZE 9 /* st,ctl-map */
+#define DDRCTL_REG_PERF_SIZE 17 /* st,ctl-perf */
+
+#define DDRPHY_REG_REG_SIZE 11 /* st,phy-reg */
+#define DDRPHY_REG_TIMING_SIZE 10 /* st,phy-timing */
+#define DDRPHY_REG_CAL_SIZE 12 /* st,phy-cal */
+
#define DDRCTL_REG_REG(x) DDRCTL_REG(x, stm32mp1_ddrctrl_reg)
-static const struct reg_desc ddr_reg[] = {
+static const struct reg_desc ddr_reg[DDRCTL_REG_REG_SIZE] = {
DDRCTL_REG_REG(mstr),
DDRCTL_REG_REG(mrctrl0),
DDRCTL_REG_REG(mrctrl1),
@@ -75,7 +90,7 @@ static const struct reg_desc ddr_reg[] = {
};
#define DDRCTL_REG_TIMING(x) DDRCTL_REG(x, stm32mp1_ddrctrl_timing)
-static const struct reg_desc ddr_timing[] = {
+static const struct reg_desc ddr_timing[DDRCTL_REG_TIMING_SIZE] = {
DDRCTL_REG_TIMING(rfshtmg),
DDRCTL_REG_TIMING(dramtmg0),
DDRCTL_REG_TIMING(dramtmg1),
@@ -91,7 +106,7 @@ static const struct reg_desc ddr_timing[] = {
};
#define DDRCTL_REG_MAP(x) DDRCTL_REG(x, stm32mp1_ddrctrl_map)
-static const struct reg_desc ddr_map[] = {
+static const struct reg_desc ddr_map[DDRCTL_REG_MAP_SIZE] = {
DDRCTL_REG_MAP(addrmap1),
DDRCTL_REG_MAP(addrmap2),
DDRCTL_REG_MAP(addrmap3),
@@ -104,7 +119,7 @@ static const struct reg_desc ddr_map[] = {
};
#define DDRCTL_REG_PERF(x) DDRCTL_REG(x, stm32mp1_ddrctrl_perf)
-static const struct reg_desc ddr_perf[] = {
+static const struct reg_desc ddr_perf[DDRCTL_REG_PERF_SIZE] = {
DDRCTL_REG_PERF(sched),
DDRCTL_REG_PERF(sched1),
DDRCTL_REG_PERF(perfhpr1),
@@ -125,7 +140,7 @@ static const struct reg_desc ddr_perf[] = {
};
#define DDRPHY_REG_REG(x) DDRPHY_REG(x, stm32mp1_ddrphy_reg)
-static const struct reg_desc ddrphy_reg[] = {
+static const struct reg_desc ddrphy_reg[DDRPHY_REG_REG_SIZE] = {
DDRPHY_REG_REG(pgcr),
DDRPHY_REG_REG(aciocr),
DDRPHY_REG_REG(dxccr),
@@ -140,7 +155,7 @@ static const struct reg_desc ddrphy_reg[] = {
};
#define DDRPHY_REG_TIMING(x) DDRPHY_REG(x, stm32mp1_ddrphy_timing)
-static const struct reg_desc ddrphy_timing[] = {
+static const struct reg_desc ddrphy_timing[DDRPHY_REG_TIMING_SIZE] = {
DDRPHY_REG_TIMING(ptr0),
DDRPHY_REG_TIMING(ptr1),
DDRPHY_REG_TIMING(ptr2),
@@ -154,7 +169,7 @@ static const struct reg_desc ddrphy_timing[] = {
};
#define DDRPHY_REG_CAL(x) DDRPHY_REG(x, stm32mp1_ddrphy_cal)
-static const struct reg_desc ddrphy_cal[] = {
+static const struct reg_desc ddrphy_cal[DDRPHY_REG_CAL_SIZE] = {
DDRPHY_REG_CAL(dx0dllcr),
DDRPHY_REG_CAL(dx0dqtr),
DDRPHY_REG_CAL(dx0dqstr),
@@ -169,36 +184,9 @@ static const struct reg_desc ddrphy_cal[] = {
DDRPHY_REG_CAL(dx3dqstr),
};
-#define DDR_REG_DYN(x) \
- { \
- .name = #x, \
- .offset = offsetof(struct stm32mp1_ddrctl, x), \
- .par_offset = INVALID_OFFSET \
- }
-
-static const struct reg_desc ddr_dyn[] = {
- DDR_REG_DYN(stat),
- DDR_REG_DYN(init0),
- DDR_REG_DYN(dfimisc),
- DDR_REG_DYN(dfistat),
- DDR_REG_DYN(swctl),
- DDR_REG_DYN(swstat),
- DDR_REG_DYN(pctrl_0),
- DDR_REG_DYN(pctrl_1),
-};
-
-#define DDRPHY_REG_DYN(x) \
- { \
- .name = #x, \
- .offset = offsetof(struct stm32mp1_ddrphy, x), \
- .par_offset = INVALID_OFFSET \
- }
-
-static const struct reg_desc ddrphy_dyn[] = {
- DDRPHY_REG_DYN(pir),
- DDRPHY_REG_DYN(pgsr),
-};
-
+/*
+ * REGISTERS ARRAY: used to parse device tree and interactive mode
+ */
enum reg_type {
REG_REG,
REG_TIMING,
@@ -207,12 +195,6 @@ enum reg_type {
REGPHY_REG,
REGPHY_TIMING,
REGPHY_CAL,
-/*
- * Dynamic registers => managed in driver or not changed,
- * can be dumped in interactive mode.
- */
- REG_DYN,
- REGPHY_DYN,
REG_TYPE_NB
};
@@ -233,55 +215,43 @@ static const struct ddr_reg_info ddr_registers[REG_TYPE_NB] = {
[REG_REG] = {
.name = "static",
.desc = ddr_reg,
- .size = ARRAY_SIZE(ddr_reg),
+ .size = DDRCTL_REG_REG_SIZE,
.base = DDR_BASE
},
[REG_TIMING] = {
.name = "timing",
.desc = ddr_timing,
- .size = ARRAY_SIZE(ddr_timing),
+ .size = DDRCTL_REG_TIMING_SIZE,
.base = DDR_BASE
},
[REG_PERF] = {
.name = "perf",
.desc = ddr_perf,
- .size = ARRAY_SIZE(ddr_perf),
+ .size = DDRCTL_REG_PERF_SIZE,
.base = DDR_BASE
},
[REG_MAP] = {
.name = "map",
.desc = ddr_map,
- .size = ARRAY_SIZE(ddr_map),
+ .size = DDRCTL_REG_MAP_SIZE,
.base = DDR_BASE
},
[REGPHY_REG] = {
.name = "static",
.desc = ddrphy_reg,
- .size = ARRAY_SIZE(ddrphy_reg),
+ .size = DDRPHY_REG_REG_SIZE,
.base = DDRPHY_BASE
},
[REGPHY_TIMING] = {
.name = "timing",
.desc = ddrphy_timing,
- .size = ARRAY_SIZE(ddrphy_timing),
+ .size = DDRPHY_REG_TIMING_SIZE,
.base = DDRPHY_BASE
},
[REGPHY_CAL] = {
.name = "cal",
.desc = ddrphy_cal,
- .size = ARRAY_SIZE(ddrphy_cal),
- .base = DDRPHY_BASE
- },
- [REG_DYN] = {
- .name = "dyn",
- .desc = ddr_dyn,
- .size = ARRAY_SIZE(ddr_dyn),
- .base = DDR_BASE
- },
- [REGPHY_DYN] = {
- .name = "dyn",
- .desc = ddrphy_dyn,
- .size = ARRAY_SIZE(ddrphy_dyn),
+ .size = DDRPHY_REG_CAL_SIZE,
.base = DDRPHY_BASE
},
};
@@ -675,7 +645,8 @@ static void stm32mp1_refresh_disable(struct stm32mp1_ddrctl *ctl)
/* Quasi-dynamic register update*/
mmio_setbits_32((uintptr_t)&ctl->rfshctl3,
DDRCTRL_RFSHCTL3_DIS_AUTO_REFRESH);
- mmio_clrbits_32((uintptr_t)&ctl->pwrctl, DDRCTRL_PWRCTL_POWERDOWN_EN);
+ mmio_clrbits_32((uintptr_t)&ctl->pwrctl, DDRCTRL_PWRCTL_POWERDOWN_EN |
+ DDRCTRL_PWRCTL_SELFREF_EN);
mmio_clrbits_32((uintptr_t)&ctl->dfimisc,
DDRCTRL_DFIMISC_DFI_INIT_COMPLETE_EN);
stm32mp1_wait_sw_done_ack(ctl);
@@ -693,11 +664,92 @@ static void stm32mp1_refresh_restore(struct stm32mp1_ddrctl *ctl,
mmio_setbits_32((uintptr_t)&ctl->pwrctl,
DDRCTRL_PWRCTL_POWERDOWN_EN);
}
+ if ((pwrctl & DDRCTRL_PWRCTL_SELFREF_EN) != 0U) {
+ mmio_setbits_32((uintptr_t)&ctl->pwrctl,
+ DDRCTRL_PWRCTL_SELFREF_EN);
+ }
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_us, tref, trefi, refcomp, i;
+
+ time_us = timeout_init_us(0) - start;
+ 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_pmic_status() > 0) {
@@ -710,7 +762,7 @@ 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;
+ uint32_t pir, ddr_reten;
int ret = -EINVAL;
if ((config->c_reg.mstr & DDRCTRL_MSTR_DDR3) != 0U) {
@@ -730,6 +782,27 @@ void stm32mp1_ddr_init(struct ddr_info *priv,
VERBOSE("name = %s\n", config->info.name);
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 */
@@ -790,6 +863,12 @@ void stm32mp1_ddr_init(struct ddr_info *priv,
set_reg(priv, REG_TIMING, &config->c_timing);
set_reg(priv, REG_MAP, &config->c_map);
+ /* 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,
@@ -811,7 +890,9 @@ void stm32mp1_ddr_init(struct ddr_info *priv,
*/
set_reg(priv, REGPHY_REG, &config->p_reg);
set_reg(priv, REGPHY_TIMING, &config->p_timing);
- set_reg(priv, REGPHY_CAL, &config->p_cal);
+ if (config->p_cal_present) {
+ set_reg(priv, REGPHY_CAL, &config->p_cal);
+ }
/* DDR3 = don't set DLLOFF for init mode */
if ((config->c_reg.mstr &
@@ -843,8 +924,20 @@ 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.
@@ -865,6 +958,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 */
@@ -872,37 +972,53 @@ void stm32mp1_ddr_init(struct ddr_info *priv,
stm32mp1_ddr3_dll_off(priv);
}
- VERBOSE("DDR DQS training : ");
-
- /*
- * 8. Disable Auto refresh and power down by setting
- * - RFSHCTL3.dis_au_refresh = 1
- * - PWRCTL.powerdown_en = 0
- * - DFIMISC.dfiinit_complete_en = 0
- */
- stm32mp1_refresh_disable(priv->ctl);
-
- /*
- * 9. Program PUBL PGCR to enable refresh during training
- * and rank to train
- * not done => keep the programed value in PGCR
- */
-
- /*
- * 10. configure PUBL PIR register to specify which training step
- * to run
- * Warning : RVTRN is not supported by this PUBL
- */
- stm32mp1_ddrphy_init(priv->phy, DDRPHYC_PIR_QSTRN);
-
- /* 11. monitor PUB PGSR.IDONE to poll cpmpletion of training sequence */
- stm32mp1_ddrphy_idone_wait(priv->phy);
+ if (config->p_cal_present) {
+ VERBOSE("DDR DQS training skipped.\n");
+ } else {
+ uint64_t time;
+
+ VERBOSE("DDR DQS training.\n");
+
+ time = timeout_init_us(0);
+
+ /*
+ * 8. Disable Auto refresh and power down by setting
+ * - RFSHCTL3.dis_au_refresh = 1
+ * - PWRCTL.powerdown_en = 0
+ * - DFIMISC.dfiinit_complete_en = 0
+ */
+ stm32mp1_refresh_disable(priv->ctl);
+
+ /*
+ * 9. Program PUBL PGCR to enable refresh during training
+ * and rank to train
+ * not done => keep the programed value in PGCR
+ */
+
+ /*
+ * 10. configure PUBL PIR register to specify which training
+ * step to run
+ * Warning : RVTRN is not supported by this PUBL
+ */
+ stm32mp1_ddrphy_init(priv->phy, DDRPHYC_PIR_QSTRN);
+
+ /* 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
- */
- stm32mp1_refresh_restore(priv->ctl, config->c_reg.rfshctl3,
- config->c_reg.pwrctl);
+ /*
+ * 12. set back registers in step 8 to the orginal values
+ * if desidered
+ */
+ stm32mp1_refresh_restore(priv->ctl, config->c_reg.rfshctl3,
+ config->c_reg.pwrctl);
+ }
/* Enable uMCTL2 AXI port 0 */
mmio_setbits_32((uintptr_t)&priv->ctl->pctrl_0,
diff --git a/drivers/st/ddr/stm32mp1_ddr_helpers.c b/drivers/st/ddr/stm32mp1_ddr_helpers.c
index fcb4cfcfd..3b8af550f 100644
--- a/drivers/st/ddr/stm32mp1_ddr_helpers.c
+++ b/drivers/st/ddr/stm32mp1_ddr_helpers.c
@@ -1,14 +1,23 @@
/*
- * Copyright (c) 2017-2019, STMicroelectronics - All Rights Reserved
+ * Copyright (c) 2017-2020, STMicroelectronics - All Rights Reserved
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <platform_def.h>
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <drivers/st/stm32mp1_ddr.h>
#include <drivers/st/stm32mp1_ddr_helpers.h>
+#include <drivers/st/stm32mp1_ddr_regs.h>
#include <lib/mmio.h>
+#define TIMEOUT_500US 500U
+
+static enum stm32mp1_ddr_sr_mode saved_ddr_sr_mode;
+
void ddr_enable_clock(void)
{
stm32mp1_clk_rcc_regs_lock();
@@ -22,3 +31,564 @@ void ddr_enable_clock(void)
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 timeout;
+ uintptr_t ddrctrl_base = stm32mp_ddrctrl_base();
+
+ mmio_setbits_32(ddrctrl_base + DDRCTRL_SWCTL, DDRCTRL_SWCTL_SW_DONE);
+
+ timeout = timeout_init_us(TIMEOUT_500US);
+ while ((mmio_read_32(ddrctrl_base + DDRCTRL_SWSTAT) &
+ DDRCTRL_SWSTAT_SW_DONE_ACK) == 0U) {
+ if (timeout_elapsed(timeout)) {
+ panic();
+ }
+ }
+}
+
+static int ddr_sw_self_refresh_in(void)
+{
+ uint64_t timeout;
+ 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
+ */
+ timeout = timeout_init_us(TIMEOUT_500US);
+ while (mmio_read_32(ddrctrl_base + DDRCTRL_PSTAT)) {
+ if (timeout_elapsed(timeout)) {
+ 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.
+ */
+ timeout = timeout_init_us(TIMEOUT_500US);
+ while (!timeout_elapsed(timeout)) {
+ 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);
+
+ /* Disable command/address output driver */
+ mmio_clrbits_32(ddrphyc_base + DDRPHYC_ACIOCR, DDRPHYC_ACIOCR_ACOE);
+
+ 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);
+
+ /* Set latch */
+ mmio_clrbits_32(ddrphyc_base + DDRPHYC_DSGCR, DDRPHYC_DSGCR_CKOE);
+
+ /* Additional delay to avoid early latch */
+ udelay(10);
+
+ /* Activate sw retention in PWRCTRL */
+ stm32mp_pwr_regs_lock();
+ mmio_setbits_32(pwr_base + PWR_CR3, PWR_CR3_DDRRETEN);
+ stm32mp_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 timeout;
+ 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(50);
+
+ /* 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 */
+ timeout = timeout_init_us(TIMEOUT_500US);
+
+ while ((mmio_read_32(ddrphyc_base + DDRPHYC_PGSR) &
+ DDRPHYC_PGSR_IDONE) == 0U) {
+ if (timeout_elapsed(timeout)) {
+ 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 */
+ stm32mp_pwr_regs_lock();
+ mmio_clrbits_32(pwr_base + PWR_CR3, PWR_CR3_DDRRETEN);
+ stm32mp_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);
+
+ /* Enable command/address output driver */
+ mmio_setbits_32(ddrphyc_base + DDRPHYC_ACIOCR, DDRPHYC_ACIOCR_ACOE);
+
+ 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);
+
+ /* Release latch */
+ mmio_setbits_32(ddrphyc_base + DDRPHYC_DSGCR, DDRPHYC_DSGCR_CKOE);
+
+ 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 */
+ timeout = timeout_init_us(TIMEOUT_500US);
+ while ((mmio_read_32(ddrctrl_base + DDRCTRL_STAT) &
+ DDRCTRL_STAT_OPERATING_MODE_MASK) !=
+ DDRCTRL_STAT_OPERATING_MODE_NORMAL) {
+ if (timeout_elapsed(timeout)) {
+ 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 */
+ stm32mp_pwr_regs_lock();
+ mmio_setbits_32(pwr_base + PWR_CR3, PWR_CR3_DDRSREN);
+ stm32mp_pwr_regs_unlock();
+
+ return 0;
+}
+
+static 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);
+}
+
+static 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);
+}
+
+static 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);
+}
+
+enum stm32mp1_ddr_sr_mode ddr_read_sr_mode(void)
+{
+ uint32_t pwrctl = mmio_read_32(stm32mp_ddrctrl_base() + DDRCTRL_PWRCTL);
+
+ switch (pwrctl & (DDRCTRL_PWRCTL_EN_DFI_DRAM_CLK_DISABLE |
+ DDRCTRL_PWRCTL_SELFREF_EN)) {
+ case 0U:
+ return DDR_SSR_MODE;
+
+ case DDRCTRL_PWRCTL_EN_DFI_DRAM_CLK_DISABLE:
+ return DDR_HSR_MODE;
+
+ case DDRCTRL_PWRCTL_EN_DFI_DRAM_CLK_DISABLE | DDRCTRL_PWRCTL_SELFREF_EN:
+ return DDR_ASR_MODE;
+
+ default:
+ return DDR_SR_MODE_INVALID;
+ }
+}
+
+void ddr_set_sr_mode(enum stm32mp1_ddr_sr_mode mode)
+{
+ switch (mode) {
+ case DDR_SSR_MODE:
+ ddr_sr_mode_ssr();
+ break;
+
+ case DDR_HSR_MODE:
+ ddr_sr_mode_hsr();
+ break;
+
+ case DDR_ASR_MODE:
+ ddr_sr_mode_asr();
+ break;
+
+ default:
+ ERROR("Unknown Self Refresh mode\n");
+ panic();
+ }
+}
+
+void ddr_save_sr_mode(void)
+{
+ saved_ddr_sr_mode = ddr_read_sr_mode();
+}
+
+void ddr_restore_sr_mode(void)
+{
+ ddr_set_sr_mode(saved_ddr_sr_mode);
+}
+
+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 4ae55fcc7..e6652e504 100644
--- a/drivers/st/ddr/stm32mp1_ram.c
+++ b/drivers/st/ddr/stm32mp1_ram.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2018-2019, STMicroelectronics - All Rights Reserved
+ * Copyright (C) 2018-2020, STMicroelectronics - All Rights Reserved
*
* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
*/
@@ -49,6 +49,26 @@ int stm32mp1_ddr_clk_enable(struct ddr_info *priv, uint32_t mem_speed)
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
@@ -168,23 +188,30 @@ static int stm32mp1_ddr_setup(void)
int ret;
struct stm32mp1_ddr_config config;
int node, len;
- uint32_t 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) \
+#define PARAM(x, y, z) \
{ \
.name = x, \
.offset = offsetof(struct stm32mp1_ddr_config, y), \
- .size = sizeof(config.y) / sizeof(uint32_t) \
+ .size = sizeof(config.y) / sizeof(uint32_t), \
+ .present = z \
}
-#define CTL_PARAM(x) PARAM("st,ctl-"#x, c_##x)
-#define PHY_PARAM(x) PARAM("st,phy-"#x, p_##x)
+#define CTL_PARAM(x) PARAM("st,ctl-"#x, c_##x, NULL)
+#define PHY_PARAM(x) PARAM("st,phy-"#x, p_##x, NULL)
+#define PHY_PARAM_OPT(x) PARAM("st,phy-"#x, p_##x, &config.p_##x##_present)
const struct {
const char *name; /* Name in DT */
const uint32_t offset; /* Offset in config struct */
const uint32_t size; /* Size of parameters */
+ bool * const present; /* presence indication for opt */
} param[] = {
CTL_PARAM(reg),
CTL_PARAM(timing),
@@ -192,16 +219,15 @@ static int stm32mp1_ddr_setup(void)
CTL_PARAM(perf),
PHY_PARAM(reg),
PHY_PARAM(timing),
- PHY_PARAM(cal)
+ PHY_PARAM_OPT(cal)
};
if (fdt_get_address(&fdt) == 0) {
return -ENOENT;
}
- node = fdt_node_offset_by_compatible(fdt, -1, DT_DDR_COMPAT);
+ node = dt_get_node_by_compatible(DT_DDR_COMPAT);
if (node < 0) {
- ERROR("%s: Cannot read DDR node in DT\n", __func__);
return -EINVAL;
}
@@ -230,13 +256,34 @@ static int stm32mp1_ddr_setup(void)
VERBOSE("%s: %s[0x%x] = %d\n", __func__,
param[idx].name, param[idx].size, ret);
- if (ret != 0) {
- ERROR("%s: Cannot read %s\n",
- __func__, param[idx].name);
+ if ((ret != 0) &&
+ ((ret != -FDT_ERR_NOTFOUND) ||
+ (param[idx].present == NULL))) {
+ ERROR("%s: Cannot read %s, error=%d\n",
+ __func__, param[idx].name, ret);
return -EINVAL;
}
+ if (param[idx].present != NULL) {
+ /* save presence of optional parameters */
+ *(param[idx].present) = true;
+ if (ret == -FDT_ERR_NOTFOUND) {
+ *(param[idx].present) = false;
+ }
+ }
}
+ config.self_refresh = false;
+
+ 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);
@@ -245,36 +292,58 @@ 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);
- write_sctlr(read_sctlr() & ~SCTLR_C_BIT);
- dcsw_op_all(DC_OP_CISW);
+ 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();
+ }
}
- write_sctlr(read_sctlr() | SCTLR_C_BIT);
+ /*
+ * Initialization sequence has configured DDR registers with settings.
+ * The Self Refresh (SR) mode corresponding to these settings has now
+ * to be set.
+ */
+ ddr_set_sr_mode(ddr_read_sr_mode());
return 0;
}
diff --git a/drivers/st/etzpc/etzpc.c b/drivers/st/etzpc/etzpc.c
new file mode 100644
index 000000000..8795c6e00
--- /dev/null
+++ b/drivers/st/etzpc/etzpc.c
@@ -0,0 +1,310 @@
+/*
+ * Copyright (c) 2017-2019, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <stdint.h>
+
+#include <libfdt.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/st/etzpc.h>
+#include <dt-bindings/soc/st,stm32-etzpc.h>
+#include <lib/mmio.h>
+#include <lib/utils_def.h>
+
+/* 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/fmc/stm32_fmc2_nand.c b/drivers/st/fmc/stm32_fmc2_nand.c
new file mode 100644
index 000000000..e976c3bdd
--- /dev/null
+++ b/drivers/st/fmc/stm32_fmc2_nand.c
@@ -0,0 +1,883 @@
+/*
+ * Copyright (c) 2019-2020, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdint.h>
+
+#include <libfdt.h>
+
+#include <platform_def.h>
+
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <drivers/raw_nand.h>
+#include <drivers/st/stm32_fmc2_nand.h>
+#include <drivers/st/stm32_gpio.h>
+#include <drivers/st/stm32mp_reset.h>
+#include <lib/mmio.h>
+#include <lib/utils_def.h>
+
+#define TIMEOUT_US_1MS U(1000)
+
+/* FMC2 Compatibility */
+#define DT_FMC2_COMPAT "st,stm32mp15-fmc2"
+#define MAX_CS 2U
+
+/* FMC2 Controller Registers */
+#define FMC2_BCR1 0x00U
+#define FMC2_PCR 0x80U
+#define FMC2_SR 0x84U
+#define FMC2_PMEM 0x88U
+#define FMC2_PATT 0x8CU
+#define FMC2_HECCR 0x94U
+#define FMC2_BCHISR 0x254U
+#define FMC2_BCHDSR0 0x27CU
+#define FMC2_BCHDSR1 0x280U
+#define FMC2_BCHDSR2 0x284U
+#define FMC2_BCHDSR3 0x288U
+#define FMC2_BCHDSR4 0x28CU
+
+/* FMC2_BCR1 register */
+#define FMC2_BCR1_FMC2EN BIT(31)
+/* FMC2_PCR register */
+#define FMC2_PCR_PWAITEN BIT(1)
+#define FMC2_PCR_PBKEN BIT(2)
+#define FMC2_PCR_PWID_MASK GENMASK_32(5, 4)
+#define FMC2_PCR_PWID(x) (((x) << 4) & FMC2_PCR_PWID_MASK)
+#define FMC2_PCR_PWID_8 0x0U
+#define FMC2_PCR_PWID_16 0x1U
+#define FMC2_PCR_ECCEN BIT(6)
+#define FMC2_PCR_ECCALG BIT(8)
+#define FMC2_PCR_TCLR_MASK GENMASK_32(12, 9)
+#define FMC2_PCR_TCLR(x) (((x) << 9) & FMC2_PCR_TCLR_MASK)
+#define FMC2_PCR_TCLR_DEFAULT 0xFU
+#define FMC2_PCR_TAR_MASK GENMASK_32(16, 13)
+#define FMC2_PCR_TAR(x) (((x) << 13) & FMC2_PCR_TAR_MASK)
+#define FMC2_PCR_TAR_DEFAULT 0xFU
+#define FMC2_PCR_ECCSS_MASK GENMASK_32(19, 17)
+#define FMC2_PCR_ECCSS(x) (((x) << 17) & FMC2_PCR_ECCSS_MASK)
+#define FMC2_PCR_ECCSS_512 0x1U
+#define FMC2_PCR_ECCSS_2048 0x3U
+#define FMC2_PCR_BCHECC BIT(24)
+#define FMC2_PCR_WEN BIT(25)
+/* FMC2_SR register */
+#define FMC2_SR_NWRF BIT(6)
+/* FMC2_PMEM register*/
+#define FMC2_PMEM_MEMSET(x) (((x) & GENMASK_32(7, 0)) << 0)
+#define FMC2_PMEM_MEMWAIT(x) (((x) & GENMASK_32(7, 0)) << 8)
+#define FMC2_PMEM_MEMHOLD(x) (((x) & GENMASK_32(7, 0)) << 16)
+#define FMC2_PMEM_MEMHIZ(x) (((x) & GENMASK_32(7, 0)) << 24)
+#define FMC2_PMEM_DEFAULT 0x0A0A0A0AU
+/* FMC2_PATT register */
+#define FMC2_PATT_ATTSET(x) (((x) & GENMASK_32(7, 0)) << 0)
+#define FMC2_PATT_ATTWAIT(x) (((x) & GENMASK_32(7, 0)) << 8)
+#define FMC2_PATT_ATTHOLD(x) (((x) & GENMASK_32(7, 0)) << 16)
+#define FMC2_PATT_ATTHIZ(x) (((x) & GENMASK_32(7, 0)) << 24)
+#define FMC2_PATT_DEFAULT 0x0A0A0A0AU
+/* FMC2_BCHISR register */
+#define FMC2_BCHISR_DERF BIT(1)
+/* FMC2_BCHDSR0 register */
+#define FMC2_BCHDSR0_DUE BIT(0)
+#define FMC2_BCHDSR0_DEF BIT(1)
+#define FMC2_BCHDSR0_DEN_MASK GENMASK_32(7, 4)
+#define FMC2_BCHDSR0_DEN_SHIFT 4U
+/* FMC2_BCHDSR1 register */
+#define FMC2_BCHDSR1_EBP1_MASK GENMASK_32(12, 0)
+#define FMC2_BCHDSR1_EBP2_MASK GENMASK_32(28, 16)
+#define FMC2_BCHDSR1_EBP2_SHIFT 16U
+/* FMC2_BCHDSR2 register */
+#define FMC2_BCHDSR2_EBP3_MASK GENMASK_32(12, 0)
+#define FMC2_BCHDSR2_EBP4_MASK GENMASK_32(28, 16)
+#define FMC2_BCHDSR2_EBP4_SHIFT 16U
+/* FMC2_BCHDSR3 register */
+#define FMC2_BCHDSR3_EBP5_MASK GENMASK_32(12, 0)
+#define FMC2_BCHDSR3_EBP6_MASK GENMASK_32(28, 16)
+#define FMC2_BCHDSR3_EBP6_SHIFT 16U
+/* FMC2_BCHDSR4 register */
+#define FMC2_BCHDSR4_EBP7_MASK GENMASK_32(12, 0)
+#define FMC2_BCHDSR4_EBP8_MASK GENMASK_32(28, 16)
+#define FMC2_BCHDSR4_EBP8_SHIFT 16U
+
+/* Timings */
+#define FMC2_THIZ 0x01U
+#define FMC2_TIO 8000U
+#define FMC2_TSYNC 3000U
+#define FMC2_PCR_TIMING_MASK GENMASK_32(3, 0)
+#define FMC2_PMEM_PATT_TIMING_MASK GENMASK_32(7, 0)
+
+#define FMC2_BBM_LEN 2U
+#define FMC2_MAX_ECC_BYTES 14U
+#define TIMEOUT_US_10_MS 10000U
+#define FMC2_PSEC_PER_MSEC (1000UL * 1000UL * 1000UL)
+
+enum stm32_fmc2_ecc {
+ FMC2_ECC_HAM = 1U,
+ FMC2_ECC_BCH4 = 4U,
+ FMC2_ECC_BCH8 = 8U
+};
+
+struct stm32_fmc2_cs_reg {
+ uintptr_t data_base;
+ uintptr_t cmd_base;
+ uintptr_t addr_base;
+};
+
+struct stm32_fmc2_nand_timings {
+ 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;
+};
+
+struct stm32_fmc2_nfc {
+ uintptr_t reg_base;
+ struct stm32_fmc2_cs_reg cs[MAX_CS];
+ unsigned long clock_id;
+ unsigned int reset_id;
+ uint8_t cs_sel;
+};
+
+static struct stm32_fmc2_nfc stm32_fmc2;
+
+static uintptr_t fmc2_base(void)
+{
+ return stm32_fmc2.reg_base;
+}
+
+static void stm32_fmc2_nand_setup_timing(void)
+{
+ struct stm32_fmc2_nand_timings tims;
+ unsigned long hclk = stm32mp_clk_get_rate(stm32_fmc2.clock_id);
+ unsigned long hclkp = FMC2_PSEC_PER_MSEC / (hclk / 1000U);
+ unsigned long timing, tar, tclr, thiz, twait;
+ unsigned long tset_mem, tset_att, thold_mem, thold_att;
+ uint32_t pcr, pmem, patt;
+
+ tar = MAX(hclkp, NAND_TAR_MIN);
+ timing = div_round_up(tar, hclkp) - 1U;
+ tims.tar = MIN(timing, (unsigned long)FMC2_PCR_TIMING_MASK);
+
+ tclr = MAX(hclkp, NAND_TCLR_MIN);
+ timing = div_round_up(tclr, hclkp) - 1U;
+ tims.tclr = MIN(timing, (unsigned long)FMC2_PCR_TIMING_MASK);
+
+ tims.thiz = FMC2_THIZ;
+ thiz = (tims.thiz + 1U) * hclkp;
+
+ /*
+ * tWAIT > tRP
+ * tWAIT > tWP
+ * tWAIT > tREA + tIO
+ */
+ twait = MAX(hclkp, NAND_TRP_MIN);
+ twait = MAX(twait, NAND_TWP_MIN);
+ twait = MAX(twait, NAND_TREA_MAX + FMC2_TIO);
+ timing = div_round_up(twait, hclkp);
+ tims.twait = CLAMP(timing, 1UL,
+ (unsigned long)FMC2_PMEM_PATT_TIMING_MASK);
+
+ /*
+ * tSETUP_MEM > tCS - tWAIT
+ * tSETUP_MEM > tALS - tWAIT
+ * tSETUP_MEM > tDS - (tWAIT - tHIZ)
+ */
+ tset_mem = hclkp;
+ if ((twait < NAND_TCS_MIN) && (tset_mem < (NAND_TCS_MIN - twait))) {
+ tset_mem = NAND_TCS_MIN - twait;
+ }
+ if ((twait < NAND_TALS_MIN) && (tset_mem < (NAND_TALS_MIN - twait))) {
+ tset_mem = NAND_TALS_MIN - twait;
+ }
+ if ((twait > thiz) && ((twait - thiz) < NAND_TDS_MIN) &&
+ (tset_mem < (NAND_TDS_MIN - (twait - thiz)))) {
+ tset_mem = NAND_TDS_MIN - (twait - thiz);
+ }
+ timing = div_round_up(tset_mem, hclkp);
+ tims.tset_mem = CLAMP(timing, 1UL,
+ (unsigned long)FMC2_PMEM_PATT_TIMING_MASK);
+
+ /*
+ * tHOLD_MEM > tCH
+ * tHOLD_MEM > tREH - tSETUP_MEM
+ * tHOLD_MEM > max(tRC, tWC) - (tSETUP_MEM + tWAIT)
+ */
+ thold_mem = MAX(hclkp, NAND_TCH_MIN);
+ if ((tset_mem < NAND_TREH_MIN) &&
+ (thold_mem < (NAND_TREH_MIN - tset_mem))) {
+ thold_mem = NAND_TREH_MIN - tset_mem;
+ }
+ if (((tset_mem + twait) < NAND_TRC_MIN) &&
+ (thold_mem < (NAND_TRC_MIN - (tset_mem + twait)))) {
+ thold_mem = NAND_TRC_MIN - (tset_mem + twait);
+ }
+ if (((tset_mem + twait) < NAND_TWC_MIN) &&
+ (thold_mem < (NAND_TWC_MIN - (tset_mem + twait)))) {
+ thold_mem = NAND_TWC_MIN - (tset_mem + twait);
+ }
+ timing = div_round_up(thold_mem, hclkp);
+ tims.thold_mem = CLAMP(timing, 1UL,
+ (unsigned long)FMC2_PMEM_PATT_TIMING_MASK);
+
+ /*
+ * 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 < NAND_TCS_MIN) && (tset_att < (NAND_TCS_MIN - twait))) {
+ tset_att = NAND_TCS_MIN - twait;
+ }
+ if ((twait < NAND_TCLS_MIN) && (tset_att < (NAND_TCLS_MIN - twait))) {
+ tset_att = NAND_TCLS_MIN - twait;
+ }
+ if ((twait < NAND_TALS_MIN) && (tset_att < (NAND_TALS_MIN - twait))) {
+ tset_att = NAND_TALS_MIN - twait;
+ }
+ if ((thold_mem < NAND_TRHW_MIN) &&
+ (tset_att < (NAND_TRHW_MIN - thold_mem))) {
+ tset_att = NAND_TRHW_MIN - thold_mem;
+ }
+ if ((twait > thiz) && ((twait - thiz) < NAND_TDS_MIN) &&
+ (tset_att < (NAND_TDS_MIN - (twait - thiz)))) {
+ tset_att = NAND_TDS_MIN - (twait - thiz);
+ }
+ timing = div_round_up(tset_att, hclkp);
+ tims.tset_att = CLAMP(timing, 1UL,
+ (unsigned long)FMC2_PMEM_PATT_TIMING_MASK);
+
+ /*
+ * 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 = MAX(hclkp, NAND_TALH_MIN);
+ thold_att = MAX(thold_att, NAND_TCH_MIN);
+ thold_att = MAX(thold_att, NAND_TCLH_MIN);
+ thold_att = MAX(thold_att, NAND_TCOH_MIN);
+ thold_att = MAX(thold_att, NAND_TDH_MIN);
+ if (((NAND_TWB_MAX + FMC2_TIO + FMC2_TSYNC) > tset_mem) &&
+ (thold_att < (NAND_TWB_MAX + FMC2_TIO + FMC2_TSYNC - tset_mem))) {
+ thold_att = NAND_TWB_MAX + FMC2_TIO + FMC2_TSYNC - tset_mem;
+ }
+ if ((tset_mem < NAND_TADL_MIN) &&
+ (thold_att < (NAND_TADL_MIN - tset_mem))) {
+ thold_att = NAND_TADL_MIN - tset_mem;
+ }
+ if ((tset_mem < NAND_TWH_MIN) &&
+ (thold_att < (NAND_TWH_MIN - tset_mem))) {
+ thold_att = NAND_TWH_MIN - tset_mem;
+ }
+ if ((tset_mem < NAND_TWHR_MIN) &&
+ (thold_att < (NAND_TWHR_MIN - tset_mem))) {
+ thold_att = NAND_TWHR_MIN - tset_mem;
+ }
+ if (((tset_att + twait) < NAND_TRC_MIN) &&
+ (thold_att < (NAND_TRC_MIN - (tset_att + twait)))) {
+ thold_att = NAND_TRC_MIN - (tset_att + twait);
+ }
+ if (((tset_att + twait) < NAND_TWC_MIN) &&
+ (thold_att < (NAND_TWC_MIN - (tset_att + twait)))) {
+ thold_att = NAND_TWC_MIN - (tset_att + twait);
+ }
+ timing = div_round_up(thold_att, hclkp);
+ tims.thold_att = CLAMP(timing, 1UL,
+ (unsigned long)FMC2_PMEM_PATT_TIMING_MASK);
+
+ VERBOSE("NAND timings: %u - %u - %u - %u - %u - %u - %u - %u\n",
+ tims.tclr, tims.tar, tims.thiz, tims.twait,
+ tims.thold_mem, tims.tset_mem,
+ tims.thold_att, tims.tset_att);
+
+ /* Set tclr/tar timings */
+ pcr = mmio_read_32(fmc2_base() + FMC2_PCR);
+ pcr &= ~FMC2_PCR_TCLR_MASK;
+ pcr |= FMC2_PCR_TCLR(tims.tclr);
+ pcr &= ~FMC2_PCR_TAR_MASK;
+ pcr |= FMC2_PCR_TAR(tims.tar);
+
+ /* Set tset/twait/thold/thiz timings in common bank */
+ pmem = FMC2_PMEM_MEMSET(tims.tset_mem);
+ pmem |= FMC2_PMEM_MEMWAIT(tims.twait);
+ pmem |= FMC2_PMEM_MEMHOLD(tims.thold_mem);
+ pmem |= FMC2_PMEM_MEMHIZ(tims.thiz);
+
+ /* Set tset/twait/thold/thiz timings in attribute bank */
+ patt = FMC2_PATT_ATTSET(tims.tset_att);
+ patt |= FMC2_PATT_ATTWAIT(tims.twait);
+ patt |= FMC2_PATT_ATTHOLD(tims.thold_att);
+ patt |= FMC2_PATT_ATTHIZ(tims.thiz);
+
+ mmio_write_32(fmc2_base() + FMC2_PCR, pcr);
+ mmio_write_32(fmc2_base() + FMC2_PMEM, pmem);
+ mmio_write_32(fmc2_base() + FMC2_PATT, patt);
+}
+
+static void stm32_fmc2_set_buswidth_16(bool set)
+{
+ mmio_clrsetbits_32(fmc2_base() + FMC2_PCR, FMC2_PCR_PWID_MASK,
+ (set ? FMC2_PCR_PWID(FMC2_PCR_PWID_16) : 0U));
+}
+
+static void stm32_fmc2_set_ecc(bool enable)
+{
+ mmio_clrsetbits_32(fmc2_base() + FMC2_PCR, FMC2_PCR_ECCEN,
+ (enable ? FMC2_PCR_ECCEN : 0U));
+}
+
+static int stm32_fmc2_ham_correct(uint8_t *buffer, uint8_t *eccbuffer,
+ uint8_t *ecc)
+{
+ 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 = ecc[0] ^ eccbuffer[0];
+ xor_ecc_2b = ecc[1] ^ eccbuffer[1];
+ xor_ecc_3b = ecc[2] ^ eccbuffer[2];
+
+ xor_ecc.val = 0U;
+ 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 == 0U) {
+ return 0; /* No Error */
+ }
+
+ xor_ecc_ones = __builtin_popcount(xor_ecc.val);
+ if (xor_ecc_ones < 23U) {
+ if (xor_ecc_ones == 12U) {
+ uint16_t bit_address, byte_address;
+
+ /* Correctable ERROR */
+ bit_address = ((xor_ecc_1b >> 1) & BIT(0)) |
+ ((xor_ecc_1b >> 2) & BIT(1)) |
+ ((xor_ecc_1b >> 3) & BIT(2));
+
+ byte_address = ((xor_ecc_1b >> 7) & BIT(0)) |
+ ((xor_ecc_2b) & BIT(1)) |
+ ((xor_ecc_2b >> 1) & BIT(2)) |
+ ((xor_ecc_2b >> 2) & BIT(3)) |
+ ((xor_ecc_2b >> 3) & BIT(4)) |
+ ((xor_ecc_3b << 4) & BIT(5)) |
+ ((xor_ecc_3b << 3) & BIT(6)) |
+ ((xor_ecc_3b << 2) & BIT(7)) |
+ ((xor_ecc_3b << 1) & BIT(8));
+
+ /* Correct bit error in the data */
+ buffer[byte_address] =
+ buffer[byte_address] ^ BIT(bit_address);
+ VERBOSE("Hamming: 1 ECC error corrected\n");
+
+ return 0;
+ }
+
+ /* Non Correctable ERROR */
+ ERROR("%s: Uncorrectable ECC Errors\n", __func__);
+ return -1;
+ }
+
+ /* ECC ERROR */
+ ERROR("%s: Hamming correction error\n", __func__);
+ return -1;
+}
+
+
+static int stm32_fmc2_ham_calculate(uint8_t *buffer, uint8_t *ecc)
+{
+ uint32_t heccr;
+ uint64_t timeout = timeout_init_us(TIMEOUT_US_10_MS);
+
+ while ((mmio_read_32(fmc2_base() + FMC2_SR) & FMC2_SR_NWRF) == 0U) {
+ if (timeout_elapsed(timeout)) {
+ return -ETIMEDOUT;
+ }
+ }
+
+ heccr = mmio_read_32(fmc2_base() + FMC2_HECCR);
+
+ ecc[0] = heccr;
+ ecc[1] = heccr >> 8;
+ ecc[2] = heccr >> 16;
+
+ /* Disable ECC */
+ stm32_fmc2_set_ecc(false);
+
+ return 0;
+}
+
+static int stm32_fmc2_bch_correct(uint8_t *buffer, unsigned int eccsize)
+{
+ uint32_t bchdsr0, bchdsr1, bchdsr2, bchdsr3, bchdsr4;
+ uint16_t pos[8];
+ int i, den;
+ uint64_t timeout = timeout_init_us(TIMEOUT_US_10_MS);
+
+ while ((mmio_read_32(fmc2_base() + FMC2_BCHISR) &
+ FMC2_BCHISR_DERF) == 0U) {
+ if (timeout_elapsed(timeout)) {
+ return -ETIMEDOUT;
+ }
+ }
+
+ bchdsr0 = mmio_read_32(fmc2_base() + FMC2_BCHDSR0);
+ bchdsr1 = mmio_read_32(fmc2_base() + FMC2_BCHDSR1);
+ bchdsr2 = mmio_read_32(fmc2_base() + FMC2_BCHDSR2);
+ bchdsr3 = mmio_read_32(fmc2_base() + FMC2_BCHDSR3);
+ bchdsr4 = mmio_read_32(fmc2_base() + FMC2_BCHDSR4);
+
+ /* Disable ECC */
+ stm32_fmc2_set_ecc(false);
+
+ /* No error found */
+ if ((bchdsr0 & FMC2_BCHDSR0_DEF) == 0U) {
+ return 0;
+ }
+
+ /* Too many errors detected */
+ if ((bchdsr0 & FMC2_BCHDSR0_DUE) != 0U) {
+ return -EBADMSG;
+ }
+
+ pos[0] = bchdsr1 & FMC2_BCHDSR1_EBP1_MASK;
+ pos[1] = (bchdsr1 & FMC2_BCHDSR1_EBP2_MASK) >> FMC2_BCHDSR1_EBP2_SHIFT;
+ pos[2] = bchdsr2 & FMC2_BCHDSR2_EBP3_MASK;
+ pos[3] = (bchdsr2 & FMC2_BCHDSR2_EBP4_MASK) >> FMC2_BCHDSR2_EBP4_SHIFT;
+ pos[4] = bchdsr3 & FMC2_BCHDSR3_EBP5_MASK;
+ pos[5] = (bchdsr3 & FMC2_BCHDSR3_EBP6_MASK) >> FMC2_BCHDSR3_EBP6_SHIFT;
+ pos[6] = bchdsr4 & FMC2_BCHDSR4_EBP7_MASK;
+ pos[7] = (bchdsr4 & FMC2_BCHDSR4_EBP8_MASK) >> FMC2_BCHDSR4_EBP8_SHIFT;
+
+ den = (bchdsr0 & FMC2_BCHDSR0_DEN_MASK) >> FMC2_BCHDSR0_DEN_SHIFT;
+ for (i = 0; i < den; i++) {
+ if (pos[i] < (eccsize * 8U)) {
+ uint8_t bitmask = BIT(pos[i] % 8U);
+ uint32_t offset = pos[i] / 8U;
+
+ *(buffer + offset) ^= bitmask;
+ }
+ }
+
+ return 0;
+}
+
+static void stm32_fmc2_hwctl(struct nand_device *nand)
+{
+ stm32_fmc2_set_ecc(false);
+
+ if (nand->ecc.max_bit_corr != FMC2_ECC_HAM) {
+ mmio_clrbits_32(fmc2_base() + FMC2_PCR, FMC2_PCR_WEN);
+ }
+
+ stm32_fmc2_set_ecc(true);
+}
+
+static int stm32_fmc2_read_page(struct nand_device *nand,
+ unsigned int page, uintptr_t buffer)
+{
+ unsigned int eccsize = nand->ecc.size;
+ unsigned int eccbytes = nand->ecc.bytes;
+ unsigned int eccsteps = nand->page_size / eccsize;
+ uint8_t ecc_corr[FMC2_MAX_ECC_BYTES];
+ uint8_t ecc_cal[FMC2_MAX_ECC_BYTES] = {0U};
+ uint8_t *p;
+ unsigned int i;
+ unsigned int s;
+ int ret;
+
+ VERBOSE(">%s page %i buffer %lx\n", __func__, page, buffer);
+
+ ret = nand_read_page_cmd(page, 0U, 0U, 0U);
+ if (ret != 0) {
+ return ret;
+ }
+
+ for (s = 0U, i = nand->page_size + FMC2_BBM_LEN, p = (uint8_t *)buffer;
+ s < eccsteps;
+ s++, i += eccbytes, p += eccsize) {
+ stm32_fmc2_hwctl(nand);
+
+ /* Read the NAND page sector (512 bytes) */
+ ret = nand_change_read_column_cmd(s * eccsize, (uintptr_t)p,
+ eccsize);
+ if (ret != 0) {
+ return ret;
+ }
+
+ if (nand->ecc.max_bit_corr == FMC2_ECC_HAM) {
+ ret = stm32_fmc2_ham_calculate(p, ecc_cal);
+ if (ret != 0) {
+ return ret;
+ }
+ }
+
+ /* Read the corresponding ECC bytes */
+ ret = nand_change_read_column_cmd(i, (uintptr_t)ecc_corr,
+ eccbytes);
+ if (ret != 0) {
+ return ret;
+ }
+
+ /* Correct the data */
+ if (nand->ecc.max_bit_corr == FMC2_ECC_HAM) {
+ ret = stm32_fmc2_ham_correct(p, ecc_corr, ecc_cal);
+ } else {
+ ret = stm32_fmc2_bch_correct(p, eccsize);
+ }
+
+ if (ret != 0) {
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static void stm32_fmc2_read_data(struct nand_device *nand,
+ uint8_t *buff, unsigned int length,
+ bool use_bus8)
+{
+ uintptr_t data_base = stm32_fmc2.cs[stm32_fmc2.cs_sel].data_base;
+
+ if (use_bus8 && (nand->buswidth == NAND_BUS_WIDTH_16)) {
+ stm32_fmc2_set_buswidth_16(false);
+ }
+
+ if ((((uintptr_t)buff & BIT(0)) != 0U) && (length != 0U)) {
+ *buff = mmio_read_8(data_base);
+ buff += sizeof(uint8_t);
+ length -= sizeof(uint8_t);
+ }
+
+ if ((((uintptr_t)buff & GENMASK_32(1, 0)) != 0U) &&
+ (length >= sizeof(uint16_t))) {
+ *(uint16_t *)buff = mmio_read_16(data_base);
+ buff += sizeof(uint16_t);
+ length -= sizeof(uint16_t);
+ }
+
+ /* 32bit aligned */
+ while (length >= sizeof(uint32_t)) {
+ *(uint32_t *)buff = mmio_read_32(data_base);
+ buff += sizeof(uint32_t);
+ length -= sizeof(uint32_t);
+ }
+
+ /* Read remaining bytes */
+ if (length >= sizeof(uint16_t)) {
+ *(uint16_t *)buff = mmio_read_16(data_base);
+ buff += sizeof(uint16_t);
+ length -= sizeof(uint16_t);
+ }
+
+ if (length != 0U) {
+ *buff = mmio_read_8(data_base);
+ }
+
+ if (use_bus8 && (nand->buswidth == NAND_BUS_WIDTH_16)) {
+ /* Reconfigure bus width to 16-bit */
+ stm32_fmc2_set_buswidth_16(true);
+ }
+}
+
+static void stm32_fmc2_write_data(struct nand_device *nand,
+ uint8_t *buff, unsigned int length,
+ bool use_bus8)
+{
+ uintptr_t data_base = stm32_fmc2.cs[stm32_fmc2.cs_sel].data_base;
+
+ if (use_bus8 && (nand->buswidth == NAND_BUS_WIDTH_16)) {
+ /* Reconfigure bus width to 8-bit */
+ stm32_fmc2_set_buswidth_16(false);
+ }
+
+ if ((((uintptr_t)buff & BIT(0)) != 0U) && (length != 0U)) {
+ mmio_write_8(data_base, *buff);
+ buff += sizeof(uint8_t);
+ length -= sizeof(uint8_t);
+ }
+
+ if ((((uintptr_t)buff & GENMASK_32(1, 0)) != 0U) &&
+ (length >= sizeof(uint16_t))) {
+ mmio_write_16(data_base, *(uint16_t *)buff);
+ buff += sizeof(uint16_t);
+ length -= sizeof(uint16_t);
+ }
+
+ /* 32bits aligned */
+ while (length >= sizeof(uint32_t)) {
+ mmio_write_32(data_base, *(uint32_t *)buff);
+ buff += sizeof(uint32_t);
+ length -= sizeof(uint32_t);
+ }
+
+ /* Read remaining bytes */
+ if (length >= sizeof(uint16_t)) {
+ mmio_write_16(data_base, *(uint16_t *)buff);
+ buff += sizeof(uint16_t);
+ length -= sizeof(uint16_t);
+ }
+
+ if (length != 0U) {
+ mmio_write_8(data_base, *buff);
+ }
+
+ if (use_bus8 && (nand->buswidth == NAND_BUS_WIDTH_16)) {
+ /* Reconfigure bus width to 16-bit */
+ stm32_fmc2_set_buswidth_16(true);
+ }
+}
+
+static void stm32_fmc2_ctrl_init(void)
+{
+ uint32_t pcr = mmio_read_32(fmc2_base() + FMC2_PCR);
+ uint32_t bcr1 = mmio_read_32(fmc2_base() + FMC2_BCR1);
+
+ /* Enable wait feature and NAND flash memory bank */
+ pcr |= FMC2_PCR_PWAITEN;
+ pcr |= FMC2_PCR_PBKEN;
+
+ /* Set buswidth to 8 bits mode for identification */
+ pcr &= ~FMC2_PCR_PWID_MASK;
+
+ /* ECC logic is disabled */
+ pcr &= ~FMC2_PCR_ECCEN;
+
+ /* Default mode */
+ pcr &= ~FMC2_PCR_ECCALG;
+ pcr &= ~FMC2_PCR_BCHECC;
+ pcr &= ~FMC2_PCR_WEN;
+
+ /* Set default ECC sector size */
+ pcr &= ~FMC2_PCR_ECCSS_MASK;
+ pcr |= FMC2_PCR_ECCSS(FMC2_PCR_ECCSS_2048);
+
+ /* Set default TCLR/TAR timings */
+ pcr &= ~FMC2_PCR_TCLR_MASK;
+ pcr |= FMC2_PCR_TCLR(FMC2_PCR_TCLR_DEFAULT);
+ pcr &= ~FMC2_PCR_TAR_MASK;
+ pcr |= FMC2_PCR_TAR(FMC2_PCR_TAR_DEFAULT);
+
+ /* Enable FMC2 controller */
+ bcr1 |= FMC2_BCR1_FMC2EN;
+
+ mmio_write_32(fmc2_base() + FMC2_BCR1, bcr1);
+ mmio_write_32(fmc2_base() + FMC2_PCR, pcr);
+ mmio_write_32(fmc2_base() + FMC2_PMEM, FMC2_PMEM_DEFAULT);
+ mmio_write_32(fmc2_base() + FMC2_PATT, FMC2_PATT_DEFAULT);
+}
+
+static int stm32_fmc2_exec(struct nand_req *req)
+{
+ int ret = 0;
+
+ switch (req->type & NAND_REQ_MASK) {
+ case NAND_REQ_CMD:
+ VERBOSE("Write CMD %x\n", (uint8_t)req->type);
+ mmio_write_8(stm32_fmc2.cs[stm32_fmc2.cs_sel].cmd_base,
+ (uint8_t)req->type);
+ break;
+ case NAND_REQ_ADDR:
+ VERBOSE("Write ADDR %x\n", *(req->addr));
+ mmio_write_8(stm32_fmc2.cs[stm32_fmc2.cs_sel].addr_base,
+ *(req->addr));
+ break;
+ case NAND_REQ_DATAIN:
+ VERBOSE("Read data\n");
+ stm32_fmc2_read_data(req->nand, req->addr, req->length,
+ ((req->type & NAND_REQ_BUS_WIDTH_8) !=
+ 0U));
+ break;
+ case NAND_REQ_DATAOUT:
+ VERBOSE("Write data\n");
+ stm32_fmc2_write_data(req->nand, req->addr, req->length,
+ ((req->type & NAND_REQ_BUS_WIDTH_8) !=
+ 0U));
+ break;
+ case NAND_REQ_WAIT:
+ VERBOSE("WAIT Ready\n");
+ ret = nand_wait_ready(req->delay_ms);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ };
+
+ return ret;
+}
+
+static void stm32_fmc2_setup(struct nand_device *nand)
+{
+ uint32_t pcr = mmio_read_32(fmc2_base() + FMC2_PCR);
+
+ /* Set buswidth */
+ pcr &= ~FMC2_PCR_PWID_MASK;
+ if (nand->buswidth == NAND_BUS_WIDTH_16) {
+ pcr |= FMC2_PCR_PWID(FMC2_PCR_PWID_16);
+ }
+
+ if (nand->ecc.mode == NAND_ECC_HW) {
+ nand->mtd_read_page = stm32_fmc2_read_page;
+
+ pcr &= ~FMC2_PCR_ECCALG;
+ pcr &= ~FMC2_PCR_BCHECC;
+
+ pcr &= ~FMC2_PCR_ECCSS_MASK;
+ pcr |= FMC2_PCR_ECCSS(FMC2_PCR_ECCSS_512);
+
+ switch (nand->ecc.max_bit_corr) {
+ case FMC2_ECC_HAM:
+ nand->ecc.bytes = 3;
+ break;
+ case FMC2_ECC_BCH8:
+ pcr |= FMC2_PCR_ECCALG;
+ pcr |= FMC2_PCR_BCHECC;
+ nand->ecc.bytes = 13;
+ break;
+ default:
+ /* Use FMC2 ECC BCH4 */
+ pcr |= FMC2_PCR_ECCALG;
+ nand->ecc.bytes = 7;
+ break;
+ }
+
+ if ((nand->buswidth & NAND_BUS_WIDTH_16) != 0) {
+ nand->ecc.bytes++;
+ }
+ }
+
+ mmio_write_32(stm32_fmc2.reg_base + FMC2_PCR, pcr);
+}
+
+static const struct nand_ctrl_ops ctrl_ops = {
+ .setup = stm32_fmc2_setup,
+ .exec = stm32_fmc2_exec
+};
+
+int stm32_fmc2_init(void)
+{
+ int fmc_node;
+ int fmc_subnode = 0;
+ int nchips = 0;
+ unsigned int i;
+ void *fdt = NULL;
+ const fdt32_t *cuint;
+ struct dt_node_info info;
+
+ if (fdt_get_address(&fdt) == 0) {
+ return -FDT_ERR_NOTFOUND;
+ }
+
+ fmc_node = dt_get_node(&info, -1, DT_FMC2_COMPAT);
+ if (fmc_node == -FDT_ERR_NOTFOUND) {
+ WARN("No FMC2 node found\n");
+ return fmc_node;
+ }
+
+ if (info.status == DT_DISABLED) {
+ return -FDT_ERR_NOTFOUND;
+ }
+
+ stm32_fmc2.reg_base = info.base;
+
+ if ((info.clock < 0) || (info.reset < 0)) {
+ return -FDT_ERR_BADVALUE;
+ }
+
+ stm32_fmc2.clock_id = (unsigned long)info.clock;
+ stm32_fmc2.reset_id = (unsigned int)info.reset;
+
+ cuint = fdt_getprop(fdt, fmc_node, "reg", NULL);
+ if (cuint == NULL) {
+ return -FDT_ERR_BADVALUE;
+ }
+
+ cuint += 2;
+
+ for (i = 0U; i < MAX_CS; i++) {
+ stm32_fmc2.cs[i].data_base = fdt32_to_cpu(*cuint);
+ stm32_fmc2.cs[i].cmd_base = fdt32_to_cpu(*(cuint + 2));
+ stm32_fmc2.cs[i].addr_base = fdt32_to_cpu(*(cuint + 4));
+ cuint += 6;
+ }
+
+ /* Pinctrl initialization */
+ if (dt_set_pinctrl_config(fmc_node) != 0) {
+ return -FDT_ERR_BADVALUE;
+ }
+
+ /* Parse flash nodes */
+ fdt_for_each_subnode(fmc_subnode, fdt, fmc_node) {
+ nchips++;
+ }
+
+ if (nchips != 1) {
+ WARN("Only one SLC NAND device supported\n");
+ return -FDT_ERR_BADVALUE;
+ }
+
+ fdt_for_each_subnode(fmc_subnode, fdt, fmc_node) {
+ /* Get chip select */
+ cuint = fdt_getprop(fdt, fmc_subnode, "reg", NULL);
+ if (cuint == NULL) {
+ WARN("Chip select not well defined\n");
+ return -FDT_ERR_BADVALUE;
+ }
+ stm32_fmc2.cs_sel = fdt32_to_cpu(*cuint);
+ VERBOSE("NAND CS %i\n", stm32_fmc2.cs_sel);
+ }
+
+ /* Enable Clock */
+ stm32mp_clk_enable(stm32_fmc2.clock_id);
+
+ /* Reset IP */
+ if (stm32mp_reset_assert_to(stm32_fmc2.reset_id, TIMEOUT_US_1MS)) {
+ panic();
+ }
+ if (stm32mp_reset_deassert_to(stm32_fmc2.reset_id, TIMEOUT_US_1MS)) {
+ panic();
+ }
+
+ /* Setup default IP registers */
+ stm32_fmc2_ctrl_init();
+
+ /* Setup default timings */
+ stm32_fmc2_nand_setup_timing();
+
+ /* Init NAND RAW framework */
+ nand_raw_ctrl_init(&ctrl_ops);
+
+ return 0;
+}
diff --git a/drivers/st/gpio/stm32_gpio.c b/drivers/st/gpio/stm32_gpio.c
index a13c341a8..cdb56ffbe 100644
--- a/drivers/st/gpio/stm32_gpio.c
+++ b/drivers/st/gpio/stm32_gpio.c
@@ -254,6 +254,12 @@ void set_gpio(uint32_t bank, uint32_t pin, uint32_t mode, uint32_t speed,
mmio_read_32(base + GPIO_AFRH_OFFSET));
stm32mp_clk_disable(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)
@@ -263,6 +269,8 @@ void set_gpio_secure_cfg(uint32_t bank, uint32_t pin, bool secure)
assert(pin <= GPIO_PIN_MAX);
+ assert(!(secure && stm32mp_gpio_bank_is_non_secure(bank)));
+
stm32mp_clk_enable(clock);
if (secure) {
diff --git a/drivers/st/i2c/stm32_i2c.c b/drivers/st/i2c/stm32_i2c.c
index ed880522b..f12d40516 100644
--- a/drivers/st/i2c/stm32_i2c.c
+++ b/drivers/st/i2c/stm32_i2c.c
@@ -1,10 +1,11 @@
/*
* Copyright (c) 2016-2019, STMicroelectronics - All Rights Reserved
*
- * SPDX-License-Identifier: BSD-3-Clause
+ * SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
*/
#include <errno.h>
+#include <limits.h>
#include <stdbool.h>
#include <stdlib.h>
@@ -38,8 +39,87 @@
#define I2C_NSEC_PER_SEC 1000000000L
-/* I2C Timing hard-coded value, for I2C clock source is HSI at 64MHz */
-#define I2C_TIMING 0x10D07DB5
+/*
+ * struct i2c_spec_s - Private I2C timing specifications.
+ * @rate: 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 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;
+};
+
+/*
+ * I2C specification values as per version 6.0, 4th of April 2014 [1],
+ * table 10 page 48: Characteristics of the SDA and SCL bus lines for
+ * Standard, Fast, and Fast-mode Plus I2C-bus devices.
+ *
+ * [1] https://www.i2c-bus.org/specification/
+ */
+static const struct i2c_spec_s i2c_specs[] = {
+ /* Standard - 100KHz */
+ {
+ .rate = STANDARD_RATE,
+ .fall_max = 300,
+ .rise_max = 1000,
+ .hddat_min = 0,
+ .vddat_max = 3450,
+ .sudat_min = 250,
+ .l_min = 4700,
+ .h_min = 4000,
+ },
+ /* Fast - 400KHz */
+ {
+ .rate = FAST_RATE,
+ .fall_max = 300,
+ .rise_max = 300,
+ .hddat_min = 0,
+ .vddat_max = 900,
+ .sudat_min = 100,
+ .l_min = 1300,
+ .h_min = 600,
+ },
+ /* FastPlus - 1MHz */
+ {
+ .rate = FAST_PLUS_RATE,
+ .fall_max = 100,
+ .rise_max = 120,
+ .hddat_min = 0,
+ .vddat_max = 450,
+ .sudat_min = 50,
+ .l_min = 500,
+ .h_min = 260,
+ },
+};
+
static void notif_i2c_timeout(struct i2c_handle_s *hi2c)
{
@@ -48,6 +128,298 @@ static void notif_i2c_timeout(struct i2c_handle_s *hi2c)
hi2c->i2c_state = I2C_STATE_READY;
}
+static const struct i2c_spec_s *get_specs(uint32_t rate)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(i2c_specs); i++) {
+ if (rate <= i2c_specs[i].rate) {
+ return &i2c_specs[i];
+ }
+ }
+
+ /* NOT REACHED */
+ return NULL;
+}
+
+#define RATE_MIN(rate) (((rate) / 100U) * 80U)
+/*
+ * @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)
+{
+ const struct i2c_spec_s *specs;
+ uint32_t speed_freq;
+ uint32_t i2cclk = udiv_round_nearest(I2C_NSEC_PER_SEC, clock_src);
+ uint32_t i2cbus;
+ 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];
+
+ specs = get_specs(init->bus_rate);
+ if (specs == NULL) {
+ ERROR("I2C speed out of bound {%d}\n", init->bus_rate);
+ return -EINVAL;
+ }
+
+ speed_freq = specs->rate;
+ i2cbus = udiv_round_nearest(I2C_NSEC_PER_SEC, speed_freq);
+ clk_error_prev = INT_MAX;
+
+ if ((init->rise_time > specs->rise_max) ||
+ (init->fall_time > specs->fall_max)) {
+ ERROR(" I2C timings out of bound Rise{%d>%d}/Fall{%d>%d}\n",
+ init->rise_time, specs->rise_max,
+ init->fall_time, specs->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 = specs->hddat_min + init->fall_time -
+ af_delay_min - ((init->digital_filter_coef + 3) * i2cclk);
+
+ sdadel_max = specs->vddat_max - init->rise_time -
+ af_delay_max - ((init->digital_filter_coef + 4) * i2cclk);
+
+ scldel_min = init->rise_time + specs->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 / RATE_MIN(specs->rate);
+ clk_min = I2C_NSEC_PER_SEC / specs->rate;
+
+ /*
+ * 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 < specs->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 >= specs->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;
+}
+
+static uint32_t get_lower_rate(uint32_t rate)
+{
+ int i;
+
+ for (i = ARRAY_SIZE(i2c_specs) - 1; i >= 0; i--) {
+ if (rate > i2c_specs[i].rate) {
+ return i2c_specs[i].rate;
+ }
+ }
+
+ return i2c_specs[0].rate;
+}
+
+/*
+ * @brief Setup the I2C device timings.
+ * @param hi2c: Pointer to a struct i2c_handle_s structure that contains
+ * 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 = (uint32_t)stm32mp_clk_get_rate(hi2c->clock);
+ if (clock_src == 0U) {
+ ERROR("I2C clock rate is 0\n");
+ return -EINVAL;
+ }
+
+ /*
+ * If the timing has already been computed, and the frequency is the
+ * same as when it was computed, then use the saved timing.
+ */
+ if (clock_src == hi2c->saved_frequency) {
+ *timing = hi2c->saved_timing;
+ return 0;
+ }
+
+ do {
+ rc = i2c_compute_timing(init, clock_src, timing);
+ if (rc != 0) {
+ ERROR("Failed to compute I2C timings\n");
+ if (init->bus_rate > STANDARD_RATE) {
+ init->bus_rate = get_lower_rate(init->bus_rate);
+ WARN("Downgrade I2C speed to %uHz)\n",
+ init->bus_rate);
+ } else {
+ break;
+ }
+ }
+ } while (rc != 0);
+
+ if (rc != 0) {
+ ERROR("Impossible to compute I2C timings\n");
+ return rc;
+ }
+
+ VERBOSE("I2C Freq(%i), Clk Source(%i)\n",
+ init->bus_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);
+
+ hi2c->saved_timing = *timing;
+ hi2c->saved_frequency = clock_src;
+
+ return 0;
+}
+
/*
* @brief Configure I2C Analog noise filter.
* @param hi2c: Pointer to a struct i2c_handle_s structure that contains
@@ -88,49 +460,30 @@ static int i2c_config_analog_filter(struct i2c_handle_s *hi2c,
/*
* @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)
+int stm32_i2c_get_setup_from_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;
- }
+ uint32_t read_val;
+
+ init->rise_time = fdt_read_uint32_default(node,
+ "i2c-scl-rising-time-ns",
+ STM32_I2C_RISE_TIME_DEFAULT);
+
+ init->fall_time = fdt_read_uint32_default(node,
+ "i2c-scl-falling-time-ns",
+ STM32_I2C_FALL_TIME_DEFAULT);
+
+ read_val = fdt_read_uint32_default(node, "clock-frequency",
+ STANDARD_RATE);
+ if (read_val > FAST_PLUS_RATE) {
+ ERROR("Invalid bus speed (%i > %i)\n", read_val,
+ FAST_PLUS_RATE);
+ return -FDT_ERR_BADVALUE;
}
+ init->bus_rate = read_val;
return dt_set_pinctrl_config(node);
}
@@ -146,7 +499,7 @@ int stm32_i2c_init(struct i2c_handle_s *hi2c,
struct stm32_i2c_init_s *init_data)
{
int rc = 0;
- uint32_t timing = I2C_TIMING;
+ uint32_t timing;
if (hi2c == NULL) {
return -ENOENT;
@@ -158,6 +511,11 @@ int stm32_i2c_init(struct i2c_handle_s *hi2c,
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 */
@@ -978,4 +1336,3 @@ bail:
return rc;
}
-
diff --git a/drivers/st/io/io_mmc.c b/drivers/st/io/io_mmc.c
index a239b5f3a..0b0e84ec1 100644
--- a/drivers/st/io/io_mmc.c
+++ b/drivers/st/io/io_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
*/
@@ -20,14 +20,15 @@ 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, ssize_t offset);
+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 ssize_t seek_offset;
+static signed long long seek_offset;
static const io_dev_connector_t mmc_dev_connector = {
.dev_open = mmc_dev_open
@@ -85,7 +86,8 @@ static int mmc_block_open(io_dev_info_t *dev_info, const uintptr_t spec,
}
/* Seek to a particular file offset on the mmc device */
-static int mmc_block_seek(io_entity_t *entity, int mode, ssize_t offset)
+static int mmc_block_seek(io_entity_t *entity, int mode,
+ signed long long offset)
{
seek_offset = offset;
return 0;
@@ -95,12 +97,18 @@ static int mmc_block_seek(io_entity_t *entity, int mode, ssize_t offset)
static int mmc_block_read(io_entity_t *entity, uintptr_t buffer,
size_t length, size_t *length_read)
{
- *length_read = mmc_read_blocks(seek_offset / MMC_BLOCK_SIZE,
- buffer, length);
+ uint8_t retries = 3U;
- if (*length_read != length) {
- return -EIO;
- }
+ 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;
}
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 000000000..20da9656e
--- /dev/null
+++ b/drivers/st/io/io_programmer_st_usb.c
@@ -0,0 +1,381 @@
+/*
+ * Copyright (c) 2017-2020, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/io/io_driver.h>
+#include <drivers/io/io_storage.h>
+#include <drivers/st/io_programmer.h>
+#include <drivers/st/io_programmer_st_usb.h>
+#include <drivers/st/io_stm32image.h>
+#include <drivers/st/stm32_iwdg.h>
+#include <lib/usb/usb_st_dfu.h>
+
+#define USB_STATE_READY 0
+#define USB_STATE_WRITTEN 1
+
+#define IO_USB_TIMEOUT_10_SEC U(10000000)
+#define DETACH_TIMEOUT U(0x100)
+#define USB_DFU_MAX_XFER_SIZE 1024
+
+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;
+
+/* 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)&current_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 {
+#if TRUSTED_BOARD_BOOT
+ stm32mp_save_loaded_header(header);
+#endif
+ 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();
+
+ 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 = stm32mp_check_header(header, (uintptr_t)local_ptr);
+ if (result) {
+ ERROR("Header check failed\n");
+ return result;
+ }
+
+ /* Wait Detach in case of bl33 */
+ if (current_phase.phase_id == PHASE_SSBL) {
+ uint64_t 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();
+ timeout = timeout_init_us(IO_USB_TIMEOUT_10_SEC);
+
+ while (detach_timeout != 0U) {
+ usb_core_handle_it((usb_handle_t *)
+ usb_dev_info.info);
+
+ if (usb_dfu_detach_req() == 0U) {
+ /*
+ * Continue to handle usb core IT to assure
+ * complete data transmission
+ */
+ detach_timeout--;
+ }
+
+ if (timeout_elapsed(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
index 413521b1e..a50a0df97 100644
--- a/drivers/st/io/io_stm32image.c
+++ b/drivers/st/io/io_stm32image.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2018-2020, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -182,53 +182,26 @@ static int stm32image_partition_size(io_entity_t *entity, size_t *length)
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;
- }
+ result = io_seek(backend_handle, IO_SEEK_SET, *stm32_img);
+ if (result != 0) {
+ ERROR("%s: io_seek (%i)\n", __func__, result);
+ goto out;
}
- io_close(backend_handle);
-
+ result = io_read(backend_handle, (uintptr_t)header,
+ MAX_LBA_SIZE, &bytes_read);
if (result != 0) {
- return result;
+ ERROR("%s: io_read (%i)\n", __func__, result);
+ goto out;
+ }
+
+ 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);
+ result = -ENOMEM;
+ goto out;
}
if (header->image_length < stm32image_dev.lba_size) {
@@ -239,15 +212,21 @@ static int stm32image_partition_size(io_entity_t *entity, size_t *length)
INFO("STM32 Image size : %lu\n", (unsigned long)*length);
- return 0;
+out:
+ io_close(backend_handle);
+
+ return result;
}
/* 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;
- uint8_t *local_buffer = (uint8_t *)buffer;
+ int offset;
+ int local_length;
+ uintptr_t backend_handle;
+ int result = -EINVAL;
+ uint8_t *local_buffer;
boot_api_image_header_t *header =
(boot_api_image_header_t *)first_lba_buffer;
@@ -255,101 +234,55 @@ static int stm32image_partition_read(io_entity_t *entity, uintptr_t buffer,
assert(buffer != 0U);
assert(length_read != NULL);
+ local_buffer = (uint8_t *)buffer;
*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;
- }
+#if TRUSTED_BOARD_BOOT
+ stm32mp_save_loaded_header(header);
+#endif
+
+ /* 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 = stm32mp_check_header(header, buffer);
- if (result != 0) {
- ERROR("Header check failed\n");
- *length_read = 0;
- header->magic = 0;
- }
+ result = io_open(backend_dev_handle, backend_image_spec,
+ &backend_handle);
+ if (result != 0) {
+ ERROR("%s: io_open (%i)\n", __func__, result);
+ return result;
+ }
- result = stm32mp_auth_image(header, buffer);
- if (result != 0) {
- ERROR("Authentication Failed (%i)\n", result);
- return result;
- }
+ result = io_seek(backend_handle, IO_SEEK_SET, *stm32_img + offset);
+ if (result != 0) {
+ ERROR("%s: io_seek (%i)\n", __func__, result);
+ goto out;
+ }
- io_close(backend_handle);
+ result = io_read(backend_handle, (uintptr_t)local_buffer,
+ local_length, length_read);
+ if (result != 0) {
+ ERROR("%s: io_read (%i)\n", __func__, result);
+ goto out;
}
+ /* Adding part of size already read from header */
+ *length_read += MAX_LBA_SIZE - sizeof(boot_api_image_header_t);
+
+out:
+ io_close(backend_handle);
return result;
}
diff --git a/drivers/st/iwdg/stm32_iwdg.c b/drivers/st/iwdg/stm32_iwdg.c
index ea6fbb2b9..6055e4d84 100644
--- a/drivers/st/iwdg/stm32_iwdg.c
+++ b/drivers/st/iwdg/stm32_iwdg.c
@@ -22,11 +22,30 @@
#include <lib/utils.h>
#include <plat/common/platform.h>
+#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;
@@ -52,6 +71,109 @@ static int stm32_iwdg_get_dt_node(struct dt_node_info *info, int offset)
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();
+
+ 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(void)
{
uint8_t i;
@@ -74,6 +196,7 @@ void stm32_iwdg_refresh(void)
int stm32_iwdg_init(void)
{
int node = -1;
+ int __unused res;
struct dt_node_info dt_info;
void *fdt;
uint32_t __unused count = 0;
@@ -137,6 +260,23 @@ int stm32_iwdg_init(void)
((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(idx, iwdg->flags) != BSEC_OK) {
return -1;
diff --git a/drivers/st/mmc/stm32_sdmmc2.c b/drivers/st/mmc/stm32_sdmmc2.c
index 24e6efe98..782127c49 100644
--- a/drivers/st/mmc/stm32_sdmmc2.c
+++ b/drivers/st/mmc/stm32_sdmmc2.c
@@ -50,6 +50,7 @@
/* SDMMC power control register */
#define SDMMC_POWER_PWRCTRL GENMASK(1, 0)
+#define SDMMC_POWER_PWRCTRL_PWR_CYCLE BIT(1)
#define SDMMC_POWER_DIRPOL BIT(4)
/* SDMMC clock control register */
@@ -116,6 +117,15 @@
#define TIMEOUT_US_10_MS 10000U
#define TIMEOUT_US_1_S 1000000U
+/* Power cycle delays in ms */
+#define VCC_POWER_OFF_DELAY 2
+#define VCC_POWER_ON_DELAY 2
+#define POWER_CYCLE_DELAY 2
+#define POWER_OFF_DELAY 2
+#define POWER_ON_DELAY 1
+
+#define TIMEOUT_US_1MS U(1000)
+
#define DT_SDMMC2_COMPAT "st,stm32-sdmmc2"
static void stm32_sdmmc2_init(void);
@@ -137,12 +147,35 @@ static const struct mmc_ops stm32_sdmmc2_ops = {
static struct stm32_sdmmc2_params sdmmc2_params;
+static bool next_cmd_is_acmd;
+
#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;
@@ -153,6 +186,26 @@ static void stm32_sdmmc2_init(void)
freq = MIN(sdmmc2_params.max_freq, freq);
}
+ if (sdmmc2_params.vmmc_regu.id != -1) {
+ stm32mp_regulator_register(&sdmmc2_params.vmmc_regu);
+ stm32mp_regulator_disable(&sdmmc2_params.vmmc_regu);
+ }
+
+ mdelay(VCC_POWER_OFF_DELAY);
+
+ mmio_write_32(base + SDMMC_POWER,
+ SDMMC_POWER_PWRCTRL_PWR_CYCLE | sdmmc2_params.dirpol);
+ mdelay(POWER_CYCLE_DELAY);
+
+ if (sdmmc2_params.vmmc_regu.id != -1) {
+ stm32mp_regulator_enable(&sdmmc2_params.vmmc_regu);
+ }
+
+ mdelay(VCC_POWER_ON_DELAY);
+
+ mmio_write_32(base + SDMMC_POWER, sdmmc2_params.dirpol);
+ mdelay(POWER_OFF_DELAY);
+
clock_div = div_round_up(sdmmc2_params.clk_rate, freq * 2U);
mmio_write_32(base + SDMMC_CLKCR, SDMMC_CLKCR_HWFC_EN | clock_div |
@@ -162,7 +215,7 @@ static void stm32_sdmmc2_init(void)
mmio_write_32(base + SDMMC_POWER,
SDMMC_POWER_PWRCTRL | sdmmc2_params.dirpol);
- mdelay(1);
+ mdelay(POWER_ON_DELAY);
}
static int stm32_sdmmc2_stop_transfer(void)
@@ -220,6 +273,20 @@ static int stm32_sdmmc2_send_cmd_req(struct mmc_cmd *cmd)
case MMC_CMD(1):
arg_reg |= OCR_POWERUP;
break;
+ case MMC_CMD(6):
+ if ((sdmmc2_params.device_info->mmc_dev_type == MMC_IS_SD_HC) &&
+ (!next_cmd_is_acmd)) {
+ 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;
case MMC_CMD(8):
if (sdmmc2_params.device_info->mmc_dev_type == MMC_IS_EMMC) {
cmd_reg |= SDMMC_CMDR_CMDTRANS;
@@ -257,6 +324,8 @@ static int stm32_sdmmc2_send_cmd_req(struct mmc_cmd *cmd)
break;
}
+ next_cmd_is_acmd = (cmd->cmd_idx == MMC_CMD(55));
+
if ((cmd->resp_type & MMC_RSP_BUSY) != 0U) {
mmio_write_32(base + SDMMC_DTIMER, UINT32_MAX);
}
@@ -550,6 +619,7 @@ static int stm32_sdmmc2_read(int lba, uintptr_t buf, size_t size)
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);
@@ -567,6 +637,7 @@ static int stm32_sdmmc2_read(int lba, uintptr_t buf, size_t size)
if (timeout_elapsed(timeout)) {
ERROR("%s: timeout 1s (status = %x)\n",
__func__, status);
+ dump_registers();
mmio_write_32(base + SDMMC_ICR,
SDMMC_STATIC_FLAGS);
@@ -615,6 +686,7 @@ static int stm32_sdmmc2_dt_get_config(void)
int sdmmc_node;
void *fdt = NULL;
const fdt32_t *cuint;
+ struct dt_node_info dt_info;
if (fdt_get_address(&fdt) == 0) {
return -FDT_ERR_NOTFOUND;
@@ -624,27 +696,14 @@ static int stm32_sdmmc2_dt_get_config(void)
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);
- }
-
+ sdmmc_node = dt_match_instance_by_compatible(DT_SDMMC2_COMPAT,
+ sdmmc2_params.reg_base);
if (sdmmc_node == -FDT_ERR_NOTFOUND) {
return -FDT_ERR_NOTFOUND;
}
- if (fdt_get_status(sdmmc_node) == DT_DISABLED) {
+ dt_fill_device_info(&dt_info, sdmmc_node);
+ if (dt_info.status == DT_DISABLED) {
return -FDT_ERR_NOTFOUND;
}
@@ -652,21 +711,8 @@ static int stm32_sdmmc2_dt_get_config(void)
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);
+ sdmmc2_params.clock_id = dt_info.clock;
+ sdmmc2_params.reset_id = dt_info.reset;
if ((fdt_getprop(fdt, sdmmc_node, "st,use-ckin", NULL)) != NULL) {
sdmmc2_params.pin_ckin = SDMMC_CLKCR_SELCLKRX_0;
@@ -701,6 +747,11 @@ static int stm32_sdmmc2_dt_get_config(void)
sdmmc2_params.max_freq = fdt32_to_cpu(*cuint);
}
+ cuint = fdt_getprop(fdt, sdmmc_node, "vmmc-supply", NULL);
+ if (cuint != NULL) {
+ sdmmc2_params.vmmc_regu.id = fdt32_to_cpu(*cuint);
+ }
+
return 0;
}
@@ -719,6 +770,8 @@ int stm32_sdmmc2_mmc_init(struct stm32_sdmmc2_params *params)
memcpy(&sdmmc2_params, params, sizeof(struct stm32_sdmmc2_params));
+ sdmmc2_params.vmmc_regu.id = -1;
+
if (stm32_sdmmc2_dt_get_config() != 0) {
ERROR("%s: DT error\n", __func__);
return -ENOMEM;
@@ -726,9 +779,13 @@ int stm32_sdmmc2_mmc_init(struct stm32_sdmmc2_params *params)
stm32mp_clk_enable(sdmmc2_params.clock_id);
- stm32mp_reset_assert(sdmmc2_params.reset_id);
+ if (stm32mp_reset_assert_to(sdmmc2_params.reset_id, TIMEOUT_US_1MS)) {
+ panic();
+ }
udelay(2);
- stm32mp_reset_deassert(sdmmc2_params.reset_id);
+ if (stm32mp_reset_deassert_to(sdmmc2_params.reset_id, TIMEOUT_US_1MS)) {
+ panic();
+ }
mdelay(1);
sdmmc2_params.clk_rate = stm32mp_clk_get_rate(sdmmc2_params.clock_id);
diff --git a/drivers/st/pmic/stm32mp_pmic.c b/drivers/st/pmic/stm32mp_pmic.c
index 9e9dddc4d..07249f607 100644
--- a/drivers/st/pmic/stm32mp_pmic.c
+++ b/drivers/st/pmic/stm32mp_pmic.c
@@ -1,9 +1,10 @@
/*
- * Copyright (c) 2017-2019, STMicroelectronics - All Rights Reserved
+ * Copyright (c) 2017-2020, STMicroelectronics - All Rights Reserved
*
* SPDX-License-Identifier: BSD-3-Clause
*/
+#include <assert.h>
#include <errno.h>
#include <libfdt.h>
@@ -22,156 +23,396 @@
#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
+#define CMD_GET_MIN_VOLTAGE 0U
+#define CMD_CONFIG_BOOT_ON 1U
+#define CMD_CONFIG_LP 2U
+
static struct i2c_handle_s i2c_handle;
static uint32_t pmic_i2c_addr;
-static int dt_get_pmic_node(void *fdt)
+static int dt_get_pmic_node(void)
{
- return fdt_node_offset_by_compatible(fdt, -1, "st,stpmic1");
+ static int node = -FDT_ERR_BADOFFSET;
+
+ if (node == -FDT_ERR_BADOFFSET) {
+ node = dt_get_node_by_compatible("st,stpmic1");
+ }
+
+ return node;
}
int dt_pmic_status(void)
{
+ static int status = -FDT_ERR_BADVALUE;
int node;
- void *fdt;
- if (fdt_get_address(&fdt) == 0) {
- return -ENOENT;
+ if (status != -FDT_ERR_BADVALUE) {
+ return status;
}
- node = dt_get_pmic_node(fdt);
+ node = dt_get_pmic_node();
if (node <= 0) {
- return -FDT_ERR_NOTFOUND;
+ status = -FDT_ERR_NOTFOUND;
+
+ return status;
}
- return fdt_get_status(node);
+ status = (int)fdt_get_status(node);
+
+ return status;
}
-/*
- * Get PMIC and its I2C bus configuration from the device tree.
- * Return 0 on success, negative on error, 1 if no PMIC node is found.
- */
-static int dt_pmic_i2c_config(struct dt_node_info *i2c_info,
- struct stm32_i2c_init_s *init)
+static bool dt_pmic_is_secure(void)
+{
+ int status = dt_pmic_status();
+
+ return (status >= 0) &&
+ (status == DT_SECURE) &&
+ (i2c_handle.dt_status == DT_SECURE);
+}
+
+static int dt_pmic_get_regulator_voltage(void *fdt, int node,
+ uint16_t *min_mv, uint16_t *max_mv)
{
- int pmic_node, i2c_node;
- void *fdt;
const fdt32_t *cuint;
- if (fdt_get_address(&fdt) == 0) {
- return -ENOENT;
+ cuint = fdt_getprop(fdt, node, "regulator-min-microvolt", NULL);
+ if (cuint == NULL) {
+ return -FDT_ERR_NOTFOUND;
}
- pmic_node = dt_get_pmic_node(fdt);
- if (pmic_node < 0) {
- return 1;
+ if (min_mv != NULL) {
+ *min_mv = (uint16_t)(fdt32_to_cpu(*cuint) / 1000U);
}
- cuint = fdt_getprop(fdt, pmic_node, "reg", NULL);
+ cuint = fdt_getprop(fdt, node, "regulator-max-microvolt", NULL);
if (cuint == NULL) {
return -FDT_ERR_NOTFOUND;
}
- pmic_i2c_addr = fdt32_to_cpu(*cuint) << 1;
- if (pmic_i2c_addr > UINT16_MAX) {
- return -EINVAL;
+ if (max_mv != NULL) {
+ *max_mv = (uint16_t)(fdt32_to_cpu(*cuint) / 1000U);
}
- i2c_node = fdt_parent_offset(fdt, pmic_node);
- if (i2c_node < 0) {
- return -FDT_ERR_NOTFOUND;
+ return 0;
+}
+
+static int pmic_config_boot_on(void *fdt, int node, const char *regu_name)
+{
+ uint16_t voltage = 0U;
+ uint16_t voltage_min;
+ uint16_t voltage_max;
+ int status;
+ int pmic_voltage;
+
+ if ((fdt_getprop(fdt, node, "regulator-boot-on", NULL) == NULL) &&
+ (fdt_getprop(fdt, node, "regulator-always-on", NULL) == NULL)) {
+ return 0;
}
- dt_fill_device_info(i2c_info, i2c_node);
- if (i2c_info->base == 0U) {
- return -FDT_ERR_NOTFOUND;
+ if (fdt_getprop(fdt, node, "regulator-pull-down", NULL) != NULL) {
+
+ status = stpmic1_regulator_pull_down_set(regu_name);
+ if (status < 0) {
+ return status;
+ }
+ }
+
+ if (fdt_getprop(fdt, node, "st,mask-reset", NULL) != NULL) {
+
+ status = stpmic1_regulator_mask_reset_set(regu_name);
+ if (status < 0) {
+ return status;
+ }
+ }
+
+ if (dt_pmic_get_regulator_voltage(fdt, node, &voltage_min,
+ &voltage_max) < 0) {
+ return 0;
+ }
+
+ pmic_voltage = stpmic1_regulator_voltage_get(regu_name);
+ if (pmic_voltage < 0) {
+ return pmic_voltage;
+ }
+
+ if ((uint16_t)pmic_voltage < voltage_min) {
+ voltage = voltage_min;
+ }
+
+ if ((uint16_t)pmic_voltage > voltage_max) {
+ voltage = voltage_max;
+ }
+
+ /* Only re-program voltage if not in the range provided in DT. */
+ if (voltage != 0U) {
+ status = stpmic1_regulator_voltage_set(regu_name, voltage);
+ if (status < 0) {
+ return status;
+ }
+ }
+
+ if (!stpmic1_is_regulator_enabled(regu_name)) {
+ status = stpmic1_regulator_enable(regu_name);
+ if (status < 0) {
+ return status;
+ }
}
- return stm32_i2c_get_setup_from_fdt(fdt, i2c_node, init);
+ return 0;
}
-int dt_pmic_configure_boot_on_regulators(void)
+#if defined(IMAGE_BL32)
+static int pmic_config_lp(void *fdt, int node, const char *node_name,
+ const char *regu_name)
{
- int pmic_node, regulators_node, regulator_node;
+ int status;
+ const fdt32_t *cuint;
+ int regulator_state_node;
+
+ status = stpmic1_powerctrl_on();
+ if (status < 0) {
+ return status;
+ };
+
+ /*
+ * First, copy active configuration (Control register) to
+ * PWRCTRL Control register, even if regulator_state_node
+ * does not exist.
+ */
+ status = stpmic1_lp_copy_reg(regu_name);
+ if (status < 0) {
+ return status;
+ }
+
+ /* Then apply configs from regulator_state_node */
+ regulator_state_node = fdt_subnode_offset(fdt, node, node_name);
+ if (regulator_state_node <= 0) {
+ return 0;
+ }
+
+ if (fdt_getprop(fdt, regulator_state_node, "regulator-on-in-suspend",
+ NULL) != NULL) {
+ status = stpmic1_lp_reg_on_off(regu_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(regu_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(regu_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(regu_name, 1);
+ if (status < 0) {
+ return status;
+ }
+ }
+ }
+
+ return 0;
+}
+#endif
+
+static int pmic_operate(uint8_t command, const char *node_name,
+ uint16_t *voltage_mv)
+{
+ int pmic_node, regulators_node, subnode;
void *fdt;
+ int ret = -EIO;
if (fdt_get_address(&fdt) == 0) {
return -ENOENT;
}
- pmic_node = dt_get_pmic_node(fdt);
+ pmic_node = dt_get_pmic_node();
if (pmic_node < 0) {
- return -FDT_ERR_NOTFOUND;
+ return -ENOENT;
}
regulators_node = fdt_subnode_offset(fdt, pmic_node, "regulators");
+ if (regulators_node < 0) {
+ return -ENOENT;
+ }
- 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;
- }
+ fdt_for_each_subnode(subnode, fdt, regulators_node) {
+ const char *regu_name = fdt_get_name(fdt, subnode, NULL);
- if (fdt_getprop(fdt, regulator_node, "regulator-pull-down",
- NULL) != NULL) {
+ switch (command) {
+ case CMD_GET_MIN_VOLTAGE:
+ assert(node_name != NULL);
+ assert(voltage_mv != NULL);
- status = stpmic1_regulator_pull_down_set(node_name);
- if (status != 0) {
- return status;
+ if (strcmp(regu_name, node_name) != 0) {
+ continue;
}
- }
- if (fdt_getprop(fdt, regulator_node, "st,mask-reset",
- NULL) != NULL) {
+ ret = dt_pmic_get_regulator_voltage(fdt, subnode,
+ voltage_mv, NULL);
+ if (ret < 0) {
+ return -ENXIO;
+ }
- status = stpmic1_regulator_mask_reset_set(node_name);
- if (status != 0) {
- return status;
+ return ret;
+
+ case CMD_CONFIG_BOOT_ON:
+ ret = pmic_config_boot_on(fdt, subnode, regu_name);
+ if (ret < 0) {
+ return ret;
}
+ break;
+
+#if defined(IMAGE_BL32)
+ case CMD_CONFIG_LP:
+ assert(node_name != NULL);
+
+ ret = pmic_config_lp(fdt, subnode, node_name,
+ regu_name);
+ if (ret < 0) {
+ return ret;
+ }
+ break;
+#endif
+
+ default:
+ return -EINVAL;
+ }
+ }
+
+ return ret;
+}
+
+/*
+ * 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)
+{
+ static int i2c_node = -FDT_ERR_NOTFOUND;
+
+ if (i2c_node == -FDT_ERR_NOTFOUND) {
+ void *fdt;
+ int pmic_node;
+ const fdt32_t *cuint;
+
+ if (fdt_get_address(&fdt) == 0) {
+ return -FDT_ERR_NOTFOUND;
+ }
+
+ pmic_node = dt_get_pmic_node();
+ if (pmic_node < 0) {
+ return 1;
}
- cuint = fdt_getprop(fdt, regulator_node,
- "regulator-min-microvolt", NULL);
+ cuint = fdt_getprop(fdt, pmic_node, "reg", NULL);
if (cuint == NULL) {
- continue;
+ return -FDT_ERR_NOTFOUND;
}
- /* DT uses microvolts, whereas driver awaits millivolts */
- voltage = (uint16_t)(fdt32_to_cpu(*cuint) / 1000U);
+ pmic_i2c_addr = fdt32_to_cpu(*cuint) << 1;
+ if (pmic_i2c_addr > UINT16_MAX) {
+ return -FDT_ERR_BADVALUE;
+ }
- status = stpmic1_regulator_voltage_set(node_name, voltage);
- if (status != 0) {
- return status;
+ i2c_node = fdt_parent_offset(fdt, pmic_node);
+ if (i2c_node < 0) {
+ return -FDT_ERR_NOTFOUND;
}
+ }
- if (stpmic1_is_regulator_enabled(node_name) == 0U) {
- status = stpmic1_regulator_enable(node_name);
- if (status != 0) {
- return status;
- }
+ dt_fill_device_info(i2c_info, i2c_node);
+ if (i2c_info->base == 0U) {
+ return -FDT_ERR_NOTFOUND;
+ }
+
+ return stm32_i2c_get_setup_from_fdt(i2c_node, init);
+}
+
+int pmic_configure_boot_on_regulators(void)
+{
+ return pmic_operate(CMD_CONFIG_BOOT_ON, NULL, NULL);
+}
+
+int pmic_set_lp_config(const char *node_name)
+{
+ return pmic_operate(CMD_CONFIG_LP, node_name, NULL);
+}
+
+int dt_pmic_find_supply(const char **supply_name, const char *regu_name)
+{
+ int pmic_node, regulators_node, subnode;
+ void *fdt;
+
+ if (fdt_get_address(&fdt) == 0) {
+ return -FDT_ERR_NOTFOUND;
+ }
+
+ pmic_node = dt_get_pmic_node();
+ if (pmic_node < 0) {
+ return -FDT_ERR_NOTFOUND;
+ }
+
+ regulators_node = fdt_subnode_offset(fdt, pmic_node, "regulators");
+ if (regulators_node < 0) {
+ return -FDT_ERR_NOTFOUND;
+ }
+
+ fdt_for_each_subnode(subnode, fdt, regulators_node) {
+ const char *name;
+
+ name = fdt_getprop(fdt, subnode, "regulator-name", NULL);
+ if ((name != NULL) &&
+ (strcmp(name, regu_name) == 0)) {
+ *supply_name = fdt_get_name(fdt, subnode, NULL);
+ return 0;
}
}
- return 0;
+ return -FDT_ERR_NOTFOUND;
+}
+
+int pmic_set_regulator_min_voltage(const char *regu_name)
+{
+ int rc = -ENOENT;
+ const char *supply_name;
+
+ if (dt_pmic_find_supply(&supply_name, regu_name) == 0) {
+ uint16_t min_mv;
+
+ rc = pmic_operate(CMD_GET_MIN_VOLTAGE, supply_name, &min_mv);
+ if (rc == 0) {
+ rc = stpmic1_regulator_voltage_set(supply_name, min_mv);
+ }
+ }
+
+ return rc;
}
bool initialize_pmic_i2c(void)
@@ -195,6 +436,7 @@ bool initialize_pmic_i2c(void)
i2c->i2c_base_addr = i2c_info.base;
i2c->dt_status = i2c_info.status;
i2c->clock = i2c_info.clock;
+ i2c->i2c_state = I2C_STATE_RESET;
i2c_init.own_address1 = pmic_i2c_addr;
i2c_init.addressing_mode = I2C_ADDRESSINGMODE_7BIT;
i2c_init.dual_address_mode = I2C_DUALADDRESS_DISABLE;
@@ -223,15 +465,104 @@ bool initialize_pmic_i2c(void)
return true;
}
-void initialize_pmic(void)
+static void register_non_secure_pmic(void)
{
- unsigned long pmic_version;
+ if (i2c_handle.i2c_base_addr == 0U) {
+ return;
+ }
+
+ stm32mp_register_non_secure_periph_iomem(i2c_handle.i2c_base_addr);
+}
+
+static void register_secure_pmic(void)
+{
+ stm32mp_register_secure_periph_iomem(i2c_handle.i2c_base_addr);
+}
+static int pmic_regulator_enable(struct stm32mp_regulator *regu)
+{
+ void *fdt;
+ const char *node_name;
+
+ if (fdt_get_address(&fdt) == 0) {
+ return -ENOENT;
+ }
+
+ node_name = fdt_get_name(fdt, fdt_node_offset_by_phandle(fdt, regu->id),
+ NULL);
+
+ return stpmic1_regulator_enable(node_name);
+}
+
+static int pmic_regulator_disable(struct stm32mp_regulator *regu)
+{
+ void *fdt;
+ const char *node_name;
+
+ if (fdt_get_address(&fdt) == 0) {
+ return -ENOENT;
+ }
+
+ node_name = fdt_get_name(fdt, fdt_node_offset_by_phandle(fdt, regu->id),
+ NULL);
+
+ return stpmic1_regulator_disable(node_name);
+}
+
+static const struct stm32mp_regulator_ops pmic_regu_ops = {
+ .enable = pmic_regulator_enable,
+ .disable = pmic_regulator_disable,
+};
+
+bool is_pmic_regulator(struct stm32mp_regulator *regu)
+{
+ void *fdt;
+ int parent_node;
+
+ if (fdt_get_address(&fdt) == 0) {
+ return false;
+ }
+
+ parent_node = fdt_parent_offset(fdt,
+ fdt_node_offset_by_phandle(fdt,
+ regu->id));
+ return (fdt_node_check_compatible(fdt, parent_node,
+ "st,stpmic1-regulators") == 0);
+}
+
+void bind_pmic_regulator(struct stm32mp_regulator *regu)
+{
+ regu->ops = &pmic_regu_ops;
+}
+
+void initialize_pmic(void)
+{
if (!initialize_pmic_i2c()) {
VERBOSE("No PMIC\n");
+ register_non_secure_pmic();
return;
}
+ if (dt_pmic_is_secure()) {
+ register_secure_pmic();
+ } else {
+ VERBOSE("PMIC is not secure-only hence assumed non secure\n");
+ register_non_secure_pmic();
+ }
+}
+
+void configure_pmic(void)
+{
+ if (pmic_configure_boot_on_regulators() < 0) {
+ panic();
+ };
+}
+
+#if DEBUG
+void print_pmic_info_and_debug(void)
+{
+ unsigned long pmic_version;
+
if (stpmic1_get_version(&pmic_version) != 0) {
ERROR("Failed to access PMIC\n");
panic();
@@ -239,19 +570,20 @@ void initialize_pmic(void)
INFO("PMIC version = 0x%02lx\n", pmic_version);
stpmic1_dump_regulators();
-
-#if defined(IMAGE_BL2)
- if (dt_pmic_configure_boot_on_regulators() != 0) {
- panic();
- };
-#endif
}
+#endif
int pmic_ddr_power_init(enum ddr_type ddr_type)
{
bool buck3_at_1v8 = false;
uint8_t read_val;
int status;
+ uint16_t buck2_mv;
+ uint16_t ldo3_mv;
+
+ if (pmic_operate(CMD_GET_MIN_VOLTAGE, "buck2", &buck2_mv) != 0) {
+ return -EPERM;
+ }
switch (ddr_type) {
case STM32MP_DDR3:
@@ -271,7 +603,7 @@ int pmic_ddr_power_init(enum ddr_type ddr_type)
return status;
}
- status = stpmic1_regulator_voltage_set("buck2", 1350);
+ status = stpmic1_regulator_voltage_set("buck2", buck2_mv);
if (status != 0) {
return status;
}
@@ -321,7 +653,6 @@ int pmic_ddr_power_init(enum ddr_type ddr_type)
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;
}
@@ -331,7 +662,16 @@ int pmic_ddr_power_init(enum ddr_type ddr_type)
return status;
}
- status = stpmic1_regulator_voltage_set("buck2", 1200);
+ if (pmic_operate(CMD_GET_MIN_VOLTAGE, "ldo3", &ldo3_mv) != 0) {
+ return -EPERM;
+ }
+
+ status = stpmic1_regulator_voltage_set("ldo3", ldo3_mv);
+ if (status != 0) {
+ return status;
+ }
+
+ status = stpmic1_regulator_voltage_set("buck2", buck2_mv);
if (status != 0) {
return status;
}
diff --git a/drivers/st/pmic/stpmic1.c b/drivers/st/pmic/stpmic1.c
index 999963054..a1db120dc 100644
--- a/drivers/st/pmic/stpmic1.c
+++ b/drivers/st/pmic/stpmic1.c
@@ -1,9 +1,10 @@
/*
- * Copyright (c) 2016-2019, STMicroelectronics - All Rights Reserved
+ * Copyright (c) 2016-2020, STMicroelectronics - All Rights Reserved
*
* SPDX-License-Identifier: BSD-3-Clause
*/
+#include <errno.h>
#include <string.h>
#include <common/debug.h>
@@ -419,6 +420,10 @@ static const uint16_t vref_ddr_voltage_table[] = {
3300,
};
+static const uint16_t fixed_5v_voltage_table[] = {
+ 5000,
+};
+
/* Table of Regulators in PMIC SoC */
static const struct regul_struct regulators_table[] = {
{
@@ -528,6 +533,27 @@ static const struct regul_struct regulators_table[] = {
.mask_reset_reg = MASK_RESET_LDO_REG,
.mask_reset = VREF_DDR_MASK_RESET,
},
+ {
+ .dt_node_name = "boost",
+ .voltage_table = fixed_5v_voltage_table,
+ .voltage_table_size = ARRAY_SIZE(fixed_5v_voltage_table),
+ .control_reg = USB_CONTROL_REG,
+ .mask_reset = BOOST_ENABLED,
+ },
+ {
+ .dt_node_name = "pwr_sw1",
+ .voltage_table = fixed_5v_voltage_table,
+ .voltage_table_size = ARRAY_SIZE(fixed_5v_voltage_table),
+ .control_reg = USB_CONTROL_REG,
+ .mask_reset = USBSW_OTG_SWITCH_ENABLED,
+ },
+ {
+ .dt_node_name = "pwr_sw2",
+ .voltage_table = fixed_5v_voltage_table,
+ .voltage_table_size = ARRAY_SIZE(fixed_5v_voltage_table),
+ .control_reg = USB_CONTROL_REG,
+ .mask_reset = SWIN_SWOUT_ENABLED,
+ },
};
#define MAX_REGUL ARRAY_SIZE(regulators_table)
@@ -581,17 +607,19 @@ int stpmic1_regulator_enable(const char *name)
{
const struct regul_struct *regul = get_regulator_data(name);
- return stpmic1_register_update(regul->control_reg, BIT(0), BIT(0));
+ return stpmic1_register_update(regul->control_reg, LDO_BUCK_ENABLE_MASK,
+ LDO_BUCK_ENABLE_MASK);
}
int stpmic1_regulator_disable(const char *name)
{
const struct regul_struct *regul = get_regulator_data(name);
- return stpmic1_register_update(regul->control_reg, 0, BIT(0));
+ return stpmic1_register_update(regul->control_reg, 0,
+ LDO_BUCK_ENABLE_MASK);
}
-uint8_t stpmic1_is_regulator_enabled(const char *name)
+bool stpmic1_is_regulator_enabled(const char *name)
{
uint8_t val;
const struct regul_struct *regul = get_regulator_data(name);
@@ -600,7 +628,7 @@ uint8_t stpmic1_is_regulator_enabled(const char *name)
panic();
}
- return (val & 0x1U);
+ return (val & LDO_BUCK_ENABLE_MASK) == LDO_BUCK_ENABLE_MASK;
}
int stpmic1_regulator_voltage_set(const char *name, uint16_t millivolts)
@@ -648,11 +676,68 @@ int stpmic1_regulator_mask_reset_set(const char *name)
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);
+
+ if (regul->low_power_reg == 0U) {
+ return 0;
+ }
+
+ 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<N> or ldo<N> (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;
+ int status;
/* Voltage can be set for buck<N> or ldo<N> (except ldo4) regulators */
if (strncmp(name, "buck", 4) == 0) {
@@ -664,13 +749,16 @@ int stpmic1_regulator_voltage_get(const char *name)
return 0;
}
- if (stpmic1_register_read(regul->control_reg, &value))
- return -1;
+ status = stpmic1_register_read(regul->control_reg, &value);
+ if (status < 0) {
+ return status;
+ }
value = (value & mask) >> LDO_BUCK_VOLTAGE_SHIFT;
- if (value > regul->voltage_table_size)
- return -1;
+ if (value > regul->voltage_table_size) {
+ return -ERANGE;
+ }
return (int)regul->voltage_table[value];
}
@@ -706,7 +794,7 @@ int stpmic1_register_write(uint8_t register_id, uint8_t value)
}
if (readval != value) {
- return -1;
+ return -EIO;
}
}
#endif
@@ -751,12 +839,12 @@ void stpmic1_dump_regulators(void)
int stpmic1_get_version(unsigned long *version)
{
- int rc;
uint8_t read_val;
+ int status;
- rc = stpmic1_register_read(VERSION_STATUS_REG, &read_val);
- if (rc) {
- return -1;
+ status = stpmic1_register_read(VERSION_STATUS_REG, &read_val);
+ if (status < 0) {
+ return status;
}
*version = (unsigned long)read_val;
diff --git a/drivers/st/regulator/stm32mp_dummy_regulator.c b/drivers/st/regulator/stm32mp_dummy_regulator.c
new file mode 100644
index 000000000..1003aba05
--- /dev/null
+++ b/drivers/st/regulator/stm32mp_dummy_regulator.c
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2019, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <drivers/st/stm32mp_dummy_regulator.h>
+
+static int dummy_regulator_enable(struct stm32mp_regulator *regu)
+{
+ return 0;
+}
+
+static int dummy_regulator_disable(struct stm32mp_regulator *regu)
+{
+ return 0;
+}
+
+static const struct stm32mp_regulator_ops dummy_regu_ops = {
+ .enable = dummy_regulator_enable,
+ .disable = dummy_regulator_disable,
+};
+
+void bind_dummy_regulator(struct stm32mp_regulator *regu)
+{
+ regu->ops = &dummy_regu_ops;
+}
diff --git a/drivers/st/regulator/stm32mp_regulator.c b/drivers/st/regulator/stm32mp_regulator.c
new file mode 100644
index 000000000..f0e4a4ae5
--- /dev/null
+++ b/drivers/st/regulator/stm32mp_regulator.c
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2019, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <drivers/st/stm32mp_regulator.h>
+
+#pragma weak plat_bind_regulator
+int plat_bind_regulator(struct stm32mp_regulator *regu)
+{
+ return -1;
+}
+
+int stm32mp_regulator_enable(struct stm32mp_regulator *regu)
+{
+ assert((regu->ops != NULL) && (regu->ops->enable != NULL));
+
+ return regu->ops->enable(regu);
+}
+
+int stm32mp_regulator_disable(struct stm32mp_regulator *regu)
+{
+ assert((regu->ops != NULL) && (regu->ops->disable != NULL));
+
+ if (regu->always_on) {
+ return 0;
+ }
+
+ return regu->ops->disable(regu);
+}
+
+int stm32mp_regulator_register(struct stm32mp_regulator *regu)
+{
+ return plat_bind_regulator(regu);
+}
diff --git a/drivers/st/reset/stm32mp1_reset.c b/drivers/st/reset/stm32mp1_reset.c
index fd3f93e01..a1e6e6b86 100644
--- a/drivers/st/reset/stm32mp1_reset.c
+++ b/drivers/st/reset/stm32mp1_reset.c
@@ -6,6 +6,8 @@
#include <limits.h>
+#include <lib/libc/errno.h>
+
#include <platform_def.h>
#include <common/bl_common.h>
@@ -15,8 +17,6 @@
#include <lib/mmio.h>
#include <lib/utils_def.h>
-#define RESET_TIMEOUT_US_1MS U(1000)
-
static uint32_t id2reg_offset(unsigned int reset_id)
{
return ((reset_id & GENMASK(31, 5)) >> 5) * sizeof(uint32_t);
@@ -27,36 +27,52 @@ 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)
+int stm32mp_reset_assert_to(uint32_t id, unsigned int to_us)
{
uint32_t offset = id2reg_offset(id);
uint32_t bitmsk = BIT(id2reg_bit_pos(id));
- uint64_t timeout_ref;
uintptr_t rcc_base = stm32mp_rcc_base();
mmio_write_32(rcc_base + offset, bitmsk);
- timeout_ref = timeout_init_us(RESET_TIMEOUT_US_1MS);
- while ((mmio_read_32(rcc_base + offset) & bitmsk) == 0U) {
- if (timeout_elapsed(timeout_ref)) {
- panic();
+ if (to_us != 0) {
+ uint64_t timeout_ref = timeout_init_us(to_us);
+
+ while ((mmio_read_32(rcc_base + offset) & bitmsk) == 0U) {
+ if (timeout_elapsed(timeout_ref)) {
+ break;
+ }
+ }
+
+ if ((mmio_read_32(rcc_base + offset) & bitmsk) == 0U) {
+ return -ETIMEDOUT;
}
}
+
+ return 0;
}
-void stm32mp_reset_deassert(uint32_t id)
+int stm32mp_reset_deassert_to(uint32_t id, unsigned int to_us)
{
uint32_t offset = id2reg_offset(id) + RCC_RSTCLRR_OFFSET;
uint32_t bitmsk = BIT(id2reg_bit_pos(id));
- uint64_t timeout_ref;
uintptr_t rcc_base = stm32mp_rcc_base();
mmio_write_32(rcc_base + offset, bitmsk);
- timeout_ref = timeout_init_us(RESET_TIMEOUT_US_1MS);
- while ((mmio_read_32(rcc_base + offset) & bitmsk) != 0U) {
- if (timeout_elapsed(timeout_ref)) {
- panic();
+ if (to_us != 0) {
+ uint64_t timeout_ref = timeout_init_us(to_us);
+
+ while ((mmio_read_32(rcc_base + offset) & bitmsk) != 0U) {
+ if (timeout_elapsed(timeout_ref)) {
+ break;
+ }
+ }
+
+ if ((mmio_read_32(rcc_base + offset) & bitmsk) != 0U) {
+ return -ETIMEDOUT;
}
}
+
+ return 0;
}
diff --git a/drivers/st/rng/stm32_rng.c b/drivers/st/rng/stm32_rng.c
new file mode 100644
index 000000000..b22065616
--- /dev/null
+++ b/drivers/st/rng/stm32_rng.c
@@ -0,0 +1,188 @@
+/*
+ * Copyright (c) 2018-2019, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <stdbool.h>
+
+#include <libfdt.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <drivers/delay_timer.h>
+#include <drivers/st/stm32_rng.h>
+#include <drivers/st/stm32mp_reset.h>
+#include <lib/mmio.h>
+
+#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
+
+#define TIMEOUT_US_1MS U(1000)
+
+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;
+
+ 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) {
+ if (stm32mp_reset_assert_to((unsigned long)dt_rng.reset,
+ TIMEOUT_US_1MS))
+ panic();
+
+ udelay(20);
+ if (stm32mp_reset_deassert_to((unsigned long)dt_rng.reset,
+ TIMEOUT_US_1MS))
+ panic();
+ }
+
+ VERBOSE("Init RNG done\n");
+
+ return 0;
+}
diff --git a/drivers/st/rtc/stm32_rtc.c b/drivers/st/rtc/stm32_rtc.c
new file mode 100644
index 000000000..3bfaed772
--- /dev/null
+++ b/drivers/st/rtc/stm32_rtc.c
@@ -0,0 +1,479 @@
+/*
+ * Copyright (c) 2018-2019, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/st/stm32_rtc.h>
+#include <drivers/st/stm32mp_clkfunc.h>
+#include <lib/mmio.h>
+#include <lib/spinlock.h>
+
+#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)
+{
+ if (stm32mp_lock_available()) {
+ spin_lock(&lock);
+ }
+}
+
+void stm32_rtc_regs_unlock(void)
+{
+ if (stm32mp_lock_available()) {
+ 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 signed long long stm32_rtc_diff_frac(struct stm32_rtc_calendar *cur,
+ struct stm32_rtc_calendar *ref)
+{
+ return (signed long long)stm32_rtc_get_second_fraction(cur) -
+ (signed long long)stm32_rtc_get_second_fraction(ref);
+}
+
+/*******************************************************************************
+ * This function computes the time difference between two timestamps.
+ * It includes seconds, minutes and hours.
+ * Here again the returned value is in milliseconds.
+ ******************************************************************************/
+static signed long long stm32_rtc_diff_time(struct stm32_rtc_time *current,
+ struct stm32_rtc_time *ref)
+{
+ 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);
+
+ return (curr_s - ref_s) * 1000;
+}
+
+/*******************************************************************************
+ * 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 signed long long stm32_rtc_diff_date(struct stm32_rtc_time *current,
+ struct stm32_rtc_time *ref)
+{
+ uint32_t diff_in_days = 0;
+ uint32_t m;
+ 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 (24 * 60 * 60 * 1000) * (signed 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)
+{
+ signed 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 (unsigned long long)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/scmi-msg/base.c b/drivers/st/scmi-msg/base.c
new file mode 100644
index 000000000..80ce190f7
--- /dev/null
+++ b/drivers/st/scmi-msg/base.c
@@ -0,0 +1,202 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Copyright (c) 2015-2019, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2019, Linaro Limited
+ */
+#include <assert.h>
+#include <string.h>
+
+#include <common/confine_array_index.h>
+#include <drivers/st/scmi-msg.h>
+#include <drivers/st/scmi.h>
+#include <lib/utils.h>
+#include <lib/utils_def.h>
+
+#include "common.h"
+
+static bool message_id_is_supported(unsigned int message_id);
+
+static void report_version(struct scmi_msg *msg)
+{
+ struct scmi_protocol_version_p2a return_values = {
+ .status = SCMI_SUCCESS,
+ .version = SCMI_PROTOCOL_VERSION_BASE,
+ };
+
+ if (msg->in_size != 0U) {
+ scmi_status_response(msg, SCMI_PROTOCOL_ERROR);
+ return;
+ }
+
+ scmi_write_response(msg, &return_values, sizeof(return_values));
+}
+
+static void report_attributes(struct scmi_msg *msg)
+{
+ size_t protocol_count = plat_scmi_protocol_count();
+ struct scmi_protocol_attributes_p2a return_values = {
+ .status = SCMI_SUCCESS,
+ /* Null agent count since agent discovery is not supported */
+ .attributes = SCMI_BASE_PROTOCOL_ATTRIBUTES(protocol_count, 0U),
+ };
+
+ if (msg->in_size != 0U) {
+ scmi_status_response(msg, SCMI_PROTOCOL_ERROR);
+ return;
+ }
+
+ scmi_write_response(msg, &return_values, sizeof(return_values));
+}
+
+static void report_message_attributes(struct scmi_msg *msg)
+{
+ struct scmi_protocol_message_attributes_a2p *in_args = (void *)msg->in;
+ struct scmi_protocol_message_attributes_p2a return_values = {
+ .status = SCMI_SUCCESS,
+ /* For this protocol, attributes shall be zero */
+ .attributes = 0U,
+ };
+
+ if (msg->in_size != sizeof(*in_args)) {
+ scmi_status_response(msg, SCMI_PROTOCOL_ERROR);
+ return;
+ }
+
+ if (!message_id_is_supported(in_args->message_id)) {
+ scmi_status_response(msg, SCMI_NOT_FOUND);
+ return;
+ }
+
+ scmi_write_response(msg, &return_values, sizeof(return_values));
+}
+
+static void discover_vendor(struct scmi_msg *msg)
+{
+ const char *name = plat_scmi_vendor_name();
+ struct scmi_base_discover_vendor_p2a return_values = {
+ .status = SCMI_SUCCESS,
+ };
+
+ if (msg->in_size != 0U) {
+ scmi_status_response(msg, SCMI_PROTOCOL_ERROR);
+ return;
+ }
+
+ COPY_NAME_IDENTIFIER(return_values.vendor_identifier, name);
+
+ scmi_write_response(msg, &return_values, sizeof(return_values));
+}
+
+static void discover_sub_vendor(struct scmi_msg *msg)
+{
+ const char *name = plat_scmi_sub_vendor_name();
+ struct scmi_base_discover_sub_vendor_p2a return_values = {
+ .status = SCMI_SUCCESS,
+ };
+
+ if (msg->in_size != 0U) {
+ scmi_status_response(msg, SCMI_PROTOCOL_ERROR);
+ return;
+ }
+
+ COPY_NAME_IDENTIFIER(return_values.sub_vendor_identifier, name);
+
+ scmi_write_response(msg, &return_values, sizeof(return_values));
+}
+
+static void discover_implementation_version(struct scmi_msg *msg)
+{
+ struct scmi_protocol_version_p2a return_values = {
+ .status = SCMI_SUCCESS,
+ .version = SCMI_IMPL_VERSION,
+ };
+
+ if (msg->in_size != 0U) {
+ scmi_status_response(msg, SCMI_PROTOCOL_ERROR);
+ return;
+ }
+
+ scmi_write_response(msg, &return_values, sizeof(return_values));
+}
+
+static unsigned int count_protocols_in_list(const uint8_t *protocol_list)
+{
+ unsigned int count = 0U;
+
+ if (protocol_list != NULL) {
+ while (protocol_list[count] != 0U) {
+ count++;
+ }
+ }
+
+ return count;
+}
+
+#define MAX_PROTOCOL_IN_LIST 8U
+
+static void discover_list_protocols(struct scmi_msg *msg)
+{
+ const struct scmi_base_discover_list_protocols_a2p *a2p = NULL;
+ struct scmi_base_discover_list_protocols_p2a p2a = {
+ .status = SCMI_SUCCESS,
+ };
+ uint8_t outargs[sizeof(p2a) + MAX_PROTOCOL_IN_LIST] = { 0U };
+ const uint8_t *list = NULL;
+ unsigned int count = 0U;
+
+ if (msg->in_size != sizeof(*a2p)) {
+ scmi_status_response(msg, SCMI_PROTOCOL_ERROR);
+ return;
+ }
+
+ assert(msg->out_size > sizeof(outargs));
+
+ a2p = (void *)msg->in;
+
+ list = plat_scmi_protocol_list(msg->agent_id);
+ count = count_protocols_in_list(list);
+ if (count > a2p->skip) {
+ count = MIN(count - a2p->skip, MAX_PROTOCOL_IN_LIST);
+ } else {
+ count = 0U;
+ }
+
+ p2a.num_protocols = count;
+
+ memcpy(outargs, &p2a, sizeof(p2a));
+ memcpy(outargs + sizeof(p2a), list + a2p->skip, count);
+
+ scmi_write_response(msg, outargs, sizeof(outargs));
+}
+
+static const scmi_msg_handler_t scmi_base_handler_table[] = {
+ [SCMI_PROTOCOL_VERSION] = report_version,
+ [SCMI_PROTOCOL_ATTRIBUTES] = report_attributes,
+ [SCMI_PROTOCOL_MESSAGE_ATTRIBUTES] = report_message_attributes,
+ [SCMI_BASE_DISCOVER_VENDOR] = discover_vendor,
+ [SCMI_BASE_DISCOVER_SUB_VENDOR] = discover_sub_vendor,
+ [SCMI_BASE_DISCOVER_IMPLEMENTATION_VERSION] =
+ discover_implementation_version,
+ [SCMI_BASE_DISCOVER_LIST_PROTOCOLS] = discover_list_protocols,
+};
+
+static bool message_id_is_supported(unsigned int message_id)
+{
+ return (message_id < ARRAY_SIZE(scmi_base_handler_table)) &&
+ (scmi_base_handler_table[message_id] != NULL);
+}
+
+scmi_msg_handler_t scmi_msg_get_base_handler(struct scmi_msg *msg)
+{
+ const size_t array_size = ARRAY_SIZE(scmi_base_handler_table);
+ unsigned int message_id = 0U;
+
+ if (msg->message_id >= array_size) {
+ VERBOSE("Base handle not found %u\n", msg->message_id);
+ return NULL;
+ }
+
+ message_id = confine_array_index(msg->message_id, array_size);
+
+ return scmi_base_handler_table[message_id];
+}
diff --git a/drivers/st/scmi-msg/base.h b/drivers/st/scmi-msg/base.h
new file mode 100644
index 000000000..689f30a8b
--- /dev/null
+++ b/drivers/st/scmi-msg/base.h
@@ -0,0 +1,75 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * Copyright (c) 2015-2019, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2019, Linaro Limited
+ */
+
+#ifndef SCMI_MSG_BASE_H
+#define SCMI_MSG_BASE_H
+
+#include <stdint.h>
+
+#define SCMI_PROTOCOL_VERSION_BASE 0x20000U
+
+#define SCMI_DEFAULT_STRING_LENGTH 16U
+
+enum scmi_base_message_id {
+ SCMI_BASE_DISCOVER_VENDOR = 0x003,
+ SCMI_BASE_DISCOVER_SUB_VENDOR = 0x004,
+ SCMI_BASE_DISCOVER_IMPLEMENTATION_VERSION = 0x005,
+ SCMI_BASE_DISCOVER_LIST_PROTOCOLS = 0x006,
+ SCMI_BASE_DISCOVER_AGENT = 0x007,
+ SCMI_BASE_NOTIFY_ERRORS = 0x008,
+};
+
+/*
+ * PROTOCOL_ATTRIBUTES
+ */
+
+#define SCMI_BASE_PROTOCOL_ATTRS_NUM_PROTOCOLS_POS 0
+#define SCMI_BASE_PROTOCOL_ATTRS_NUM_AGENTS_POS 8
+
+#define SCMI_BASE_PROTOCOL_ATTRS_NUM_PROTOCOLS_MASK 0xFFU
+#define SCMI_BASE_PROTOCOL_ATTRS_NUM_AGENTS_MASK 0xFF00U
+
+#define SCMI_BASE_PROTOCOL_ATTRIBUTES(NUM_PROTOCOLS, NUM_AGENTS) \
+ ((((NUM_PROTOCOLS) << SCMI_BASE_PROTOCOL_ATTRS_NUM_PROTOCOLS_POS) & \
+ SCMI_BASE_PROTOCOL_ATTRS_NUM_PROTOCOLS_MASK) | \
+ (((NUM_AGENTS) << SCMI_BASE_PROTOCOL_ATTRS_NUM_AGENTS_POS) & \
+ SCMI_BASE_PROTOCOL_ATTRS_NUM_AGENTS_MASK))
+
+/*
+ * BASE_DISCOVER_VENDOR
+ */
+struct scmi_base_discover_vendor_p2a {
+ int32_t status;
+ char vendor_identifier[SCMI_DEFAULT_STRING_LENGTH];
+};
+
+/*
+ * BASE_DISCOVER_SUB_VENDOR
+ */
+struct scmi_base_discover_sub_vendor_p2a {
+ int32_t status;
+ char sub_vendor_identifier[SCMI_DEFAULT_STRING_LENGTH];
+};
+
+/*
+ * BASE_DISCOVER_IMPLEMENTATION_VERSION
+ * No special structure right now, see protocol_version.
+ */
+
+/*
+ * BASE_DISCOVER_LIST_PROTOCOLS
+ */
+struct scmi_base_discover_list_protocols_a2p {
+ uint32_t skip;
+};
+
+struct scmi_base_discover_list_protocols_p2a {
+ int32_t status;
+ uint32_t num_protocols;
+ uint32_t protocols[];
+};
+
+#endif /* SCMI_MSG_BASE_H */
diff --git a/drivers/st/scmi-msg/clock.c b/drivers/st/scmi-msg/clock.c
new file mode 100644
index 000000000..72859cbc9
--- /dev/null
+++ b/drivers/st/scmi-msg/clock.c
@@ -0,0 +1,388 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Copyright (c) 2015-2020, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2019-2020, Linaro Limited
+ */
+#include <cdefs.h>
+#include <string.h>
+
+#include <common/confine_array_index.h>
+#include <drivers/st/scmi-msg.h>
+#include <drivers/st/scmi.h>
+#include <lib/utils_def.h>
+
+#include "common.h"
+
+#pragma weak plat_scmi_clock_count
+#pragma weak plat_scmi_clock_get_name
+#pragma weak plat_scmi_clock_rates_array
+#pragma weak plat_scmi_clock_rates_by_step
+#pragma weak plat_scmi_clock_get_rate
+#pragma weak plat_scmi_clock_set_rate
+#pragma weak plat_scmi_clock_get_state
+#pragma weak plat_scmi_clock_set_state
+
+static bool message_id_is_supported(unsigned int message_id);
+
+size_t plat_scmi_clock_count(unsigned int agent_id __unused)
+{
+ return 0U;
+}
+
+const char *plat_scmi_clock_get_name(unsigned int agent_id __unused,
+ unsigned int scmi_id __unused)
+{
+ return NULL;
+}
+
+int32_t plat_scmi_clock_rates_array(unsigned int agent_id __unused,
+ unsigned int scmi_id __unused,
+ unsigned long *rates __unused,
+ size_t *nb_elts __unused)
+{
+ return SCMI_NOT_SUPPORTED;
+}
+
+int32_t plat_scmi_clock_rates_by_step(unsigned int agent_id __unused,
+ unsigned int scmi_id __unused,
+ unsigned long *steps __unused)
+{
+ return SCMI_NOT_SUPPORTED;
+}
+
+unsigned long plat_scmi_clock_get_rate(unsigned int agent_id __unused,
+ unsigned int scmi_id __unused)
+{
+ return 0U;
+}
+
+int32_t plat_scmi_clock_set_rate(unsigned int agent_id __unused,
+ unsigned int scmi_id __unused,
+ unsigned long rate __unused)
+{
+ return SCMI_NOT_SUPPORTED;
+}
+
+int32_t plat_scmi_clock_get_state(unsigned int agent_id __unused,
+ unsigned int scmi_id __unused)
+{
+ return SCMI_NOT_SUPPORTED;
+}
+
+int32_t plat_scmi_clock_set_state(unsigned int agent_id __unused,
+ unsigned int scmi_id __unused,
+ bool enable_not_disable __unused)
+{
+ return SCMI_NOT_SUPPORTED;
+}
+
+static void report_version(struct scmi_msg *msg)
+{
+ struct scmi_protocol_version_p2a return_values = {
+ .status = SCMI_SUCCESS,
+ .version = SCMI_PROTOCOL_VERSION_CLOCK,
+ };
+
+ if (msg->in_size != 0) {
+ scmi_status_response(msg, SCMI_PROTOCOL_ERROR);
+ return;
+ }
+
+ scmi_write_response(msg, &return_values, sizeof(return_values));
+}
+
+static void report_attributes(struct scmi_msg *msg)
+{
+ size_t agent_count = plat_scmi_clock_count(msg->agent_id);
+ struct scmi_protocol_attributes_p2a return_values = {
+ .status = SCMI_SUCCESS,
+ .attributes = SCMI_CLOCK_PROTOCOL_ATTRIBUTES(1U, agent_count),
+ };
+
+ if (msg->in_size != 0) {
+ scmi_status_response(msg, SCMI_PROTOCOL_ERROR);
+ return;
+ }
+
+ scmi_write_response(msg, &return_values, sizeof(return_values));
+}
+
+static void report_message_attributes(struct scmi_msg *msg)
+{
+ struct scmi_protocol_message_attributes_a2p *in_args = (void *)msg->in;
+ struct scmi_protocol_message_attributes_p2a return_values = {
+ .status = SCMI_SUCCESS,
+ /* For this protocol, attributes shall be zero */
+ .attributes = 0U,
+ };
+
+ if (msg->in_size != sizeof(*in_args)) {
+ scmi_status_response(msg, SCMI_PROTOCOL_ERROR);
+ return;
+ }
+
+ if (!message_id_is_supported(in_args->message_id)) {
+ scmi_status_response(msg, SCMI_NOT_FOUND);
+ return;
+ }
+
+ scmi_write_response(msg, &return_values, sizeof(return_values));
+}
+
+static void scmi_clock_attributes(struct scmi_msg *msg)
+{
+ const struct scmi_clock_attributes_a2p *in_args = (void *)msg->in;
+ struct scmi_clock_attributes_p2a return_values = {
+ .status = SCMI_SUCCESS,
+ };
+ const char *name = NULL;
+ unsigned int clock_id = 0U;
+
+ if (msg->in_size != sizeof(*in_args)) {
+ scmi_status_response(msg, SCMI_PROTOCOL_ERROR);
+ return;
+ }
+
+ if (in_args->clock_id >= plat_scmi_clock_count(msg->agent_id)) {
+ scmi_status_response(msg, SCMI_INVALID_PARAMETERS);
+ return;
+ }
+
+ clock_id = confine_array_index(in_args->clock_id,
+ plat_scmi_clock_count(msg->agent_id));
+
+ name = plat_scmi_clock_get_name(msg->agent_id, clock_id);
+ if (name == NULL) {
+ scmi_status_response(msg, SCMI_NOT_FOUND);
+ return;
+ }
+
+ COPY_NAME_IDENTIFIER(return_values.clock_name, name);
+
+ return_values.attributes = plat_scmi_clock_get_state(msg->agent_id,
+ clock_id);
+
+ scmi_write_response(msg, &return_values, sizeof(return_values));
+}
+
+static void scmi_clock_rate_get(struct scmi_msg *msg)
+{
+ const struct scmi_clock_rate_get_a2p *in_args = (void *)msg->in;
+ unsigned long rate = 0U;
+ struct scmi_clock_rate_get_p2a return_values = {
+ .status = SCMI_SUCCESS,
+ };
+ unsigned int clock_id = 0U;
+
+ if (msg->in_size != sizeof(*in_args)) {
+ scmi_status_response(msg, SCMI_PROTOCOL_ERROR);
+ return;
+ }
+
+ if (in_args->clock_id >= plat_scmi_clock_count(msg->agent_id)) {
+ scmi_status_response(msg, SCMI_INVALID_PARAMETERS);
+ return;
+ }
+
+ clock_id = confine_array_index(in_args->clock_id,
+ plat_scmi_clock_count(msg->agent_id));
+
+ rate = plat_scmi_clock_get_rate(msg->agent_id, clock_id);
+
+ return_values.rate[0] = (uint32_t)rate;
+ return_values.rate[1] = (uint32_t)((uint64_t)rate >> 32);
+
+ scmi_write_response(msg, &return_values, sizeof(return_values));
+}
+
+static void scmi_clock_rate_set(struct scmi_msg *msg)
+{
+ const struct scmi_clock_rate_set_a2p *in_args = (void *)msg->in;
+ unsigned long rate = 0U;
+ int32_t status = 0;
+ unsigned int clock_id = 0U;
+
+ if (msg->in_size != sizeof(*in_args)) {
+ scmi_status_response(msg, SCMI_PROTOCOL_ERROR);
+ return;
+ }
+
+ if (in_args->clock_id >= plat_scmi_clock_count(msg->agent_id)) {
+ scmi_status_response(msg, SCMI_INVALID_PARAMETERS);
+ return;
+ }
+
+ clock_id = confine_array_index(in_args->clock_id,
+ plat_scmi_clock_count(msg->agent_id));
+
+ rate = (unsigned long)(((uint64_t)in_args->rate[1] << 32) |
+ in_args->rate[0]);
+
+ status = plat_scmi_clock_set_rate(msg->agent_id, clock_id, rate);
+
+ scmi_status_response(msg, status);
+}
+
+static void scmi_clock_config_set(struct scmi_msg *msg)
+{
+ const struct scmi_clock_config_set_a2p *in_args = (void *)msg->in;
+ int32_t status = SCMI_GENERIC_ERROR;
+ bool enable = false;
+ unsigned int clock_id = 0U;
+
+ if (msg->in_size != sizeof(*in_args)) {
+ scmi_status_response(msg, SCMI_PROTOCOL_ERROR);
+ return;
+ }
+
+ if (in_args->clock_id >= plat_scmi_clock_count(msg->agent_id)) {
+ scmi_status_response(msg, SCMI_INVALID_PARAMETERS);
+ return;
+ }
+
+ clock_id = confine_array_index(in_args->clock_id,
+ plat_scmi_clock_count(msg->agent_id));
+
+ enable = in_args->attributes & SCMI_CLOCK_CONFIG_SET_ENABLE_MASK;
+
+ status = plat_scmi_clock_set_state(msg->agent_id, clock_id, enable);
+
+ scmi_status_response(msg, status);
+}
+
+#define RATES_ARRAY_SIZE_MAX (SCMI_PLAYLOAD_MAX - \
+ sizeof(struct scmi_clock_describe_rates_p2a))
+
+#define SCMI_RATES_BY_ARRAY(_nb_rates, _rem_rates) \
+ SCMI_CLOCK_DESCRIBE_RATES_NUM_RATES_FLAGS((_nb_rates), \
+ SCMI_CLOCK_RATE_FORMAT_LIST, \
+ (_rem_rates))
+#define SCMI_RATES_BY_STEP \
+ SCMI_CLOCK_DESCRIBE_RATES_NUM_RATES_FLAGS(3U, \
+ SCMI_CLOCK_RATE_FORMAT_RANGE, \
+ 0U)
+
+#define RATE_DESC_SIZE sizeof(struct scmi_clock_rate)
+
+static void write_rate_desc_array_in_buffer(char *dest, unsigned long *rates,
+ size_t nb_elt)
+{
+ uint32_t *out = (uint32_t *)(uintptr_t)dest;
+ size_t n;
+
+ ASSERT_SYM_PTR_ALIGN(out);
+
+ for (n = 0U; n < nb_elt; n++) {
+ out[2 * n] = (uint32_t)rates[n];
+ out[2 * n + 1] = (uint32_t)((uint64_t)rates[n] >> 32);
+ }
+}
+
+static void scmi_clock_describe_rates(struct scmi_msg *msg)
+{
+ const struct scmi_clock_describe_rates_a2p *in_args = (void *)msg->in;
+ struct scmi_clock_describe_rates_p2a p2a = {
+ .status = SCMI_SUCCESS,
+ };
+ size_t nb_rates;
+ int32_t status;
+ unsigned int clock_id;
+
+ if (msg->in_size != sizeof(*in_args)) {
+ scmi_status_response(msg, SCMI_PROTOCOL_ERROR);
+ return;
+ }
+
+ if (in_args->clock_id >= plat_scmi_clock_count(msg->agent_id)) {
+ scmi_status_response(msg, SCMI_INVALID_PARAMETERS);
+ return;
+ }
+
+ clock_id = confine_array_index(in_args->clock_id,
+ plat_scmi_clock_count(msg->agent_id));
+
+ /* Platform may support array rate description */
+ status = plat_scmi_clock_rates_array(msg->agent_id, clock_id, NULL,
+ &nb_rates);
+ if (status == SCMI_SUCCESS) {
+ /* Currently 12 cells mex, so it's affordable for the stack */
+ unsigned long plat_rates[RATES_ARRAY_SIZE_MAX / RATE_DESC_SIZE];
+ size_t max_nb = RATES_ARRAY_SIZE_MAX / RATE_DESC_SIZE;
+ size_t ret_nb = MIN(nb_rates - in_args->rate_index, max_nb);
+ size_t rem_nb = nb_rates - in_args->rate_index - ret_nb;
+
+ status = plat_scmi_clock_rates_array(msg->agent_id, clock_id,
+ plat_rates, &ret_nb);
+ if (status == SCMI_SUCCESS) {
+ write_rate_desc_array_in_buffer(msg->out + sizeof(p2a),
+ plat_rates, ret_nb);
+
+ p2a.num_rates_flags = SCMI_RATES_BY_ARRAY(ret_nb,
+ rem_nb);
+ p2a.status = SCMI_SUCCESS;
+
+ memcpy(msg->out, &p2a, sizeof(p2a));
+ msg->out_size_out = sizeof(p2a) +
+ ret_nb * RATE_DESC_SIZE;
+ }
+ } else if (status == SCMI_NOT_SUPPORTED) {
+ unsigned long triplet[3] = { 0U, 0U, 0U };
+
+ /* Platform may support min§max/step triplet description */
+ status = plat_scmi_clock_rates_by_step(msg->agent_id, clock_id,
+ triplet);
+ if (status == SCMI_SUCCESS) {
+ write_rate_desc_array_in_buffer(msg->out + sizeof(p2a),
+ triplet, 3U);
+
+ p2a.num_rates_flags = SCMI_RATES_BY_STEP;
+ p2a.status = SCMI_SUCCESS;
+
+ memcpy(msg->out, &p2a, sizeof(p2a));
+ msg->out_size_out = sizeof(p2a) + (3U * RATE_DESC_SIZE);
+ }
+ } else {
+ /* Fallthrough generic exit sequence below with error status */
+ }
+
+ if (status != SCMI_SUCCESS) {
+ scmi_status_response(msg, status);
+ } else {
+ /*
+ * Message payload is already writen to msg->out, and
+ * msg->out_size_out updated.
+ */
+ }
+}
+
+static const scmi_msg_handler_t scmi_clock_handler_table[] = {
+ [SCMI_PROTOCOL_VERSION] = report_version,
+ [SCMI_PROTOCOL_ATTRIBUTES] = report_attributes,
+ [SCMI_PROTOCOL_MESSAGE_ATTRIBUTES] = report_message_attributes,
+ [SCMI_CLOCK_ATTRIBUTES] = scmi_clock_attributes,
+ [SCMI_CLOCK_DESCRIBE_RATES] = scmi_clock_describe_rates,
+ [SCMI_CLOCK_RATE_SET] = scmi_clock_rate_set,
+ [SCMI_CLOCK_RATE_GET] = scmi_clock_rate_get,
+ [SCMI_CLOCK_CONFIG_SET] = scmi_clock_config_set,
+};
+
+static bool message_id_is_supported(size_t message_id)
+{
+ return (message_id < ARRAY_SIZE(scmi_clock_handler_table)) &&
+ (scmi_clock_handler_table[message_id] != NULL);
+}
+
+scmi_msg_handler_t scmi_msg_get_clock_handler(struct scmi_msg *msg)
+{
+ const size_t array_size = ARRAY_SIZE(scmi_clock_handler_table);
+ unsigned int message_id = 0U;
+
+ if (msg->message_id >= array_size) {
+ VERBOSE("Clock handle not found %u", msg->message_id);
+ return NULL;
+ }
+
+ message_id = confine_array_index(msg->message_id, array_size);
+
+ return scmi_clock_handler_table[message_id];
+}
diff --git a/drivers/st/scmi-msg/clock.h b/drivers/st/scmi-msg/clock.h
new file mode 100644
index 000000000..a637934ee
--- /dev/null
+++ b/drivers/st/scmi-msg/clock.h
@@ -0,0 +1,150 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * Copyright (c) 2015-2019, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2019, Linaro Limited
+ */
+
+#ifndef SCMI_MSG_CLOCK_H
+#define SCMI_MSG_CLOCK_H
+
+#include <stdint.h>
+
+#include <lib/utils_def.h>
+
+#define SCMI_PROTOCOL_VERSION_CLOCK 0x20000U
+
+/*
+ * Identifiers of the SCMI Clock Management Protocol commands
+ */
+enum scmi_clock_command_id {
+ SCMI_CLOCK_ATTRIBUTES = 0x003,
+ SCMI_CLOCK_DESCRIBE_RATES = 0x004,
+ SCMI_CLOCK_RATE_SET = 0x005,
+ SCMI_CLOCK_RATE_GET = 0x006,
+ SCMI_CLOCK_CONFIG_SET = 0x007,
+};
+
+/* Protocol attributes */
+#define SCMI_CLOCK_CLOCK_COUNT_MASK GENMASK(15, 0)
+#define SCMI_CLOCK_MAX_PENDING_TRANSITIONS_MASK GENMASK(23, 16)
+
+#define SCMI_CLOCK_PROTOCOL_ATTRIBUTES(_max_pending, _clk_count) \
+ ((((_max_pending) << 16) & SCMI_CLOCK_MAX_PENDING_TRANSITIONS_MASK) | \
+ (((_clk_count) & SCMI_CLOCK_CLOCK_COUNT_MASK)))
+
+struct scmi_clock_attributes_a2p {
+ uint32_t clock_id;
+};
+
+#define SCMI_CLOCK_NAME_LENGTH_MAX 16U
+
+struct scmi_clock_attributes_p2a {
+ int32_t status;
+ uint32_t attributes;
+ char clock_name[SCMI_CLOCK_NAME_LENGTH_MAX];
+};
+
+/*
+ * Clock Rate Get
+ */
+
+struct scmi_clock_rate_get_a2p {
+ uint32_t clock_id;
+};
+
+struct scmi_clock_rate_get_p2a {
+ int32_t status;
+ uint32_t rate[2];
+};
+
+/*
+ * Clock Rate Set
+ */
+
+/* If set, set the new clock rate asynchronously */
+#define SCMI_CLOCK_RATE_SET_ASYNC_POS 0
+/* If set, do not send a delayed asynchronous response */
+#define SCMI_CLOCK_RATE_SET_NO_DELAYED_RESPONSE_POS 1
+/* Round up, if set, otherwise round down */
+#define SCMI_CLOCK_RATE_SET_ROUND_UP_POS 2
+/* If set, the platform chooses the appropriate rounding mode */
+#define SCMI_CLOCK_RATE_SET_ROUND_AUTO_POS 3
+
+#define SCMI_CLOCK_RATE_SET_ASYNC_MASK \
+ BIT(SCMI_CLOCK_RATE_SET_ASYNC_POS)
+#define SCMI_CLOCK_RATE_SET_NO_DELAYED_RESPONSE_MASK \
+ BIT(SCMI_CLOCK_RATE_SET_NO_DELAYED_RESPONSE_POS)
+#define SCMI_CLOCK_RATE_SET_ROUND_UP_MASK \
+ BIT(SCMI_CLOCK_RATE_SET_ROUND_UP_POS)
+#define SCMI_CLOCK_RATE_SET_ROUND_AUTO_MASK \
+ BIT(SCMI_CLOCK_RATE_SET_ROUND_AUTO_POS)
+
+struct scmi_clock_rate_set_a2p {
+ uint32_t flags;
+ uint32_t clock_id;
+ uint32_t rate[2];
+};
+
+struct scmi_clock_rate_set_p2a {
+ int32_t status;
+};
+
+/*
+ * Clock Config Set
+ */
+
+#define SCMI_CLOCK_CONFIG_SET_ENABLE_POS 0
+
+#define SCMI_CLOCK_CONFIG_SET_ENABLE_MASK \
+ BIT(SCMI_CLOCK_CONFIG_SET_ENABLE_POS)
+
+struct scmi_clock_config_set_a2p {
+ uint32_t clock_id;
+ uint32_t attributes;
+};
+
+struct scmi_clock_config_set_p2a {
+ int32_t status;
+};
+
+/*
+ * Clock Describe Rates
+ */
+
+#define SCMI_CLOCK_RATE_FORMAT_RANGE 1U
+#define SCMI_CLOCK_RATE_FORMAT_LIST 0U
+
+#define SCMI_CLOCK_DESCRIBE_RATES_REMAINING_MASK GENMASK_32(31, 16)
+#define SCMI_CLOCK_DESCRIBE_RATES_REMAINING_POS 16
+
+#define SCMI_CLOCK_DESCRIBE_RATES_FORMAT_MASK BIT(12)
+#define SCMI_CLOCK_DESCRIBE_RATES_FORMAT_POS 12
+
+#define SCMI_CLOCK_DESCRIBE_RATES_COUNT_MASK GENMASK_32(11, 0)
+
+#define SCMI_CLOCK_DESCRIBE_RATES_NUM_RATES_FLAGS(_count, _fmt, _rem_rates) \
+ ( \
+ ((_count) & SCMI_CLOCK_DESCRIBE_RATES_COUNT_MASK) | \
+ (((_rem_rates) << SCMI_CLOCK_DESCRIBE_RATES_REMAINING_POS) & \
+ SCMI_CLOCK_DESCRIBE_RATES_REMAINING_MASK) | \
+ (((_fmt) << SCMI_CLOCK_DESCRIBE_RATES_FORMAT_POS) & \
+ SCMI_CLOCK_DESCRIBE_RATES_FORMAT_MASK) \
+ )
+
+struct scmi_clock_rate {
+ uint32_t low;
+ uint32_t high;
+};
+
+struct scmi_clock_describe_rates_a2p {
+ uint32_t clock_id;
+ uint32_t rate_index;
+};
+
+struct scmi_clock_describe_rates_p2a {
+ int32_t status;
+ uint32_t num_rates_flags;
+ struct scmi_clock_rate rates[];
+};
+
+#endif /* SCMI_MSG_CLOCK_H */
diff --git a/drivers/st/scmi-msg/common.h b/drivers/st/scmi-msg/common.h
new file mode 100644
index 000000000..bf073418f
--- /dev/null
+++ b/drivers/st/scmi-msg/common.h
@@ -0,0 +1,136 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * Copyright (c) 2015-2019, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2019, Linaro Limited
+ */
+#ifndef SCMI_MSG_COMMON_H
+#define SCMI_MSG_COMMON_H
+
+#include <assert.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <string.h>
+
+#include "base.h"
+#include "clock.h"
+#include "reset_domain.h"
+
+#define SCMI_VERSION 0x20000U
+#define SCMI_IMPL_VERSION 0U
+
+#define SCMI_PLAYLOAD_MAX 92U
+
+/*
+ * Copy name identifier in target buffer following the SCMI specification
+ * that state name identifier shall be a null terminated string.
+ */
+#define COPY_NAME_IDENTIFIER(_dst_array, _name) \
+ do { \
+ assert(strlen(_name) < sizeof(_dst_array)); \
+ strlcpy((_dst_array), (_name), sizeof(_dst_array)); \
+ } while (0)
+
+/* Common command identifiers shared by all procotols */
+enum scmi_common_message_id {
+ SCMI_PROTOCOL_VERSION = 0x000,
+ SCMI_PROTOCOL_ATTRIBUTES = 0x001,
+ SCMI_PROTOCOL_MESSAGE_ATTRIBUTES = 0x002
+};
+
+/* Common platform-to-agent (p2a) PROTOCOL_VERSION structure */
+struct scmi_protocol_version_p2a {
+ int32_t status;
+ uint32_t version;
+};
+
+/* Generic platform-to-agent (p2a) PROTOCOL_ATTRIBUTES structure */
+struct scmi_protocol_attributes_p2a {
+ int32_t status;
+ uint32_t attributes;
+};
+
+/* Generic agent-to-platform (a2p) PROTOCOL_MESSAGE_ATTRIBUTES structure */
+struct scmi_protocol_message_attributes_a2p {
+ uint32_t message_id;
+};
+
+/* Generic platform-to-agent (p2a) PROTOCOL_MESSAGE_ATTRIBUTES structure */
+struct scmi_protocol_message_attributes_p2a {
+ int32_t status;
+ uint32_t attributes;
+};
+
+/*
+ * struct scmi_msg - SCMI message context
+ *
+ * @agent_id: SCMI agent ID, safely set from secure world
+ * @protocol_id: SCMI protocol ID for the related message, set by caller agent
+ * @message_id: SCMI message ID for the related message, set by caller agent
+ * @in: Address of the incoming message payload copied in secure memory
+ * @in_size: Byte length of the incoming message payload, set by caller agent
+ * @out: Address of of the output message payload message in non-secure memory
+ * @out_size: Byte length of the provisionned output buffer
+ * @out_size_out: Byte length of the output message payload
+ */
+struct scmi_msg {
+ unsigned int agent_id;
+ unsigned int protocol_id;
+ unsigned int message_id;
+ char *in;
+ size_t in_size;
+ char *out;
+ size_t out_size;
+ size_t out_size_out;
+};
+
+/*
+ * Type scmi_msg_handler_t is used by procotol drivers to safely find
+ * the handler function for the incoming message ID.
+ */
+typedef void (*scmi_msg_handler_t)(struct scmi_msg *msg);
+
+/*
+ * scmi_msg_get_base_handler - Return a handler for a base message
+ * @msg - message to process
+ * Return a function handler for the message or NULL
+ */
+scmi_msg_handler_t scmi_msg_get_base_handler(struct scmi_msg *msg);
+
+/*
+ * scmi_msg_get_clock_handler - Return a handler for a clock message
+ * @msg - message to process
+ * Return a function handler for the message or NULL
+ */
+scmi_msg_handler_t scmi_msg_get_clock_handler(struct scmi_msg *msg);
+
+/*
+ * scmi_msg_get_rd_handler - Return a handler for a reset domain message
+ * @msg - message to process
+ * Return a function handler for the message or NULL
+ */
+scmi_msg_handler_t scmi_msg_get_rd_handler(struct scmi_msg *msg);
+
+/*
+ * Process Read, process and write response for input SCMI message
+ *
+ * @msg: SCMI message context
+ */
+void scmi_process_message(struct scmi_msg *msg);
+
+/*
+ * Write SCMI response payload to output message shared memory
+ *
+ * @msg: SCMI message context
+ * @payload: Output message payload
+ * @size: Byte size of output message payload
+ */
+void scmi_write_response(struct scmi_msg *msg, void *payload, size_t size);
+
+/*
+ * Write status only SCMI response payload to output message shared memory
+ *
+ * @msg: SCMI message context
+ * @status: SCMI status value returned to caller
+ */
+void scmi_status_response(struct scmi_msg *msg, int32_t status);
+#endif /* SCMI_MSG_COMMON_H */
diff --git a/drivers/st/scmi-msg/entry.c b/drivers/st/scmi-msg/entry.c
new file mode 100644
index 000000000..ae1384e2b
--- /dev/null
+++ b/drivers/st/scmi-msg/entry.c
@@ -0,0 +1,63 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Copyright (c) 2015-2020, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2019-2020, Linaro Limited
+ */
+
+#include <assert.h>
+
+#include <drivers/st/scmi-msg.h>
+#include <drivers/st/scmi.h>
+
+#include "common.h"
+
+void scmi_status_response(struct scmi_msg *msg, int32_t status)
+{
+ assert(msg->out && msg->out_size >= sizeof(int32_t));
+
+ memcpy(msg->out, &status, sizeof(int32_t));
+ msg->out_size_out = sizeof(int32_t);
+}
+
+void scmi_write_response(struct scmi_msg *msg, void *payload, size_t size)
+{
+ /*
+ * Output payload shall be at least the size of the status
+ * Output buffer shall be at least be the size of the status
+ * Output paylaod shall fit in output buffer
+ */
+ assert(payload && size >= sizeof(int32_t) && size <= msg->out_size &&
+ msg->out && msg->out_size >= sizeof(int32_t));
+
+ memcpy(msg->out, payload, size);
+ msg->out_size_out = size;
+}
+
+void scmi_process_message(struct scmi_msg *msg)
+{
+ scmi_msg_handler_t handler = NULL;
+
+ switch (msg->protocol_id) {
+ case SCMI_PROTOCOL_ID_BASE:
+ handler = scmi_msg_get_base_handler(msg);
+ break;
+ case SCMI_PROTOCOL_ID_CLOCK:
+ handler = scmi_msg_get_clock_handler(msg);
+ break;
+ case SCMI_PROTOCOL_ID_RESET_DOMAIN:
+ handler = scmi_msg_get_rd_handler(msg);
+ break;
+ default:
+ break;
+ }
+
+ if (handler) {
+ handler(msg);
+ return;
+ }
+
+ ERROR("Agent %u Protocol 0x%x Message 0x%x: not supported",
+ msg->agent_id, msg->protocol_id, msg->message_id);
+
+ scmi_status_response(msg, SCMI_NOT_SUPPORTED);
+}
diff --git a/drivers/st/scmi-msg/reset_domain.c b/drivers/st/scmi-msg/reset_domain.c
new file mode 100644
index 000000000..23e205b7a
--- /dev/null
+++ b/drivers/st/scmi-msg/reset_domain.c
@@ -0,0 +1,202 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Copyright (c) 2015-2020, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2019-2020, Linaro Limited
+ */
+#include <cdefs.h>
+#include <string.h>
+
+#include <common/confine_array_index.h>
+#include <drivers/st/scmi-msg.h>
+#include <drivers/st/scmi.h>
+#include <lib/utils.h>
+#include <lib/utils_def.h>
+
+#include "common.h"
+
+static bool message_id_is_supported(unsigned int message_id);
+
+#pragma weak plat_scmi_rd_count
+#pragma weak plat_scmi_rd_get_name
+#pragma weak plat_scmi_rd_autonomous
+#pragma weak plat_scmi_rd_set_state
+
+size_t plat_scmi_rd_count(unsigned int agent_id __unused)
+{
+ return 0U;
+}
+
+const char *plat_scmi_rd_get_name(unsigned int agent_id __unused,
+ unsigned int scmi_id __unused)
+{
+ return NULL;
+}
+
+int32_t plat_scmi_rd_autonomous(unsigned int agent_id __unused,
+ unsigned int scmi_id __unused,
+ unsigned int state __unused)
+{
+ return SCMI_NOT_SUPPORTED;
+}
+
+int32_t plat_scmi_rd_set_state(unsigned int agent_id __unused,
+ unsigned int scmi_id __unused,
+ bool assert_not_deassert __unused)
+{
+ return SCMI_NOT_SUPPORTED;
+}
+
+static void report_version(struct scmi_msg *msg)
+{
+ struct scmi_protocol_version_p2a return_values = {
+ .status = SCMI_SUCCESS,
+ .version = SCMI_PROTOCOL_VERSION_RESET_DOMAIN,
+ };
+
+ if (msg->in_size != 0U) {
+ scmi_status_response(msg, SCMI_PROTOCOL_ERROR);
+ return;
+ }
+
+ scmi_write_response(msg, &return_values, sizeof(return_values));
+}
+
+static void report_attributes(struct scmi_msg *msg)
+{
+ struct scmi_protocol_attributes_p2a return_values = {
+ .status = SCMI_SUCCESS,
+ .attributes = plat_scmi_rd_count(msg->agent_id),
+ };
+
+ if (msg->in_size != 0U) {
+ scmi_status_response(msg, SCMI_PROTOCOL_ERROR);
+ return;
+ }
+
+ scmi_write_response(msg, &return_values, sizeof(return_values));
+}
+
+static void report_message_attributes(struct scmi_msg *msg)
+{
+ struct scmi_protocol_message_attributes_a2p *in_args = (void *)msg->in;
+ struct scmi_protocol_message_attributes_p2a return_values = {
+ .status = SCMI_SUCCESS,
+ .attributes = 0U,
+ };
+
+ if (msg->in_size != sizeof(*in_args)) {
+ scmi_status_response(msg, SCMI_PROTOCOL_ERROR);
+ return;
+ }
+
+ if (!message_id_is_supported(in_args->message_id)) {
+ scmi_status_response(msg, SCMI_NOT_FOUND);
+ return;
+ }
+
+ scmi_write_response(msg, &return_values, sizeof(return_values));
+}
+
+static void reset_domain_attributes(struct scmi_msg *msg)
+{
+ struct scmi_reset_domain_attributes_a2p *in_args = (void *)msg->in;
+ struct scmi_reset_domain_attributes_p2a return_values;
+ const char *name = NULL;
+ unsigned int domain_id = 0U;
+
+ if (msg->in_size != sizeof(*in_args)) {
+ scmi_status_response(msg, SCMI_PROTOCOL_ERROR);
+ return;
+ }
+
+ if (in_args->domain_id >= plat_scmi_rd_count(msg->agent_id)) {
+ scmi_status_response(msg, SCMI_INVALID_PARAMETERS);
+ return;
+ }
+
+ domain_id = confine_array_index(in_args->domain_id,
+ plat_scmi_rd_count(msg->agent_id));
+
+ name = plat_scmi_rd_get_name(msg->agent_id, domain_id);
+ if (name == NULL) {
+ scmi_status_response(msg, SCMI_NOT_FOUND);
+ return;
+ }
+
+ zeromem(&return_values, sizeof(return_values));
+ return_values.status = SCMI_SUCCESS;
+ return_values.flags = 0U; /* Async and Notif are not supported */
+ return_values.latency = SCMI_RESET_DOMAIN_ATTR_UNK_LAT;
+ COPY_NAME_IDENTIFIER(return_values.name, name);
+
+ scmi_write_response(msg, &return_values, sizeof(return_values));
+}
+
+static void reset_request(struct scmi_msg *msg)
+{
+ struct scmi_reset_domain_request_a2p *in_args = (void *)msg->in;
+ struct scmi_reset_domain_request_p2a out_args = {
+ .status = SCMI_SUCCESS,
+ };
+ unsigned int domain_id = 0U;
+
+ domain_id = confine_array_index(in_args->domain_id,
+ plat_scmi_rd_count(msg->agent_id));
+
+ if (msg->in_size != sizeof(*in_args)) {
+ scmi_status_response(msg, SCMI_PROTOCOL_ERROR);
+ return;
+ }
+
+ if (in_args->domain_id >= plat_scmi_rd_count(msg->agent_id)) {
+ scmi_status_response(msg, SCMI_NOT_FOUND);
+ return;
+ }
+
+ if ((in_args->flags & SCMI_RESET_DOMAIN_AUTO) != 0U) {
+ out_args.status = plat_scmi_rd_autonomous(msg->agent_id,
+ domain_id,
+ in_args->reset_state);
+ } else if ((in_args->flags & SCMI_RESET_DOMAIN_EXPLICIT) != 0U) {
+ out_args.status = plat_scmi_rd_set_state(msg->agent_id,
+ domain_id, true);
+ } else {
+ out_args.status = plat_scmi_rd_set_state(msg->agent_id,
+ domain_id, false);
+ }
+
+ if (out_args.status != SCMI_SUCCESS) {
+ scmi_status_response(msg, out_args.status);
+ } else {
+ scmi_write_response(msg, &out_args, sizeof(out_args));
+ }
+}
+
+static const scmi_msg_handler_t scmi_rd_handler_table[] = {
+ [SCMI_PROTOCOL_VERSION] = report_version,
+ [SCMI_PROTOCOL_ATTRIBUTES] = report_attributes,
+ [SCMI_PROTOCOL_MESSAGE_ATTRIBUTES] = report_message_attributes,
+ [SCMI_RESET_DOMAIN_ATTRIBUTES] = reset_domain_attributes,
+ [SCMI_RESET_DOMAIN_REQUEST] = reset_request,
+};
+
+static bool message_id_is_supported(unsigned int message_id)
+{
+ return (message_id < ARRAY_SIZE(scmi_rd_handler_table)) &&
+ (scmi_rd_handler_table[message_id] != NULL);
+}
+
+scmi_msg_handler_t scmi_msg_get_rd_handler(struct scmi_msg *msg)
+{
+ const size_t array_size = ARRAY_SIZE(scmi_rd_handler_table);
+ unsigned int message_id = 0U;
+
+ if (msg->message_id >= array_size) {
+ VERBOSE("Reset domain handle not found %u\n", msg->message_id);
+ return NULL;
+ }
+
+ message_id = confine_array_index(msg->message_id, array_size);
+
+ return scmi_rd_handler_table[message_id];
+}
diff --git a/drivers/st/scmi-msg/reset_domain.h b/drivers/st/scmi-msg/reset_domain.h
new file mode 100644
index 000000000..47bee5e39
--- /dev/null
+++ b/drivers/st/scmi-msg/reset_domain.h
@@ -0,0 +1,122 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * Copyright (c) 2015-2019, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2019, Linaro Limited
+ */
+#ifndef SCMI_MSG_RESET_DOMAIN_H
+#define SCMI_MSG_RESET_DOMAIN_H
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#include <lib/utils_def.h>
+
+#define SCMI_PROTOCOL_VERSION_RESET_DOMAIN 0x10000U
+
+#define SCMI_RESET_STATE_ARCH BIT(31)
+#define SCMI_RESET_STATE_IMPL 0U
+
+/*
+ * Identifiers of the SCMI Reset Domain Management Protocol commands
+ */
+enum scmi_reset_domain_command_id {
+ SCMI_RESET_DOMAIN_ATTRIBUTES = 0x03,
+ SCMI_RESET_DOMAIN_REQUEST = 0x04,
+ SCMI_RESET_DOMAIN_NOTIFY = 0x05,
+};
+
+/*
+ * Identifiers of the SCMI Reset Domain Management Protocol responses
+ */
+enum scmi_reset_domain_response_id {
+ SCMI_RESET_ISSUED = 0x00,
+ SCMI_RESET_COMPLETE = 0x04,
+};
+
+/*
+ * PROTOCOL_ATTRIBUTES
+ */
+
+#define SCMI_RESET_DOMAIN_COUNT_MASK GENMASK_32(15, 0)
+
+struct scmi_reset_domain_protocol_attributes_p2a {
+ int32_t status;
+ uint32_t attributes;
+};
+
+/* Value for scmi_reset_domain_attributes_p2a:flags */
+#define SCMI_RESET_DOMAIN_ATTR_ASYNC BIT(31)
+#define SCMI_RESET_DOMAIN_ATTR_NOTIF BIT(30)
+
+/* Value for scmi_reset_domain_attributes_p2a:latency */
+#define SCMI_RESET_DOMAIN_ATTR_UNK_LAT 0x7fffffffU
+#define SCMI_RESET_DOMAIN_ATTR_MAX_LAT 0x7ffffffeU
+
+/* Macro for scmi_reset_domain_attributes_p2a:name */
+#define SCMI_RESET_DOMAIN_ATTR_NAME_SZ 16U
+
+struct scmi_reset_domain_attributes_a2p {
+ uint32_t domain_id;
+};
+
+struct scmi_reset_domain_attributes_p2a {
+ int32_t status;
+ uint32_t flags;
+ uint32_t latency;
+ char name[SCMI_RESET_DOMAIN_ATTR_NAME_SZ];
+};
+
+/*
+ * RESET
+ */
+
+/* Values for scmi_reset_domain_request_a2p:flags */
+#define SCMI_RESET_DOMAIN_ASYNC BIT(2)
+#define SCMI_RESET_DOMAIN_EXPLICIT BIT(1)
+#define SCMI_RESET_DOMAIN_AUTO BIT(0)
+
+struct scmi_reset_domain_request_a2p {
+ uint32_t domain_id;
+ uint32_t flags;
+ uint32_t reset_state;
+};
+
+struct scmi_reset_domain_request_p2a {
+ int32_t status;
+};
+
+/*
+ * RESET_NOTIFY
+ */
+
+/* Values for scmi_reset_notify_p2a:flags */
+#define SCMI_RESET_DOMAIN_DO_NOTIFY BIT(0)
+
+struct scmi_reset_domain_notify_a2p {
+ uint32_t domain_id;
+ uint32_t notify_enable;
+};
+
+struct scmi_reset_domain_notify_p2a {
+ int32_t status;
+};
+
+/*
+ * RESET_COMPLETE
+ */
+
+struct scmi_reset_domain_complete_p2a {
+ int32_t status;
+ uint32_t domain_id;
+};
+
+/*
+ * RESET_ISSUED
+ */
+
+struct scmi_reset_domain_issued_p2a {
+ uint32_t domain_id;
+ uint32_t reset_state;
+};
+
+#endif /* SCMI_MSG_RESET_DOMAIN_H */
diff --git a/drivers/st/scmi-msg/smt.c b/drivers/st/scmi-msg/smt.c
new file mode 100644
index 000000000..9a0502a08
--- /dev/null
+++ b/drivers/st/scmi-msg/smt.c
@@ -0,0 +1,206 @@
+// SPDX-License-Identifier: BSD-2-Clause
+/*
+ * Copyright (c) 2015-2019, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2019-2020, Linaro Limited
+ */
+#include <assert.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <string.h>
+
+#include <drivers/st/scmi-msg.h>
+#include <drivers/st/scmi.h>
+#include <lib/cassert.h>
+#include <lib/mmio.h>
+#include <lib/spinlock.h>
+#include <lib/utils.h>
+#include <plat/common/platform.h>
+
+#include "common.h"
+
+/* Legacy SMT/SCMI messages are 128 bytes at most including SMT header */
+#define SCMI_PLAYLOAD_MAX 92U
+#define SCMI_PLAYLOAD_U32_MAX (SCMI_PLAYLOAD_MAX / sizeof(uint32_t))
+
+/**
+ * struct smt_header - SMT formatted header for SMT base shared memory transfer
+ *
+ * @status: Bit flags, see SMT_STATUS_*
+ * @flags: Bit flags, see SMT_FLAG_*
+ * @length: Byte size of message payload (variable) + ::message_header (32bit)
+ * payload: SCMI message payload data
+ */
+struct smt_header {
+ uint32_t reserved0;
+ uint32_t status;
+ uint64_t reserved1;
+ uint32_t flags;
+ uint32_t length; /* message_header + payload */
+ uint32_t message_header;
+ uint32_t payload[];
+};
+
+CASSERT(SCMI_PLAYLOAD_MAX + sizeof(struct smt_header) <= SMT_BUF_SLOT_SIZE,
+ assert_scmi_message_max_length_fits_in_smt_buffer_slot);
+
+/* Flag set in smt_header::status when SMT does not contain pending message */
+#define SMT_STATUS_FREE BIT(0)
+/* Flag set in smt_header::status when SMT reports an error */
+#define SMT_STATUS_ERROR BIT(1)
+
+/* Flag set in smt_header::flags when SMT uses interrupts */
+#define SMT_FLAG_INTR_ENABLED BIT(1)
+
+/* Bit fields packed in smt_header::message_header */
+#define SMT_MSG_ID_MASK GENMASK_32(7, 0)
+#define SMT_HDR_MSG_ID(_hdr) ((_hdr) & SMT_MSG_ID_MASK)
+
+#define SMT_MSG_TYPE_MASK GENMASK_32(9, 8)
+#define SMT_HDR_TYPE_ID(_hdr) (((_hdr) & SMT_MSG_TYPE_MASK) >> 8)
+
+#define SMT_MSG_PROT_ID_MASK GENMASK_32(17, 10)
+#define SMT_HDR_PROT_ID(_hdr) (((_hdr) & SMT_MSG_PROT_ID_MASK) >> 10)
+
+/*
+ * Provision input message payload buffers for fastcall SMC context entries
+ * and for interrupt context execution entries.
+ */
+static uint32_t fast_smc_payload[PLATFORM_CORE_COUNT][SCMI_PLAYLOAD_U32_MAX];
+static uint32_t interrupt_payload[PLATFORM_CORE_COUNT][SCMI_PLAYLOAD_U32_MAX];
+
+/* SMP protection on channel access */
+static struct spinlock smt_channels_lock;
+
+/* If channel is not busy, set busy and return true, otherwise return false */
+static bool channel_set_busy(struct scmi_msg_channel *chan)
+{
+ bool channel_is_busy;
+
+ spin_lock(&smt_channels_lock);
+
+ channel_is_busy = chan->busy;
+
+ if (!channel_is_busy) {
+ chan->busy = true;
+ }
+
+ spin_unlock(&smt_channels_lock);
+
+ return !channel_is_busy;
+}
+
+static void channel_release_busy(struct scmi_msg_channel *chan)
+{
+ chan->busy = false;
+}
+
+static struct smt_header *channel_to_smt_hdr(struct scmi_msg_channel *chan)
+{
+ return (struct smt_header *)chan->shm_addr;
+}
+
+/*
+ * Creates a SCMI message instance in secure memory and push it in the SCMI
+ * message drivers. Message structure contains SCMI protocol meta-data and
+ * references to input payload in secure memory and output message buffer
+ * in shared memory.
+ */
+static void scmi_proccess_smt(unsigned int agent_id, uint32_t *payload_buf)
+{
+ struct scmi_msg_channel *chan;
+ struct smt_header *smt_hdr;
+ size_t in_payload_size;
+ uint32_t smt_status;
+ struct scmi_msg msg;
+ bool error = true;
+
+ chan = plat_scmi_get_channel(agent_id);
+ if (chan == NULL) {
+ return;
+ }
+
+ smt_hdr = channel_to_smt_hdr(chan);
+ assert(smt_hdr);
+
+ smt_status = __atomic_load_n(&smt_hdr->status, __ATOMIC_RELAXED);
+
+ if (!channel_set_busy(chan)) {
+ VERBOSE("SCMI channel %u busy", agent_id);
+ goto out;
+ }
+
+ in_payload_size = __atomic_load_n(&smt_hdr->length, __ATOMIC_RELAXED) -
+ sizeof(smt_hdr->message_header);
+
+ if (in_payload_size > SCMI_PLAYLOAD_MAX) {
+ VERBOSE("SCMI payload too big %u", in_payload_size);
+ goto out;
+ }
+
+ if (smt_status & (SMT_STATUS_ERROR | SMT_STATUS_FREE)) {
+ VERBOSE("SCMI channel bad status 0x%x",
+ smt_hdr->status & (SMT_STATUS_ERROR | SMT_STATUS_FREE));
+ goto out;
+ }
+
+ /* Fill message */
+ zeromem(&msg, sizeof(msg));
+ msg.in = (char *)payload_buf;
+ msg.in_size = in_payload_size;
+ msg.out = (char *)smt_hdr->payload;
+ msg.out_size = chan->shm_size - sizeof(*smt_hdr);
+
+ assert(msg.out && msg.out_size >= sizeof(int32_t));
+
+ /* Here the payload is copied in secure memory */
+ memcpy(msg.in, smt_hdr->payload, in_payload_size);
+
+ msg.protocol_id = SMT_HDR_PROT_ID(smt_hdr->message_header);
+ msg.message_id = SMT_HDR_MSG_ID(smt_hdr->message_header);
+ msg.agent_id = agent_id;
+
+ scmi_process_message(&msg);
+
+ /* Update message length with the length of the response message */
+ smt_hdr->length = msg.out_size_out + sizeof(smt_hdr->message_header);
+
+ channel_release_busy(chan);
+ error = false;
+
+out:
+ if (error) {
+ VERBOSE("SCMI error");
+ smt_hdr->status |= SMT_STATUS_ERROR | SMT_STATUS_FREE;
+ } else {
+ smt_hdr->status |= SMT_STATUS_FREE;
+ }
+}
+
+void scmi_smt_fastcall_smc_entry(unsigned int agent_id)
+{
+ scmi_proccess_smt(agent_id,
+ fast_smc_payload[plat_my_core_pos()]);
+}
+
+void scmi_smt_interrupt_entry(unsigned int agent_id)
+{
+ scmi_proccess_smt(agent_id,
+ interrupt_payload[plat_my_core_pos()]);
+}
+
+/* Init a SMT header for a shared memory buffer: state it a free/no-error */
+void scmi_smt_init_agent_channel(struct scmi_msg_channel *chan)
+{
+ if (chan != NULL) {
+ struct smt_header *smt_header = channel_to_smt_hdr(chan);
+
+ if (smt_header != NULL) {
+ memset(smt_header, 0, sizeof(*smt_header));
+ smt_header->status = SMT_STATUS_FREE;
+
+ return;
+ }
+ }
+
+ panic();
+}
diff --git a/drivers/st/spi/stm32_qspi.c b/drivers/st/spi/stm32_qspi.c
new file mode 100644
index 000000000..f4a13386f
--- /dev/null
+++ b/drivers/st/spi/stm32_qspi.c
@@ -0,0 +1,507 @@
+/*
+ * Copyright (c) 2019-2020, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
+ */
+
+#include <libfdt.h>
+
+#include <platform_def.h>
+
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <drivers/spi_mem.h>
+#include <drivers/st/stm32_gpio.h>
+#include <drivers/st/stm32_qspi.h>
+#include <drivers/st/stm32mp_reset.h>
+#include <lib/mmio.h>
+#include <lib/utils_def.h>
+
+#define TIMEOUT_US_1MS U(1000)
+
+/* QUADSPI registers */
+#define QSPI_CR 0x00U
+#define QSPI_DCR 0x04U
+#define QSPI_SR 0x08U
+#define QSPI_FCR 0x0CU
+#define QSPI_DLR 0x10U
+#define QSPI_CCR 0x14U
+#define QSPI_AR 0x18U
+#define QSPI_ABR 0x1CU
+#define QSPI_DR 0x20U
+#define QSPI_PSMKR 0x24U
+#define QSPI_PSMAR 0x28U
+#define QSPI_PIR 0x2CU
+#define QSPI_LPTR 0x30U
+
+/* QUADSPI control register */
+#define QSPI_CR_EN BIT(0)
+#define QSPI_CR_ABORT BIT(1)
+#define QSPI_CR_DMAEN BIT(2)
+#define QSPI_CR_TCEN BIT(3)
+#define QSPI_CR_SSHIFT BIT(4)
+#define QSPI_CR_DFM BIT(6)
+#define QSPI_CR_FSEL BIT(7)
+#define QSPI_CR_FTHRES_SHIFT 8U
+#define QSPI_CR_TEIE BIT(16)
+#define QSPI_CR_TCIE BIT(17)
+#define QSPI_CR_FTIE BIT(18)
+#define QSPI_CR_SMIE BIT(19)
+#define QSPI_CR_TOIE BIT(20)
+#define QSPI_CR_APMS BIT(22)
+#define QSPI_CR_PMM BIT(23)
+#define QSPI_CR_PRESCALER_MASK GENMASK_32(31, 24)
+#define QSPI_CR_PRESCALER_SHIFT 24U
+
+/* QUADSPI device configuration register */
+#define QSPI_DCR_CKMODE BIT(0)
+#define QSPI_DCR_CSHT_MASK GENMASK_32(10, 8)
+#define QSPI_DCR_CSHT_SHIFT 8U
+#define QSPI_DCR_FSIZE_MASK GENMASK_32(20, 16)
+#define QSPI_DCR_FSIZE_SHIFT 16U
+
+/* QUADSPI status register */
+#define QSPI_SR_TEF BIT(0)
+#define QSPI_SR_TCF BIT(1)
+#define QSPI_SR_FTF BIT(2)
+#define QSPI_SR_SMF BIT(3)
+#define QSPI_SR_TOF BIT(4)
+#define QSPI_SR_BUSY BIT(5)
+
+/* QUADSPI flag clear register */
+#define QSPI_FCR_CTEF BIT(0)
+#define QSPI_FCR_CTCF BIT(1)
+#define QSPI_FCR_CSMF BIT(3)
+#define QSPI_FCR_CTOF BIT(4)
+
+/* QUADSPI communication configuration register */
+#define QSPI_CCR_DDRM BIT(31)
+#define QSPI_CCR_DHHC BIT(30)
+#define QSPI_CCR_SIOO BIT(28)
+#define QSPI_CCR_FMODE_SHIFT 26U
+#define QSPI_CCR_DMODE_SHIFT 24U
+#define QSPI_CCR_DCYC_SHIFT 18U
+#define QSPI_CCR_ABSIZE_SHIFT 16U
+#define QSPI_CCR_ABMODE_SHIFT 14U
+#define QSPI_CCR_ADSIZE_SHIFT 12U
+#define QSPI_CCR_ADMODE_SHIFT 10U
+#define QSPI_CCR_IMODE_SHIFT 8U
+#define QSPI_CCR_IND_WRITE 0U
+#define QSPI_CCR_IND_READ 1U
+#define QSPI_CCR_MEM_MAP 3U
+
+#define QSPI_MAX_CHIP 2U
+
+#define QSPI_FIFO_TIMEOUT_US 30U
+#define QSPI_CMD_TIMEOUT_US 1000U
+#define QSPI_BUSY_TIMEOUT_US 100U
+#define QSPI_ABT_TIMEOUT_US 100U
+
+#define DT_QSPI_COMPAT "st,stm32f469-qspi"
+
+#define FREQ_100MHZ 100000000U
+
+struct stm32_qspi_ctrl {
+ uintptr_t reg_base;
+ uintptr_t mm_base;
+ size_t mm_size;
+ unsigned long clock_id;
+ unsigned int reset_id;
+};
+
+static struct stm32_qspi_ctrl stm32_qspi;
+
+static uintptr_t qspi_base(void)
+{
+ return stm32_qspi.reg_base;
+}
+
+static int stm32_qspi_wait_for_not_busy(void)
+{
+ uint64_t timeout = timeout_init_us(QSPI_BUSY_TIMEOUT_US);
+
+ while ((mmio_read_32(qspi_base() + QSPI_SR) & QSPI_SR_BUSY) != 0U) {
+ if (timeout_elapsed(timeout)) {
+ ERROR("%s: busy timeout\n", __func__);
+ return -ETIMEDOUT;
+ }
+ }
+
+ return 0;
+}
+
+static int stm32_qspi_wait_cmd(const struct spi_mem_op *op)
+{
+ int ret = 0;
+ uint64_t timeout;
+
+ if (op->data.nbytes == 0U) {
+ return stm32_qspi_wait_for_not_busy();
+ }
+
+ timeout = timeout_init_us(QSPI_CMD_TIMEOUT_US);
+ while ((mmio_read_32(qspi_base() + QSPI_SR) & QSPI_SR_TCF) == 0U) {
+ if (timeout_elapsed(timeout)) {
+ ret = -ETIMEDOUT;
+ break;
+ }
+ }
+
+ if (ret == 0) {
+ if ((mmio_read_32(qspi_base() + QSPI_SR) & QSPI_SR_TEF) != 0U) {
+ ERROR("%s: transfer error\n", __func__);
+ ret = -EIO;
+ }
+ } else {
+ ERROR("%s: cmd timeout\n", __func__);
+ }
+
+ /* Clear flags */
+ mmio_write_32(qspi_base() + QSPI_FCR, QSPI_FCR_CTCF | QSPI_FCR_CTEF);
+
+ return ret;
+}
+
+static void stm32_qspi_read_fifo(uint8_t *val, uintptr_t addr)
+{
+ *val = mmio_read_8(addr);
+}
+
+static void stm32_qspi_write_fifo(uint8_t *val, uintptr_t addr)
+{
+ mmio_write_8(addr, *val);
+}
+
+static int stm32_qspi_poll(const struct spi_mem_op *op)
+{
+ void (*fifo)(uint8_t *val, uintptr_t addr);
+ uint32_t len;
+ uint8_t *buf;
+
+ if (op->data.dir == SPI_MEM_DATA_IN) {
+ fifo = stm32_qspi_read_fifo;
+ } else {
+ fifo = stm32_qspi_write_fifo;
+ }
+
+ buf = (uint8_t *)op->data.buf;
+
+ for (len = op->data.nbytes; len != 0U; len--) {
+ uint64_t timeout = timeout_init_us(QSPI_FIFO_TIMEOUT_US);
+
+ while ((mmio_read_32(qspi_base() + QSPI_SR) &
+ QSPI_SR_FTF) == 0U) {
+ if (timeout_elapsed(timeout)) {
+ ERROR("%s: fifo timeout\n", __func__);
+ return -ETIMEDOUT;
+ }
+ }
+
+ fifo(buf++, qspi_base() + QSPI_DR);
+ }
+
+ return 0;
+}
+
+static int stm32_qspi_mm(const struct spi_mem_op *op)
+{
+ memcpy(op->data.buf,
+ (void *)(stm32_qspi.mm_base + (size_t)op->addr.val),
+ op->data.nbytes);
+
+ return 0;
+}
+
+static int stm32_qspi_tx(const struct spi_mem_op *op, uint8_t mode)
+{
+ if (op->data.nbytes == 0U) {
+ return 0;
+ }
+
+ if (mode == QSPI_CCR_MEM_MAP) {
+ return stm32_qspi_mm(op);
+ }
+
+ return stm32_qspi_poll(op);
+}
+
+static unsigned int stm32_qspi_get_mode(uint8_t buswidth)
+{
+ if (buswidth == 4U) {
+ return 3U;
+ }
+
+ return buswidth;
+}
+
+static int stm32_qspi_exec_op(const struct spi_mem_op *op)
+{
+ uint64_t timeout;
+ uint32_t ccr;
+ size_t addr_max;
+ uint8_t mode = QSPI_CCR_IND_WRITE;
+ int ret;
+
+ VERBOSE("%s: cmd:%x mode:%d.%d.%d.%d addr:%llx len:%x\n",
+ __func__, op->cmd.opcode, op->cmd.buswidth, op->addr.buswidth,
+ op->dummy.buswidth, op->data.buswidth,
+ op->addr.val, op->data.nbytes);
+
+ ret = stm32_qspi_wait_for_not_busy();
+ if (ret != 0) {
+ return ret;
+ }
+
+ addr_max = op->addr.val + op->data.nbytes + 1U;
+
+ if ((op->data.dir == SPI_MEM_DATA_IN) && (op->data.nbytes != 0U)) {
+ if ((addr_max < stm32_qspi.mm_size) &&
+ (op->addr.buswidth != 0U)) {
+ mode = QSPI_CCR_MEM_MAP;
+ } else {
+ mode = QSPI_CCR_IND_READ;
+ }
+ }
+
+ if (op->data.nbytes != 0U) {
+ mmio_write_32(qspi_base() + QSPI_DLR, op->data.nbytes - 1U);
+ }
+
+ ccr = mode << QSPI_CCR_FMODE_SHIFT;
+ ccr |= op->cmd.opcode;
+ ccr |= stm32_qspi_get_mode(op->cmd.buswidth) << QSPI_CCR_IMODE_SHIFT;
+
+ if (op->addr.nbytes != 0U) {
+ ccr |= (op->addr.nbytes - 1U) << QSPI_CCR_ADSIZE_SHIFT;
+ ccr |= stm32_qspi_get_mode(op->addr.buswidth) <<
+ QSPI_CCR_ADMODE_SHIFT;
+ }
+
+ if ((op->dummy.buswidth != 0U) && (op->dummy.nbytes != 0U)) {
+ ccr |= (op->dummy.nbytes * 8U / op->dummy.buswidth) <<
+ QSPI_CCR_DCYC_SHIFT;
+ }
+
+ if (op->data.nbytes != 0U) {
+ ccr |= stm32_qspi_get_mode(op->data.buswidth) <<
+ QSPI_CCR_DMODE_SHIFT;
+ }
+
+ mmio_write_32(qspi_base() + QSPI_CCR, ccr);
+
+ if ((op->addr.nbytes != 0U) && (mode != QSPI_CCR_MEM_MAP)) {
+ mmio_write_32(qspi_base() + QSPI_AR, op->addr.val);
+ }
+
+ ret = stm32_qspi_tx(op, mode);
+
+ /*
+ * Abort in:
+ * - Error case.
+ * - Memory mapped read: prefetching must be stopped if we read the last
+ * byte of device (device size - fifo size). If device size is not
+ * known then prefetching is always stopped.
+ */
+ if ((ret != 0) || (mode == QSPI_CCR_MEM_MAP)) {
+ goto abort;
+ }
+
+ /* Wait end of TX in indirect mode */
+ ret = stm32_qspi_wait_cmd(op);
+ if (ret != 0) {
+ goto abort;
+ }
+
+ return 0;
+
+abort:
+ mmio_setbits_32(qspi_base() + QSPI_CR, QSPI_CR_ABORT);
+
+ /* Wait clear of abort bit by hardware */
+ timeout = timeout_init_us(QSPI_ABT_TIMEOUT_US);
+ while ((mmio_read_32(qspi_base() + QSPI_CR) & QSPI_CR_ABORT) != 0U) {
+ if (timeout_elapsed(timeout)) {
+ ret = -ETIMEDOUT;
+ break;
+ }
+ }
+
+ mmio_write_32(qspi_base() + QSPI_FCR, QSPI_FCR_CTCF);
+
+ if (ret != 0) {
+ ERROR("%s: exec op error\n", __func__);
+ }
+
+ return ret;
+}
+
+static int stm32_qspi_claim_bus(unsigned int cs)
+{
+ uint32_t cr;
+
+ if (cs >= QSPI_MAX_CHIP) {
+ return -ENODEV;
+ }
+
+ /* Set chip select and enable the controller */
+ cr = QSPI_CR_EN;
+ if (cs == 1U) {
+ cr |= QSPI_CR_FSEL;
+ }
+
+ mmio_clrsetbits_32(qspi_base() + QSPI_CR, QSPI_CR_FSEL, cr);
+
+ return 0;
+}
+
+static void stm32_qspi_release_bus(void)
+{
+ mmio_clrbits_32(qspi_base() + QSPI_CR, QSPI_CR_EN);
+}
+
+static int stm32_qspi_set_speed(unsigned int hz)
+{
+ unsigned long qspi_clk = stm32mp_clk_get_rate(stm32_qspi.clock_id);
+ uint32_t prescaler = UINT8_MAX;
+ uint32_t csht;
+ int ret;
+
+ if (qspi_clk == 0U) {
+ return -EINVAL;
+ }
+
+ if (hz > 0U) {
+ prescaler = div_round_up(qspi_clk, hz) - 1U;
+ if (prescaler > UINT8_MAX) {
+ prescaler = UINT8_MAX;
+ }
+ }
+
+ csht = div_round_up((5U * qspi_clk) / (prescaler + 1U), FREQ_100MHZ);
+ csht = ((csht - 1U) << QSPI_DCR_CSHT_SHIFT) & QSPI_DCR_CSHT_MASK;
+
+ ret = stm32_qspi_wait_for_not_busy();
+ if (ret != 0) {
+ return ret;
+ }
+
+ mmio_clrsetbits_32(qspi_base() + QSPI_CR, QSPI_CR_PRESCALER_MASK,
+ prescaler << QSPI_CR_PRESCALER_SHIFT);
+
+ mmio_clrsetbits_32(qspi_base() + QSPI_DCR, QSPI_DCR_CSHT_MASK, csht);
+
+ VERBOSE("%s: speed=%lu\n", __func__, qspi_clk / (prescaler + 1U));
+
+ return 0;
+}
+
+static int stm32_qspi_set_mode(unsigned int mode)
+{
+ int ret;
+
+ ret = stm32_qspi_wait_for_not_busy();
+ if (ret != 0) {
+ return ret;
+ }
+
+ if ((mode & SPI_CS_HIGH) != 0U) {
+ return -ENODEV;
+ }
+
+ if (((mode & SPI_CPHA) != 0U) && ((mode & SPI_CPOL) != 0U)) {
+ mmio_setbits_32(qspi_base() + QSPI_DCR, QSPI_DCR_CKMODE);
+ } else if (((mode & SPI_CPHA) == 0U) && ((mode & SPI_CPOL) == 0U)) {
+ mmio_clrbits_32(qspi_base() + QSPI_DCR, QSPI_DCR_CKMODE);
+ } else {
+ return -ENODEV;
+ }
+
+ VERBOSE("%s: mode=0x%x\n", __func__, mode);
+
+ if ((mode & SPI_RX_QUAD) != 0U) {
+ VERBOSE("rx: quad\n");
+ } else if ((mode & SPI_RX_DUAL) != 0U) {
+ VERBOSE("rx: dual\n");
+ } else {
+ VERBOSE("rx: single\n");
+ }
+
+ if ((mode & SPI_TX_QUAD) != 0U) {
+ VERBOSE("tx: quad\n");
+ } else if ((mode & SPI_TX_DUAL) != 0U) {
+ VERBOSE("tx: dual\n");
+ } else {
+ VERBOSE("tx: single\n");
+ }
+
+ return 0;
+}
+
+static const struct spi_bus_ops stm32_qspi_bus_ops = {
+ .claim_bus = stm32_qspi_claim_bus,
+ .release_bus = stm32_qspi_release_bus,
+ .set_speed = stm32_qspi_set_speed,
+ .set_mode = stm32_qspi_set_mode,
+ .exec_op = stm32_qspi_exec_op,
+};
+
+int stm32_qspi_init(void)
+{
+ size_t size;
+ int qspi_node;
+ struct dt_node_info info;
+ void *fdt = NULL;
+ int ret;
+
+ if (fdt_get_address(&fdt) == 0) {
+ return -FDT_ERR_NOTFOUND;
+ }
+
+ qspi_node = dt_get_node(&info, -1, DT_QSPI_COMPAT);
+ if (qspi_node < 0) {
+ ERROR("No QSPI ctrl found\n");
+ return -FDT_ERR_NOTFOUND;
+ }
+
+ if (info.status == DT_DISABLED) {
+ return -FDT_ERR_NOTFOUND;
+ }
+
+ ret = fdt_get_reg_props_by_name(qspi_node, "qspi",
+ &stm32_qspi.reg_base, &size);
+ if (ret != 0) {
+ return ret;
+ }
+
+ ret = fdt_get_reg_props_by_name(qspi_node, "qspi_mm",
+ &stm32_qspi.mm_base,
+ &stm32_qspi.mm_size);
+ if (ret != 0) {
+ return ret;
+ }
+
+ if (dt_set_pinctrl_config(qspi_node) != 0) {
+ return -FDT_ERR_BADVALUE;
+ }
+
+ if ((info.clock < 0) || (info.reset < 0)) {
+ return -FDT_ERR_BADVALUE;
+ }
+
+ stm32_qspi.clock_id = (unsigned long)info.clock;
+ stm32_qspi.reset_id = (unsigned int)info.reset;
+
+ stm32mp_clk_enable(stm32_qspi.clock_id);
+
+ if (stm32mp_reset_assert_to(stm32_qspi.reset_id, TIMEOUT_US_1MS)) {
+ panic();
+ }
+ if (stm32mp_reset_deassert_to(stm32_qspi.reset_id, TIMEOUT_US_1MS)) {
+ panic();
+ }
+
+ mmio_write_32(qspi_base() + QSPI_CR, QSPI_CR_SSHIFT);
+ mmio_write_32(qspi_base() + QSPI_DCR, QSPI_DCR_FSIZE_MASK);
+
+ return spi_mem_init_slave(fdt, qspi_node, &stm32_qspi_bus_ops);
+};
diff --git a/drivers/st/tamper/stm32_tamp.c b/drivers/st/tamper/stm32_tamp.c
new file mode 100644
index 000000000..216e324d5
--- /dev/null
+++ b/drivers/st/tamper/stm32_tamp.c
@@ -0,0 +1,377 @@
+/*
+ * Copyright (c) 2018-2020, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+
+#include <libfdt.h>
+
+#include <platform_def.h>
+
+#include <drivers/st/stm32_rng.h>
+#include <drivers/st/stm32_rtc.h>
+#include <drivers/st/stm32_tamp.h>
+#include <lib/mmio.h>
+
+#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].func != NULL) {
+ int_list[tamp].func(int_id);
+ }
+
+ 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].func != NULL) {
+ ext_list[tamp].func(ext_id);
+ }
+
+ 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 TAMP is enabled */
+ if ((dt_tamp.status != DT_SECURE) &&
+ (dt_tamp.status != DT_SHARED)) {
+ 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 000000000..a4e178ec4
--- /dev/null
+++ b/drivers/st/timer/stm32_timer.c
@@ -0,0 +1,316 @@
+/*
+ * Copyright (c) 2018-2019, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <stdbool.h>
+
+#include <libfdt.h>
+
+#include <platform_def.h>
+
+#include <drivers/delay_timer.h>
+#include <drivers/st/stm32_timer.h>
+#include <lib/mmio.h>
+
+#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
+#define TIM_MIN_FREQ_CALIB 50000000U
+
+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 int stm32_timer_config(struct stm32_timer_instance *timer)
+{
+ stm32mp_clk_enable(timer->clk);
+
+ timer->freq = stm32mp_clk_timer_get_rate(timer->clk);
+
+ if (timer->freq < TIM_MIN_FREQ_CALIB) {
+ WARN("Timer is not accurate enough for calibration\n");
+ stm32mp_clk_disable(timer->clk);
+ return -EINVAL;
+ }
+
+ 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);
+
+ return 0;
+}
+
+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;
+
+ if (stm32_timer_config(timer) < 0) {
+ return 0U;
+ }
+
+ 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);
+ if (stm32_timer_config(timer) < 0) {
+ timer->base = 0;
+ continue;
+ }
+ }
+
+ 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);
+ if (stm32_timer_config(timer) < 0) {
+ timer->base = 0;
+ continue;
+ }
+ }
+ }
+ }
+
+ 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 ca3c1f618..0fabcc82e 100644
--- a/drivers/st/uart/aarch32/stm32_console.S
+++ b/drivers/st/uart/aarch32/stm32_console.S
@@ -122,17 +122,15 @@ 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_stm32_core_putc
/* Check the input parameter */
@@ -140,13 +138,19 @@ func console_stm32_core_putc
beq putc_error
/* Check Transmit Data Register Empty */
+ mov r3, #USART_TIMEOUT
txe_loop:
+ subs r3, r3, #1
+ beq putc_error
ldr r2, [r1, #USART_ISR]
tst r2, #USART_ISR_TXE
beq txe_loop
str r0, [r1, #USART_TDR]
/* Check transmit complete flag */
+ mov r3, #USART_TIMEOUT
tc_loop:
+ subs r3, r3, #1
+ beq putc_error
ldr r2, [r1, #USART_ISR]
tst r2, #USART_ISR_TC
beq tc_loop
@@ -200,14 +204,17 @@ endfunc console_stm32_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_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
diff --git a/drivers/st/uart/io_programmer_uart.c b/drivers/st/uart/io_programmer_uart.c
new file mode 100644
index 000000000..6d024e158
--- /dev/null
+++ b/drivers/st/uart/io_programmer_uart.c
@@ -0,0 +1,587 @@
+/*
+ * Copyright (c) 2015-2020, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/io/io_driver.h>
+#include <drivers/io/io_storage.h>
+#include <drivers/st/io_programmer.h>
+#include <drivers/st/io_stm32image.h>
+#include <drivers/st/io_uart.h>
+#include <drivers/st/stm32_iwdg.h>
+
+/* 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)&current_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();
+
+ 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 = stm32mp_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);
+ }
+
+ return stm32mp_check_header(header, buffer);
+
+ 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)) {
+#if TRUSTED_BOARD_BOOT
+ stm32mp_save_loaded_header(header_buffer);
+#endif
+ 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();
+
+ 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 000000000..70ccc378e
--- /dev/null
+++ b/drivers/st/uart/stm32mp1xx_hal_uart.c
@@ -0,0 +1,801 @@
+/**
+ ******************************************************************************
+ * @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
+ *
+ * <h2><center>&copy; COPYRIGHT(c) 2015-2017 STMicroelectronics</center></h2>
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ ******************************************************************************
+ */
+
+/* Includes ------------------------------------------------------------------*/
+#include <assert.h>
+#include <string.h>
+
+#include <platform_def.h>
+
+#include <common/bl_common.h>
+#include <drivers/st/stm32mp_clkfunc.h>
+#include <drivers/st/stm32mp1xx_hal_uart.h>
+
+/** @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 000000000..fc0b8625e
--- /dev/null
+++ b/drivers/st/usb_dwc2/usb_dwc2.c
@@ -0,0 +1,859 @@
+/*
+ * Copyright (c) 2015-2019, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/st/usb_dwc2.h>
+
+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/fdts/stm32mp15-ddr.dtsi b/fdts/stm32mp15-ddr.dtsi
index 4825691f9..f0657ad12 100644
--- a/fdts/stm32mp15-ddr.dtsi
+++ b/fdts/stm32mp15-ddr.dtsi
@@ -132,6 +132,7 @@
DDR_MR3
>;
+#ifdef DDR_PHY_CAL_SKIP
st,phy-cal = <
DDR_DX0DLLCR
DDR_DX0DQTR
@@ -146,6 +147,7 @@
DDR_DX3DQTR
DDR_DX3DQSTR
>;
+#endif
status = "okay";
};
diff --git a/fdts/stm32mp15-ddr3-1x4Gb-1066-binG.dtsi b/fdts/stm32mp15-ddr3-1x4Gb-1066-binG.dtsi
index 11e8f2bef..c0fc1f772 100644
--- a/fdts/stm32mp15-ddr3-1x4Gb-1066-binG.dtsi
+++ b/fdts/stm32mp15-ddr3-1x4Gb-1066-binG.dtsi
@@ -1,24 +1,23 @@
// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
/*
* Copyright (C) 2018, STMicroelectronics - All Rights Reserved
+ */
+
+/*
+ * File generated by STMicroelectronics STM32CubeMX DDR Tool for MPUs
+ * DDR type: DDR3 / DDR3L
+ * DDR width: 16bits
+ * DDR density: 4Gb
+ * System frequency: 533000Khz
+ * Relaxed Timing Mode: false
+ * Address mapping type: RBC
*
- * 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
+ * Save Date: 2020.02.20, save Time: 18:45:20
*/
-#define DDR_MEM_NAME "DDR3-1066/888 bin G 1x4Gb 533MHz v1.45"
-#define DDR_MEM_SPEED 533000
-#define DDR_MEM_SIZE 0x20000000
+
+#define DDR_MEM_NAME "DDR3-DDR3L 16bits 533000Khz"
+#define DDR_MEM_SPEED 533000
+#define DDR_MEM_SIZE 0x20000000
#define DDR_MSTR 0x00041401
#define DDR_MRCTRL0 0x00000010
@@ -50,15 +49,6 @@
#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
@@ -83,6 +73,15 @@
#define DDR_PCFGQOS1_1 0x00800040
#define DDR_PCFGWQOS0_1 0x01100C03
#define DDR_PCFGWQOS1_1 0x01000200
+#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_PGCR 0x01442E02
#define DDR_PTR0 0x0022AA5B
#define DDR_PTR1 0x04841104
diff --git a/fdts/stm32mp15-ddr3-2x4Gb-1066-binG.dtsi b/fdts/stm32mp15-ddr3-2x4Gb-1066-binG.dtsi
index 4b70b6055..fc226d254 100644
--- a/fdts/stm32mp15-ddr3-2x4Gb-1066-binG.dtsi
+++ b/fdts/stm32mp15-ddr3-2x4Gb-1066-binG.dtsi
@@ -1,24 +1,23 @@
// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
/*
* Copyright (C) 2018, STMicroelectronics - All Rights Reserved
+ */
+
+/*
+ * File generated by STMicroelectronics STM32CubeMX DDR Tool for MPUs
+ * DDR type: DDR3 / DDR3L
+ * DDR width: 32bits
+ * DDR density: 8Gb
+ * System frequency: 533000Khz
+ * Relaxed Timing Mode: false
+ * Address mapping type: RBC
*
- * STM32MP157C ED1 BOARD configuration
- * 2x DDR3L 4Gb each, 16-bit, 533MHz, Single Die Package in flyby topology.
- * Reference used NT5CC256M16DP-DI from NANYA
- *
- * DDR type / Platform DDR3/3L
- * freq 533MHz
- * width 32
- * datasheet 0 = MT41J256M16-187 / DDR3-1066 bin G
- * DDR density 8
- * timing mode optimized
- * Scheduling/QoS options : type = 2
- * address mapping : RBC
- * Tc > + 85C : N
+ * Save Date: 2020.02.20, save Time: 18:49:33
*/
-#define DDR_MEM_NAME "DDR3-1066/888 bin G 2x4Gb 533MHz v1.45"
-#define DDR_MEM_SPEED 533000
-#define DDR_MEM_SIZE 0x40000000
+
+#define DDR_MEM_NAME "DDR3-DDR3L 32bits 533000Khz"
+#define DDR_MEM_SPEED 533000
+#define DDR_MEM_SIZE 0x40000000
#define DDR_MSTR 0x00040401
#define DDR_MRCTRL0 0x00000010
@@ -50,15 +49,6 @@
#define DDR_DFIUPD1 0x00000000
#define DDR_DFIUPD2 0x00000000
#define DDR_DFIPHYMSTR 0x00000000
-#define DDR_ADDRMAP1 0x00080808
-#define DDR_ADDRMAP2 0x00000000
-#define DDR_ADDRMAP3 0x00000000
-#define DDR_ADDRMAP4 0x00001F1F
-#define DDR_ADDRMAP5 0x07070707
-#define DDR_ADDRMAP6 0x0F070707
-#define DDR_ADDRMAP9 0x00000000
-#define DDR_ADDRMAP10 0x00000000
-#define DDR_ADDRMAP11 0x00000000
#define DDR_ODTCFG 0x06000600
#define DDR_ODTMAP 0x00000001
#define DDR_SCHED 0x00000C01
@@ -83,6 +73,15 @@
#define DDR_PCFGQOS1_1 0x00800040
#define DDR_PCFGWQOS0_1 0x01100C03
#define DDR_PCFGWQOS1_1 0x01000200
+#define DDR_ADDRMAP1 0x00080808
+#define DDR_ADDRMAP2 0x00000000
+#define DDR_ADDRMAP3 0x00000000
+#define DDR_ADDRMAP4 0x00001F1F
+#define DDR_ADDRMAP5 0x07070707
+#define DDR_ADDRMAP6 0x0F070707
+#define DDR_ADDRMAP9 0x00000000
+#define DDR_ADDRMAP10 0x00000000
+#define DDR_ADDRMAP11 0x00000000
#define DDR_PGCR 0x01442E02
#define DDR_PTR0 0x0022AA5B
#define DDR_PTR1 0x04841104
diff --git a/fdts/stm32mp15-pinctrl.dtsi b/fdts/stm32mp15-pinctrl.dtsi
new file mode 100644
index 000000000..d3d1744ec
--- /dev/null
+++ b/fdts/stm32mp15-pinctrl.dtsi
@@ -0,0 +1,292 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
+/*
+ * Copyright (C) STMicroelectronics 2017 - All Rights Reserved
+ * Author: Ludovic Barre <ludovic.barre@st.com> for STMicroelectronics.
+ */
+#include <dt-bindings/pinctrl/stm32-pinfunc.h>
+
+&pinctrl {
+ fmc_pins_a: fmc-0 {
+ pins1 {
+ pinmux = <STM32_PINMUX('D', 4, AF12)>, /* FMC_NOE */
+ <STM32_PINMUX('D', 5, AF12)>, /* FMC_NWE */
+ <STM32_PINMUX('D', 11, AF12)>, /* FMC_A16_FMC_CLE */
+ <STM32_PINMUX('D', 12, AF12)>, /* FMC_A17_FMC_ALE */
+ <STM32_PINMUX('D', 14, AF12)>, /* FMC_D0 */
+ <STM32_PINMUX('D', 15, AF12)>, /* FMC_D1 */
+ <STM32_PINMUX('D', 0, AF12)>, /* FMC_D2 */
+ <STM32_PINMUX('D', 1, AF12)>, /* FMC_D3 */
+ <STM32_PINMUX('E', 7, AF12)>, /* FMC_D4 */
+ <STM32_PINMUX('E', 8, AF12)>, /* FMC_D5 */
+ <STM32_PINMUX('E', 9, AF12)>, /* FMC_D6 */
+ <STM32_PINMUX('E', 10, AF12)>, /* FMC_D7 */
+ <STM32_PINMUX('G', 9, AF12)>; /* FMC_NE2_FMC_NCE */
+ bias-disable;
+ drive-push-pull;
+ slew-rate = <1>;
+ };
+ pins2 {
+ pinmux = <STM32_PINMUX('D', 6, AF12)>; /* FMC_NWAIT */
+ bias-pull-up;
+ };
+ };
+
+ qspi_clk_pins_a: qspi-clk-0 {
+ pins {
+ pinmux = <STM32_PINMUX('F', 10, AF9)>; /* QSPI_CLK */
+ bias-disable;
+ drive-push-pull;
+ slew-rate = <3>;
+ };
+ };
+
+ qspi_bk1_pins_a: qspi-bk1-0 {
+ pins1 {
+ pinmux = <STM32_PINMUX('F', 8, AF10)>, /* QSPI_BK1_IO0 */
+ <STM32_PINMUX('F', 9, AF10)>, /* QSPI_BK1_IO1 */
+ <STM32_PINMUX('F', 7, AF9)>, /* QSPI_BK1_IO2 */
+ <STM32_PINMUX('F', 6, AF9)>; /* QSPI_BK1_IO3 */
+ bias-disable;
+ drive-push-pull;
+ slew-rate = <1>;
+ };
+ pins2 {
+ pinmux = <STM32_PINMUX('B', 6, AF10)>; /* QSPI_BK1_NCS */
+ bias-pull-up;
+ drive-push-pull;
+ slew-rate = <1>;
+ };
+ };
+
+ qspi_bk2_pins_a: qspi-bk2-0 {
+ pins1 {
+ pinmux = <STM32_PINMUX('H', 2, AF9)>, /* QSPI_BK2_IO0 */
+ <STM32_PINMUX('H', 3, AF9)>, /* QSPI_BK2_IO1 */
+ <STM32_PINMUX('G', 10, AF11)>, /* QSPI_BK2_IO2 */
+ <STM32_PINMUX('G', 7, AF11)>; /* QSPI_BK2_IO3 */
+ bias-disable;
+ drive-push-pull;
+ slew-rate = <1>;
+ };
+ pins2 {
+ pinmux = <STM32_PINMUX('C', 0, AF10)>; /* QSPI_BK2_NCS */
+ bias-pull-up;
+ drive-push-pull;
+ slew-rate = <1>;
+ };
+ };
+
+ rtc_out2_rmp_pins_a: rtc-out2-rmp-pins-0 {
+ pins {
+ pinmux = <STM32_PINMUX('I', 8, ANALOG)>; /* RTC_OUT2_RMP */
+ };
+ };
+
+ sdmmc1_b4_pins_a: sdmmc1-b4-0 {
+ pins1 {
+ pinmux = <STM32_PINMUX('C', 8, AF12)>, /* SDMMC1_D0 */
+ <STM32_PINMUX('C', 9, AF12)>, /* SDMMC1_D1 */
+ <STM32_PINMUX('C', 10, AF12)>, /* SDMMC1_D2 */
+ <STM32_PINMUX('C', 11, AF12)>, /* SDMMC1_D3 */
+ <STM32_PINMUX('D', 2, AF12)>; /* SDMMC1_CMD */
+ slew-rate = <1>;
+ drive-push-pull;
+ bias-disable;
+ };
+ pins2 {
+ pinmux = <STM32_PINMUX('C', 12, AF12)>; /* SDMMC1_CK */
+ slew-rate = <2>;
+ drive-push-pull;
+ bias-disable;
+ };
+ };
+
+ sdmmc1_dir_pins_a: sdmmc1-dir-0 {
+ pins1 {
+ pinmux = <STM32_PINMUX('F', 2, AF11)>, /* SDMMC1_D0DIR */
+ <STM32_PINMUX('C', 7, AF8)>, /* SDMMC1_D123DIR */
+ <STM32_PINMUX('B', 9, AF11)>; /* SDMMC1_CDIR */
+ slew-rate = <1>;
+ drive-push-pull;
+ bias-pull-up;
+ };
+ pins2{
+ pinmux = <STM32_PINMUX('E', 4, AF8)>; /* SDMMC1_CKIN */
+ bias-pull-up;
+ };
+ };
+
+ sdmmc2_b4_pins_a: sdmmc2-b4-0 {
+ pins1 {
+ pinmux = <STM32_PINMUX('B', 14, AF9)>, /* SDMMC2_D0 */
+ <STM32_PINMUX('B', 15, AF9)>, /* SDMMC2_D1 */
+ <STM32_PINMUX('B', 3, AF9)>, /* SDMMC2_D2 */
+ <STM32_PINMUX('B', 4, AF9)>, /* SDMMC2_D3 */
+ <STM32_PINMUX('G', 6, AF10)>; /* SDMMC2_CMD */
+ slew-rate = <1>;
+ drive-push-pull;
+ bias-pull-up;
+ };
+ pins2 {
+ pinmux = <STM32_PINMUX('E', 3, AF9)>; /* SDMMC2_CK */
+ slew-rate = <2>;
+ drive-push-pull;
+ bias-pull-up;
+ };
+ };
+
+ sdmmc2_b4_pins_b: sdmmc2-b4-1 {
+ pins1 {
+ pinmux = <STM32_PINMUX('B', 14, AF9)>, /* SDMMC2_D0 */
+ <STM32_PINMUX('B', 15, AF9)>, /* SDMMC2_D1 */
+ <STM32_PINMUX('B', 3, AF9)>, /* SDMMC2_D2 */
+ <STM32_PINMUX('B', 4, AF9)>, /* SDMMC2_D3 */
+ <STM32_PINMUX('G', 6, AF10)>; /* SDMMC2_CMD */
+ slew-rate = <1>;
+ drive-push-pull;
+ bias-disable;
+ };
+ pins2 {
+ pinmux = <STM32_PINMUX('E', 3, AF9)>; /* SDMMC2_CK */
+ slew-rate = <2>;
+ drive-push-pull;
+ bias-disable;
+ };
+ };
+
+ sdmmc2_d47_pins_a: sdmmc2-d47-0 {
+ pins {
+ pinmux = <STM32_PINMUX('A', 8, AF9)>, /* SDMMC2_D4 */
+ <STM32_PINMUX('A', 9, AF10)>, /* SDMMC2_D5 */
+ <STM32_PINMUX('E', 5, AF9)>, /* SDMMC2_D6 */
+ <STM32_PINMUX('D', 3, AF9)>; /* SDMMC2_D7 */
+ slew-rate = <1>;
+ drive-push-pull;
+ bias-pull-up;
+ };
+ };
+
+ uart4_pins_a: uart4-0 {
+ pins1 {
+ pinmux = <STM32_PINMUX('G', 11, AF6)>; /* UART4_TX */
+ bias-disable;
+ drive-push-pull;
+ slew-rate = <0>;
+ };
+ pins2 {
+ pinmux = <STM32_PINMUX('B', 2, AF8)>; /* UART4_RX */
+ bias-disable;
+ };
+ };
+
+ uart4_pins_b: uart4-1 {
+ pins1 {
+ pinmux = <STM32_PINMUX('D', 1, AF8)>; /* UART4_TX */
+ bias-disable;
+ drive-push-pull;
+ slew-rate = <0>;
+ };
+ pins2 {
+ pinmux = <STM32_PINMUX('B', 2, AF8)>; /* UART4_RX */
+ bias-disable;
+ };
+ };
+
+ uart7_pins_a: uart7-0 {
+ pins1 {
+ pinmux = <STM32_PINMUX('E', 8, AF7)>; /* UART4_TX */
+ bias-disable;
+ drive-push-pull;
+ slew-rate = <0>;
+ };
+ pins2 {
+ pinmux = <STM32_PINMUX('E', 7, AF7)>, /* UART4_RX */
+ <STM32_PINMUX('E', 10, AF7)>, /* UART4_CTS */
+ <STM32_PINMUX('E', 9, AF7)>; /* UART4_RTS */
+ bias-disable;
+ };
+ };
+
+ uart7_pins_b: uart7-1 {
+ pins1 {
+ pinmux = <STM32_PINMUX('E', 8, AF7)>; /* USART7_TX */
+ bias-disable;
+ drive-push-pull;
+ slew-rate = <0>;
+ };
+ pins2 {
+ pinmux = <STM32_PINMUX('E', 7, AF7)>; /* USART7_RX */
+ bias-disable;
+ };
+ };
+
+ usart2_pins_a: usart2-0 {
+ pins1 {
+ pinmux = <STM32_PINMUX('D', 5, AF7)>, /* USART2_TX */
+ <STM32_PINMUX('D', 4, AF7)>; /* USART2_RTS */
+ bias-disable;
+ drive-push-pull;
+ slew-rate = <3>;
+ };
+ pins2 {
+ pinmux = <STM32_PINMUX('D', 6, AF7)>, /* USART2_RX */
+ <STM32_PINMUX('D', 3, AF7)>; /* USART2_CTS_NSS */
+ bias-disable;
+ };
+ };
+
+ usart3_pins_a: usart3-0 {
+ pins1 {
+ pinmux = <STM32_PINMUX('B', 10, AF7)>, /* USART3_TX */
+ <STM32_PINMUX('G', 8, AF8)>; /* USART3_RTS */
+ bias-disable;
+ drive-push-pull;
+ slew-rate = <0>;
+ };
+ pins2 {
+ pinmux = <STM32_PINMUX('B', 12, AF8)>, /* USART3_RX */
+ <STM32_PINMUX('I', 10, AF8)>; /* USART3_CTS_NSS */
+ bias-disable;
+ };
+ };
+
+ usart3_pins_b: usart3-1 {
+ pins1 {
+ pinmux = <STM32_PINMUX('B', 10, AF7)>, /* USART3_TX */
+ <STM32_PINMUX('G', 8, AF8)>; /* USART3_RTS */
+ bias-disable;
+ drive-push-pull;
+ slew-rate = <0>;
+ };
+ pins2 {
+ pinmux = <STM32_PINMUX('B', 12, AF8)>, /* USART3_RX */
+ <STM32_PINMUX('B', 13, AF7)>; /* USART3_CTS_NSS */
+ bias-disable;
+ };
+ };
+
+ usbotg_hs_pins_a: usbotg_hs-0 {
+ pins {
+ pinmux = <STM32_PINMUX('A', 10, ANALOG)>; /* OTG_ID */
+ };
+ };
+
+ usbotg_fs_dp_dm_pins_a: usbotg-fs-dp-dm-0 {
+ pins {
+ pinmux = <STM32_PINMUX('A', 11, ANALOG)>, /* OTG_FS_DM */
+ <STM32_PINMUX('A', 12, ANALOG)>; /* OTG_FS_DP */
+ };
+ };
+};
+
+&pinctrl_z {
+ i2c4_pins_a: i2c4-0 {
+ pins {
+ pinmux = <STM32_PINMUX('Z', 4, AF6)>, /* I2C4_SCL */
+ <STM32_PINMUX('Z', 5, AF6)>; /* I2C4_SDA */
+ bias-disable;
+ drive-open-drain;
+ slew-rate = <0>;
+ };
+ };
+};
diff --git a/fdts/stm32mp151.dtsi b/fdts/stm32mp151.dtsi
new file mode 100644
index 000000000..6e6dff4f7
--- /dev/null
+++ b/fdts/stm32mp151.dtsi
@@ -0,0 +1,683 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
+/*
+ * Copyright (C) STMicroelectronics 2017 - All Rights Reserved
+ * Author: Ludovic Barre <ludovic.barre@st.com> for STMicroelectronics.
+ */
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/clock/stm32mp1-clks.h>
+#include <dt-bindings/reset/stm32mp1-resets.h>
+
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ cpu0: cpu@0 {
+ compatible = "arm,cortex-a7";
+ device_type = "cpu";
+ reg = <0>;
+ clocks = <&rcc CK_MPU>;
+ clock-names = "cpu";
+ operating-points-v2 = <&cpu0_opp_table>;
+ nvmem-cells = <&part_number_otp>;
+ nvmem-cell-names = "part_number";
+ };
+ };
+
+ cpu0_opp_table: cpu0-opp-table {
+ compatible = "operating-points-v2";
+ opp-shared;
+ };
+
+ nvmem_layout: nvmem_layout@0 {
+ compatible = "st,stm32-nvmem-layout";
+
+ nvmem-cells = <&cfg0_otp>,
+ <&part_number_otp>,
+ <&monotonic_otp>,
+ <&nand_otp>,
+ <&uid_otp>,
+ <&package_otp>,
+ <&hw2_otp>;
+
+ nvmem-cell-names = "cfg0_otp",
+ "part_number_otp",
+ "monotonic_otp",
+ "nand_otp",
+ "uid_otp",
+ "package_otp",
+ "hw2_otp";
+ };
+
+ psci {
+ compatible = "arm,psci-1.0";
+ method = "smc";
+ };
+
+ intc: interrupt-controller@a0021000 {
+ compatible = "arm,cortex-a7-gic";
+ #interrupt-cells = <3>;
+ interrupt-controller;
+ reg = <0xa0021000 0x1000>,
+ <0xa0022000 0x2000>;
+ };
+
+ clocks {
+ clk_hse: clk-hse {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <24000000>;
+ };
+
+ clk_hsi: clk-hsi {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <64000000>;
+ };
+
+ clk_lse: clk-lse {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <32768>;
+ };
+
+ clk_lsi: clk-lsi {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <32000>;
+ };
+
+ clk_csi: clk-csi {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <4000000>;
+ };
+ };
+
+ 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";
+ secure-status = "disabled";
+ };
+
+ usart2: serial@4000e000 {
+ compatible = "st,stm32h7-uart";
+ reg = <0x4000e000 0x400>;
+ interrupts = <GIC_SPI 38 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&rcc USART2_K>;
+ resets = <&rcc USART2_R>;
+ status = "disabled";
+ };
+
+ usart3: serial@4000f000 {
+ compatible = "st,stm32h7-uart";
+ reg = <0x4000f000 0x400>;
+ interrupts = <GIC_SPI 39 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&rcc USART3_K>;
+ resets = <&rcc USART3_R>;
+ status = "disabled";
+ };
+
+ uart4: serial@40010000 {
+ compatible = "st,stm32h7-uart";
+ reg = <0x40010000 0x400>;
+ interrupts-extended = <&exti 30 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&rcc UART4_K>;
+ resets = <&rcc UART4_R>;
+ wakeup-source;
+ status = "disabled";
+ };
+
+ uart5: serial@40011000 {
+ compatible = "st,stm32h7-uart";
+ reg = <0x40011000 0x400>;
+ interrupts = <GIC_SPI 53 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&rcc UART5_K>;
+ resets = <&rcc UART5_R>;
+ status = "disabled";
+ };
+
+ uart7: serial@40018000 {
+ compatible = "st,stm32h7-uart";
+ reg = <0x40018000 0x400>;
+ interrupts = <GIC_SPI 82 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&rcc UART7_K>;
+ resets = <&rcc UART7_R>;
+ status = "disabled";
+ };
+
+ uart8: serial@40019000 {
+ compatible = "st,stm32h7-uart";
+ reg = <0x40019000 0x400>;
+ interrupts = <GIC_SPI 83 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&rcc UART8_K>;
+ resets = <&rcc UART8_R>;
+ status = "disabled";
+ };
+
+ usart6: serial@44003000 {
+ compatible = "st,stm32h7-uart";
+ reg = <0x44003000 0x400>;
+ interrupts = <GIC_SPI 71 IRQ_TYPE_LEVEL_HIGH>;
+ 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";
+ secure-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";
+ interrupts = <GIC_SPI 98 IRQ_TYPE_LEVEL_HIGH>;
+ g-rx-fifo-size = <512>;
+ g-np-tx-fifo-size = <32>;
+ g-tx-fifo-size = <256 16 16 16 16 16 16 16>;
+ dr_mode = "otg";
+ usb33d-supply = <&usb33>;
+ status = "disabled";
+ };
+
+ rcc: rcc@50000000 {
+ compatible = "st,stm32mp1-rcc", "syscon";
+ reg = <0x50000000 0x1000>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ #clock-cells = <1>;
+ #reset-cells = <1>;
+ interrupts = <GIC_SPI 5 IRQ_TYPE_LEVEL_HIGH>;
+ secure-interrupts = <GIC_SPI 145 IRQ_TYPE_LEVEL_HIGH>;
+ secure-interrupt-names = "wakeup";
+ };
+
+ pwr_regulators: pwr@50001000 {
+ compatible = "st,stm32mp1,pwr-reg";
+ reg = <0x50001000 0x10>;
+ st,tzcr = <&rcc 0x0 0x1>;
+
+ reg11: reg11 {
+ regulator-name = "reg11";
+ regulator-min-microvolt = <1100000>;
+ regulator-max-microvolt = <1100000>;
+ };
+
+ reg18: reg18 {
+ regulator-name = "reg18";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ };
+
+ usb33: usb33 {
+ regulator-name = "usb33";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ };
+ };
+
+ pwr_mcu: pwr_mcu@50001014 {
+ compatible = "syscon";
+ reg = <0x50001014 0x4>;
+ };
+
+ pwr_irq: pwr@50001020 {
+ compatible = "st,stm32mp1-pwr";
+ reg = <0x50001020 0x100>;
+ interrupts = <GIC_SPI 149 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-controller;
+ #interrupt-cells = <3>;
+ };
+
+ 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_irq>;
+ st,irq-number = <6>;
+ };
+ };
+
+ syscfg: syscon@50020000 {
+ compatible = "st,stm32mp157-syscfg", "syscon";
+ reg = <0x50020000 0x400>;
+ clocks = <&rcc SYSCFG>;
+ };
+
+ hash1: hash@54002000 {
+ compatible = "st,stm32f756-hash";
+ reg = <0x54002000 0x400>;
+ interrupts = <GIC_SPI 80 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&rcc HASH1>;
+ resets = <&rcc HASH1_R>;
+ status = "disabled";
+ secure-status = "disabled";
+ };
+
+ rng1: rng@54003000 {
+ compatible = "st,stm32-rng";
+ reg = <0x54003000 0x400>;
+ clocks = <&rcc RNG1_K>;
+ resets = <&rcc RNG1_R>;
+ status = "disabled";
+ secure-status = "disabled";
+ };
+
+ fmc: nand-controller@58002000 {
+ compatible = "st,stm32mp15-fmc2";
+ reg = <0x58002000 0x1000>,
+ <0x80000000 0x1000>,
+ <0x88010000 0x1000>,
+ <0x88020000 0x1000>,
+ <0x81000000 0x1000>,
+ <0x89010000 0x1000>,
+ <0x89020000 0x1000>;
+ interrupts = <GIC_SPI 48 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&rcc FMC_K>;
+ resets = <&rcc FMC_R>;
+ status = "disabled";
+ };
+
+ qspi: spi@58003000 {
+ compatible = "st,stm32f469-qspi";
+ reg = <0x58003000 0x1000>, <0x70000000 0x10000000>;
+ reg-names = "qspi", "qspi_mm";
+ interrupts = <GIC_SPI 92 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&rcc QSPI_K>;
+ resets = <&rcc QSPI_R>;
+ status = "disabled";
+ };
+
+ sdmmc1: sdmmc@58005000 {
+ compatible = "st,stm32-sdmmc2", "arm,pl18x", "arm,primecell";
+ arm,primecell-periphid = <0x00253180>;
+ reg = <0x58005000 0x1000>, <0x58006000 0x1000>;
+ interrupts = <GIC_SPI 49 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "cmd_irq";
+ clocks = <&rcc SDMMC1_K>;
+ clock-names = "apb_pclk";
+ resets = <&rcc SDMMC1_R>;
+ cap-sd-highspeed;
+ cap-mmc-highspeed;
+ max-frequency = <120000000>;
+ status = "disabled";
+ };
+
+ sdmmc2: sdmmc@58007000 {
+ compatible = "st,stm32-sdmmc2", "arm,pl18x", "arm,primecell";
+ arm,primecell-periphid = <0x00253180>;
+ reg = <0x58007000 0x1000>, <0x58008000 0x1000>;
+ interrupts = <GIC_SPI 124 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "cmd_irq";
+ clocks = <&rcc SDMMC2_K>;
+ clock-names = "apb_pclk";
+ resets = <&rcc SDMMC2_R>;
+ cap-sd-highspeed;
+ cap-mmc-highspeed;
+ max-frequency = <120000000>;
+ status = "disabled";
+ };
+
+ iwdg2: watchdog@5a002000 {
+ compatible = "st,stm32mp1-iwdg";
+ reg = <0x5a002000 0x400>;
+ secure-interrupts = <GIC_SPI 151 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&rcc IWDG2>, <&rcc CK_LSI>;
+ clock-names = "pclk", "lsi";
+ status = "disabled";
+ secure-status = "disabled";
+ };
+
+ usbphyc: usbphyc@5a006000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ #clock-cells = <0>;
+ compatible = "st,stm32mp1-usbphyc";
+ reg = <0x5a006000 0x1000>;
+ clocks = <&rcc USBPHY_K>;
+ resets = <&rcc USBPHY_R>;
+ vdda1v1-supply = <&reg11>;
+ vdda1v8-supply = <&reg18>;
+ status = "disabled";
+
+ usbphyc_port0: usb-phy@0 {
+ #phy-cells = <0>;
+ reg = <0>;
+ };
+
+ usbphyc_port1: usb-phy@1 {
+ #phy-cells = <1>;
+ reg = <1>;
+ };
+ };
+
+ usart1: serial@5c000000 {
+ compatible = "st,stm32h7-uart";
+ reg = <0x5c000000 0x400>;
+ interrupts = <GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&rcc USART1_K>;
+ resets = <&rcc USART1_R>;
+ status = "disabled";
+ secure-status = "disabled";
+ };
+
+ spi6: spi@5c001000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "st,stm32h7-spi";
+ reg = <0x5c001000 0x400>;
+ interrupts = <GIC_SPI 86 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&rcc SPI6_K>;
+ resets = <&rcc SPI6_R>;
+ status = "disabled";
+ secure-status = "disabled";
+ };
+
+ i2c4: i2c@5c002000 {
+ compatible = "st,stm32mp15-i2c";
+ reg = <0x5c002000 0x400>;
+ interrupt-names = "event", "error";
+ interrupts-extended = <&exti 24 IRQ_TYPE_LEVEL_HIGH>,
+ <&intc GIC_SPI 96 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&rcc I2C4_K>;
+ resets = <&rcc I2C4_R>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ st,syscfg-fmp = <&syscfg 0x4 0x8>;
+ wakeup-source;
+ status = "disabled";
+ secure-status = "disabled";
+ };
+
+ iwdg1: watchdog@5c003000 {
+ compatible = "st,stm32mp1-iwdg";
+ reg = <0x5C003000 0x400>;
+ interrupts = <GIC_SPI 150 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&rcc IWDG1>, <&rcc CK_LSI>;
+ clock-names = "pclk", "lsi";
+ status = "disabled";
+ secure-status = "disabled";
+ };
+
+ rtc: rtc@5c004000 {
+ compatible = "st,stm32mp1-rtc";
+ reg = <0x5c004000 0x400>;
+ clocks = <&rcc RTCAPB>, <&rcc RTC>;
+ clock-names = "pclk", "rtc_ck";
+ interrupts-extended = <&exti 19 IRQ_TYPE_LEVEL_HIGH>;
+ status = "disabled";
+ secure-status = "disabled";
+ };
+
+ bsec: nvmem@5c005000 {
+ compatible = "st,stm32mp15-bsec";
+ reg = <0x5c005000 0x400>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ cfg0_otp: cfg0_otp@0 {
+ reg = <0x0 0x1>;
+ };
+ part_number_otp: part_number_otp@4 {
+ reg = <0x4 0x1>;
+ };
+ monotonic_otp: monotonic_otp@10 {
+ reg = <0x10 0x4>;
+ };
+ nand_otp: nand_otp@24 {
+ reg = <0x24 0x4>;
+ };
+ uid_otp: uid_otp@34 {
+ reg = <0x34 0xc>;
+ };
+ package_otp: package_otp@40 {
+ reg = <0x40 0x4>;
+ };
+ hw2_otp: hw2_otp@48 {
+ reg = <0x48 0x4>;
+ };
+ ts_cal1: calib@5c {
+ reg = <0x5c 0x2>;
+ };
+ ts_cal2: calib@5e {
+ reg = <0x5e 0x2>;
+ };
+ pkh_otp: pkh_otp@60 {
+ reg = <0x60 0x20>;
+ };
+ mac_addr: mac_addr@e4 {
+ reg = <0xe4 0x8>;
+ st,non-secure-otp;
+ };
+ };
+
+ 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>;
+ };
+
+ i2c6: i2c@5c009000 {
+ compatible = "st,stm32mp15-i2c";
+ reg = <0x5c009000 0x400>;
+ interrupt-names = "event", "error";
+ interrupts-extended = <&exti 54 IRQ_TYPE_LEVEL_HIGH>,
+ <&intc GIC_SPI 136 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&rcc I2C6_K>;
+ resets = <&rcc I2C6_R>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ st,syscfg-fmp = <&syscfg 0x4 0x20>;
+ wakeup-source;
+ status = "disabled";
+ secure-status = "disabled";
+ };
+
+ tamp: tamp@5c00a000 {
+ compatible = "st,stm32-tamp", "simple-bus", "syscon", "simple-mfd";
+ reg = <0x5c00a000 0x400>;
+ secure-interrupts = <GIC_SPI 197 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&rcc RTCAPB>;
+ };
+
+ /*
+ * Break node order to solve dependency probe issue between
+ * pinctrl and exti.
+ */
+ pinctrl: pin-controller@50002000 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "st,stm32mp157-pinctrl";
+ ranges = <0 0x50002000 0xa400>;
+ interrupt-parent = <&exti>;
+ st,syscfg = <&exti 0x60 0xff>;
+ pins-are-numbered;
+
+ gpioa: gpio@50002000 {
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ reg = <0x0 0x400>;
+ clocks = <&rcc GPIOA>;
+ st,bank-name = "GPIOA";
+ status = "disabled";
+ };
+
+ gpiob: gpio@50003000 {
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ reg = <0x1000 0x400>;
+ clocks = <&rcc GPIOB>;
+ st,bank-name = "GPIOB";
+ status = "disabled";
+ };
+
+ gpioc: gpio@50004000 {
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ reg = <0x2000 0x400>;
+ clocks = <&rcc GPIOC>;
+ st,bank-name = "GPIOC";
+ status = "disabled";
+ };
+
+ gpiod: gpio@50005000 {
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ reg = <0x3000 0x400>;
+ clocks = <&rcc GPIOD>;
+ st,bank-name = "GPIOD";
+ status = "disabled";
+ };
+
+ gpioe: gpio@50006000 {
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ reg = <0x4000 0x400>;
+ clocks = <&rcc GPIOE>;
+ st,bank-name = "GPIOE";
+ status = "disabled";
+ };
+
+ gpiof: gpio@50007000 {
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ reg = <0x5000 0x400>;
+ clocks = <&rcc GPIOF>;
+ st,bank-name = "GPIOF";
+ status = "disabled";
+ };
+
+ gpiog: gpio@50008000 {
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ reg = <0x6000 0x400>;
+ clocks = <&rcc GPIOG>;
+ st,bank-name = "GPIOG";
+ status = "disabled";
+ };
+
+ gpioh: gpio@50009000 {
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ reg = <0x7000 0x400>;
+ clocks = <&rcc GPIOH>;
+ st,bank-name = "GPIOH";
+ status = "disabled";
+ };
+
+ gpioi: gpio@5000a000 {
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ reg = <0x8000 0x400>;
+ clocks = <&rcc GPIOI>;
+ st,bank-name = "GPIOI";
+ status = "disabled";
+ };
+
+ gpioj: gpio@5000b000 {
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ reg = <0x9000 0x400>;
+ clocks = <&rcc GPIOJ>;
+ st,bank-name = "GPIOJ";
+ status = "disabled";
+ };
+
+ gpiok: gpio@5000c000 {
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ reg = <0xa000 0x400>;
+ clocks = <&rcc GPIOK>;
+ st,bank-name = "GPIOK";
+ status = "disabled";
+ };
+ };
+
+ pinctrl_z: pin-controller-z@54004000 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "st,stm32mp157-z-pinctrl";
+ ranges = <0 0x54004000 0x400>;
+ pins-are-numbered;
+ interrupt-parent = <&exti>;
+ st,syscfg = <&exti 0x60 0xff>;
+
+ gpioz: gpio@54004000 {
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ reg = <0 0x400>;
+ clocks = <&rcc GPIOZ>;
+ st,bank-name = "GPIOZ";
+ st,bank-ioport = <11>;
+ status = "disabled";
+ secure-status = "disabled";
+ };
+ };
+ };
+};
diff --git a/fdts/stm32mp153.dtsi b/fdts/stm32mp153.dtsi
new file mode 100644
index 000000000..617380a52
--- /dev/null
+++ b/fdts/stm32mp153.dtsi
@@ -0,0 +1,20 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
+/*
+ * Copyright (C) STMicroelectronics 2019 - All Rights Reserved
+ * Author: Alexandre Torgue <alexandre.torgue@st.com> for STMicroelectronics.
+ */
+
+#include "stm32mp151.dtsi"
+
+/ {
+ cpus {
+ cpu1: cpu@1 {
+ compatible = "arm,cortex-a7";
+ device_type = "cpu";
+ reg = <1>;
+ clocks = <&rcc CK_MPU>;
+ clock-names = "cpu";
+ operating-points-v2 = <&cpu0_opp_table>;
+ };
+ };
+};
diff --git a/fdts/stm32mp157-pinctrl.dtsi b/fdts/stm32mp157-pinctrl.dtsi
deleted file mode 100644
index 8e480b2c1..000000000
--- a/fdts/stm32mp157-pinctrl.dtsi
+++ /dev/null
@@ -1,348 +0,0 @@
-// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
-/*
- * Copyright (C) STMicroelectronics 2017 - All Rights Reserved
- * Author: Ludovic Barre <ludovic.barre@st.com> for STMicroelectronics.
- */
-#include <dt-bindings/pinctrl/stm32-pinfunc.h>
-
-/ {
- soc {
- pinctrl: pin-controller@50002000 {
- #address-cells = <1>;
- #size-cells = <1>;
- compatible = "st,stm32mp157-pinctrl";
- ranges = <0 0x50002000 0xa400>;
- pins-are-numbered;
-
- gpioa: gpio@50002000 {
- gpio-controller;
- #gpio-cells = <2>;
- interrupt-controller;
- #interrupt-cells = <2>;
- reg = <0x0 0x400>;
- clocks = <&rcc GPIOA>;
- st,bank-name = "GPIOA";
- status = "disabled";
- };
-
- gpiob: gpio@50003000 {
- gpio-controller;
- #gpio-cells = <2>;
- interrupt-controller;
- #interrupt-cells = <2>;
- reg = <0x1000 0x400>;
- clocks = <&rcc GPIOB>;
- st,bank-name = "GPIOB";
- status = "disabled";
- };
-
- gpioc: gpio@50004000 {
- gpio-controller;
- #gpio-cells = <2>;
- interrupt-controller;
- #interrupt-cells = <2>;
- reg = <0x2000 0x400>;
- clocks = <&rcc GPIOC>;
- st,bank-name = "GPIOC";
- status = "disabled";
- };
-
- gpiod: gpio@50005000 {
- gpio-controller;
- #gpio-cells = <2>;
- interrupt-controller;
- #interrupt-cells = <2>;
- reg = <0x3000 0x400>;
- clocks = <&rcc GPIOD>;
- st,bank-name = "GPIOD";
- status = "disabled";
- };
-
- gpioe: gpio@50006000 {
- gpio-controller;
- #gpio-cells = <2>;
- interrupt-controller;
- #interrupt-cells = <2>;
- reg = <0x4000 0x400>;
- clocks = <&rcc GPIOE>;
- st,bank-name = "GPIOE";
- status = "disabled";
- };
-
- gpiof: gpio@50007000 {
- gpio-controller;
- #gpio-cells = <2>;
- interrupt-controller;
- #interrupt-cells = <2>;
- reg = <0x5000 0x400>;
- clocks = <&rcc GPIOF>;
- st,bank-name = "GPIOF";
- status = "disabled";
- };
-
- gpiog: gpio@50008000 {
- gpio-controller;
- #gpio-cells = <2>;
- interrupt-controller;
- #interrupt-cells = <2>;
- reg = <0x6000 0x400>;
- clocks = <&rcc GPIOG>;
- st,bank-name = "GPIOG";
- status = "disabled";
- };
-
- gpioh: gpio@50009000 {
- gpio-controller;
- #gpio-cells = <2>;
- interrupt-controller;
- #interrupt-cells = <2>;
- reg = <0x7000 0x400>;
- clocks = <&rcc GPIOH>;
- st,bank-name = "GPIOH";
- status = "disabled";
- };
-
- gpioi: gpio@5000a000 {
- gpio-controller;
- #gpio-cells = <2>;
- interrupt-controller;
- #interrupt-cells = <2>;
- reg = <0x8000 0x400>;
- clocks = <&rcc GPIOI>;
- st,bank-name = "GPIOI";
- status = "disabled";
- };
-
- gpioj: gpio@5000b000 {
- gpio-controller;
- #gpio-cells = <2>;
- interrupt-controller;
- #interrupt-cells = <2>;
- reg = <0x9000 0x400>;
- clocks = <&rcc GPIOJ>;
- st,bank-name = "GPIOJ";
- status = "disabled";
- };
-
- gpiok: gpio@5000c000 {
- gpio-controller;
- #gpio-cells = <2>;
- interrupt-controller;
- #interrupt-cells = <2>;
- reg = <0xa000 0x400>;
- clocks = <&rcc GPIOK>;
- st,bank-name = "GPIOK";
- status = "disabled";
- };
-
- qspi_bk1_pins_a: qspi-bk1-0 {
- pins1 {
- pinmux = <STM32_PINMUX('F', 8, AF10)>, /* QSPI_BK1_IO0 */
- <STM32_PINMUX('F', 9, AF10)>, /* QSPI_BK1_IO1 */
- <STM32_PINMUX('F', 7, AF9)>, /* QSPI_BK1_IO2 */
- <STM32_PINMUX('F', 6, AF9)>; /* QSPI_BK1_IO3 */
- bias-disable;
- drive-push-pull;
- slew-rate = <1>;
- };
- pins2 {
- pinmux = <STM32_PINMUX('B', 6, AF10)>; /* QSPI_BK1_NCS */
- bias-pull-up;
- drive-push-pull;
- slew-rate = <1>;
- };
- };
-
- qspi_bk2_pins_a: qspi-bk2-0 {
- pins1 {
- pinmux = <STM32_PINMUX('H', 2, AF9)>, /* QSPI_BK2_IO0 */
- <STM32_PINMUX('H', 3, AF9)>, /* QSPI_BK2_IO1 */
- <STM32_PINMUX('G', 10, AF11)>, /* QSPI_BK2_IO2 */
- <STM32_PINMUX('G', 7, AF11)>; /* QSPI_BK2_IO3 */
- bias-disable;
- drive-push-pull;
- slew-rate = <1>;
- };
- pins2 {
- pinmux = <STM32_PINMUX('C', 0, AF10)>; /* QSPI_BK2_NCS */
- bias-pull-up;
- drive-push-pull;
- slew-rate = <1>;
- };
- };
-
- qspi_clk_pins_a: qspi-clk-0 {
- pins {
- pinmux = <STM32_PINMUX('F', 10, AF9)>; /* QSPI_CLK */
- bias-disable;
- drive-push-pull;
- slew-rate = <3>;
- };
- };
-
- sdmmc1_b4_pins_a: sdmmc1-b4-0 {
- pins1 {
- pinmux = <STM32_PINMUX('C', 8, AF12)>, /* SDMMC1_D0 */
- <STM32_PINMUX('C', 9, AF12)>, /* SDMMC1_D1 */
- <STM32_PINMUX('C', 10, AF12)>, /* SDMMC1_D2 */
- <STM32_PINMUX('C', 11, AF12)>, /* SDMMC1_D3 */
- <STM32_PINMUX('D', 2, AF12)>; /* SDMMC1_CMD */
- slew-rate = <1>;
- drive-push-pull;
- bias-disable;
- };
- pins2 {
- pinmux = <STM32_PINMUX('C', 12, AF12)>; /* SDMMC1_CK */
- slew-rate = <2>;
- drive-push-pull;
- bias-disable;
- };
- };
-
- sdmmc1_dir_pins_a: sdmmc1-dir-0 {
- pins1 {
- pinmux = <STM32_PINMUX('F', 2, AF11)>, /* SDMMC1_D0DIR */
- <STM32_PINMUX('C', 7, AF8)>, /* SDMMC1_D123DIR */
- <STM32_PINMUX('B', 9, AF11)>; /* SDMMC1_CDIR */
- slew-rate = <1>;
- drive-push-pull;
- bias-pull-up;
- };
- pins2{
- pinmux = <STM32_PINMUX('E', 4, AF8)>; /* SDMMC1_CKIN */
- bias-pull-up;
- };
- };
-
- sdmmc2_b4_pins_a: sdmmc2-b4-0 {
- pins1 {
- pinmux = <STM32_PINMUX('B', 14, AF9)>, /* SDMMC2_D0 */
- <STM32_PINMUX('B', 15, AF9)>, /* SDMMC2_D1 */
- <STM32_PINMUX('B', 3, AF9)>, /* SDMMC2_D2 */
- <STM32_PINMUX('B', 4, AF9)>, /* SDMMC2_D3 */
- <STM32_PINMUX('G', 6, AF10)>; /* SDMMC2_CMD */
- slew-rate = <1>;
- drive-push-pull;
- bias-pull-up;
- };
- pins2 {
- pinmux = <STM32_PINMUX('E', 3, AF9)>; /* SDMMC2_CK */
- slew-rate = <2>;
- drive-push-pull;
- bias-pull-up;
- };
- };
-
- sdmmc2_d47_pins_a: sdmmc2-d47-0 {
- pins {
- pinmux = <STM32_PINMUX('A', 8, AF9)>, /* SDMMC2_D4 */
- <STM32_PINMUX('A', 9, AF10)>, /* SDMMC2_D5 */
- <STM32_PINMUX('E', 5, AF9)>, /* SDMMC2_D6 */
- <STM32_PINMUX('D', 3, AF9)>; /* SDMMC2_D7 */
- slew-rate = <1>;
- drive-push-pull;
- bias-pull-up;
- };
- };
-
- uart4_pins_a: uart4-0 {
- pins1 {
- pinmux = <STM32_PINMUX('G', 11, AF6)>; /* UART4_TX */
- bias-disable;
- drive-push-pull;
- slew-rate = <0>;
- };
- pins2 {
- pinmux = <STM32_PINMUX('B', 2, AF8)>; /* UART4_RX */
- bias-disable;
- };
- };
-
- uart4_pins_b: uart4-1 {
- pins1 {
- pinmux = <STM32_PINMUX('D', 1, AF8)>; /* UART4_TX */
- bias-disable;
- drive-push-pull;
- slew-rate = <0>;
- };
- pins2 {
- pinmux = <STM32_PINMUX('B', 2, AF8)>; /* UART4_RX */
- bias-disable;
- };
- };
-
- uart7_pins_a: uart7-0 {
- pins1 {
- pinmux = <STM32_PINMUX('E', 8, AF7)>; /* USART7_TX */
- bias-disable;
- drive-push-pull;
- slew-rate = <0>;
- };
- pins2 {
- pinmux = <STM32_PINMUX('E', 7, AF7)>; /* USART7_RX */
- bias-disable;
- };
- };
-
- usart3_pins_a: usart3-0 {
- pins1 {
- pinmux = <STM32_PINMUX('B', 10, AF7)>, /* USART3_TX */
- <STM32_PINMUX('G', 8, AF8)>; /* USART3_RTS */
- bias-disable;
- drive-push-pull;
- slew-rate = <0>;
- };
- pins2 {
- pinmux = <STM32_PINMUX('B', 12, AF8)>, /* USART3_RX */
- <STM32_PINMUX('I', 10, AF8)>; /* USART3_CTS_NSS */
- bias-disable;
- };
- };
-
- usart3_pins_b: usart3-1 {
- pins1 {
- pinmux = <STM32_PINMUX('B', 10, AF7)>, /* USART3_TX */
- <STM32_PINMUX('G', 8, AF8)>; /* USART3_RTS */
- bias-disable;
- drive-push-pull;
- slew-rate = <0>;
- };
- pins2 {
- pinmux = <STM32_PINMUX('B', 12, AF8)>, /* USART3_RX */
- <STM32_PINMUX('B', 13, AF7)>; /* USART3_CTS_NSS */
- bias-disable;
- };
- };
- };
-
- pinctrl_z: pin-controller-z@54004000 {
- #address-cells = <1>;
- #size-cells = <1>;
- compatible = "st,stm32mp157-z-pinctrl";
- ranges = <0 0x54004000 0x400>;
- pins-are-numbered;
-
- gpioz: gpio@54004000 {
- gpio-controller;
- #gpio-cells = <2>;
- interrupt-controller;
- #interrupt-cells = <2>;
- reg = <0 0x400>;
- clocks = <&rcc GPIOZ>;
- st,bank-name = "GPIOZ";
- st,bank-ioport = <11>;
- status = "disabled";
- };
-
- i2c4_pins_a: i2c4-0 {
- pins {
- pinmux = <STM32_PINMUX('Z', 4, AF6)>, /* I2C4_SCL */
- <STM32_PINMUX('Z', 5, AF6)>; /* I2C4_SDA */
- bias-disable;
- drive-open-drain;
- slew-rate = <0>;
- };
- };
- };
- };
-};
diff --git a/fdts/stm32mp157.dtsi b/fdts/stm32mp157.dtsi
new file mode 100644
index 000000000..c83402907
--- /dev/null
+++ b/fdts/stm32mp157.dtsi
@@ -0,0 +1,7 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
+/*
+ * Copyright (C) STMicroelectronics 2019 - All Rights Reserved
+ * Author: Alexandre Torgue <alexandre.torgue@st.com> for STMicroelectronics.
+ */
+
+#include "stm32mp153.dtsi"
diff --git a/fdts/stm32mp157a-avenger96.dts b/fdts/stm32mp157a-avenger96.dts
index 907940c78..d9b3d1d8f 100644
--- a/fdts/stm32mp157a-avenger96.dts
+++ b/fdts/stm32mp157a-avenger96.dts
@@ -9,21 +9,49 @@
/dts-v1/;
-#include "stm32mp157c.dtsi"
-#include "stm32mp157cac-pinctrl.dtsi"
+#include "stm32mp157.dtsi"
+#include "stm32mp15xa.dtsi"
+#include "stm32mp15-pinctrl.dtsi"
+#include "stm32mp15xxac-pinctrl.dtsi"
+#include <dt-bindings/clock/stm32mp1-clksrc.h>
+#include <dt-bindings/power/stm32mp1-power.h>
+#include <dt-bindings/soc/st,stm32-etzpc.h>
+#include "stm32mp15-ddr3-2x4Gb-1066-binG.dtsi"
/ {
model = "Arrow Electronics STM32MP157A Avenger96 board";
- compatible = "st,stm32mp157a-avenger96", "st,stm32mp157";
+ compatible = "arrow,stm32mp157a-avenger96", "st,stm32mp157";
aliases {
+ mmc0 = &sdmmc1;
serial0 = &uart4;
+ serial1 = &uart7;
};
chosen {
stdout-path = "serial0:115200n8";
};
+ memory@c0000000 {
+ device_type = "memory";
+ reg = <0xc0000000 0x40000000>;
+ };
+};
+
+&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_DDRCTRL_ID, DECPROT_S_RW, DECPROT_LOCK)
+ DECPROT(STM32MP1_ETZPC_DDRPHYC_ID, DECPROT_S_RW, DECPROT_LOCK)
+ DECPROT(STM32MP1_ETZPC_STGENC_ID, DECPROT_S_RW, DECPROT_LOCK)
+ DECPROT(STM32MP1_ETZPC_BKPSRAM_ID, DECPROT_S_RW, DECPROT_LOCK)
+ DECPROT(STM32MP1_ETZPC_IWDG1_ID, DECPROT_S_RW, DECPROT_LOCK)
+ >;
};
&i2c4 {
@@ -43,16 +71,17 @@
st,main-control-register = <0x04>;
st,vin-control-register = <0xc0>;
- st,usb-control-register = <0x20>;
+ st,usb-control-register = <0x30>;
regulators {
compatible = "st,stpmic1-regulators";
-
ldo1-supply = <&v3v3>;
ldo2-supply = <&v3v3>;
ldo3-supply = <&vdd_ddr>;
ldo5-supply = <&v3v3>;
ldo6-supply = <&v3v3>;
+ pwr_sw1-supply = <&bst_out>;
+ pwr_sw2-supply = <&bst_out>;
vddcore: buck1 {
regulator-name = "vddcore";
@@ -61,6 +90,16 @@
regulator-always-on;
regulator-initial-mode = <0>;
regulator-over-current-protection;
+ 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: buck2 {
@@ -70,6 +109,17 @@
regulator-always-on;
regulator-initial-mode = <0>;
regulator-over-current-protection;
+ 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: buck3 {
@@ -80,6 +130,18 @@
st,mask-reset;
regulator-initial-mode = <0>;
regulator-over-current-protection;
+ 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: buck4 {
@@ -89,18 +151,36 @@
regulator-always-on;
regulator-over-current-protection;
regulator-initial-mode = <0>;
+ standby-ddr-sr {
+ regulator-off-in-suspend;
+ };
+ standby-ddr-off {
+ regulator-off-in-suspend;
+ };
};
vdda: ldo1 {
regulator-name = "vdda";
regulator-min-microvolt = <2900000>;
regulator-max-microvolt = <2900000>;
+ standby-ddr-sr {
+ regulator-off-in-suspend;
+ };
+ standby-ddr-off {
+ regulator-off-in-suspend;
+ };
};
v2v8: ldo2 {
regulator-name = "v2v8";
regulator-min-microvolt = <2800000>;
regulator-max-microvolt = <2800000>;
+ standby-ddr-sr {
+ regulator-off-in-suspend;
+ };
+ standby-ddr-off {
+ regulator-off-in-suspend;
+ };
};
vtt_ddr: ldo3 {
@@ -109,12 +189,27 @@
regulator-max-microvolt = <750000>;
regulator-always-on;
regulator-over-current-protection;
+ lp-stop {
+ regulator-off-in-suspend;
+ };
+ standby-ddr-sr {
+ regulator-off-in-suspend;
+ };
+ standby-ddr-off {
+ regulator-off-in-suspend;
+ };
};
vdd_usb: ldo4 {
regulator-name = "vdd_usb";
regulator-min-microvolt = <3300000>;
regulator-max-microvolt = <3300000>;
+ standby-ddr-sr {
+ regulator-off-in-suspend;
+ };
+ standby-ddr-off {
+ regulator-off-in-suspend;
+ };
};
vdd_sd: ldo5 {
@@ -122,18 +217,52 @@
regulator-min-microvolt = <2900000>;
regulator-max-microvolt = <2900000>;
regulator-boot-on;
+ standby-ddr-sr {
+ regulator-off-in-suspend;
+ };
+ standby-ddr-off {
+ regulator-off-in-suspend;
+ };
};
v1v8: ldo6 {
regulator-name = "v1v8";
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
+ standby-ddr-sr {
+ regulator-off-in-suspend;
+ };
+ standby-ddr-off {
+ regulator-off-in-suspend;
+ };
};
vref_ddr: vref_ddr {
regulator-name = "vref_ddr";
regulator-always-on;
regulator-over-current-protection;
+ lp-stop {
+ regulator-on-in-suspend;
+ };
+ standby-ddr-sr {
+ regulator-on-in-suspend;
+ };
+ standby-ddr-off {
+ regulator-off-in-suspend;
+ };
+ };
+
+ bst_out: boost {
+ regulator-name = "bst_out";
+ };
+
+ vbus_otg: pwr_sw1 {
+ regulator-name = "vbus_otg";
+ };
+
+ vbus_sw: pwr_sw2 {
+ regulator-name = "vbus_sw";
+ regulator-active-discharge = <1>;
};
};
};
@@ -142,56 +271,21 @@
&iwdg2 {
timeout-sec = <32>;
status = "okay";
+ secure-status = "okay";
};
-&rng1 {
- status = "okay";
-};
-
-&rtc {
- status = "okay";
-};
-
-&sdmmc1 {
- pinctrl-names = "default";
- pinctrl-0 = <&sdmmc1_b4_pins_a &sdmmc1_dir_pins_a>;
- broken-cd;
- st,sig-dir;
- st,neg-edge;
- st,use-ckin;
- bus-width = <4>;
- vmmc-supply = <&vdda>;
- status = "okay";
-};
-
-&uart4 {
- pinctrl-names = "default";
- pinctrl-0 = <&uart4_pins_b>;
- status = "okay";
-};
-
-/* ATF Specific */
-#include <dt-bindings/clock/stm32mp1-clksrc.h>
-#include "stm32mp15-ddr3-2x4Gb-1066-binG.dtsi"
-#include "stm32mp157c-security.dtsi"
-
-/ {
- aliases {
- gpio0 = &gpioa;
- gpio1 = &gpiob;
- gpio2 = &gpioc;
- gpio3 = &gpiod;
- gpio4 = &gpioe;
- gpio5 = &gpiof;
- gpio6 = &gpiog;
- gpio7 = &gpioh;
- gpio8 = &gpioi;
- gpio25 = &gpioz;
- i2c3 = &i2c4;
- };
+&pwr_regulators {
+ system_suspend_supported_soc_modes = <
+ STM32_PM_CSLEEP_RUN
+ STM32_PM_CSTOP_ALLOW_LP_STOP
+ STM32_PM_CSTOP_ALLOW_LPLV_STOP
+ STM32_PM_CSTOP_ALLOW_STANDBY_DDR_SR
+ >;
+ system_off_soc_mode = <STM32_PM_CSTOP_ALLOW_STANDBY_DDR_OFF>;
+ vdd-supply = <&vdd>;
+ vdd_3v3_usbfs-supply = <&vdd_usb>;
};
-/* CLOCK init */
&rcc {
secure-status = "disabled";
st,clksrc = <
@@ -260,24 +354,69 @@
/* VCO = 1300.0 MHz => P = 650 (CPU) */
pll1: st,pll@0 {
- cfg = < 2 80 0 0 0 PQR(1,0,0) >;
- frac = < 0x800 >;
+ compatible = "st,stm32mp1-pll";
+ reg = <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 >;
+ compatible = "st,stm32mp1-pll";
+ reg = <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 >;
+ compatible = "st,stm32mp1-pll";
+ reg = <2>;
+ cfg = <1 33 1 16 36 PQR(1,1,1)>;
+ frac = <0x1a04>;
};
/* VCO = 480.0 MHz => P = 120, Q = 40, R = 96 */
pll4: st,pll@3 {
- cfg = < 1 39 3 11 4 PQR(1,1,1) >;
+ compatible = "st,stm32mp1-pll";
+ reg = <3>;
+ cfg = <1 39 3 11 4 PQR(1,1,1)>;
};
};
+
+&rng1 {
+ status = "okay";
+ secure-status = "okay";
+};
+
+&rtc {
+ status = "okay";
+ secure-status = "okay";
+};
+
+&sdmmc1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&sdmmc1_b4_pins_a &sdmmc1_dir_pins_a>;
+ st,sig-dir;
+ st,neg-edge;
+ st,use-ckin;
+ bus-width = <4>;
+ vmmc-supply = <&vdd_sd>;
+ status = "okay";
+};
+
+&uart4 {
+ /* On Low speed expansion header */
+ label = "LS-UART1";
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart4_pins_b>;
+ status = "okay";
+};
+
+&uart7 {
+ /* On Low speed expansion header */
+ label = "LS-UART0";
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart7_pins_a>;
+ status = "okay";
+};
diff --git a/fdts/stm32mp157a-dk1.dts b/fdts/stm32mp157a-dk1.dts
index 4ea83f7cd..4d506bce5 100644
--- a/fdts/stm32mp157a-dk1.dts
+++ b/fdts/stm32mp157a-dk1.dts
@@ -1,13 +1,17 @@
// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
/*
- * Copyright (C) STMicroelectronics 2018-2019 - All Rights Reserved
- * Author: Alexandre Torgue <alexandre.torgue@st.com>.
+ * Copyright (C) STMicroelectronics 2019 - All Rights Reserved
+ * Author: Alexandre Torgue <alexandre.torgue@st.com> for STMicroelectronics.
*/
/dts-v1/;
-#include "stm32mp157c.dtsi"
-#include "stm32mp157cac-pinctrl.dtsi"
+#include "stm32mp157.dtsi"
+#include "stm32mp15xa.dtsi"
+#include "stm32mp15-pinctrl.dtsi"
+#include "stm32mp15xxac-pinctrl.dtsi"
+#include "stm32mp15xx-dkx.dtsi"
+#include <dt-bindings/soc/st,stm32-etzpc.h>
/ {
model = "STMicroelectronics STM32MP157A-DK1 Discovery Board";
@@ -22,290 +26,20 @@
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-regulators {
- vdd-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 <dt-bindings/clock/stm32mp1-clksrc.h>
-#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 = "disabled";
- 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
+&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_DDRCTRL_ID, DECPROT_S_RW, DECPROT_LOCK)
+ DECPROT(STM32MP1_ETZPC_DDRPHYC_ID, DECPROT_S_RW, DECPROT_LOCK)
+ DECPROT(STM32MP1_ETZPC_STGENC_ID, DECPROT_S_RW, DECPROT_LOCK)
+ DECPROT(STM32MP1_ETZPC_BKPSRAM_ID, DECPROT_S_RW, DECPROT_LOCK)
+ DECPROT(STM32MP1_ETZPC_IWDG1_ID, DECPROT_S_RW, DECPROT_LOCK)
>;
-
- 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_PLL4R
- 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) >;
- };
-};
-
-&bsec {
- board_id: board_id@ec {
- reg = <0xec 0x4>;
- status = "okay";
- secure-status = "okay";
- };
};
diff --git a/fdts/stm32mp157a-ed1.dts b/fdts/stm32mp157a-ed1.dts
new file mode 100644
index 000000000..4f84ec623
--- /dev/null
+++ b/fdts/stm32mp157a-ed1.dts
@@ -0,0 +1,46 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
+/*
+ * Copyright (C) STMicroelectronics 2019 - All Rights Reserved
+ * Author: Alexandre Torgue <alexandre.torgue@st.com> for STMicroelectronics.
+ */
+/dts-v1/;
+
+#include "stm32mp157.dtsi"
+#include "stm32mp15xa.dtsi"
+#include "stm32mp15-pinctrl.dtsi"
+#include "stm32mp15xxaa-pinctrl.dtsi"
+#include "stm32mp15xx-edx.dtsi"
+#include <dt-bindings/soc/st,stm32-etzpc.h>
+
+/ {
+ model = "STMicroelectronics STM32MP157A eval daughter";
+ compatible = "st,stm32mp157a-ed1", "st,stm32mp157";
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+
+ aliases {
+ serial0 = &uart4;
+ };
+};
+
+&cpu1 {
+ cpu-supply = <&vddcore>;
+};
+
+&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_DDRCTRL_ID, DECPROT_S_RW, DECPROT_LOCK)
+ DECPROT(STM32MP1_ETZPC_DDRPHYC_ID, DECPROT_S_RW, DECPROT_LOCK)
+ DECPROT(STM32MP1_ETZPC_STGENC_ID, DECPROT_S_RW, DECPROT_LOCK)
+ DECPROT(STM32MP1_ETZPC_BKPSRAM_ID, DECPROT_S_RW, DECPROT_LOCK)
+ DECPROT(STM32MP1_ETZPC_IWDG1_ID, DECPROT_S_RW, DECPROT_LOCK)
+ >;
+};
diff --git a/fdts/stm32mp157a-ev1.dts b/fdts/stm32mp157a-ev1.dts
new file mode 100644
index 000000000..c577a9052
--- /dev/null
+++ b/fdts/stm32mp157a-ev1.dts
@@ -0,0 +1,23 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
+/*
+ * Copyright (C) STMicroelectronics 2019 - All Rights Reserved
+ * Author: Alexandre Torgue <alexandre.torgue@st.com> for STMicroelectronics.
+ */
+/dts-v1/;
+
+#include "stm32mp157a-ed1.dts"
+#include "stm32mp15xx-evx.dtsi"
+
+/ {
+ model = "STMicroelectronics STM32MP157A eval daughter on eval mother";
+ compatible = "st,stm32mp157a-ev1", "st,stm32mp157a-ed1", "st,stm32mp157";
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+
+ aliases {
+ serial1 = &usart3;
+ };
+};
+
diff --git a/fdts/stm32mp157c-dk2.dts b/fdts/stm32mp157c-dk2.dts
index fdcf4c802..436a15970 100644
--- a/fdts/stm32mp157c-dk2.dts
+++ b/fdts/stm32mp157c-dk2.dts
@@ -1,16 +1,51 @@
// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
/*
- * Copyright (C) STMicroelectronics 2018 - All Rights Reserved
- * Author: Alexandre Torgue <alexandre.torgue@st.com>.
+ * Copyright (C) STMicroelectronics 2019 - All Rights Reserved
+ * Author: Alexandre Torgue <alexandre.torgue@st.com> for STMicroelectronics.
*/
/dts-v1/;
-#include "stm32mp157a-dk1.dts"
+#include "stm32mp157.dtsi"
+#include "stm32mp15xc.dtsi"
+#include "stm32mp15-pinctrl.dtsi"
+#include "stm32mp15xxac-pinctrl.dtsi"
+#include "stm32mp15xx-dkx.dtsi"
+#include <dt-bindings/soc/st,stm32-etzpc.h>
/ {
model = "STMicroelectronics STM32MP157C-DK2 Discovery Board";
compatible = "st,stm32mp157c-dk2", "st,stm32mp157";
+ aliases {
+ serial0 = &uart4;
+ serial1 = &usart3;
+ serial2 = &uart7;
+ serial3 = &usart2;
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+};
+
+&cryp1 {
+ status = "okay";
};
+&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)
+ DECPROT(STM32MP1_ETZPC_DDRCTRL_ID, DECPROT_S_RW, DECPROT_LOCK)
+ DECPROT(STM32MP1_ETZPC_DDRPHYC_ID, DECPROT_S_RW, DECPROT_LOCK)
+ DECPROT(STM32MP1_ETZPC_STGENC_ID, DECPROT_S_RW, DECPROT_LOCK)
+ DECPROT(STM32MP1_ETZPC_BKPSRAM_ID, DECPROT_S_RW, DECPROT_LOCK)
+ DECPROT(STM32MP1_ETZPC_IWDG1_ID, DECPROT_S_RW, DECPROT_LOCK)
+ >;
+};
diff --git a/fdts/stm32mp157c-ed1.dts b/fdts/stm32mp157c-ed1.dts
index 779492552..5aadb1ff0 100644
--- a/fdts/stm32mp157c-ed1.dts
+++ b/fdts/stm32mp157c-ed1.dts
@@ -1,12 +1,16 @@
// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
/*
- * Copyright (C) STMicroelectronics 2017-2019 - All Rights Reserved
- * Author: Ludovic Barre <ludovic.barre@st.com> for STMicroelectronics.
+ * Copyright (C) STMicroelectronics 2019 - All Rights Reserved
+ * Author: Alexandre Torgue <alexandre.torgue@st.com> for STMicroelectronics.
*/
/dts-v1/;
-#include "stm32mp157c.dtsi"
-#include "stm32mp157caa-pinctrl.dtsi"
+#include "stm32mp157.dtsi"
+#include "stm32mp15xc.dtsi"
+#include "stm32mp15-pinctrl.dtsi"
+#include "stm32mp15xxaa-pinctrl.dtsi"
+#include "stm32mp15xx-edx.dtsi"
+#include <dt-bindings/soc/st,stm32-etzpc.h>
/ {
model = "STMicroelectronics STM32MP157C eval daughter";
@@ -21,297 +25,27 @@
};
};
-&clk_hse {
- st,digbypass;
+&cpu1 {
+ cpu-supply = <&vddcore>;
};
-&i2c4 {
- pinctrl-names = "default";
- pinctrl-0 = <&i2c4_pins_a>;
- i2c-scl-rising-time-ns = <185>;
- i2c-scl-falling-time-ns = <20>;
- status = "okay";
-
- pmic: stpmic@33 {
- compatible = "st,stpmic1";
- reg = <0x33>;
- interrupts-extended = <&exti_pwr 55 IRQ_TYPE_EDGE_FALLING>;
- interrupt-controller;
- #interrupt-cells = <2>;
- status = "okay";
-
- st,main-control-register = <0x04>;
- st,vin-control-register = <0xc0>;
- st,usb-control-register = <0x20>;
-
- regulators {
- compatible = "st,stpmic1-regulators";
-
- ldo1-supply = <&v3v3>;
- ldo2-supply = <&v3v3>;
- ldo3-supply = <&vdd_ddr>;
- ldo5-supply = <&v3v3>;
- ldo6-supply = <&v3v3>;
-
- vddcore: buck1 {
- regulator-name = "vddcore";
- regulator-min-microvolt = <1200000>;
- regulator-max-microvolt = <1350000>;
- regulator-always-on;
- regulator-initial-mode = <0>;
- regulator-over-current-protection;
- };
-
- vdd_ddr: buck2 {
- regulator-name = "vdd_ddr";
- regulator-min-microvolt = <1350000>;
- regulator-max-microvolt = <1350000>;
- regulator-always-on;
- regulator-initial-mode = <0>;
- regulator-over-current-protection;
- };
-
- vdd: buck3 {
- regulator-name = "vdd";
- regulator-min-microvolt = <3300000>;
- regulator-max-microvolt = <3300000>;
- regulator-always-on;
- st,mask-reset;
- regulator-initial-mode = <0>;
- regulator-over-current-protection;
- };
-
- v3v3: buck4 {
- regulator-name = "v3v3";
- regulator-min-microvolt = <3300000>;
- regulator-max-microvolt = <3300000>;
- regulator-always-on;
- regulator-over-current-protection;
- regulator-initial-mode = <0>;
- };
-
- vdda: ldo1 {
- regulator-name = "vdda";
- regulator-min-microvolt = <2900000>;
- regulator-max-microvolt = <2900000>;
- };
-
- v2v8: ldo2 {
- regulator-name = "v2v8";
- regulator-min-microvolt = <2800000>;
- regulator-max-microvolt = <2800000>;
- };
-
- vtt_ddr: ldo3 {
- regulator-name = "vtt_ddr";
- regulator-min-microvolt = <500000>;
- regulator-max-microvolt = <750000>;
- regulator-always-on;
- regulator-over-current-protection;
- };
-
- vdd_usb: ldo4 {
- regulator-name = "vdd_usb";
- regulator-min-microvolt = <3300000>;
- regulator-max-microvolt = <3300000>;
- };
-
- vdd_sd: ldo5 {
- regulator-name = "vdd_sd";
- regulator-min-microvolt = <2900000>;
- regulator-max-microvolt = <2900000>;
- regulator-boot-on;
- };
-
- v1v8: ldo6 {
- regulator-name = "v1v8";
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- };
-
- vref_ddr: vref_ddr {
- regulator-name = "vref_ddr";
- regulator-always-on;
- regulator-over-current-protection;
- };
- };
- };
-};
-
-&iwdg2 {
- timeout-sec = <32>;
- status = "okay";
-};
-
-&pwr {
- pwr-regulators {
- vdd-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,sig-dir;
- st,neg-edge;
- st,use-ckin;
- bus-width = <4>;
- vmmc-supply = <&vdd_sd>;
- sd-uhs-sdr12;
- sd-uhs-sdr25;
- sd-uhs-sdr50;
- sd-uhs-ddr50;
- sd-uhs-sdr104;
- status = "okay";
-};
-
-&sdmmc2 {
- pinctrl-names = "default";
- pinctrl-0 = <&sdmmc2_b4_pins_a &sdmmc2_d47_pins_a>;
- non-removable;
- no-sd;
- no-sdio;
- st,neg-edge;
- bus-width = <8>;
- vmmc-supply = <&v3v3>;
- vqmmc-supply = <&v3v3>;
- mmc-ddr-3_3v;
- status = "okay";
-};
-
-&uart4 {
- pinctrl-names = "default";
- pinctrl-0 = <&uart4_pins_a>;
+&cryp1 {
status = "okay";
};
-/* ATF Specific */
-#include <dt-bindings/clock/stm32mp1-clksrc.h>
-#include "stm32mp15-ddr3-2x4Gb-1066-binG.dtsi"
-#include "stm32mp157c-security.dtsi"
-
-/ {
- aliases {
- gpio0 = &gpioa;
- gpio1 = &gpiob;
- gpio2 = &gpioc;
- gpio3 = &gpiod;
- gpio4 = &gpioe;
- gpio5 = &gpiof;
- gpio6 = &gpiog;
- gpio7 = &gpioh;
- gpio8 = &gpioi;
- gpio9 = &gpioj;
- gpio10 = &gpiok;
- gpio25 = &gpioz;
- i2c3 = &i2c4;
- };
-};
-
-/* CLOCK init */
-&rcc {
- secure-status = "disabled";
- 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
+&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)
+ DECPROT(STM32MP1_ETZPC_DDRCTRL_ID, DECPROT_S_RW, DECPROT_LOCK)
+ DECPROT(STM32MP1_ETZPC_DDRPHYC_ID, DECPROT_S_RW, DECPROT_LOCK)
+ DECPROT(STM32MP1_ETZPC_STGENC_ID, DECPROT_S_RW, DECPROT_LOCK)
+ DECPROT(STM32MP1_ETZPC_BKPSRAM_ID, DECPROT_S_RW, DECPROT_LOCK)
+ DECPROT(STM32MP1_ETZPC_IWDG1_ID, DECPROT_S_RW, DECPROT_LOCK)
>;
-
- 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_PLL4R
- 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) >;
- };
-};
-
-&bsec {
- board_id: board_id@ec {
- reg = <0xec 0x4>;
- status = "okay";
- secure-status = "okay";
- };
};
diff --git a/fdts/stm32mp157c-ev1.dts b/fdts/stm32mp157c-ev1.dts
index cfde8ed90..dd7da4195 100644
--- a/fdts/stm32mp157c-ev1.dts
+++ b/fdts/stm32mp157c-ev1.dts
@@ -1,11 +1,12 @@
// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
/*
- * Copyright (C) STMicroelectronics 2017 - All Rights Reserved
- * Author: Ludovic Barre <ludovic.barre@st.com> for STMicroelectronics.
+ * Copyright (C) STMicroelectronics 2019 - All Rights Reserved
+ * Author: Alexandre Torgue <alexandre.torgue@st.com> for STMicroelectronics.
*/
/dts-v1/;
#include "stm32mp157c-ed1.dts"
+#include "stm32mp15xx-evx.dtsi"
/ {
model = "STMicroelectronics STM32MP157C eval daughter on eval mother";
@@ -19,49 +20,3 @@
serial1 = &usart3;
};
};
-
-&fmc {
- status = "okay";
- #address-cells = <1>;
- #size-cells = <0>;
-
- nand: nand@0 {
- reg = <0>;
- nand-on-flash-bbt;
- #address-cells = <1>;
- #size-cells = <1>;
- };
-};
-
-&qspi {
- pinctrl-names = "default";
- pinctrl-0 = <&qspi_clk_pins_a &qspi_bk1_pins_a &qspi_bk2_pins_a>;
- reg = <0x58003000 0x1000>, <0x70000000 0x4000000>;
- #address-cells = <1>;
- #size-cells = <0>;
- status = "okay";
-
- flash0: mx66l51235l@0 {
- compatible = "jedec,spi-nor";
- reg = <0>;
- spi-rx-bus-width = <4>;
- spi-max-frequency = <108000000>;
- #address-cells = <1>;
- #size-cells = <1>;
- };
-
- flash1: mx66l51235l@1 {
- compatible = "jedec,spi-nor";
- reg = <1>;
- spi-rx-bus-width = <4>;
- spi-max-frequency = <108000000>;
- #address-cells = <1>;
- #size-cells = <1>;
- };
-};
-
-&usart3 {
- pinctrl-names = "default";
- pinctrl-0 = <&usart3_pins_a>;
- status = "disabled";
-};
diff --git a/fdts/stm32mp157c-security.dtsi b/fdts/stm32mp157c-security.dtsi
deleted file mode 100644
index 165ffa0cb..000000000
--- a/fdts/stm32mp157c-security.dtsi
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (c) 2017-2019, STMicroelectronics - All Rights Reserved
- *
- * SPDX-License-Identifier: GPL-2.0+ BSD-3-Clause
- */
-
-/ {
- soc {
- stgen: stgen@5c008000 {
- compatible = "st,stm32-stgen";
- reg = <0x5C008000 0x1000>;
- status = "okay";
- };
- };
-};
-
-&bsec {
- mac_addr: mac_addr@e4 {
- reg = <0xe4 0x6>;
- status = "okay";
- secure-status = "okay";
- };
- /* Spare field to align on 32-bit OTP granularity */
- spare_ns_ea: spare_ns_ea@ea {
- reg = <0xea 0x2>;
- status = "okay";
- secure-status = "okay";
- };
-};
-
-&hash1 {
- secure-status = "okay";
-};
-
-&sdmmc1 {
- compatible = "st,stm32-sdmmc2";
-};
-
-&sdmmc2 {
- compatible = "st,stm32-sdmmc2";
-};
diff --git a/fdts/stm32mp157c.dtsi b/fdts/stm32mp157c.dtsi
deleted file mode 100644
index 0942a91c2..000000000
--- a/fdts/stm32mp157c.dtsi
+++ /dev/null
@@ -1,366 +0,0 @@
-// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
-/*
- * Copyright (C) STMicroelectronics 2017-2019 - All Rights Reserved
- * Author: Ludovic Barre <ludovic.barre@st.com> for STMicroelectronics.
- */
-#include <dt-bindings/interrupt-controller/arm-gic.h>
-#include <dt-bindings/clock/stm32mp1-clks.h>
-#include <dt-bindings/reset/stm32mp1-resets.h>
-
-/ {
- #address-cells = <1>;
- #size-cells = <1>;
-
- intc: interrupt-controller@a0021000 {
- compatible = "arm,cortex-a7-gic";
- #interrupt-cells = <3>;
- interrupt-controller;
- reg = <0xa0021000 0x1000>,
- <0xa0022000 0x2000>;
- };
-
- clocks {
- clk_hse: clk-hse {
- #clock-cells = <0>;
- compatible = "fixed-clock";
- clock-frequency = <24000000>;
- };
-
- clk_hsi: clk-hsi {
- #clock-cells = <0>;
- compatible = "fixed-clock";
- clock-frequency = <64000000>;
- };
-
- clk_lse: clk-lse {
- #clock-cells = <0>;
- compatible = "fixed-clock";
- clock-frequency = <32768>;
- };
-
- clk_lsi: clk-lsi {
- #clock-cells = <0>;
- compatible = "fixed-clock";
- clock-frequency = <32000>;
- };
-
- clk_csi: clk-csi {
- #clock-cells = <0>;
- compatible = "fixed-clock";
- clock-frequency = <4000000>;
- };
-
- clk_i2s_ckin: i2s_ckin {
- #clock-cells = <0>;
- compatible = "fixed-clock";
- clock-frequency = <0>;
- };
-
- clk_dsi_phy: ck_dsi_phy {
- #clock-cells = <0>;
- compatible = "fixed-clock";
- clock-frequency = <0>;
- };
- };
-
- soc {
- compatible = "simple-bus";
- #address-cells = <1>;
- #size-cells = <1>;
- interrupt-parent = <&intc>;
- ranges;
-
- timers12: timer@40006000 {
- #address-cells = <1>;
- #size-cells = <0>;
- compatible = "st,stm32-timers";
- reg = <0x40006000 0x400>;
- clocks = <&rcc TIM12_K>;
- clock-names = "int";
- status = "disabled";
- };
-
- usart2: serial@4000e000 {
- compatible = "st,stm32h7-uart";
- reg = <0x4000e000 0x400>;
- clocks = <&rcc USART2_K>;
- resets = <&rcc USART2_R>;
- status = "disabled";
- };
-
- usart3: serial@4000f000 {
- compatible = "st,stm32h7-uart";
- reg = <0x4000f000 0x400>;
- clocks = <&rcc USART3_K>;
- resets = <&rcc USART3_R>;
- status = "disabled";
- };
-
- uart4: serial@40010000 {
- compatible = "st,stm32h7-uart";
- reg = <0x40010000 0x400>;
- clocks = <&rcc UART4_K>;
- resets = <&rcc UART4_R>;
- status = "disabled";
- };
-
- uart5: serial@40011000 {
- compatible = "st,stm32h7-uart";
- reg = <0x40011000 0x400>;
- clocks = <&rcc UART5_K>;
- resets = <&rcc UART5_R>;
- status = "disabled";
- };
-
-
- uart7: serial@40018000 {
- compatible = "st,stm32h7-uart";
- reg = <0x40018000 0x400>;
- clocks = <&rcc UART7_K>;
- resets = <&rcc UART7_R>;
- status = "disabled";
- };
-
- uart8: serial@40019000 {
- compatible = "st,stm32h7-uart";
- reg = <0x40019000 0x400>;
- clocks = <&rcc UART8_K>;
- resets = <&rcc UART8_R>;
- status = "disabled";
- };
-
- usart6: serial@44003000 {
- compatible = "st,stm32h7-uart";
- reg = <0x44003000 0x400>;
- clocks = <&rcc USART6_K>;
- resets = <&rcc USART6_R>;
- status = "disabled";
- };
-
- timers15: timer@44006000 {
- #address-cells = <1>;
- #size-cells = <0>;
- compatible = "st,stm32-timers";
- reg = <0x44006000 0x400>;
- clocks = <&rcc TIM15_K>;
- clock-names = "int";
- status = "disabled";
- };
-
- sdmmc3: sdmmc@48004000 {
- compatible = "arm,pl18x", "arm,primecell";
- arm,primecell-periphid = <0x00253180>;
- reg = <0x48004000 0x400>, <0x48005000 0x400>;
- clocks = <&rcc SDMMC3_K>;
- clock-names = "apb_pclk";
- resets = <&rcc SDMMC3_R>;
- cap-sd-highspeed;
- cap-mmc-highspeed;
- max-frequency = <120000000>;
- status = "disabled";
- };
-
- usbotg_hs: usb-otg@49000000 {
- compatible = "st,stm32mp1-hsotg", "snps,dwc2";
- reg = <0x49000000 0x10000>;
- clocks = <&rcc USBO_K>;
- clock-names = "otg";
- resets = <&rcc USBO_R>;
- reset-names = "dwc2";
- status = "disabled";
- };
-
- rcc: rcc@50000000 {
- compatible = "st,stm32mp1-rcc", "syscon";
- reg = <0x50000000 0x1000>;
- #clock-cells = <1>;
- #reset-cells = <1>;
- interrupts = <GIC_SPI 5 IRQ_TYPE_LEVEL_HIGH>;
- };
-
- pwr: pwr@50001000 {
- compatible = "st,stm32mp1-pwr", "syscon", "simple-mfd";
- reg = <0x50001000 0x400>;
- };
-
- exti: interrupt-controller@5000d000 {
- compatible = "st,stm32mp1-exti", "syscon";
- interrupt-controller;
- #interrupt-cells = <2>;
- reg = <0x5000d000 0x400>;
-
- /* exti_pwr is an extra interrupt controller used for
- * EXTI 55 to 60. It's mapped on pwr interrupt
- * controller.
- */
- exti_pwr: exti-pwr {
- interrupt-controller;
- #interrupt-cells = <2>;
- interrupt-parent = <&pwr>;
- st,irq-number = <6>;
- };
- };
-
- syscfg: syscon@50020000 {
- compatible = "st,stm32mp157-syscfg", "syscon";
- reg = <0x50020000 0x400>;
- clocks = <&rcc SYSCFG>;
- };
-
- cryp1: cryp@54001000 {
- compatible = "st,stm32mp1-cryp";
- reg = <0x54001000 0x400>;
- interrupts = <GIC_SPI 79 IRQ_TYPE_LEVEL_HIGH>;
- clocks = <&rcc CRYP1>;
- resets = <&rcc CRYP1_R>;
- status = "disabled";
- };
-
- hash1: hash@54002000 {
- compatible = "st,stm32f756-hash";
- reg = <0x54002000 0x400>;
- interrupts = <GIC_SPI 80 IRQ_TYPE_LEVEL_HIGH>;
- clocks = <&rcc HASH1>;
- resets = <&rcc HASH1_R>;
- status = "disabled";
- };
-
- rng1: rng@54003000 {
- compatible = "st,stm32-rng";
- reg = <0x54003000 0x400>;
- clocks = <&rcc RNG1_K>;
- resets = <&rcc RNG1_R>;
- status = "disabled";
- };
-
- fmc: nand-controller@58002000 {
- compatible = "st,stm32mp15-fmc2";
- reg = <0x58002000 0x1000>,
- <0x80000000 0x1000>,
- <0x88010000 0x1000>,
- <0x88020000 0x1000>,
- <0x81000000 0x1000>,
- <0x89010000 0x1000>,
- <0x89020000 0x1000>;
- clocks = <&rcc FMC_K>;
- resets = <&rcc FMC_R>;
- status = "disabled";
- };
-
- qspi: qspi@58003000 {
- compatible = "st,stm32f469-qspi";
- reg = <0x58003000 0x1000>, <0x70000000 0x10000000>;
- reg-names = "qspi", "qspi_mm";
- clocks = <&rcc QSPI_K>;
- resets = <&rcc QSPI_R>;
- status = "disabled";
- };
-
- sdmmc1: sdmmc@58005000 {
- compatible = "arm,pl18x", "arm,primecell";
- arm,primecell-periphid = <0x00253180>;
- reg = <0x58005000 0x1000>, <0x58006000 0x1000>;
- clocks = <&rcc SDMMC1_K>;
- clock-names = "apb_pclk";
- resets = <&rcc SDMMC1_R>;
- cap-sd-highspeed;
- cap-mmc-highspeed;
- max-frequency = <120000000>;
- status = "disabled";
- };
-
- sdmmc2: sdmmc@58007000 {
- compatible = "arm,pl18x", "arm,primecell";
- arm,primecell-periphid = <0x00253180>;
- reg = <0x58007000 0x1000>, <0x58008000 0x1000>;
- clocks = <&rcc SDMMC2_K>;
- clock-names = "apb_pclk";
- resets = <&rcc SDMMC2_R>;
- cap-sd-highspeed;
- cap-mmc-highspeed;
- max-frequency = <120000000>;
- status = "disabled";
- };
-
- iwdg2: watchdog@5a002000 {
- compatible = "st,stm32mp1-iwdg";
- reg = <0x5a002000 0x400>;
- clocks = <&rcc IWDG2>, <&rcc CK_LSI>;
- clock-names = "pclk", "lsi";
- status = "disabled";
- };
-
- usart1: serial@5c000000 {
- compatible = "st,stm32h7-uart";
- reg = <0x5c000000 0x400>;
- interrupt-names = "event", "wakeup";
- interrupts-extended = <&intc GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH>,
- <&exti 26 1>;
- clocks = <&rcc USART1_K>;
- resets = <&rcc USART1_R>;
- status = "disabled";
- };
-
- spi6: spi@5c001000 {
- #address-cells = <1>;
- #size-cells = <0>;
- compatible = "st,stm32h7-spi";
- reg = <0x5c001000 0x400>;
- interrupts = <GIC_SPI 86 IRQ_TYPE_LEVEL_HIGH>;
- clocks = <&rcc SPI6_K>;
- resets = <&rcc SPI6_R>;
- status = "disabled";
- };
-
- i2c4: i2c@5c002000 {
- compatible = "st,stm32f7-i2c";
- reg = <0x5c002000 0x400>;
- interrupt-names = "event", "error", "wakeup";
- interrupts-extended = <&intc GIC_SPI 95 IRQ_TYPE_LEVEL_HIGH>,
- <&intc GIC_SPI 96 IRQ_TYPE_LEVEL_HIGH>,
- <&exti 24 1>;
- clocks = <&rcc I2C4_K>;
- resets = <&rcc I2C4_R>;
- #address-cells = <1>;
- #size-cells = <0>;
- status = "disabled";
- };
-
- rtc: rtc@5c004000 {
- compatible = "st,stm32mp1-rtc";
- reg = <0x5c004000 0x400>;
- clocks = <&rcc RTCAPB>, <&rcc RTC>;
- clock-names = "pclk", "rtc_ck";
- interrupts-extended = <&intc GIC_SPI 3 IRQ_TYPE_LEVEL_HIGH>,
- <&exti 19 1>;
- status = "disabled";
- };
-
- bsec: nvmem@5c005000 {
- compatible = "st,stm32mp15-bsec";
- reg = <0x5c005000 0x400>;
- #address-cells = <1>;
- #size-cells = <1>;
- ts_cal1: calib@5c {
- reg = <0x5c 0x2>;
- };
- ts_cal2: calib@5e {
- reg = <0x5e 0x2>;
- };
- };
-
- i2c6: i2c@5c009000 {
- compatible = "st,stm32f7-i2c";
- reg = <0x5c009000 0x400>;
- interrupt-names = "event", "error", "wakeup";
- interrupts-extended = <&intc GIC_SPI 135 IRQ_TYPE_LEVEL_HIGH>,
- <&intc GIC_SPI 136 IRQ_TYPE_LEVEL_HIGH>,
- <&exti 54 1>;
- clocks = <&rcc I2C6_K>;
- resets = <&rcc I2C6_R>;
- #address-cells = <1>;
- #size-cells = <0>;
- status = "disabled";
- };
- };
-};
diff --git a/fdts/stm32mp157caa-pinctrl.dtsi b/fdts/stm32mp157caa-pinctrl.dtsi
deleted file mode 100644
index 9b9cd086c..000000000
--- a/fdts/stm32mp157caa-pinctrl.dtsi
+++ /dev/null
@@ -1,90 +0,0 @@
-// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
-/*
- * Copyright (C) STMicroelectronics 2018 - All Rights Reserved
- * Author: Alexandre Torgue <alexandre.torgue@st.com>
- */
-
-#include "stm32mp157-pinctrl.dtsi"
-/ {
- soc {
- pinctrl: pin-controller@50002000 {
- st,package = <STM32MP157CAA>;
-
- gpioa: gpio@50002000 {
- status = "okay";
- ngpios = <16>;
- gpio-ranges = <&pinctrl 0 0 16>;
- };
-
- gpiob: gpio@50003000 {
- status = "okay";
- ngpios = <16>;
- gpio-ranges = <&pinctrl 0 16 16>;
- };
-
- gpioc: gpio@50004000 {
- status = "okay";
- ngpios = <16>;
- gpio-ranges = <&pinctrl 0 32 16>;
- };
-
- gpiod: gpio@50005000 {
- status = "okay";
- ngpios = <16>;
- gpio-ranges = <&pinctrl 0 48 16>;
- };
-
- gpioe: gpio@50006000 {
- status = "okay";
- ngpios = <16>;
- gpio-ranges = <&pinctrl 0 64 16>;
- };
-
- gpiof: gpio@50007000 {
- status = "okay";
- ngpios = <16>;
- gpio-ranges = <&pinctrl 0 80 16>;
- };
-
- gpiog: gpio@50008000 {
- status = "okay";
- ngpios = <16>;
- gpio-ranges = <&pinctrl 0 96 16>;
- };
-
- gpioh: gpio@50009000 {
- status = "okay";
- ngpios = <16>;
- gpio-ranges = <&pinctrl 0 112 16>;
- };
-
- gpioi: gpio@5000a000 {
- status = "okay";
- ngpios = <16>;
- gpio-ranges = <&pinctrl 0 128 16>;
- };
-
- gpioj: gpio@5000b000 {
- status = "okay";
- ngpios = <16>;
- gpio-ranges = <&pinctrl 0 144 16>;
- };
-
- gpiok: gpio@5000c000 {
- status = "okay";
- ngpios = <8>;
- gpio-ranges = <&pinctrl 0 160 8>;
- };
- };
-
- pinctrl_z: pin-controller-z@54004000 {
- st,package = <STM32MP157CAA>;
-
- gpioz: gpio@54004000 {
- status = "okay";
- ngpios = <8>;
- gpio-ranges = <&pinctrl_z 0 400 8>;
- };
- };
- };
-};
diff --git a/fdts/stm32mp157cac-pinctrl.dtsi b/fdts/stm32mp157cac-pinctrl.dtsi
deleted file mode 100644
index 777f9919d..000000000
--- a/fdts/stm32mp157cac-pinctrl.dtsi
+++ /dev/null
@@ -1,78 +0,0 @@
-// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
-/*
- * Copyright (C) STMicroelectronics 2018 - All Rights Reserved
- * Author: Alexandre Torgue <alexandre.torgue@st.com>
- */
-
-#include "stm32mp157-pinctrl.dtsi"
-/ {
- soc {
- pinctrl: pin-controller@50002000 {
- st,package = <STM32MP157CAC>;
-
- 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 = <STM32MP157CAC>;
-
- gpioz: gpio@54004000 {
- status = "okay";
- ngpios = <8>;
- gpio-ranges = <&pinctrl_z 0 400 8>;
- };
- };
- };
-};
diff --git a/fdts/stm32mp157d-dk1.dts b/fdts/stm32mp157d-dk1.dts
new file mode 100644
index 000000000..d320f993e
--- /dev/null
+++ b/fdts/stm32mp157d-dk1.dts
@@ -0,0 +1,49 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
+/*
+ * Copyright (C) STMicroelectronics 2019 - All Rights Reserved
+ * Author: Alexandre Torgue <alexandre.torgue@st.com> for STMicroelectronics.
+ */
+
+/dts-v1/;
+
+#include "stm32mp157.dtsi"
+#include "stm32mp15xd.dtsi"
+#include "stm32mp15-pinctrl.dtsi"
+#include "stm32mp15xxac-pinctrl.dtsi"
+#include "stm32mp15xx-dkx.dtsi"
+#include <dt-bindings/soc/st,stm32-etzpc.h>
+
+/ {
+ model = "STMicroelectronics STM32MP157D-DK1 Discovery Board";
+ compatible = "st,stm32mp157d-dk1", "st,stm32mp157";
+
+ aliases {
+ serial0 = &uart4;
+ serial1 = &usart3;
+ serial2 = &uart7;
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+};
+
+&cpu1 {
+ cpu-supply = <&vddcore>;
+};
+
+&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_DDRCTRL_ID, DECPROT_S_RW, DECPROT_LOCK)
+ DECPROT(STM32MP1_ETZPC_DDRPHYC_ID, DECPROT_S_RW, DECPROT_LOCK)
+ DECPROT(STM32MP1_ETZPC_STGENC_ID, DECPROT_S_RW, DECPROT_LOCK)
+ DECPROT(STM32MP1_ETZPC_BKPSRAM_ID, DECPROT_S_RW, DECPROT_LOCK)
+ DECPROT(STM32MP1_ETZPC_IWDG1_ID, DECPROT_S_RW, DECPROT_LOCK)
+ >;
+};
diff --git a/fdts/stm32mp157d-ed1.dts b/fdts/stm32mp157d-ed1.dts
new file mode 100644
index 000000000..76f0614d6
--- /dev/null
+++ b/fdts/stm32mp157d-ed1.dts
@@ -0,0 +1,46 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
+/*
+ * Copyright (C) STMicroelectronics 2019 - All Rights Reserved
+ * Author: Alexandre Torgue <alexandre.torgue@st.com> for STMicroelectronics.
+ */
+/dts-v1/;
+
+#include "stm32mp157.dtsi"
+#include "stm32mp15xd.dtsi"
+#include "stm32mp15-pinctrl.dtsi"
+#include "stm32mp15xxaa-pinctrl.dtsi"
+#include "stm32mp15xx-edx.dtsi"
+#include <dt-bindings/soc/st,stm32-etzpc.h>
+
+/ {
+ model = "STMicroelectronics STM32MP157D eval daughter";
+ compatible = "st,stm32mp157d-ed1", "st,stm32mp157";
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+
+ aliases {
+ serial0 = &uart4;
+ };
+};
+
+&cpu1 {
+ cpu-supply = <&vddcore>;
+};
+
+&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_DDRCTRL_ID, DECPROT_S_RW, DECPROT_LOCK)
+ DECPROT(STM32MP1_ETZPC_DDRPHYC_ID, DECPROT_S_RW, DECPROT_LOCK)
+ DECPROT(STM32MP1_ETZPC_STGENC_ID, DECPROT_S_RW, DECPROT_LOCK)
+ DECPROT(STM32MP1_ETZPC_BKPSRAM_ID, DECPROT_S_RW, DECPROT_LOCK)
+ DECPROT(STM32MP1_ETZPC_IWDG1_ID, DECPROT_S_RW, DECPROT_LOCK)
+ >;
+};
diff --git a/fdts/stm32mp157d-ev1.dts b/fdts/stm32mp157d-ev1.dts
new file mode 100644
index 000000000..47d962b57
--- /dev/null
+++ b/fdts/stm32mp157d-ev1.dts
@@ -0,0 +1,22 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
+/*
+ * Copyright (C) STMicroelectronics 2019 - All Rights Reserved
+ * Author: Alexandre Torgue <alexandre.torgue@st.com> for STMicroelectronics.
+ */
+/dts-v1/;
+
+#include "stm32mp157d-ed1.dts"
+#include "stm32mp15xx-evx.dtsi"
+
+/ {
+ model = "STMicroelectronics STM32MP157D eval daughter on eval mother";
+ compatible = "st,stm32mp157d-ev1", "st,stm32mp157d-ed1", "st,stm32mp157";
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+
+ aliases {
+ serial1 = &usart3;
+ };
+};
diff --git a/fdts/stm32mp157f-dk2.dts b/fdts/stm32mp157f-dk2.dts
new file mode 100644
index 000000000..9c79bfb43
--- /dev/null
+++ b/fdts/stm32mp157f-dk2.dts
@@ -0,0 +1,55 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
+/*
+ * Copyright (C) STMicroelectronics 2019 - All Rights Reserved
+ * Author: Alexandre Torgue <alexandre.torgue@st.com> for STMicroelectronics.
+ */
+
+/dts-v1/;
+
+#include "stm32mp157.dtsi"
+#include "stm32mp15xf.dtsi"
+#include "stm32mp15-pinctrl.dtsi"
+#include "stm32mp15xxac-pinctrl.dtsi"
+#include "stm32mp15xx-dkx.dtsi"
+#include <dt-bindings/soc/st,stm32-etzpc.h>
+
+/ {
+ model = "STMicroelectronics STM32MP157F-DK2 Discovery Board";
+ compatible = "st,stm32mp157f-dk2", "st,stm32mp157";
+
+ aliases {
+ serial0 = &uart4;
+ serial1 = &usart3;
+ serial2 = &uart7;
+ serial3 = &usart2;
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+};
+
+&cpu1 {
+ cpu-supply = <&vddcore>;
+};
+
+&cryp1 {
+ status = "okay";
+};
+
+&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)
+ DECPROT(STM32MP1_ETZPC_DDRCTRL_ID, DECPROT_S_RW, DECPROT_LOCK)
+ DECPROT(STM32MP1_ETZPC_DDRPHYC_ID, DECPROT_S_RW, DECPROT_LOCK)
+ DECPROT(STM32MP1_ETZPC_STGENC_ID, DECPROT_S_RW, DECPROT_LOCK)
+ DECPROT(STM32MP1_ETZPC_BKPSRAM_ID, DECPROT_S_RW, DECPROT_LOCK)
+ DECPROT(STM32MP1_ETZPC_IWDG1_ID, DECPROT_S_RW, DECPROT_LOCK)
+ >;
+};
diff --git a/fdts/stm32mp157f-ed1.dts b/fdts/stm32mp157f-ed1.dts
new file mode 100644
index 000000000..a659cf84d
--- /dev/null
+++ b/fdts/stm32mp157f-ed1.dts
@@ -0,0 +1,51 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
+/*
+ * Copyright (C) STMicroelectronics 2019 - All Rights Reserved
+ * Author: Alexandre Torgue <alexandre.torgue@st.com> for STMicroelectronics.
+ */
+/dts-v1/;
+
+#include "stm32mp157.dtsi"
+#include "stm32mp15xf.dtsi"
+#include "stm32mp15-pinctrl.dtsi"
+#include "stm32mp15xxaa-pinctrl.dtsi"
+#include "stm32mp15xx-edx.dtsi"
+#include <dt-bindings/soc/st,stm32-etzpc.h>
+
+/ {
+ model = "STMicroelectronics STM32MP157F eval daughter";
+ compatible = "st,stm32mp157f-ed1", "st,stm32mp157";
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+
+ aliases {
+ serial0 = &uart4;
+ };
+};
+
+&cpu1{
+ cpu-supply = <&vddcore>;
+};
+
+&cryp1 {
+ status = "okay";
+};
+
+&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)
+ DECPROT(STM32MP1_ETZPC_DDRCTRL_ID, DECPROT_S_RW, DECPROT_LOCK)
+ DECPROT(STM32MP1_ETZPC_DDRPHYC_ID, DECPROT_S_RW, DECPROT_LOCK)
+ DECPROT(STM32MP1_ETZPC_STGENC_ID, DECPROT_S_RW, DECPROT_LOCK)
+ DECPROT(STM32MP1_ETZPC_BKPSRAM_ID, DECPROT_S_RW, DECPROT_LOCK)
+ DECPROT(STM32MP1_ETZPC_IWDG1_ID, DECPROT_S_RW, DECPROT_LOCK)
+ >;
+};
diff --git a/fdts/stm32mp157f-ev1.dts b/fdts/stm32mp157f-ev1.dts
new file mode 100644
index 000000000..c8598ce55
--- /dev/null
+++ b/fdts/stm32mp157f-ev1.dts
@@ -0,0 +1,22 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
+/*
+ * Copyright (C) STMicroelectronics 2019 - All Rights Reserved
+ * Author: Alexandre Torgue <alexandre.torgue@st.com> for STMicroelectronics.
+ */
+/dts-v1/;
+
+#include "stm32mp157f-ed1.dts"
+#include "stm32mp15xx-evx.dtsi"
+
+/ {
+ model = "STMicroelectronics STM32MP157F eval daughter on eval mother";
+ compatible = "st,stm32mp157f-ev1", "st,stm32mp157f-ed1", "st,stm32mp157";
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+
+ aliases {
+ serial1 = &usart3;
+ };
+};
diff --git a/fdts/stm32mp15xa.dtsi b/fdts/stm32mp15xa.dtsi
new file mode 100644
index 000000000..5ed7e594f
--- /dev/null
+++ b/fdts/stm32mp15xa.dtsi
@@ -0,0 +1,13 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
+/*
+ * Copyright (C) STMicroelectronics 2019 - All Rights Reserved
+ * Author: Alexandre Torgue <alexandre.torgue@st.com> for STMicroelectronics.
+ */
+
+&cpu0_opp_table {
+ opp-650000000 {
+ opp-hz = /bits/ 64 <650000000>;
+ opp-microvolt = <1200000>;
+ opp-supported-hw = <0x1>;
+ };
+};
diff --git a/fdts/stm32mp15xc.dtsi b/fdts/stm32mp15xc.dtsi
new file mode 100644
index 000000000..68d822d8c
--- /dev/null
+++ b/fdts/stm32mp15xc.dtsi
@@ -0,0 +1,21 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
+/*
+ * Copyright (C) STMicroelectronics 2019 - All Rights Reserved
+ * Author: Alexandre Torgue <alexandre.torgue@st.com> for STMicroelectronics.
+ */
+
+#include "stm32mp15xa.dtsi"
+
+/ {
+ soc {
+ cryp1: cryp@54001000 {
+ compatible = "st,stm32mp1-cryp";
+ reg = <0x54001000 0x400>;
+ interrupts = <GIC_SPI 79 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&rcc CRYP1>;
+ resets = <&rcc CRYP1_R>;
+ status = "disabled";
+ secure-status = "disabled";
+ };
+ };
+};
diff --git a/fdts/stm32mp15xd.dtsi b/fdts/stm32mp15xd.dtsi
new file mode 100644
index 000000000..18b05ee38
--- /dev/null
+++ b/fdts/stm32mp15xd.dtsi
@@ -0,0 +1,19 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
+/*
+ * Copyright (C) STMicroelectronics 2019 - All Rights Reserved
+ * Author: Alexandre Torgue <alexandre.torgue@st.com> for STMicroelectronics.
+ */
+
+&cpu0_opp_table {
+ opp-800000000 {
+ opp-hz = /bits/ 64 <800000000>;
+ opp-microvolt = <1350000>;
+ opp-supported-hw = <0x2>;
+ };
+ opp-400000000 {
+ opp-hz = /bits/ 64 <400000000>;
+ opp-microvolt = <1200000>;
+ opp-supported-hw = <0x2>;
+ opp-suspend;
+ };
+};
diff --git a/fdts/stm32mp15xf.dtsi b/fdts/stm32mp15xf.dtsi
new file mode 100644
index 000000000..526a1627c
--- /dev/null
+++ b/fdts/stm32mp15xf.dtsi
@@ -0,0 +1,21 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
+/*
+ * Copyright (C) STMicroelectronics 2019 - All Rights Reserved
+ * Author: Alexandre Torgue <alexandre.torgue@st.com> for STMicroelectronics.
+ */
+
+#include "stm32mp15xd.dtsi"
+
+/ {
+ soc {
+ cryp1: cryp@54001000 {
+ compatible = "st,stm32mp1-cryp";
+ reg = <0x54001000 0x400>;
+ interrupts = <GIC_SPI 79 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&rcc CRYP1>;
+ resets = <&rcc CRYP1_R>;
+ status = "disabled";
+ secure-status = "disabled";
+ };
+ };
+};
diff --git a/fdts/stm32mp15xx-dkx.dtsi b/fdts/stm32mp15xx-dkx.dtsi
new file mode 100644
index 000000000..53790f29b
--- /dev/null
+++ b/fdts/stm32mp15xx-dkx.dtsi
@@ -0,0 +1,470 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
+/*
+ * Copyright (C) STMicroelectronics 2019 - All Rights Reserved
+ * Author: Alexandre Torgue <alexandre.torgue@st.com> for STMicroelectronics.
+ */
+
+#include <dt-bindings/clock/stm32mp1-clksrc.h>
+#include <dt-bindings/power/stm32mp1-power.h>
+#include "stm32mp15-ddr3-1x4Gb-1066-binG.dtsi"
+
+/ {
+ memory@c0000000 {
+ device_type = "memory";
+ reg = <0xc0000000 0x20000000>;
+ };
+
+ vin: vin {
+ compatible = "regulator-fixed";
+ regulator-name = "vin";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ regulator-always-on;
+ };
+};
+
+&bsec {
+ board_id: board_id@ec {
+ reg = <0xec 0x4>;
+ st,non-secure-otp;
+ };
+};
+
+&clk_hse {
+ st,digbypass;
+};
+
+&cpu0{
+ cpu-supply = <&vddcore>;
+};
+
+&cpu1{
+ cpu-supply = <&vddcore>;
+};
+
+&hash1 {
+ status = "okay";
+};
+
+&i2c4 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c4_pins_a>;
+ i2c-scl-rising-time-ns = <185>;
+ i2c-scl-falling-time-ns = <20>;
+ clock-frequency = <400000>;
+ status = "okay";
+ secure-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";
+ secure-status = "okay";
+
+ regulators {
+ compatible = "st,stpmic1-regulators";
+ buck1-supply = <&vin>;
+ buck2-supply = <&vin>;
+ buck3-supply = <&vin>;
+ buck4-supply = <&vin>;
+ ldo1-supply = <&v3v3>;
+ ldo2-supply = <&vin>;
+ ldo3-supply = <&vdd_ddr>;
+ ldo4-supply = <&vin>;
+ ldo5-supply = <&vin>;
+ ldo6-supply = <&v3v3>;
+ vref_ddr-supply = <&vin>;
+ boost-supply = <&vin>;
+ pwr_sw1-supply = <&bst_out>;
+ pwr_sw2-supply = <&bst_out>;
+
+ vddcore: buck1 {
+ regulator-name = "vddcore";
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1350000>;
+ regulator-always-on;
+ regulator-initial-mode = <0>;
+ regulator-over-current-protection;
+ 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: buck2 {
+ regulator-name = "vdd_ddr";
+ regulator-min-microvolt = <1350000>;
+ regulator-max-microvolt = <1350000>;
+ regulator-always-on;
+ regulator-initial-mode = <0>;
+ regulator-over-current-protection;
+ 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: 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;
+ 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: buck4 {
+ regulator-name = "v3v3";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ regulator-over-current-protection;
+ regulator-initial-mode = <0>;
+ 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: ldo1 {
+ regulator-name = "v1v8_audio";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ standby-ddr-sr {
+ regulator-off-in-suspend;
+ };
+ standby-ddr-off {
+ regulator-off-in-suspend;
+ };
+ };
+
+ v3v3_hdmi: ldo2 {
+ regulator-name = "v3v3_hdmi";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ standby-ddr-sr {
+ regulator-off-in-suspend;
+ };
+ standby-ddr-off {
+ regulator-off-in-suspend;
+ };
+ };
+
+ vtt_ddr: ldo3 {
+ regulator-name = "vtt_ddr";
+ regulator-min-microvolt = <500000>;
+ regulator-max-microvolt = <750000>;
+ regulator-always-on;
+ regulator-over-current-protection;
+ lp-stop {
+ regulator-off-in-suspend;
+ };
+ standby-ddr-sr {
+ regulator-off-in-suspend;
+ };
+ standby-ddr-off {
+ regulator-off-in-suspend;
+ };
+ };
+
+ vdd_usb: ldo4 {
+ regulator-name = "vdd_usb";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ standby-ddr-sr {
+ regulator-on-in-suspend;
+ };
+ standby-ddr-off {
+ regulator-off-in-suspend;
+ };
+ };
+
+ vdda: ldo5 {
+ regulator-name = "vdda";
+ regulator-min-microvolt = <2900000>;
+ regulator-max-microvolt = <2900000>;
+ regulator-boot-on;
+ standby-ddr-sr {
+ regulator-off-in-suspend;
+ };
+ standby-ddr-off {
+ regulator-off-in-suspend;
+ };
+ };
+
+ v1v2_hdmi: ldo6 {
+ regulator-name = "v1v2_hdmi";
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ regulator-always-on;
+ standby-ddr-sr {
+ regulator-off-in-suspend;
+ };
+ standby-ddr-off {
+ regulator-off-in-suspend;
+ };
+ };
+
+ vref_ddr: vref_ddr {
+ regulator-name = "vref_ddr";
+ regulator-always-on;
+ regulator-over-current-protection;
+ lp-stop {
+ regulator-on-in-suspend;
+ };
+ standby-ddr-sr {
+ regulator-on-in-suspend;
+ };
+ standby-ddr-off {
+ regulator-off-in-suspend;
+ };
+ };
+
+ bst_out: boost {
+ regulator-name = "bst_out";
+ };
+
+ vbus_otg: pwr_sw1 {
+ regulator-name = "vbus_otg";
+ };
+
+ vbus_sw: pwr_sw2 {
+ regulator-name = "vbus_sw";
+ regulator-active-discharge = <1>;
+ };
+ };
+ };
+};
+
+&iwdg2 {
+ timeout-sec = <32>;
+ status = "okay";
+ secure-status = "okay";
+};
+
+&nvmem_layout {
+ nvmem-cells = <&cfg0_otp>,
+ <&part_number_otp>,
+ <&monotonic_otp>,
+ <&nand_otp>,
+ <&uid_otp>,
+ <&package_otp>,
+ <&hw2_otp>,
+ <&pkh_otp>,
+ <&board_id>;
+
+ nvmem-cell-names = "cfg0_otp",
+ "part_number_otp",
+ "monotonic_otp",
+ "nand_otp",
+ "uid_otp",
+ "package_otp",
+ "hw2_otp",
+ "pkh_otp",
+ "board_id";
+};
+
+&pwr_regulators {
+ 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 = <STM32_PM_CSTOP_ALLOW_STANDBY_DDR_OFF>;
+ vdd-supply = <&vdd>;
+ vdd_3v3_usbfs-supply = <&vdd_usb>;
+};
+
+&rcc {
+ 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_PLL4R
+ 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 = 1066.0 MHz => P = 266 (AXI), Q = 533 (GPU), R = 533 (DDR) */
+ pll2: st,pll@1 {
+ compatible = "st,stm32mp1-pll";
+ reg = <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 {
+ compatible = "st,stm32mp1-pll";
+ reg = <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 {
+ compatible = "st,stm32mp1-pll";
+ reg = <3>;
+ cfg = <3 98 5 7 7 PQR(1,1,1)>;
+ };
+};
+
+&rng1 {
+ status = "okay";
+ secure-status = "okay";
+};
+
+&rtc {
+ status = "okay";
+ secure-status = "okay";
+};
+
+&sdmmc1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&sdmmc1_b4_pins_a>;
+ disable-wp;
+ st,neg-edge;
+ bus-width = <4>;
+ vmmc-supply = <&v3v3>;
+ status = "okay";
+};
+
+&timers15 {
+ secure-status = "okay";
+ st,hsi-cal-input = <7>;
+ st,csi-cal-input = <8>;
+};
+
+&uart4 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart4_pins_a>;
+ status = "okay";
+};
+
+&uart7 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart7_pins_b>;
+ status = "disabled";
+};
+
+&usart3 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&usart3_pins_b>;
+ uart-has-rtscts;
+ status = "disabled";
+};
+
+&usbotg_hs {
+ phys = <&usbphyc_port1 0>;
+ phy-names = "usb2-phy";
+ usb-role-switch;
+ status = "okay";
+};
+
+&usbphyc {
+ status = "okay";
+};
+
+&usbphyc_port0 {
+ phy-supply = <&vdd_usb>;
+};
+
+&usbphyc_port1 {
+ phy-supply = <&vdd_usb>;
+};
diff --git a/fdts/stm32mp15xx-edx.dtsi b/fdts/stm32mp15xx-edx.dtsi
new file mode 100644
index 000000000..dd921908b
--- /dev/null
+++ b/fdts/stm32mp15xx-edx.dtsi
@@ -0,0 +1,479 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
+/*
+ * Copyright (C) STMicroelectronics 2017 - All Rights Reserved
+ * Author: Ludovic Barre <ludovic.barre@st.com> for STMicroelectronics.
+ */
+
+#include <dt-bindings/clock/stm32mp1-clksrc.h>
+#include <dt-bindings/power/stm32mp1-power.h>
+#include "stm32mp15-ddr3-2x4Gb-1066-binG.dtsi"
+
+/ {
+ memory@c0000000 {
+ device_type = "memory";
+ reg = <0xC0000000 0x40000000>;
+ };
+
+ vin: vin {
+ compatible = "regulator-fixed";
+ regulator-name = "vin";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ regulator-always-on;
+ };
+};
+
+&bsec {
+ board_id: board_id@ec {
+ reg = <0xec 0x4>;
+ st,non-secure-otp;
+ };
+};
+
+&clk_hse {
+ st,digbypass;
+};
+
+&cpu0{
+ cpu-supply = <&vddcore>;
+};
+
+&hash1 {
+ status = "okay";
+};
+
+&i2c4 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c4_pins_a>;
+ i2c-scl-rising-time-ns = <185>;
+ i2c-scl-falling-time-ns = <20>;
+ clock-frequency = <400000>;
+ status = "okay";
+ secure-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";
+ secure-status = "okay";
+
+ regulators {
+ compatible = "st,stpmic1-regulators";
+ buck1-supply = <&vin>;
+ buck2-supply = <&vin>;
+ buck3-supply = <&vin>;
+ buck4-supply = <&vin>;
+ ldo1-supply = <&v3v3>;
+ ldo2-supply = <&v3v3>;
+ ldo3-supply = <&vdd_ddr>;
+ ldo4-supply = <&vin>;
+ ldo5-supply = <&v3v3>;
+ ldo6-supply = <&v3v3>;
+ vref_ddr-supply = <&vin>;
+ boost-supply = <&vin>;
+ pwr_sw1-supply = <&bst_out>;
+ pwr_sw2-supply = <&bst_out>;
+
+ vddcore: buck1 {
+ regulator-name = "vddcore";
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1350000>;
+ regulator-always-on;
+ regulator-initial-mode = <0>;
+ regulator-over-current-protection;
+ lp-stop {
+ regulator-on-in-suspend;
+ regulator-suspend-microvolt = <1200000>;
+ };
+ lplv-stop {
+ regulator-on-in-suspend;
+ regulator-suspend-microvolt = <900000>;
+ };
+ standby-ddr-sr {
+ regulator-off-in-suspend;
+ };
+ standby-ddr-off {
+ regulator-off-in-suspend;
+ };
+ };
+
+ 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;
+ lp-stop {
+ regulator-suspend-microvolt = <1350000>;
+ regulator-on-in-suspend;
+ };
+ lplv-stop {
+ regulator-suspend-microvolt = <1350000>;
+ regulator-on-in-suspend;
+ };
+ standby-ddr-sr {
+ regulator-suspend-microvolt = <1350000>;
+ regulator-on-in-suspend;
+ };
+ standby-ddr-off {
+ regulator-off-in-suspend;
+ };
+ };
+
+ 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;
+ lp-stop {
+ regulator-suspend-microvolt = <3300000>;
+ regulator-on-in-suspend;
+ };
+ lplv-stop {
+ regulator-suspend-microvolt = <3300000>;
+ regulator-on-in-suspend;
+ };
+ standby-ddr-sr {
+ regulator-suspend-microvolt = <3300000>;
+ regulator-on-in-suspend;
+ };
+ standby-ddr-off {
+ regulator-suspend-microvolt = <3300000>;
+ regulator-on-in-suspend;
+ };
+ };
+
+ v3v3: buck4 {
+ regulator-name = "v3v3";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ regulator-over-current-protection;
+ regulator-initial-mode = <0>;
+ standby-ddr-sr {
+ regulator-off-in-suspend;
+ };
+ standby-ddr-off {
+ regulator-off-in-suspend;
+ };
+ };
+
+ vdda: ldo1 {
+ regulator-name = "vdda";
+ regulator-min-microvolt = <2900000>;
+ regulator-max-microvolt = <2900000>;
+ standby-ddr-sr {
+ regulator-off-in-suspend;
+ };
+ standby-ddr-off {
+ regulator-off-in-suspend;
+ };
+ };
+
+ v2v8: ldo2 {
+ regulator-name = "v2v8";
+ regulator-min-microvolt = <2800000>;
+ regulator-max-microvolt = <2800000>;
+ standby-ddr-sr {
+ regulator-off-in-suspend;
+ };
+ standby-ddr-off {
+ regulator-off-in-suspend;
+ };
+ };
+
+ vtt_ddr: ldo3 {
+ regulator-name = "vtt_ddr";
+ regulator-min-microvolt = <500000>;
+ regulator-max-microvolt = <750000>;
+ regulator-always-on;
+ regulator-over-current-protection;
+ lp-stop {
+ regulator-off-in-suspend;
+ };
+ lplv-stop {
+ regulator-off-in-suspend;
+ };
+ standby-ddr-sr {
+ regulator-off-in-suspend;
+ };
+ standby-ddr-off {
+ regulator-off-in-suspend;
+ };
+ };
+
+ vdd_usb: ldo4 {
+ regulator-name = "vdd_usb";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ standby-ddr-sr {
+ regulator-on-in-suspend;
+ };
+ standby-ddr-off {
+ regulator-off-in-suspend;
+ };
+ };
+
+ vdd_sd: ldo5 {
+ regulator-name = "vdd_sd";
+ regulator-min-microvolt = <2900000>;
+ regulator-max-microvolt = <2900000>;
+ regulator-boot-on;
+ standby-ddr-sr {
+ regulator-off-in-suspend;
+ };
+ standby-ddr-off {
+ regulator-off-in-suspend;
+ };
+ };
+
+ v1v8: ldo6 {
+ regulator-name = "v1v8";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ standby-ddr-sr {
+ regulator-off-in-suspend;
+ };
+ standby-ddr-off {
+ regulator-off-in-suspend;
+ };
+ };
+
+ vref_ddr: vref_ddr {
+ regulator-name = "vref_ddr";
+ regulator-always-on;
+ regulator-over-current-protection;
+ lp-stop {
+ regulator-on-in-suspend;
+ };
+ lplv-stop {
+ regulator-on-in-suspend;
+ };
+ standby-ddr-sr {
+ regulator-on-in-suspend;
+ };
+ standby-ddr-off {
+ regulator-off-in-suspend;
+ };
+ };
+
+ bst_out: boost {
+ regulator-name = "bst_out";
+ };
+
+ vbus_otg: pwr_sw1 {
+ regulator-name = "vbus_otg";
+ };
+
+ vbus_sw: pwr_sw2 {
+ regulator-name = "vbus_sw";
+ regulator-active-discharge = <1>;
+ };
+ };
+ };
+};
+
+&iwdg2 {
+ timeout-sec = <32>;
+ status = "okay";
+ secure-status = "okay";
+};
+
+&nvmem_layout {
+ nvmem-cells = <&cfg0_otp>,
+ <&part_number_otp>,
+ <&monotonic_otp>,
+ <&nand_otp>,
+ <&uid_otp>,
+ <&package_otp>,
+ <&hw2_otp>,
+ <&pkh_otp>,
+ <&board_id>;
+
+ nvmem-cell-names = "cfg0_otp",
+ "part_number_otp",
+ "monotonic_otp",
+ "nand_otp",
+ "uid_otp",
+ "package_otp",
+ "hw2_otp",
+ "pkh_otp",
+ "board_id";
+};
+
+&pwr_regulators {
+ system_suspend_supported_soc_modes = <
+ STM32_PM_CSLEEP_RUN
+ STM32_PM_CSTOP_ALLOW_LP_STOP
+ STM32_PM_CSTOP_ALLOW_LPLV_STOP
+ STM32_PM_CSTOP_ALLOW_STANDBY_DDR_SR
+ >;
+ system_off_soc_mode = <STM32_PM_CSTOP_ALLOW_STANDBY_DDR_OFF>;
+ vdd-supply = <&vdd>;
+ vdd_3v3_usbfs-supply = <&vdd_usb>;
+};
+
+&rcc {
+ 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_PLL4R
+ 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 = 1066.0 MHz => P = 266 (AXI), Q = 533 (GPU), R = 533 (DDR) */
+ pll2: st,pll@1 {
+ compatible = "st,stm32mp1-pll";
+ reg = <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 {
+ compatible = "st,stm32mp1-pll";
+ reg = <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 {
+ compatible = "st,stm32mp1-pll";
+ reg = <3>;
+ cfg = <3 98 5 7 7 PQR(1,1,1)>;
+ };
+};
+
+&rng1 {
+ status = "okay";
+ secure-status = "okay";
+};
+
+&rtc {
+ status = "okay";
+ secure-status = "okay";
+};
+
+&sdmmc1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&sdmmc1_b4_pins_a &sdmmc1_dir_pins_a>;
+ disable-wp;
+ st,sig-dir;
+ st,neg-edge;
+ st,use-ckin;
+ bus-width = <4>;
+ vmmc-supply = <&vdd_sd>;
+ sd-uhs-sdr12;
+ sd-uhs-sdr25;
+ sd-uhs-sdr50;
+ sd-uhs-ddr50;
+ sd-uhs-sdr104;
+ status = "okay";
+};
+
+&sdmmc2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&sdmmc2_b4_pins_a &sdmmc2_d47_pins_a>;
+ non-removable;
+ no-sd;
+ no-sdio;
+ st,neg-edge;
+ bus-width = <8>;
+ vmmc-supply = <&v3v3>;
+ vqmmc-supply = <&vdd>;
+ mmc-ddr-3_3v;
+ status = "okay";
+};
+
+&timers15 {
+ secure-status = "okay";
+ st,hsi-cal-input = <7>;
+ st,csi-cal-input = <8>;
+};
+
+&uart4 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart4_pins_a>;
+ status = "okay";
+};
+
+&usbotg_hs {
+ vbus-supply = <&vbus_otg>;
+};
+
+&usbphyc_port0 {
+ phy-supply = <&vdd_usb>;
+};
+
+&usbphyc_port1 {
+ phy-supply = <&vdd_usb>;
+};
diff --git a/fdts/stm32mp15xx-evx.dtsi b/fdts/stm32mp15xx-evx.dtsi
new file mode 100644
index 000000000..fee2bac86
--- /dev/null
+++ b/fdts/stm32mp15xx-evx.dtsi
@@ -0,0 +1,71 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
+/*
+ * Copyright (C) STMicroelectronics 2017 - All Rights Reserved
+ * Author: Ludovic Barre <ludovic.barre@st.com> for STMicroelectronics.
+ */
+
+&fmc {
+ pinctrl-names = "default";
+ pinctrl-0 = <&fmc_pins_a>;
+ status = "okay";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ nand@0 {
+ reg = <0>;
+ nand-on-flash-bbt;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ };
+};
+
+&i2c4 {
+ pmic: stpmic@33 {
+ regulators {
+ v1v8: ldo6 {
+ regulator-enable-ramp-delay = <300000>;
+ };
+ };
+ };
+};
+
+&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>;
+ };
+};
+
+&timers12 {
+ status = "disabled";
+};
+
+&usart3 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&usart3_pins_a>;
+ uart-has-rtscts;
+ status = "disabled";
+};
+
+&usbotg_hs {
+ pinctrl-0 = <&usbotg_hs_pins_a>;
+ pinctrl-names = "default";
+ phys = <&usbphyc_port1 0>;
+ phy-names = "usb2-phy";
+ status = "okay";
+};
+
+&usbphyc {
+ status = "okay";
+};
diff --git a/fdts/stm32mp15xxaa-pinctrl.dtsi b/fdts/stm32mp15xxaa-pinctrl.dtsi
new file mode 100644
index 000000000..341529b30
--- /dev/null
+++ b/fdts/stm32mp15xxaa-pinctrl.dtsi
@@ -0,0 +1,86 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
+/*
+ * Copyright (C) STMicroelectronics 2019 - All Rights Reserved
+ * Author: Alexandre Torgue <alexandre.torgue@st.com>
+ */
+
+&pinctrl {
+ st,package = <STM32MP_PKG_AA>;
+
+ gpioa: gpio@50002000 {
+ status = "okay";
+ ngpios = <16>;
+ gpio-ranges = <&pinctrl 0 0 16>;
+ };
+
+ gpiob: gpio@50003000 {
+ status = "okay";
+ ngpios = <16>;
+ gpio-ranges = <&pinctrl 0 16 16>;
+ };
+
+ gpioc: gpio@50004000 {
+ status = "okay";
+ ngpios = <16>;
+ gpio-ranges = <&pinctrl 0 32 16>;
+ };
+
+ gpiod: gpio@50005000 {
+ status = "okay";
+ ngpios = <16>;
+ gpio-ranges = <&pinctrl 0 48 16>;
+ };
+
+ gpioe: gpio@50006000 {
+ status = "okay";
+ ngpios = <16>;
+ gpio-ranges = <&pinctrl 0 64 16>;
+ };
+
+ gpiof: gpio@50007000 {
+ status = "okay";
+ ngpios = <16>;
+ gpio-ranges = <&pinctrl 0 80 16>;
+ };
+
+ gpiog: gpio@50008000 {
+ status = "okay";
+ ngpios = <16>;
+ gpio-ranges = <&pinctrl 0 96 16>;
+ };
+
+ gpioh: gpio@50009000 {
+ status = "okay";
+ ngpios = <16>;
+ gpio-ranges = <&pinctrl 0 112 16>;
+ };
+
+ gpioi: gpio@5000a000 {
+ status = "okay";
+ ngpios = <16>;
+ gpio-ranges = <&pinctrl 0 128 16>;
+ };
+
+ gpioj: gpio@5000b000 {
+ status = "okay";
+ ngpios = <16>;
+ gpio-ranges = <&pinctrl 0 144 16>;
+ };
+
+ gpiok: gpio@5000c000 {
+ status = "okay";
+ ngpios = <8>;
+ gpio-ranges = <&pinctrl 0 160 8>;
+ };
+};
+
+&pinctrl_z {
+ st,package = <STM32MP_PKG_AA>;
+
+ gpioz: gpio@54004000 {
+ status = "okay";
+ secure-status = "okay";
+ ngpios = <8>;
+ gpio-ranges = <&pinctrl_z 0 400 8>;
+ };
+};
diff --git a/fdts/stm32mp15xxab-pinctrl.dtsi b/fdts/stm32mp15xxab-pinctrl.dtsi
new file mode 100644
index 000000000..d29af8986
--- /dev/null
+++ b/fdts/stm32mp15xxab-pinctrl.dtsi
@@ -0,0 +1,57 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
+/*
+ * Copyright (C) STMicroelectronics 2019 - All Rights Reserved
+ * Author: Alexandre Torgue <alexandre.torgue@st.com>
+ */
+
+&pinctrl {
+ st,package = <STM32MP_PKG_AB>;
+
+ 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/stm32mp15xxac-pinctrl.dtsi b/fdts/stm32mp15xxac-pinctrl.dtsi
new file mode 100644
index 000000000..02070bba5
--- /dev/null
+++ b/fdts/stm32mp15xxac-pinctrl.dtsi
@@ -0,0 +1,74 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
+/*
+ * Copyright (C) STMicroelectronics 2019 - All Rights Reserved
+ * Author: Alexandre Torgue <alexandre.torgue@st.com>
+ */
+
+&pinctrl {
+ st,package = <STM32MP_PKG_AC>;
+
+ 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 {
+ st,package = <STM32MP_PKG_AC>;
+
+ gpioz: gpio@54004000 {
+ status = "okay";
+ secure-status = "okay";
+ ngpios = <8>;
+ gpio-ranges = <&pinctrl_z 0 400 8>;
+ };
+};
diff --git a/fdts/stm32mp15xxad-pinctrl.dtsi b/fdts/stm32mp15xxad-pinctrl.dtsi
new file mode 100644
index 000000000..023f5404c
--- /dev/null
+++ b/fdts/stm32mp15xxad-pinctrl.dtsi
@@ -0,0 +1,57 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
+/*
+ * Copyright (C) STMicroelectronics 2019 - All Rights Reserved
+ * Author: Alexandre Torgue <alexandre.torgue@st.com>
+ */
+
+&pinctrl {
+ st,package = <STM32MP_PKG_AD>;
+
+ 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/arch/aarch32/arch.h b/include/arch/aarch32/arch.h
index 20175481f..3aa7f9126 100644
--- a/include/arch/aarch32/arch.h
+++ b/include/arch/aarch32/arch.h
@@ -457,13 +457,13 @@
* system level implementation of the Generic Timer.
******************************************************************************/
/* Physical Count register. */
-#define CNTPCT_LO U(0x0)
+#define CNTBASEN_CNTPCT_LO U(0x0)
/* Counter Frequency register. */
#define CNTBASEN_CNTFRQ U(0x10)
/* Physical Timer CompareValue register. */
-#define CNTP_CVAL_LO U(0x20)
+#define CNTBASEN_CNTP_CVAL_LO U(0x20)
/* Physical Timer Control register. */
-#define CNTP_CTL U(0x2c)
+#define CNTBASEN_CNTP_CTL U(0x2c)
/* Physical timer control register bit fields shifts and masks */
#define CNTP_CTL_ENABLE_SHIFT 0
@@ -522,6 +522,9 @@
#define HSTR p15, 4, c1, c1, 3
#define CNTHCTL p15, 4, c14, c1, 0
#define CNTKCTL p15, 0, c14, c1, 0
+#define CNTP_TVAL p15, 0, c14, c2, 0
+#define CNTP_CTL p15, 0, c14, c2, 1
+#define CNTV_CTL p15, 0, c14, c3, 1
#define VPIDR p15, 4, c0, c0, 0
#define VMPIDR p15, 4, c0, c0, 5
#define ISR p15, 0, c12, c1, 0
@@ -531,6 +534,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
@@ -581,6 +585,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
******************************************************************************/
@@ -634,6 +644,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/arch/aarch32/arch_helpers.h b/include/arch/aarch32/arch_helpers.h
index cbac84b93..8749dc91d 100644
--- a/include/arch/aarch32/arch_helpers.h
+++ b/include/arch/aarch32/arch_helpers.h
@@ -246,6 +246,9 @@ 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(cntp_tval, CNTP_TVAL)
+DEFINE_COPROCR_RW_FUNCS(cntp_ctl, CNTP_CTL)
+DEFINE_COPROCR_RW_FUNCS(cntv_ctl, CNTV_CTL)
DEFINE_COPROCR_RW_FUNCS(cnthp_ctl_el2, CNTHP_CTL)
DEFINE_COPROCR_RW_FUNCS(cnthp_tval_el2, CNTHP_TVAL)
DEFINE_COPROCR_RW_FUNCS_64(cnthp_cval_el2, CNTHP_CVAL_64)
@@ -288,6 +291,7 @@ DEFINE_COPROCR_READ_FUNC(pmcr, PMCR)
* Address translation
*/
DEFINE_COPROCR_WRITE_FUNC(ats1cpr, ATS1CPR)
+DEFINE_COPROCR_WRITE_FUNC(ats1cpw, ATS1CPW)
DEFINE_COPROCR_WRITE_FUNC(ats1hr, ATS1HR)
DEFINE_COPROCR_RW_FUNCS_64(par, PAR_64)
diff --git a/include/arch/aarch32/el3_common_macros.S b/include/arch/aarch32/el3_common_macros.S
index 7559de446..4fd746d5a 100644
--- a/include/arch/aarch32/el3_common_macros.S
+++ b/include/arch/aarch32/el3_common_macros.S
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2016-2020, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -329,6 +329,11 @@
bl inv_dcache_range
#endif
+ /*
+ * zeromem uses r12 whereas it is used to save previous BL arg3,
+ * save it in r7
+ */
+ mov r7, r12
ldr r0, =__BSS_START__
ldr r1, =__BSS_SIZE__
bl zeromem
@@ -339,6 +344,9 @@
bl zeromem
#endif
+ /* Restore r12 */
+ mov r12, r7
+
#if defined(IMAGE_BL1) || (defined(IMAGE_BL2) && BL2_AT_EL3 && BL2_IN_XIP_MEM)
/* -----------------------------------------------------
* Copy data from ROM to RAM.
diff --git a/include/arch/aarch64/arch.h b/include/arch/aarch64/arch.h
index 3ff2912f1..307dad585 100644
--- a/include/arch/aarch64/arch.h
+++ b/include/arch/aarch64/arch.h
@@ -670,13 +670,13 @@
* system level implementation of the Generic Timer.
******************************************************************************/
/* Physical Count register. */
-#define CNTPCT_LO U(0x0)
+#define CNTBASEN_CNTPCT_LO U(0x0)
/* Counter Frequency register. */
#define CNTBASEN_CNTFRQ U(0x10)
/* Physical Timer CompareValue register. */
-#define CNTP_CVAL_LO U(0x20)
+#define CNTBASEN_CNTP_CVAL_LO U(0x20)
/* Physical Timer Control register. */
-#define CNTP_CTL U(0x2c)
+#define CNTBASEN_CNTP_CTL U(0x2c)
/* PMCR_EL0 definitions */
#define PMCR_EL0_RESET_VAL U(0x0)
diff --git a/include/common/confine_array_index.h b/include/common/confine_array_index.h
new file mode 100644
index 000000000..23c8b4e67
--- /dev/null
+++ b/include/common/confine_array_index.h
@@ -0,0 +1,145 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/* Copyright (c) 2020 Linaro Limited */
+// Copyright 2019 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/*
+ * Content of LICENSE file mentioned above:
+Copyright 2019 The Fuchsia Authors. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+ * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+ * Neither the name of Google Inc. nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef FBL_CONFINE_ARRAY_INDEX_H_
+#define FBL_CONFINE_ARRAY_INDEX_H_
+
+#include <stddef.h>
+
+// confine_array_index() bounds-checks and sanitizes an array index safely in the presence of
+// speculative execution information leak bugs such as Spectre V1. confine_array_index() always
+// returns a sanitized index, even in speculative-path execution.
+//
+// Callers need to combine confine_array_index with a conventional bounds check; the bounds
+// check will return any necessary errors in the nonspeculative path, confine_array_index will
+// confine indexes in the speculative path.
+//
+// Use:
+// confine_array_index() returns |index|, if it is < size, or 0 if |index| is >= size.
+//
+// Example (may leak table1 contents):
+// 1: int lookup3(size_t index) {
+// 2: if (index >= table1_size) {
+// 3: return -1;
+// 4: }
+// 5: size_t index2 = table1[index];
+// 6: return table2[index2];
+// 7: }
+//
+// Converted:
+//
+// 1: int lookup3(size_t index) {
+// 2: if (index >= table1_size) {
+// 3: return -1;
+// 4: }
+// 5: size_t safe_index = confine_array_index(index, table1_size);
+// 6: size_t index2 = table1[safe_index];
+// 7: return table2[index2];
+// 8: }
+#ifdef __aarch64__
+static inline size_t confine_array_index(size_t index, size_t size) {
+ size_t safe_index;
+ // Use a conditional select and a CSDB barrier to enforce validation of |index|.
+ // See "Cache Speculation Side-channels" whitepaper, section "Software Mitigation".
+ // "" The combination of both a conditional select/conditional move and the new barrier are
+ // sufficient to address this problem on ALL Arm implementations... ""
+ asm(
+ "cmp %1, %2\n" // %1 holds the unsanitized index
+ "csel %0, %1, xzr, lo\n" // Select index or zero based on carry (%1 within range)
+ "csdb\n"
+ : "=r"(safe_index)
+ : "r"(index), "r"(size)
+ : "cc");
+ return safe_index;
+}
+#endif
+#ifdef __arm__
+static inline size_t confine_array_index(size_t index, size_t size)
+{
+ size_t ret_val = index;
+
+ /*
+ * For the ARMv7/AArch32 case we're basing the select and barrier
+ * code on __load_no_speculate1() in <speculation_barrier.h> as we
+ * lack the csel instruction.
+ */
+
+#ifdef __thumb2__
+ asm volatile (
+ ".syntax unified\n"
+ "cmp %0, %1\n"
+ "it cs\n"
+#ifdef __clang__
+#pragma clang diagnostic push
+ /* Avoid 'deprecated instruction in IT block [-Werror,-Winline-asm]' */
+#pragma clang diagnostic ignored "-Winline-asm"
+#endif
+ "movcs %0, #0\n"
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+ ".inst.n 0xf3af\t@ CSDB\n"
+ ".inst.n 0x8014\t@ CSDB"
+ : "+r" (ret_val) : "r" (size) : "cc");
+#else
+ asm volatile (
+ ".syntax unified\n"
+ "cmp %0, %1\n" /* %0 holds the unsanitized index */
+ "movcs %0, #0\n"
+ ".inst 0xe320f014\t@ CSDB"
+ : "+r" (ret_val) : "r" (size) : "cc");
+#endif
+
+ return ret_val;
+}
+#endif /* __arm__ */
+
+#ifdef __x86_64__
+static inline size_t confine_array_index(size_t index, size_t size) {
+ size_t safe_index = 0;
+ // Use a conditional move to enforce validation of |index|.
+ // The conditional move has a data dependency on the result of a comparison and cannot
+ // execute until the comparison is resolved.
+ // See "Software Techniques for Managing Speculation on AMD Processors", Mitigation V1-2.
+ // See "Analyzing potential bounds check bypass vulnerabilities", Revision 002,
+ // Section 5.2 Bounds clipping
+ __asm__(
+ "cmp %1, %2\n"
+ "cmova %1, %0\n" // Select between $0 and |index|
+ : "+r"(safe_index)
+ : "r"(index), "r"(size)
+ : "cc");
+ return safe_index;
+}
+#endif
+#endif // FBL_CONFINE_ARRAY_INDEX_H_
diff --git a/include/common/speculation_barrier.h b/include/common/speculation_barrier.h
new file mode 100644
index 000000000..ef74e3617
--- /dev/null
+++ b/include/common/speculation_barrier.h
@@ -0,0 +1,508 @@
+/* SPDX-License-Identifier: BSL-1.0 */
+/* Copyright (c) 2017 Arm Limited. All rights reserved.
+
+ Boost Software License - Version 1.0 - August 17th, 2003
+
+ Permission is hereby granted, free of charge, to any person or organization
+ obtaining a copy of the software and accompanying documentation covered by
+ this license (the "Software") to use, reproduce, display, distribute,
+ execute, and transmit the Software, and to prepare derivative works of the
+ Software, and to permit third-parties to whom the Software is furnished to do
+ so, all subject to the following:
+
+ The copyright notices in the Software and this entire statement, including
+ the above license grant, this restriction and the following disclaimer, must
+ be included in all copies of the Software, in whole or in part, and all
+ derivative works of the Software, unless such copies or derivative works are
+ solely in the form of machine-executable object code generated by a source
+ language processor.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+ SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE FOR
+ ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ DEALINGS IN THE SOFTWARE. */
+
+
+#ifdef __HAVE_LOAD_NO_SPECULATE
+#define load_no_speculate(__ptr, __low, __high) \
+(__extension__ ({ \
+ __typeof__ ((__ptr)) __ptr_once = (__ptr); \
+ __builtin_load_no_speculate (__ptr_once, __low, __high, \
+ 0, __ptr_once); \
+}))
+
+#define load_no_speculate_fail(__ptr, __low, __high, __failval) \
+(__extension__ ({ \
+ __typeof__ ((__ptr)) __ptr_once = (__ptr); \
+ __builtin_load_no_speculate (__ptr_once, __low, __high, \
+ __failval, __ptr_once); \
+}))
+
+#define load_no_speculate_cmp(__ptr, __low, __high, __failval, __cmpptr) \
+ (__builtin_load_no_speculate (__ptr, __low, __high, __failval, __cmpptr))
+
+#else
+
+#ifdef __GNUC__
+#define __UNUSED __attribute__((unused))
+#else
+#define __UNUSED
+#endif
+
+#ifdef __aarch64__
+
+#define __load_no_speculate1(__ptr, __low, __high, __failval, \
+ __cmpptr, __w, __sz) \
+(__extension__ ({ \
+ __typeof__ (0 + (*(__ptr))) __nln_val; \
+ /* This typecasting is required to ensure correct handling of upper \
+ bits of failval, to ensure a clean return from the CSEL below. */ \
+ __typeof__(*(__ptr)) __fv \
+ = (__typeof__(*(__ptr)))(unsigned long long) (__failval); \
+ /* If __high is explicitly NULL, we must not emit the \
+ upper-bound comparison. We need to cast __high to an \
+ unsigned long long before handing it to __builtin_constant_p to \
+ ensure that clang/llvm correctly detects NULL as a constant if it \
+ is defined as (void*) 0. */ \
+ if (__builtin_constant_p ((unsigned long long)__high) \
+ && __high == ((void *)0)) \
+ { \
+ __asm__ volatile ( \
+ "cmp\t%[__c], %[__l]\n\t" \
+ "bcc\t.ns%=\n\t" \
+ "ldr" __sz "\t%" __w "[__v], %[__p]\n" \
+ ".ns%=:\n\t" \
+ "csel\t%" __w "[__v], %" __w "[__v], %" __w "[__f], cs\n\t" \
+ "hint\t#0x14 // CSDB" \
+ /* The value we have loaded, or failval if the condition check \
+ fails. */ \
+ : [__v] "=&r" (__nln_val) \
+ /* The pointer we wish to use for comparisons, and the low and \
+ high bounds to use in that comparison. Note that this need \
+ not be the same as the pointer from which we will load. */ \
+ : [__c] "r" (__cmpptr), [__l] "r" (__low), \
+ /* The memory location from which we will load. */ \
+ [__p] "m" (*(__ptr)), \
+ /* The value to return if the condition check fails. */ \
+ [__f] "rZ" (__fv) \
+ /* We always clobber the condition codes. */ \
+ : "cc"); \
+ } \
+ else \
+ { \
+ __asm__ volatile ( \
+ "cmp\t%[__c], %[__l]\n\t" \
+ "ccmp\t%[__c], %[__h], 2, cs\n\t" \
+ "bcs\t.ns%=\n\t" \
+ "ldr" __sz "\t%" __w "[__v], %[__p]\n" \
+ ".ns%=:\n\t" \
+ "csel\t%" __w "[__v], %" __w "[__v], %" __w "[__f], cc\n\t" \
+ "hint\t#0x14 // CSDB" \
+ /* The value we have loaded, or failval if the condition check \
+ fails. */ \
+ : [__v] "=&r" (__nln_val) \
+ /* The pointer we wish to use for comparisons, and the low and \
+ high bounds to use in that comparison. Note that this need \
+ not be the same as the pointer from which we will load. */ \
+ : [__c] "r" (__cmpptr), [__l] "r" (__low), \
+ [__h] "r" (__high), \
+ /* The memory location from which we will load. */ \
+ [__p] "m" (*(__ptr)), \
+ /* The value to return if the condition check fails. */ \
+ [__f] "rZ" (__fv) \
+ /* We always clobber the condition codes. */ \
+ : "cc"); \
+ } \
+ (__typeof__ (*(__ptr))) __nln_val; \
+}))
+
+#define __load_no_speculate(__ptr, __low, __high, __failval, __cmpptr) \
+(__extension__ ({ \
+ __typeof__ (0 + *(__ptr)) __nl_val; \
+ \
+ switch (sizeof(*(__ptr))) { \
+ case 1: \
+ __nl_val = __load_no_speculate1 (__ptr, __low, __high, \
+ __failval, __cmpptr, "w", "b"); \
+ break; \
+ case 2: \
+ __nl_val = __load_no_speculate1 (__ptr, __low, __high, \
+ __failval, __cmpptr, "w", "h"); \
+ break; \
+ case 4: \
+ __nl_val = __load_no_speculate1 (__ptr, __low, __high, \
+ __failval, __cmpptr, "w", ""); \
+ break; \
+ case 8: \
+ __nl_val = __load_no_speculate1 (__ptr, __low, __high, \
+ __failval, __cmpptr, "x", ""); \
+ break; \
+ default: \
+ { \
+ char __static_assert_no_speculate_load_size_too_big \
+ [sizeof (__nl_val) > 8 ? -1 : 1] __UNUSED; \
+ break; \
+ } \
+ } \
+ \
+ (__typeof__ (*(__ptr))) __nl_val; \
+}))
+
+#define load_no_speculate(__ptr, __low, __high) \
+(__extension__ ({ \
+ __typeof__ ((__ptr)) __ptr_once = (__ptr); \
+ __load_no_speculate (__ptr_once, __low, __high, 0, __ptr_once); \
+}))
+
+#define load_no_speculate_fail(__ptr, __low, __high, __failval) \
+(__extension__ ({ \
+ __typeof__ ((__ptr)) __ptr_once = (__ptr); \
+ __load_no_speculate (__ptr_once, __low, __high, \
+ __failval, __ptr_once); \
+}))
+
+#define load_no_speculate_cmp(__ptr, __low, __high, __failval, __cmpptr) \
+ (__load_no_speculate (__ptr, __low, __high, __failval, __cmpptr))
+
+/* AArch32 support for ARM and Thumb-2. Thumb-1 is not supported. */
+#elif defined (__ARM_32BIT_STATE) && (defined (__thumb2__) || !defined (__thumb__))
+#ifdef __thumb2__
+/* Thumb2 case. */
+
+#define __load_no_speculate1(__ptr, __low, __high, __failval, \
+ __cmpptr, __sz) \
+(__extension__ ({ \
+ __typeof__ (0 + *(__ptr)) __nln_val; \
+ __typeof__(*(__ptr)) __fv \
+ = (__typeof__(*(__ptr)))(unsigned long) (__failval); \
+ /* If __high is explicitly NULL, we must not emit the \
+ upper-bound comparison. We need to cast __high to an \
+ unsigned long before handing it to __builtin_constant_p to \
+ ensure that clang/llvm correctly detects NULL as a constant if it \
+ is defined as (void*) 0. */ \
+ if (__builtin_constant_p ((unsigned long)__high) \
+ && __high == ((void *)0)) \
+ { \
+ __asm__ volatile ( \
+ ".syntax unified\n\t" \
+ "cmp\t%[__c], %[__l]\n\t" \
+ "bcc\t.ns%=\n\t" \
+ "ldr" __sz "\t%[__v], %[__p]\n" \
+ ".ns%=:\n\t" \
+ "it\tcc\n\t" \
+ "movcc\t%[__v], %[__f]\n\t" \
+ ".inst.n 0xf3af\t@ CSDB\n\t" \
+ ".inst.n 0x8014\t@ CSDB" \
+ /* The value we have loaded, or failval if the condition check \
+ fails. */ \
+ : [__v] "=&l" (__nln_val) \
+ /* The pointer we wish to use for comparisons, and the low and \
+ high bounds to use in that comparison. Note that this need \
+ not be the same as the pointer from which we will load. */ \
+ : [__c] "r" (__cmpptr), [__l] "r" (__low), \
+ /* The memory location from which we will load. */ \
+ [__p] "m" (*(__ptr)), \
+ /* The value to return if the condition check fails. */ \
+ [__f] "r" (__fv) \
+ /* We always clobber the condition codes. */ \
+ : "cc"); \
+ } \
+ else \
+ { \
+ __asm__ volatile ( \
+ ".syntax unified\n\t" \
+ "cmp\t%[__c], %[__l]\n\t" \
+ "it\tcs\n\t" \
+ "cmpcs\t%[__h], %[__c]\n\t" \
+ "bls\t.ns%=\n\t" \
+ "ldr" __sz "\t%[__v], %[__p]\n" \
+ ".ns%=:\n\t" \
+ "it\tls\n\t" \
+ "movls\t%[__v], %[__f]\n\t" \
+ ".inst.n 0xf3af\t@ CSDB\n\t" \
+ ".inst.n 0x8014\t@ CSDB" \
+ /* The value we have loaded, or failval if the condition check \
+ fails. */ \
+ : [__v] "=&l" (__nln_val) \
+ /* The pointer we wish to use for comparisons, and the low and \
+ high bounds to use in that comparison. Note that this need \
+ not be the same as the pointer from which we will load. */ \
+ : [__c] "r" (__cmpptr), [__l] "r" (__low), \
+ [__h] "r" (__high), \
+ /* The memory location from which we will load. */ \
+ [__p] "m" (*(__ptr)), \
+ /* The value to return if the condition check fails. */ \
+ [__f] "r" (__fv) \
+ /* We always clobber the condition codes. */ \
+ : "cc"); \
+ } \
+ (__typeof__ (*(__ptr))) __nln_val; \
+})) \
+ \
+/* Double-word version. */
+#define __load_no_speculate2(__ptr, __low, __high, __failval, \
+ __cmpptr) \
+(__extension__ ({ \
+ __typeof__ (0 + *(__ptr)) __nln_val; \
+ __typeof__(*(__ptr)) __fv \
+ = (__typeof__(*(__ptr)))(unsigned long) (__failval); \
+ /* If __high is explicitly NULL, we must not emit the \
+ upper-bound comparison. We need to cast __high to an \
+ unsigned long before handing it to __builtin_constant_p to \
+ ensure that clang/llvm correctly detects NULL as a constant if it \
+ is defined as (void*) 0. */ \
+ if (__builtin_constant_p ((unsigned long)__high) \
+ && __high == ((void *)0)) \
+ { \
+ __asm__ volatile ( \
+ ".syntax unified\n\t" \
+ "cmp\t%[__c], %[__l]\n\t" \
+ "bcc\t.ns%=\n\t" \
+ "ldr\t%Q[__v], [%[__p]]\n\t" \
+ "ldr\t%R[__v], [%[__p], #4]\n" \
+ ".ns%=:\n\t" \
+ "it\tcc\n\t" \
+ "movcc\t%Q[__v], %Q[__f]\n\t" \
+ "it\tcc\n\t" \
+ "movcc\t%R[__v], %R[__f]\n\t" \
+ ".inst.n 0xf3af\t@ CSDB\n\t" \
+ ".inst.n 0x8014\t@ CSDB" \
+ /* The value we have loaded, or failval if the condition check \
+ fails. */ \
+ : [__v] "=&l" (__nln_val) \
+ /* The pointer we wish to use for comparisons, and the low and \
+ high bounds to use in that comparison. Note that this need \
+ not be the same as the pointer from which we will load. */ \
+ : [__c] "r" (__cmpptr), [__l] "r" (__low), \
+ /* The memory location from which we will load. */ \
+ [__p] "r" (__ptr), \
+ /* The value to return if the condition check fails. */ \
+ [__f] "r" (__fv) \
+ /* We always clobber the condition codes. */ \
+ : "cc"); \
+ } \
+ else \
+ { \
+ __asm__ volatile ( \
+ ".syntax unified\n\t" \
+ "cmp\t%[__c], %[__l]\n\t" \
+ "it\tcs\n\t" \
+ "cmpcs\t%[__h], %[__c]\n\t" \
+ "bls\t.ns%=\n\t" \
+ "ldr\t%Q[__v], [%[__p]]\n\t" \
+ "ldr\t%R[__v], [%[__p], #4]\n" \
+ ".ns%=:\n\t" \
+ "it\tls\n\t" \
+ "movls\t%Q[__v], %Q[__f]\n\t" \
+ "it\tls\n\t" \
+ "movls\t%R[__v], %R[__f]\n\t" \
+ ".inst.n 0xf3af\t@ CSDB\n\t" \
+ ".inst.n 0x8014\t@ CSDB" \
+ /* The value we have loaded, or failval if the condition check \
+ fails. */ \
+ : [__v] "=&l" (__nln_val) \
+ /* The pointer we wish to use for comparisons, and the low and \
+ high bounds to use in that comparison. Note that this need \
+ not be the same as the pointer from which we will load. */ \
+ : [__c] "r" (__cmpptr), [__l] "r" (__low), \
+ [__h] "r" (__high), \
+ /* The memory location from which we will load. */ \
+ [__p] "r" (__ptr), \
+ /* The value to return if the condition check fails. */ \
+ [__f] "r" (__fv) \
+ /* We always clobber the condition codes. */ \
+ : "cc"); \
+ } \
+ (__typeof__ (*(__ptr))) __nln_val; \
+}))
+
+#else
+/* ARM case. */
+
+#define __load_no_speculate1(__ptr, __low, __high, __failval, \
+ __cmpptr, __sz) \
+(__extension__ ({ \
+ __typeof__ (0 + *(__ptr)) __nln_val; \
+ __typeof__(*(__ptr)) __fv \
+ = (__typeof__(*(__ptr)))(unsigned long) (__failval); \
+ /* If __high is explicitly NULL, we must not emit the \
+ upper-bound comparison. We need to cast __high to an \
+ unsigned long before handing it to __builtin_constant_p to \
+ ensure that clang/llvm correctly detects NULL as a constant if it \
+ is defined as (void*) 0. */ \
+ if (__builtin_constant_p ((unsigned long)__high) \
+ && __high == ((void *)0)) \
+ { \
+ __asm__ volatile ( \
+ ".syntax unified\n\t" \
+ "cmp\t%[__c], %[__l]\n\t" \
+ "ldr" __sz "cs\t%[__v], %[__p]\n\t" \
+ "movcc\t%[__v], %[__f]\n\t" \
+ ".inst 0xe320f014\t@ CSDB" \
+ /* The value we have loaded, or failval if the condition check \
+ fails. */ \
+ : [__v] "=&r" (__nln_val) \
+ /* The pointer we wish to use for comparisons, and the low and \
+ high bounds to use in that comparison. Note that this need \
+ not be the same as the pointer from which we will load. */ \
+ : [__c] "r" (__cmpptr), [__l] "r" (__low), \
+ /* The memory location from which we will load. */ \
+ [__p] "m" (*(__ptr)), \
+ /* The value to return if the condition check fails. */ \
+ [__f] "rKI" (__fv) \
+ /* We always clobber the condition codes. */ \
+ : "cc"); \
+ } \
+ else \
+ { \
+ __asm__ volatile ( \
+ ".syntax unified\n\t" \
+ "cmp\t%[__c], %[__l]\n\t" \
+ "cmpcs\t%[__h], %[__c]\n\t" \
+ "ldr" __sz "hi\t%[__v], %[__p]\n\t" \
+ "movls\t%[__v], %[__f]\n\t" \
+ ".inst 0xe320f014\t@ CSDB" \
+ /* The value we have loaded, or failval if the condition check \
+ fails. */ \
+ : [__v] "=&r" (__nln_val) \
+ /* The pointer we wish to use for comparisons, and the low and \
+ high bounds to use in that comparison. Note that this need \
+ not be the same as the pointer from which we will load. */ \
+ : [__c] "r" (__cmpptr), [__l] "r" (__low), \
+ [__h] "r" (__high), \
+ /* The memory location from which we will load. */ \
+ [__p] "m" (*(__ptr)), \
+ /* The value to return if the condition check fails. */ \
+ [__f] "rKI" (__fv) \
+ /* We always clobber the condition codes. */ \
+ : "cc"); \
+ } \
+ (__typeof__ (*(__ptr))) __nln_val; \
+}))
+
+/* Double-word version. */
+#define __load_no_speculate2(__ptr, __low, __high, __failval, \
+ __cmpptr) \
+(__extension__ ({ \
+ __typeof__ (0 + *(__ptr)) __nln_val; \
+ __typeof__(*(__ptr)) __fv \
+ = (__typeof__(*(__ptr)))(unsigned long) (__failval); \
+ /* If __high is explicitly NULL, we must not emit the \
+ upper-bound comparison. We need to cast __high to an \
+ unsigned long before handing it to __builtin_constant_p to \
+ ensure that clang/llvm correctly detects NULL as a constant if it \
+ is defined as (void*) 0. */ \
+ if (__builtin_constant_p ((unsigned long)__high) \
+ && __high == ((void *)0)) \
+ { \
+ __asm__ volatile ( \
+ ".syntax unified\n\t" \
+ "cmp\t%[__c], %[__l]\n\t" \
+ "ldrcs\t%Q[__v], [%[__p]]\n\t" \
+ "ldrcs\t%R[__v], [%[__p], #4]\n\t" \
+ "movcc\t%Q[__v], %Q[__f]\n\t" \
+ "movcc\t%R[__v], %R[__f]\n\t" \
+ ".inst 0xe320f014\t@ CSDB" \
+ /* The value we have loaded, or failval if the condition check \
+ fails. */ \
+ : [__v] "=&r" (__nln_val) \
+ /* The pointer we wish to use for comparisons, and the low and \
+ high bounds to use in that comparison. Note that this need \
+ not be the same as the pointer from which we will load. */ \
+ : [__c] "r" (__cmpptr), [__l] "r" (__low), \
+ /* The memory location from which we will load. */ \
+ [__p] "r" (__ptr), \
+ /* The value to return if the condition check fails. */ \
+ [__f] "r" (__fv) \
+ /* We always clobber the condition codes. */ \
+ : "cc"); \
+ } \
+ else \
+ { \
+ __asm__ volatile ( \
+ ".syntax unified\n\t" \
+ "cmp\t%[__c], %[__l]\n\t" \
+ "cmpcs\t%[__h], %[__c]\n\t" \
+ "ldrhi\t%Q[__v], [%[__p]]\n\t" \
+ "ldrhi\t%R[__v], [%[__p], #4]\n\t" \
+ "movls\t%Q[__v], %Q[__f]\n\t" \
+ "movls\t%R[__v], %R[__f]\n\t" \
+ ".inst 0xe320f014\t@ CSDB" \
+ /* The value we have loaded, or failval if the condition check \
+ fails. */ \
+ : [__v] "=&r" (__nln_val) \
+ /* The pointer we wish to use for comparisons, and the low and \
+ high bounds to use in that comparison. Note that this need \
+ not be the same as the pointer from which we will load. */ \
+ : [__c] "r" (__cmpptr), [__l] "r" (__low), \
+ [__h] "r" (__high), \
+ /* The memory location from which we will load. */ \
+ [__p] "r" (__ptr), \
+ /* The value to return if the condition check fails. */ \
+ [__f] "r" (__fv) \
+ /* We always clobber the condition codes. */ \
+ : "cc"); \
+ } \
+ (__typeof__ (*(__ptr))) __nln_val; \
+}))
+
+#endif // __thumb2__
+
+/* Common to ARM and Thumb2. */
+
+#define __load_no_speculate(__ptr, __low, __high, __failval, __cmpptr) \
+(__extension__ ({ \
+ __typeof__ (0 + *(__ptr)) __nl_val; \
+ \
+ switch (sizeof(*(__ptr))) { \
+ case 1: \
+ __nl_val = __load_no_speculate1 (__ptr, __low, __high, \
+ __failval, __cmpptr, "b"); \
+ break; \
+ case 2: \
+ __nl_val = __load_no_speculate1 (__ptr, __low, __high, \
+ __failval, __cmpptr, "h"); \
+ break; \
+ case 4: \
+ __nl_val = __load_no_speculate1 (__ptr, __low, __high, \
+ __failval, __cmpptr, ""); \
+ break; \
+ case 8: \
+ __nl_val = __load_no_speculate2 (__ptr, __low, __high, \
+ __failval, __cmpptr); \
+ break; \
+ default: \
+ { \
+ char __static_assert_no_speculate_load_size_too_big \
+ [sizeof (__nl_val) > 8 ? -1 : 1] __UNUSED; \
+ break; \
+ } \
+ } \
+ \
+ (__typeof__ (*(__ptr))) __nl_val; \
+}))
+
+#define load_no_speculate(__ptr, __low, __high) \
+(__extension__ ({ \
+ __typeof__ ((__ptr)) __ptr_once = (__ptr); \
+ __load_no_speculate (__ptr_once, __low, __high, 0, __ptr_once); \
+}))
+
+#define load_no_speculate_fail(__ptr, __low, __high, __failval) \
+(__extension__ ({ \
+ __typeof__ ((__ptr)) __ptr_once = (__ptr); \
+ __load_no_speculate (__ptr_once, __low, __high, \
+ __failval, __ptr_once); \
+}))
+
+#define load_no_speculate_cmp(__ptr, __low, __high, __failval, __cmpptr) \
+ (__load_no_speculate (__ptr, __low, __high, __failval, __cmpptr))
+
+#else
+#error "No fallback provided for load_no_speculate"
+#endif
+
+#endif
diff --git a/include/drivers/arm/tzc400.h b/include/drivers/arm/tzc400.h
index 32aeb0350..a0d134d64 100644
--- a/include/drivers/arm/tzc400.h
+++ b/include/drivers/arm/tzc400.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014-2018, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2014-2019, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -33,6 +33,7 @@
#define BUILD_CONFIG_NR_SHIFT 0
#define BUILD_CONFIG_NR_MASK U(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.
@@ -103,39 +104,40 @@
******************************************************************************/
void tzc400_init(uintptr_t base);
void tzc400_configure_region0(unsigned int sec_attr,
- unsigned int ns_device_access);
+ unsigned int ns_device_access);
void tzc400_configure_region(unsigned int filters,
- unsigned int region,
- unsigned long long region_base,
- unsigned long long region_top,
- unsigned int sec_attr,
- unsigned int nsaid_permissions);
+ unsigned int region,
+ unsigned long long region_base,
+ unsigned long long region_top,
+ unsigned int sec_attr,
+ unsigned int nsaid_permissions);
void tzc400_set_action(unsigned int 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)
{
tzc400_init(base);
}
-static inline void tzc_configure_region0(
- unsigned int sec_attr,
- unsigned int ns_device_access)
+static inline void tzc_configure_region0(unsigned int sec_attr,
+ unsigned int ns_device_access)
{
tzc400_configure_region0(sec_attr, ns_device_access);
}
-static inline void tzc_configure_region(
- unsigned int filters,
- unsigned int region,
- unsigned long long region_base,
- unsigned long long region_top,
- unsigned int sec_attr,
- unsigned int ns_device_access)
+static inline void tzc_configure_region(unsigned int filters,
+ unsigned int region,
+ unsigned long long region_base,
+ unsigned long long region_top,
+ unsigned int sec_attr,
+ unsigned int ns_device_access)
{
tzc400_configure_region(filters, region, region_base,
- region_top, sec_attr, ns_device_access);
+ region_top, sec_attr, ns_device_access);
}
static inline void tzc_set_action(unsigned int action)
@@ -143,7 +145,6 @@ static inline void tzc_set_action(unsigned int action)
tzc400_set_action(action);
}
-
static inline void tzc_enable_filters(void)
{
tzc400_enable_filters();
diff --git a/include/drivers/io/io_driver.h b/include/drivers/io/io_driver.h
index 2b704f491..d8bb435aa 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_mtd.h b/include/drivers/io/io_mtd.h
new file mode 100644
index 000000000..1395ff601
--- /dev/null
+++ b/include/drivers/io/io_mtd.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef IO_MTD_H
+#define IO_MTD_H
+
+#include <stdint.h>
+#include <stdio.h>
+
+#include <drivers/io/io_storage.h>
+
+/* MTD devices ops */
+typedef struct io_mtd_ops {
+ /*
+ * Initialize MTD framework and retrieve device information.
+ *
+ * @size: [out] MTD device size in bytes.
+ * @erase_size: [out] MTD erase size in bytes.
+ * Return 0 on success, a negative error code otherwise.
+ */
+ int (*init)(unsigned long long *size, unsigned int *erase_size);
+
+ /*
+ * Execute a read memory operation.
+ *
+ * @offset: Offset in bytes to start read operation.
+ * @buffer: [out] Buffer to store read data.
+ * @length: Required length to be read in bytes.
+ * @out_length: [out] Length read in bytes.
+ * Return 0 on success, a negative error code otherwise.
+ */
+ int (*read)(unsigned int offset, uintptr_t buffer, size_t length,
+ size_t *out_length);
+
+ /*
+ * Execute a write memory operation.
+ *
+ * @offset: Offset in bytes to start write operation.
+ * @buffer: Buffer to be written in device.
+ * @length: Required length to be written in bytes.
+ * Return 0 on success, a negative error code otherwise.
+ */
+ int (*write)(unsigned int offset, uintptr_t buffer, size_t length);
+} io_mtd_ops_t;
+
+typedef struct io_mtd_dev_spec {
+ unsigned long long device_size;
+ unsigned int erase_size;
+ io_mtd_ops_t ops;
+} io_mtd_dev_spec_t;
+
+struct io_dev_connector;
+
+int register_io_dev_mtd(const struct io_dev_connector **dev_con);
+
+#endif /* IO_MTD_H */
diff --git a/include/drivers/io/io_storage.h b/include/drivers/io/io_storage.h
index 084c67c47..f04214b69 100644
--- a/include/drivers/io/io_storage.h
+++ b/include/drivers/io/io_storage.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2014-2019, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -22,8 +22,11 @@ typedef enum {
IO_TYPE_DUMMY,
IO_TYPE_FIRMWARE_IMAGE_PACKAGE,
IO_TYPE_BLOCK,
+ IO_TYPE_MTD,
IO_TYPE_MMC,
IO_TYPE_STM32IMAGE,
+ IO_TYPE_UART,
+ IO_TYPE_USB,
IO_TYPE_MAX
} io_type_t;
@@ -86,7 +89,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/mmc.h b/include/drivers/mmc.h
index 7611f019a..2b4f5ab8b 100644
--- a/include/drivers/mmc.h
+++ b/include/drivers/mmc.h
@@ -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
*/
@@ -104,6 +104,7 @@
#define MMC_STATE_SLP 10
#define MMC_FLAG_CMD23 (U(1) << 0)
+#define MMC_FLAG_SD_CMD6 (U(1) << 1)
#define CMD8_CHECK_PATTERN U(0xAA)
#define VHS_2_7_3_6_V BIT(8)
@@ -111,6 +112,9 @@
#define SD_SCR_BUS_WIDTH_1 BIT(8)
#define SD_SCR_BUS_WIDTH_4 BIT(10)
+#define SD_SWITCH_FUNC_CHECK 0U
+#define SD_SWITCH_FUNC_SWITCH 1U
+
struct mmc_cmd {
unsigned int cmd_idx;
unsigned int cmd_arg;
@@ -210,6 +214,27 @@ struct mmc_csd_sd_v2 {
unsigned int csd_structure: 2;
};
+struct sd_switch_status {
+ unsigned short max_current;
+ unsigned short support_g6;
+ unsigned short support_g5;
+ unsigned short support_g4;
+ unsigned short support_g3;
+ unsigned short support_g2;
+ unsigned short support_g1;
+ unsigned char sel_g6_g5;
+ unsigned char sel_g4_g3;
+ unsigned char sel_g2_g1;
+ unsigned char data_struct_ver;
+ unsigned short busy_g6;
+ unsigned short busy_g5;
+ unsigned short busy_g4;
+ unsigned short busy_g3;
+ unsigned short busy_g2;
+ unsigned short busy_g1;
+ unsigned short reserved[17];
+};
+
enum mmc_device_type {
MMC_IS_EMMC,
MMC_IS_SD,
diff --git a/include/drivers/nand.h b/include/drivers/nand.h
new file mode 100644
index 000000000..1dbb008f9
--- /dev/null
+++ b/include/drivers/nand.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2019, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef DRIVERS_NAND_H
+#define DRIVERS_NAND_H
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <lib/utils_def.h>
+
+#define PSEC_TO_MSEC(x) div_round_up((x), 1000000000ULL)
+
+struct ecc {
+ unsigned int mode; /* ECC mode NAND_ECC_MODE_{NONE|HW|ONDIE} */
+ unsigned int size; /* Data byte per ECC step */
+ unsigned int bytes; /* ECC bytes per step */
+ unsigned int max_bit_corr; /* Max correctible bits per ECC steps */
+};
+
+struct nand_device {
+ unsigned int block_size;
+ unsigned int page_size;
+ unsigned long long size;
+ unsigned int nb_planes;
+ unsigned int buswidth;
+ struct ecc ecc;
+ int (*mtd_block_is_bad)(unsigned int block);
+ int (*mtd_read_page)(struct nand_device *nand, unsigned int page,
+ uintptr_t buffer);
+};
+
+/*
+ * Read bytes from NAND device
+ *
+ * @offset: Byte offset to read from in device
+ * @buffer: [out] Bytes read from device
+ * @length: Number of bytes to read
+ * @length_read: [out] Number of bytes read from device
+ * Return: 0 on success, a negative errno on failure
+ */
+int nand_read(unsigned int offset, uintptr_t buffer, size_t length,
+ size_t *length_read);
+
+/*
+ * Get NAND device instance
+ *
+ * Return: NAND device instance reference
+ */
+struct nand_device *get_nand_device(void);
+
+#endif /* DRIVERS_NAND_H */
diff --git a/include/drivers/raw_nand.h b/include/drivers/raw_nand.h
new file mode 100644
index 000000000..9018f0242
--- /dev/null
+++ b/include/drivers/raw_nand.h
@@ -0,0 +1,188 @@
+/*
+ * Copyright (c) 2019-2020, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef DRIVERS_RAW_NAND_H
+#define DRIVERS_RAW_NAND_H
+
+#include <cdefs.h>
+#include <stdint.h>
+
+#include <drivers/nand.h>
+
+/* NAND ONFI default value mode 0 in picosecond */
+#define NAND_TADL_MIN 400000UL
+#define NAND_TALH_MIN 20000UL
+#define NAND_TALS_MIN 50000UL
+#define NAND_TAR_MIN 25000UL
+#define NAND_TCCS_MIN 500000UL
+#define NAND_TCEA_MIN 100000UL
+#define NAND_TCEH_MIN 20000UL
+#define NAND_TCH_MIN 20000UL
+#define NAND_TCHZ_MAX 100000UL
+#define NAND_TCLH_MIN 20000UL
+#define NAND_TCLR_MIN 20000UL
+#define NAND_TCLS_MIN 50000UL
+#define NAND_TCOH_MIN 0UL
+#define NAND_TCS_MIN 70000UL
+#define NAND_TDH_MIN 20000UL
+#define NAND_TDS_MIN 40000UL
+#define NAND_TFEAT_MAX 1000000UL
+#define NAND_TIR_MIN 10000UL
+#define NAND_TITC_MIN 1000000UL
+#define NAND_TR_MAX 200000000UL
+#define NAND_TRC_MIN 100000UL
+#define NAND_TREA_MAX 40000UL
+#define NAND_TREH_MIN 30000UL
+#define NAND_TRHOH_MIN 0UL
+#define NAND_TRHW_MIN 200000UL
+#define NAND_TRHZ_MAX 200000UL
+#define NAND_TRLOH_MIN 0UL
+#define NAND_TRP_MIN 50000UL
+#define NAND_TRR_MIN 40000UL
+#define NAND_TRST_MAX 250000000000ULL
+#define NAND_TWB_MAX 200000UL
+#define NAND_TWC_MIN 100000UL
+#define NAND_TWH_MIN 30000UL
+#define NAND_TWHR_MIN 120000UL
+#define NAND_TWP_MIN 50000UL
+#define NAND_TWW_MIN 100000UL
+
+/* NAND request types */
+#define NAND_REQ_CMD 0x0000U
+#define NAND_REQ_ADDR 0x1000U
+#define NAND_REQ_DATAIN 0x2000U
+#define NAND_REQ_DATAOUT 0x3000U
+#define NAND_REQ_WAIT 0x4000U
+#define NAND_REQ_MASK GENMASK(14, 12)
+#define NAND_REQ_BUS_WIDTH_8 BIT(15)
+
+#define PARAM_PAGE_SIZE 256
+
+/* NAND ONFI commands */
+#define NAND_CMD_READ_1ST 0x00U
+#define NAND_CMD_CHANGE_1ST 0x05U
+#define NAND_CMD_READID_SIG_ADDR 0x20U
+#define NAND_CMD_READ_2ND 0x30U
+#define NAND_CMD_STATUS 0x70U
+#define NAND_CMD_READID 0x90U
+#define NAND_CMD_CHANGE_2ND 0xE0U
+#define NAND_CMD_READ_PARAM_PAGE 0xECU
+#define NAND_CMD_RESET 0xFFU
+
+#define ONFI_REV_21 BIT(3)
+#define ONFI_FEAT_BUS_WIDTH_16 BIT(0)
+#define ONFI_FEAT_EXTENDED_PARAM BIT(7)
+
+/* NAND ECC type */
+#define NAND_ECC_NONE U(0)
+#define NAND_ECC_HW U(1)
+#define NAND_ECC_ONDIE U(2)
+
+/* NAND bus width */
+#define NAND_BUS_WIDTH_8 U(0)
+#define NAND_BUS_WIDTH_16 U(1)
+
+struct nand_req {
+ struct nand_device *nand;
+ uint16_t type;
+ uint8_t *addr;
+ unsigned int length;
+ unsigned int delay_ms;
+ unsigned int inst_delay;
+};
+
+struct nand_param_page {
+ /* Rev information and feature block */
+ uint32_t page_sig;
+ uint16_t rev;
+ uint16_t features;
+ uint16_t opt_cmd;
+ uint8_t jtg;
+ uint8_t train_cmd;
+ uint16_t ext_param_length;
+ uint8_t nb_param_pages;
+ uint8_t reserved1[17];
+ /* Manufacturer information */
+ uint8_t manufacturer[12];
+ uint8_t model[20];
+ uint8_t manufacturer_id;
+ uint16_t data_code;
+ uint8_t reserved2[13];
+ /* Memory organization */
+ uint32_t bytes_per_page;
+ uint16_t spare_per_page;
+ uint32_t bytes_per_partial;
+ uint16_t spare_per_partial;
+ uint32_t num_pages_per_blk;
+ uint32_t num_blk_in_lun;
+ uint8_t num_lun;
+ uint8_t num_addr_cycles;
+ uint8_t bit_per_cell;
+ uint16_t max_bb_per_lun;
+ uint16_t blk_endur;
+ uint8_t valid_blk_begin;
+ uint16_t blk_enbur_valid;
+ uint8_t nb_prog_page;
+ uint8_t partial_prog_attr;
+ uint8_t nb_ecc_bits;
+ uint8_t plane_addr;
+ uint8_t mplanes_ops;
+ uint8_t ez_nand;
+ uint8_t reserved3[12];
+ /* Electrical parameters */
+ uint8_t io_pin_cap_max;
+ uint16_t sdr_timing_mode;
+ uint16_t sdr_prog_cache_timing;
+ uint16_t tprog;
+ uint16_t tbers;
+ uint16_t tr;
+ uint16_t tccs;
+ uint8_t nvddr_timing_mode;
+ uint8_t nvddr2_timing_mode;
+ uint8_t nvddr_features;
+ uint16_t clk_input_cap_typ;
+ uint16_t io_pin_cap_typ;
+ uint16_t input_pin_cap_typ;
+ uint8_t input_pin_cap_max;
+ uint8_t drv_strength_support;
+ uint16_t tr_max;
+ uint16_t tadl;
+ uint16_t tr_typ;
+ uint8_t reserved4[6];
+ /* Vendor block */
+ uint16_t vendor_revision;
+ uint8_t vendor[88];
+ uint16_t crc16;
+} __packed;
+
+struct nand_ctrl_ops {
+ int (*exec)(struct nand_req *req);
+ void (*setup)(struct nand_device *nand);
+};
+
+struct rawnand_device {
+ struct nand_device *nand_dev;
+ const struct nand_ctrl_ops *ops;
+};
+
+int nand_raw_init(unsigned long long *size, unsigned int *erase_size);
+int nand_wait_ready(unsigned long delay);
+int nand_read_page_cmd(unsigned int page, unsigned int offset,
+ uintptr_t buffer, unsigned int len);
+int nand_change_read_column_cmd(unsigned int offset, uintptr_t buffer,
+ unsigned int len);
+void nand_raw_ctrl_init(const struct nand_ctrl_ops *ops);
+
+/*
+ * Platform can implement this to override default raw NAND instance
+ * configuration.
+ *
+ * @device: target raw NAND instance.
+ * Return 0 on success, negative value otherwise.
+ */
+int plat_get_raw_nand_data(struct rawnand_device *device);
+
+#endif /* DRIVERS_RAW_NAND_H */
diff --git a/include/drivers/spi_mem.h b/include/drivers/spi_mem.h
new file mode 100644
index 000000000..d1953acf4
--- /dev/null
+++ b/include/drivers/spi_mem.h
@@ -0,0 +1,130 @@
+/*
+ * Copyright (c) 2019, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef DRIVERS_SPI_MEM_H
+#define DRIVERS_SPI_MEM_H
+
+#include <errno.h>
+#include <stdbool.h>
+#include <stdint.h>
+
+#define SPI_MEM_BUSWIDTH_1_LINE 1U
+#define SPI_MEM_BUSWIDTH_2_LINE 2U
+#define SPI_MEM_BUSWIDTH_4_LINE 4U
+
+/*
+ * enum spi_mem_data_dir - Describes the direction of a SPI memory data
+ * transfer from the controller perspective.
+ * @SPI_MEM_DATA_IN: data coming from the SPI memory.
+ * @SPI_MEM_DATA_OUT: data sent to the SPI memory.
+ */
+enum spi_mem_data_dir {
+ SPI_MEM_DATA_IN,
+ SPI_MEM_DATA_OUT,
+};
+
+/*
+ * struct spi_mem_op - Describes a SPI memory operation.
+ *
+ * @cmd.buswidth: Number of IO lines used to transmit the command.
+ * @cmd.opcode: Operation opcode.
+ * @addr.nbytes: Number of address bytes to send. Can be zero if the operation
+ * does not need to send an address.
+ * @addr.buswidth: Number of IO lines used to transmit the address.
+ * @addr.val: Address value. This value is always sent MSB first on the bus.
+ * Note that only @addr.nbytes are taken into account in this
+ * address value, so users should make sure the value fits in the
+ * assigned number of bytes.
+ * @dummy.nbytes: Number of dummy bytes to send after an opcode or address. Can
+ * be zero if the operation does not require dummy bytes.
+ * @dummy.buswidth: Number of IO lines used to transmit the dummy bytes.
+ * @data.buswidth: Number of IO lines used to send/receive the data.
+ * @data.dir: Direction of the transfer.
+ * @data.nbytes: Number of data bytes to transfer.
+ * @data.buf: Input or output data buffer depending on data::dir.
+ */
+struct spi_mem_op {
+ struct {
+ uint8_t buswidth;
+ uint8_t opcode;
+ } cmd;
+
+ struct {
+ uint8_t nbytes;
+ uint8_t buswidth;
+ uint64_t val;
+ } addr;
+
+ struct {
+ uint8_t nbytes;
+ uint8_t buswidth;
+ } dummy;
+
+ struct {
+ uint8_t buswidth;
+ enum spi_mem_data_dir dir;
+ unsigned int nbytes;
+ void *buf;
+ } data;
+};
+
+/* SPI mode flags */
+#define SPI_CPHA BIT(0) /* clock phase */
+#define SPI_CPOL BIT(1) /* clock polarity */
+#define SPI_CS_HIGH BIT(2) /* CS active high */
+#define SPI_LSB_FIRST BIT(3) /* per-word bits-on-wire */
+#define SPI_3WIRE BIT(4) /* SI/SO signals shared */
+#define SPI_PREAMBLE BIT(5) /* Skip preamble bytes */
+#define SPI_TX_DUAL BIT(6) /* transmit with 2 wires */
+#define SPI_TX_QUAD BIT(7) /* transmit with 4 wires */
+#define SPI_RX_DUAL BIT(8) /* receive with 2 wires */
+#define SPI_RX_QUAD BIT(9) /* receive with 4 wires */
+
+struct spi_bus_ops {
+ /*
+ * Claim the bus and prepare it for communication.
+ *
+ * @cs: The chip select.
+ * Returns: 0 if the bus was claimed successfully, or a negative value
+ * if it wasn't.
+ */
+ int (*claim_bus)(unsigned int cs);
+
+ /*
+ * Release the SPI bus.
+ */
+ void (*release_bus)(void);
+
+ /*
+ * Set transfer speed.
+ *
+ * @hz: The transfer speed in Hertz.
+ * Returns: 0 on success, a negative error code otherwise.
+ */
+ int (*set_speed)(unsigned int hz);
+
+ /*
+ * Set the SPI mode/flags.
+ *
+ * @mode: Requested SPI mode (SPI_... flags).
+ * Returns: 0 on success, a negative error code otherwise.
+ */
+ int (*set_mode)(unsigned int mode);
+
+ /*
+ * Execute a SPI memory operation.
+ *
+ * @op: The memory operation to execute.
+ * Returns: 0 on success, a negative error code otherwise.
+ */
+ int (*exec_op)(const struct spi_mem_op *op);
+};
+
+int spi_mem_exec_op(const struct spi_mem_op *op);
+int spi_mem_init_slave(void *fdt, int bus_node,
+ const struct spi_bus_ops *ops);
+
+#endif /* DRIVERS_SPI_MEM_H */
diff --git a/include/drivers/spi_nand.h b/include/drivers/spi_nand.h
new file mode 100644
index 000000000..40e206375
--- /dev/null
+++ b/include/drivers/spi_nand.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2019, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef DRIVERS_SPI_NAND_H
+#define DRIVERS_SPI_NAND_H
+
+#include <drivers/nand.h>
+#include <drivers/spi_mem.h>
+
+#define SPI_NAND_OP_GET_FEATURE 0x0FU
+#define SPI_NAND_OP_SET_FEATURE 0x1FU
+#define SPI_NAND_OP_READ_ID 0x9FU
+#define SPI_NAND_OP_LOAD_PAGE 0x13U
+#define SPI_NAND_OP_RESET 0xFFU
+#define SPI_NAND_OP_READ_FROM_CACHE 0x03U
+#define SPI_NAND_OP_READ_FROM_CACHE_2X 0x3BU
+#define SPI_NAND_OP_READ_FROM_CACHE_4X 0x6BU
+
+/* Configuration register */
+#define SPI_NAND_REG_CFG 0xB0U
+#define SPI_NAND_CFG_ECC_EN BIT(4)
+#define SPI_NAND_CFG_QE BIT(0)
+
+/* Status register */
+#define SPI_NAND_REG_STATUS 0xC0U
+#define SPI_NAND_STATUS_BUSY BIT(0)
+#define SPI_NAND_STATUS_ECC_UNCOR BIT(5)
+
+struct spinand_device {
+ struct nand_device *nand_dev;
+ struct spi_mem_op spi_read_cache_op;
+ uint8_t cfg_cache; /* Cached value of SPI NAND device register CFG */
+};
+
+int spi_nand_init(unsigned long long *size, unsigned int *erase_size);
+
+/*
+ * Platform can implement this to override default SPI-NAND instance
+ * configuration.
+ *
+ * @device: target SPI-NAND instance.
+ * Return 0 on success, negative value otherwise.
+ */
+int plat_get_spi_nand_data(struct spinand_device *device);
+
+#endif /* DRIVERS_SPI_NAND_H */
diff --git a/include/drivers/spi_nor.h b/include/drivers/spi_nor.h
new file mode 100644
index 000000000..72cfe5b34
--- /dev/null
+++ b/include/drivers/spi_nor.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2019, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef DRIVERS_SPI_NOR_H
+#define DRIVERS_SPI_NOR_H
+
+#include <drivers/spi_mem.h>
+
+/* OPCODE */
+#define SPI_NOR_OP_WREN 0x06U /* Write enable */
+#define SPI_NOR_OP_WRSR 0x01U /* Write status register 1 byte */
+#define SPI_NOR_OP_READ_ID 0x9FU /* Read JEDEC ID */
+#define SPI_NOR_OP_READ_CR 0x35U /* Read configuration register */
+#define SPI_NOR_OP_READ_SR 0x05U /* Read status register */
+#define SPI_NOR_OP_READ_FSR 0x70U /* Read flag status register */
+#define SPINOR_OP_RDEAR 0xC8U /* Read Extended Address Register */
+#define SPINOR_OP_WREAR 0xC5U /* Write Extended Address Register */
+
+/* Used for Spansion flashes only. */
+#define SPINOR_OP_BRWR 0x17U /* Bank register write */
+#define SPINOR_OP_BRRD 0x16U /* Bank register read */
+
+#define SPI_NOR_OP_READ 0x03U /* Read data bytes (low frequency) */
+#define SPI_NOR_OP_READ_FAST 0x0BU /* Read data bytes (high frequency) */
+#define SPI_NOR_OP_READ_1_1_2 0x3BU /* Read data bytes (Dual Output SPI) */
+#define SPI_NOR_OP_READ_1_2_2 0xBBU /* Read data bytes (Dual I/O SPI) */
+#define SPI_NOR_OP_READ_1_1_4 0x6BU /* Read data bytes (Quad Output SPI) */
+#define SPI_NOR_OP_READ_1_4_4 0xEBU /* Read data bytes (Quad I/O SPI) */
+
+/* Flags for NOR specific configuration */
+#define SPI_NOR_USE_FSR BIT(0)
+#define SPI_NOR_USE_BANK BIT(1)
+
+struct nor_device {
+ struct spi_mem_op read_op;
+ uint32_t size;
+ uint32_t flags;
+ uint8_t selected_bank;
+ uint8_t bank_write_cmd;
+ uint8_t bank_read_cmd;
+};
+
+int spi_nor_read(unsigned int offset, uintptr_t buffer, size_t length,
+ size_t *length_read);
+int spi_nor_init(unsigned long long *device_size, unsigned int *erase_size);
+
+/*
+ * Platform can implement this to override default NOR instance configuration.
+ *
+ * @device: target NOR instance.
+ * Return 0 on success, negative value otherwise.
+ */
+int plat_get_nor_data(struct nor_device *device);
+
+#endif /* DRIVERS_SPI_NOR_H */
diff --git a/include/drivers/st/bsec.h b/include/drivers/st/bsec.h
index d833e7ab2..6601e56a9 100644
--- a/include/drivers/st/bsec.h
+++ b/include/drivers/st/bsec.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019, STMicroelectronics - All Rights Reserved
+ * Copyright (c) 2015-2019, STMicroelectronics - All Rights Reserved
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -19,13 +19,6 @@
#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
*/
@@ -35,110 +28,34 @@
#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
+#define BSEC_TIMEOUT 0xFFFFFFF9U
+#define BSEC_RETRY 0xFFFFFFF8U
+#define BSEC_NOT_SUPPORTED 0xFFFFFFF7U
+#define BSEC_WRITE_LOCKED 0xFFFFFFF6U
+#define BSEC_ERROR_INVALID_FVR 0xFFFFFFF5U
/*
- * BSEC_OTP_LOCK register
+ * OTP MODE
*/
-#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
+ * OTP Lock services definition.
+ * Value must corresponding to the bit number in the register.
+ * Special case: (bit number << 1) for BSEC3.
*/
#define BSEC_LOCK_UPPER_OTP 0x00
+#define BSEC_LOCK_GWLOCK 0x01
#define BSEC_LOCK_DEBUG 0x02
#define BSEC_LOCK_PROGRAM 0x03
+#define BSEC_LOCK_KVLOCK 0x04
-/* Values for struct bsec_config::freq */
+/*
+ * Values for struct bsec_config::freq
+ */
#define FREQ_10_20_MHZ 0x0
#define FREQ_20_30_MHZ 0x1
#define FREQ_30_45_MHZ 0x2
@@ -146,22 +63,28 @@
/*
* Device info structure, providing device-specific functions and a means of
- * adding driver-specific state
+ * adding driver-specific state.
*/
struct bsec_config {
+ uint8_t den_lock; /*
+ * Debug enable sticky lock
+ * 1 debug enable is locked until next reset
+ */
+
+ /* BSEC2 only */
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
+ 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
+ uint8_t prog_lock; /*
+ * Programming Sticky lock
* 1 programming is locked until next reset
*/
- uint8_t den_lock; /* Debug enable sticky lock
- * 1 debug enable is locked until next reset
- */
- uint8_t upper_otp_lock; /* Shadowing of upper OTP sticky lock
+ uint8_t upper_otp_lock; /*
+ * Shadowing of upper OTP sticky lock
* 1 shadowing of upper OTP is locked
* until next reset
*/
@@ -173,6 +96,9 @@ 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_find_otp_name_in_dt(const char *name, uint32_t *otp,
+ uint32_t *otp_len);
+
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);
@@ -190,14 +116,14 @@ 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);
+uint32_t bsec_set_sr_lock(uint32_t otp);
+uint32_t bsec_read_sr_lock(uint32_t otp, bool *value);
+uint32_t bsec_set_sw_lock(uint32_t otp);
+uint32_t bsec_read_sw_lock(uint32_t otp, bool *value);
+uint32_t bsec_set_sp_lock(uint32_t otp);
+uint32_t bsec_read_sp_lock(uint32_t otp, bool *value);
+uint32_t bsec_read_permanent_lock(uint32_t otp, bool *value);
+uint32_t bsec_otp_lock(uint32_t service);
uint32_t bsec_shadow_read_otp(uint32_t *otp_value, uint32_t word);
uint32_t bsec_check_nsec_access_rights(uint32_t otp);
diff --git a/include/drivers/st/bsec2_reg.h b/include/drivers/st/bsec2_reg.h
new file mode 100644
index 000000000..9da952603
--- /dev/null
+++ b/include/drivers/st/bsec2_reg.h
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2019, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef BSEC2_REG_H
+#define BSEC2_REG_H
+
+#include <lib/utils_def.h>
+
+/* IP configuration */
+#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)
+
+/* BSEC REGISTER OFFSET (base relative) */
+#define BSEC_OTP_CONF_OFF U(0x000)
+#define BSEC_OTP_CTRL_OFF U(0x004)
+#define BSEC_OTP_WRDATA_OFF U(0x008)
+#define BSEC_OTP_STATUS_OFF U(0x00C)
+#define BSEC_OTP_LOCK_OFF U(0x010)
+#define BSEC_DEN_OFF U(0x014)
+#define BSEC_DISTURBED_OFF U(0x01C)
+#define BSEC_DISTURBED1_OFF U(0x020)
+#define BSEC_DISTURBED2_OFF U(0x024)
+#define BSEC_ERROR_OFF U(0x034)
+#define BSEC_ERROR1_OFF U(0x038)
+#define BSEC_ERROR2_OFF U(0x03C)
+#define BSEC_WRLOCK_OFF U(0x04C) /* Safmem permanent lock */
+#define BSEC_WRLOCK1_OFF U(0x050)
+#define BSEC_WRLOCK2_OFF U(0x054)
+#define BSEC_SPLOCK_OFF U(0x064) /* Program safmem sticky lock */
+#define BSEC_SPLOCK1_OFF U(0x068)
+#define BSEC_SPLOCK2_OFF U(0x06C)
+#define BSEC_SWLOCK_OFF U(0x07C) /* Write in OTP sticky lock */
+#define BSEC_SWLOCK1_OFF U(0x080)
+#define BSEC_SWLOCK2_OFF U(0x084)
+#define BSEC_SRLOCK_OFF U(0x094) /* Shadowing sticky lock */
+#define BSEC_SRLOCK1_OFF U(0x098)
+#define BSEC_SRLOCK2_OFF U(0x09C)
+#define BSEC_JTAG_IN_OFF U(0x0AC)
+#define BSEC_JTAG_OUT_OFF U(0x0B0)
+#define BSEC_SCRATCH_OFF U(0x0B4)
+#define BSEC_OTP_DATA_OFF U(0x200)
+#define BSEC_IPHW_CFG_OFF U(0xFF0)
+#define BSEC_IPVR_OFF U(0xFF4)
+#define BSEC_IP_ID_OFF U(0xFF8)
+#define BSEC_IP_MAGIC_ID_OFF U(0xFFC)
+
+/* 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 0
+#define BSEC_WRITE BIT(8)
+#define BSEC_LOCK BIT(9)
+
+/* 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)
+
+/* 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)
+
+/* BSEC_IPVR Register */
+#define BSEC_IPVR_MSK GENMASK(7, 0)
+
+#endif /* BSEC2_REG_H */
diff --git a/include/drivers/st/etzpc.h b/include/drivers/st/etzpc.h
new file mode 100644
index 000000000..c0ed06f6e
--- /dev/null
+++ b/include/drivers/st/etzpc.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2017-2019, STMicroelectronics - All Rights Reserved
+ *
+ * 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/io_programmer.h b/include/drivers/st/io_programmer.h
new file mode 100644
index 000000000..c6c2de10f
--- /dev/null
+++ b/include/drivers/st/io_programmer.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2015-2019, STMicroelectronics - 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 000000000..79effad87
--- /dev/null
+++ b/include/drivers/st/io_programmer_st_usb.h
@@ -0,0 +1,12 @@
+/*
+ * Copyright (c) 2015-2019, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef __IO_USB_H__
+#define __IO_USB_H__
+
+int register_io_dev_usb(const io_dev_connector_t **dev_con);
+
+#endif /* __IO_USB_H__ */
diff --git a/include/drivers/st/io_stm32image.h b/include/drivers/st/io_stm32image.h
index 68060558b..f9fa3630c 100644
--- a/include/drivers/st/io_stm32image.h
+++ b/include/drivers/st/io_stm32image.h
@@ -23,7 +23,7 @@ struct stm32image_part_info {
struct stm32image_device_info {
struct stm32image_part_info part_info[STM32_PART_NUM];
- uint32_t device_size;
+ unsigned long long device_size;
uint32_t lba_size;
};
diff --git a/include/drivers/st/io_uart.h b/include/drivers/st/io_uart.h
new file mode 100644
index 000000000..86f9483a9
--- /dev/null
+++ b/include/drivers/st/io_uart.h
@@ -0,0 +1,12 @@
+/*
+ * Copyright (c) 2015-2019, STMicroelectronics - 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/scmi-msg.h b/include/drivers/st/scmi-msg.h
new file mode 100644
index 000000000..6fa597185
--- /dev/null
+++ b/include/drivers/st/scmi-msg.h
@@ -0,0 +1,207 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * Copyright (c) 2015-2019, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2019, Linaro Limited
+ */
+
+#ifndef SCMI_MSG_H
+#define SCMI_MSG_H
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+
+/* Minimum size expected for SMT based shared memory message buffers */
+#define SMT_BUF_SLOT_SIZE 128U
+
+/* A channel abstract a communication path between agent and server */
+struct scmi_msg_channel;
+
+/*
+ * struct scmi_msg_channel - Shared memory buffer for a agent-to-server channel
+ *
+ * @shm_addr: Address of the shared memory for the SCMI channel
+ * @shm_size: Byte size of the shared memory for the SCMI channel
+ * @busy: True when channel is busy, flase when channel is free
+ * @agent_name: Agent name or NULL, SCMI protocol exposes 16 bytes max.
+ */
+struct scmi_msg_channel {
+ uintptr_t shm_addr;
+ size_t shm_size;
+ bool busy;
+ const char *agent_name;
+};
+
+/*
+ * Initialize SMT memory buffer, called by platform at init for each
+ * agent channel using the SMT header format.
+ *
+ * @chan: Pointer to the channel shared memory to be initialized
+ */
+void scmi_smt_init_agent_channel(struct scmi_msg_channel *chan);
+
+/*
+ * Process SMT formatted message in a fastcall SMC execution context.
+ * Called by platform on SMC entry. When returning, output message is
+ * available in shared memory for agent to read the response.
+ *
+ * @agent_id: SCMI agent ID the SMT belongs to
+ */
+void scmi_smt_fastcall_smc_entry(unsigned int agent_id);
+
+/*
+ * Process SMT formatted message in a secure interrupt execution context.
+ * Called by platform interrupt handler. When returning, output message is
+ * available in shared memory for agent to read the response.
+ *
+ * @agent_id: SCMI agent ID the SMT belongs to
+ */
+void scmi_smt_interrupt_entry(unsigned int agent_id);
+
+/* Platform callback functions */
+
+/*
+ * Return the SCMI channel related to an agent
+ * @agent_id: SCMI agent ID
+ * Return a pointer to channel on success, NULL otherwise
+ */
+struct scmi_msg_channel *plat_scmi_get_channel(unsigned int agent_id);
+
+/*
+ * Return how many SCMI protocols supported by the platform
+ * According to the SCMI specification, this function does not target
+ * a specific agent ID and shall return all platform known capabilities.
+ */
+size_t plat_scmi_protocol_count(void);
+
+/*
+ * Get the count and list of SCMI protocols (but base) supported for an agent
+ *
+ * @agent_id: SCMI agent ID
+ * Return a pointer to a null terminated array supported protocol IDs.
+ */
+const uint8_t *plat_scmi_protocol_list(unsigned int agent_id);
+
+/* Get the name of the SCMI vendor for the platform */
+const char *plat_scmi_vendor_name(void);
+
+/* Get the name of the SCMI sub-vendor for the platform */
+const char *plat_scmi_sub_vendor_name(void);
+
+/* Handlers for SCMI Clock protocol services */
+
+/*
+ * Return number of clock controllers for an agent
+ * @agent_id: SCMI agent ID
+ * Return number of clock controllers
+ */
+size_t plat_scmi_clock_count(unsigned int agent_id);
+
+/*
+ * Get clock controller string ID (aka name)
+ * @agent_id: SCMI agent ID
+ * @scmi_id: SCMI clock ID
+ * Return pointer to name or NULL
+ */
+const char *plat_scmi_clock_get_name(unsigned int agent_id,
+ unsigned int scmi_id);
+
+/*
+ * Get clock possible rate as an array of frequencies in Hertz.
+ *
+ * @agent_id: SCMI agent ID
+ * @scmi_id: SCMI clock ID
+ * @rates: If NULL, function returns, else output rates array
+ * @nb_elts: Array size of @rates.
+ * Return an SCMI compliant error code
+ */
+int32_t plat_scmi_clock_rates_array(unsigned int agent_id, unsigned int scmi_id,
+ unsigned long *rates, size_t *nb_elts);
+
+/*
+ * Get clock possible rate as range with regular steps in Hertz
+ *
+ * @agent_id: SCMI agent ID
+ * @scmi_id: SCMI clock ID
+ * @min_max_step: 3 cell array for min, max and step rate data
+ * Return an SCMI compliant error code
+ */
+int32_t plat_scmi_clock_rates_by_step(unsigned int agent_id,
+ unsigned int scmi_id,
+ unsigned long *min_max_step);
+
+/*
+ * Get clock rate in Hertz
+ * @agent_id: SCMI agent ID
+ * @scmi_id: SCMI clock ID
+ * Return clock rate or 0 if not supported
+ */
+unsigned long plat_scmi_clock_get_rate(unsigned int agent_id,
+ unsigned int scmi_id);
+
+/*
+ * Set clock rate in Hertz
+ * @agent_id: SCMI agent ID
+ * @scmi_id: SCMI clock ID
+ * @rate: Target clock frequency in Hertz
+ * Return a compliant SCMI error code
+ */
+int32_t plat_scmi_clock_set_rate(unsigned int agent_id, unsigned int scmi_id,
+ unsigned long rate);
+
+/*
+ * Get clock state (enabled or disabled)
+ * @agent_id: SCMI agent ID
+ * @scmi_id: SCMI clock ID
+ * Return 1 if clock is enabled, 0 if disables, or a negative SCMI error code
+ */
+int32_t plat_scmi_clock_get_state(unsigned int agent_id, unsigned int scmi_id);
+
+/*
+ * Get clock state (enabled or disabled)
+ * @agent_id: SCMI agent ID
+ * @scmi_id: SCMI clock ID
+ * @enable_not_disable: Enable clock if true, disable clock otherwise
+ * Return a compliant SCMI error code
+ */
+int32_t plat_scmi_clock_set_state(unsigned int agent_id, unsigned int scmi_id,
+ bool enable_not_disable);
+
+/* Handlers for SCMI Reset Domain protocol services */
+
+/*
+ * Return number of reset domains for the agent
+ * @agent_id: SCMI agent ID
+ * Return number of reset domains
+ */
+size_t plat_scmi_rd_count(unsigned int agent_id);
+
+/*
+ * Get reset domain string ID (aka name)
+ * @agent_id: SCMI agent ID
+ * @scmi_id: SCMI reset domain ID
+ * Return pointer to name or NULL
+ */
+const char *plat_scmi_rd_get_name(unsigned int agent_id, unsigned int scmi_id);
+
+/*
+ * Perform a reset cycle on a target reset domain
+ * @agent_id: SCMI agent ID
+ * @scmi_id: SCMI reset domain ID
+ * @state: Target reset state (see SCMI specification, 0 means context loss)
+ * Return a compliant SCMI error code
+ */
+int32_t plat_scmi_rd_autonomous(unsigned int agent_id, unsigned int scmi_id,
+ unsigned int state);
+
+/*
+ * Assert or deassert target reset domain
+ * @agent_id: SCMI agent ID
+ * @scmi_id: SCMI reset domain ID
+ * @assert_not_deassert: Assert domain if true, otherwise deassert domain
+ * Return a compliant SCMI error code
+ */
+int32_t plat_scmi_rd_set_state(unsigned int agent_id, unsigned int scmi_id,
+ bool assert_not_deassert);
+
+#endif /* SCMI_MSG_H */
diff --git a/include/drivers/st/scmi.h b/include/drivers/st/scmi.h
new file mode 100644
index 000000000..ac9c798f0
--- /dev/null
+++ b/include/drivers/st/scmi.h
@@ -0,0 +1,29 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * Copyright (c) 2015-2019, Arm Limited and Contributors. All rights reserved.
+ */
+#ifndef SCMI_MSG_SCMI_H
+#define SCMI_MSG_SCMI_H
+
+#define SCMI_PROTOCOL_ID_BASE 0x10
+#define SCMI_PROTOCOL_ID_POWER_DOMAIN 0x11
+#define SCMI_PROTOCOL_ID_SYS_POWER 0x12
+#define SCMI_PROTOCOL_ID_PERF 0x13
+#define SCMI_PROTOCOL_ID_CLOCK 0x14
+#define SCMI_PROTOCOL_ID_SENSOR 0x15
+#define SCMI_PROTOCOL_ID_RESET_DOMAIN 0x16
+
+/* SCMI error codes reported to agent through server-to-agent messages */
+#define SCMI_SUCCESS 0
+#define SCMI_NOT_SUPPORTED (-1)
+#define SCMI_INVALID_PARAMETERS (-2)
+#define SCMI_DENIED (-3)
+#define SCMI_NOT_FOUND (-4)
+#define SCMI_OUT_OF_RANGE (-5)
+#define SCMI_BUSY (-6)
+#define SCMI_COMMS_ERROR (-7)
+#define SCMI_GENERIC_ERROR (-8)
+#define SCMI_HARDWARE_ERROR (-9)
+#define SCMI_PROTOCOL_ERROR (-10)
+
+#endif /* SCMI_MSG_SCMI_H */
diff --git a/include/drivers/st/stm32_fmc2_nand.h b/include/drivers/st/stm32_fmc2_nand.h
new file mode 100644
index 000000000..81d5b9de1
--- /dev/null
+++ b/include/drivers/st/stm32_fmc2_nand.h
@@ -0,0 +1,12 @@
+/*
+ * Copyright (c) 2019, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
+ */
+
+#ifndef STM32_FMC2_NAND_H
+#define STM32_FMC2_NAND_H
+
+int stm32_fmc2_init(void);
+
+#endif /* STM32_FMC2_NAND_H */
diff --git a/include/drivers/st/stm32_i2c.h b/include/drivers/st/stm32_i2c.h
index 170d4cf81..e1a3782b2 100644
--- a/include/drivers/st/stm32_i2c.h
+++ b/include/drivers/st/stm32_i2c.h
@@ -1,7 +1,7 @@
/*
* Copyright (c) 2016-2019, STMicroelectronics - All Rights Reserved
*
- * SPDX-License-Identifier: BSD-3-Clause
+ * SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
*/
#ifndef STM32_I2C_H
@@ -73,6 +73,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)
@@ -111,15 +126,9 @@
#define I2C_ICR_TIMOUTCF BIT(12)
#define I2C_ICR_ALERTCF BIT(13)
-enum i2c_speed_e {
- I2C_SPEED_STANDARD, /* 100 kHz */
- I2C_SPEED_FAST, /* 400 kHz */
- I2C_SPEED_FAST_PLUS, /* 1 MHz */
-};
-
-#define STANDARD_RATE 100000
-#define FAST_RATE 400000
-#define FAST_PLUS_RATE 1000000
+#define STANDARD_RATE 100000
+#define FAST_RATE 400000
+#define FAST_PLUS_RATE 1000000
struct stm32_i2c_init_s {
uint32_t own_address1; /*
@@ -181,12 +190,7 @@ struct stm32_i2c_init_s {
* time in nanoseconds.
*/
- enum i2c_speed_e speed_mode; /*
- * Specifies the I2C clock source
- * frequency mode.
- * This parameter can be a value of @ref
- * i2c_speed_mode_e.
- */
+ uint32_t bus_rate; /* Specifies the I2C clock frequency */
int analog_filter; /*
* Specifies if the I2C analog noise
@@ -238,6 +242,8 @@ struct i2c_handle_s {
enum i2c_state_e i2c_state; /* Communication state */
enum i2c_mode_e i2c_mode; /* Communication mode */
uint32_t i2c_err; /* Error code */
+ uint32_t saved_timing; /* Saved timing value */
+ uint32_t saved_frequency; /* Saved frequency value */
};
#define I2C_ADDRESSINGMODE_7BIT 0x00000001U
@@ -299,8 +305,7 @@ struct i2c_handle_s {
#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_get_setup_from_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,
diff --git a/include/drivers/st/stm32_iwdg.h b/include/drivers/st/stm32_iwdg.h
index bad25244a..c0c009779 100644
--- a/include/drivers/st/stm32_iwdg.h
+++ b/include/drivers/st/stm32_iwdg.h
@@ -15,5 +15,6 @@
int stm32_iwdg_init(void);
void stm32_iwdg_refresh(void);
+void __dead2 stm32_iwdg_it_handler(int id);
#endif /* STM32_IWDG_H */
diff --git a/include/drivers/st/stm32_qspi.h b/include/drivers/st/stm32_qspi.h
new file mode 100644
index 000000000..f47fca445
--- /dev/null
+++ b/include/drivers/st/stm32_qspi.h
@@ -0,0 +1,12 @@
+/*
+ * Copyright (c) 2019, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
+ */
+
+#ifndef STM32_QSPI_H
+#define STM32_QSPI_H
+
+int stm32_qspi_init(void);
+
+#endif /* STM32_QSPI_H */
diff --git a/include/drivers/st/stm32_rng.h b/include/drivers/st/stm32_rng.h
new file mode 100644
index 000000000..a64411865
--- /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 000000000..128dd2d14
--- /dev/null
+++ b/include/drivers/st/stm32_rtc.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2017-2019, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef STM32_RTC_H
+#define STM32_RTC_H
+
+#include <stdbool.h>
+
+#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 /* STM32_RTC_H */
diff --git a/include/drivers/st/stm32_sdmmc2.h b/include/drivers/st/stm32_sdmmc2.h
index 4853208c2..5b4bd0e16 100644
--- a/include/drivers/st/stm32_sdmmc2.h
+++ b/include/drivers/st/stm32_sdmmc2.h
@@ -10,6 +10,7 @@
#include <stdbool.h>
#include <drivers/mmc.h>
+#include <drivers/st/stm32mp_regulator.h>
struct stm32_sdmmc2_params {
uintptr_t reg_base;
@@ -24,6 +25,7 @@ struct stm32_sdmmc2_params {
unsigned int reset_id;
unsigned int max_freq;
bool use_dma;
+ struct stm32mp_regulator vmmc_regu;
};
unsigned long long stm32_sdmmc2_mmc_get_device_size(void);
diff --git a/include/drivers/st/stm32_tamp.h b/include/drivers/st/stm32_tamp.h
new file mode 100644
index 000000000..a4a6a964f
--- /dev/null
+++ b/include/drivers/st/stm32_tamp.h
@@ -0,0 +1,163 @@
+/*
+ * Copyright (c) 2014-2019, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef STM32_TAMP_H
+#define STM32_TAMP_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 (*func)(int id);
+};
+
+struct stm32_tamp_ext {
+ int id;
+ uint8_t mode;
+ uint8_t erase;
+ uint8_t evt_mask;
+ void (*func)(int id);
+};
+
+/*
+ * 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 /* STM32_TAMP_H */
diff --git a/include/drivers/st/stm32_timer.h b/include/drivers/st/stm32_timer.h
new file mode 100644
index 000000000..0e2eb91fe
--- /dev/null
+++ b/include/drivers/st/stm32_timer.h
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2018-2019, STMicroelectronics - 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/stm32mp1_calib.h b/include/drivers/st/stm32mp1_calib.h
new file mode 100644
index 000000000..ef69cb456
--- /dev/null
+++ b/include/drivers/st/stm32mp1_calib.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2018-2019, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef STM32MP1_CALIB_H
+#define STM32MP1_CALIB_H
+
+#include <stdbool.h>
+#include <stdint.h>
+
+bool stm32mp1_calib_get_wakeup(void);
+void stm32mp1_calib_set_wakeup(bool state);
+void stm32mp1_calib_it_handler(uint32_t id);
+int stm32mp1_calib_start_hsi_cal(void);
+int stm32mp1_calib_start_csi_cal(void);
+void stm32mp1_calib_init(void);
+
+#endif /* STM32MP1_CLK_H */
diff --git a/include/drivers/st/stm32mp1_clk.h b/include/drivers/st/stm32mp1_clk.h
index 1ebd39ff7..ded8185f2 100644
--- a/include/drivers/st/stm32mp1_clk.h
+++ b/include/drivers/st/stm32mp1_clk.h
@@ -22,41 +22,49 @@ enum stm32mp_osc_id {
extern const char *stm32mp_osc_node_label[NB_OSC];
-int stm32mp1_clk_probe(void);
-int stm32mp1_clk_init(void);
+#define PLL1_SETTINGS_VALID_ID U(0x504C4C31) /* "PLL1" */
-bool stm32mp1_rcc_is_secure(void);
-bool stm32mp1_rcc_is_mckprot(void);
+int stm32mp1_clk_probe(void);
+int stm32mp1_clk_init(uint32_t pll1_freq_mhz);
-void __stm32mp1_clk_enable(unsigned long id, bool caller_is_secure);
-void __stm32mp1_clk_disable(unsigned long id, bool caller_is_secure);
+int stm32mp1_clk_compute_all_pll1_settings(uint32_t buck1_voltage);
+void stm32mp1_clk_lp_save_opp_pll1_settings(uint8_t *data, size_t size);
+void stm32mp1_clk_lp_load_opp_pll1_settings(uint8_t *data, size_t size);
-static inline void stm32mp1_clk_enable_non_secure(unsigned long id)
-{
- __stm32mp1_clk_enable(id, false);
-}
+int stm32mp1_clk_get_maxfreq_opp(uint32_t *freq_mhz, uint32_t *voltage_mv);
-static inline void stm32mp1_clk_enable_secure(unsigned long id)
-{
- __stm32mp1_clk_enable(id, true);
-}
+bool stm32mp1_rcc_is_secure(void);
+bool stm32mp1_rcc_is_mckprot(void);
-static inline void stm32mp1_clk_disable_non_secure(unsigned long id)
-{
- __stm32mp1_clk_disable(id, false);
-}
+void stm32mp1_clk_force_enable(unsigned long id);
+void stm32mp1_clk_force_disable(unsigned long id);
-static inline void stm32mp1_clk_disable_secure(unsigned long id)
-{
- __stm32mp1_clk_disable(id, true);
-}
+unsigned long stm32mp_clk_timer_get_rate(unsigned long id);
-unsigned int stm32mp1_clk_get_refcount(unsigned long id);
+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);
-void stm32mp1_stgen_increment(unsigned long long offset_in_ms);
+unsigned long stm32mp1_clk_rcc2id(unsigned int offset, unsigned int bit);
+
+int stm32mp1_round_opp_khz(uint32_t *freq_khz);
+int stm32mp1_set_opp_khz(uint32_t freq_khz);
+
+void stm32mp1_clock_suspend(void);
+void stm32mp1_clock_resume(void);
+
+void stm32mp1_clock_stopmode_save(void);
+int stm32mp1_clock_stopmode_resume(void);
+
+void restore_clock_pm_context(void);
+void save_clock_pm_context(void);
+
+void stm32mp1_register_clock_parents_secure(unsigned long id);
+
+void stm32mp1_update_earlyboot_clocks_state(void);
+
+void stm32mp1_dump_clocks_state(void);
#endif /* STM32MP1_CLK_H */
diff --git a/include/drivers/st/stm32mp1_ddr.h b/include/drivers/st/stm32mp1_ddr.h
index 4ab37d6b4..c8f8d12ad 100644
--- a/include/drivers/st/stm32mp1_ddr.h
+++ b/include/drivers/st/stm32mp1_ddr.h
@@ -8,9 +8,6 @@
#define STM32MP1_DDR_H
#include <stdbool.h>
-#include <stdint.h>
-
-#define DT_DDR_COMPAT "st,stm32mp1-ddr"
struct stm32mp1_ddr_size {
uint64_t base;
@@ -166,9 +163,13 @@ struct stm32mp1_ddr_config {
struct stm32mp1_ddrphy_reg p_reg;
struct stm32mp1_ddrphy_timing p_timing;
struct stm32mp1_ddrphy_cal p_cal;
+ bool p_cal_present;
+ bool self_refresh;
+ uint32_t zdata;
};
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 */
diff --git a/include/drivers/st/stm32mp1_ddr_helpers.h b/include/drivers/st/stm32mp1_ddr_helpers.h
index 38f24152a..210beee8a 100644
--- a/include/drivers/st/stm32mp1_ddr_helpers.h
+++ b/include/drivers/st/stm32mp1_ddr_helpers.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2018, STMicroelectronics - All Rights Reserved
+ * Copyright (c) 2017-2020, STMicroelectronics - All Rights Reserved
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -7,6 +7,23 @@
#ifndef STM32MP1_DDR_HELPERS_H
#define STM32MP1_DDR_HELPERS_H
+#include <stdbool.h>
+#include <stdint.h>
+
+enum stm32mp1_ddr_sr_mode {
+ DDR_SR_MODE_INVALID = 0,
+ DDR_SSR_MODE,
+ DDR_HSR_MODE,
+ DDR_ASR_MODE,
+};
+
void ddr_enable_clock(void);
+int ddr_sw_self_refresh_exit(void);
+int ddr_standby_sr_entry(uint32_t *zq0cr0_zdata);
+enum stm32mp1_ddr_sr_mode ddr_read_sr_mode(void);
+void ddr_set_sr_mode(enum stm32mp1_ddr_sr_mode mode);
+void ddr_save_sr_mode(void);
+void ddr_restore_sr_mode(void);
+bool ddr_is_nonsecured_area(uintptr_t address, uint32_t length);
#endif /* STM32MP1_DDR_HELPERS_H */
diff --git a/include/drivers/st/stm32mp1_ddr_regs.h b/include/drivers/st/stm32mp1_ddr_regs.h
index 342239a52..af232a308 100644
--- a/include/drivers/st/stm32mp1_ddr_regs.h
+++ b/include/drivers/st/stm32mp1_ddr_regs.h
@@ -380,6 +380,7 @@ struct stm32mp1_ddrphy {
#define DDRPHYC_PTR0_TITMSRST_OFFSET 18
#define DDRPHYC_PTR0_TITMSRST_MASK GENMASK(21, 18)
+#define DDRPHYC_ACIOCR_ACOE BIT(1)
#define DDRPHYC_ACIOCR_ACPDD BIT(3)
#define DDRPHYC_ACIOCR_ACPDR BIT(4)
#define DDRPHYC_ACIOCR_CKPDD_MASK GENMASK(10, 8)
@@ -399,6 +400,7 @@ struct stm32mp1_ddrphy {
#define DDRPHYC_DSGCR_ODTPDD_MASK GENMASK(23, 20)
#define DDRPHYC_DSGCR_ODTPDD_0 BIT(20)
#define DDRPHYC_DSGCR_NL2PD BIT(24)
+#define DDRPHYC_DSGCR_CKOE BIT(28)
#define DDRPHYC_ZQ0CRN_ZDATA_MASK GENMASK(27, 0)
#define DDRPHYC_ZQ0CRN_ZDATA_SHIFT 0
diff --git a/include/drivers/st/stm32mp1_pwr.h b/include/drivers/st/stm32mp1_pwr.h
index e17df44fb..9b662f2d1 100644
--- a/include/drivers/st/stm32mp1_pwr.h
+++ b/include/drivers/st/stm32mp1_pwr.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2018, STMicroelectronics - All Rights Reserved
+ * Copyright (c) 2017-2019, STMicroelectronics - All Rights Reserved
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -13,20 +13,39 @@
#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_CR2_BRRDY BIT(16)
+#define PWR_CR2_RRRDY BIT(17)
+
+#define PWR_CR3_VBE BIT(8)
+#define PWR_CR3_VBRS BIT(9)
#define PWR_CR3_DDRSREN BIT(10)
#define PWR_CR3_DDRSRDIS BIT(11)
#define PWR_CR3_DDRRETEN BIT(12)
+#define PWR_CR3_USB33DEN BIT(24)
+#define PWR_CR3_REG18EN BIT(28)
+#define PWR_CR3_REG11EN BIT(30)
#define PWR_MPUCR_PDDS BIT(0)
#define PWR_MPUCR_CSTDBYDIS BIT(3)
#define PWR_MPUCR_CSSF BIT(9)
+#define PWR_MCUCR_PDDS BIT(0)
+
+#define PWR_WKUPCR_MASK GENMASK(27, 16) | GENMASK(13, 8) | GENMASK(5, 0)
+
+#define PWR_MPUWKUPENR_MASK GENMASK(5, 0)
+
#endif /* STM32MP1_PWR_H */
diff --git a/include/drivers/st/stm32mp1_rcc.h b/include/drivers/st/stm32mp1_rcc.h
index 4b4aac87d..91c6f087b 100644
--- a/include/drivers/st/stm32mp1_rcc.h
+++ b/include/drivers/st/stm32mp1_rcc.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2019, STMicroelectronics - All Rights Reserved
+ * Copyright (c) 2015-2020, STMicroelectronics - All Rights Reserved
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -390,7 +390,8 @@
#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)
+#define RCC_HSICFGR_HSICAL_MASK GENMASK(24, 16)
+#define RCC_HSICFGR_HSICAL_TEMP_MASK GENMASK(27, 25)
/* Fields of RCC_CSICFGR register */
#define RCC_CSICFGR_CSITRIM_SHIFT 8
@@ -449,6 +450,9 @@
#define RCC_MP_SREQCLRR_STPREQ_P0 BIT(0)
#define RCC_MP_SREQCLRR_STPREQ_P1 BIT(1)
+/* Global Control Register */
+#define RCC_MP_GCR_BOOT_MCU BIT(0)
+
/* Values of RCC_UART24CKSELR register */
#define RCC_UART24CKSELR_HSI 0x00000002
@@ -462,8 +466,15 @@
#define RCC_MP_APB5ENSETR_USART1EN BIT(4)
#define RCC_MP_APB5ENSETR_RTCAPBEN BIT(8)
#define RCC_MP_APB5ENSETR_IWDG1APBEN BIT(15)
+#define RCC_MP_APB5ENSETR_STGENEN BIT(20)
/* Values of RCC_MP_AHB4ENSETR register */
+#define RCC_MP_AHB4ENSETR_GPIOAEN BIT(0)
+#define RCC_MP_AHB4ENSETR_GPIOBEN BIT(1)
+#define RCC_MP_AHB4ENSETR_GPIOCEN BIT(2)
+#define RCC_MP_AHB4ENSETR_GPIODEN BIT(3)
+#define RCC_MP_AHB4ENSETR_GPIOEEN BIT(4)
+#define RCC_MP_AHB4ENSETR_GPIOFEN BIT(5)
#define RCC_MP_AHB4ENSETR_GPIOGEN BIT(6)
#define RCC_MP_AHB4ENSETR_GPIOHEN BIT(7)
@@ -473,6 +484,12 @@
#define RCC_MP_AHB5ENSETR_HASH1EN BIT(5)
#define RCC_MP_AHB5ENSETR_RNG1EN BIT(6)
+/* Values of RCC_AHB6RSTSETR register */
+#define RCC_AHB6RSTSETR_GPURST BIT(5)
+
+/* Values of RCC_MP_APB5LPENSETR register */
+#define RCC_MP_APB5LPENSETR_STGENSTPEN BIT(21)
+
/* Values of RCC_MP_IWDGFZSETR register */
#define RCC_MP_IWDGFZSETR_IWDG1 BIT(0)
#define RCC_MP_IWDGFZSETR_IWDG2 BIT(1)
@@ -558,4 +575,12 @@
#define RCC_USBCKSELR_USBOSRC_MASK BIT(4)
#define RCC_USBCKSELR_USBOSRC_SHIFT 4
+/* RCC_MPCKSELR register fields */
+#define RCC_MPCKSELR_MPUSRC_MASK GENMASK(1, 0)
+#define RCC_MPCKSELR_MPUSRC_SHIFT 0
+
+/* RCC_CPERCKSELR register fields */
+#define RCC_CPERCKSELR_PERSRC_MASK GENMASK(1, 0)
+#define RCC_CPERCKSELR_PERSRC_SHIFT 0
+
#endif /* STM32MP1_RCC_H */
diff --git a/include/drivers/st/stm32mp1xx_hal.h b/include/drivers/st/stm32mp1xx_hal.h
new file mode 100644
index 000000000..547f7f9ae
--- /dev/null
+++ b/include/drivers/st/stm32mp1xx_hal.h
@@ -0,0 +1,204 @@
+/*
+ * Copyright (c) 2015-2019, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef __STM32_HAL_H
+#define __STM32_HAL_H
+
+#include <stdint.h>
+#include <stddef.h>
+
+#include <arch_helpers.h>
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+
+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 000000000..465aa9273
--- /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
+ *
+ * <h2><center>&copy; COPYRIGHT(c) 2015 STMicroelectronics</center></h2>
+ *
+ * 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 <drivers/st/stm32_uart_regs.h>
+#include <drivers/st/stm32mp1xx_hal.h>
+
+/**
+ * @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 000000000..28ec13c3b
--- /dev/null
+++ b/include/drivers/st/stm32mp1xx_hal_uart_ex.h
@@ -0,0 +1,88 @@
+/**
+ ******************************************************************************
+ * @file stm32mp1xx_hal_uart_ex.h
+ * @author MCD Application Team
+ * @version $VERSION$
+ * @date $DATE$
+ * @brief Header file of UART HAL Extended module.
+ ******************************************************************************
+ * @attention
+ *
+ * <h2><center>&copy; COPYRIGHT(c) 2015-2017 STMicroelectronics</center></h2>
+ *
+ * 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
index 076916730..a0aaa002f 100644
--- a/include/drivers/st/stm32mp_clkfunc.h
+++ b/include/drivers/st/stm32mp_clkfunc.h
@@ -19,15 +19,25 @@ uint32_t fdt_osc_read_uint32_default(enum stm32mp_osc_id osc_id,
const char *prop_name,
uint32_t dflt_value);
-int fdt_get_rcc_node(void *fdt);
-uint32_t fdt_rcc_read_addr(void);
+int fdt_get_rcc_node(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);
+int fdt_rcc_enable_it(const char *name);
-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);
+
+bool fdt_is_pll1_predefined(void);
+
+void stm32mp_stgen_config(unsigned long rate);
+void stm32mp_stgen_restore_counter(unsigned long long value,
+ unsigned long long offset_in_ms);
+unsigned long long stm32mp_stgen_get_counter(void);
#endif /* STM32MP_CLKFUNC_H */
diff --git a/include/drivers/st/stm32mp_dummy_regulator.h b/include/drivers/st/stm32mp_dummy_regulator.h
new file mode 100644
index 000000000..6804192ba
--- /dev/null
+++ b/include/drivers/st/stm32mp_dummy_regulator.h
@@ -0,0 +1,14 @@
+/*
+ * Copyright (C) 2019, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef STM32MP_DUMMY_REGULATOR_H
+#define STM32MP_DUMMY_REGULATOR_H
+
+#include <drivers/st/stm32mp_regulator.h>
+
+void bind_dummy_regulator(struct stm32mp_regulator *regu);
+
+#endif /* STM32MP_DUMMY_REGULATOR_H */
diff --git a/include/drivers/st/stm32mp_pmic.h b/include/drivers/st/stm32mp_pmic.h
index 984cd6014..898a28b44 100644
--- a/include/drivers/st/stm32mp_pmic.h
+++ b/include/drivers/st/stm32mp_pmic.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019, STMicroelectronics - All Rights Reserved
+ * Copyright (c) 2017-2020, STMicroelectronics - All Rights Reserved
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -11,6 +11,8 @@
#include <platform_def.h>
+#include <drivers/st/stm32mp_regulator.h>
+
/*
* dt_pmic_status - Check PMIC status from device tree
*
@@ -25,7 +27,24 @@ int dt_pmic_status(void);
*
* Returns 0 on success, and negative values on errors
*/
-int dt_pmic_configure_boot_on_regulators(void);
+int pmic_configure_boot_on_regulators(void);
+
+int pmic_set_lp_config(const char *node_name);
+
+/*
+ * dt_pmic_find_supply - Find the supply name related to a regulator name
+ *
+ * Returns 0 on success, and negative values on errors
+ */
+int dt_pmic_find_supply(const char **supply_name, const char *regu_name);
+
+/*
+ * pmic_set_regulator_min_voltage - Set target supply to its device tree
+ * "regulator-min-microvolt" value.
+ *
+ * Returns 0 on success, and negative values on errors
+ */
+int pmic_set_regulator_min_voltage(const char *regu_name);
/*
* initialize_pmic_i2c - Initialize I2C for the PMIC control
@@ -41,6 +60,24 @@ bool initialize_pmic_i2c(void);
*/
void initialize_pmic(void);
+/*
+ * configure_pmic - PMIC configuration function, called at platform init
+ *
+ * Panics on errors
+ */
+void configure_pmic(void);
+
+#if DEBUG
+void print_pmic_info_and_debug(void);
+#else
+static inline void print_pmic_info_and_debug(void)
+{
+}
+#endif
+
+bool is_pmic_regulator(struct stm32mp_regulator *regu);
+void bind_pmic_regulator(struct stm32mp_regulator *regu);
+
/*
* pmic_ddr_power_init - Initialize regulators required for DDR
*
diff --git a/include/drivers/st/stm32mp_regulator.h b/include/drivers/st/stm32mp_regulator.h
new file mode 100644
index 000000000..7a66b97ba
--- /dev/null
+++ b/include/drivers/st/stm32mp_regulator.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2019, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef STM32MP_REGULATOR_H
+#define STM32MP_REGULATOR_H
+
+#include <stdbool.h>
+
+struct stm32mp_regulator;
+
+struct stm32mp_regulator_ops {
+ int (*enable)(struct stm32mp_regulator *regu);
+ int (*disable)(struct stm32mp_regulator *regu);
+};
+
+struct stm32mp_regulator {
+ const struct stm32mp_regulator_ops *ops;
+ int id;
+ bool always_on;
+};
+
+int stm32mp_regulator_enable(struct stm32mp_regulator *regu);
+int stm32mp_regulator_disable(struct stm32mp_regulator *regu);
+int stm32mp_regulator_register(struct stm32mp_regulator *regu);
+
+int plat_bind_regulator(struct stm32mp_regulator *regu);
+
+#endif /* STM32MP_REGULATOR_H */
diff --git a/include/drivers/st/stm32mp_reset.h b/include/drivers/st/stm32mp_reset.h
index 2da5adf44..7114dddf0 100644
--- a/include/drivers/st/stm32mp_reset.h
+++ b/include/drivers/st/stm32mp_reset.h
@@ -9,7 +9,42 @@
#include <stdint.h>
-void stm32mp_reset_assert(uint32_t reset_id);
-void stm32mp_reset_deassert(uint32_t reset_id);
+/*
+ * Assert target reset, if @to_us non null, wait until reset is asserted
+ *
+ * @reset_id: Reset controller ID
+ * @to_us: Timeout in microsecond, or 0 if not waiting
+ * Return 0 on success and -ETIMEDOUT if waiting and timeout expired
+ */
+int stm32mp_reset_assert_to(uint32_t reset_id, unsigned int to_us);
+
+/*
+ * Enable reset control for target resource
+ *
+ * @reset_id: Reset controller ID
+ */
+static inline void stm32mp_reset_set(uint32_t reset_id)
+{
+ (void)stm32mp_reset_assert_to(reset_id, 0);
+}
+
+/*
+ * Deassert target reset, if @to_us non null, wait until reset is deasserted
+ *
+ * @reset_id: Reset controller ID
+ * @to_us: Timeout in microsecond, or 0 if not waiting
+ * Return 0 on success and -ETIMEDOUT if waiting and timeout expired
+ */
+int stm32mp_reset_deassert_to(uint32_t reset_id, unsigned int to_us);
+
+/*
+ * Release reset control for target resource
+ *
+ * @reset_id: Reset controller ID
+ */
+static inline void stm32mp_reset_release(uint32_t reset_id)
+{
+ (void)stm32mp_reset_deassert_to(reset_id, 0);
+}
#endif /* STM32MP_RESET_H */
diff --git a/include/drivers/st/stpmic1.h b/include/drivers/st/stpmic1.h
index f7e293b18..5c8933d84 100644
--- a/include/drivers/st/stpmic1.h
+++ b/include/drivers/st/stpmic1.h
@@ -86,15 +86,15 @@
#define ITSOURCE4_REG 0xB3U
/* Registers masks */
-#define LDO_VOLTAGE_MASK 0x7CU
-#define BUCK_VOLTAGE_MASK 0xFCU
+#define LDO_VOLTAGE_MASK GENMASK(6, 2)
+#define BUCK_VOLTAGE_MASK GENMASK(7, 2)
#define LDO_BUCK_VOLTAGE_SHIFT 2
-#define LDO_BUCK_ENABLE_MASK 0x01U
-#define LDO_BUCK_HPLP_ENABLE_MASK 0x02U
+#define LDO_BUCK_ENABLE_MASK BIT(0)
+#define LDO_BUCK_HPLP_ENABLE_MASK BIT(1)
#define LDO_BUCK_HPLP_SHIFT 1
-#define LDO_BUCK_RANK_MASK 0x01U
-#define LDO_BUCK_RESET_MASK 0x01U
-#define LDO_BUCK_PULL_DOWN_MASK 0x03U
+#define LDO_BUCK_RANK_MASK BIT(0)
+#define LDO_BUCK_RESET_MASK BIT(0)
+#define LDO_BUCK_PULL_DOWN_MASK GENMASK(1, 0)
/* Pull down register */
#define BUCK1_PULL_DOWN_SHIFT 0
@@ -135,12 +135,12 @@
/* Main PMIC VINLOW Control Register (VIN_CONTROL_REGC DMSC) */
#define SWIN_DETECTOR_ENABLED BIT(7)
#define SWOUT_DETECTOR_ENABLED BIT(6)
-#define VINLOW_HYST_MASK 0x3
+#define VINLOW_HYST_MASK GENMASK(1, 0)
#define VINLOW_HYST_SHIFT 4
-#define VINLOW_THRESHOLD_MASK 0x7
+#define VINLOW_THRESHOLD_MASK GENMASK(2, 0)
#define VINLOW_THRESHOLD_SHIFT 1
-#define VINLOW_ENABLED 0x01
-#define VINLOW_CTRL_REG_MASK 0xFF
+#define VINLOW_ENABLED BIT(0)
+#define VINLOW_CTRL_REG_MASK GENMASK(7, 0)
/* USB Control Register */
#define BOOST_OVP_DISABLED BIT(7)
@@ -148,6 +148,7 @@
#define OCP_LIMIT_HIGH BIT(3)
#define SWIN_SWOUT_ENABLED BIT(2)
#define USBSW_OTG_SWITCH_ENABLED BIT(1)
+#define BOOST_ENABLED BIT(0)
int stpmic1_powerctrl_on(void);
int stpmic1_switch_off(void);
@@ -156,11 +157,15 @@ 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);
+bool stpmic1_is_regulator_enabled(const char *name);
int stpmic1_regulator_voltage_set(const char *name, uint16_t millivolts);
int stpmic1_regulator_voltage_get(const char *name);
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);
diff --git a/include/drivers/st/usb_dwc2.h b/include/drivers/st/usb_dwc2.h
new file mode 100644
index 000000000..caff54669
--- /dev/null
+++ b/include/drivers/st/usb_dwc2.h
@@ -0,0 +1,443 @@
+/*
+ * Copyright (c) 2015-2019, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef __USB_DWC2_H
+#define __USB_DWC2_H
+
+#include <lib/usb/usb_core.h>
+
+/* 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/clock/stm32mp1-clks.h b/include/dt-bindings/clock/stm32mp1-clks.h
index 18bdb57f3..824dd45b2 100644
--- a/include/dt-bindings/clock/stm32mp1-clks.h
+++ b/include/dt-bindings/clock/stm32mp1-clks.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */
+/* SPDX-License-Identifier: GPL-2.0+ or BSD-3-Clause */
/*
* Copyright (C) STMicroelectronics 2018 - All Rights Reserved
* Author: Gabriel Fernandez <gabriel.fernandez@st.com> for STMicroelectronics.
@@ -179,6 +179,12 @@
#define DAC12_K 168
#define ETHPTP_K 169
+#define PCLK1 170
+#define PCLK2 171
+#define PCLK3 172
+#define PCLK4 173
+#define PCLK5 174
+
/* PLL */
#define PLL1 176
#define PLL2 177
@@ -248,4 +254,31 @@
#define STM32MP1_LAST_CLK 232
+/* SCMI clock identifiers */
+#define CK_SCMI0_HSE 0
+#define CK_SCMI0_HSI 1
+#define CK_SCMI0_CSI 2
+#define CK_SCMI0_LSE 3
+#define CK_SCMI0_LSI 4
+#define CK_SCMI0_PLL2_Q 5
+#define CK_SCMI0_PLL2_R 6
+#define CK_SCMI0_MPU 7
+#define CK_SCMI0_AXI 8
+#define CK_SCMI0_BSEC 9
+#define CK_SCMI0_CRYP1 10
+#define CK_SCMI0_GPIOZ 11
+#define CK_SCMI0_HASH1 12
+#define CK_SCMI0_I2C4 13
+#define CK_SCMI0_I2C6 14
+#define CK_SCMI0_IWDG1 15
+#define CK_SCMI0_RNG1 16
+#define CK_SCMI0_RTC 17
+#define CK_SCMI0_RTCAPB 18
+#define CK_SCMI0_SPI6 19
+#define CK_SCMI0_USART1 20
+
+#define CK_SCMI1_PLL3_Q 0
+#define CK_SCMI1_PLL3_R 1
+#define CK_SCMI1_MCU 2
+
#endif /* _DT_BINDINGS_STM32MP1_CLKS_H_ */
diff --git a/include/dt-bindings/pinctrl/stm32-pinfunc.h b/include/dt-bindings/pinctrl/stm32-pinfunc.h
index 7f6e4b94d..1bc2c40fc 100644
--- a/include/dt-bindings/pinctrl/stm32-pinfunc.h
+++ b/include/dt-bindings/pinctrl/stm32-pinfunc.h
@@ -26,6 +26,7 @@
#define AF14 0xf
#define AF15 0x10
#define ANALOG 0x11
+#define RSVD 0x12
/* define Pins number*/
#define PIN_NO(port, line) (((port) - 'A') * 0x10 + (line))
@@ -33,9 +34,9 @@
#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
+#define STM32MP_PKG_AA 0x1
+#define STM32MP_PKG_AB 0x2
+#define STM32MP_PKG_AC 0x4
+#define STM32MP_PKG_AD 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 000000000..d588dd71f
--- /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) 2018-2019, STMicroelectronics - All Rights Reserved
+ * Author: Yann Gautier <yann.gautier@st.com> 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/reset/stm32mp1-resets.h b/include/dt-bindings/reset/stm32mp1-resets.h
index f0c3aaef6..bc71924fa 100644
--- a/include/dt-bindings/reset/stm32mp1-resets.h
+++ b/include/dt-bindings/reset/stm32mp1-resets.h
@@ -105,4 +105,17 @@
#define GPIOJ_R 19785
#define GPIOK_R 19786
+/* SCMI reset domain identifiers */
+#define RST_SCMI0_SPI6 0
+#define RST_SCMI0_I2C4 1
+#define RST_SCMI0_I2C6 2
+#define RST_SCMI0_USART1 3
+#define RST_SCMI0_STGEN 4
+#define RST_SCMI0_GPIOZ 5
+#define RST_SCMI0_CRYP1 6
+#define RST_SCMI0_HASH1 7
+#define RST_SCMI0_RNG1 8
+#define RST_SCMI0_MDMA 9
+#define RST_SCMI0_MCU 10
+
#endif /* _DT_BINDINGS_STM32MP1_RESET_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 000000000..6678b8e66
--- /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/optee_utils.h b/include/lib/optee_utils.h
index 6067caff4..ba44f998e 100644
--- a/include/lib/optee_utils.h
+++ b/include/lib/optee_utils.h
@@ -9,6 +9,7 @@
#include <common/bl_common.h>
+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/usb/usb_core.h b/include/lib/usb/usb_core.h
new file mode 100644
index 000000000..e4dd43862
--- /dev/null
+++ b/include/lib/usb/usb_core.h
@@ -0,0 +1,353 @@
+/*
+ * Copyright (c) 2015-2019, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef USB_CORE_H
+#define USB_CORE_H
+
+#include <stdint.h>
+
+#include <lib/utils_def.h>
+
+#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 /* USB_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 000000000..8a3a5a505
--- /dev/null
+++ b/include/lib/usb/usb_st_dfu.h
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 2015-2019, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef USB_ST_DFU_H
+#define USB_ST_DFU_H
+
+#include <stdint.h>
+
+#include <lib/usb/usb_core.h>
+
+#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_ST_DFU_H */
diff --git a/include/lib/utils_def.h b/include/lib/utils_def.h
index 35ae33a68..8efa90751 100644
--- a/include/lib/utils_def.h
+++ b/include/lib/utils_def.h
@@ -63,6 +63,16 @@
((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__ ({ \
__typeof__(x) _x = (x); \
__typeof__(y) _y = (y); \
@@ -77,6 +87,15 @@
_x > _y ? _x : _y; \
})
+#define CLAMP(x, min, max) __extension__ ({ \
+ __typeof__(x) _x = (x); \
+ __typeof__(min) _min = (min); \
+ __typeof__(max) _max = (max); \
+ (void)(&_x == &_min); \
+ (void)(&_x == &_max); \
+ (_x > _max ? _max : (_x < _min ? _min : _x)); \
+})
+
/*
* The round_up() macro rounds up a value to the given boundary in a
* type-agnostic yet type-safe manner. The boundary must be a power of two.
diff --git a/include/lib/xlat_tables/xlat_tables_v2_helpers.h b/include/lib/xlat_tables/xlat_tables_v2_helpers.h
index b17b71a87..69f142aab 100644
--- a/include/lib/xlat_tables/xlat_tables_v2_helpers.h
+++ b/include/lib/xlat_tables/xlat_tables_v2_helpers.h
@@ -122,6 +122,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)\
@@ -130,14 +161,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 eeae62141..0922c5342 100644
--- a/include/plat/common/platform.h
+++ b/include/plat/common/platform.h
@@ -96,6 +96,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);
@@ -103,7 +108,7 @@ void plat_error_handler(int err) __dead2;
void plat_panic_handler(void) __dead2;
const char *plat_log_get_prefix(unsigned int log_level);
void bl2_plat_preload_setup(void);
-int plat_try_next_boot_source(void);
+int plat_try_next_boot_source(unsigned int image_id);
/*******************************************************************************
* Mandatory BL1 functions
diff --git a/lib/compiler-rt/builtins/arm/aeabi_ldivmod.S b/lib/compiler-rt/builtins/arm/aeabi_ldivmod.S
new file mode 100644
index 000000000..038ae5d72
--- /dev/null
+++ b/lib/compiler-rt/builtins/arm/aeabi_ldivmod.S
@@ -0,0 +1,46 @@
+//===-- aeabi_ldivmod.S - EABI ldivmod implementation ---------------------===//
+//
+// 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.
+//
+//===----------------------------------------------------------------------===//
+
+#include "../assembly.h"
+
+// struct { int64_t quot, int64_t rem}
+// __aeabi_ldivmod(int64_t numerator, int64_t denominator) {
+// int64_t rem, quot;
+// quot = __divmoddi4(numerator, denominator, &rem);
+// return {quot, rem};
+// }
+
+#if defined(__MINGW32__)
+#define __aeabi_ldivmod __rt_sdiv64
+#endif
+
+ .syntax unified
+ .p2align 2
+DEFINE_COMPILERRT_FUNCTION(__aeabi_ldivmod)
+ push {r6, lr}
+ sub sp, sp, #16
+ add r6, sp, #8
+ str r6, [sp]
+#if defined(__MINGW32__)
+ movs r6, r0
+ movs r0, r2
+ movs r2, r6
+ movs r6, r1
+ movs r1, r3
+ movs r3, r6
+#endif
+ bl SYMBOL_NAME(__divmoddi4)
+ ldr r2, [sp, #8]
+ ldr r3, [sp, #12]
+ add sp, sp, #16
+ pop {r6, pc}
+END_COMPILERRT_FUNCTION(__aeabi_ldivmod)
+
+NO_EXEC_STACK_DIRECTIVE
+
diff --git a/lib/compiler-rt/builtins/divdi3.c b/lib/compiler-rt/builtins/divdi3.c
new file mode 100644
index 000000000..b8eebcb20
--- /dev/null
+++ b/lib/compiler-rt/builtins/divdi3.c
@@ -0,0 +1,29 @@
+/* ===-- divdi3.c - Implement __divdi3 -------------------------------------===
+ *
+ * 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 __divdi3 for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+/* Returns: a / b */
+
+COMPILER_RT_ABI di_int
+__divdi3(di_int a, di_int b)
+{
+ const int bits_in_dword_m1 = (int)(sizeof(di_int) * CHAR_BIT) - 1;
+ di_int s_a = a >> bits_in_dword_m1; /* s_a = a < 0 ? -1 : 0 */
+ di_int s_b = b >> bits_in_dword_m1; /* s_b = b < 0 ? -1 : 0 */
+ a = (a ^ s_a) - s_a; /* negate if s_a == -1 */
+ b = (b ^ s_b) - s_b; /* negate if s_b == -1 */
+ s_a ^= s_b; /*sign of quotient */
+ return (__udivmoddi4(a, b, (du_int*)0) ^ s_a) - s_a; /* negate if s_a == -1 */
+}
diff --git a/lib/compiler-rt/builtins/divmoddi4.c b/lib/compiler-rt/builtins/divmoddi4.c
new file mode 100644
index 000000000..0d4df67a6
--- /dev/null
+++ b/lib/compiler-rt/builtins/divmoddi4.c
@@ -0,0 +1,25 @@
+/*===-- divmoddi4.c - Implement __divmoddi4 --------------------------------===
+ *
+ * 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 __divmoddi4 for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+/* Returns: a / b, *rem = a % b */
+
+COMPILER_RT_ABI di_int
+__divmoddi4(di_int a, di_int b, di_int* rem)
+{
+ di_int d = __divdi3(a,b);
+ *rem = a - (d*b);
+ return d;
+}
diff --git a/lib/compiler-rt/builtins/popcountdi2.c b/lib/compiler-rt/builtins/popcountdi2.c
new file mode 100644
index 000000000..5e8a62f07
--- /dev/null
+++ b/lib/compiler-rt/builtins/popcountdi2.c
@@ -0,0 +1,36 @@
+/* ===-- popcountdi2.c - Implement __popcountdi2 ----------------------------===
+ *
+ * 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 __popcountdi2 for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+/* Returns: count of 1 bits */
+
+COMPILER_RT_ABI si_int
+__popcountdi2(di_int a)
+{
+ du_int x2 = (du_int)a;
+ x2 = x2 - ((x2 >> 1) & 0x5555555555555555uLL);
+ /* Every 2 bits holds the sum of every pair of bits (32) */
+ x2 = ((x2 >> 2) & 0x3333333333333333uLL) + (x2 & 0x3333333333333333uLL);
+ /* Every 4 bits holds the sum of every 4-set of bits (3 significant bits) (16) */
+ x2 = (x2 + (x2 >> 4)) & 0x0F0F0F0F0F0F0F0FuLL;
+ /* Every 8 bits holds the sum of every 8-set of bits (4 significant bits) (8) */
+ su_int x = (su_int)(x2 + (x2 >> 32));
+ /* The lower 32 bits hold four 16 bit sums (5 significant bits). */
+ /* Upper 32 bits are garbage */
+ x = x + (x >> 16);
+ /* The lower 16 bits hold two 32 bit sums (6 significant bits). */
+ /* Upper 16 bits are garbage */
+ return (x + (x >> 8)) & 0x0000007F; /* (7 significant bits) */
+}
diff --git a/lib/compiler-rt/builtins/popcountsi2.c b/lib/compiler-rt/builtins/popcountsi2.c
new file mode 100644
index 000000000..44544ff49
--- /dev/null
+++ b/lib/compiler-rt/builtins/popcountsi2.c
@@ -0,0 +1,33 @@
+/* ===-- popcountsi2.c - Implement __popcountsi2 ---------------------------===
+ *
+ * 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 __popcountsi2 for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+/* Returns: count of 1 bits */
+
+COMPILER_RT_ABI si_int
+__popcountsi2(si_int a)
+{
+ su_int x = (su_int)a;
+ x = x - ((x >> 1) & 0x55555555);
+ /* Every 2 bits holds the sum of every pair of bits */
+ x = ((x >> 2) & 0x33333333) + (x & 0x33333333);
+ /* Every 4 bits holds the sum of every 4-set of bits (3 significant bits) */
+ x = (x + (x >> 4)) & 0x0F0F0F0F;
+ /* Every 8 bits holds the sum of every 8-set of bits (4 significant bits) */
+ x = (x + (x >> 16));
+ /* The lower 16 bits hold two 8 bit sums (5 significant bits).*/
+ /* Upper 16 bits are garbage */
+ return (x + (x >> 8)) & 0x0000003F; /* (6 significant bits) */
+}
diff --git a/lib/compiler-rt/compiler-rt.mk b/lib/compiler-rt/compiler-rt.mk
index 49e497eb8..40c669f98 100644
--- a/lib/compiler-rt/compiler-rt.mk
+++ b/lib/compiler-rt/compiler-rt.mk
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+# Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
@@ -28,9 +28,15 @@
# POSSIBILITY OF SUCH DAMAGE.
#
+COMPILER_RT_SRCS := lib/compiler-rt/builtins/popcountdi2.c \
+ lib/compiler-rt/builtins/popcountsi2.c
+
ifeq (${ARCH},aarch32)
-COMPILER_RT_SRCS := lib/compiler-rt/builtins/arm/aeabi_uldivmod.S \
- lib/compiler-rt/builtins/udivmoddi4.c \
+COMPILER_RT_SRCS += lib/compiler-rt/builtins/arm/aeabi_ldivmod.S \
+ lib/compiler-rt/builtins/arm/aeabi_uldivmod.S \
lib/compiler-rt/builtins/ctzdi2.c \
- lib/compiler-rt/builtins/lshrdi3.c
+ lib/compiler-rt/builtins/divdi3.c \
+ lib/compiler-rt/builtins/divmoddi4.c \
+ lib/compiler-rt/builtins/lshrdi3.c \
+ lib/compiler-rt/builtins/udivmoddi4.c
endif
diff --git a/lib/optee/optee_utils.c b/lib/optee/optee_utils.c
index 2a407939b..d5a336b55 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,
return 0;
}
+/*******************************************************************************
+ * 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 000000000..fd0f20424
--- /dev/null
+++ b/lib/usb/usb_core.c
@@ -0,0 +1,733 @@
+/*
+ * Copyright (c) 2015-2019, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+
+#include <common/debug.h>
+#include <lib/usb/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, &param)) {
+ 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 000000000..8876b7499
--- /dev/null
+++ b/lib/usb/usb_st_dfu.c
@@ -0,0 +1,865 @@
+/*
+ * Copyright (c) 2015-2019, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <string.h>
+
+#include <platform_def.h>
+
+#include <common/debug.h>
+#include <lib/usb/usb_st_dfu.h>
+
+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:
+ usb_dfu_detach(pdev, req);
+ 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 4b01b9b7a..f045d3e16 100644
--- a/lib/xlat_tables/aarch32/xlat_tables.c
+++ b/lib/xlat_tables/aarch32/xlat_tables.c
@@ -26,8 +26,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 c86412c9b..e62454d55 100644
--- a/lib/xlat_tables/aarch64/xlat_tables.c
+++ b/lib/xlat_tables/aarch64/xlat_tables.c
@@ -25,6 +25,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 23fe3f0b4..ba0ffbe19 100644
--- a/lib/xlat_tables/xlat_tables_common.c
+++ b/lib/xlat_tables/xlat_tables_common.c
@@ -38,8 +38,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;
@@ -411,6 +420,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 4f62f469f..2982b25e6 100644
--- a/lib/xlat_tables_v2/xlat_tables_core.c
+++ b/lib/xlat_tables_v2/xlat_tables_core.c
@@ -1191,7 +1191,12 @@ void __init 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/defaults.mk b/make_helpers/defaults.mk
index b7fb173b1..df8ab79e4 100644
--- a/make_helpers/defaults.mk
+++ b/make_helpers/defaults.mk
@@ -106,6 +106,9 @@ ENABLE_BTI := 0
# Use BRANCH_PROTECTION to enable PAUTH.
ENABLE_PAUTH := 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/common/aarch32/platform_helpers.S b/plat/common/aarch32/platform_helpers.S
index 5b9cb5914..d2c20b4a7 100644
--- a/plat/common/aarch32/platform_helpers.S
+++ b/plat/common/aarch32/platform_helpers.S
@@ -8,6 +8,11 @@
#include <asm_macros.S>
.weak plat_report_exception
+#if AARCH32_EXCEPTION_DEBUG
+ .weak plat_report_undef_inst
+ .weak plat_report_prefetch_abort
+ .weak plat_report_data_abort
+#endif
.weak plat_reset_handler
.weak plat_disable_acp
.weak bl1_plat_prepare_exit
@@ -23,6 +28,35 @@ 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
+
/* -----------------------------------------------------
* Placeholder function which should be redefined by
* each platform.
diff --git a/plat/common/plat_bl_common.c b/plat/common/plat_bl_common.c
index b46656c7a..bf7fba807 100644
--- a/plat/common/plat_bl_common.c
+++ b/plat/common/plat_bl_common.c
@@ -48,7 +48,7 @@ int bl2_plat_handle_post_image_load(unsigned int image_id)
return 0;
}
-int plat_try_next_boot_source(void)
+int plat_try_next_boot_source(unsigned int image_id)
{
return 0;
}
diff --git a/plat/st/common/bl2_io_storage.c b/plat/st/common/bl2_io_storage.c
index 38b2a0bd7..f94a5c2c2 100644
--- a/plat/st/common/bl2_io_storage.c
+++ b/plat/st/common/bl2_io_storage.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2015-2020, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -14,23 +14,42 @@
#include <drivers/io/io_block.h>
#include <drivers/io/io_driver.h>
#include <drivers/io/io_dummy.h>
+#include <drivers/io/io_mtd.h>
#include <drivers/io/io_storage.h>
#include <drivers/mmc.h>
#include <drivers/partition/partition.h>
+#include <drivers/raw_nand.h>
+#include <drivers/spi_nand.h>
+#include <drivers/spi_nor.h>
#include <drivers/st/io_mmc.h>
#include <drivers/st/io_stm32image.h>
+#include <drivers/st/stm32_fmc2_nand.h>
+#include <drivers/st/stm32_qspi.h>
#include <drivers/st/stm32_sdmmc2.h>
#include <lib/mmio.h>
#include <lib/utils.h>
#include <plat/common/platform.h>
+#if STM32MP_UART_PROGRAMMER
+#include <drivers/st/io_uart.h>
+#endif
+#if STM32MP_USB_PROGRAMMER
+#include <drivers/st/io_programmer_st_usb.h>
+#include <drivers/st/usb_dwc2.h>
+#include <lib/usb/usb_core.h>
+#include <lib/usb/usb_st_dfu.h>
+#include <usb_ctx.h>
+#endif
+
/* 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;
+static uintptr_t storage_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 */
@@ -51,8 +70,63 @@ static const io_block_dev_spec_t mmc_block_dev_spec = {
.block_size = MMC_BLOCK_SIZE,
};
-static uintptr_t storage_dev_handle;
static const io_dev_connector_t *mmc_dev_con;
+#endif /* STM32MP_SDMMC || STM32MP_EMMC */
+
+#if STM32MP_SPI_NOR
+static io_mtd_dev_spec_t spi_nor_dev_spec = {
+ .ops = {
+ .init = spi_nor_init,
+ .read = spi_nor_read,
+ },
+};
+#endif
+
+#if STM32MP_RAW_NAND
+static io_mtd_dev_spec_t nand_dev_spec = {
+ .ops = {
+ .init = nand_raw_init,
+ .read = nand_read,
+ },
+};
+
+static const io_dev_connector_t *nand_dev_con;
+#endif
+
+#if STM32MP_SPI_NAND
+static io_mtd_dev_spec_t spi_nand_dev_spec = {
+ .ops = {
+ .init = spi_nand_init,
+ .read = nand_read,
+ },
+};
+#endif
+
+#if STM32MP_SPI_NAND || STM32MP_SPI_NOR
+static const io_dev_connector_t *spi_dev_con;
+#endif
+
+#if STM32MP_UART_PROGRAMMER
+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 */
+
+#if STM32MP_USB_PROGRAMMER
+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_PROGRAMMER */
#ifdef AARCH32_SP_OPTEE
static const struct stm32image_part_info optee_header_partition_spec = {
@@ -96,7 +170,7 @@ enum {
IMG_IDX_NUM
};
-static struct stm32image_device_info stm32image_dev_info_spec = {
+static struct stm32image_device_info stm32image_dev_info_spec __unused = {
.lba_size = MMC_BLOCK_SIZE,
.part_info[IMG_IDX_BL33] = {
.name = BL33_IMAGE_NAME,
@@ -123,7 +197,7 @@ static io_block_spec_t stm32image_block_spec = {
.length = 0,
};
-static const io_dev_connector_t *stm32image_dev_con;
+static const io_dev_connector_t *stm32image_dev_con __unused;
static int open_dummy(const uintptr_t spec);
static int open_image(const uintptr_t spec);
@@ -169,11 +243,13 @@ static const struct plat_io_policy policies[] = {
.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,
@@ -205,8 +281,24 @@ static void print_boot_device(boot_api_context_t *boot_context)
case BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_EMMC:
INFO("Using EMMC\n");
break;
+ case BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_NOR_QSPI:
+ INFO("Using QSPI NOR\n");
+ break;
+ case BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_NAND_FMC:
+ INFO("Using FMC NAND\n");
+ break;
+ case BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_NAND_QSPI:
+ INFO("Using SPI NAND\n");
+ break;
+ case BOOT_API_CTX_BOOT_INTERFACE_SEL_SERIAL_UART:
+ INFO("Using UART\n");
+ break;
+ case BOOT_API_CTX_BOOT_INTERFACE_SEL_SERIAL_USB:
+ INFO("Using USB\n");
+ break;
default:
- ERROR("Boot interface not found\n");
+ ERROR("Boot interface %u not found\n",
+ boot_context->boot_interface_selected);
panic();
break;
}
@@ -216,6 +308,7 @@ static void print_boot_device(boot_api_context_t *boot_context)
}
}
+#if STM32MP_SDMMC || STM32MP_EMMC
static void boot_mmc(enum mmc_device_type mmc_dev_type,
uint16_t boot_interface_instance)
{
@@ -251,6 +344,10 @@ static void boot_mmc(enum mmc_device_type mmc_dev_type,
break;
}
+ if (mmc_dev_type == MMC_IS_SD) {
+ params.flags = MMC_FLAG_SD_CMD6;
+ }
+
params.device_info = &device_info;
if (stm32_sdmmc2_mmc_init(&params) != 0) {
ERROR("SDMMC%u init failed\n", boot_interface_instance);
@@ -305,6 +402,243 @@ static void boot_mmc(enum mmc_device_type mmc_dev_type,
&image_dev_handle);
assert(io_result == 0);
}
+#endif /* STM32MP_SDMMC || STM32MP_EMMC */
+
+#if STM32MP_SPI_NOR
+static void boot_spi_nor(boot_api_context_t *boot_context)
+{
+ int io_result __unused;
+ uint8_t idx;
+ struct stm32image_part_info *part;
+
+ io_result = stm32_qspi_init();
+ assert(io_result == 0);
+
+ io_result = register_io_dev_mtd(&spi_dev_con);
+ assert(io_result == 0);
+
+ /* Open connections to device */
+ io_result = io_dev_open(spi_dev_con,
+ (uintptr_t)&spi_nor_dev_spec,
+ &storage_dev_handle);
+ assert(io_result == 0);
+
+ stm32image_dev_info_spec.device_size = spi_nor_dev_spec.device_size;
+
+ idx = IMG_IDX_BL33;
+ part = &stm32image_dev_info_spec.part_info[idx];
+ part->part_offset = STM32MP_NOR_BL33_OFFSET;
+ part->bkp_offset = 0U;
+
+#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 = 0U;
+
+ idx = IMG_IDX_OPTEE_PAGED;
+ part = &stm32image_dev_info_spec.part_info[idx];
+ part->part_offset = STM32MP_NOR_TEED_OFFSET;
+ part->bkp_offset = 0U;
+
+ idx = IMG_IDX_OPTEE_PAGER;
+ part = &stm32image_dev_info_spec.part_info[idx];
+ part->part_offset = STM32MP_NOR_TEEX_OFFSET;
+ part->bkp_offset = 0U;
+#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);
+}
+#endif /* STM32MP_SPI_NOR */
+
+#if STM32MP_RAW_NAND
+static void boot_fmc2_nand(boot_api_context_t *boot_context)
+{
+ int io_result __unused;
+ uint8_t idx;
+ struct stm32image_part_info *part;
+
+ io_result = stm32_fmc2_init();
+ assert(io_result == 0);
+
+ /* Register the IO device on this platform */
+ io_result = register_io_dev_mtd(&nand_dev_con);
+ assert(io_result == 0);
+
+ /* Open connections to device */
+ 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.device_size;
+
+ 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.erase_size;
+
+#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.erase_size;
+
+ 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.erase_size;
+
+ 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.erase_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);
+}
+#endif /* STM32MP_RAW_NAND */
+
+#if STM32MP_SPI_NAND
+static void boot_spi_nand(boot_api_context_t *boot_context)
+{
+ int io_result __unused;
+ uint8_t idx;
+ struct stm32image_part_info *part;
+
+ io_result = stm32_qspi_init();
+ assert(io_result == 0);
+
+ io_result = register_io_dev_mtd(&spi_dev_con);
+ assert(io_result == 0);
+
+ /* Open connections to device */
+ io_result = io_dev_open(spi_dev_con,
+ (uintptr_t)&spi_nand_dev_spec,
+ &storage_dev_handle);
+ assert(io_result == 0);
+
+ stm32image_dev_info_spec.device_size =
+ spi_nand_dev_spec.device_size;
+
+ idx = IMG_IDX_BL33;
+ part = &stm32image_dev_info_spec.part_info[idx];
+ part->part_offset = STM32MP_NAND_BL33_OFFSET;
+ part->bkp_offset = spi_nand_dev_spec.erase_size;
+
+#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 = spi_nand_dev_spec.erase_size;
+
+ idx = IMG_IDX_OPTEE_PAGED;
+ part = &stm32image_dev_info_spec.part_info[idx];
+ part->part_offset = STM32MP_NAND_TEED_OFFSET;
+ part->bkp_offset = spi_nand_dev_spec.erase_size;
+
+ idx = IMG_IDX_OPTEE_PAGER;
+ part = &stm32image_dev_info_spec.part_info[idx];
+ part->part_offset = STM32MP_NAND_TEEX_OFFSET;
+ part->bkp_offset = spi_nand_dev_spec.erase_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);
+}
+#endif /* STM32MP_SPI_NAND */
+
+#if STM32MP_UART_PROGRAMMER
+static void flash_uart(uint16_t boot_interface_instance)
+{
+ int io_result __unused;
+ uintptr_t uart_addr;
+
+ /* 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_interface_instance);
+
+ if (uart_addr != 0U) {
+ 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 */
+ io_result = io_dev_open(uart_dev_con, (uintptr_t)&uart_programmer,
+ &image_dev_handle);
+ assert(io_result == 0);
+}
+#endif
+
+#if STM32MP_USB_PROGRAMMER
+static void flash_usb(struct usb_ctx *usb_context)
+{
+ int io_result __unused;
+
+ 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;
+ usb_dfu_handle.dev_status[1] = 0;
+ usb_dfu_handle.dev_status[2] = 0;
+ usb_dfu_handle.dev_status[3] = 0;
+ usb_dfu_handle.dev_status[4] = usb_dfu_handle.dev_state;
+ usb_dfu_handle.dev_status[5] = 0;
+
+ /* Register the IO devices on this platform */
+ io_result = register_io_dev_usb(&usb_dev_con);
+ assert(io_result == 0);
+
+ /* Open connections to devices */
+ io_result = io_dev_open(usb_dev_con,
+ (uintptr_t)&usb_core_handle,
+ &image_dev_handle);
+
+ assert(io_result == 0);
+}
+#endif
void stm32mp_io_setup(void)
{
@@ -328,18 +662,53 @@ void stm32mp_io_setup(void)
assert(io_result == 0);
switch (boot_context->boot_interface_selected) {
+#if STM32MP_SDMMC
case BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_SD:
dmbsy();
boot_mmc(MMC_IS_SD, boot_context->boot_interface_instance);
break;
+#endif
+#if STM32MP_EMMC
case BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_EMMC:
dmbsy();
boot_mmc(MMC_IS_EMMC, boot_context->boot_interface_instance);
break;
+#endif
+#if STM32MP_SPI_NOR
+ case BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_NOR_QSPI:
+ dmbsy();
+ boot_spi_nor(boot_context);
+ break;
+#endif
+#if STM32MP_RAW_NAND
+ case BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_NAND_FMC:
+ dmbsy();
+ boot_fmc2_nand(boot_context);
+ break;
+#endif
+#if STM32MP_SPI_NAND
+ case BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_NAND_QSPI:
+ dmbsy();
+ boot_spi_nand(boot_context);
+ break;
+#endif
+#if STM32MP_UART_PROGRAMMER
+ case BOOT_API_CTX_BOOT_INTERFACE_SEL_SERIAL_UART:
+ dmbsy();
+ flash_uart(boot_context->boot_interface_instance);
+ break;
+#endif
+#if STM32MP_USB_PROGRAMMER
+ case BOOT_API_CTX_BOOT_INTERFACE_SEL_SERIAL_USB:
+ dmbsy();
+ flash_usb((struct usb_ctx *)boot_context->usb_context);
+ break;
+#endif
default:
ERROR("Boot interface %d not supported\n",
boot_context->boot_interface_selected);
+ panic();
break;
}
}
@@ -365,3 +734,58 @@ int plat_get_image_source(unsigned int image_id, uintptr_t *dev_handle,
return rc;
}
+
+/*
+ * This function shall return 0 if it cannot find an alternate
+ * image to be loaded and any non-zero value otherwise.
+ */
+int plat_try_next_boot_source(unsigned int image_id)
+{
+ int io_result __unused;
+ const struct stm32image_part_info *partition_spec;
+ struct stm32image_part_info *part;
+ const struct plat_io_policy *policy;
+ uint32_t idx;
+ static unsigned int backup_nb;
+ static unsigned int backup_id = MAX_NUMBER_IDS;
+
+ assert(image_id < ARRAY_SIZE(policies));
+
+ if (backup_id != image_id) {
+ backup_id = image_id;
+ backup_nb = 0;
+ }
+
+ backup_nb++;
+
+ if (backup_nb >= PLATFORM_MTD_BACKUP_BLOCKS) {
+ return 0;
+ }
+
+ policy = &policies[image_id];
+ partition_spec = (struct stm32image_part_info *)policy->image_spec;
+ for (idx = 0U; idx < STM32_PART_NUM; idx++) {
+ part = &stm32image_dev_info_spec.part_info[idx];
+ if (part->binary_type == partition_spec->binary_type) {
+ break;
+ }
+ }
+
+ assert(idx < STM32_PART_NUM);
+
+ if (part->bkp_offset == 0U) {
+ return 0;
+ }
+
+ part->part_offset += part->bkp_offset;
+ /*
+ * Reopen the io_dev as it was closed in the load_auth_image()
+ * sequence.
+ */
+ io_result = io_dev_open(stm32image_dev_con,
+ (uintptr_t)&stm32image_dev_info_spec,
+ &image_dev_handle);
+ assert(io_result == 0);
+
+ return 1;
+}
diff --git a/plat/st/common/include/stm32mp_auth.h b/plat/st/common/include/stm32mp_auth.h
deleted file mode 100644
index 3075d18ac..000000000
--- a/plat/st/common/include/stm32mp_auth.h
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#ifndef STM32MP_AUTH_H
-#define STM32MP_AUTH_H
-
-struct stm32mp_auth_ops {
- uint32_t (*check_key)(uint8_t *pubkey_in, uint8_t *pubkey_out);
- uint32_t (*verify_signature)(uint8_t *hash_in, uint8_t *pubkey_in,
- uint8_t *signature, uint32_t ecc_algo);
-};
-
-void stm32mp_init_auth(struct stm32mp_auth_ops *init_ptr);
-int stm32mp_auth_image(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
index 4f8567979..ab419f15f 100644
--- a/plat/st/common/include/stm32mp_common.h
+++ b/plat/st/common/include/stm32mp_common.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2018-2019, STMicroelectronics - All Rights Reserved
+ * Copyright (C) 2018-2020, STMicroelectronics - All Rights Reserved
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -7,16 +7,22 @@
#ifndef STM32MP_COMMON_H
#define STM32MP_COMMON_H
+#include <cdefs.h>
#include <stdbool.h>
#include <platform_def.h>
+void __dead2 stm32mp_plat_reset(int cpu);
+
/* Functions to save and get boot context address given by ROM code */
void stm32mp_save_boot_ctx_address(uintptr_t address);
uintptr_t stm32mp_get_boot_ctx_address(void);
bool stm32mp_is_single_core(void);
bool stm32mp_is_closed_device(void);
+bool stm32mp_is_auth_supported(void);
+
+const char *stm32mp_get_cpu_supply_name(void);
/* Return the base address of the DDR controller */
uintptr_t stm32mp_ddrctrl_base(void);
@@ -30,9 +36,22 @@ uintptr_t stm32mp_pwr_base(void);
/* Return the base address of the RCC peripheral */
uintptr_t stm32mp_rcc_base(void);
+void stm32_gic_pcpu_init(void);
+void stm32_gic_init(void);
+int stm32_gic_enable_spi(int node, const char *name);
+
/* Check MMU status to allow spinlock use */
bool stm32mp_lock_available(void);
+/* SMP protection on PWR registers access */
+void stm32mp_pwr_regs_lock(void);
+void stm32mp_pwr_regs_unlock(void);
+
+int stm32_get_otp_index(const char *otp_name, uint32_t *otp_idx,
+ uint32_t *otp_len);
+int stm32_get_otp_value(const char *otp_name, uint32_t *otp_val);
+int stm32_get_otp_value_from_idx(const uint32_t otp_idx, uint32_t *otp_val);
+
/* Get IWDG platform instance ID from peripheral IO memory base address */
uint32_t stm32_iwdg_get_instance(uintptr_t base);
@@ -44,6 +63,11 @@ uint32_t stm32_iwdg_get_otp_config(uint32_t iwdg_inst);
uint32_t stm32_iwdg_shadow_update(uint32_t iwdg_inst, uint32_t flags);
#endif
+#if STM32MP_UART_PROGRAMMER
+/* Get the UART address from its instance number */
+uintptr_t get_uart_address(uint32_t instance_nb);
+#endif
+
/*
* Platform util functions for the GPIO driver
* @bank: Target GPIO bank ID as per DT bindings
@@ -67,14 +91,17 @@ void stm32mp_print_cpuinfo(void);
/* Print board information */
void stm32mp_print_boardinfo(void);
+/* Check HW CPU OPP support */
+bool stm32mp_supports_cpu_opp(uint32_t opp_id);
+
/*
* Util for clock gating and to get clock rate for stm32 and platform drivers
* @id: Target clock ID, ID used in clock DT bindings
*/
bool stm32mp_clk_is_enabled(unsigned long id);
+unsigned long stm32mp_clk_get_rate(unsigned long id);
void stm32mp_clk_enable(unsigned long id);
void stm32mp_clk_disable(unsigned long id);
-unsigned long stm32mp_clk_get_rate(unsigned long id);
/* Initialise the IO layer and register platform IO devices */
void stm32mp_io_setup(void);
@@ -87,4 +114,10 @@ void stm32mp_io_setup(void);
*/
int stm32mp_check_header(boot_api_image_header_t *header, uintptr_t buffer);
+#if TRUSTED_BOARD_BOOT
+void stm32mp_save_loaded_header(void *header);
+void stm32mp_delete_loaded_header(void);
+boot_api_image_header_t *stm32mp_get_loaded_header(void);
+#endif
+
#endif /* STM32MP_COMMON_H */
diff --git a/plat/st/common/include/stm32mp_dt.h b/plat/st/common/include/stm32mp_dt.h
index 74b01b3aa..873bed551 100644
--- a/plat/st/common/include/stm32mp_dt.h
+++ b/plat/st/common/include/stm32mp_dt.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2017-2020, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -9,6 +9,8 @@
#include <stdbool.h>
+#include <libfdt.h>
+
#define DT_DISABLED U(0)
#define DT_NON_SECURE U(1)
#define DT_SECURE U(2)
@@ -28,20 +30,28 @@ 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);
+int dt_get_node_by_compatible(const char *compatible);
+int dt_match_instance_by_compatible(const char *compatible, uintptr_t address);
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);
+int dt_get_max_opp_freqvolt(uint32_t *freq_khz, uint32_t *voltage_mv);
+int dt_get_all_opp_freqvolt(uint32_t *count, uint32_t *freq_khz_array,
+ uint32_t *voltage_mv_array);
uint32_t dt_get_pwr_vdd_voltage(void);
-uintptr_t dt_get_syscfg_base(void);
+const char *dt_get_cpu_regulator_name(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
index 8b786cc04..8b048284c 100644
--- a/plat/st/common/include/stm32mp_shres_helpers.h
+++ b/plat/st/common/include/stm32mp_shres_helpers.h
@@ -12,63 +12,16 @@
#include <common/debug.h>
/*
- * 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.
+ * Lock/unlock access to shared registers
+ *
+ * @lock - NULL or pointer to spin lock
*/
-#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) ? 1 : 0;
- *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);
-}
+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);
#endif /* STM32MP_SHRES_HELPERS_H */
diff --git a/plat/st/common/stm32_gic.c b/plat/st/common/stm32_gic.c
new file mode 100644
index 000000000..ec3e3525c
--- /dev/null
+++ b/plat/st/common/stm32_gic.c
@@ -0,0 +1,223 @@
+/*
+ * Copyright (c) 2016-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <libfdt.h>
+
+#include <platform_def.h>
+
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <drivers/arm/gicv2.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <lib/utils.h>
+#include <plat/common/platform.h>
+
+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
+ * interrupts.
+ *****************************************************************************/
+static const interrupt_prop_t stm32_interrupt_props[] = {
+ PLATFORM_G1S_PROPS(GICV2_INTR_GROUP0),
+ PLATFORM_G0_PROPS(GICV2_INTR_GROUP0)
+};
+
+/* 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 gicv2_driver_data_t platform_gic_data = {
+ .interrupt_props = stm32_interrupt_props,
+ .interrupt_props_num = ARRAY_SIZE(stm32_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, STM32MP_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 stm32_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();
+
+ stm32_gic_pcpu_init();
+}
+
+void stm32_gic_pcpu_init(void)
+{
+ gicv2_pcpu_distif_init();
+ 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) {
+ switch (fdt_get_status(node)) {
+ case DT_SECURE:
+ index = fdt_stringlist_search(fdt, node,
+ "interrupt-names", name);
+ break;
+ default:
+ index = fdt_stringlist_search(fdt, node,
+ "secure-interrupt-names",
+ name);
+ break;
+ }
+
+ 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/common/stm32mp_auth.c b/plat/st/common/stm32mp_auth.c
deleted file mode 100644
index 0ef6d5454..000000000
--- a/plat/st/common/stm32mp_auth.c
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * Copyright (c) 2019, STMicroelectronics - All Rights Reserved
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#include <errno.h>
-
-#include <platform_def.h>
-
-#include <common/debug.h>
-#include <drivers/io/io_storage.h>
-#include <drivers/st/bsec.h>
-#include <drivers/st/stm32_hash.h>
-#include <lib/xlat_tables/xlat_tables_v2.h>
-#include <plat/common/platform.h>
-
-static const struct stm32mp_auth_ops *auth_ops;
-
-void stm32mp_init_auth(struct stm32mp_auth_ops *init_ptr)
-{
- if ((init_ptr == NULL) ||
- (init_ptr->check_key == NULL) ||
- (init_ptr->verify_signature == NULL) ||
- (stm32_hash_register() != 0)) {
- panic();
- }
-
- auth_ops = init_ptr;
-}
-
-int stm32mp_auth_image(boot_api_image_header_t *header, uintptr_t buffer)
-{
- int ret;
- 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);
-
- /* Check Security Status */
- if (!stm32mp_is_closed_device()) {
- if (header->option_flags != 0U) {
- WARN("Skip signature check (header option)\n");
- return 0;
- }
- INFO("Check signature on Open device\n");
- }
-
- ret = mmap_add_dynamic_region(STM32MP_ROM_BASE, STM32MP_ROM_BASE,
- STM32MP_ROM_SIZE, MT_CODE | MT_SECURE);
- if (ret != 0) {
- return ret;
- }
-
- /* Check Public Key */
- if (auth_ops->check_key(header->ecc_pubk, NULL) != BOOT_API_RETURN_OK) {
- ret = -EINVAL;
- goto err;
- }
-
- /* Compute end of header hash and payload hash */
- stm32_hash_init(HASH_SHA256);
-
- ret = stm32_hash_update((uint8_t *)&header->header_version,
- sizeof(boot_api_image_header_t) -
- header_skip_cksum);
- if (ret != 0) {
- ERROR("Hash of header failed, %i\n", ret);
- goto err;
- }
-
- ret = stm32_hash_final_update((uint8_t *)buffer,
- header->image_length, image_hash);
- if (ret != 0) {
- ERROR("Hash of payload failed\n");
- goto err;
- }
-
- /* Verify signature */
- if (auth_ops->verify_signature(image_hash, header->ecc_pubk,
- header->image_signature,
- header->ecc_algo_type) !=
- BOOT_API_RETURN_OK) {
- ret = -EINVAL;
- }
-
-err:
- mmap_remove_dynamic_region(STM32MP_ROM_BASE, STM32MP_ROM_SIZE);
- return ret;
-}
diff --git a/plat/st/common/stm32mp_common.c b/plat/st/common/stm32mp_common.c
index afa87f487..e838995cc 100644
--- a/plat/st/common/stm32mp_common.c
+++ b/plat/st/common/stm32mp_common.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2015-2020, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -12,8 +12,15 @@
#include <arch_helpers.h>
#include <common/debug.h>
#include <drivers/st/stm32mp_clkfunc.h>
+#include <drivers/st/stm32mp_pmic.h>
+#include <lib/spinlock.h>
+#include <lib/utils.h>
#include <plat/common/platform.h>
+#define HEADER_VERSION_MAJOR_MASK GENMASK(23, 16)
+
+static struct spinlock lock;
+
uintptr_t plat_get_ns_image_entrypoint(void)
{
return BL33_BASE;
@@ -24,6 +31,12 @@ unsigned int plat_get_syscnt_freq2(void)
return read_cntfrq_el0();
}
+#pragma weak stm32mp_plat_reset
+void __dead2 stm32mp_plat_reset(int cpu)
+{
+ panic();
+}
+
static uintptr_t boot_ctx_address;
void stm32mp_save_boot_ctx_address(uintptr_t address)
@@ -38,54 +51,22 @@ uintptr_t stm32mp_get_boot_ctx_address(void)
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;
+ 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;
+ 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;
+ 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;
+ return RCC_BASE;
}
bool stm32mp_lock_available(void)
@@ -96,6 +77,20 @@ bool stm32mp_lock_available(void)
return (read_sctlr() & c_m_bits) == c_m_bits;
}
+void stm32mp_pwr_regs_lock(void)
+{
+ if (stm32mp_lock_available()) {
+ spin_lock(&lock);
+ }
+}
+
+void stm32mp_pwr_regs_unlock(void)
+{
+ if (stm32mp_lock_available()) {
+ spin_unlock(&lock);
+ }
+}
+
uintptr_t stm32_get_gpio_bank_base(unsigned int bank)
{
if (bank == GPIO_BANK_Z) {
@@ -120,34 +115,89 @@ uint32_t stm32_get_gpio_bank_offset(unsigned int bank)
int stm32mp_check_header(boot_api_image_header_t *header, uintptr_t buffer)
{
- uint32_t i;
- uint32_t img_checksum = 0U;
-
/*
* Check header/payload validity:
* - Header magic
* - Header version
- * - Payload checksum
+ * - Payload checksum if no signature verification
*/
if (header->magic != BOOT_API_IMAGE_HEADER_MAGIC_NB) {
ERROR("Header magic\n");
return -EINVAL;
}
- if (header->header_version != BOOT_API_HEADER_VERSION) {
+ if ((header->header_version & HEADER_VERSION_MAJOR_MASK) !=
+ (BOOT_API_HEADER_VERSION & HEADER_VERSION_MAJOR_MASK)) {
ERROR("Header version\n");
return -EINVAL;
}
- for (i = 0U; i < header->image_length; i++) {
- img_checksum += *(uint8_t *)(buffer + i);
- }
+ if (header->option_flags == 1U) {
+ uint32_t i;
+ uint32_t img_checksum = 0U;
- if (header->payload_checksum != img_checksum) {
- ERROR("Checksum: 0x%x (awaited: 0x%x)\n", img_checksum,
- header->payload_checksum);
- return -EINVAL;
+ for (i = 0U; i < header->image_length; i++) {
+ img_checksum += *(uint8_t *)(buffer + i);
+ }
+
+ if (header->payload_checksum != img_checksum) {
+ ERROR("Checksum: 0x%x (awaited: 0x%x)\n", img_checksum,
+ header->payload_checksum);
+ return -EINVAL;
+ }
}
return 0;
}
+
+/* Return CPU supply name */
+const char *stm32mp_get_cpu_supply_name(void)
+{
+ const char *regulator;
+ const char *supply = NULL;
+
+ regulator = dt_get_cpu_regulator_name();
+ if (regulator == NULL) {
+ return NULL;
+ }
+
+ if (dt_pmic_status() > 0) {
+ if (dt_pmic_find_supply(&supply, regulator) != 0) {
+ return NULL;
+ }
+ }
+
+ return supply;
+}
+
+#if TRUSTED_BOARD_BOOT
+/* Save pointer to last loaded header */
+static boot_api_image_header_t *latest_stm32_header;
+
+/* Save last loaded header */
+void stm32mp_save_loaded_header(void *header)
+{
+ assert(latest_stm32_header == NULL);
+
+ latest_stm32_header = header;
+}
+
+/* Discard last loaded header */
+void stm32mp_delete_loaded_header(void)
+{
+ if (latest_stm32_header == NULL) {
+ return;
+ }
+
+ zeromem(latest_stm32_header, sizeof(boot_api_image_header_t));
+ latest_stm32_header = NULL;
+}
+
+/* Get last loaded header */
+boot_api_image_header_t *stm32mp_get_loaded_header(void)
+{
+ assert(latest_stm32_header != NULL);
+
+ return latest_stm32_header;
+}
+#endif /* TRUSTED_BOARD_BOOT */
diff --git a/plat/st/common/stm32mp_cot.c b/plat/st/common/stm32mp_cot.c
new file mode 100644
index 000000000..5f673fde7
--- /dev/null
+++ b/plat/st/common/stm32mp_cot.c
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2020, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <drivers/auth/auth_mod.h>
+#include <plat/common/platform.h>
+
+static auth_param_type_desc_t stm32_header_pk =
+ AUTH_PARAM_TYPE_DESC(AUTH_PARAM_PUB_KEY, 0);
+static auth_param_type_desc_t stm32_header_sig =
+ AUTH_PARAM_TYPE_DESC(AUTH_PARAM_SIG, 0);
+static auth_param_type_desc_t stm32_header_sig_alg =
+ AUTH_PARAM_TYPE_DESC(AUTH_PARAM_SIG_ALG, 0);
+static auth_param_type_desc_t stm32_load =
+ AUTH_PARAM_TYPE_DESC(AUTH_PARAM_RAW_DATA, 0);
+
+#if defined(AARCH32_SP_OPTEE)
+static const auth_img_desc_t bl32_image = {
+ .img_id = BL32_IMAGE_ID,
+ .img_type = IMG_PLAT,
+ .parent = NULL,
+ .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
+ [0] = {
+ .type = AUTH_METHOD_SIG,
+ .param.sig = {
+ .pk = &stm32_header_pk,
+ .sig = &stm32_header_sig,
+ .alg = &stm32_header_sig_alg,
+ .data = &stm32_load
+ }
+ },
+ },
+};
+
+static const auth_img_desc_t bl32_extra1_image = {
+ .img_id = BL32_EXTRA1_IMAGE_ID,
+ .img_type = IMG_PLAT,
+ .parent = NULL,
+ .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
+ [0] = {
+ .type = AUTH_METHOD_SIG,
+ .param.sig = {
+ .pk = &stm32_header_pk,
+ .sig = &stm32_header_sig,
+ .alg = &stm32_header_sig_alg,
+ .data = &stm32_load
+ }
+ },
+ },
+};
+
+static const auth_img_desc_t bl32_extra2_image = {
+ .img_id = BL32_EXTRA2_IMAGE_ID,
+ .img_type = IMG_PLAT,
+ .parent = NULL,
+ .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
+ [0] = {
+ .type = AUTH_METHOD_SIG,
+ .param.sig = {
+ .pk = &stm32_header_pk,
+ .sig = &stm32_header_sig,
+ .alg = &stm32_header_sig_alg,
+ .data = &stm32_load
+ }
+ },
+ },
+};
+#else
+static const auth_img_desc_t bl32_image = {
+ .img_id = BL32_IMAGE_ID,
+ .img_type = IMG_RAW,
+ .parent = NULL,
+ .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
+ [0] = {
+ .type = AUTH_METHOD_NONE, /* Already verified by BL1
+ * as loaded in the same time
+ * as BL2
+ */
+ }
+ },
+};
+#endif
+
+static const auth_img_desc_t bl33_image = {
+ .img_id = BL33_IMAGE_ID,
+ .img_type = IMG_PLAT,
+ .parent = NULL,
+ .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
+ [0] = {
+ .type = AUTH_METHOD_SIG,
+ .param.sig = {
+ .pk = &stm32_header_pk,
+ .sig = &stm32_header_sig,
+ .alg = &stm32_header_sig_alg,
+ .data = &stm32_load
+ }
+ },
+ },
+};
+
+static const auth_img_desc_t * const cot_desc[] = {
+ [BL32_IMAGE_ID] = &bl32_image,
+#if defined(AARCH32_SP_OPTEE)
+ [BL32_EXTRA1_IMAGE_ID] = &bl32_extra1_image,
+ [BL32_EXTRA2_IMAGE_ID] = &bl32_extra2_image,
+#endif
+ [BL33_IMAGE_ID] = &bl33_image,
+};
+
+REGISTER_COT(cot_desc);
diff --git a/plat/st/common/stm32mp_crypto_lib.c b/plat/st/common/stm32mp_crypto_lib.c
new file mode 100644
index 000000000..6e8c6355d
--- /dev/null
+++ b/plat/st/common/stm32mp_crypto_lib.c
@@ -0,0 +1,174 @@
+/*
+ * Copyright (c) 2020, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+
+#include <platform_def.h>
+
+#include <common/debug.h>
+#include <drivers/auth/crypto_mod.h>
+#include <drivers/io/io_storage.h>
+#include <drivers/st/bsec.h>
+#include <drivers/st/stm32_hash.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+#include <plat/common/platform.h>
+
+struct stm32mp_auth_ops {
+ uint32_t (*check_key)(uint8_t *pubkey_in, uint8_t *pubkey_out);
+ uint32_t (*verify_signature)(uint8_t *hash_in, uint8_t *pubkey_in,
+ uint8_t *signature, uint32_t ecc_algo);
+};
+
+static struct stm32mp_auth_ops auth_ops;
+
+static void crypto_lib_init(void)
+{
+ boot_api_context_t *boot_context =
+ (boot_api_context_t *)stm32mp_get_boot_ctx_address();
+
+ if (!stm32mp_is_auth_supported()) {
+ return;
+ }
+
+ auth_ops.check_key = boot_context->bootrom_ecdsa_check_key;
+ auth_ops.verify_signature =
+ boot_context->bootrom_ecdsa_verify_signature;
+
+ if (stm32_hash_register() != 0) {
+ panic();
+ }
+}
+
+static int crypto_verify_signature(void *data_ptr, unsigned int data_len,
+ void *sig_ptr, unsigned int sig_len,
+ void *sig_alg, unsigned int sig_alg_len,
+ void *pk_ptr, unsigned int pk_len)
+{
+ uint8_t image_hash[BOOT_API_SHA256_DIGEST_SIZE_IN_BYTES];
+ uint32_t option_flags;
+ uint32_t ecc_algo_type;
+ uint32_t header_len;
+ int result;
+ boot_api_image_header_t *header = stm32mp_get_loaded_header();
+
+ header_len = sizeof(boot_api_image_header_t) - sizeof(header->magic) -
+ sizeof(header->image_signature) -
+ sizeof(header->payload_checksum);
+
+ if ((((size_t)sig_alg % __alignof__(uint32_t)) != 0) ||
+ (sig_alg_len != sizeof(option_flags) + sizeof(ecc_algo_type))) {
+ return -EINVAL;
+ }
+
+ option_flags = ((uint32_t *)sig_alg)[0];
+ ecc_algo_type = ((uint32_t *)sig_alg)[1];
+
+ /* Check security status */
+ if (!stm32mp_is_closed_device()) {
+ if (option_flags != 0U) {
+ WARN("Skip signature check (header option)\n");
+ stm32mp_delete_loaded_header();
+ return 0;
+ }
+ INFO("Check signature on Open device\n");
+ }
+
+ /* Check key/sign size */
+ if ((pk_len != BOOT_API_ECDSA_PUB_KEY_LEN_IN_BYTES) ||
+ (sig_len != BOOT_API_ECDSA_SIGNATURE_LEN_IN_BYTES)) {
+ return -EINVAL;
+ }
+
+ result = mmap_add_dynamic_region(STM32MP_ROM_BASE, STM32MP_ROM_BASE,
+ STM32MP_ROM_SIZE, MT_CODE | MT_SECURE);
+ if (result != 0) {
+ return result;
+ }
+
+ if (!stm32mp_is_closed_device()) {
+ /*
+ * Check public key here in case of non-secure device
+ * It is done in the generic framework in case of close
+ * device.
+ */
+ if (auth_ops.check_key(pk_ptr, NULL) != BOOT_API_RETURN_OK) {
+ ERROR("ROTPK verification failed\n");
+ result = -EINVAL;
+ goto out;
+ } else {
+ NOTICE("ROTPK verification forced and checked OK\n");
+ }
+ }
+
+ /* Compute hash for the data covered by the signature */
+ stm32_hash_init(HASH_SHA256);
+
+ result = stm32_hash_update((void *)&header->header_version, header_len);
+ if (result != 0) {
+ VERBOSE("Hash of header failed, %i\n", result);
+ goto out;
+ }
+
+ result = stm32_hash_final_update((uint8_t *)data_ptr,
+ data_len, image_hash);
+ if (result != 0) {
+ VERBOSE("Hash of payload failed, %i\n", result);
+ goto out;
+ }
+
+ /* Verify signature */
+ if (auth_ops.verify_signature(image_hash, pk_ptr, sig_ptr,
+ ecc_algo_type) != BOOT_API_RETURN_OK) {
+ result = -EAUTH;
+ }
+
+out:
+ mmap_remove_dynamic_region(STM32MP_ROM_BASE, STM32MP_ROM_SIZE);
+ if (result != 0) {
+ stm32mp_delete_loaded_header();
+ }
+
+ return result;
+}
+
+static int crypto_verify_hash(void *data_ptr, unsigned int data_len,
+ void *digest_info_ptr,
+ unsigned int digest_info_len)
+{
+ int ret;
+ uint8_t calc_hash[BOOT_API_SHA256_DIGEST_SIZE_IN_BYTES];
+
+ if (digest_info_len != BOOT_API_SHA256_DIGEST_SIZE_IN_BYTES) {
+ VERBOSE("%s: unexpected digest_len\n", __func__);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ stm32_hash_init(HASH_SHA256);
+ ret = stm32_hash_final_update(data_ptr, data_len, calc_hash);
+ if (ret != 0) {
+ VERBOSE("%s: hash failed\n", __func__);
+ goto out;
+ }
+
+ ret = memcmp(calc_hash, digest_info_ptr, digest_info_len);
+ if (ret != 0) {
+ VERBOSE("%s: not expected digest\n", __func__);
+ ret = -EAUTH;
+ }
+
+out:
+ /* Clean header as no more used */
+ stm32mp_delete_loaded_header();
+
+ return ret;
+}
+
+REGISTER_CRYPTO_LIB("stm32_crypto_lib",
+ crypto_lib_init,
+ crypto_verify_signature,
+ crypto_verify_hash);
diff --git a/plat/st/common/stm32mp_dt.c b/plat/st/common/stm32mp_dt.c
index 17da4904a..f6de0b62a 100644
--- a/plat/st/common/stm32mp_dt.c
+++ b/plat/st/common/stm32mp_dt.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2017-2020, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -13,8 +13,6 @@
#include <common/debug.h>
#include <drivers/st/stm32_gpio.h>
-#include <drivers/st/stm32mp1_ddr.h>
-#include <drivers/st/stm32mp1_ram.h>
#include <stm32mp_dt.h>
@@ -92,6 +90,79 @@ uint8_t fdt_get_status(int node)
return status;
}
+#if ENABLE_ASSERTIONS
+/*******************************************************************************
+ * This function returns the address cells from the node parent.
+ * Returns:
+ * - #address-cells value if success.
+ * - invalid value if error.
+ * - a default value if undefined #address-cells property as per libfdt
+ * implementation.
+ ******************************************************************************/
+static int fdt_get_node_parent_address_cells(int node)
+{
+ int parent;
+
+ parent = fdt_parent_offset(fdt, node);
+ if (parent < 0) {
+ return -FDT_ERR_NOTFOUND;
+ }
+
+ return fdt_address_cells(fdt, parent);
+}
+
+/*******************************************************************************
+ * This function returns the size cells from the node parent.
+ * Returns:
+ * - #size-cells value if success.
+ * - invalid value if error.
+ * - a default value if undefined #size-cells property as per libfdt
+ * implementation.
+ ******************************************************************************/
+static int fdt_get_node_parent_size_cells(int node)
+{
+ int parent;
+
+ parent = fdt_parent_offset(fdt, node);
+ if (parent < 0) {
+ return -FDT_ERR_NOTFOUND;
+ }
+
+ return fdt_size_cells(fdt, parent);
+}
+#endif
+
+/*******************************************************************************
+ * 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;
+
+ default:
+ *array = fdt_getprop(fdt, node, "secure-interrupts", len);
+ break;
+ }
+
+ if (*array == NULL) {
+ return -FDT_ERR_NOTFOUND;
+ }
+
+ return 0;
+}
+
/*******************************************************************************
* This function reads a value of a node property (generic use of fdt
* library).
@@ -145,6 +216,46 @@ int fdt_read_uint32_array(int node, const char *prop_name, uint32_t *array,
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;
+
+ assert((fdt_get_node_parent_address_cells(node) == 1) &&
+ (fdt_get_node_parent_size_cells(node) == 1));
+
+ 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;
+ if (base != NULL) {
+ *base = fdt32_to_cpu(*cuint);
+ }
+ cuint++;
+ if (size != NULL) {
+ *size = fdt32_to_cpu(*cuint);
+ }
+
+ return 0;
+}
+
/*******************************************************************************
* This function gets the stdout path node.
* It reads the value indicated inside the device tree.
@@ -215,6 +326,8 @@ void dt_fill_device_info(struct dt_node_info *info, int node)
{
const fdt32_t *cuint;
+ assert(fdt_get_node_parent_address_cells(node) == 1);
+
cuint = fdt_getprop(fdt, node, "reg", NULL);
if (cuint != NULL) {
info->base = fdt32_to_cpu(*cuint);
@@ -277,6 +390,53 @@ int dt_get_stdout_uart_info(struct dt_node_info *info)
return node;
}
+/*******************************************************************************
+ * This function returns the node offset matching compatible string in the DT.
+ * It is only valid for single instance peripherals (DDR, RCC, PWR, STGEN,
+ * SYSCFG...).
+ * Returns value on success, and error value on failure.
+ ******************************************************************************/
+int dt_get_node_by_compatible(const char *compatible)
+{
+ int node = fdt_node_offset_by_compatible(fdt, -1, compatible);
+
+ if (node < 0) {
+ INFO("Cannot find %s node in DT\n", compatible);
+ }
+
+ return node;
+}
+
+/*******************************************************************************
+ * This function returns the node offset matching compatible string in the DT,
+ * and also matching the reg property with the given address.
+ * Returns value on success, and error value on failure.
+ ******************************************************************************/
+int dt_match_instance_by_compatible(const char *compatible, uintptr_t address)
+{
+ int node;
+
+ for (node = fdt_node_offset_by_compatible(fdt, -1, compatible);
+ node != -FDT_ERR_NOTFOUND;
+ node = fdt_node_offset_by_compatible(fdt, node, compatible)) {
+ const fdt32_t *cuint;
+
+ assert(fdt_get_node_parent_address_cells(node) == 1);
+
+ cuint = fdt_getprop(fdt, node, "reg", NULL);
+ if (cuint == NULL) {
+ continue;
+ }
+
+ if ((uintptr_t)fdt32_to_cpu(*cuint) == address) {
+ return node;
+ }
+ }
+
+ return -FDT_ERR_NOTFOUND;
+}
+
+
/*******************************************************************************
* This function gets DDR size information from the DT.
* Returns value in bytes on success, and 0 on failure.
@@ -285,9 +445,8 @@ uint32_t dt_get_ddr_size(void)
{
int node;
- node = fdt_node_offset_by_compatible(fdt, -1, DT_DDR_COMPAT);
+ node = dt_get_node_by_compatible(DT_DDR_COMPAT);
if (node < 0) {
- INFO("%s: Cannot read DDR node in DT\n", __func__);
return 0;
}
@@ -295,70 +454,168 @@ uint32_t dt_get_ddr_size(void)
}
/*******************************************************************************
- * This function gets DDRCTRL base address information from the DT.
- * Returns value on success, and 0 on failure.
+ * This function gets OPP table node from the DT.
+ * Returns node offset on success and a negative FDT error code on failure.
******************************************************************************/
-uintptr_t dt_get_ddrctrl_base(void)
+static int dt_get_opp_table_node(void)
{
- int node;
- uint32_t array[4];
+ return dt_get_node_by_compatible(DT_OPP_COMPAT);
+}
- 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;
+/*******************************************************************************
+ * This function gets OPP parameters (frequency in KHz and voltage in mV) from
+ * an OPP table subnode. Platform HW support capabilities are also checked.
+ * Returns 0 on success and a negative FDT error code on failure.
+ ******************************************************************************/
+static int dt_get_opp_freqvolt_from_subnode(int subnode, uint32_t *freq_khz,
+ uint32_t *voltage_mv)
+{
+ const fdt64_t *cuint64;
+ const fdt32_t *cuint32;
+ uint64_t read_freq_64;
+ uint32_t read_voltage_32;
+
+ assert(freq_khz != NULL);
+ assert(voltage_mv != NULL);
+
+ cuint32 = fdt_getprop(fdt, subnode, "opp-supported-hw", NULL);
+ if (cuint32 != NULL) {
+ if (!stm32mp_supports_cpu_opp(fdt32_to_cpu(*cuint32))) {
+ VERBOSE("Invalid opp-supported-hw 0x%x\n",
+ fdt32_to_cpu(*cuint32));
+ return -FDT_ERR_BADVALUE;
+ }
}
- if (fdt_read_uint32_array(node, "reg", array, 4) < 0) {
- return 0;
+ cuint64 = fdt_getprop(fdt, subnode, "opp-hz", NULL);
+ if (cuint64 == NULL) {
+ VERBOSE("Missing opp-hz\n");
+ return -FDT_ERR_NOTFOUND;
+ }
+
+ /* Frequency value expressed in KHz must fit on 32 bits */
+ read_freq_64 = fdt64_to_cpu(*cuint64) / 1000ULL;
+ if (read_freq_64 > (uint64_t)UINT32_MAX) {
+ VERBOSE("Invalid opp-hz %llu\n", read_freq_64);
+ return -FDT_ERR_BADVALUE;
+ }
+
+ cuint32 = fdt_getprop(fdt, subnode, "opp-microvolt", NULL);
+ if (cuint32 == NULL) {
+ VERBOSE("Missing opp-microvolt\n");
+ return -FDT_ERR_NOTFOUND;
+ }
+
+ /* Millivolt value must fit on 16 bits */
+ read_voltage_32 = fdt32_to_cpu(*cuint32) / 1000U;
+ if (read_voltage_32 > (uint32_t)UINT16_MAX) {
+ VERBOSE("Invalid opp-microvolt %u\n", read_voltage_32);
+ return -FDT_ERR_BADVALUE;
}
- return array[0];
+ *freq_khz = (uint32_t)read_freq_64;
+
+ *voltage_mv = read_voltage_32;
+
+ return 0;
}
/*******************************************************************************
- * This function gets DDRPHYC base address information from the DT.
- * Returns value on success, and 0 on failure.
+ * This function parses OPP table in DT and finds the parameters for the
+ * highest frequency supported by the HW platform.
+ * If found, the new frequency and voltage values override the original ones.
+ * Returns 0 on success and a negative FDT error code on failure.
******************************************************************************/
-uintptr_t dt_get_ddrphyc_base(void)
+int dt_get_max_opp_freqvolt(uint32_t *freq_khz, uint32_t *voltage_mv)
{
int node;
- uint32_t array[4];
+ int subnode;
+ uint32_t freq = 0U;
+ uint32_t voltage = 0U;
+
+ assert(freq_khz != NULL);
+ assert(voltage_mv != NULL);
- node = fdt_node_offset_by_compatible(fdt, -1, DT_DDR_COMPAT);
+ node = dt_get_opp_table_node();
if (node < 0) {
- INFO("%s: Cannot read DDR node in DT\n", __func__);
- return 0;
+ return node;
}
- if (fdt_read_uint32_array(node, "reg", array, 4) < 0) {
- return 0;
+ fdt_for_each_subnode(subnode, fdt, node) {
+ uint32_t read_freq;
+ uint32_t read_voltage;
+
+ if (dt_get_opp_freqvolt_from_subnode(subnode, &read_freq,
+ &read_voltage) != 0) {
+ continue;
+ }
+
+ if (read_freq > freq) {
+ freq = read_freq;
+ voltage = read_voltage;
+ }
+ }
+
+ if ((freq == 0U) || (voltage == 0U)) {
+ return -FDT_ERR_NOTFOUND;
}
- return array[2];
+ *freq_khz = freq;
+ *voltage_mv = voltage;
+
+ return 0;
}
/*******************************************************************************
- * This function gets PWR base address information from the DT.
- * Returns value on success, and 0 on failure.
+ * This function parses OPP table in DT and finds all parameters supported by
+ * the HW platform.
+ * If found, the corresponding frequency and voltage values are respectively
+ * stored in @*freq_khz_array and @*voltage_mv_array.
+ * Note that @*count has to be set by caller to the effective size allocated
+ * for both tables. Its value is then replaced by the number of filled elements.
+ * Returns 0 on success and a negative FDT error code on failure.
******************************************************************************/
-uintptr_t dt_get_pwr_base(void)
+int dt_get_all_opp_freqvolt(uint32_t *count, uint32_t *freq_khz_array,
+ uint32_t *voltage_mv_array)
{
int node;
- const fdt32_t *cuint;
+ int subnode;
+ int idx = 0;
+
+ assert(count != NULL);
+ assert(freq_khz_array != NULL);
+ assert(voltage_mv_array != NULL);
- node = fdt_node_offset_by_compatible(fdt, -1, DT_PWR_COMPAT);
+ node = dt_get_opp_table_node();
if (node < 0) {
- INFO("%s: Cannot read PWR node in DT\n", __func__);
- return 0;
+ return node;
}
- cuint = fdt_getprop(fdt, node, "reg", NULL);
- if (cuint == NULL) {
- return 0;
+ fdt_for_each_subnode(subnode, fdt, node) {
+ uint32_t read_freq;
+ uint32_t read_voltage;
+
+ if (dt_get_opp_freqvolt_from_subnode(subnode, &read_freq,
+ &read_voltage) != 0) {
+ continue;
+ }
+
+ if (idx >= *count) {
+ return -FDT_ERR_NOSPACE;
+ }
+
+ freq_khz_array[idx] = read_freq;
+ voltage_mv_array[idx] = read_voltage;
+ idx++;
}
- return fdt32_to_cpu(*cuint);
+ if (idx == 0U) {
+ return -FDT_ERR_NOTFOUND;
+ }
+
+ *count = idx;
+
+ return 0;
}
/*******************************************************************************
@@ -367,22 +624,15 @@ uintptr_t dt_get_pwr_base(void)
******************************************************************************/
uint32_t dt_get_pwr_vdd_voltage(void)
{
- int node, pwr_regulators_node;
+ int node;
const fdt32_t *cuint;
- node = fdt_node_offset_by_compatible(fdt, -1, DT_PWR_COMPAT);
+ node = dt_get_node_by_compatible(DT_PWR_COMPAT);
if (node < 0) {
- INFO("%s: Cannot read PWR node in DT\n", __func__);
return 0;
}
- pwr_regulators_node = fdt_subnode_offset(fdt, node, "pwr-regulators");
- if (node < 0) {
- INFO("%s: Cannot read pwr-regulators node in DT\n", __func__);
- return 0;
- }
-
- cuint = fdt_getprop(fdt, pwr_regulators_node, "vdd-supply", NULL);
+ cuint = fdt_getprop(fdt, node, "vdd-supply", NULL);
if (cuint == NULL) {
return 0;
}
@@ -401,26 +651,30 @@ uint32_t dt_get_pwr_vdd_voltage(void)
}
/*******************************************************************************
- * This function gets SYSCFG base address information from the DT.
- * Returns value on success, and 0 on failure.
+ * This function retrieves CPU regulator name from DT.
+ * Returns string taken from supply node, NULL otherwise.
******************************************************************************/
-uintptr_t dt_get_syscfg_base(void)
+const char *dt_get_cpu_regulator_name(void)
{
int node;
const fdt32_t *cuint;
- node = fdt_node_offset_by_compatible(fdt, -1, DT_SYSCFG_COMPAT);
+ node = fdt_path_offset(fdt, "/cpus/cpu@0");
if (node < 0) {
- INFO("%s: Cannot read SYSCFG node in DT\n", __func__);
- return 0;
+ return NULL;
}
- cuint = fdt_getprop(fdt, node, "reg", NULL);
+ cuint = fdt_getprop(fdt, node, "cpu-supply", NULL);
if (cuint == NULL) {
- return 0;
+ return NULL;
}
- return fdt32_to_cpu(*cuint);
+ node = fdt_node_offset_by_phandle(fdt, fdt32_to_cpu(*cuint));
+ if (node < 0) {
+ return NULL;
+ }
+
+ return (const char *)fdt_getprop(fdt, node, "regulator-name", NULL);
}
/*******************************************************************************
@@ -437,3 +691,67 @@ const char *dt_get_board_model(void)
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_img_parser_lib.c b/plat/st/common/stm32mp_img_parser_lib.c
new file mode 100644
index 000000000..f4c8bd642
--- /dev/null
+++ b/plat/st/common/stm32mp_img_parser_lib.c
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2020, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <errno.h>
+
+#include <platform_def.h>
+
+#include <common/debug.h>
+#include <drivers/auth/img_parser_mod.h>
+#include <plat/common/platform.h>
+
+static void img_lib_init(void)
+{
+}
+
+static int img_check_integrity(void *img, unsigned int img_len)
+{
+ return stm32mp_check_header(stm32mp_get_loaded_header(),
+ (uintptr_t)img);
+}
+
+static int img_get_auth_param(const auth_param_type_desc_t *type_desc,
+ void *img, unsigned int img_len, void **param,
+ unsigned int *param_len)
+{
+ boot_api_image_header_t *image_header = stm32mp_get_loaded_header();
+
+ switch (type_desc->type) {
+ case AUTH_PARAM_SIG:
+ *param_len = sizeof(image_header->image_signature);
+ *param = &image_header->image_signature;
+ break;
+ case AUTH_PARAM_SIG_ALG:
+ *param_len = sizeof(image_header->option_flags) +
+ sizeof(image_header->ecc_algo_type);
+ *param = &image_header->option_flags;
+ /*
+ * Store option_flags and ecc_alog_type in same param
+ * structure because they both have the same header fields.
+ */
+ break;
+ case AUTH_PARAM_PUB_KEY:
+ *param_len = sizeof(image_header->ecc_pubk);
+ *param = &image_header->ecc_pubk;
+ break;
+ case AUTH_PARAM_RAW_DATA:
+ if (type_desc->cookie == NULL) {
+ *param_len = image_header->image_length;
+ *param = img;
+ } else {
+ return -EINVAL;
+ }
+ break;
+ case AUTH_PARAM_NV_CTR:
+ if (type_desc->cookie == NULL) {
+ *param_len = sizeof(image_header->image_version);
+ *param = &image_header->image_version;
+ } else {
+ return -EINVAL;
+ }
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+REGISTER_IMG_PARSER_LIB(IMG_PLAT, "stm32_img_parser_lib",
+ img_lib_init,
+ img_check_integrity,
+ img_get_auth_param);
diff --git a/plat/st/common/stm32mp_shres_helpers.c b/plat/st/common/stm32mp_shres_helpers.c
new file mode 100644
index 000000000..12633e47d
--- /dev/null
+++ b/plat/st/common/stm32mp_shres_helpers.c
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2018-2019, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <lib/mmio.h>
+#include <lib/spinlock.h>
+
+#include <stm32mp_shres_helpers.h>
+
+static struct spinlock shregs_lock;
+
+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/common/stm32mp_trusted_boot.c b/plat/st/common/stm32mp_trusted_boot.c
new file mode 100644
index 000000000..f47584206
--- /dev/null
+++ b/plat/st/common/stm32mp_trusted_boot.c
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2020, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <endian.h>
+#include <errno.h>
+#include <limits.h>
+
+#include <platform_def.h>
+
+#include <common/debug.h>
+#include <plat/common/platform.h>
+
+static uint32_t root_pk_hash[BOOT_API_SHA256_DIGEST_SIZE_IN_BYTES /
+ sizeof(uint32_t)];
+
+int plat_get_rotpk_info(void *cookie, void **key_ptr, unsigned int *key_len,
+ unsigned int *flags)
+{
+ uint32_t otp_idx;
+ uint32_t otp_val;
+ uint32_t len;
+ size_t i;
+
+ if (cookie != NULL) {
+ return -EINVAL;
+ }
+
+ if (stm32_get_otp_index(PKH_OTP, &otp_idx, &len) != 0) {
+ VERBOSE("get_rot_pk_hash: get index error\n");
+ return -EINVAL;
+ }
+ if (len != (CHAR_BIT * BOOT_API_SHA256_DIGEST_SIZE_IN_BYTES)) {
+ VERBOSE("get_rot_pk_hash: length Error\n");
+ return -EINVAL;
+ }
+
+ for (i = 0U; i < ARRAY_SIZE(root_pk_hash); i++) {
+ if (stm32_get_otp_value_from_idx(otp_idx + i, &otp_val) != 0) {
+ return -EINVAL;
+ }
+
+ root_pk_hash[i] = bswap32(otp_val);
+ }
+
+ *key_ptr = &root_pk_hash;
+ *key_len = BOOT_API_SHA256_DIGEST_SIZE_IN_BYTES;
+ *flags = ROTPK_IS_HASH;
+
+ if (!stm32mp_is_closed_device()) {
+ *flags |= ROTPK_NOT_DEPLOYED;
+ }
+
+ return 0;
+}
+
+int plat_get_nv_ctr(void *cookie, unsigned int *nv_ctr)
+{
+ /*
+ * This monotonic counter is the counter used by ROM code
+ * to identify BL2.
+ */
+ if ((cookie == NULL) &&
+ (stm32_get_otp_value(MONOTONIC_OTP, nv_ctr) == 0)) {
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
+int plat_set_nv_ctr(void *cookie, unsigned int nv_ctr)
+{
+ return -EINVAL;
+}
diff --git a/plat/st/stm32mp1/bl2_plat_setup.c b/plat/st/stm32mp1/bl2_plat_setup.c
index d9e29b4e8..3f5eb5674 100644
--- a/plat/st/stm32mp1/bl2_plat_setup.c
+++ b/plat/st/stm32mp1/bl2_plat_setup.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2015-2020, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -18,21 +18,47 @@
#include <drivers/st/bsec.h>
#include <drivers/st/stm32_console.h>
#include <drivers/st/stm32_iwdg.h>
+#include <drivers/st/stm32mp_clkfunc.h>
#include <drivers/st/stm32mp_pmic.h>
#include <drivers/st/stm32mp_reset.h>
#include <drivers/st/stm32mp1_clk.h>
#include <drivers/st/stm32mp1_pwr.h>
#include <drivers/st/stm32mp1_ram.h>
+#if STM32MP_UART_PROGRAMMER
+#include <drivers/st/stm32mp1xx_hal_uart.h>
+#endif
+#include <drivers/st/stpmic1.h>
#include <lib/mmio.h>
#include <lib/optee_utils.h>
#include <lib/xlat_tables/xlat_tables_v2.h>
#include <plat/common/platform.h>
+#include <boot_api.h>
#include <stm32mp1_context.h>
#include <stm32mp1_dbgmcu.h>
+#define PWRLP_TEMPO_5_HSI 5
+
+#define TIMEOUT_US_1MS U(1000)
+
+static const char debug_msg[626] = {
+ "***************************************************\n"
+ "** NOTICE NOTICE NOTICE NOTICE NOTICE **\n"
+ "** **\n"
+ "** DEBUG ACCESS PORT IS OPEN! **\n"
+ "** This boot image is only for debugging purpose **\n"
+ "** and is unsafe for production use. **\n"
+ "** **\n"
+ "** If you see this message and you are not **\n"
+ "** debugging report this immediately to your **\n"
+ "** vendor! **\n"
+ "** **\n"
+ "***************************************************\n"
+};
+
static struct console_stm32 console;
-static struct stm32mp_auth_ops stm32mp1_auth_ops;
+static enum boot_device_e boot_device = BOOT_DEVICE_BOARD;
+static bool wakeup_standby;
static void print_reset_reason(void)
{
@@ -119,6 +145,11 @@ static void print_reset_reason(void)
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,
@@ -131,9 +162,14 @@ void bl2_platform_setup(void)
{
int ret;
- if (dt_pmic_status() > 0) {
- initialize_pmic();
- }
+ /*
+ * Map DDR non cacheable during its initialisation to avoid
+ * speculative loads before accesses are fully setup.
+ */
+ ret = mmap_add_dynamic_region(STM32MP_DDR_BASE, STM32MP_DDR_BASE,
+ STM32MP_DDR_MAX_SIZE,
+ MT_NON_CACHEABLE | MT_RW | MT_NS);
+ assert(ret == 0);
ret = stm32mp1_ddr_probe();
if (ret < 0) {
@@ -141,13 +177,151 @@ void bl2_platform_setup(void)
panic();
}
+ ret = mmap_remove_dynamic_region(STM32MP_DDR_BASE,
+ STM32MP_DDR_MAX_SIZE);
+ assert(ret == 0);
+
#ifdef AARCH32_SP_OPTEE
INFO("BL2 runs OP-TEE setup\n");
+
+ /* Map non secure DDR for BL33 load, now with cacheable attribute */
+ ret = mmap_add_dynamic_region(STM32MP_DDR_BASE, STM32MP_DDR_BASE,
+ dt_get_ddr_size() - STM32MP_DDR_S_SIZE -
+ STM32MP_DDR_SHMEM_SIZE,
+ MT_MEMORY | MT_RW | MT_NS);
+ assert(ret == 0);
+
+ ret = mmap_add_dynamic_region(STM32MP_DDR_BASE + dt_get_ddr_size() -
+ STM32MP_DDR_S_SIZE -
+ STM32MP_DDR_SHMEM_SIZE,
+ STM32MP_DDR_BASE + dt_get_ddr_size() -
+ STM32MP_DDR_S_SIZE -
+ STM32MP_DDR_SHMEM_SIZE,
+ STM32MP_DDR_S_SIZE,
+ MT_MEMORY | MT_RW | MT_SECURE);
+ assert(ret == 0);
+
/* Initialize tzc400 after DDR initialization */
stm32mp1_security_setup();
#else
INFO("BL2 runs SP_MIN setup\n");
+
+ /* Map non secure DDR for BL33 load, now with cacheable attribute */
+ ret = mmap_add_dynamic_region(STM32MP_DDR_BASE, STM32MP_DDR_BASE,
+ dt_get_ddr_size(),
+ MT_MEMORY | MT_RW | MT_NS);
+ assert(ret == 0);
#endif
+
+ if ((dt_pmic_status() > 0) && (!wakeup_standby)) {
+ configure_pmic();
+ }
+}
+
+static void update_monotonic_counter(void)
+{
+ uint32_t version;
+ uint32_t otp;
+
+ CASSERT(STM32_TF_VERSION <= MAX_MONOTONIC_VALUE,
+ assert_stm32mp1_monotonic_counter_reach_max);
+
+ /* Check if monotonic counter needs to be incremented */
+ if (stm32_get_otp_index(MONOTONIC_OTP, &otp, NULL) != 0) {
+ panic();
+ }
+
+ if (stm32_get_otp_value(MONOTONIC_OTP, &version) != 0) {
+ panic();
+ }
+
+ 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, 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);
+ }
+}
+
+static void initialize_clock(void)
+{
+ uint32_t voltage_mv = 0U;
+ uint32_t freq_khz = 0U;
+ int ret = 0;
+
+ if (wakeup_standby) {
+ ret = stm32_get_pll1_settings_from_context();
+ }
+
+ /*
+ * If no pre-defined PLL1 settings in DT, find the highest frequency
+ * in the OPP table (in DT, compatible with plaform capabilities, or
+ * in structure restored in RAM), and set related CPU supply voltage.
+ * If PLL1 settings found in DT, we consider CPU supply voltage in DT
+ * is consistent with it.
+ */
+ if ((ret == 0) && !fdt_is_pll1_predefined()) {
+ if (wakeup_standby) {
+ ret = stm32mp1_clk_get_maxfreq_opp(&freq_khz,
+ &voltage_mv);
+ } else {
+ ret = dt_get_max_opp_freqvolt(&freq_khz, &voltage_mv);
+ }
+
+ if (ret != 0) {
+ panic();
+ }
+
+ if (dt_pmic_status() > 0) {
+ int read_voltage;
+ const char *name;
+
+ name = stm32mp_get_cpu_supply_name();
+ if (name == NULL) {
+ panic();
+ }
+
+ read_voltage = stpmic1_regulator_voltage_get(name);
+ if (read_voltage < 0) {
+ panic();
+ }
+
+ if (voltage_mv != (uint32_t)read_voltage) {
+ if (stpmic1_regulator_voltage_set(name,
+ (uint16_t)voltage_mv) != 0) {
+ panic();
+ }
+ }
+ }
+ }
+
+ if (stm32mp1_clk_init(freq_khz) < 0) {
+ panic();
+ }
+}
+
+static void reset_uart(uint32_t reset)
+{
+ if (stm32mp_reset_assert_to(reset, TIMEOUT_US_1MS)) {
+ panic();
+ }
+
+ udelay(2);
+
+ if (stm32mp_reset_deassert_to(reset, TIMEOUT_US_1MS)) {
+ panic();
+ }
+
+ mdelay(1);
}
void bl2_el3_plat_arch_setup(void)
@@ -160,20 +334,16 @@ void bl2_el3_plat_arch_setup(void)
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);
#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_SHMEM_SIZE,
- STM32MP_DDR_BASE + dt_get_ddr_size() -
- STM32MP_DDR_S_SIZE - STM32MP_DDR_SHMEM_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);
@@ -181,19 +351,12 @@ void bl2_el3_plat_arch_setup(void)
/* Prevent corruption of preloaded BL32 */
mmap_add_region(BL32_BASE, BL32_BASE,
BL32_LIMIT - BL32_BASE,
- MT_MEMORY | MT_RO | MT_SECURE);
-
+ MT_RO_DATA | 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);
+ MT_RO_DATA | MT_SECURE);
configure_mmu();
@@ -204,6 +367,11 @@ void bl2_el3_plat_arch_setup(void)
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
@@ -215,6 +383,12 @@ void bl2_el3_plat_arch_setup(void)
;
}
+ /*
+ * 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();
}
@@ -231,25 +405,72 @@ void bl2_el3_plat_arch_setup(void)
mmio_clrbits_32(rcc_base + RCC_BDCR, RCC_BDCR_VSWRST);
}
+ /* 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);
+
+ /* Disable retention and backup RAM content after standby */
+ mmio_clrbits_32(pwr_base + PWR_CR2, PWR_CR2_BREN | PWR_CR2_RREN);
+
/* Disable MCKPROT */
mmio_clrbits_32(rcc_base + RCC_TZCR, RCC_TZCR_MCKPROT);
+ /* Enable BKP Register protection */
+ mmio_write_32(TAMP_SMCR,
+ TAMP_BKP_SEC_NUMBER << TAMP_BKP_SEC_WDPROT_SHIFT |
+ TAMP_BKP_SEC_NUMBER << TAMP_BKP_SEC_RWDPROT_SHIFT);
+
+ 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);
+ }
+
+ wakeup_standby = (mmio_read_32(bkpr_core1_addr) != 0U);
+
generic_delay_timer_init();
+#if STM32MP_USB_PROGRAMMER
+ 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();
}
- if (stm32mp1_clk_init() < 0) {
- panic();
+ if (dt_pmic_status() > 0) {
+ initialize_pmic();
}
- stm32mp1_syscfg_init();
+ initialize_clock();
result = dt_get_stdout_uart_info(&dt_uart_info);
if ((result <= 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;
@@ -259,12 +480,17 @@ void bl2_el3_plat_arch_setup(void)
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);
+ }
+
stm32mp_clk_enable((unsigned long)dt_uart_info.clock);
- stm32mp_reset_assert((uint32_t)dt_uart_info.reset);
- udelay(2);
- stm32mp_reset_deassert((uint32_t)dt_uart_info.reset);
- mdelay(1);
+ reset_uart((uint32_t)dt_uart_info.reset);
clk_rate = stm32mp_clk_get_rate((unsigned long)dt_uart_info.clock);
@@ -285,22 +511,40 @@ void bl2_el3_plat_arch_setup(void)
stm32mp_print_boardinfo();
+#if TRUSTED_BOARD_BOOT
if (boot_context->auth_status != BOOT_API_CTX_AUTH_NO) {
NOTICE("Bootrom authentication %s\n",
(boot_context->auth_status == BOOT_API_CTX_AUTH_FAILED) ?
"failed" : "succeeded");
}
+#endif
skip_console_init:
+#if !TRUSTED_BOARD_BOOT
+ if (stm32mp_is_closed_device()) {
+ /* Closed chip required authentication */
+ ERROR("Secured chip must enabled TRUSTED_BOARD_BOOT\n");
+ panic();
+ }
+#endif
+
+ stm32mp1_syscfg_init();
+
if (stm32_iwdg_init() < 0) {
panic();
}
stm32_iwdg_refresh();
- result = stm32mp1_dbgmcu_freeze_iwdg2();
- if (result != 0) {
- INFO("IWDG2 freeze error : %i\n", result);
+ if (bsec_read_debug_conf() != 0U) {
+ result = stm32mp1_dbgmcu_freeze_iwdg2();
+ if (result != 0) {
+ INFO("IWDG2 freeze error : %i\n", result);
+ }
+
+ if (stm32mp_is_closed_device()) {
+ NOTICE("\n%s", debug_msg);
+ }
}
if (stm32_save_boot_interface(boot_context->boot_interface_selected,
@@ -309,20 +553,47 @@ skip_console_init:
ERROR("Cannot save boot interface\n");
}
- stm32mp1_auth_ops.check_key = boot_context->bootrom_ecdsa_check_key;
- stm32mp1_auth_ops.verify_signature =
- boot_context->bootrom_ecdsa_verify_signature;
-
- stm32mp_init_auth(&stm32mp1_auth_ops);
-
stm32mp1_arch_security_setup();
print_reset_reason();
+ update_monotonic_counter();
+
+ if (dt_pmic_status() > 0) {
+ initialize_pmic();
+ print_pmic_info_and_debug();
+ }
+
stm32mp_io_setup();
}
#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 -
+ STM32MP_DDR_SHMEM_SIZE;
+ unpaged->image_max_size = STM32MP_DDR_S_SIZE;
+ }
+ paged->image_base = STM32MP_DDR_BASE + dt_get_ddr_size() -
+ STM32MP_DDR_S_SIZE - STM32MP_DDR_SHMEM_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`.
@@ -331,30 +602,34 @@ 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);
+#if TRUSTED_BOARD_BOOT
+ /* Clean header to avoid loaded header reused */
+ stm32mp_delete_loaded_header();
+#endif
+
switch (image_id) {
case BL32_IMAGE_ID:
+#if defined(AARCH32_SP_OPTEE)
bl_mem_params->ep_info.pc =
bl_mem_params->image_info.image_base;
pager_mem_params = get_bl_mem_params_node(BL32_EXTRA1_IMAGE_ID);
assert(pager_mem_params != NULL);
- pager_mem_params->image_info.image_base = STM32MP_OPTEE_BASE;
- pager_mem_params->image_info.image_max_size =
- STM32MP_OPTEE_SIZE;
paged_mem_params = get_bl_mem_params_node(BL32_EXTRA2_IMAGE_ID);
assert(paged_mem_params != NULL);
- paged_mem_params->image_info.image_base = STM32MP_DDR_BASE +
- (dt_get_ddr_size() - STM32MP_DDR_S_SIZE -
- STM32MP_DDR_SHMEM_SIZE);
- paged_mem_params->image_info.image_max_size =
- STM32MP_DDR_S_SIZE;
+
+ 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,
@@ -371,12 +646,18 @@ int bl2_plat_handle_post_image_load(unsigned int image_id)
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 != NULL);
bl32_mem_params->ep_info.lr_svc = bl_mem_params->ep_info.pc;
+#endif
+
+ flush_dcache_range(bl_mem_params->image_info.image_base,
+ bl_mem_params->image_info.image_max_size);
break;
default:
@@ -386,4 +667,3 @@ int bl2_plat_handle_post_image_load(unsigned int image_id)
return err;
}
-#endif
diff --git a/plat/st/stm32mp1/include/boot_api.h b/plat/st/stm32mp1/include/boot_api.h
index 2284970fa..872e2044c 100644
--- a/plat/st/stm32mp1/include/boot_api.h
+++ b/plat/st/stm32mp1/include/boot_api.h
@@ -10,6 +10,90 @@
#include <stdint.h>
#include <stdio.h>
+/*
+ * 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'
*/
@@ -33,6 +117,21 @@
/* Boot occurred on EMMC */
#define BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_EMMC 0x2U
+/* Boot occurred on 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 QSPI NAND */
+#define BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_NAND_QSPI 0x7U
+
/**
* @brief Possible value of boot context field 'EmmcXferStatus'
*/
@@ -56,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 */
@@ -86,6 +189,64 @@
#define BOOT_API_A7_CORE0_MAGIC_NUMBER 0xCA7FACE0U
#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
@@ -100,6 +261,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'
*/
@@ -124,7 +318,58 @@
/* Closed = OTP_CFG0[6] */
#define BOOT_API_OTP_MODE_CLOSED_BIT_POS 6
-#define BOOT_API_RETURN_OK 0x66U
+#define BOOT_API_RETURN_OK 0x77U
+
+/* 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
@@ -142,9 +387,29 @@ typedef struct {
*/
uint16_t boot_interface_selected;
uint16_t boot_interface_instance;
- uint32_t reserved1[13];
+ uint32_t reserved1[12];
+ uint32_t usb_context;
uint32_t otp_afmux_values[3];
- uint32_t reserved[5];
+ 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;
uint32_t auth_status;
/*
@@ -194,6 +459,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;
diff --git a/plat/st/stm32mp1/include/platform_def.h b/plat/st/stm32mp1/include/platform_def.h
index 263e6d6e1..694c3c4bb 100644
--- a/plat/st/stm32mp1/include/platform_def.h
+++ b/plat/st/stm32mp1/include/platform_def.h
@@ -51,6 +51,7 @@
#define MAX_IO_DEVICES U(4)
#define MAX_IO_HANDLES U(4)
#define MAX_IO_BLOCK_DEVICES U(1)
+#define MAX_IO_MTD_DEVICES U(1)
/*******************************************************************************
* BL2 specific defines.
@@ -82,6 +83,10 @@
*/
#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.
******************************************************************************/
@@ -112,6 +117,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)
@@ -121,7 +128,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 STM32MP_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)
diff --git a/plat/st/stm32mp1/include/stm32mp1_boot_device.h b/plat/st/stm32mp1/include/stm32mp1_boot_device.h
new file mode 100644
index 000000000..a74598395
--- /dev/null
+++ b/plat/st/stm32mp1/include/stm32mp1_boot_device.h
@@ -0,0 +1,18 @@
+/*
+ * Copyright (c) 2019, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef STM32MP1_BOOT_DEVICE_H
+#define STM32MP1_BOOT_DEVICE_H
+
+#include <drivers/raw_nand.h>
+#include <drivers/spi_nand.h>
+#include <drivers/spi_nor.h>
+
+int plat_get_raw_nand_data(struct rawnand_device *device);
+int plat_get_spi_nand_data(struct spinand_device *device);
+int plat_get_nor_data(struct nor_device *device);
+
+#endif /* STM32MP1_BOOT_DEVICE_H */
diff --git a/plat/st/stm32mp1/include/stm32mp1_context.h b/plat/st/stm32mp1/include/stm32mp1_context.h
index 698415af2..21214d35a 100644
--- a/plat/st/stm32mp1/include/stm32mp1_context.h
+++ b/plat/st/stm32mp1/include/stm32mp1_context.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -7,8 +7,26 @@
#ifndef STM32MP1_CONTEXT_H
#define STM32MP1_CONTEXT_H
+#include <stdbool.h>
#include <stdint.h>
+#define DDR_CRC_GRANULE 32
+
+void stm32_clean_context(void);
+int stm32_save_context(uint32_t zq0cr0_zdata);
+int stm32_restore_context(void);
+unsigned long long stm32_get_stgen_from_context(void);
+int stm32_restore_backup_reg(void);
+uint32_t stm32_get_zdata_from_context(void);
+int stm32_get_pll1_settings_from_context(void);
+bool stm32_are_pll1_settings_valid_in_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);
+
+void stm32mp1_pm_save_clock_cfg(size_t offset, uint8_t *data, size_t size);
+void stm32mp1_pm_restore_clock_cfg(size_t offset, uint8_t *data, size_t size);
#endif /* STM32MP1_CONTEXT_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 000000000..82b3d36c1
--- /dev/null
+++ b/plat/st/stm32mp1/include/stm32mp1_low_power.h
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2017-2019, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef STM32MP1_LOW_POWER_H
+#define STM32MP1_LOW_POWER_H
+
+#include <stdbool.h>
+#include <stdint.h>
+
+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 000000000..7bd07956a
--- /dev/null
+++ b/plat/st/stm32mp1/include/stm32mp1_power_config.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2017-2019, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef STM32MP1_POWER_CONFIG_H
+#define STM32MP1_POWER_CONFIG_H
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#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 e38fca012..e9fadb063 100644
--- a/plat/st/stm32mp1/include/stm32mp1_private.h
+++ b/plat/st/stm32mp1/include/stm32mp1_private.h
@@ -9,16 +9,31 @@
#include <stdint.h>
+#include <drivers/st/etzpc.h>
+
+enum boot_device_e {
+ BOOT_DEVICE_USB,
+ BOOT_DEVICE_BOARD
+};
+
void configure_mmu(void);
+void stm32mp_mask_timer(void);
+void __dead2 stm32mp_wait_cpu_reset(void);
+
void stm32mp1_arch_security_setup(void);
void stm32mp1_security_setup(void);
-void stm32mp1_gic_pcpu_init(void);
-void stm32mp1_gic_init(void);
+enum boot_device_e get_boot_device(void);
+
+enum etzpc_decprot_attributes stm32mp_etzpc_binding2decprot(uint32_t mode);
void stm32mp1_syscfg_init(void);
void stm32mp1_syscfg_enable_io_compensation(void);
void stm32mp1_syscfg_disable_io_compensation(void);
+void stm32mp1_init_scmi_server(void);
+void stm32mp1_pm_save_scmi_state(uint8_t *state, size_t size);
+void stm32mp1_pm_restore_scmi_state(uint8_t *state, size_t size);
+
#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 000000000..89c333358
--- /dev/null
+++ b/plat/st/stm32mp1/include/stm32mp1_shared_resources.h
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2017-2020, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef STM32MP1_SHARED_RESOURCES_H
+#define STM32MP1_SHARED_RESOURCES_H
+
+#include <stdbool.h>
+
+#include <common/debug.h>
+#include <drivers/st/etzpc.h>
+
+#define STM32MP1_SHRES_GPIOZ(i) (STM32MP1_SHRES_GPIOZ_0 + (i))
+
+enum stm32mp_shres {
+ STM32MP1_SHRES_CRYP1,
+ STM32MP1_SHRES_GPIOZ_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_HASH1,
+ STM32MP1_SHRES_I2C4,
+ STM32MP1_SHRES_I2C6,
+ STM32MP1_SHRES_IWDG1,
+ STM32MP1_SHRES_MCU,
+ STM32MP1_SHRES_MDMA,
+ STM32MP1_SHRES_RNG1,
+ STM32MP1_SHRES_RTC,
+ STM32MP1_SHRES_SPI6,
+ STM32MP1_SHRES_USART1,
+ STM32MP1_SHRES_PLL3,
+
+ STM32MP1_SHRES_COUNT
+};
+
+#ifdef IMAGE_BL32
+/* Register a peripheral as secure or non-secure based on identifier */
+void stm32mp_register_secure_periph(unsigned int id);
+void stm32mp_register_non_secure_periph(unsigned int id);
+
+/* Register a peripheral as secure or non-secure based on IO base address */
+void stm32mp_register_secure_periph_iomem(uintptr_t base);
+void stm32mp_register_non_secure_periph_iomem(uintptr_t base);
+
+/* Register a GPIO as secure or non-secure based on its bank and pin numbers */
+void stm32mp_register_secure_gpio(unsigned int bank, unsigned int pin);
+void stm32mp_register_non_secure_gpio(unsigned int bank, unsigned int pin);
+
+/*
+ * Register a (non-)secure peripheral based on the ETZPC DECPROT configuration
+ */
+void stm32mp1_register_etzpc_decprot(unsigned int id,
+ enum etzpc_decprot_attributes attr);
+
+/* Consolidate peripheral states and locknew periph registering */
+void stm32mp_lock_periph_registering(void);
+
+/* Get peripheral state in shared resource driver */
+bool stm32mp1_periph_is_non_secure(unsigned long id);
+bool stm32mp1_periph_is_secure(unsigned long id);
+
+bool stm32mp_gpio_bank_is_non_secure(unsigned int bank);
+bool stm32mp_gpio_bank_is_shared(unsigned int bank);
+
+bool stm32mp_nsec_can_access_clock(unsigned long clock_id);
+bool stm32mp_nsec_can_access_reset(unsigned int reset_id);
+#else /* IMAGE_BL32 */
+static inline void stm32mp_register_secure_periph(unsigned int id)
+{
+}
+
+static inline void stm32mp_register_non_secure_periph(unsigned int id)
+{
+}
+
+static inline void stm32mp_register_secure_periph_iomem(uintptr_t base)
+{
+}
+
+static inline void stm32mp_register_non_secure_periph_iomem(uintptr_t base)
+{
+}
+
+static inline void stm32mp_register_secure_gpio(unsigned int bank,
+ unsigned int pin)
+{
+}
+
+static inline void stm32mp_register_non_secure_gpio(unsigned int bank,
+ unsigned int pin)
+{
+}
+
+static inline void stm32mp1_register_etzpc_decprot(unsigned int id,
+ enum etzpc_decprot_attributes attr)
+{
+}
+
+static inline void stm32mp_lock_periph_registering(void)
+{
+ /* Platform is not expected to lock a non existing database */
+ panic();
+}
+
+static inline bool stm32mp1_periph_is_non_secure(unsigned long id)
+{
+ return false;
+}
+
+static inline bool stm32mp1_periph_is_secure(unsigned long id)
+{
+ return true;
+}
+
+static inline bool stm32mp_gpio_bank_is_non_secure(unsigned int bank)
+{
+ return false;
+}
+
+static inline bool stm32mp_gpio_bank_is_shared(unsigned int bank)
+{
+ return false;
+}
+#endif /* IMAGE_BL32 */
+
+#endif /* STM32MP1_SHARED_RESOURCES_H */
diff --git a/plat/st/stm32mp1/include/stm32mp1_smc.h b/plat/st/stm32mp1/include/stm32mp1_smc.h
index b87275839..19ae1d0a3 100644
--- a/plat/st/stm32mp1/include/stm32mp1_smc.h
+++ b/plat/st/stm32mp1/include/stm32mp1_smc.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016-2019, STMicroelectronics - All Rights Reserved
+ * Copyright (c) 2016-2020, STMicroelectronics - All Rights Reserved
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -7,45 +7,157 @@
#ifndef STM32MP1_SMC_H
#define STM32MP1_SMC_H
+/* SMC service generic return codes */
+#define STM32_SMC_OK 0x00000000U
+#define STM32_SMC_NOT_SUPPORTED 0xFFFFFFFFU
+#define STM32_SMC_FAILED 0xFFFFFFFEU
+#define STM32_SMC_INVALID_PARAMS 0xFFFFFFFDU
+
/*
- * SMC function IDs for STM32 Service queries
+ * 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)
+ * for SiP (silicon Partner).
* https://developer.arm.com/docs/den0028/latest
*/
/* Secure Service access from Non-secure */
/*
- * STM32_SMC_BSEC call API
+ * SMC function STM32_SMC_RCC.
+ *
+ * Argument a0: (input) SMCC ID.
+ * (output) Status return code.
+ * Argument a1: (input) Service ID (STM32_SMC_REG_xxx).
+ * Argument a2: (input) Register offset or physical address.
+ * (output) Register read value, if applicable.
+ * Argument a3: (input) Register target value if applicable.
+ */
+#define STM32_SMC_RCC 0x82001000
+
+/*
+ * SMC function STM32_SMC_PWR.
+ *
+ * Argument a0: (input) SMCC ID.
+ * (output) Status return code.
+ * Argument a1: (input) Service ID (STM32_SMC_REG_xxx).
+ * Argument a2: (input) Register offset or physical address.
+ * (output) Register read value, if applicable.
+ * Argument a3: (input) Register target value if applicable.
+ */
+#define STM32_SMC_PWR 0x82001001
+
+/*
+ * SMC functions STM32_SMC_RCC_CAL.
+ *
+ * Argument a0: (input) SMCC ID.
+ * (output) Status return code.
+ * Argument a1: (input) Clock ID (from DT clock bindings).
+ */
+#define STM32_SMC_RCC_CAL 0x82001002
+
+/*
+ * SMC functions STM32_SMC_BSEC.
*
- * Argument a0: (input) SMCC ID
- * (output) status return code
- * Argument a1: (input) Service ID (STM32_SMC_BSEC_xxx)
- * Argument a2: (input) OTP index
- * (output) OTP read value, if applicable
- * Argument a3: (input) OTP value if applicable
+ * Argument a0: (input) SMCC ID.
+ * (output) Status return code.
+ * Argument a1: (input) Service ID (STM32_SMC_READ_xxx/_PROG_xxx/_WRITE_xxx).
+ * (output) OTP read value, if applicable.
+ * Argument a2: (input) OTP index.
+ * Argument a3: (input) OTP value if applicable.
*/
#define STM32_SMC_BSEC 0x82001003
+/* Low Power services */
+
+/*
+ * SIP function STM32_SMC_PD_DOMAIN.
+ *
+ * Argument a0: (input) SMCC ID.
+ * (output) Status return code.
+ * Argument a2: (index) ID of target power domain to be enabled/disabled.
+ * Argument a3: (input) 0 to disable, 1 to enable target domain.
+ */
+#define STM32_SMC_PD_DOMAIN 0x82001008
+
+/*
+ * SIP function STM32_SMC_RCC_OPP.
+ *
+ * Argument a0: (input) SMCC ID.
+ * (output) Status return code.
+ * Argument a1: (input) Service ID (STM32_SMC_RCC_OPP_xxx).
+ * (output) Rounded frequency, if applicable.
+ * Argument a2: (input) Requested frequency.
+ */
+#define STM32_SMC_RCC_OPP 0x82001009
+
+/*
+ * SIP function STM32_SIP_SVC_FUNC_SCMI_AGENT0/1
+ *
+ * Process SCMI message pending in SCMI shared memory buffer
+ * related to SCMI agent IDs 0 and 1. No input or output arguments
+ * passed through CPU general purpose registers, messages are transfer
+ * through a dedicated area in SYSRAM, mapped as device memory.
+ */
+#define STM32_SMC_SCMI_MESSAGE_AGENT0 0x82002000
+#define STM32_SMC_SCMI_MESSAGE_AGENT1 0x82002001
+
/* SMC function IDs for SiP Service queries */
+
+/*
+ * SIP function STM32_SIP_SVC_CALL_COUNT.
+ *
+ * Argument a0: (input) SMCC ID.
+ * (output) Dummy value 0.
+ */
#define STM32_SIP_SVC_CALL_COUNT 0x8200ff00
+
+/*
+ * SIP function STM32_SIP_SVC_UID.
+ *
+ * Argument a0: (input) SMCC ID.
+ * (output) Lowest 32bit of the stm32mp1 SIP service UUID.
+ * Argument a1: (output) Next 32bit of the stm32mp1 SIP service UUID.
+ * Argument a2: (output) Next 32bit of the stm32mp1 SIP service UUID.
+ * Argument a3: (output) Last 32bit of the stm32mp1 SIP service UUID.
+ */
#define STM32_SIP_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
+/* 0x8200ff02 is reserved */
-/* Number of STM32 SiP Calls implemented */
-#define STM32_COMMON_SIP_NUM_CALLS 4
+/*
+ * SIP function STM32_SIP_SVC_VERSION.
+ *
+ * Argument a0: (input) SMCC ID.
+ * (output) STM32 SIP service major.
+ * Argument a1: (output) STM32 SIP service minor.
+ */
+#define STM32_SIP_SVC_VERSION 0x8200ff03
+
+/* Service ID for STM32_SMC_RCC/_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 */
+/* Service ID for STM32_SMC_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
+#define STM32_SMC_WRLOCK_OTP 0x07
+
+/* Service ID for STM32_SMC_RCC_OPP */
+#define STM32_SMC_RCC_OPP_SET 0x0
+#define STM32_SMC_RCC_OPP_ROUND 0x1
+
+/* 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 13
#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 000000000..cb514b20a
--- /dev/null
+++ b/plat/st/stm32mp1/include/stm32mp1_usb_desc.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2015-2019, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef STM32MP1_USB_DESC_H
+#define STM32MP1_USB_DESC_H
+
+#include <lib/usb/usb_core.h>
+
+/* 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 /* STM32MP1_USB_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 000000000..95ffa4da4
--- /dev/null
+++ b/plat/st/stm32mp1/include/usb_ctx.h
@@ -0,0 +1,17 @@
+/*
+ * Copyright (c) 2015-2019, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef USB_CTX_H
+#define USB_CTX_H
+
+#include <lib/usb/usb_core.h>
+
+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_image_load.c b/plat/st/stm32mp1/plat_image_load.c
index a52db6cac..0a7437ba4 100644
--- a/plat/st/stm32mp1/plat_image_load.c
+++ b/plat/st/stm32mp1/plat_image_load.c
@@ -1,10 +1,14 @@
/*
- * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2016-2020, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
+#include <platform_def.h>
+
+#include <common/bl_common.h>
#include <common/desc_image_load.h>
+#include <lib/mmio.h>
#include <plat/common/platform.h>
/*******************************************************************************
@@ -16,11 +20,73 @@ void plat_flush_next_bl_params(void)
flush_bl_params_desc();
}
+#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);
+ }
+
+ /* Max size is non-secure DDR end address minus image_base */
+ bl33->image_info.image_max_size = STM32MP_DDR_BASE +
+ dt_get_ddr_size() -
+ STM32MP_DDR_S_SIZE -
+ STM32MP_DDR_SHMEM_SIZE -
+ bl33->image_info.image_base;
+
return get_bl_load_info_from_mem_params_desc();
}
diff --git a/plat/st/stm32mp1/platform.mk b/plat/st/stm32mp1/platform.mk
index 90b3e3c1e..840a38d14 100644
--- a/plat/st/stm32mp1/platform.mk
+++ b/plat/st/stm32mp1/platform.mk
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved.
+# Copyright (c) 2015-2020, ARM Limited and Contributors. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
@@ -9,11 +9,31 @@ ARM_WITH_NEON := yes
BL2_AT_EL3 := 1
USE_COHERENT_MEM := 0
+# Add specific ST version
+ST_VERSION := r1.0
+VERSION_STRING := v${VERSION_MAJOR}.${VERSION_MINOR}-${ST_VERSION}(${BUILD_TYPE}):${BUILD_STRING}
+
+TRUSTED_BOARD_BOOT := 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 dynamic memory mapping
+PLAT_XLAT_TABLES_DYNAMIC := 1
+$(eval $(call assert_boolean,PLAT_XLAT_TABLES_DYNAMIC))
+$(eval $(call add_define,PLAT_XLAT_TABLES_DYNAMIC))
+
+# STM32 image header version v1.0
+STM32_HEADER_VERSION_MAJOR:= 1
+STM32_HEADER_VERSION_MINOR:= 0
# Not needed for Cortex-A7
WORKAROUND_CVE_2017_5715:= 0
+AARCH32_EXCEPTION_DEBUG := 1
+
# Number of TF-A copies in the device
STM32_TF_A_COPIES := 2
$(eval $(call add_define,STM32_TF_A_COPIES))
@@ -24,6 +44,39 @@ PLAT_PARTITION_MAX_ENTRIES := $(shell echo $$(($(STM32_TF_A_COPIES) + 1)))
endif
$(eval $(call add_define,PLAT_PARTITION_MAX_ENTRIES))
+# Boot devices
+STM32MP_EMMC ?= 0
+STM32MP_SDMMC ?= 0
+STM32MP_RAW_NAND ?= 0
+STM32MP_SPI_NAND ?= 0
+STM32MP_SPI_NOR ?= 0
+
+# Serial boot devices
+STM32MP_UART_PROGRAMMER ?= 0
+STM32MP_USB_PROGRAMMER ?= 0
+
+ifeq ($(filter 1,${STM32MP_EMMC} ${STM32MP_SDMMC} ${STM32MP_RAW_NAND} \
+ ${STM32MP_SPI_NAND} ${STM32MP_SPI_NOR} ${STM32MP_UART_PROGRAMMER} \
+ ${STM32MP_USB_PROGRAMMER}),)
+$(error "No boot device driver is enabled")
+endif
+
+$(eval $(call assert_boolean,STM32MP_EMMC))
+$(eval $(call assert_boolean,STM32MP_SDMMC))
+$(eval $(call assert_boolean,STM32MP_RAW_NAND))
+$(eval $(call assert_boolean,STM32MP_SPI_NAND))
+$(eval $(call assert_boolean,STM32MP_SPI_NOR))
+$(eval $(call add_define,STM32MP_EMMC))
+$(eval $(call add_define,STM32MP_SDMMC))
+$(eval $(call add_define,STM32MP_RAW_NAND))
+$(eval $(call add_define,STM32MP_SPI_NAND))
+$(eval $(call add_define,STM32MP_SPI_NOR))
+
+$(eval $(call assert_boolean,STM32MP_UART_PROGRAMMER))
+$(eval $(call assert_boolean,STM32MP_USB_PROGRAMMER))
+$(eval $(call add_define,STM32MP_UART_PROGRAMMER))
+$(eval $(call add_define,STM32MP_USB_PROGRAMMER))
+
PLAT_INCLUDES := -Iplat/st/common/include/
PLAT_INCLUDES += -Iplat/st/stm32mp1/include/
@@ -51,7 +104,7 @@ PLAT_BL_COMMON_SOURCES += lib/cpus/aarch32/cortex_a7.S
PLAT_BL_COMMON_SOURCES += 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/bsec/bsec2.c \
drivers/st/clk/stm32mp_clkfunc.c \
drivers/st/clk/stm32mp1_clk.c \
drivers/st/ddr/stm32mp1_ddr_helpers.c \
@@ -60,8 +113,11 @@ PLAT_BL_COMMON_SOURCES += drivers/arm/tzc/tzc400.c \
drivers/st/iwdg/stm32_iwdg.c \
drivers/st/pmic/stm32mp_pmic.c \
drivers/st/pmic/stpmic1.c \
+ drivers/st/regulator/stm32mp_dummy_regulator.c \
+ drivers/st/regulator/stm32mp_regulator.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_dbgmcu.c \
plat/st/stm32mp1/stm32mp1_helper.S \
@@ -70,18 +126,64 @@ PLAT_BL_COMMON_SOURCES += drivers/arm/tzc/tzc400.c \
BL2_SOURCES += drivers/io/io_block.c \
drivers/io/io_dummy.c \
+ drivers/io/io_mtd.c \
drivers/io/io_storage.c \
drivers/st/crypto/stm32_hash.c \
drivers/st/io/io_stm32image.c \
- plat/st/common/stm32mp_auth.c \
plat/st/common/bl2_io_storage.c \
plat/st/stm32mp1/bl2_plat_setup.c
+ifeq (${TRUSTED_BOARD_BOOT},1)
+AUTH_SOURCES := drivers/auth/auth_mod.c \
+ drivers/auth/crypto_mod.c \
+ drivers/auth/img_parser_mod.c
+
+BL2_SOURCES += $(AUTH_SOURCES) \
+ plat/st/common/stm32mp_cot.c \
+ plat/st/common/stm32mp_crypto_lib.c \
+ plat/st/common/stm32mp_img_parser_lib.c \
+ plat/st/common/stm32mp_trusted_boot.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_RAW_NAND},1)
+$(eval $(call add_define_val,NAND_ONFI_DETECT,1))
+BL2_SOURCES += drivers/mtd/nand/raw_nand.c \
+ drivers/st/fmc/stm32_fmc2_nand.c
+endif
+
+ifeq (${STM32MP_SPI_NAND},1)
+BL2_SOURCES += drivers/mtd/nand/spi_nand.c
+endif
+
+ifeq (${STM32MP_SPI_NOR},1)
+BL2_SOURCES += drivers/mtd/nor/spi_nor.c
+endif
+
+ifneq ($(filter 1,${STM32MP_SPI_NAND} ${STM32MP_SPI_NOR}),)
+BL2_SOURCES += drivers/mtd/spi-mem/spi_mem.c \
+ drivers/st/spi/stm32_qspi.c
+endif
+
+ifneq ($(filter 1,${STM32MP_RAW_NAND} ${STM32MP_SPI_NAND}),)
+BL2_SOURCES += drivers/mtd/nand/core.c
+endif
+
+ifneq ($(filter 1,${STM32MP_RAW_NAND} ${STM32MP_SPI_NAND} ${STM32MP_SPI_NOR}),)
+BL2_SOURCES += plat/st/stm32mp1/stm32mp1_boot_device.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
@@ -90,10 +192,22 @@ BL2_SOURCES += common/desc_image_load.c \
plat/st/stm32mp1/plat_bl2_mem_params_desc.c \
plat/st/stm32mp1/plat_image_load.c
+ifeq (${STM32MP_USB_PROGRAMMER},1)
+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
+endif
+
ifeq ($(AARCH32_SP),optee)
BL2_SOURCES += lib/optee/optee_utils.c
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 := $(DTB_FILE_NAME:.dtb=)
@@ -105,16 +219,15 @@ STM32_TF_ELF := $(STM32_TF_STM32:.stm32=.elf)
STM32_TF_DTBFILE := ${BUILD_PLAT}/fdts/${DTB_FILE_NAME}
STM32_TF_OBJS := ${BUILD_PLAT}/stm32mp1.o
-BL2_CFLAGS += -DPLAT_XLAT_TABLES_DYNAMIC=1
-
# Variables for use with stm32image
STM32IMAGEPATH ?= tools/stm32image
STM32IMAGE ?= ${STM32IMAGEPATH}/stm32image${BIN_EXT}
+STM32IMAGE_SRC := ${STM32IMAGEPATH}/stm32image.c
-.PHONY: ${STM32_TF_STM32}
+.PHONY: check_dtc_version stm32image clean_stm32image
.SUFFIXES:
-all: check_dtc_version ${STM32_TF_STM32} stm32image
+all: check_dtc_version stm32image ${STM32_TF_STM32}
ifeq ($(AARCH32_SP),sp_min)
# BL32 is built only if using SP_MIN
@@ -124,7 +237,9 @@ endif
distclean realclean clean: clean_stm32image
-stm32image:
+stm32image: ${STM32IMAGE}
+
+${STM32IMAGE}: ${STM32IMAGE_SRC}
${Q}${MAKE} CPPFLAGS="" --no-print-directory -C ${STM32IMAGEPATH}
clean_stm32image:
@@ -161,10 +276,14 @@ ${STM32_TF_BINARY}: ${STM32_TF_ELF}
@echo "Built $@ successfully"
@echo
-${STM32_TF_STM32}: stm32image ${STM32_TF_BINARY}
+${STM32_TF_STM32}: ${STM32IMAGE} ${STM32_TF_BINARY}
@echo
- @echo "Generated $@"
+ @echo "Generate $@"
$(eval LOADADDR = $(shell cat ${STM32_TF_MAPFILE} | grep RAM | awk '{print $$2}'))
$(eval ENTRY = $(shell cat ${STM32_TF_MAPFILE} | grep "__BL2_IMAGE_START" | awk '{print $$1}'))
- ${STM32IMAGE} -s ${STM32_TF_BINARY} -d $@ -l $(LOADADDR) -e ${ENTRY} -v ${STM32_TF_VERSION}
+ @${STM32IMAGE} -s ${STM32_TF_BINARY} -d $@ \
+ -l $(LOADADDR) -e ${ENTRY} \
+ -v ${STM32_TF_VERSION} \
+ -m ${STM32_HEADER_VERSION_MAJOR} \
+ -n ${STM32_HEADER_VERSION_MINOR}
@echo
diff --git a/plat/st/stm32mp1/services/bsec_svc.c b/plat/st/stm32mp1/services/bsec_svc.c
index 2a60e4339..e75571f98 100644
--- a/plat/st/stm32mp1/services/bsec_svc.c
+++ b/plat/st/stm32mp1/services/bsec_svc.c
@@ -1,23 +1,451 @@
/*
- * Copyright (c) 2016-2019, STMicroelectronics - All Rights Reserved
+ * Copyright (c) 2016-2020, STMicroelectronics - All Rights Reserved
*
* SPDX-License-Identifier: BSD-3-Clause
*/
+#include <assert.h>
+
#include <platform_def.h>
+#include <arch.h>
+#include <arch_helpers.h>
#include <common/debug.h>
+#include <common/runtime_svc.h>
#include <drivers/st/bsec.h>
+#include <drivers/st/bsec2_reg.h>
+#include <drivers/st/stm32mp_pmic.h>
+#include <drivers/st/stm32mp1_ddr_helpers.h>
+#include <drivers/st/stpmic1.h>
+#include <lib/mmio.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+#include <services/std_svc.h>
+#include <boot_api.h>
+#include <stm32mp1_dbgmcu.h>
#include <stm32mp1_smc.h>
#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) {
+ const char *name;
+
+ initialize_pmic();
+
+ name = stm32mp_get_cpu_supply_name();
+ if (name == NULL) {
+ return BSEC_SSP_ERROR;
+ }
+
+ stpmic1_regulator_mask_reset_set(name);
+ }
+
+ return BSEC_SSP_SET;
+ }
+ return BSEC_NO_SSP;
+}
+
+#if STM32MP_USB_PROGRAMMER || STM32MP_UART_PROGRAMMER
+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_set_sp_lock((32U * j) + i) !=
+ BSEC_OK) {
+ 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_set_sw_lock((32U * j) + i) !=
+ BSEC_OK) {
+ 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_set_sr_lock((32U * j) + i) !=
+ BSEC_OK) {
+ 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;
+
+ 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;
+}
+#endif /* STM32MP_USB_PROGRAMMER || STM32MP_UART_PROGRAMMER */
+
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 __unused;
+ uintptr_t map_begin __unused;
+ size_t map_size __unused = PAGE_SIZE;
+ int ret __unused;
+
+ if ((x1 != STM32_SMC_READ_ALL) && (x1 != STM32_SMC_WRITE_ALL) &&
+ (bsec_check_nsec_access_rights(x2) != BSEC_OK)) {
+ return STM32_SMC_INVALID_PARAMS;
+ }
+
+#if STM32MP_USB_PROGRAMMER || STM32MP_UART_PROGRAMMER
+ otp_exch = NULL;
+ map_begin = 0U;
+
+ if ((x1 == STM32_SMC_READ_ALL) || (x1 == STM32_SMC_WRITE_ALL)) {
+ map_begin = round_down(x2, PAGE_SIZE);
+
+ if (round_down(x2 + sizeof(struct otp_exchange), PAGE_SIZE) !=
+ map_begin) {
+ /*
+ * Buffer end is in the next page, 2 pages need to be
+ * mapped.
+ */
+ map_size += PAGE_SIZE;
+ }
+
+ ret = mmap_add_dynamic_region(map_begin,
+ map_begin,
+ map_size,
+ MT_MEMORY | MT_RW | MT_NS);
+ assert(ret == 0);
+
+ if (!ddr_is_nonsecured_area(map_begin, map_size)) {
+ ret = mmap_remove_dynamic_region(map_begin, map_size);
+ assert(ret == 0);
+
+ return STM32_SMC_INVALID_PARAMS;
+ }
+
+ otp_exch = (struct otp_exchange *)(uintptr_t)x2;
+ }
+#endif
switch (x1) {
case STM32_SMC_READ_SHADOW:
@@ -25,6 +453,18 @@ uint32_t bsec_main(uint32_t x1, uint32_t x2, uint32_t x3,
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, x3);
+ 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:
@@ -50,11 +490,27 @@ uint32_t bsec_main(uint32_t x1, uint32_t x2, uint32_t x3,
result = bsec_write_otp(tmp_data, x2);
break;
-
- default:
- result = BSEC_ERROR;
+#if STM32MP_USB_PROGRAMMER || STM32MP_UART_PROGRAMMER
+ 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;
+#endif
+ case STM32_SMC_WRLOCK_OTP:
+ result = bsec_permanent_lock_otp(x2);
+ break;
+ default:
+ return STM32_SMC_INVALID_PARAMS;
+ }
+
+#if STM32MP_USB_PROGRAMMER || STM32MP_UART_PROGRAMMER
+ if ((x1 == STM32_SMC_READ_ALL) || (x1 == STM32_SMC_WRITE_ALL)) {
+ ret = mmap_remove_dynamic_region(map_begin, map_size);
+ assert(ret == 0);
}
+#endif
- return result;
+ return (result == BSEC_OK) ? STM32_SMC_OK : STM32_SMC_FAILED;
}
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 000000000..567a3c70f
--- /dev/null
+++ b/plat/st/stm32mp1/services/low_power_svc.c
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2017-2020, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <smccc_helpers.h>
+
+#include <stm32mp1_power_config.h>
+#include <stm32mp1_smc.h>
+
+#include "low_power_svc.h"
+
+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 000000000..eb98e9225
--- /dev/null
+++ b/plat/st/stm32mp1/services/low_power_svc.h
@@ -0,0 +1,14 @@
+/*
+ * Copyright (c) 2017-2020, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef LOW_POWER_SVC_H
+#define LOW_POWER_SVC_H
+
+#include <stdint.h>
+
+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 000000000..1213d7ef6
--- /dev/null
+++ b/plat/st/stm32mp1/services/pwr_svc.c
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2017-2019, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <common/debug.h>
+#include <drivers/st/stm32mp1_pwr.h>
+#include <lib/mmio.h>
+
+#include <stm32mp_common.h>
+#include <stm32mp1_smc.h>
+
+#include "pwr_svc.h"
+
+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;
+
+ stm32mp_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;
+ }
+
+ stm32mp_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 000000000..6dacdf80d
--- /dev/null
+++ b/plat/st/stm32mp1/services/pwr_svc.h
@@ -0,0 +1,12 @@
+/*
+ * Copyright (c) 2017-2019, STMicroelectronics - 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 000000000..640816fca
--- /dev/null
+++ b/plat/st/stm32mp1/services/rcc_svc.c
@@ -0,0 +1,172 @@
+/*
+ * Copyright (c) 2017-2019, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <limits.h>
+
+#include <platform_def.h>
+
+#include <common/debug.h>
+#include <drivers/st/stm32_gpio.h>
+#include <drivers/st/stm32mp1_clk.h>
+#include <drivers/st/stm32mp1_rcc.h>
+#include <lib/mmio.h>
+
+#include <stm32mp_common.h>
+#include <stm32mp_shres_helpers.h>
+#include <stm32mp1_shared_resources.h>
+#include <stm32mp1_smc.h>
+
+#include "rcc_svc.h"
+
+static bool offset_is_clear_register(uint32_t __unused offset)
+{
+ /* All currently allowed registers are non set/clear registers */
+ return false;
+}
+
+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:
+ if (offset_is_clear_register(offset)) {
+ mmio_write_32(addr, masked_value);
+ } else {
+ stm32mp_mmio_clrsetbits_32_shregs(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:
+ if (offset_is_clear_register(offset)) {
+ mmio_write_32(addr, masked_value);
+ } else {
+ stm32mp_mmio_setbits_32_shregs(addr, masked_value);
+ }
+ VERBOSE("set 0x%x = 0x%x => 0x%x\n", offset, value,
+ mmio_read_32(addr));
+ break;
+
+ case STM32_SMC_REG_CLEAR:
+ if (offset_is_clear_register(offset)) {
+ /* Nothing to do on CLR registers */
+ } else {
+ stm32mp_mmio_clrbits_32_shregs(addr, masked_value);
+ }
+ 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;
+
+ switch (offset) {
+ case RCC_MP_CIER:
+ case RCC_MP_CIFR:
+ allowed_mask = RCC_MP_CIFR_WKUPF;
+ break;
+ case RCC_MP_GCR:
+ allowed_mask = RCC_MP_GCR_BOOT_MCU;
+ break;
+ default:
+ panic();
+ }
+
+ 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;
+ }
+
+ 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_calib_start_csi_cal() == 0) {
+ ret = STM32_SMC_OK;
+ }
+ break;
+
+ case CK_HSI:
+ if (stm32mp1_calib_start_hsi_cal() == 0) {
+ ret = STM32_SMC_OK;
+ }
+ break;
+
+ default:
+ ret = STM32_SMC_INVALID_PARAMS;
+ break;
+ }
+
+ return ret;
+}
+
+uint32_t rcc_opp_scv_handler(uint32_t x1, uint32_t x2, uint32_t *res)
+{
+ uint32_t cmd = x1;
+ uint32_t opp = x2 / 1000U; /* KHz */
+
+ switch (cmd) {
+ case STM32_SMC_RCC_OPP_SET:
+ if (stm32mp1_set_opp_khz(opp) != 0) {
+ return STM32_SMC_FAILED;
+ }
+ break;
+
+ case STM32_SMC_RCC_OPP_ROUND:
+ if (stm32mp1_round_opp_khz(&opp) != 0) {
+ return STM32_SMC_FAILED;
+ }
+
+ if (opp > (UINT32_MAX / 1000U)) {
+ return STM32_SMC_FAILED;
+ }
+
+ *res = opp * 1000U;
+ break;
+
+ default:
+ return STM32_SMC_INVALID_PARAMS;
+ }
+
+ return STM32_SMC_OK;
+}
diff --git a/plat/st/stm32mp1/services/rcc_svc.h b/plat/st/stm32mp1/services/rcc_svc.h
new file mode 100644
index 000000000..23c75824f
--- /dev/null
+++ b/plat/st/stm32mp1/services/rcc_svc.h
@@ -0,0 +1,14 @@
+/*
+ * Copyright (c) 2017-2019, STMicroelectronics - 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);
+uint32_t rcc_opp_scv_handler(uint32_t x1, uint32_t x2, uint32_t *res);
+
+#endif /* RCC_SVC_H */
diff --git a/plat/st/stm32mp1/services/stm32mp1_svc_setup.c b/plat/st/stm32mp1/services/stm32mp1_svc_setup.c
index 72af9ff33..b2a84c15e 100644
--- a/plat/st/stm32mp1/services/stm32mp1_svc_setup.c
+++ b/plat/st/stm32mp1/services/stm32mp1_svc_setup.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014-2019, STMicroelectronics - All Rights Reserved
+ * Copyright (c) 2014-2020, STMicroelectronics - All Rights Reserved
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -9,12 +9,16 @@
#include <common/debug.h>
#include <common/runtime_svc.h>
+#include <drivers/st/scmi-msg.h>
#include <lib/psci/psci.h>
#include <tools_share/uuid.h>
#include <stm32mp1_smc.h>
#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,
@@ -65,9 +69,39 @@ static uintptr_t stm32mp1_svc_smc_handler(uint32_t smc_fid, u_register_t x1,
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_RCC_OPP:
+ ret1 = rcc_opp_scv_handler(x1, x2, &ret2);
+ ret2_enabled = true;
+ break;
+
+ case STM32_SMC_PWR:
+ ret1 = pwr_scv_handler(x1, x2, x3);
+ break;
+
+ case STM32_SMC_PD_DOMAIN:
+ ret1 = pm_domain_scv_handler(x1, x2);
+ break;
+
+ case STM32_SMC_SCMI_MESSAGE_AGENT0:
+ scmi_smt_fastcall_smc_entry(0U);
+ ret1 = STM32_SMC_OK;
+ break;
+ case STM32_SMC_SCMI_MESSAGE_AGENT1:
+ scmi_smt_fastcall_smc_entry(1U);
+ ret1 = STM32_SMC_OK;
+ break;
+
default:
WARN("Unimplemented STM32MP1 Service Call: 0x%x\n", smc_fid);
- ret1 = SMC_UNK;
+ ret1 = STM32_SMC_NOT_SUPPORTED;
break;
}
diff --git a/plat/st/stm32mp1/sp_min/sp_min-stm32mp1.mk b/plat/st/stm32mp1/sp_min/sp_min-stm32mp1.mk
index 4188cc58a..2ab8e8d4b 100644
--- a/plat/st/stm32mp1/sp_min/sp_min-stm32mp1.mk
+++ b/plat/st/stm32mp1/sp_min/sp_min-stm32mp1.mk
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
+# Copyright (c) 2017-2020, ARM Limited and Contributors. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
@@ -7,19 +7,39 @@
SP_MIN_WITH_SECURE_FIQ := 1
BL32_SOURCES += plat/common/aarch32/platform_mp_stack.S \
+ drivers/st/clk/stm32mp1_calib.c \
+ 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_shared_resources.c \
plat/st/stm32mp1/stm32mp1_topology.c
# Generic GIC v2
BL32_SOURCES += drivers/arm/gic/common/gic_common.c \
drivers/arm/gic/v2/gicv2_helpers.c \
drivers/arm/gic/v2/gicv2_main.c \
plat/common/plat_gicv2.c \
- plat/st/stm32mp1/stm32mp1_gic.c
+ plat/st/common/stm32_gic.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
+
+# SCMI server
+BL32_SOURCES += drivers/st/scmi-msg/base.c \
+ drivers/st/scmi-msg/clock.c \
+ drivers/st/scmi-msg/entry.c \
+ drivers/st/scmi-msg/reset_domain.c \
+ drivers/st/scmi-msg/smt.c \
+ plat/st/stm32mp1/stm32mp1_scmi.c
diff --git a/plat/st/stm32mp1/sp_min/sp_min_setup.c b/plat/st/stm32mp1/sp_min/sp_min_setup.c
index e10dfbfc0..f57630604 100644
--- a/plat/st/stm32mp1/sp_min/sp_min_setup.c
+++ b/plat/st/stm32mp1/sp_min/sp_min_setup.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2015-2020, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -17,10 +17,19 @@
#include <drivers/arm/tzc400.h>
#include <drivers/generic_delay_timer.h>
#include <drivers/st/bsec.h>
+#include <drivers/st/etzpc.h>
#include <drivers/st/stm32_console.h>
#include <drivers/st/stm32_gpio.h>
#include <drivers/st/stm32_iwdg.h>
+#include <drivers/st/stm32_rng.h>
+#include <drivers/st/stm32_rtc.h>
+#include <drivers/st/stm32_tamp.h>
+#include <drivers/st/stm32_timer.h>
+#include <drivers/st/stm32mp_clkfunc.h>
+#include <drivers/st/stm32mp_pmic.h>
#include <drivers/st/stm32mp1_clk.h>
+#include <drivers/st/stm32mp1_ddr_helpers.h>
+#include <drivers/st/stpmic1.h>
#include <dt-bindings/clock/stm32mp1-clks.h>
#include <lib/el3_runtime/context_mgmt.h>
#include <lib/mmio.h>
@@ -28,6 +37,7 @@
#include <plat/common/platform.h>
#include <platform_sp_min.h>
+#include <stm32mp1_power_config.h>
/******************************************************************************
* Placeholder variables for copying the arguments that have been passed to
@@ -36,23 +46,168 @@
static entry_point_info_t bl33_image_ep_info;
static struct console_stm32 console;
+static void stm32mp1_tamper_action(int id);
+
+static const char *tamper_name[PLAT_MAX_TAMP_INT] = {
+ "RTC power domain",
+ "Temperature monitoring",
+ "LSE monitoring",
+ "HSE monitoring",
+ "RTC calendar overflow",
+ "Monotonic counter"
+};
+
+static struct stm32_tamp_int int_tamp[PLAT_MAX_TAMP_INT] = {
+ {
+ .id = ITAMP1,
+ .func = stm32mp1_tamper_action,
+ },
+ {
+ .id = ITAMP2,
+ .func = stm32mp1_tamper_action,
+ },
+ {
+ .id = ITAMP3,
+ .func = stm32mp1_tamper_action,
+ },
+ {
+ .id = ITAMP4,
+ .func = stm32mp1_tamper_action,
+ },
+ 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;
+
+ stm32mp_mask_timer();
+
+ 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);
+
+ stm32mp_wait_cpu_reset();
+}
+
+static void stm32mp1_tamper_action(int id)
+{
+ ERROR("Tamper %s occurs\n", tamper_name[id]);
+ stm32mp_plat_reset(plat_my_core_pos());
+}
+
+static void configure_wakeup_interrupt(void)
+{
+ int irq_num = fdt_rcc_enable_it("wakeup");
+
+ if (irq_num < 0) {
+ ERROR("irq_num = %d\n", irq_num);
+ panic();
+ }
+
+ plat_ic_set_interrupt_priority(irq_num, STM32MP1_IRQ_RCC_SEC_PRIO);
+}
+
+static void initialize_pll1_settings(void)
+{
+ uint32_t cpu_voltage = 0U;
+
+ if (stm32_are_pll1_settings_valid_in_context()) {
+ return;
+ }
+
+ if (dt_pmic_status() > 0) {
+ const char *name = stm32mp_get_cpu_supply_name();
+ int ret;
+
+ if (name == NULL) {
+ panic();
+ }
+
+ ret = stpmic1_regulator_voltage_get(name);
+ if (ret < 0) {
+ panic();
+ }
+
+ cpu_voltage = (uint32_t)ret;
+ }
+
+ if (stm32mp1_clk_compute_all_pll1_settings(cpu_voltage) != 0) {
+ panic();
+ }
+}
/*******************************************************************************
* Interrupt handler for FIQ (secure IRQ)
******************************************************************************/
void sp_min_plat_fiq_handler(uint32_t 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_calib_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 : %u", id);
+ ERROR("SECURE IT handler not define for it : %u\n", id);
break;
}
}
@@ -66,22 +221,99 @@ 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;
}
+CASSERT((STM32MP_SEC_SYSRAM_BASE >= STM32MP_SYSRAM_BASE) &&
+ ((STM32MP_SEC_SYSRAM_BASE + STM32MP_SEC_SYSRAM_SIZE) <=
+ (STM32MP_SYSRAM_BASE + STM32MP_SYSRAM_SIZE)),
+ assert_secure_sysram_fits_into_sysram);
+
+#ifdef STM32MP_NS_SYSRAM_BASE
+CASSERT((STM32MP_NS_SYSRAM_BASE >= STM32MP_SEC_SYSRAM_BASE) &&
+ ((STM32MP_NS_SYSRAM_BASE + STM32MP_NS_SYSRAM_SIZE) ==
+ (STM32MP_SYSRAM_BASE + STM32MP_SYSRAM_SIZE)),
+ assert_non_secure_sysram_fits_at_end_of_sysram);
+
+CASSERT((STM32MP_NS_SYSRAM_BASE & GENMASK(11, 0)) == 0,
+ assert_non_secure_sysram_base_is_4kbyte_aligned);
+
+/* Last 4kByte page (12 bit wide) of SYSRAM is non-secure */
+#define TZMA1_SECURE_RANGE \
+ (((STM32MP_NS_SYSRAM_BASE - STM32MP_SYSRAM_BASE) >> 12) - 1U)
+#else
+/* STM32MP_NS_SYSRAM_BASE not defined means all SYSRAM is secure */
+#define TZMA1_SECURE_RANGE STM32MP1_ETZPC_TZMA_ALL_SECURE
+#endif /* STM32MP_NS_SYSRAM_BASE */
+
+#define TZMA0_SECURE_RANGE STM32MP1_ETZPC_TZMA_ALL_SECURE
+
+static void stm32mp1_etzpc_early_setup(void)
+{
+ etzpc_init();
+ etzpc_configure_tzma(0U, TZMA0_SECURE_RANGE);
+ etzpc_configure_tzma(1U, TZMA1_SECURE_RANGE);
+}
+
/*******************************************************************************
* Perform any BL32 specific platform actions.
******************************************************************************/
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_uart_info;
int result;
bl_params_t *params_from_bl2 = (bl_params_t *)arg0;
@@ -126,9 +358,22 @@ void sp_min_early_platform_setup2(u_register_t arg0, u_register_t arg1,
panic();
}
+ if (etzpc_init() != 0) {
+ panic();
+ }
+
+ stm32mp1_etzpc_early_setup();
+
result = dt_get_stdout_uart_info(&dt_uart_info);
+#if STM32MP_UART_PROGRAMMER
+ stm32_get_boot_interface(&boot_itf, &boot_instance);
+ if ((result > 0) && (dt_uart_info.status != 0U) &&
+ !((boot_itf == BOOT_API_CTX_BOOT_INTERFACE_SEL_SERIAL_UART) &&
+ (get_uart_address(boot_instance) == dt_uart_info.base))) {
+#else
if ((result > 0) && (dt_uart_info.status != 0U)) {
+#endif
unsigned int console_flags;
if (console_stm32_register(dt_uart_info.base, 0,
@@ -144,6 +389,50 @@ void sp_min_early_platform_setup2(u_register_t arg0, u_register_t arg1,
#endif
console_set_scope(&console.console, console_flags);
}
+
+ if (dt_pmic_status() > 0) {
+ initialize_pmic();
+ }
+
+ initialize_pll1_settings();
+
+ stm32mp1_init_lp_states();
+}
+
+/*******************************************************************************
+ * Set security setup in sp_min
+ ******************************************************************************/
+static void stm32mp1_sp_min_security_setup(void)
+{
+ uint32_t filter_conf = 0;
+ uint32_t active_conf = 0;
+ int ret;
+
+ /* 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_calib_init();
+ }
}
/*******************************************************************************
@@ -151,26 +440,27 @@ void sp_min_early_platform_setup2(u_register_t arg0, u_register_t arg1,
******************************************************************************/
void sp_min_platform_setup(void)
{
+ ddr_save_sr_mode();
+
/* Initialize tzc400 after DDR initialization */
stm32mp1_security_setup();
generic_delay_timer_init();
- stm32mp1_gic_init();
+ stm32_gic_init();
- /* Unlock ETZPC securable peripherals */
-#define STM32MP1_ETZPC_BASE 0x5C007000U
-#define ETZPC_DECPROT0 0x010U
- mmio_write_32(STM32MP1_ETZPC_BASE + ETZPC_DECPROT0, 0xFFFFFFFF);
-
- /* Set GPIO bank Z as non secure */
- for (uint32_t pin = 0U; pin < STM32MP_GPIOZ_PIN_MAX_COUNT; pin++) {
- set_gpio_secure_cfg(GPIO_BANK_Z, pin, false);
- }
+ /* Update security settings */
+ stm32mp1_sp_min_security_setup();
if (stm32_iwdg_init() < 0) {
panic();
}
+
+ configure_wakeup_interrupt();
+
+ stm32mp_lock_periph_registering();
+
+ stm32mp1_init_scmi_server();
}
void sp_min_plat_arch_setup(void)
diff --git a/plat/st/stm32mp1/stm32mp1_boot_device.c b/plat/st/stm32mp1/stm32mp1_boot_device.c
new file mode 100644
index 000000000..ee64b58c3
--- /dev/null
+++ b/plat/st/stm32mp1/stm32mp1_boot_device.c
@@ -0,0 +1,168 @@
+/*
+ * Copyright (c) 2019, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <errno.h>
+
+#include <drivers/nand.h>
+#include <lib/utils.h>
+#include <plat/common/platform.h>
+
+#define SZ_512 0x200U
+#define SZ_64M 0x4000000U
+
+#if STM32MP_RAW_NAND || STM32MP_SPI_NAND
+static int get_data_from_otp(struct nand_device *nand_dev, bool is_slc)
+{
+ uint32_t nand_param;
+
+ /* Check if NAND parameters are stored in OTP */
+ if (stm32_get_otp_value(NAND_OTP, &nand_param) != 0) {
+ ERROR("BSEC: NAND_OTP Error\n");
+ return -EACCES;
+ }
+
+ if (nand_param == 0U) {
+ return 0;
+ }
+
+ if ((nand_param & NAND_PARAM_STORED_IN_OTP) == 0U) {
+ goto ecc;
+ }
+
+ /* NAND parameter shall be read from OTP */
+ if ((nand_param & NAND_WIDTH_MASK) != 0U) {
+ nand_dev->buswidth = NAND_BUS_WIDTH_16;
+ } else {
+ nand_dev->buswidth = NAND_BUS_WIDTH_8;
+ }
+
+ switch ((nand_param & NAND_PAGE_SIZE_MASK) >> NAND_PAGE_SIZE_SHIFT) {
+ case NAND_PAGE_SIZE_2K:
+ nand_dev->page_size = 0x800U;
+ break;
+
+ case NAND_PAGE_SIZE_4K:
+ nand_dev->page_size = 0x1000U;
+ break;
+
+ case NAND_PAGE_SIZE_8K:
+ nand_dev->page_size = 0x2000U;
+ break;
+
+ default:
+ ERROR("Cannot read NAND page size\n");
+ return -EINVAL;
+ }
+
+ switch ((nand_param & NAND_BLOCK_SIZE_MASK) >> NAND_BLOCK_SIZE_SHIFT) {
+ case NAND_BLOCK_SIZE_64_PAGES:
+ nand_dev->block_size = 64U * nand_dev->page_size;
+ break;
+
+ case NAND_BLOCK_SIZE_128_PAGES:
+ nand_dev->block_size = 128U * nand_dev->page_size;
+ break;
+
+ case NAND_BLOCK_SIZE_256_PAGES:
+ nand_dev->block_size = 256U * nand_dev->page_size;
+ break;
+
+ default:
+ ERROR("Cannot read NAND block size\n");
+ return -EINVAL;
+ }
+
+ nand_dev->size = ((nand_param & NAND_BLOCK_NB_MASK) >>
+ NAND_BLOCK_NB_SHIFT) *
+ NAND_BLOCK_NB_UNIT * nand_dev->block_size;
+
+ecc:
+ if (is_slc) {
+ switch ((nand_param & NAND_ECC_BIT_NB_MASK) >>
+ NAND_ECC_BIT_NB_SHIFT) {
+ case NAND_ECC_BIT_NB_1_BITS:
+ nand_dev->ecc.max_bit_corr = 1U;
+ break;
+
+ case NAND_ECC_BIT_NB_4_BITS:
+ nand_dev->ecc.max_bit_corr = 4U;
+ break;
+
+ case NAND_ECC_BIT_NB_8_BITS:
+ nand_dev->ecc.max_bit_corr = 8U;
+ break;
+
+ case NAND_ECC_ON_DIE:
+ nand_dev->ecc.mode = NAND_ECC_ONDIE;
+ break;
+
+ default:
+ if (nand_dev->ecc.max_bit_corr == 0U) {
+ ERROR("No valid eccbit number\n");
+ return -EINVAL;
+ }
+ }
+ } else {
+ /* Selected multiple plane NAND */
+ if ((nand_param & NAND_PLANE_BIT_NB_MASK) != 0U) {
+ nand_dev->nb_planes = 2U;
+ } else {
+ nand_dev->nb_planes = 1U;
+ }
+ }
+
+ VERBOSE("OTP: Block %i Page %i Size %lli\n", nand_dev->block_size,
+ nand_dev->page_size, nand_dev->size);
+
+ return 0;
+}
+#endif /* STM32MP_RAW_NAND || STM32MP_SPI_NAND */
+
+#if STM32MP_RAW_NAND
+int plat_get_raw_nand_data(struct rawnand_device *device)
+{
+ device->nand_dev->ecc.mode = NAND_ECC_HW;
+ device->nand_dev->ecc.size = SZ_512;
+
+ return get_data_from_otp(device->nand_dev, true);
+}
+#endif
+
+#if STM32MP_SPI_NAND
+int plat_get_spi_nand_data(struct spinand_device *device)
+{
+ zeromem(&device->spi_read_cache_op, sizeof(struct spi_mem_op));
+ device->spi_read_cache_op.cmd.opcode = SPI_NAND_OP_READ_FROM_CACHE_4X;
+ device->spi_read_cache_op.cmd.buswidth = SPI_MEM_BUSWIDTH_1_LINE;
+ device->spi_read_cache_op.addr.nbytes = 2U;
+ device->spi_read_cache_op.addr.buswidth = SPI_MEM_BUSWIDTH_1_LINE;
+ device->spi_read_cache_op.dummy.nbytes = 1U;
+ device->spi_read_cache_op.dummy.buswidth = SPI_MEM_BUSWIDTH_1_LINE;
+ device->spi_read_cache_op.data.buswidth = SPI_MEM_BUSWIDTH_4_LINE;
+ device->spi_read_cache_op.data.dir = SPI_MEM_DATA_IN;
+
+ return get_data_from_otp(device->nand_dev, false);
+}
+#endif
+
+#if STM32MP_SPI_NOR
+int plat_get_nor_data(struct nor_device *device)
+{
+ device->size = SZ_64M;
+
+ zeromem(&device->read_op, sizeof(struct spi_mem_op));
+ device->read_op.cmd.opcode = SPI_NOR_OP_READ_1_1_4;
+ device->read_op.cmd.buswidth = SPI_MEM_BUSWIDTH_1_LINE;
+ device->read_op.addr.nbytes = 3U;
+ device->read_op.addr.buswidth = SPI_MEM_BUSWIDTH_1_LINE;
+ device->read_op.dummy.nbytes = 1U;
+ device->read_op.dummy.buswidth = SPI_MEM_BUSWIDTH_1_LINE;
+ device->read_op.data.buswidth = SPI_MEM_BUSWIDTH_4_LINE;
+ device->read_op.data.dir = SPI_MEM_DATA_IN;
+
+ return 0;
+}
+#endif
diff --git a/plat/st/stm32mp1/stm32mp1_context.c b/plat/st/stm32mp1/stm32mp1_context.c
index cf8a91eb4..e77b8a79f 100644
--- a/plat/st/stm32mp1/stm32mp1_context.c
+++ b/plat/st/stm32mp1/stm32mp1_context.c
@@ -5,19 +5,343 @@
*/
#include <errno.h>
+#include <string.h>
#include <platform_def.h>
-#include <drivers/st/stm32mp1_clk.h>
+#include <arch_helpers.h>
+#include <context.h>
+#include <drivers/st/stm32_rtc.h>
+#include <drivers/st/stm32mp_clkfunc.h>
+#include <drivers/st/stm32mp1_ddr_regs.h>
#include <dt-bindings/clock/stm32mp1-clks.h>
+#include <lib/el3_runtime/context_mgmt.h>
#include <lib/mmio.h>
+#include <lib/utils.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+#include <smccc_helpers.h>
#include <stm32mp1_context.h>
+#include <boot_api.h>
+
#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
+ *
+ * OPTEE_MAILBOX_MAGIC_V1:
+ * Context provides magic, resume entry, zq0cr0 zdata and DDR training buffer.
+ *
+ * OPTEE_MAILBOX_MAGIC_V2:
+ * Context provides magic, resume entry, zq0cr0 zdata, DDR training buffer
+ * and PLL1 dual OPP settings structure (86 bytes).
+ */
+#define OPTEE_MAILBOX_MAGIC_V1 (0x0001 << 16)
+#define OPTEE_MAILBOX_MAGIC_V2 (0x0002 << 16)
+#define OPTEE_MAILBOX_MAGIC (OPTEE_MAILBOX_MAGIC_V2 | \
+ TRAINING_AREA_SIZE)
+
+#define MAGIC_ID(magic) ((magic) & GENMASK_32(31, 16))
+#define MAGIC_AREA_SIZE(magic) ((magic) & GENMASK_32(15, 0))
+
+#if (PLAT_MAX_OPP_NB != 2) || (PLAT_MAX_PLLCFG_NB != 6)
+#error OPTEE_MAILBOX_MAGIC_V1 does not support expected PLL1 settings
+#endif
+#endif
+
+/* pll_settings structure size definitions (reference to clock driver) */
+#define PLL1_SETTINGS_SIZE (((PLAT_MAX_OPP_NB * \
+ (PLAT_MAX_PLLCFG_NB + 3)) + 1) * \
+ sizeof(uint32_t))
+
+/* Set to 600 bytes to be a bit flexible but could be optimized if needed */
+#define CLOCK_CONTEXT_SIZE 600
+
+/* SCMI needs only 24 bits to save the state of the 24 exposed clocks */
+#define SCMI_CONTEXT_SIZE (sizeof(uint8_t) * 4)
+
+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];
+ uint8_t pll1_settings[PLL1_SETTINGS_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];
+ uint8_t pll1_settings[PLL1_SETTINGS_SIZE];
+ unsigned long long stgen;
+ uint8_t clock_cfg[CLOCK_CONTEXT_SIZE];
+ uint8_t scmi_context[SCMI_CONTEXT_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;
+
+ switch (MAGIC_ID(backup_data->magic)) {
+ case OPTEE_MAILBOX_MAGIC_V1:
+ case OPTEE_MAILBOX_MAGIC_V2:
+ if (MAGIC_AREA_SIZE(backup_data->magic) != TRAINING_AREA_SIZE) {
+ panic();
+ }
+ break;
+ default:
+ ERROR("PM context: bad magic\n");
+ 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);
+}
+
+void stm32mp1_pm_save_clock_cfg(size_t offset, uint8_t *data, size_t size)
+{
+ struct backup_data_s *backup_data;
+
+ if (offset + size > sizeof(backup_data->clock_cfg)) {
+ panic();
+ }
+
+ backup_data = (struct backup_data_s *)STM32MP_BACKUP_RAM_BASE;
+
+ stm32mp_clk_enable(BKPSRAM);
+
+ memcpy(backup_data->clock_cfg + offset, data, size);
+
+ stm32mp_clk_disable(BKPSRAM);
+}
+
+void stm32mp1_pm_restore_clock_cfg(size_t offset, uint8_t *data, size_t size)
+{
+ struct backup_data_s *backup_data;
+
+ if (offset + size > sizeof(backup_data->clock_cfg))
+ panic();
+
+ backup_data = (struct backup_data_s *)STM32MP_BACKUP_RAM_BASE;
+
+ stm32mp_clk_enable(BKPSRAM);
+
+ memcpy(data, backup_data->clock_cfg + offset, size);
+
+ stm32mp_clk_disable(BKPSRAM);
+}
+
+int stm32_save_context(uint32_t zq0cr0_zdata)
+{
+ void *smc_context;
+ void *cpu_context;
+ struct backup_data_s *backup_data;
+
+ stm32mp1_clock_suspend();
+
+ 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);
+ backup_data->stgen = stm32mp_stgen_get_counter();
+
+ stm32mp1_clk_lp_save_opp_pll1_settings(backup_data->pll1_settings,
+ sizeof(backup_data->pll1_settings));
+
+ stm32mp1_pm_save_scmi_state(backup_data->scmi_context,
+ sizeof(backup_data->scmi_context));
+
+ save_clock_pm_context();
+
+ 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;
+
+ /* 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);
+
+ stm32mp_clk_enable(BKPSRAM);
+
+ restore_clock_pm_context();
+
+ stm32mp1_pm_restore_scmi_state(backup_data->scmi_context,
+ sizeof(backup_data->scmi_context));
+
+ /* 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);
+
+ /* Restore STGEN counter with standby mode length */
+ stm32_rtc_get_calendar(&current_calendar);
+ stdby_time_in_ms = stm32_rtc_diff_calendar(&current_calendar,
+ &backup_data->rtc);
+ stm32mp_stgen_restore_counter(backup_data->stgen, stdby_time_in_ms);
+
+ stm32mp1_clk_lp_load_opp_pll1_settings(backup_data->pll1_settings,
+ sizeof(backup_data->pll1_settings));
+
+ stm32mp_clk_disable(BKPSRAM);
+
+ stm32mp1_clock_resume();
+
+ return 0;
+}
+
+unsigned long long stm32_get_stgen_from_context(void)
+{
+ struct backup_data_s *backup_data;
+ unsigned long long stgen_cnt;
+
+ stm32mp_clk_enable(BKPSRAM);
+
+ backup_data = (struct backup_data_s *)STM32MP_BACKUP_RAM_BASE;
+
+ stgen_cnt = backup_data->stgen;
+
+ stm32mp_clk_disable(BKPSRAM);
+
+ return stgen_cnt;
+}
+#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;
+}
+
+#ifdef AARCH32_SP_OPTEE
+static int pll1_settings_in_context(struct backup_data_s *backup_data)
+{
+ switch (MAGIC_ID(backup_data->magic)) {
+ case OPTEE_MAILBOX_MAGIC_V1:
+ return -ENOENT;
+ case OPTEE_MAILBOX_MAGIC_V2:
+ assert(MAGIC_AREA_SIZE(backup_data->magic) ==
+ TRAINING_AREA_SIZE);
+ return 0;
+ default:
+ panic();
+ }
+}
+#else
+static int pll1_settings_in_context(struct backup_data_s *backup_data)
+{
+ return 0;
+}
+#endif
+
+int stm32_get_pll1_settings_from_context(void)
+{
+ struct backup_data_s *backup_data;
+ int ret;
+
+ backup_data = (struct backup_data_s *)STM32MP_BACKUP_RAM_BASE;
+
+ stm32mp_clk_enable(BKPSRAM);
+
+ ret = pll1_settings_in_context(backup_data);
+ if (ret == 0) {
+ uint8_t *data = (uint8_t *)backup_data->pll1_settings;
+ size_t size = sizeof(backup_data->pll1_settings);
+
+ stm32mp1_clk_lp_load_opp_pll1_settings(data, size);
+ }
+
+ stm32mp_clk_disable(BKPSRAM);
+
+ return ret;
+}
+
+bool stm32_are_pll1_settings_valid_in_context(void)
+{
+ struct backup_data_s *backup_data;
+ uint32_t *data;
+ bool is_valid;
+
+ stm32mp_clk_enable(BKPSRAM);
+
+ backup_data = (struct backup_data_s *)STM32MP_BACKUP_RAM_BASE;
+ data = (uint32_t *)backup_data->pll1_settings;
+
+ is_valid = (data[0] == PLL1_SETTINGS_VALID_ID);
+
+ stm32mp_clk_disable(BKPSRAM);
+
+ return is_valid;
+}
+
int stm32_save_boot_interface(uint32_t interface, uint32_t instance)
{
uint32_t bkpr_itf_idx = tamp_bkpr(TAMP_BOOT_ITF_BACKUP_REG_ID);
@@ -33,3 +357,68 @@ int stm32_save_boot_interface(uint32_t interface, uint32_t instance)
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;
+}
+
+#if defined(IMAGE_BL32)
+/*
+ * 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;
+ int ret __unused;
+
+ stm32mp_clk_enable(BKPSRAM);
+
+ backup_data = (struct backup_data_s *)STM32MP_BACKUP_RAM_BASE;
+
+ ret = mmap_add_dynamic_region(STM32MP_DDR_BASE, STM32MP_DDR_BASE,
+ PAGE_SIZE, MT_MEMORY | MT_RW | MT_NS);
+ assert(ret == 0);
+
+ memcpy(&backup_data->ddr_training_backup,
+ (const uint32_t *)STM32MP_DDR_BASE,
+ TRAINING_AREA_SIZE);
+ dsb();
+
+ ret = mmap_remove_dynamic_region(STM32MP_DDR_BASE, PAGE_SIZE);
+ assert(ret == 0);
+
+ stm32mp_clk_disable(BKPSRAM);
+}
+#endif
+
+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
index d0264968c..b9f94af0a 100644
--- a/plat/st/stm32mp1/stm32mp1_dbgmcu.c
+++ b/plat/st/stm32mp1/stm32mp1_dbgmcu.c
@@ -4,12 +4,14 @@
* SPDX-License-Identifier: BSD-3-Clause
*/
+#include <assert.h>
#include <errno.h>
#include <platform_def.h>
#include <common/debug.h>
#include <drivers/st/bsec.h>
+#include <drivers/st/bsec2_reg.h>
#include <drivers/st/stm32mp1_rcc.h>
#include <lib/mmio.h>
#include <lib/utils_def.h>
@@ -33,19 +35,11 @@ static uintptr_t get_rcc_base(void)
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 -1;
- }
+ if ((bsec_read_debug_conf() & BSEC_DBGSWGEN) == 0U) {
+ INFO("Software access to all debug components is disabled\n");
+ return -1;
}
mmio_setbits_32(rcc_base + RCC_DBGCFGR, RCC_DBGCFGR_DBGCKEN);
@@ -53,8 +47,15 @@ static int stm32mp1_dbgmcu_init(void)
return 0;
}
+/*
+ * @brief Get silicon revision from DBGMCU registers.
+ * @param chip_version: pointer to the read value.
+ * @retval 0 on success, negative value on failure.
+ */
int stm32mp1_dbgmcu_get_chip_version(uint32_t *chip_version)
{
+ assert(chip_version != NULL);
+
if (stm32mp1_dbgmcu_init() != 0) {
return -EPERM;
}
@@ -65,18 +66,29 @@ int stm32mp1_dbgmcu_get_chip_version(uint32_t *chip_version)
return 0;
}
+/*
+ * @brief Get device ID from DBGMCU registers.
+ * @param chip_dev_id: pointer to the read value.
+ * @retval 0 on success, negative value on failure.
+ */
int stm32mp1_dbgmcu_get_chip_dev_id(uint32_t *chip_dev_id)
{
+ assert(chip_dev_id != NULL);
+
if (stm32mp1_dbgmcu_init() != 0) {
return -EPERM;
}
*chip_dev_id = mmio_read_32(DBGMCU_BASE + DBGMCU_IDC) &
- DBGMCU_IDC_DEV_ID_MASK;
+ DBGMCU_IDC_DEV_ID_MASK;
return 0;
}
+/*
+ * @brief Freeze IWDG2 in debug mode.
+ * @retval None.
+ */
int stm32mp1_dbgmcu_freeze_iwdg2(void)
{
uint32_t dbg_conf;
diff --git a/plat/st/stm32mp1/stm32mp1_def.h b/plat/st/stm32mp1/stm32mp1_def.h
index a40852bde..d458805a1 100644
--- a/plat/st/stm32mp1/stm32mp1_def.h
+++ b/plat/st/stm32mp1/stm32mp1_def.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2015-2020, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -11,33 +11,51 @@
#include <drivers/st/stm32mp1_rcc.h>
#include <dt-bindings/clock/stm32mp1-clks.h>
#include <dt-bindings/reset/stm32mp1-resets.h>
+#include <dt-bindings/soc/st,stm32-etzpc.h>
#include <lib/utils_def.h>
#include <lib/xlat_tables/xlat_tables_defs.h>
#ifndef __ASSEMBLER__
#include <drivers/st/bsec.h>
+#include <drivers/st/stm32mp1_calib.h>
#include <drivers/st/stm32mp1_clk.h>
+#include <drivers/st/stm32mp1_ddr_regs.h>
+#include <drivers/st/stm32mp1_pwr.h>
+#include <drivers/st/stm32mp1xx_hal_uart.h>
#include <boot_api.h>
-#include <stm32mp_auth.h>
#include <stm32mp_common.h>
#include <stm32mp_dt.h>
#include <stm32mp_shres_helpers.h>
+#include <stm32mp1_boot_device.h>
+#include <stm32mp1_context.h>
#include <stm32mp1_dbgmcu.h>
#include <stm32mp1_private.h>
+#include <stm32mp1_shared_resources.h>
+#include <stm32mp1_usb_desc.h>
+#include <usb_ctx.h>
#endif
/*******************************************************************************
* CHIP ID
******************************************************************************/
+#define STM32MP1_CHIP_ID U(0x500)
+
#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 STM32MP157F_PART_NB U(0x05000080)
+#define STM32MP157D_PART_NB U(0x05000081)
+#define STM32MP153F_PART_NB U(0x050000A4)
+#define STM32MP153D_PART_NB U(0x050000A5)
+#define STM32MP151F_PART_NB U(0x050000AE)
+#define STM32MP151D_PART_NB U(0x050000AF)
#define STM32MP1_REV_B U(0x2000)
+#define STM32MP1_REV_Z U(0x2001)
/*******************************************************************************
* PACKAGE ID
@@ -47,6 +65,11 @@
#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
******************************************************************************/
@@ -56,12 +79,34 @@
#define STM32MP_SYSRAM_BASE U(0x2FFC0000)
#define STM32MP_SYSRAM_SIZE U(0x00040000)
+/* 384 KB (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 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)
+
+#define STM32MP_NS_SYSRAM_SIZE PAGE_SIZE
+#define STM32MP_NS_SYSRAM_BASE (STM32MP_SYSRAM_BASE + \
+ STM32MP_SYSRAM_SIZE - \
+ STM32MP_NS_SYSRAM_SIZE)
+
+#define STM32MP_SEC_SYSRAM_BASE STM32MP_SYSRAM_BASE
+#define STM32MP_SEC_SYSRAM_SIZE (STM32MP_SYSRAM_SIZE - \
+ STM32MP_NS_SYSRAM_SIZE)
+
/* DDR configuration */
#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(0x01E00000) /* 30 MB */
#define STM32MP_DDR_SHMEM_SIZE U(0x00200000) /* 2 MB */
+#else
+#define STM32MP_DDR_S_SIZE U(0)
+#define STM32MP_DDR_SHMEM_SIZE U(0)
#endif
/* DDR power initializations */
@@ -74,76 +119,121 @@ enum ddr_type {
#endif
/* Section used inside TF binaries */
-#define STM32MP_PARAM_LOAD_SIZE U(0x00002400) /* 9 Ko for param */
+#define STM32MP_PARAM_LOAD_SIZE U(0x00002400) /* 9 KB for param */
/* 256 Octets reserved for header */
#define STM32MP_HEADER_SIZE U(0x00000100)
-#define STM32MP_BINARY_BASE (STM32MP_SYSRAM_BASE + \
+#define STM32MP_BINARY_BASE (STM32MP_SEC_SYSRAM_BASE + \
STM32MP_PARAM_LOAD_SIZE + \
STM32MP_HEADER_SIZE)
-#define STM32MP_BINARY_SIZE (STM32MP_SYSRAM_SIZE - \
+#define STM32MP_BINARY_SIZE (STM32MP_SEC_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_BASE STM32MP_SEC_SYSRAM_BASE
#define STM32MP_OPTEE_SIZE (STM32MP_DTB_BASE - \
STM32MP_OPTEE_BASE)
#else
#if STACK_PROTECTOR_ENABLED
-#define STM32MP_BL32_SIZE U(0x00012000) /* 72 Ko for BL32 */
+#define STM32MP_BL32_SIZE U(0x00013000) /* 76 KB for BL32 */
#else
-#define STM32MP_BL32_SIZE U(0x00011000) /* 68 Ko for BL32 */
+#define STM32MP_BL32_SIZE U(0x00012000) /* 72 KB for BL32 */
#endif
#endif
-#define STM32MP_BL32_BASE (STM32MP_SYSRAM_BASE + \
- STM32MP_SYSRAM_SIZE - \
+#define STM32MP_BL32_BASE (STM32MP_SEC_SYSRAM_BASE + \
+ STM32MP_SEC_SYSRAM_SIZE - \
STM32MP_BL32_SIZE)
#ifdef AARCH32_SP_OPTEE
#if STACK_PROTECTOR_ENABLED
-#define STM32MP_BL2_SIZE U(0x00019000) /* 100 Ko for BL2 */
+#define STM32MP_BL2_SIZE U(0x0001A000) /* 104 KB for BL2 */
#else
-#define STM32MP_BL2_SIZE U(0x00017000) /* 92 Ko for BL2 */
+#define STM32MP_BL2_SIZE U(0x00018000) /* 96 KB for BL2 */
#endif
#else
#if STACK_PROTECTOR_ENABLED
-#define STM32MP_BL2_SIZE U(0x00018000) /* 96 Ko for BL2 */
+#define STM32MP_BL2_SIZE U(0x00019000) /* 100 KB for BL2 */
#else
-#define STM32MP_BL2_SIZE U(0x00016000) /* 88 Ko for BL2 */
+#define STM32MP_BL2_SIZE U(0x00017000) /* 92 KB for BL2 */
#endif
#endif
#define STM32MP_BL2_BASE (STM32MP_BL32_BASE - \
STM32MP_BL2_SIZE)
-/* BL2 and BL32/sp_min require 5 tables */
-#define MAX_XLAT_TABLES 5
+#if STM32MP_USB_PROGRAMMER
+ /* BL2 and BL32/sp_min require 5 finer granularity tables */
+ #define MAX_XLAT_TABLES U(5) /* 20 KB for mapping */
+#else
+ /* BL2 and BL32/sp_min require 4 finer granularity tables */
+ #define MAX_XLAT_TABLES U(4) /* 16 KB for mapping */
+#endif
/*
* MAX_MMAP_REGIONS is usually:
* BL stm32mp1_mmap size + mmap regions in *_plat_arch_setup
*/
#if defined(IMAGE_BL2)
+ #if STM32MP_USB_PROGRAMMER
+ #define MAX_MMAP_REGIONS 12
+ #else
#define MAX_MMAP_REGIONS 11
+ #endif
#endif
#if defined(IMAGE_BL32)
#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)
+
/* DTB initialization value */
-#define STM32MP_DTB_SIZE U(0x00005000) /* 20Ko for DTB */
+#define STM32MP_DTB_SIZE U(0x00006000) /* 24 KB for DTB */
-#define STM32MP_DTB_BASE (STM32MP_BL2_BASE - \
+#define STM32MP_DTB_BASE (PLAT_XLAT_BASE - \
STM32MP_DTB_SIZE)
#define STM32MP_BL33_BASE (STM32MP_DDR_BASE + U(0x100000))
+/* Define Temporary Stack size use during low power mode */
+#define STM32MP_INT_STACK_SIZE 0x100
+
+/* Define maximum page size for NAND devices */
+#define PLATFORM_MTD_MAX_PAGE_SIZE U(0x1000)
+
+/*
+ * Only used for MTD devices that need some backup blocks.
+ * Must define a number of reserved blocks (depends on devices).
+ */
+#define PLATFORM_MTD_BACKUP_BLOCKS U(20) /* (20 * MTD block size) */
+
+/*******************************************************************************
+ * STM32MP1 RAW partition offset for MTD devices
+ ******************************************************************************/
+#define STM32MP_NOR_BL33_OFFSET U(0x00080000)
+#ifdef AARCH32_SP_OPTEE
+#define STM32MP_NOR_TEEH_OFFSET U(0x00300000)
+#define STM32MP_NOR_TEED_OFFSET U(0x00340000)
+#define STM32MP_NOR_TEEX_OFFSET U(0x003C0000)
+#endif
+
+#define STM32MP_NAND_BL33_OFFSET U(0x00200000)
+#ifdef AARCH32_SP_OPTEE
+#define STM32MP_NAND_TEEH_OFFSET U(0x00600000)
+#define STM32MP_NAND_TEED_OFFSET U(0x00680000)
+#define STM32MP_NAND_TEEX_OFFSET U(0x00700000)
+#endif
+
/*******************************************************************************
* STM32MP1 device/io map related constants (used for MMU)
******************************************************************************/
@@ -163,6 +253,32 @@ enum ddr_type {
******************************************************************************/
#define PWR_BASE U(0x50001000)
+/*******************************************************************************
+ * STM32MP1 SYSCFG
+ ******************************************************************************/
+#define SYSCFG_BASE U(0x50020000)
+
+/*******************************************************************************
+ * 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
******************************************************************************/
@@ -223,6 +339,21 @@ enum ddr_type {
#define DEBUG_UART_TX_EN_REG RCC_MP_APB1ENSETR
#define DEBUG_UART_TX_EN RCC_MP_APB1ENSETR_UART4EN
+/*******************************************************************************
+ * STM32MP1 ETZPC
+ ******************************************************************************/
+#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)
+
+/* Lowest DECPROT ID for ETZPC cannot harden TZ security */
+#define STM32MP1_ETZPC_SEC_ID_LIMIT U(13)
+
+#define STM32MP1_ETZPC_TZMA_ALL_SECURE GENMASK_32(9, 0)
+
/*******************************************************************************
* STM32MP1 TZC (TZ400)
******************************************************************************/
@@ -263,15 +394,20 @@ enum ddr_type {
#define OTP_MAX_SIZE (STM32MP1_OTP_MAX_ID + 1U)
-/* OTP offsets */
-#define DATA0_OTP U(0)
-#define PART_NUMBER_OTP U(1)
-#define PACKAGE_OTP U(16)
-#define HW2_OTP U(18)
+/* OTP labels */
+#define CFG0_OTP "cfg0_otp"
+#define PART_NUMBER_OTP "part_number_otp"
+#define PACKAGE_OTP "package_otp"
+#define HW2_OTP "hw2_otp"
+#define NAND_OTP "nand_otp"
+#define MONOTONIC_OTP "monotonic_otp"
+#define UID_OTP "uid_otp"
+#define PKH_OTP "pkh_otp"
+#define BOARD_ID_OTP "board_id"
/* OTP mask */
-/* DATA0 */
-#define DATA0_OTP_SECURED BIT(6)
+/* CFG0 */
+#define CFG0_CLOSED_DEVICE BIT(6)
/* PART NUMBER */
#define PART_NUMBER_OTP_PART_MASK GENMASK_32(7, 0)
@@ -289,11 +425,71 @@ enum ddr_type {
/* HW2 OTP */
#define HW2_OTP_PRODUCT_BELOW_2V5 BIT(13)
+#define MAX_MONOTONIC_VALUE 32
+
+/* NAND OTP */
+/* NAND parameter storage flag */
+#define NAND_PARAM_STORED_IN_OTP BIT(31)
+
+/* NAND page size in bytes */
+#define NAND_PAGE_SIZE_MASK GENMASK_32(30, 29)
+#define NAND_PAGE_SIZE_SHIFT 29
+#define NAND_PAGE_SIZE_2K U(0)
+#define NAND_PAGE_SIZE_4K U(1)
+#define NAND_PAGE_SIZE_8K U(2)
+
+/* NAND block size in pages */
+#define NAND_BLOCK_SIZE_MASK GENMASK_32(28, 27)
+#define NAND_BLOCK_SIZE_SHIFT 27
+#define NAND_BLOCK_SIZE_64_PAGES U(0)
+#define NAND_BLOCK_SIZE_128_PAGES U(1)
+#define NAND_BLOCK_SIZE_256_PAGES U(2)
+
+/* NAND number of block (in unit of 256 blocs) */
+#define NAND_BLOCK_NB_MASK GENMASK_32(26, 19)
+#define NAND_BLOCK_NB_SHIFT 19
+#define NAND_BLOCK_NB_UNIT U(256)
+
+/* NAND bus width in bits */
+#define NAND_WIDTH_MASK BIT(18)
+#define NAND_WIDTH_SHIFT 18
+
+/* NAND number of ECC bits per 512 bytes */
+#define NAND_ECC_BIT_NB_MASK GENMASK_32(17, 15)
+#define NAND_ECC_BIT_NB_SHIFT 15
+#define NAND_ECC_BIT_NB_UNSET U(0)
+#define NAND_ECC_BIT_NB_1_BITS U(1)
+#define NAND_ECC_BIT_NB_4_BITS U(2)
+#define NAND_ECC_BIT_NB_8_BITS U(3)
+#define NAND_ECC_ON_DIE U(4)
+
+/* NAND number of planes */
+#define NAND_PLANE_BIT_NB_MASK BIT(14)
+
+/* MONOTONIC OTP */
+#define MAX_MONOTONIC_VALUE 32
+
+/* UID OTP */
+#define UID_WORD_NB 3
+
+/*******************************************************************************
+ * STM32MP1 HASH
+ ******************************************************************************/
+#define HASH1_BASE U(0x54002000)
+#define HASH_BASE HASH1_BASE
+
/*******************************************************************************
* STM32MP1 TAMP
******************************************************************************/
+#define PLAT_MAX_TAMP_INT U(6)
+#define PLAT_MAX_TAMP_EXT U(3)
#define TAMP_BASE U(0x5C00A000)
+#define TAMP_SMCR (TAMP_BASE + U(0x20))
#define TAMP_BKP_REGISTER_BASE (TAMP_BASE + U(0x100))
+#define TAMP_BKP_SEC_NUMBER U(10)
+#define TAMP_BKP_SEC_WDPROT_SHIFT U(16)
+#define TAMP_BKP_SEC_RWDPROT_SHIFT U(0)
+
#if !(defined(__LINKER__) || defined(__ASSEMBLER__))
static inline uint32_t tamp_bkpr(uint32_t idx)
@@ -302,6 +498,11 @@ static inline uint32_t tamp_bkpr(uint32_t idx)
}
#endif
+/*******************************************************************************
+ * STM32MP1 USB
+ ******************************************************************************/
+#define USB_OTG_BASE U(0x49000000)
+
/*******************************************************************************
* STM32MP1 DDRCTRL
******************************************************************************/
@@ -323,22 +524,69 @@ static inline uint32_t tamp_bkpr(uint32_t idx)
#define IWDG2_BASE U(0x5A002000)
/*******************************************************************************
- * STM32MP1 I2C4
+ * 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 STGEN
+ ******************************************************************************/
+#define STGEN_BASE U(0x5C008000)
+
+/*******************************************************************************
+ * STM32MP1 TIMERS
+ ******************************************************************************/
+#define TIM12_BASE U(0x40006000)
+#define TIM15_BASE U(0x44006000)
+#define TIM_MAX_INSTANCE U(2)
+
+/*******************************************************************************
+ * STM32MP1 OPP
+ ******************************************************************************/
+#define PLAT_OPP_ID1 U(1)
+#define PLAT_OPP_ID2 U(2)
+#define PLAT_MAX_OPP_NB U(2)
+#define PLAT_MAX_PLLCFG_NB U(6)
+
+/*******************************************************************************
+ * DEBUG
+ ******************************************************************************/
+/*#define ICACHE_OFF*/
+/*#define DCACHE_OFF*/
+/*#define MMU_OFF*/
+
/*******************************************************************************
* Device Tree defines
******************************************************************************/
#define DT_BSEC_COMPAT "st,stm32mp15-bsec"
+#define DT_DDR_COMPAT "st,stm32mp1-ddr"
#define DT_IWDG_COMPAT "st,stm32mp1-iwdg"
-#define DT_PWR_COMPAT "st,stm32mp1-pwr"
+#define DT_NVMEM_LAYOUT_COMPAT "st,stm32-nvmem-layout"
+#define DT_OPP_COMPAT "operating-points-v2"
+#define DT_PWR_COMPAT "st,stm32mp1,pwr-reg"
#define DT_RCC_CLK_COMPAT "st,stm32mp1-rcc"
-#define DT_SYSCFG_COMPAT "st,stm32mp157-syscfg"
+
+#define DT_PLL1_NODE_NAME "st,pll@0"
#endif /* STM32MP1_DEF_H */
diff --git a/plat/st/stm32mp1/stm32mp1_gic.c b/plat/st/stm32mp1/stm32mp1_gic.c
deleted file mode 100644
index 851a9cf0c..000000000
--- a/plat/st/stm32mp1/stm32mp1_gic.c
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#include <libfdt.h>
-
-#include <platform_def.h>
-
-#include <common/bl_common.h>
-#include <common/debug.h>
-#include <drivers/arm/gicv2.h>
-#include <dt-bindings/interrupt-controller/arm-gic.h>
-#include <lib/utils.h>
-#include <plat/common/platform.h>
-
-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
- * interrupts.
- *****************************************************************************/
-static const interrupt_prop_t stm32mp1_interrupt_props[] = {
- PLATFORM_G1S_PROPS(GICV2_INTR_GROUP0),
- PLATFORM_G0_PROPS(GICV2_INTR_GROUP0)
-};
-
-/* 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 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;
-
-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();
-
- stm32mp1_gic_pcpu_init();
-}
-
-void stm32mp1_gic_pcpu_init(void)
-{
- gicv2_pcpu_distif_init();
- gicv2_set_pe_target_mask(plat_my_core_pos());
- gicv2_cpuif_enable();
-}
diff --git a/plat/st/stm32mp1/stm32mp1_helper.S b/plat/st/stm32mp1/stm32mp1_helper.S
index bfcd991a3..b80716253 100644
--- a/plat/st/stm32mp1/stm32mp1_helper.S
+++ b/plat/st/stm32mp1/stm32mp1_helper.S
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2015-2020, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -10,12 +10,17 @@
#include <asm_macros.S>
#include <common/bl_common.h>
#include <drivers/st/stm32_gpio.h>
+#include <smccc_helpers.h>
#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
@@ -25,6 +30,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 */
@@ -32,9 +38,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
@@ -129,10 +264,16 @@ func plat_crash_console_init
bic r2, r2, #(GPIO_PULL_MASK << GPIO_TX_SHIFT)
str r2, [r1, #GPIO_PUPD_OFFSET]
/* Set alternate */
- ldr r2, [r1, #GPIO_AFRH_OFFSET]
- bic r2, r2, #(GPIO_ALTERNATE_MASK << GPIO_TX_ALT_SHIFT)
- orr r2, r2, #(DEBUG_UART_TX_GPIO_ALTERNATE << GPIO_TX_ALT_SHIFT)
- str r2, [r1, #GPIO_AFRH_OFFSET]
+ ldr r2, =DEBUG_UART_TX_GPIO_PORT
+ cmp r2, #GPIO_ALT_LOWER_LIMIT
+ ldrge r2, [r1, #GPIO_AFRH_OFFSET]
+ bicge r2, r2, #(GPIO_ALTERNATE_MASK << ((DEBUG_UART_TX_GPIO_PORT - GPIO_ALT_LOWER_LIMIT) << 2))
+ orrge r2, r2, #(DEBUG_UART_TX_GPIO_ALTERNATE << ((DEBUG_UART_TX_GPIO_PORT - GPIO_ALT_LOWER_LIMIT) << 2))
+ strge r2, [r1, #GPIO_AFRH_OFFSET]
+ ldrlt r2, [r1, #GPIO_AFRL_OFFSET]
+ biclt r2, r2, #(GPIO_ALTERNATE_MASK << (DEBUG_UART_TX_GPIO_PORT << 2))
+ orrlt r2, r2, #(DEBUG_UART_TX_GPIO_ALTERNATE << (DEBUG_UART_TX_GPIO_PORT << 2))
+ strlt r2, [r1, #GPIO_AFRL_OFFSET]
/* Enable UART clock, with its source */
ldr r1, =(RCC_BASE + DEBUG_UART_TX_CLKSRC_REG)
mov r2, #DEBUG_UART_TX_CLKSRC
@@ -174,3 +315,70 @@ func plat_crash_console_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.
+ *
+ * r6 holds the address where the fault occurred.
+ * Filling lr with this value allows debuggers to reconstruct
+ * the backtrace.
+ * ----------------------------------------------------------
+ */
+func plat_panic_handler
+ mrs r0, cpsr
+ and r0, #MODE32_MASK
+ bl plat_report_exception
+ mov lr, r6
+ 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
+ dsb
+ isb
+ 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_low_power.c b/plat/st/stm32mp1/stm32mp1_low_power.c
new file mode 100644
index 000000000..fb975f5f6
--- /dev/null
+++ b/plat/st/stm32mp1/stm32mp1_low_power.c
@@ -0,0 +1,346 @@
+/*
+ * Copyright (c) 2017-2020, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <libfdt.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/arm/gic_common.h>
+#include <drivers/arm/gicv2.h>
+#include <drivers/delay_timer.h>
+#include <drivers/st/stm32_iwdg.h>
+#include <drivers/st/stm32_rtc.h>
+#include <drivers/st/stm32mp_clkfunc.h>
+#include <drivers/st/stm32mp_pmic.h>
+#include <drivers/st/stm32mp1_ddr_helpers.h>
+#include <drivers/st/stm32mp1_pwr.h>
+#include <drivers/st/stm32mp1_rcc.h>
+#include <drivers/st/stpmic1.h>
+#include <dt-bindings/clock/stm32mp1-clks.h>
+#include <dt-bindings/power/stm32mp1-power.h>
+#include <lib/mmio.h>
+#include <plat/common/platform.h>
+
+#include <boot_api.h>
+#include <stm32mp_common.h>
+#include <stm32mp_dt.h>
+#include <stm32mp1_context.h>
+#include <stm32mp1_low_power.h>
+#include <stm32mp1_private.h>
+
+static unsigned int gicc_pmr;
+static struct stm32_rtc_calendar sleep_time;
+static bool enter_cstop_done;
+static uint32_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 (pmic_set_lp_config(node_name) < 0) {
+ panic();
+ }
+
+ if (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();
+
+ stm32mp1_syscfg_disable_io_compensation();
+
+ /* Switch to Software Self-Refresh mode */
+ ddr_set_sr_mode(DDR_SSR_MODE);
+
+ 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();
+
+ 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) {
+ panic();
+ }
+
+ stm32mp_clk_enable(RTCAPB);
+
+ mmio_write_32(bkpr_core1_addr, 0);
+ mmio_write_32(bkpr_core1_magic, 0);
+
+ stm32mp1_clock_stopmode_save();
+
+ 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();
+ }
+
+ /* Keep retention and backup RAM content in standby */
+ mmio_setbits_32(pwr_base + PWR_CR2, PWR_CR2_BREN |
+ PWR_CR2_RREN);
+ while ((mmio_read_32(pwr_base + PWR_CR2) &
+ (PWR_CR2_BRRDY | PWR_CR2_RRRDY)) == 0U) {
+ ;
+ }
+ }
+
+ 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 pwr_base = stm32mp_pwr_base();
+ uintptr_t rcc_base = stm32mp_rcc_base();
+ unsigned long long stdby_time_in_ms;
+ struct stm32_rtc_calendar current_calendar;
+
+ if (!enter_cstop_done) {
+ return;
+ }
+
+ enter_cstop_done = false;
+
+ if (ddr_sw_self_refresh_exit() != 0) {
+ panic();
+ }
+
+ /* Switch to memorized Self-Refresh mode */
+ ddr_restore_sr_mode();
+
+ 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();
+
+ /* Disable retention and backup RAM content after stop */
+ mmio_clrbits_32(pwr_base + PWR_CR2, PWR_CR2_BREN | PWR_CR2_RREN);
+
+ /* Update STGEN counter with low power mode duration */
+ stm32_rtc_get_calendar(&current_calendar);
+
+ stdby_time_in_ms = stm32_rtc_diff_calendar(&current_calendar,
+ &sleep_time);
+ stm32mp_stgen_restore_counter(stm32_get_stgen_from_context(),
+ stdby_time_in_ms);
+
+ stm32mp1_syscfg_enable_io_compensation();
+
+ if (stm32mp1_clock_stopmode_resume() != 0) {
+ panic();
+ }
+}
+
+static void enter_shutdown(void)
+{
+ /* Set DDR in Self-refresh before shutting down the platform */
+ if (ddr_standby_sr_entry(NULL) != 0) {
+ WARN("DDR can't be set in Self-refresh mode\n");
+ }
+
+ 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_calib_set_wakeup(false);
+
+ while (interrupt == GIC_SPURIOUS_INTERRUPT &&
+ !stm32mp1_calib_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();
+ }
+}
diff --git a/plat/st/stm32mp1/stm32mp1_pm.c b/plat/st/stm32mp1/stm32mp1_pm.c
index cf9fa8e69..627d209da 100644
--- a/plat/st/stm32mp1/stm32mp1_pm.c
+++ b/plat/st/stm32mp1/stm32mp1_pm.c
@@ -10,17 +10,24 @@
#include <platform_def.h>
#include <arch_helpers.h>
+#include <bl32/sp_min/platform_sp_min.h>
#include <common/debug.h>
#include <drivers/arm/gic_common.h>
#include <drivers/arm/gicv2.h>
+#include <drivers/delay_timer.h>
#include <drivers/st/stm32mp1_clk.h>
+#include <drivers/st/stm32mp1_rcc.h>
#include <dt-bindings/clock/stm32mp1-clks.h>
#include <lib/mmio.h>
#include <lib/psci/psci.h>
#include <plat/common/platform.h>
+#include <stm32mp1_low_power.h>
+#include <stm32mp1_power_config.h>
+
static uintptr_t stm32_sec_entrypoint;
static uint32_t cntfrq_core0;
+static uintptr_t saved_entrypoint;
/*******************************************************************************
* STM32MP1 handler called when a CPU is about to enter standby.
@@ -33,11 +40,12 @@ static void stm32_cpu_standby(plat_local_state_t cpu_state)
assert(cpu_state == ARM_LOCAL_STATE_RET);
/*
- * Enter standby state
- * dsb is good practice before using wfi to enter low power states
+ * Enter standby state.
+ * Synchronize on memory accesses and instruction flow before the WFI
+ * instruction.
*/
- isb();
dsb();
+ isb();
while (interrupt == GIC_SPURIOUS_INTERRUPT) {
wfi();
@@ -64,13 +72,25 @@ static int stm32_pwr_domain_on(u_register_t mpidr)
uint32_t bkpr_core1_magic =
tamp_bkpr(BOOT_API_CORE1_MAGIC_NUMBER_TAMP_BCK_REG_IDX);
+ if (stm32mp_is_single_core()) {
+ return PSCI_E_INTERN_FAIL;
+ }
+
if (mpidr == current_cpu_mpidr) {
return PSCI_E_INVALID_PARAMS;
}
- if ((stm32_sec_entrypoint < STM32MP_SYSRAM_BASE) ||
- (stm32_sec_entrypoint > (STM32MP_SYSRAM_BASE +
- (STM32MP_SYSRAM_SIZE - 1)))) {
+ /* Reset backup register content */
+ mmio_write_32(bkpr_core1_magic, 0);
+
+ /* 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);
+
+ /* Only one valid entry point */
+ if (stm32_sec_entrypoint != (uintptr_t)&sp_min_warm_entrypoint) {
return PSCI_E_INVALID_ADDRESS;
}
@@ -107,7 +127,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);
}
/*******************************************************************************
@@ -118,7 +140,7 @@ static void stm32_pwr_domain_suspend(const psci_power_state_t *target_state)
******************************************************************************/
static void stm32_pwr_domain_on_finish(const psci_power_state_t *target_state)
{
- stm32mp1_gic_pcpu_init();
+ stm32_gic_pcpu_init();
write_cntfrq_el0(cntfrq_core0);
}
@@ -134,16 +156,59 @@ 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);
+
+ /*
+ * Synchronize on memory accesses and instruction flow before
+ * auto-reset from the WFI instruction.
+ */
+ dsb();
+ isb();
+ 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()) {
+ /* 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();
}
@@ -188,6 +253,8 @@ static int stm32_validate_ns_entrypoint(uintptr_t entrypoint)
return PSCI_E_INVALID_ADDRESS;
}
+ saved_entrypoint = entrypoint;
+
return PSCI_E_SUCCESS;
}
@@ -211,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.
@@ -227,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 000000000..079c5eece
--- /dev/null
+++ b/plat/st/stm32mp1/stm32mp1_power_config.c
@@ -0,0 +1,187 @@
+/*
+ * Copyright (c) 2017-2019, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <limits.h>
+
+#include <libfdt.h>
+
+#include <common/debug.h>
+#include <dt-bindings/power/stm32mp1-power.h>
+
+#include <stm32mp_dt.h>
+#include <stm32mp1_power_config.h>
+
+#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)
+{
+ return dt_get_node_by_compatible(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();
+ 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_allowed_mode(uint32_t soc_mode)
+{
+ assert(soc_mode < ARRAY_SIZE(stm32mp1_supported_soc_modes));
+
+ if ((soc_mode == STM32_PM_CSTOP_ALLOW_STANDBY_DDR_SR) &&
+ !stm32mp1_get_pm_domain_state(STM32MP1_PD_CORE_RET)) {
+ return false;
+ }
+
+ if ((soc_mode == STM32_PM_CSTOP_ALLOW_LPLV_STOP) &&
+ !stm32mp1_get_pm_domain_state(STM32MP1_PD_CORE)) {
+ return false;
+ }
+
+ 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;
+
+ while ((mode > STM32_PM_CSLEEP_RUN) && !is_allowed_mode(mode)) {
+ mode--;
+ }
+
+ 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
index e2dcd2af7..b94857bcb 100644
--- a/plat/st/stm32mp1/stm32mp1_private.c
+++ b/plat/st/stm32mp1/stm32mp1_private.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2015-2020, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -10,32 +10,75 @@
#include <platform_def.h>
+#include <arch_helpers.h>
+#include <drivers/arm/gicv2.h>
#include <drivers/st/stm32_iwdg.h>
+#include <drivers/st/stm32mp_dummy_regulator.h>
+#include <drivers/st/stm32mp_pmic.h>
+#include <drivers/st/stm32mp_regulator.h>
+#include <drivers/st/stm32mp_reset.h>
+#include <lib/mmio.h>
#include <lib/xlat_tables/xlat_tables_v2.h>
+#include <plat/common/platform.h>
/* Internal layout of the 32bit OTP word board_id */
#define BOARD_ID_BOARD_NB_MASK GENMASK(31, 16)
#define BOARD_ID_BOARD_NB_SHIFT 16
-#define BOARD_ID_VARIANT_MASK GENMASK(15, 12)
-#define BOARD_ID_VARIANT_SHIFT 12
+#define BOARD_ID_VARCPN_MASK GENMASK(15, 12)
+#define BOARD_ID_VARCPN_SHIFT 12
#define BOARD_ID_REVISION_MASK GENMASK(11, 8)
#define BOARD_ID_REVISION_SHIFT 8
+#define BOARD_ID_VARFG_MASK GENMASK(7, 4)
+#define BOARD_ID_VARFG_SHIFT 4
#define BOARD_ID_BOM_MASK GENMASK(3, 0)
#define BOARD_ID2NB(_id) (((_id) & BOARD_ID_BOARD_NB_MASK) >> \
BOARD_ID_BOARD_NB_SHIFT)
-#define BOARD_ID2VAR(_id) (((_id) & BOARD_ID_VARIANT_MASK) >> \
- BOARD_ID_VARIANT_SHIFT)
+#define BOARD_ID2VARCPN(_id) (((_id) & BOARD_ID_VARCPN_MASK) >> \
+ BOARD_ID_VARCPN_SHIFT)
#define BOARD_ID2REV(_id) (((_id) & BOARD_ID_REVISION_MASK) >> \
BOARD_ID_REVISION_SHIFT)
+#define BOARD_ID2VARFG(_id) (((_id) & BOARD_ID_VARFG_MASK) >> \
+ BOARD_ID_VARFG_SHIFT)
#define BOARD_ID2BOM(_id) ((_id) & BOARD_ID_BOM_MASK)
-#define MAP_SRAM MAP_REGION_FLAT(STM32MP_SYSRAM_BASE, \
+#if defined(IMAGE_BL2)
+#define MAP_SEC_SYSRAM MAP_REGION_FLAT(STM32MP_SYSRAM_BASE, \
STM32MP_SYSRAM_SIZE, \
MT_MEMORY | \
MT_RW | \
MT_SECURE | \
MT_EXECUTE_NEVER)
+#elif defined(IMAGE_BL32)
+#define MAP_SEC_SYSRAM MAP_REGION_FLAT(STM32MP_SEC_SYSRAM_BASE, \
+ STM32MP_SEC_SYSRAM_SIZE, \
+ MT_MEMORY | \
+ MT_RW | \
+ MT_SECURE | \
+ MT_EXECUTE_NEVER)
+
+/* Non-secure SYSRAM is used a uncached memory for SCMI message transfer */
+#define MAP_NS_SYSRAM MAP_REGION_FLAT(STM32MP_NS_SYSRAM_BASE, \
+ STM32MP_NS_SYSRAM_SIZE, \
+ MT_DEVICE | \
+ MT_RW | \
+ MT_NS | \
+ MT_EXECUTE_NEVER)
+#endif
+
+#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, \
@@ -53,7 +96,10 @@
#if defined(IMAGE_BL2)
static const mmap_region_t stm32mp1_mmap[] = {
- MAP_SRAM,
+ MAP_SEC_SYSRAM,
+#if STM32MP_USB_PROGRAMMER
+ MAP_SRAM_MCU,
+#endif
MAP_DEVICE1,
MAP_DEVICE2,
{0}
@@ -61,7 +107,8 @@ static const mmap_region_t stm32mp1_mmap[] = {
#endif
#if defined(IMAGE_BL32)
static const mmap_region_t stm32mp1_mmap[] = {
- MAP_SRAM,
+ MAP_SEC_SYSRAM,
+ MAP_NS_SYSRAM,
MAP_DEVICE1,
MAP_DEVICE2,
{0}
@@ -70,10 +117,177 @@ static const mmap_region_t stm32mp1_mmap[] = {
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;
- enable_mmu_svc_mon(0);
+ return stm32mp1_uart_addresses[instance_nb - 1];
+}
+#endif
+
+#define ARM_CNTXCTL_IMASK BIT(1)
+
+void stm32mp_mask_timer(void)
+{
+ /* Mask timer interrupts */
+ write_cntp_ctl(read_cntp_ctl() | ARM_CNTXCTL_IMASK);
+ write_cntv_ctl(read_cntv_ctl() | ARM_CNTXCTL_IMASK);
+}
+
+void __dead2 stm32mp_wait_cpu_reset(void)
+{
+ uint32_t id;
+
+ dcsw_op_all(DC_OP_CISW);
+ write_sctlr(read_sctlr() & ~SCTLR_C_BIT);
+ dcsw_op_all(DC_OP_CISW);
+ __asm__("clrex");
+
+ dsb();
+ isb();
+
+ for ( ; ; ) {
+ 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);
+
+ wfi();
+ }
+}
+
+/*
+ * tzc_source_ip contains the TZC transaction source IPs that need to be reset
+ * before a C-A7 subsystem is reset (i.e. independent reset):
+ * - C-A7 subsystem is reset separately later in the sequence,
+ * - C-M4 subsystem is not concerned here,
+ * - DAP is excluded for debug purpose,
+ * - IPs are stored with their ETZPC IDs (STM32MP1_ETZPC_MAX_ID if not
+ * applicable) because some of them need to be reset only if they are not
+ * configured in MCU isolation mode inside ETZPC device tree.
+ */
+struct tzc_source_ip {
+ uint32_t reset_id;
+ uint32_t clock_id;
+ uint32_t decprot_id;
+};
+
+#define _TZC_FIXED(res, clk) \
+ { \
+ .reset_id = (res), \
+ .clock_id = (clk), \
+ .decprot_id = STM32MP1_ETZPC_MAX_ID, \
+ }
+
+#define _TZC_COND(res, clk, decprot) \
+ { \
+ .reset_id = (res), \
+ .clock_id = (clk), \
+ .decprot_id = (decprot), \
+ }
+
+static const struct tzc_source_ip tzc_source_ip[] = {
+ _TZC_FIXED(LTDC_R, LTDC_PX),
+ _TZC_FIXED(GPU_R, GPU),
+ _TZC_FIXED(USBH_R, USBH),
+ _TZC_FIXED(SDMMC1_R, SDMMC1_K),
+ _TZC_FIXED(SDMMC2_R, SDMMC2_K),
+ _TZC_FIXED(MDMA_R, MDMA),
+ _TZC_COND(USBO_R, USBO_K, STM32MP1_ETZPC_OTG_ID),
+ _TZC_COND(SDMMC3_R, SDMMC3_K, STM32MP1_ETZPC_SDMMC3_ID),
+ _TZC_COND(ETHMAC_R, ETHMAC, STM32MP1_ETZPC_ETH_ID),
+ _TZC_COND(DMA1_R, DMA1, STM32MP1_ETZPC_DMA1_ID),
+ _TZC_COND(DMA2_R, DMA2, STM32MP1_ETZPC_DMA2_ID),
+};
+
+#define TIMEOUT_US_1MS U(1000)
+
+void __dead2 stm32mp_plat_reset(int cpu)
+{
+ uint32_t reg = RCC_MP_GRSTCSETR_MPUP0RST;
+ uint32_t id;
+
+ /* Mask timer interrupts */
+ stm32mp_mask_timer();
+
+ for (id = 0U; id < ARRAY_SIZE(tzc_source_ip); id++) {
+ if ((!stm32mp_clk_is_enabled(tzc_source_ip[id].clock_id)) ||
+ ((tzc_source_ip[id].decprot_id != STM32MP1_ETZPC_MAX_ID) &&
+ (etzpc_get_decprot(tzc_source_ip[id].decprot_id) ==
+ TZPC_DECPROT_MCU_ISOLATION))) {
+ continue;
+ }
+
+ if (tzc_source_ip[id].reset_id != GPU_R) {
+ uint32_t reset = tzc_source_ip[id].reset_id;
+
+ if (stm32mp_reset_assert_to(reset, TIMEOUT_US_1MS)) {
+ panic();
+ }
+ if (stm32mp_reset_deassert_to(reset, TIMEOUT_US_1MS)) {
+ panic();
+ }
+ } else {
+ /* GPU reset automatically cleared by hardware */
+ mmio_setbits_32(stm32mp_rcc_base() + RCC_AHB6RSTSETR,
+ RCC_AHB6RSTSETR_GPURST);
+ }
+ }
+
+ if (!stm32mp_is_single_core()) {
+ 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;
+ }
+
+ 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);
+
+ mmio_write_32(stm32mp_rcc_base() + RCC_MP_GRSTCSETR, reg);
+
+ stm32mp_wait_cpu_reset();
}
unsigned long stm32_get_gpio_bank_clock(unsigned int bank)
@@ -87,59 +301,133 @@ unsigned long stm32_get_gpio_bank_clock(unsigned int bank)
return GPIOA + (bank - GPIO_BANK_A);
}
-static int get_part_number(uint32_t *part_nb)
+int stm32_get_otp_index(const char *otp_name, uint32_t *otp_idx,
+ uint32_t *otp_len)
{
- uint32_t part_number;
- uint32_t dev_id;
+ assert(otp_name != NULL);
+ assert(otp_idx != NULL);
- if (stm32mp1_dbgmcu_get_chip_dev_id(&dev_id) < 0) {
+ if (bsec_find_otp_name_in_dt(otp_name, otp_idx, otp_len) != BSEC_OK) {
return -1;
}
- if (bsec_shadow_read_otp(&part_number, PART_NUMBER_OTP) != BSEC_OK) {
- ERROR("BSEC: PART_NUMBER_OTP Error\n");
+ return 0;
+}
+
+int stm32_get_otp_value(const char *otp_name, uint32_t *otp_val)
+{
+ uint32_t otp_idx;
+
+ assert(otp_name != NULL);
+ assert(otp_val != NULL);
+
+ if (stm32_get_otp_index(otp_name, &otp_idx, NULL) != 0) {
return -1;
}
+ if (stm32_get_otp_value_from_idx(otp_idx, otp_val) != 0) {
+ ERROR("BSEC: %s Read Error\n", otp_name);
+ return -1;
+ }
+
+ return 0;
+}
+
+int stm32_get_otp_value_from_idx(const uint32_t otp_idx, uint32_t *otp_val)
+{
+ int ret = BSEC_NOT_SUPPORTED;
+
+ assert(otp_val != NULL);
+
+#if defined(IMAGE_BL2)
+ ret = bsec_shadow_read_otp(otp_val, otp_idx);
+#elif defined(IMAGE_BL32)
+ ret = bsec_read_otp(otp_val, otp_idx);
+#else
+#error "Not supported"
+#endif
+ if (ret != BSEC_OK) {
+ ERROR("BSEC: idx=%d Read Error\n", otp_idx);
+ return -1;
+ }
+
+ return 0;
+}
+
+static uint32_t get_part_number(void)
+{
+ static uint32_t part_number;
+ uint32_t dev_id;
+
+ if (part_number != 0U) {
+ return part_number;
+ }
+
+ if (stm32mp1_dbgmcu_get_chip_dev_id(&dev_id) < 0) {
+ INFO("Use default chip ID, debug disabled\n");
+ dev_id = STM32MP1_CHIP_ID;
+ }
+
+ if (stm32_get_otp_value(PART_NUMBER_OTP, &part_number) != 0) {
+ panic();
+ }
+
part_number = (part_number & PART_NUMBER_OTP_PART_MASK) >>
PART_NUMBER_OTP_PART_SHIFT;
- *part_nb = part_number | (dev_id << 16);
+ part_number |= dev_id << 16;
- return 0;
+ return part_number;
}
-static int get_cpu_package(uint32_t *cpu_package)
+static uint32_t get_cpu_package(void)
{
uint32_t package;
- if (bsec_shadow_read_otp(&package, PACKAGE_OTP) != BSEC_OK) {
- ERROR("BSEC: PACKAGE_OTP Error\n");
- return -1;
+ if (stm32_get_otp_value(PACKAGE_OTP, &package) != 0) {
+ panic();
}
- *cpu_package = (package & PACKAGE_OTP_PKG_MASK) >>
+ package = (package & PACKAGE_OTP_PKG_MASK) >>
PACKAGE_OTP_PKG_SHIFT;
- return 0;
+ return package;
+}
+
+bool stm32mp_supports_cpu_opp(uint32_t opp_id)
+{
+ uint32_t id;
+
+ switch (opp_id) {
+ case PLAT_OPP_ID1:
+ case PLAT_OPP_ID2:
+ id = opp_id;
+ break;
+ default:
+ return false;
+ }
+
+ switch (get_part_number()) {
+ case STM32MP157F_PART_NB:
+ case STM32MP157D_PART_NB:
+ case STM32MP153F_PART_NB:
+ case STM32MP153D_PART_NB:
+ case STM32MP151F_PART_NB:
+ case STM32MP151D_PART_NB:
+ return true;
+ default:
+ return id == PLAT_OPP_ID1;
+ }
}
void stm32mp_print_cpuinfo(void)
{
const char *cpu_s, *cpu_r, *pkg;
- uint32_t part_number;
- uint32_t cpu_package;
uint32_t chip_dev_id;
int ret;
/* MPUs Part Numbers */
- ret = get_part_number(&part_number);
- if (ret < 0) {
- WARN("Cannot get part number\n");
- return;
- }
-
- switch (part_number) {
+ switch (get_part_number()) {
case STM32MP157C_PART_NB:
cpu_s = "157C";
break;
@@ -158,19 +446,31 @@ void stm32mp_print_cpuinfo(void)
case STM32MP151A_PART_NB:
cpu_s = "151A";
break;
+ case STM32MP157F_PART_NB:
+ cpu_s = "157F";
+ break;
+ case STM32MP157D_PART_NB:
+ cpu_s = "157D";
+ break;
+ case STM32MP153F_PART_NB:
+ cpu_s = "153F";
+ break;
+ case STM32MP153D_PART_NB:
+ cpu_s = "153D";
+ break;
+ case STM32MP151F_PART_NB:
+ cpu_s = "151F";
+ break;
+ case STM32MP151D_PART_NB:
+ cpu_s = "151D";
+ break;
default:
cpu_s = "????";
break;
}
/* Package */
- ret = get_cpu_package(&cpu_package);
- if (ret < 0) {
- WARN("Cannot get CPU package\n");
- return;
- }
-
- switch (cpu_package) {
+ switch (get_cpu_package()) {
case PKG_AA_LFBGA448:
pkg = "AA";
break;
@@ -191,14 +491,16 @@ void stm32mp_print_cpuinfo(void)
/* REVISION */
ret = stm32mp1_dbgmcu_get_chip_version(&chip_dev_id);
if (ret < 0) {
- WARN("Cannot get CPU version\n");
- return;
+ INFO("Cannot get CPU version, debug disabled\n");
}
switch (chip_dev_id) {
case STM32MP1_REV_B:
cpu_r = "B";
break;
+ case STM32MP1_REV_Z:
+ cpu_r = "Z";
+ break;
default:
cpu_r = "?";
break;
@@ -209,35 +511,9 @@ void stm32mp_print_cpuinfo(void)
void stm32mp_print_boardinfo(void)
{
- uint32_t board_id;
- uint32_t board_otp;
- int bsec_node, bsec_board_id_node;
- void *fdt;
- const fdt32_t *cuint;
-
- if (fdt_get_address(&fdt) == 0) {
- panic();
- }
-
- bsec_node = fdt_node_offset_by_compatible(fdt, -1, DT_BSEC_COMPAT);
- if (bsec_node < 0) {
- return;
- }
-
- bsec_board_id_node = fdt_subnode_offset(fdt, bsec_node, "board_id");
- if (bsec_board_id_node <= 0) {
- return;
- }
-
- cuint = fdt_getprop(fdt, bsec_board_id_node, "reg", NULL);
- if (cuint == NULL) {
- panic();
- }
+ uint32_t board_id = 0;
- board_otp = fdt32_to_cpu(*cuint) / sizeof(uint32_t);
-
- if (bsec_shadow_read_otp(&board_id, board_otp) != BSEC_OK) {
- ERROR("BSEC: PART_NUMBER_OTP Error\n");
+ if (stm32_get_otp_value(BOARD_ID_OTP, &board_id) != 0) {
return;
}
@@ -246,9 +522,10 @@ void stm32mp_print_boardinfo(void)
rev[0] = BOARD_ID2REV(board_id) - 1 + 'A';
rev[1] = '\0';
- NOTICE("Board: MB%04x Var%d Rev.%s-%02d\n",
+ NOTICE("Board: MB%04x Var%d.%d Rev.%s-%02d\n",
BOARD_ID2NB(board_id),
- BOARD_ID2VAR(board_id),
+ BOARD_ID2VARCPN(board_id),
+ BOARD_ID2VARFG(board_id),
rev,
BOARD_ID2BOM(board_id));
}
@@ -257,25 +534,15 @@ void stm32mp_print_boardinfo(void)
/* Return true when SoC provides a single Cortex-A7 core, and false otherwise */
bool stm32mp_is_single_core(void)
{
- uint32_t part_number;
- bool ret = false;
-
- if (get_part_number(&part_number) < 0) {
- ERROR("Invalid part number, assume single core chip");
- return true;
- }
-
- switch (part_number) {
+ switch (get_part_number()) {
case STM32MP151A_PART_NB:
case STM32MP151C_PART_NB:
- ret = true;
- break;
-
+ case STM32MP151D_PART_NB:
+ case STM32MP151F_PART_NB:
+ return true;
default:
- break;
+ return false;
}
-
- return ret;
}
/* Return true when device is in closed state */
@@ -283,12 +550,27 @@ bool stm32mp_is_closed_device(void)
{
uint32_t value;
- if ((bsec_shadow_register(DATA0_OTP) != BSEC_OK) ||
- (bsec_read_otp(&value, DATA0_OTP) != BSEC_OK)) {
+ if (stm32_get_otp_value(CFG0_OTP, &value) != 0) {
return true;
}
- return (value & DATA0_OTP_SECURED) == DATA0_OTP_SECURED;
+ return (value & CFG0_CLOSED_DEVICE) == CFG0_CLOSED_DEVICE;
+}
+
+/* Return true when device supports secure boot */
+bool stm32mp_is_auth_supported(void)
+{
+ switch (get_part_number()) {
+ case STM32MP151C_PART_NB:
+ case STM32MP151F_PART_NB:
+ case STM32MP153C_PART_NB:
+ case STM32MP153F_PART_NB:
+ case STM32MP157C_PART_NB:
+ case STM32MP157F_PART_NB:
+ return true;
+ default:
+ return false;
+ }
}
uint32_t stm32_iwdg_get_instance(uintptr_t base)
@@ -308,13 +590,7 @@ uint32_t stm32_iwdg_get_otp_config(uint32_t iwdg_inst)
uint32_t iwdg_cfg = 0U;
uint32_t otp_value;
-#if defined(IMAGE_BL2)
- if (bsec_shadow_register(HW2_OTP) != BSEC_OK) {
- panic();
- }
-#endif
-
- if (bsec_read_otp(&otp_value, HW2_OTP) != BSEC_OK) {
+ if (stm32_get_otp_value(HW2_OTP, &otp_value) != 0) {
panic();
}
@@ -336,32 +612,82 @@ uint32_t stm32_iwdg_get_otp_config(uint32_t iwdg_inst)
#if defined(IMAGE_BL2)
uint32_t stm32_iwdg_shadow_update(uint32_t iwdg_inst, uint32_t flags)
{
+ uint32_t otp_value;
uint32_t otp;
uint32_t result;
- if (bsec_shadow_read_otp(&otp, HW2_OTP) != BSEC_OK) {
+ if (stm32_get_otp_index(HW2_OTP, &otp, NULL) != 0) {
panic();
}
- if ((flags & IWDG_DISABLE_ON_STOP) != 0U) {
- otp |= BIT(iwdg_inst + HW2_OTP_IWDG_FZ_STOP_POS);
+ if (stm32_get_otp_value(HW2_OTP, &otp_value) != 0) {
+ panic();
+ }
+
+ if ((flags & IWDG_DISABLE_ON_STOP) != 0) {
+ otp_value |= BIT(iwdg_inst + HW2_OTP_IWDG_FZ_STOP_POS);
}
- if ((flags & IWDG_DISABLE_ON_STANDBY) != 0U) {
- otp |= BIT(iwdg_inst + HW2_OTP_IWDG_FZ_STANDBY_POS);
+ if ((flags & IWDG_DISABLE_ON_STANDBY) != 0) {
+ otp_value |= BIT(iwdg_inst + HW2_OTP_IWDG_FZ_STANDBY_POS);
}
- result = bsec_write_otp(otp, HW2_OTP);
+ result = bsec_write_otp(otp_value, 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)) {
+ if ((bsec_set_sr_lock(otp) != BSEC_OK) ||
+ (bsec_set_sw_lock(otp) != BSEC_OK)) {
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();
+ }
+}
+
+int plat_bind_regulator(struct stm32mp_regulator *regu)
+{
+ void *fdt;
+ int regu_node;
+
+ if (fdt_get_address(&fdt) == 0) {
+ return false;
+ }
+
+ if ((dt_pmic_status() > 0) && is_pmic_regulator(regu)) {
+ bind_pmic_regulator(regu);
+ } else {
+ bind_dummy_regulator(regu);
+ }
+
+ regu_node = fdt_node_offset_by_phandle(fdt, regu->id);
+ if (fdt_getprop(fdt, regu_node, "regulator-always-on", NULL) != NULL) {
+ regu->always_on = true;
+ }
+
+ return 0;
+}
diff --git a/plat/st/stm32mp1/stm32mp1_scmi.c b/plat/st/stm32mp1/stm32mp1_scmi.c
new file mode 100644
index 000000000..c1e91538f
--- /dev/null
+++ b/plat/st/stm32mp1/stm32mp1_scmi.c
@@ -0,0 +1,582 @@
+/*
+ * Copyright (c) 2019-2020, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <assert.h>
+#include <cdefs.h>
+#include <stdint.h>
+
+#include <platform_def.h>
+
+#include <drivers/st/scmi-msg.h>
+#include <drivers/st/scmi.h>
+#include <drivers/st/stm32mp1_clk.h>
+#include <drivers/st/stm32mp_reset.h>
+#include <dt-bindings/clock/stm32mp1-clks.h>
+#include <dt-bindings/reset/stm32mp1-resets.h>
+#include <lib/cassert.h>
+#include <lib/utils.h>
+
+#define TIMEOUT_US_1MS 1000U
+
+#define SCMI_CLOCK_NAME_SIZE 16U
+#define SCMI_RD_NAME_SIZE 16U
+
+/*
+ * struct stm32_scmi_clk - Data for the exposed clock
+ * @clock_id: Clock identifier in RCC clock driver
+ * @name: Clock string ID exposed to agent
+ * @enabled: State of the SCMI clock
+ */
+struct stm32_scmi_clk {
+ unsigned long clock_id;
+ const char *name;
+ bool enabled;
+};
+
+/*
+ * struct stm32_scmi_rd - Data for the exposed reset controller
+ * @reset_id: Reset identifier in RCC reset driver
+ * @name: Reset string ID exposed to agent
+ */
+struct stm32_scmi_rd {
+ unsigned long reset_id;
+ const char *name;
+};
+
+/* Locate all non-secure SMT message buffers in last page of SYSRAM */
+#define SMT_BUFFER_BASE STM32MP_NS_SYSRAM_BASE
+#define SMT_SLOT_SIZE 0x200U
+#define SMT_BUFFER0_BASE SMT_BUFFER_BASE
+#define SMT_BUFFER1_BASE (SMT_BUFFER_BASE + SMT_SLOT_SIZE)
+#define SMT_BUFFER_END (SMT_BUFFER1_BASE + SMT_BUF_SLOT_SIZE)
+
+CASSERT(SMT_BUFFER_END < (STM32MP_NS_SYSRAM_BASE + STM32MP_NS_SYSRAM_SIZE),
+ assert_scmi_shm_fits_in_non_secure_sysram);
+
+static struct scmi_msg_channel scmi_channel[] = {
+ [0] = {
+ .shm_addr = SMT_BUFFER0_BASE,
+ .shm_size = SMT_BUF_SLOT_SIZE,
+ },
+ [1] = {
+ .shm_addr = SMT_BUFFER1_BASE,
+ .shm_size = SMT_BUF_SLOT_SIZE,
+ },
+};
+
+struct scmi_msg_channel *plat_scmi_get_channel(unsigned int agent_id)
+{
+ assert(agent_id < ARRAY_SIZE(scmi_channel));
+
+ return &scmi_channel[agent_id];
+}
+
+#define CLOCK_CELL(_scmi_id, _id, _name, _init_enabled) \
+ [_scmi_id] = { \
+ .clock_id = _id, \
+ .name = _name, \
+ .enabled = _init_enabled, \
+ }
+
+static struct stm32_scmi_clk stm32_scmi0_clock[] = {
+ CLOCK_CELL(CK_SCMI0_HSE, CK_HSE, "ck_hse", true),
+ CLOCK_CELL(CK_SCMI0_HSI, CK_HSI, "ck_hsi", true),
+ CLOCK_CELL(CK_SCMI0_CSI, CK_CSI, "ck_csi", true),
+ CLOCK_CELL(CK_SCMI0_LSE, CK_LSE, "ck_lse", true),
+ CLOCK_CELL(CK_SCMI0_LSI, CK_LSI, "ck_lsi", true),
+ CLOCK_CELL(CK_SCMI0_PLL2_Q, PLL2_Q, "pll2_q", true),
+ CLOCK_CELL(CK_SCMI0_PLL2_R, PLL2_R, "pll2_r", true),
+ CLOCK_CELL(CK_SCMI0_MPU, CK_MPU, "ck_mpu", true),
+ CLOCK_CELL(CK_SCMI0_AXI, CK_AXI, "ck_axi", true),
+ CLOCK_CELL(CK_SCMI0_BSEC, BSEC, "bsec", true),
+ CLOCK_CELL(CK_SCMI0_CRYP1, CRYP1, "cryp1", false),
+ CLOCK_CELL(CK_SCMI0_GPIOZ, GPIOZ, "gpioz", false),
+ CLOCK_CELL(CK_SCMI0_HASH1, HASH1, "hash1", false),
+ CLOCK_CELL(CK_SCMI0_I2C4, I2C4_K, "i2c4_k", false),
+ CLOCK_CELL(CK_SCMI0_I2C6, I2C6_K, "i2c6_k", false),
+ CLOCK_CELL(CK_SCMI0_IWDG1, IWDG1, "iwdg1", false),
+ CLOCK_CELL(CK_SCMI0_RNG1, RNG1_K, "rng1_k", true),
+ CLOCK_CELL(CK_SCMI0_RTC, RTC, "ck_rtc", true),
+ CLOCK_CELL(CK_SCMI0_RTCAPB, RTCAPB, "rtcapb", true),
+ CLOCK_CELL(CK_SCMI0_SPI6, SPI6_K, "spi6_k", false),
+ CLOCK_CELL(CK_SCMI0_USART1, USART1_K, "usart1_k", false),
+};
+
+static struct stm32_scmi_clk stm32_scmi1_clock[] = {
+ CLOCK_CELL(CK_SCMI1_PLL3_Q, PLL3_Q, "pll3_q", true),
+ CLOCK_CELL(CK_SCMI1_PLL3_R, PLL3_R, "pll3_r", true),
+ CLOCK_CELL(CK_SCMI1_MCU, CK_MCU, "ck_mcu", false),
+};
+
+#define RESET_CELL(_scmi_id, _id, _name) \
+ [_scmi_id] = { \
+ .reset_id = _id, \
+ .name = _name, \
+ }
+
+static struct stm32_scmi_rd stm32_scmi0_reset_domain[] = {
+ RESET_CELL(RST_SCMI0_SPI6, SPI6_R, "spi6"),
+ RESET_CELL(RST_SCMI0_I2C4, I2C4_R, "i2c4"),
+ RESET_CELL(RST_SCMI0_I2C6, I2C6_R, "i2c6"),
+ RESET_CELL(RST_SCMI0_USART1, USART1_R, "usart1"),
+ RESET_CELL(RST_SCMI0_STGEN, STGEN_R, "stgen"),
+ RESET_CELL(RST_SCMI0_GPIOZ, GPIOZ_R, "gpioz"),
+ RESET_CELL(RST_SCMI0_CRYP1, CRYP1_R, "cryp1"),
+ RESET_CELL(RST_SCMI0_HASH1, HASH1_R, "hash1"),
+ RESET_CELL(RST_SCMI0_RNG1, RNG1_R, "rng1"),
+ RESET_CELL(RST_SCMI0_MDMA, MDMA_R, "mdma"),
+ RESET_CELL(RST_SCMI0_MCU, MCU_R, "mcu"),
+};
+
+struct scmi_agent_resources {
+ struct stm32_scmi_clk *clock;
+ size_t clock_count;
+ struct stm32_scmi_rd *rd;
+ size_t rd_count;
+};
+
+static const struct scmi_agent_resources agent_resources[] = {
+ [0] = {
+ .clock = stm32_scmi0_clock,
+ .clock_count = ARRAY_SIZE(stm32_scmi0_clock),
+ .rd = stm32_scmi0_reset_domain,
+ .rd_count = ARRAY_SIZE(stm32_scmi0_reset_domain),
+ },
+ [1] = {
+ .clock = stm32_scmi1_clock,
+ .clock_count = ARRAY_SIZE(stm32_scmi1_clock),
+ },
+};
+
+static const struct scmi_agent_resources *find_resource(unsigned int agent_id)
+{
+ assert(agent_id < ARRAY_SIZE(agent_resources));
+
+ return &agent_resources[agent_id];
+}
+
+#if ENABLE_ASSERTIONS
+static size_t plat_scmi_protocol_count_paranoid(void)
+{
+ unsigned int n = 0U;
+ unsigned int count = 0U;
+
+ for (n = 0U; n < ARRAY_SIZE(agent_resources); n++) {
+ if (agent_resources[n].clock_count) {
+ count++;
+ break;
+ }
+ }
+
+ for (n = 0U; n < ARRAY_SIZE(agent_resources); n++) {
+ if (agent_resources[n].rd_count) {
+ count++;
+ break;
+ }
+ }
+
+ return count;
+}
+#endif
+
+static const char vendor[] = "ST";
+static const char sub_vendor[] = "";
+
+const char *plat_scmi_vendor_name(void)
+{
+ return vendor;
+}
+
+const char *plat_scmi_sub_vendor_name(void)
+{
+ return sub_vendor;
+}
+
+/* Currently supporting Clocks and Reset Domains */
+static const uint8_t plat_protocol_list[] = {
+ SCMI_PROTOCOL_ID_CLOCK,
+ SCMI_PROTOCOL_ID_RESET_DOMAIN,
+ 0U /* Null termination */
+};
+
+size_t plat_scmi_protocol_count(void)
+{
+ const size_t count = ARRAY_SIZE(plat_protocol_list) - 1U;
+
+ assert(count == plat_scmi_protocol_count_paranoid());
+
+ return count;
+}
+
+const uint8_t *plat_scmi_protocol_list(unsigned int agent_id __unused)
+{
+ assert(plat_scmi_protocol_count_paranoid() ==
+ (ARRAY_SIZE(plat_protocol_list) - 1U));
+
+ return plat_protocol_list;
+}
+
+/*
+ * Platform SCMI clocks
+ */
+static struct stm32_scmi_clk *find_clock(unsigned int agent_id,
+ unsigned int scmi_id)
+{
+ const struct scmi_agent_resources *resource = find_resource(agent_id);
+ size_t n = 0U;
+
+ if (resource != NULL) {
+ for (n = 0U; n < resource->clock_count; n++) {
+ if (n == scmi_id) {
+ return &resource->clock[n];
+ }
+ }
+ }
+
+ return NULL;
+}
+
+size_t plat_scmi_clock_count(unsigned int agent_id)
+{
+ const struct scmi_agent_resources *resource = find_resource(agent_id);
+
+ if (resource == NULL) {
+ return 0U;
+ }
+
+ return resource->clock_count;
+}
+
+const char *plat_scmi_clock_get_name(unsigned int agent_id,
+ unsigned int scmi_id)
+{
+ struct stm32_scmi_clk *clock = find_clock(agent_id, scmi_id);
+
+ if ((clock == NULL) ||
+ !stm32mp_nsec_can_access_clock(clock->clock_id)) {
+ return NULL;
+ }
+
+ return clock->name;
+}
+
+int32_t plat_scmi_clock_rates_array(unsigned int agent_id, unsigned int scmi_id,
+ unsigned long *array, size_t *nb_elts)
+{
+ /*
+ * Do not expose clock rates by array since not supported by
+ * Linux kernel
+ */
+ return SCMI_NOT_SUPPORTED;
+}
+
+int32_t plat_scmi_clock_rates_by_step(unsigned int agent_id,
+ unsigned int scmi_id,
+ unsigned long *array)
+{
+ struct stm32_scmi_clk *clock = find_clock(agent_id, scmi_id);
+
+ if (clock == NULL) {
+ return SCMI_NOT_FOUND;
+ }
+
+ if (!stm32mp_nsec_can_access_clock(clock->clock_id)) {
+ return SCMI_DENIED;
+ }
+
+ switch (scmi_id) {
+ case CK_SCMI0_MPU:
+ /*
+ * Pretend we support all rates for MPU clock,
+ * CLOCK_RATE_SET will reject unsupported rates.
+ */
+ array[0] = 0U;
+ array[1] = UINT32_MAX;
+ array[2] = 1U;
+ break;
+ default:
+ array[0] = stm32mp_clk_get_rate(clock->clock_id);
+ array[1] = array[0];
+ array[2] = 0U;
+ break;
+ }
+ return SCMI_SUCCESS;
+}
+
+int32_t plat_scmi_clock_set_rate(unsigned int agent_id,
+ unsigned int scmi_id,
+ unsigned long rate)
+{
+ int ret;
+ /* find_rd() returns NULL if clock exists for denied the agent */
+ struct stm32_scmi_clk *clock = find_clock(agent_id, scmi_id);
+
+ if (clock == NULL) {
+ return SCMI_NOT_FOUND;
+ }
+
+ if (!stm32mp_nsec_can_access_clock(clock->clock_id)) {
+ return SCMI_DENIED;
+ }
+
+ switch (scmi_id) {
+ case CK_SCMI0_MPU:
+ ret = stm32mp1_set_opp_khz(rate / 1000UL);
+ if (ret != 0) {
+ return SCMI_INVALID_PARAMETERS;
+ }
+ break;
+ default:
+ if (rate != stm32mp_clk_get_rate(clock->clock_id)) {
+ return SCMI_INVALID_PARAMETERS;
+ }
+ break;
+ }
+
+ return SCMI_SUCCESS;
+}
+
+unsigned long plat_scmi_clock_get_rate(unsigned int agent_id,
+ unsigned int scmi_id)
+{
+ struct stm32_scmi_clk *clock = find_clock(agent_id, scmi_id);
+
+ if ((clock == NULL) ||
+ !stm32mp_nsec_can_access_clock(clock->clock_id)) {
+ return 0U;
+ }
+
+ return stm32mp_clk_get_rate(clock->clock_id);
+}
+
+int32_t plat_scmi_clock_get_state(unsigned int agent_id, unsigned int scmi_id)
+{
+ struct stm32_scmi_clk *clock = find_clock(agent_id, scmi_id);
+
+ if ((clock == NULL) ||
+ !stm32mp_nsec_can_access_clock(clock->clock_id)) {
+ return 0U;
+ }
+
+ return (int32_t)clock->enabled;
+}
+
+int32_t plat_scmi_clock_set_state(unsigned int agent_id, unsigned int scmi_id,
+ bool enable_not_disable)
+{
+ struct stm32_scmi_clk *clock = find_clock(agent_id, scmi_id);
+
+ if (clock == NULL) {
+ return SCMI_NOT_FOUND;
+ }
+
+ if (!stm32mp_nsec_can_access_clock(clock->clock_id)) {
+ return SCMI_DENIED;
+ }
+
+ if (enable_not_disable) {
+ if (!clock->enabled) {
+ VERBOSE("SCMI clock %u enable\n", scmi_id);
+ stm32mp_clk_enable(clock->clock_id);
+ clock->enabled = true;
+ }
+ } else {
+ if (clock->enabled) {
+ VERBOSE("SCMI clock %u disable\n", scmi_id);
+ stm32mp_clk_disable(clock->clock_id);
+ clock->enabled = false;
+ }
+ }
+
+ return SCMI_SUCCESS;
+}
+
+/*
+ * Platform SCMI reset domains
+ */
+static struct stm32_scmi_rd *find_rd(unsigned int agent_id,
+ unsigned int scmi_id)
+{
+ const struct scmi_agent_resources *resource = find_resource(agent_id);
+ size_t n;
+
+ if (resource != NULL) {
+ for (n = 0U; n < resource->rd_count; n++) {
+ if (n == scmi_id) {
+ return &resource->rd[n];
+ }
+ }
+ }
+
+ return NULL;
+}
+
+const char *plat_scmi_rd_get_name(unsigned int agent_id, unsigned int scmi_id)
+{
+ const struct stm32_scmi_rd *rd = find_rd(agent_id, scmi_id);
+
+ if (rd == NULL) {
+ return NULL;
+ }
+
+ return rd->name;
+}
+
+size_t plat_scmi_rd_count(unsigned int agent_id)
+{
+ const struct scmi_agent_resources *resource = find_resource(agent_id);
+
+ if (resource == NULL) {
+ return 0U;
+ }
+
+ return resource->rd_count;
+}
+
+int32_t plat_scmi_rd_autonomous(unsigned int agent_id, unsigned int scmi_id,
+ uint32_t state)
+{
+ const struct stm32_scmi_rd *rd = find_rd(agent_id, scmi_id);
+
+ if (rd == NULL) {
+ return SCMI_NOT_FOUND;
+ }
+
+ if (!stm32mp_nsec_can_access_reset(rd->reset_id)) {
+ return SCMI_DENIED;
+ }
+
+ /* Supports only reset with context loss */
+ if (state != 0U) {
+ return SCMI_NOT_SUPPORTED;
+ }
+
+ VERBOSE("SCMI reset %lu cycle\n", rd->reset_id);
+
+ if (stm32mp_reset_assert_to(rd->reset_id, TIMEOUT_US_1MS)) {
+ return SCMI_HARDWARE_ERROR;
+ }
+
+ if (stm32mp_reset_deassert_to(rd->reset_id, TIMEOUT_US_1MS)) {
+ return SCMI_HARDWARE_ERROR;
+ }
+
+ return SCMI_SUCCESS;
+}
+
+int32_t plat_scmi_rd_set_state(unsigned int agent_id, unsigned int scmi_id,
+ bool assert_not_deassert)
+{
+ const struct stm32_scmi_rd *rd = find_rd(agent_id, scmi_id);
+
+ if (rd == NULL) {
+ return SCMI_NOT_FOUND;
+ }
+
+ if (!stm32mp_nsec_can_access_reset(rd->reset_id)) {
+ return SCMI_DENIED;
+ }
+
+ if (assert_not_deassert) {
+ VERBOSE("SCMI reset %lu set\n", rd->reset_id);
+ stm32mp_reset_set(rd->reset_id);
+ } else {
+ VERBOSE("SCMI reset %lu release\n", rd->reset_id);
+ stm32mp_reset_release(rd->reset_id);
+ }
+
+ return SCMI_SUCCESS;
+}
+
+/*
+ * Initialize platform SCMI resources
+ */
+void stm32mp1_init_scmi_server(void)
+{
+ size_t i;
+ size_t j;
+
+ for (i = 0U; i < ARRAY_SIZE(scmi_channel); i++) {
+ scmi_smt_init_agent_channel(&scmi_channel[i]);
+ }
+
+ for (i = 0U; i < ARRAY_SIZE(agent_resources); i++) {
+ const struct scmi_agent_resources *res = &agent_resources[i];
+
+ for (j = 0U; j < res->clock_count; j++) {
+ struct stm32_scmi_clk *clk = &res->clock[j];
+
+ if ((clk->name == NULL) ||
+ (strlen(clk->name) >= SCMI_CLOCK_NAME_SIZE)) {
+ ERROR("Invalid SCMI clock name\n");
+ panic();
+ }
+
+ /* Sync SCMI clocks with their targeted initial state */
+ if (clk->enabled &&
+ stm32mp_nsec_can_access_clock(clk->clock_id)) {
+ stm32mp_clk_enable(clk->clock_id);
+ }
+ }
+
+ for (j = 0U; j < res->rd_count; j++) {
+ struct stm32_scmi_rd *rd = &res->rd[j];
+
+ if ((rd->name == NULL) ||
+ (strlen(rd->name) >= SCMI_RD_NAME_SIZE)) {
+ ERROR("Invalid SCMI reset domain name\n");
+ panic();
+ }
+ }
+ }
+}
+
+/*
+ * Save and restore SCMI state since lost during suspend.
+ * Only clock enabled field needs to be updated.
+ */
+void stm32mp1_pm_save_scmi_state(uint8_t *state, size_t size)
+{
+ size_t i;
+ size_t j;
+ size_t cnt = 0U;
+
+ zeromem(state, size);
+
+ for (i = 0U; i < ARRAY_SIZE(agent_resources); i++) {
+ for (j = 0U; j < agent_resources[i].clock_count; j++) {
+ if ((cnt / 8) > size) {
+ VERBOSE("state table too small\n");
+ panic();
+ }
+
+ if (agent_resources[i].clock[j].enabled) {
+ *(state + (cnt / 8)) |= (uint8_t)BIT(cnt % 8);
+ }
+
+ cnt++;
+ }
+ }
+}
+
+void stm32mp1_pm_restore_scmi_state(uint8_t *state, size_t size)
+{
+ size_t i;
+ size_t j;
+ size_t cnt = 0U;
+
+ for (i = 0U; i < ARRAY_SIZE(agent_resources); i++) {
+ for (j = 0U; j < agent_resources[i].clock_count; j++) {
+ if ((*(state + (cnt / 8)) & BIT(cnt % 8)) == 0U) {
+ agent_resources[i].clock[j].enabled = 0;
+ } else {
+ agent_resources[i].clock[j].enabled = 1;
+ }
+
+ assert((cnt / 8) <= size);
+ cnt++;
+ }
+ }
+}
diff --git a/plat/st/stm32mp1/stm32mp1_security.c b/plat/st/stm32mp1/stm32mp1_security.c
index 61db2e7c7..41762fa6b 100644
--- a/plat/st/stm32mp1/stm32mp1_security.c
+++ b/plat/st/stm32mp1/stm32mp1_security.c
@@ -86,8 +86,11 @@ static void init_tzc400(void)
TZC_REGION_NSEC_ALL_ACCESS_RDWR);
#endif
- /* Raise an exception if a NS device tries to access secure memory */
- tzc400_set_action(TZC_ACTION_ERR);
+ /*
+ * Raise an interrupt (secure FIQ) if a NS device tries to access
+ * secure memory
+ */
+ tzc400_set_action(TZC_ACTION_INT);
tzc400_enable_filters();
}
diff --git a/plat/st/stm32mp1/stm32mp1_shared_resources.c b/plat/st/stm32mp1/stm32mp1_shared_resources.c
new file mode 100644
index 000000000..232fbebdb
--- /dev/null
+++ b/plat/st/stm32mp1/stm32mp1_shared_resources.c
@@ -0,0 +1,743 @@
+/*
+ * Copyright (c) 2017-2020, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stdint.h>
+#include <stdio.h>
+
+#include <platform_def.h>
+
+#include <arch.h>
+#include <common/debug.h>
+#include <drivers/st/stm32_gpio.h>
+
+#include <stm32mp_dt.h>
+#include <stm32mp_shres_helpers.h>
+#include <stm32mp1_shared_resources.h>
+
+static bool registering_locked;
+static int8_t gpioz_nbpin = -1;
+
+/*
+ * Shared peripherals and resources.
+ * Defines resource that may be non secure, secure or shared.
+ * May be a device, a bus, a clock, a memory.
+ * Shared peripherals and resources registration
+ *
+ * Each resource assignation is stored in a table. The state defaults
+ * to SHRES_UNREGISTERED if the resource is not explicitly assigned.
+ *
+ * Each IO of the GPIOZ IO can be secure or non-secure.
+ */
+#define SHRES_NON_SECURE 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_MDMA] = "MDMA",
+ [STM32MP1_SHRES_PLL3] = "PLL3",
+};
+
+static const char *shres2str_id(unsigned int id)
+{
+ return shres2str_id_tbl[id];
+}
+
+static const char *shres2str_state_tbl[4] = {
+ [SHRES_UNREGISTERED] = "unregistered",
+ [SHRES_NON_SECURE] = "non-secure",
+ [SHRES_SECURE] = "secure",
+};
+
+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 void register_periph(unsigned int id, unsigned int state)
+{
+ assert((id < STM32MP1_SHRES_COUNT) &&
+ ((state == SHRES_SECURE) || (state == SHRES_NON_SECURE)));
+
+ if (registering_locked) {
+ if (shres_state[id] == state) {
+ return;
+ }
+
+ panic();
+ }
+
+ if ((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) {
+ 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;
+ default:
+ /* No expected resource dependency */
+ break;
+ }
+ }
+}
+
+static bool stm32mp1_mckprot_resource(unsigned int id)
+{
+ switch (id) {
+ case STM32MP1_SHRES_MCU:
+ case STM32MP1_SHRES_PLL3:
+ return true;
+ default:
+ return false;
+ }
+}
+
+/* Register resource by ID */
+void stm32mp_register_secure_periph(unsigned int id)
+{
+ register_periph(id, SHRES_SECURE);
+}
+
+void stm32mp_register_non_secure_periph(unsigned int id)
+{
+ register_periph(id, SHRES_NON_SECURE);
+}
+
+/* Register resource by IO memory base address */
+static void register_periph_iomem(uintptr_t base, unsigned int state)
+{
+ unsigned int id;
+
+ switch (base) {
+ case IWDG1_BASE:
+ id = STM32MP1_SHRES_IWDG1;
+ break;
+ case USART1_BASE:
+ id = STM32MP1_SHRES_USART1;
+ break;
+ case SPI6_BASE:
+ id = STM32MP1_SHRES_SPI6;
+ break;
+ case I2C4_BASE:
+ id = STM32MP1_SHRES_I2C4;
+ break;
+ case I2C6_BASE:
+ id = STM32MP1_SHRES_I2C6;
+ break;
+ case RTC_BASE:
+ id = STM32MP1_SHRES_RTC;
+ break;
+ case RNG1_BASE:
+ id = STM32MP1_SHRES_RNG1;
+ break;
+ case CRYP1_BASE:
+ id = STM32MP1_SHRES_CRYP1;
+ break;
+ case HASH1_BASE:
+ id = STM32MP1_SHRES_HASH1;
+ break;
+
+ 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();
+ }
+
+ switch (id) {
+ case STM32MP1_ETZPC_STGENC_ID:
+ case STM32MP1_ETZPC_BKPSRAM_ID:
+ case STM32MP1_ETZPC_DDRCTRL_ID:
+ case STM32MP1_ETZPC_DDRPHYC_ID:
+ /* We assume these must always be assigned to secure world */
+ if (state != SHRES_SECURE) {
+ panic();
+ }
+ break;
+ default:
+ id_shres = decprot2shres(id);
+ if (id_shres == SHRES_INVALID) {
+ if (state == SHRES_SECURE) {
+ panic();
+ }
+ } else {
+ register_periph(id_shres, state);
+ }
+ break;
+ }
+}
+
+/* Get resource state: these accesses lock the registering support */
+static void lock_registering(void)
+{
+ registering_locked = true;
+}
+
+bool stm32mp1_periph_is_non_secure(unsigned long id)
+{
+ lock_registering();
+
+ /* Resource not registered are assumed non-secure */
+ return (shres_state[id] == SHRES_NON_SECURE) ||
+ (shres_state[id] == SHRES_UNREGISTERED);
+}
+
+bool stm32mp1_periph_is_secure(unsigned long id)
+{
+ lock_registering();
+
+ return shres_state[id] == SHRES_SECURE;
+}
+
+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_secure(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_secure(STM32MP1_SHRES_GPIOZ(i))) {
+ non_secure++;
+ }
+ }
+
+ return non_secure == get_gpioz_nbpin();
+}
+
+static 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();
+}
+
+CASSERT((CK_HSE == 0) &&
+ ((CK_HSE + 1) == CK_CSI) &&
+ ((CK_HSE + 2) == CK_LSI) &&
+ ((CK_HSE + 3) == CK_LSE) &&
+ ((CK_HSE + 4) == CK_HSI) &&
+ ((CK_HSE + 5) == CK_HSE_DIV2) &&
+ ((PLL1_P + 1) == PLL1_Q) &&
+ ((PLL1_P + 2) == PLL1_R) &&
+ ((PLL1_P + 3) == PLL2_P) &&
+ ((PLL1_P + 4) == PLL2_Q) &&
+ ((PLL1_P + 5) == PLL2_R) &&
+ ((PLL1_P + 6) == PLL3_P) &&
+ ((PLL1_P + 7) == PLL3_Q) &&
+ ((PLL1_P + 8) == PLL3_R),
+ assert_clock_id_not_as_expected);
+
+bool stm32mp_nsec_can_access_clock(unsigned long clock_id)
+{
+ enum stm32mp_shres shres_id = STM32MP1_SHRES_COUNT;
+
+ /* Oscillators and PLLs are visible from non-secure world */
+ if ((clock_id <= CK_HSE_DIV2) ||
+ ((clock_id >= PLL1_P) && (clock_id <= PLL3_R))) {
+ return true;
+ }
+
+ switch (clock_id) {
+ case BSEC:
+ case CK_AXI:
+ case CK_MPU:
+ case RTCAPB:
+ return true;
+ case GPIOZ:
+ return !stm32mp_gpio_bank_is_secure(GPIO_BANK_Z);
+ case SPI6_K:
+ shres_id = STM32MP1_SHRES_SPI6;
+ break;
+ case I2C4_K:
+ shres_id = STM32MP1_SHRES_I2C4;
+ break;
+ case I2C6_K:
+ shres_id = STM32MP1_SHRES_I2C6;
+ break;
+ case USART1_K:
+ shres_id = STM32MP1_SHRES_USART1;
+ break;
+ case IWDG1:
+ shres_id = STM32MP1_SHRES_IWDG1;
+ break;
+ case CRYP1:
+ shres_id = STM32MP1_SHRES_CRYP1;
+ break;
+ case HASH1:
+ shres_id = STM32MP1_SHRES_HASH1;
+ break;
+ case RNG1_K:
+ shres_id = STM32MP1_SHRES_RNG1;
+ break;
+ case RTC:
+ shres_id = STM32MP1_SHRES_RTC;
+ break;
+ case CK_MCU:
+ shres_id = STM32MP1_SHRES_MCU;
+ break;
+ default:
+ return false;
+ }
+
+ return !stm32mp1_periph_is_secure(shres_id);
+}
+
+bool stm32mp_nsec_can_access_reset(unsigned int reset_id)
+{
+ enum stm32mp_shres shres_id = STM32MP1_SHRES_COUNT;
+
+ switch (reset_id) {
+ case GPIOZ_R:
+ return stm32mp_gpio_bank_is_non_secure(GPIO_BANK_Z);
+ case SPI6_R:
+ shres_id = STM32MP1_SHRES_SPI6;
+ break;
+ case I2C4_R:
+ shres_id = STM32MP1_SHRES_I2C4;
+ break;
+ case I2C6_R:
+ shres_id = STM32MP1_SHRES_I2C6;
+ break;
+ case USART1_R:
+ shres_id = STM32MP1_SHRES_USART1;
+ break;
+ case CRYP1_R:
+ shres_id = STM32MP1_SHRES_CRYP1;
+ break;
+ case HASH1_R:
+ shres_id = STM32MP1_SHRES_HASH1;
+ break;
+ case RNG1_R:
+ shres_id = STM32MP1_SHRES_RNG1;
+ break;
+ case MDMA_R:
+ shres_id = STM32MP1_SHRES_MDMA;
+ break;
+ case MCU_R:
+ shres_id = STM32MP1_SHRES_MCU;
+ break;
+ default:
+ return false;
+ }
+
+ return !stm32mp1_periph_is_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_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) {
+ INFO("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();
+
+ for (n = 0; n < ARRAY_SIZE(shres_state); n++) {
+ if (shres_state[n] == SHRES_SECURE) {
+ 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++) {
+ unsigned int id = STM32MP1_SHRES_GPIOZ(pin);
+ bool secure = stm32mp1_periph_is_secure(id);
+
+ set_gpio_secure_cfg(GPIO_BANK_Z, pin, secure);
+ }
+}
+
+void stm32mp_lock_periph_registering(void)
+{
+ uint32_t __unused id;
+
+ registering_locked = true;
+
+ for (id = 0; id < STM32MP1_SHRES_COUNT; id++) {
+ uint8_t state = shres_state[id];
+
+ assert((state == SHRES_SECURE) ||
+ (state == SHRES_NON_SECURE) ||
+ (state == SHRES_UNREGISTERED));
+
+ if (state == SHRES_SECURE) {
+ INFO("stm32mp %s (%u): %s\n",
+ shres2str_id(id), id,
+ state == SHRES_SECURE ? "Secure" :
+ state == SHRES_NON_SECURE ? "Non-secure" :
+ state == SHRES_UNREGISTERED ? "Unregistered" :
+ "<Invalid>");
+ }
+ }
+
+ stm32mp1_dump_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
index 2fd06f38a..1585590bc 100644
--- a/plat/st/stm32mp1/stm32mp1_syscfg.c
+++ b/plat/st/stm32mp1/stm32mp1_syscfg.c
@@ -7,15 +7,16 @@
#include <platform_def.h>
#include <common/debug.h>
-#include <drivers/st/bsec.h>
+#include <drivers/st/stm32mp1_clk.h>
#include <drivers/st/stpmic1.h>
#include <lib/mmio.h>
+#include <stm32mp_common.h>
#include <stm32mp_dt.h>
#include <stm32mp1_private.h>
/*
- * SYSCFG REGISTER OFFSET (base relative)
+ * SYSCFG register offsets (base relative)
*/
#define SYSCFG_BOOTR 0x00U
#define SYSCFG_IOCTRLSETR 0x18U
@@ -53,6 +54,8 @@
#define SYSCFG_CMPCR_RAPSRC GENMASK(23, 20)
#define SYSCFG_CMPCR_ANSRC_SHIFT 24
+#define SYSCFG_CMPCR_READY_TIMEOUT_US 10000U
+
/*
* SYSCFG_CMPENSETR Register
*/
@@ -61,20 +64,20 @@
void stm32mp1_syscfg_init(void)
{
uint32_t bootr;
- uint32_t otp = 0;
+ uint32_t otp_value;
uint32_t vdd_voltage;
- uintptr_t syscfg_base = dt_get_syscfg_base();
+ bool product_below_2v5;
/*
* Interconnect update : select master using the port 1.
* LTDC = AXI_M9.
*/
- mmio_write_32(syscfg_base + SYSCFG_ICNR, SYSCFG_ICNR_AXI_M9);
+ mmio_write_32(SYSCFG_BASE + SYSCFG_ICNR, SYSCFG_ICNR_AXI_M9);
/* Disable Pull-Down for boot pin connected to VDD */
- bootr = mmio_read_32(syscfg_base + SYSCFG_BOOTR) &
+ bootr = mmio_read_32(SYSCFG_BASE + SYSCFG_BOOTR) &
SYSCFG_BOOTR_BOOT_MASK;
- mmio_clrsetbits_32(syscfg_base + SYSCFG_BOOTR, SYSCFG_BOOTR_BOOTPD_MASK,
+ mmio_clrsetbits_32(SYSCFG_BASE + SYSCFG_BOOTR, SYSCFG_BOOTR_BOOTPD_MASK,
bootr << SYSCFG_BOOTR_BOOTPD_SHIFT);
/*
@@ -92,11 +95,11 @@ void stm32mp1_syscfg_init(void)
* => TF-A enables the low power mode only if VDD < 2.7V (in DT)
* but this value needs to be consistent with board design.
*/
- if (bsec_read_otp(&otp, HW2_OTP) != BSEC_OK) {
+ if (stm32_get_otp_value(HW2_OTP, &otp_value) != 0) {
panic();
}
- otp = otp & HW2_OTP_PRODUCT_BELOW_2V5;
+ product_below_2v5 = (otp_value & HW2_OTP_PRODUCT_BELOW_2V5) != 0U;
/* Get VDD supply */
vdd_voltage = dt_get_pwr_vdd_voltage();
@@ -105,18 +108,18 @@ void stm32mp1_syscfg_init(void)
if (vdd_voltage == 0U) {
WARN("VDD unknown");
} else if (vdd_voltage < 2700000U) {
- mmio_write_32(syscfg_base + SYSCFG_IOCTRLSETR,
+ 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) {
+ if (!product_below_2v5) {
INFO("Product_below_2v5=0: HSLVEN protected by HW\n");
}
} else {
- if (otp != 0U) {
+ if (product_below_2v5) {
ERROR("Product_below_2v5=1:\n");
ERROR("\tHSLVEN update is destructive,\n");
ERROR("\tno update as VDD > 2.7V\n");
@@ -129,29 +132,37 @@ void stm32mp1_syscfg_init(void)
void stm32mp1_syscfg_enable_io_compensation(void)
{
- uintptr_t syscfg_base = dt_get_syscfg_base();
+ uint64_t start;
/*
* Activate automatic I/O compensation.
* Warning: need to ensure CSI enabled and ready in clock driver.
* Enable non-secure clock, we assume non-secure is suspended.
*/
- stm32mp1_clk_enable_non_secure(SYSCFG);
+ stm32mp1_clk_force_enable(SYSCFG);
- mmio_setbits_32(syscfg_base + SYSCFG_CMPENSETR,
+ mmio_setbits_32(SYSCFG_BASE + SYSCFG_CMPENSETR,
SYSCFG_CMPENSETR_MPU_EN);
- while ((mmio_read_32(syscfg_base + SYSCFG_CMPCR) &
+ start = timeout_init_us(SYSCFG_CMPCR_READY_TIMEOUT_US);
+
+ while ((mmio_read_32(SYSCFG_BASE + SYSCFG_CMPCR) &
SYSCFG_CMPCR_READY) == 0U) {
- ;
+ if (timeout_elapsed(start)) {
+ /*
+ * Failure on IO compensation enable is not a issue:
+ * warn only.
+ */
+ WARN("IO compensation cell not ready\n");
+ break;
+ }
}
- mmio_clrbits_32(syscfg_base + SYSCFG_CMPCR, SYSCFG_CMPCR_SW_CTRL);
+ mmio_clrbits_32(SYSCFG_BASE + SYSCFG_CMPCR, SYSCFG_CMPCR_SW_CTRL);
}
void stm32mp1_syscfg_disable_io_compensation(void)
{
- uintptr_t syscfg_base = dt_get_syscfg_base();
uint32_t value;
/*
@@ -160,21 +171,19 @@ void stm32mp1_syscfg_disable_io_compensation(void)
* requested for other usages and always OFF in STANDBY.
* Disable non-secure SYSCFG clock, we assume non-secure is suspended.
*/
- value = mmio_read_32(syscfg_base + SYSCFG_CMPCR) >>
+ value = mmio_read_32(SYSCFG_BASE + SYSCFG_CMPCR) >>
SYSCFG_CMPCR_ANSRC_SHIFT;
- mmio_clrbits_32(syscfg_base + SYSCFG_CMPCR,
+ mmio_clrbits_32(SYSCFG_BASE + SYSCFG_CMPCR,
SYSCFG_CMPCR_RANSRC | SYSCFG_CMPCR_RAPSRC);
- value = mmio_read_32(syscfg_base + SYSCFG_CMPCR) |
+ value = mmio_read_32(SYSCFG_BASE + SYSCFG_CMPCR) |
(value << SYSCFG_CMPCR_RANSRC_SHIFT);
- mmio_write_32(syscfg_base + SYSCFG_CMPCR, value);
-
- mmio_setbits_32(syscfg_base + SYSCFG_CMPCR, SYSCFG_CMPCR_SW_CTRL);
+ mmio_write_32(SYSCFG_BASE + SYSCFG_CMPCR, value | SYSCFG_CMPCR_SW_CTRL);
- mmio_clrbits_32(syscfg_base + SYSCFG_CMPENSETR,
+ mmio_clrbits_32(SYSCFG_BASE + SYSCFG_CMPENSETR,
SYSCFG_CMPENSETR_MPU_EN);
- stm32mp1_clk_disable_non_secure(SYSCFG);
+ stm32mp1_clk_force_disable(SYSCFG);
}
diff --git a/plat/st/stm32mp1/stm32mp1_usb_desc.c b/plat/st/stm32mp1/stm32mp1_usb_desc.c
new file mode 100644
index 000000000..3ca06922a
--- /dev/null
+++ b/plat/st/stm32mp1/stm32mp1_usb_desc.c
@@ -0,0 +1,418 @@
+/*
+ * Copyright (c) 2015-2019, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <limits.h>
+#include <string.h>
+
+#include <platform_def.h>
+
+#include <common/debug.h>
+#include <drivers/st/bsec.h>
+#include <lib/usb/usb_core.h>
+#include <lib/usb/usb_st_dfu.h>
+
+#include <stm32mp_common.h>
+#include <stm32mp1_usb_desc.h>
+
+/* 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: Configuration 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[UID_WORD_NB] = {0U, 0U, 0U};
+ uint32_t otp;
+ uint32_t len;
+
+ if (stm32_get_otp_index(UID_OTP, &otp, &len) != 0) {
+ ERROR("BSEC: Get UID_OTP number Error\n");
+ return;
+ }
+
+ if ((len / __WORD_BIT) != UID_WORD_NB) {
+ ERROR("BSEC: Get UID_OTP length Error\n");
+ return;
+ }
+
+ for (i = 0; i < UID_WORD_NB; i++) {
+ if (bsec_shadow_read_otp(&deviceserial[i], i + 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/stm32image/stm32image.c b/tools/stm32image/stm32image.c
index 41024e286..209e0c9d8 100644
--- a/tools/stm32image/stm32image.c
+++ b/tools/stm32image/stm32image.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2018, STMicroelectronics - All Rights Reserved
+ * Copyright (c) 2017-2020, STMicroelectronics - All Rights Reserved
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -45,8 +45,6 @@ struct stm32_header {
uint8_t binary_type;
};
-static struct stm32_header stm32image_header;
-
static void stm32image_default_header(struct stm32_header *ptr)
{
if (!ptr) {
@@ -54,10 +52,9 @@ static void stm32image_default_header(struct stm32_header *ptr)
}
ptr->magic_number = HEADER_MAGIC;
- ptr->header_version[VER_MAJOR] = HEADER_VERSION_V1;
ptr->option_flags = HEADER_DEFAULT_OPTION;
- ptr->ecdsa_algorithm = 1;
- ptr->version_number = 0;
+ ptr->ecdsa_algorithm = __cpu_to_le32(1);
+ ptr->version_number = __cpu_to_le32(0);
ptr->binary_type = TF_BINARY_TYPE;
}
@@ -105,27 +102,33 @@ static void stm32image_print_header(const void *ptr)
}
static void stm32image_set_header(void *ptr, struct stat *sbuf, int ifd,
- uint32_t loadaddr, uint32_t ep, uint32_t ver)
+ uint32_t loadaddr, uint32_t ep, uint32_t ver,
+ uint32_t major, uint32_t minor)
{
struct stm32_header *stm32hdr = (struct stm32_header *)ptr;
stm32image_default_header(stm32hdr);
+ stm32hdr->header_version[VER_MAJOR] = major;
+ stm32hdr->header_version[VER_MINOR] = minor;
stm32hdr->load_address = __cpu_to_le32(loadaddr);
stm32hdr->image_entry_point = __cpu_to_le32(ep);
stm32hdr->image_length = __cpu_to_le32((uint32_t)sbuf->st_size -
sizeof(struct stm32_header));
- stm32hdr->image_checksum = stm32image_checksum(ptr, sbuf->st_size);
+ stm32hdr->image_checksum =
+ __cpu_to_le32(stm32image_checksum(ptr, sbuf->st_size));
stm32hdr->version_number = __cpu_to_le32(ver);
}
static int stm32image_create_header_file(char *srcname, char *destname,
uint32_t loadaddr, uint32_t entry,
- uint32_t version)
+ uint32_t version, uint32_t major,
+ uint32_t minor)
{
int src_fd, dest_fd;
struct stat sbuf;
unsigned char *ptr;
+ struct stm32_header stm32image_header;
dest_fd = open(destname, O_RDWR | O_CREAT | O_TRUNC | O_APPEND, 0666);
if (dest_fd == -1) {
@@ -177,11 +180,12 @@ static int stm32image_create_header_file(char *srcname, char *destname,
dest_fd, 0);
if (ptr == MAP_FAILED) {
- fprintf(stderr, "Can't read %s\n", srcname);
+ fprintf(stderr, "Can't write %s\n", destname);
return -1;
}
- stm32image_set_header(ptr, &sbuf, dest_fd, loadaddr, entry, version);
+ stm32image_set_header(ptr, &sbuf, dest_fd, loadaddr, entry, version,
+ major, minor);
stm32image_print_header(ptr);
@@ -193,9 +197,11 @@ static int stm32image_create_header_file(char *srcname, char *destname,
int main(int argc, char *argv[])
{
int opt, loadaddr = -1, entry = -1, err = 0, version = 0;
+ int major = HEADER_VERSION_V1;
+ int minor = 0;
char *dest = NULL, *src = NULL;
- while ((opt = getopt(argc, argv, ":s:d:l:e:v:")) != -1) {
+ while ((opt = getopt(argc, argv, ":s:d:l:e:v:m:n:")) != -1) {
switch (opt) {
case 's':
src = optarg;
@@ -204,17 +210,23 @@ int main(int argc, char *argv[])
dest = optarg;
break;
case 'l':
- loadaddr = strtol(optarg, NULL, 16);
+ loadaddr = strtol(optarg, NULL, 0);
break;
case 'e':
- entry = strtol(optarg, NULL, 16);
+ entry = strtol(optarg, NULL, 0);
break;
case 'v':
- version = strtol(optarg, NULL, 10);
+ version = strtol(optarg, NULL, 0);
+ break;
+ case 'm':
+ major = strtol(optarg, NULL, 0);
+ break;
+ case 'n':
+ minor = strtol(optarg, NULL, 0);
break;
default:
fprintf(stderr,
- "Usage : %s [-s srcfile] [-d destfile] [-l loadaddr] [-e entry_point]\n",
+ "Usage : %s [-s srcfile] [-d destfile] [-l loadaddr] [-e entry_point] [-m major] [-n minor]\n",
argv[0]);
return -1;
}
@@ -241,7 +253,7 @@ int main(int argc, char *argv[])
}
err = stm32image_create_header_file(src, dest, loadaddr,
- entry, version);
+ entry, version, major, minor);
return err;
}
--
2.17.1