45591 lines
1.3 MiB
45591 lines
1.3 MiB
From b378eb77ad6177d7bd5cb1a5befc4b0c52f70e2c Mon Sep 17 00:00:00 2001
|
|
From: christophe montaud <christophe.montaud@st.com>
|
|
Date: Tue, 29 Jan 2019 18:16:44 +0100
|
|
Subject: [PATCH] st update r1
|
|
|
|
---
|
|
.checkpatch.conf | 18 +
|
|
Makefile | 56 +-
|
|
bl2/aarch32/bl2_arch_setup.c | 1 +
|
|
bl2/aarch32/bl2_el3_entrypoint.S | 4 +
|
|
bl2/aarch32/bl2_el3_exceptions.S | 9 +
|
|
bl2/aarch32/bl2_entrypoint.S | 9 +
|
|
bl2/bl2_image_load_v2.c | 14 +-
|
|
bl2/bl2_private.h | 3 +
|
|
bl2u/aarch32/bl2u_entrypoint.S | 9 +
|
|
bl32/sp_min/aarch32/entrypoint.S | 9 +
|
|
common/aarch32/debug.S | 54 +-
|
|
docs/devicetree/bindings/arm/secure.txt | 53 +
|
|
docs/devicetree/bindings/clock/st,stm32mp1-rcc.txt | 324 +++
|
|
docs/devicetree/bindings/i2c/i2c-stm32.txt | 54 +
|
|
docs/devicetree/bindings/mmc/mmci.txt | 72 +
|
|
docs/devicetree/bindings/mmc/st,stm32-sdmmc2.txt | 22 +
|
|
docs/devicetree/bindings/power/st,stm32mp1-pwr.txt | 42 +
|
|
docs/devicetree/bindings/power/st,stpmic1.txt | 132 ++
|
|
docs/devicetree/bindings/reset/st,stm32mp1-rcc.txt | 6 +
|
|
docs/devicetree/bindings/rng/st,stm32-rng.txt | 23 +
|
|
docs/devicetree/bindings/serial/st,stm32-usart.txt | 88 +
|
|
docs/devicetree/bindings/soc/st,stm32-etzpc.txt | 56 +
|
|
docs/devicetree/bindings/soc/st,stm32-romem.txt | 31 +
|
|
docs/devicetree/bindings/soc/st,stm32-stgen.txt | 18 +
|
|
docs/devicetree/bindings/soc/st,stm32-tamp.txt | 22 +
|
|
.../devicetree/bindings/watchdog/st,stm32-iwdg.txt | 28 +
|
|
docs/plat/stm32mp1.rst | 16 +
|
|
docs/porting-guide.rst | 44 +-
|
|
drivers/arm/pl011/aarch32/pl011_console.S | 139 +-
|
|
drivers/arm/pl011/aarch64/pl011_console.S | 3 +-
|
|
drivers/arm/tzc/tzc400.c | 129 ++
|
|
drivers/cadence/uart/aarch64/cdns_console.S | 4 +-
|
|
drivers/console/aarch32/console.S | 105 +-
|
|
drivers/console/aarch32/deprecated_console.S | 112 +
|
|
drivers/console/aarch32/multi_console.S | 318 +++
|
|
drivers/console/aarch64/skeleton_console.S | 9 +-
|
|
.../coreboot/cbmem_console/aarch64/cbmem_console.S | 3 +-
|
|
drivers/io/io_block.c | 8 +-
|
|
drivers/io/io_memmap.c | 5 +-
|
|
drivers/io/io_semihosting.c | 4 +-
|
|
drivers/io/io_storage.c | 2 +-
|
|
drivers/mmc/mmc.c | 23 +-
|
|
drivers/partition/gpt.c | 10 +-
|
|
drivers/partition/partition.c | 2 +-
|
|
drivers/st/bsec/bsec.c | 911 ++++++++
|
|
drivers/st/clk/stm32mp1_clk.c | 2247 +++++++++++++++-----
|
|
drivers/st/clk/stm32mp1_clkfunc.c | 211 +-
|
|
drivers/st/clk/stm32mp_clkfunc.c | 307 +++
|
|
drivers/st/ddr/stm32mp1_ddr.c | 484 +++--
|
|
drivers/st/ddr/stm32mp1_ddr_helpers.c | 510 ++++-
|
|
drivers/st/ddr/stm32mp1_ram.c | 194 +-
|
|
drivers/st/etzpc/etzpc.c | 310 +++
|
|
drivers/st/gpio/stm32_gpio.c | 267 ++-
|
|
drivers/st/hash/hash_sec.c | 369 ++++
|
|
drivers/st/i2c/stm32_i2c.c | 1371 ++++++++++++
|
|
drivers/st/io/io_mmc.c | 134 ++
|
|
drivers/st/io/io_programmer_st_usb.c | 379 ++++
|
|
drivers/st/io/io_stm32image.c | 381 ++++
|
|
drivers/st/iwdg/stm32_iwdg.c | 289 +++
|
|
drivers/st/mmc/stm32_sdmmc2.c | 752 +++++++
|
|
drivers/st/nand/io_nand.c | 228 ++
|
|
drivers/st/nand/nand.c | 1548 ++++++++++++++
|
|
drivers/st/pmic/stm32_i2c.c | 851 --------
|
|
drivers/st/pmic/stm32mp1_pmic.c | 346 ---
|
|
drivers/st/pmic/stm32mp_pmic.c | 522 +++++
|
|
drivers/st/pmic/stpmic1.c | 817 +++++++
|
|
drivers/st/pmic/stpmu1.c | 600 ------
|
|
drivers/st/qspi/io_qspi.c | 349 +++
|
|
drivers/st/reset/stm32mp1_reset.c | 64 +-
|
|
drivers/st/rng/stm32_rng.c | 191 ++
|
|
drivers/st/rtc/stm32_rtc.c | 499 +++++
|
|
drivers/st/tamper/stm32_tamp.c | 375 ++++
|
|
drivers/st/timer/stm32_timer.c | 297 +++
|
|
drivers/st/uart/aarch32/stm32_console.S | 151 +-
|
|
drivers/st/uart/io_programmer_uart.c | 597 ++++++
|
|
drivers/st/uart/stm32mp1xx_hal_uart.c | 799 +++++++
|
|
drivers/st/usb_dwc2/usb_dwc2.c | 858 ++++++++
|
|
drivers/ti/uart/aarch64/16550_console.S | 3 +-
|
|
fdts/stm32mp15-ddr.dtsi | 2 +-
|
|
fdts/stm32mp15-ddr3-1x4Gb-1066-binG.dtsi | 121 ++
|
|
fdts/stm32mp15-ddr3-2x4Gb-1066-binG.dtsi | 19 +-
|
|
fdts/stm32mp157-pinctrl.dtsi | 154 +-
|
|
fdts/stm32mp157a-dk1.dts | 464 ++++
|
|
fdts/stm32mp157c-dk2.dts | 16 +
|
|
fdts/stm32mp157c-ed1.dts | 342 ++-
|
|
fdts/stm32mp157c-ev1.dts | 52 +-
|
|
fdts/stm32mp157c-security.dtsi | 71 +
|
|
fdts/stm32mp157c.dtsi | 215 +-
|
|
fdts/stm32mp157caa-pinctrl.dtsi | 8 +-
|
|
fdts/stm32mp157cab-pinctrl.dtsi | 62 +
|
|
fdts/stm32mp157cac-pinctrl.dtsi | 78 +
|
|
fdts/stm32mp157cad-pinctrl.dtsi | 62 +
|
|
include/common/aarch32/console_macros.S | 84 +
|
|
include/common/aarch64/console_macros.S | 46 +-
|
|
include/common/tbbr/tbbr_img_def.h | 8 +-
|
|
include/drivers/arm/tzc400.h | 4 +
|
|
include/drivers/io/io_driver.h | 2 +-
|
|
include/drivers/io/io_storage.h | 8 +-
|
|
include/drivers/st/bsec.h | 205 ++
|
|
include/drivers/st/etzpc.h | 32 +
|
|
include/drivers/st/hash_sec.h | 113 +
|
|
include/drivers/st/io_mmc.h | 14 +
|
|
include/drivers/st/io_nand.h | 19 +
|
|
include/drivers/st/io_programmer.h | 51 +
|
|
include/drivers/st/io_programmer_st_usb.h | 20 +
|
|
include/drivers/st/io_qspi.h | 92 +
|
|
include/drivers/st/io_stm32image.h | 32 +
|
|
include/drivers/st/io_uart.h | 12 +
|
|
include/drivers/st/nand.h | 252 +++
|
|
include/drivers/st/stm32_console.h | 34 +
|
|
include/drivers/st/stm32_gpio.h | 68 +-
|
|
include/drivers/st/stm32_hal_hash_reg.h | 136 ++
|
|
include/drivers/st/stm32_i2c.h | 303 +--
|
|
include/drivers/st/stm32_iwdg.h | 20 +
|
|
include/drivers/st/stm32_rng.h | 13 +
|
|
include/drivers/st/stm32_rtc.h | 79 +
|
|
include/drivers/st/stm32_sdmmc2.h | 31 +
|
|
include/drivers/st/stm32_tamp.h | 163 ++
|
|
include/drivers/st/stm32_timer.h | 21 +
|
|
include/drivers/st/stm32_uart_regs.h | 199 ++
|
|
include/drivers/st/stm32mp1_clk.h | 71 +-
|
|
include/drivers/st/stm32mp1_clkfunc.h | 18 +-
|
|
include/drivers/st/stm32mp1_ddr.h | 13 +-
|
|
include/drivers/st/stm32mp1_ddr_helpers.h | 14 +-
|
|
include/drivers/st/stm32mp1_ddr_regs.h | 15 +-
|
|
include/drivers/st/stm32mp1_pmic.h | 18 -
|
|
include/drivers/st/stm32mp1_pwr.h | 31 +-
|
|
include/drivers/st/stm32mp1_ram.h | 6 +-
|
|
include/drivers/st/stm32mp1_rcc.h | 138 +-
|
|
include/drivers/st/stm32mp1_reset.h | 15 -
|
|
include/drivers/st/stm32mp1xx_hal.h | 203 ++
|
|
include/drivers/st/stm32mp1xx_hal_uart.h | 1586 ++++++++++++++
|
|
include/drivers/st/stm32mp1xx_hal_uart_ex.h | 87 +
|
|
include/drivers/st/stm32mp_clkfunc.h | 28 +
|
|
include/drivers/st/stm32mp_pmic.h | 24 +
|
|
include/drivers/st/stm32mp_reset.h | 15 +
|
|
include/drivers/st/stpmic1.h | 173 ++
|
|
include/drivers/st/stpmu1.h | 141 --
|
|
include/drivers/st/usb_dwc2.h | 443 ++++
|
|
include/dt-bindings/interrupt-controller/arm-gic.h | 21 +
|
|
include/dt-bindings/pinctrl/stm32-pinfunc.h | 6 +
|
|
include/dt-bindings/power/stm32mp1-power.h | 19 +
|
|
include/dt-bindings/soc/st,stm32-etzpc.h | 107 +
|
|
include/lib/aarch32/arch.h | 14 +
|
|
include/lib/aarch32/arch_helpers.h | 3 +
|
|
include/lib/cpus/aarch32/cortex_a9.h | 5 +
|
|
include/lib/optee_utils.h | 1 +
|
|
include/lib/psci/psci.h | 8 +-
|
|
include/lib/usb/usb_core.h | 352 +++
|
|
include/lib/usb/usb_st_dfu.h | 115 +
|
|
include/lib/utils.h | 29 +-
|
|
include/lib/utils_def.h | 20 +-
|
|
include/lib/xlat_tables/xlat_tables_v2_helpers.h | 41 +-
|
|
include/plat/common/platform.h | 5 +
|
|
lib/compiler-rt/builtins/int_lib.h | 13 +-
|
|
lib/compiler-rt/builtins/lshrdi3.c | 45 +
|
|
lib/compiler-rt/compiler-rt.mk | 3 +-
|
|
lib/libfdt/fdt_ro.c | 2 +-
|
|
lib/optee/optee_utils.c | 30 +
|
|
lib/usb/usb_core.c | 732 +++++++
|
|
lib/usb/usb_st_dfu.c | 865 ++++++++
|
|
lib/xlat_tables/aarch32/xlat_tables.c | 9 +
|
|
lib/xlat_tables/aarch64/xlat_tables.c | 4 +
|
|
lib/xlat_tables/xlat_tables_common.c | 18 +
|
|
lib/xlat_tables_v2/xlat_tables_core.c | 7 +-
|
|
make_helpers/build_macros.mk | 15 +-
|
|
make_helpers/defaults.mk | 3 +
|
|
plat/arm/common/aarch32/arm_helpers.S | 6 +-
|
|
plat/arm/common/arm_common.mk | 4 +-
|
|
plat/arm/common/sp_min/arm_sp_min_setup.c | 7 +-
|
|
plat/common/aarch32/crash_console_helpers.S | 92 +
|
|
plat/common/aarch32/plat_sp_min_common.c | 4 +
|
|
plat/common/aarch32/platform_helpers.S | 38 +
|
|
plat/common/aarch64/crash_console_helpers.S | 92 +
|
|
plat/common/aarch64/platform_helpers.S | 4 +
|
|
plat/common/plat_log_common.c | 1 +
|
|
plat/imx/common/lpuart_console.S | 3 +-
|
|
plat/layerscape/common/aarch64/ls_console.S | 3 +-
|
|
plat/st/common/bl2_io_storage.c | 773 +++++++
|
|
plat/st/common/include/stm32mp_auth.h | 15 +
|
|
plat/st/common/include/stm32mp_common.h | 49 +
|
|
plat/st/common/include/stm32mp_dt.h | 54 +
|
|
plat/st/common/include/stm32mp_shres_helpers.h | 86 +
|
|
plat/st/common/stm32mp_auth.c | 121 ++
|
|
plat/st/common/stm32mp_common.c | 168 ++
|
|
plat/st/common/stm32mp_dt.c | 559 +++++
|
|
plat/st/common/stm32mp_shres_helpers.c | 71 +
|
|
plat/st/stm32mp1/bl2_io_storage.c | 193 --
|
|
plat/st/stm32mp1/bl2_plat_setup.c | 447 +++-
|
|
plat/st/stm32mp1/include/boot_api.h | 411 +++-
|
|
plat/st/stm32mp1/include/platform_def.h | 64 +-
|
|
plat/st/stm32mp1/include/stm32mp1_context.h | 18 +-
|
|
plat/st/stm32mp1/include/stm32mp1_dbgmcu.h | 26 +
|
|
plat/st/stm32mp1/include/stm32mp1_dt.h | 41 -
|
|
plat/st/stm32mp1/include/stm32mp1_low_power.h | 19 +
|
|
plat/st/stm32mp1/include/stm32mp1_power_config.h | 28 +
|
|
plat/st/stm32mp1/include/stm32mp1_private.h | 30 +-
|
|
.../stm32mp1/include/stm32mp1_shared_resources.h | 83 +
|
|
plat/st/stm32mp1/include/stm32mp1_smc.h | 68 +
|
|
plat/st/stm32mp1/include/stm32mp1_usb_desc.h | 55 +
|
|
plat/st/stm32mp1/include/usb_ctx.h | 17 +
|
|
plat/st/stm32mp1/plat_bl2_mem_params_desc.c | 49 +-
|
|
plat/st/stm32mp1/plat_image_load.c | 103 +
|
|
plat/st/stm32mp1/platform.mk | 144 +-
|
|
plat/st/stm32mp1/services/bsec_svc.c | 460 ++++
|
|
plat/st/stm32mp1/services/bsec_svc.h | 21 +
|
|
plat/st/stm32mp1/services/low_power_svc.c | 46 +
|
|
plat/st/stm32mp1/services/low_power_svc.h | 15 +
|
|
plat/st/stm32mp1/services/pwr_svc.c | 124 ++
|
|
plat/st/stm32mp1/services/pwr_svc.h | 13 +
|
|
plat/st/stm32mp1/services/rcc_svc.c | 477 +++++
|
|
plat/st/stm32mp1/services/rcc_svc.h | 14 +
|
|
plat/st/stm32mp1/services/stm32mp1_svc_setup.c | 113 +
|
|
plat/st/stm32mp1/sp_min/sp_min-stm32mp1.mk | 14 +
|
|
plat/st/stm32mp1/sp_min/sp_min_setup.c | 243 ++-
|
|
plat/st/stm32mp1/stm32mp1.ld.S | 19 +-
|
|
plat/st/stm32mp1/stm32mp1_common.c | 101 -
|
|
plat/st/stm32mp1/stm32mp1_context.c | 220 +-
|
|
plat/st/stm32mp1/stm32mp1_dbgmcu.c | 153 ++
|
|
plat/st/stm32mp1/stm32mp1_def.h | 441 +++-
|
|
plat/st/stm32mp1/stm32mp1_dt.c | 476 -----
|
|
plat/st/stm32mp1/stm32mp1_gic.c | 173 +-
|
|
plat/st/stm32mp1/stm32mp1_helper.S | 248 ++-
|
|
plat/st/stm32mp1/stm32mp1_helper_dbg.S | 227 ++
|
|
plat/st/stm32mp1/stm32mp1_low_power.c | 311 +++
|
|
plat/st/stm32mp1/stm32mp1_pm.c | 118 +-
|
|
plat/st/stm32mp1/stm32mp1_power_config.c | 193 ++
|
|
plat/st/stm32mp1/stm32mp1_private.c | 379 ++++
|
|
plat/st/stm32mp1/stm32mp1_security.c | 91 +-
|
|
plat/st/stm32mp1/stm32mp1_shared_resources.c | 833 ++++++++
|
|
plat/st/stm32mp1/stm32mp1_syscfg.c | 144 ++
|
|
plat/st/stm32mp1/stm32mp1_usb_desc.c | 401 ++++
|
|
tools/cert_create/Makefile | 18 +-
|
|
tools/doimage/Makefile | 20 +-
|
|
tools/fiptool/Makefile | 14 +-
|
|
tools/stm32image/Makefile | 20 +-
|
|
tools/stm32image/stm32image.c | 2 +-
|
|
237 files changed, 34905 insertions(+), 4745 deletions(-)
|
|
create mode 100644 docs/devicetree/bindings/arm/secure.txt
|
|
create mode 100644 docs/devicetree/bindings/clock/st,stm32mp1-rcc.txt
|
|
create mode 100644 docs/devicetree/bindings/i2c/i2c-stm32.txt
|
|
create mode 100644 docs/devicetree/bindings/mmc/mmci.txt
|
|
create mode 100644 docs/devicetree/bindings/mmc/st,stm32-sdmmc2.txt
|
|
create mode 100644 docs/devicetree/bindings/power/st,stm32mp1-pwr.txt
|
|
create mode 100644 docs/devicetree/bindings/power/st,stpmic1.txt
|
|
create mode 100644 docs/devicetree/bindings/reset/st,stm32mp1-rcc.txt
|
|
create mode 100644 docs/devicetree/bindings/rng/st,stm32-rng.txt
|
|
create mode 100644 docs/devicetree/bindings/serial/st,stm32-usart.txt
|
|
create mode 100644 docs/devicetree/bindings/soc/st,stm32-etzpc.txt
|
|
create mode 100644 docs/devicetree/bindings/soc/st,stm32-romem.txt
|
|
create mode 100644 docs/devicetree/bindings/soc/st,stm32-stgen.txt
|
|
create mode 100644 docs/devicetree/bindings/soc/st,stm32-tamp.txt
|
|
create mode 100644 docs/devicetree/bindings/watchdog/st,stm32-iwdg.txt
|
|
create mode 100644 drivers/console/aarch32/deprecated_console.S
|
|
create mode 100644 drivers/console/aarch32/multi_console.S
|
|
create mode 100644 drivers/st/bsec/bsec.c
|
|
create mode 100644 drivers/st/clk/stm32mp_clkfunc.c
|
|
create mode 100644 drivers/st/etzpc/etzpc.c
|
|
create mode 100644 drivers/st/hash/hash_sec.c
|
|
create mode 100644 drivers/st/i2c/stm32_i2c.c
|
|
create mode 100644 drivers/st/io/io_mmc.c
|
|
create mode 100644 drivers/st/io/io_programmer_st_usb.c
|
|
create mode 100644 drivers/st/io/io_stm32image.c
|
|
create mode 100644 drivers/st/iwdg/stm32_iwdg.c
|
|
create mode 100644 drivers/st/mmc/stm32_sdmmc2.c
|
|
create mode 100644 drivers/st/nand/io_nand.c
|
|
create mode 100644 drivers/st/nand/nand.c
|
|
delete mode 100644 drivers/st/pmic/stm32_i2c.c
|
|
delete mode 100644 drivers/st/pmic/stm32mp1_pmic.c
|
|
create mode 100644 drivers/st/pmic/stm32mp_pmic.c
|
|
create mode 100644 drivers/st/pmic/stpmic1.c
|
|
delete mode 100644 drivers/st/pmic/stpmu1.c
|
|
create mode 100644 drivers/st/qspi/io_qspi.c
|
|
create mode 100644 drivers/st/rng/stm32_rng.c
|
|
create mode 100644 drivers/st/rtc/stm32_rtc.c
|
|
create mode 100644 drivers/st/tamper/stm32_tamp.c
|
|
create mode 100644 drivers/st/timer/stm32_timer.c
|
|
create mode 100644 drivers/st/uart/io_programmer_uart.c
|
|
create mode 100644 drivers/st/uart/stm32mp1xx_hal_uart.c
|
|
create mode 100644 drivers/st/usb_dwc2/usb_dwc2.c
|
|
create mode 100644 fdts/stm32mp15-ddr3-1x4Gb-1066-binG.dtsi
|
|
create mode 100644 fdts/stm32mp157a-dk1.dts
|
|
create mode 100644 fdts/stm32mp157c-dk2.dts
|
|
create mode 100644 fdts/stm32mp157c-security.dtsi
|
|
create mode 100644 fdts/stm32mp157cab-pinctrl.dtsi
|
|
create mode 100644 fdts/stm32mp157cac-pinctrl.dtsi
|
|
create mode 100644 fdts/stm32mp157cad-pinctrl.dtsi
|
|
create mode 100644 include/common/aarch32/console_macros.S
|
|
create mode 100644 include/drivers/st/bsec.h
|
|
create mode 100644 include/drivers/st/etzpc.h
|
|
create mode 100644 include/drivers/st/hash_sec.h
|
|
create mode 100644 include/drivers/st/io_mmc.h
|
|
create mode 100644 include/drivers/st/io_nand.h
|
|
create mode 100644 include/drivers/st/io_programmer.h
|
|
create mode 100644 include/drivers/st/io_programmer_st_usb.h
|
|
create mode 100644 include/drivers/st/io_qspi.h
|
|
create mode 100644 include/drivers/st/io_stm32image.h
|
|
create mode 100644 include/drivers/st/io_uart.h
|
|
create mode 100644 include/drivers/st/nand.h
|
|
create mode 100644 include/drivers/st/stm32_console.h
|
|
create mode 100644 include/drivers/st/stm32_hal_hash_reg.h
|
|
create mode 100644 include/drivers/st/stm32_iwdg.h
|
|
create mode 100644 include/drivers/st/stm32_rng.h
|
|
create mode 100644 include/drivers/st/stm32_rtc.h
|
|
create mode 100644 include/drivers/st/stm32_sdmmc2.h
|
|
create mode 100644 include/drivers/st/stm32_tamp.h
|
|
create mode 100644 include/drivers/st/stm32_timer.h
|
|
create mode 100644 include/drivers/st/stm32_uart_regs.h
|
|
delete mode 100644 include/drivers/st/stm32mp1_pmic.h
|
|
delete mode 100644 include/drivers/st/stm32mp1_reset.h
|
|
create mode 100644 include/drivers/st/stm32mp1xx_hal.h
|
|
create mode 100644 include/drivers/st/stm32mp1xx_hal_uart.h
|
|
create mode 100644 include/drivers/st/stm32mp1xx_hal_uart_ex.h
|
|
create mode 100644 include/drivers/st/stm32mp_clkfunc.h
|
|
create mode 100644 include/drivers/st/stm32mp_pmic.h
|
|
create mode 100644 include/drivers/st/stm32mp_reset.h
|
|
create mode 100644 include/drivers/st/stpmic1.h
|
|
delete mode 100644 include/drivers/st/stpmu1.h
|
|
create mode 100644 include/drivers/st/usb_dwc2.h
|
|
create mode 100644 include/dt-bindings/interrupt-controller/arm-gic.h
|
|
create mode 100644 include/dt-bindings/power/stm32mp1-power.h
|
|
create mode 100644 include/dt-bindings/soc/st,stm32-etzpc.h
|
|
create mode 100644 include/lib/usb/usb_core.h
|
|
create mode 100644 include/lib/usb/usb_st_dfu.h
|
|
create mode 100644 lib/compiler-rt/builtins/lshrdi3.c
|
|
create mode 100644 lib/usb/usb_core.c
|
|
create mode 100644 lib/usb/usb_st_dfu.c
|
|
create mode 100644 plat/common/aarch32/crash_console_helpers.S
|
|
create mode 100644 plat/common/aarch64/crash_console_helpers.S
|
|
create mode 100644 plat/st/common/bl2_io_storage.c
|
|
create mode 100644 plat/st/common/include/stm32mp_auth.h
|
|
create mode 100644 plat/st/common/include/stm32mp_common.h
|
|
create mode 100644 plat/st/common/include/stm32mp_dt.h
|
|
create mode 100644 plat/st/common/include/stm32mp_shres_helpers.h
|
|
create mode 100644 plat/st/common/stm32mp_auth.c
|
|
create mode 100644 plat/st/common/stm32mp_common.c
|
|
create mode 100644 plat/st/common/stm32mp_dt.c
|
|
create mode 100644 plat/st/common/stm32mp_shres_helpers.c
|
|
delete mode 100644 plat/st/stm32mp1/bl2_io_storage.c
|
|
create mode 100644 plat/st/stm32mp1/include/stm32mp1_dbgmcu.h
|
|
delete mode 100644 plat/st/stm32mp1/include/stm32mp1_dt.h
|
|
create mode 100644 plat/st/stm32mp1/include/stm32mp1_low_power.h
|
|
create mode 100644 plat/st/stm32mp1/include/stm32mp1_power_config.h
|
|
create mode 100644 plat/st/stm32mp1/include/stm32mp1_shared_resources.h
|
|
create mode 100644 plat/st/stm32mp1/include/stm32mp1_smc.h
|
|
create mode 100644 plat/st/stm32mp1/include/stm32mp1_usb_desc.h
|
|
create mode 100644 plat/st/stm32mp1/include/usb_ctx.h
|
|
create mode 100644 plat/st/stm32mp1/services/bsec_svc.c
|
|
create mode 100644 plat/st/stm32mp1/services/bsec_svc.h
|
|
create mode 100644 plat/st/stm32mp1/services/low_power_svc.c
|
|
create mode 100644 plat/st/stm32mp1/services/low_power_svc.h
|
|
create mode 100644 plat/st/stm32mp1/services/pwr_svc.c
|
|
create mode 100644 plat/st/stm32mp1/services/pwr_svc.h
|
|
create mode 100644 plat/st/stm32mp1/services/rcc_svc.c
|
|
create mode 100644 plat/st/stm32mp1/services/rcc_svc.h
|
|
create mode 100644 plat/st/stm32mp1/services/stm32mp1_svc_setup.c
|
|
delete mode 100644 plat/st/stm32mp1/stm32mp1_common.c
|
|
create mode 100644 plat/st/stm32mp1/stm32mp1_dbgmcu.c
|
|
delete mode 100644 plat/st/stm32mp1/stm32mp1_dt.c
|
|
create mode 100644 plat/st/stm32mp1/stm32mp1_helper_dbg.S
|
|
create mode 100644 plat/st/stm32mp1/stm32mp1_low_power.c
|
|
create mode 100644 plat/st/stm32mp1/stm32mp1_power_config.c
|
|
create mode 100644 plat/st/stm32mp1/stm32mp1_private.c
|
|
create mode 100644 plat/st/stm32mp1/stm32mp1_shared_resources.c
|
|
create mode 100644 plat/st/stm32mp1/stm32mp1_syscfg.c
|
|
create mode 100644 plat/st/stm32mp1/stm32mp1_usb_desc.c
|
|
|
|
diff --git a/.checkpatch.conf b/.checkpatch.conf
|
|
index 63bdf7b..066207b 100644
|
|
--- a/.checkpatch.conf
|
|
+++ b/.checkpatch.conf
|
|
@@ -93,3 +93,21 @@
|
|
# "Use of volatile is usually wrong: see Documentation/volatile-considered-harmful.txt"
|
|
# We allow the usage of the volatile keyword in TF.
|
|
--ignore VOLATILE
|
|
+
|
|
+# PREFER_KERNEL_TYPES reports this kind of messages (when using --strict):
|
|
+# "Prefer kernel type 'u32' over 'uint32_t'"
|
|
+--ignore PREFER_KERNEL_TYPES
|
|
+
|
|
+# USLEEP_RANGE reports this kind of messages (when using --strict):
|
|
+# "usleep_range is preferred over udelay; see Documentation/timers/timers-howto.txt"
|
|
+--ignore USLEEP_RANGE
|
|
+
|
|
+# COMPARISON_TO_NULL reports this kind of messages (when using --strict):
|
|
+# Comparison to NULL could be written ""
|
|
+--ignore COMPARISON_TO_NULL
|
|
+
|
|
+# UNNECESSARY_PARENTHESES reports this kind of messages (when using --strict):
|
|
+# Unnecessary parentheses around ""
|
|
+--ignore UNNECESSARY_PARENTHESES
|
|
+
|
|
+--ignore BRACES
|
|
diff --git a/Makefile b/Makefile
|
|
index 23a1b0a..cda7e7d 100644
|
|
--- a/Makefile
|
|
+++ b/Makefile
|
|
@@ -187,8 +187,48 @@ TF_CFLAGS_aarch64 += -mgeneral-regs-only -mstrict-align
|
|
ASFLAGS_aarch32 = $(march32-directive)
|
|
ASFLAGS_aarch64 = -march=armv8-a
|
|
|
|
+WARNING1 := -Wextra
|
|
+WARNING1 += -Wunused -Wno-unused-parameter
|
|
+WARNING1 += -Wmissing-declarations
|
|
+WARNING1 += -Wmissing-format-attribute
|
|
+WARNING1 += -Wmissing-prototypes
|
|
+WARNING1 += -Wold-style-definition
|
|
+WARNING1 += -Wunused-but-set-variable
|
|
+WARNING1 += -Wunused-const-variable
|
|
+
|
|
+WARNING2 := -Waggregate-return
|
|
+WARNING2 += -Wcast-align
|
|
+WARNING2 += -Wdisabled-optimization
|
|
+WARNING2 += -Wnested-externs
|
|
+WARNING2 += -Wshadow
|
|
+WARNING2 += -Wlogical-op
|
|
+WARNING2 += -Wmissing-field-initializers
|
|
+WARNING2 += -Wsign-compare
|
|
+WARNING2 += -Wmaybe-uninitialized
|
|
+
|
|
+WARNING3 := -Wbad-function-cast
|
|
+WARNING3 += -Wcast-qual
|
|
+WARNING3 += -Wconversion
|
|
+WARNING3 += -Wpacked
|
|
+WARNING3 += -Wpadded
|
|
+WARNING3 += -Wpointer-arith
|
|
+WARNING3 += -Wredundant-decls
|
|
+WARNING3 += -Wswitch-default
|
|
+WARNING3 += -Wpacked-bitfield-compat
|
|
+WARNING3 += -Wvla
|
|
+
|
|
+ifeq (${W},1)
|
|
+WARN_OR_ERROR := $(WARNING1)
|
|
+else ifeq (${W},2)
|
|
+WARN_OR_ERROR := $(WARNING1) $(WARNING2)
|
|
+else ifeq (${W},3)
|
|
+WARN_OR_ERROR := $(WARNING1) $(WARNING2) $(WARNING3)
|
|
+else
|
|
+WARN_OR_ERROR := -Werror
|
|
+endif
|
|
+
|
|
CPPFLAGS = ${DEFINES} ${INCLUDES} ${MBEDTLS_INC} -nostdinc \
|
|
- -Wmissing-include-dirs -Werror
|
|
+ -Wmissing-include-dirs $(WARN_OR_ERROR)
|
|
ASFLAGS += $(CPPFLAGS) $(ASFLAGS_$(ARCH)) \
|
|
-D__ASSEMBLY__ -ffreestanding \
|
|
-Wa,--fatal-warnings
|
|
@@ -396,12 +436,6 @@ ifeq ($(HW_ASSISTED_COHERENCY)-$(USE_COHERENT_MEM),1-1)
|
|
$(error USE_COHERENT_MEM cannot be enabled with HW_ASSISTED_COHERENCY)
|
|
endif
|
|
|
|
-ifneq ($(MULTI_CONSOLE_API), 0)
|
|
- ifeq (${ARCH},aarch32)
|
|
- $(error "Error: MULTI_CONSOLE_API is not supported for AArch32")
|
|
- endif
|
|
-endif
|
|
-
|
|
#For now, BL2_IN_XIP_MEM is only supported when BL2_AT_EL3 is 1.
|
|
ifeq ($(BL2_AT_EL3)-$(BL2_IN_XIP_MEM),0-1)
|
|
$(error "BL2_IN_XIP_MEM is only supported when BL2_AT_EL3 is enabled")
|
|
@@ -592,6 +626,7 @@ $(eval $(call assert_boolean,USE_TBBR_DEFS))
|
|
$(eval $(call assert_boolean,WARMBOOT_ENABLE_DCACHE_EARLY))
|
|
$(eval $(call assert_boolean,BL2_AT_EL3))
|
|
$(eval $(call assert_boolean,BL2_IN_XIP_MEM))
|
|
+$(eval $(call assert_boolean,AARCH32_EXCEPTION_DEBUG))
|
|
|
|
$(eval $(call assert_numeric,ARM_ARCH_MAJOR))
|
|
$(eval $(call assert_numeric,ARM_ARCH_MINOR))
|
|
@@ -644,6 +679,7 @@ $(eval $(call add_define,USE_TBBR_DEFS))
|
|
$(eval $(call add_define,WARMBOOT_ENABLE_DCACHE_EARLY))
|
|
$(eval $(call add_define,BL2_AT_EL3))
|
|
$(eval $(call add_define,BL2_IN_XIP_MEM))
|
|
+$(eval $(call add_define,AARCH32_EXCEPTION_DEBUG))
|
|
|
|
# Define the EL3_PAYLOAD_BASE flag only if it is provided.
|
|
ifdef EL3_PAYLOAD_BASE
|
|
@@ -784,9 +820,11 @@ checkpatch: locate-checkpatch
|
|
for commit in `git rev-list $$COMMON_COMMIT..HEAD`; do \
|
|
printf "\n[*] Checking style of '$$commit'\n\n"; \
|
|
git log --format=email "$$commit~..$$commit" \
|
|
- -- ${CHECK_PATHS} | ${CHECKPATCH} - || true; \
|
|
+ -- ${CHECK_PATHS} | ${CHECKPATCH} --strict - || \
|
|
+ true; \
|
|
git diff --format=email "$$commit~..$$commit" \
|
|
- -- ${CHECK_PATHS} | ${CHECKPATCH} - || true; \
|
|
+ -- ${CHECK_PATHS} | ${CHECKPATCH} --strict - || \
|
|
+ true; \
|
|
done
|
|
|
|
certtool: ${CRTTOOL}
|
|
diff --git a/bl2/aarch32/bl2_arch_setup.c b/bl2/aarch32/bl2_arch_setup.c
|
|
index db8a068..4fd8d07 100644
|
|
--- a/bl2/aarch32/bl2_arch_setup.c
|
|
+++ b/bl2/aarch32/bl2_arch_setup.c
|
|
@@ -4,6 +4,7 @@
|
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
*/
|
|
|
|
+#include "../bl2_private.h"
|
|
|
|
/*******************************************************************************
|
|
* Place holder function to perform any Secure SVC specific architectural
|
|
diff --git a/bl2/aarch32/bl2_el3_entrypoint.S b/bl2/aarch32/bl2_el3_entrypoint.S
|
|
index 0c7b064..437188e 100644
|
|
--- a/bl2/aarch32/bl2_el3_entrypoint.S
|
|
+++ b/bl2/aarch32/bl2_el3_entrypoint.S
|
|
@@ -15,6 +15,10 @@
|
|
|
|
|
|
func bl2_entrypoint
|
|
+#if STM32MP1_RESET_HALT_WORKAROUND
|
|
+ bl plat_dbg_attach_loop
|
|
+#endif
|
|
+
|
|
/* Save arguments x0-x3 from previous Boot loader */
|
|
mov r9, r0
|
|
mov r10, r1
|
|
diff --git a/bl2/aarch32/bl2_el3_exceptions.S b/bl2/aarch32/bl2_el3_exceptions.S
|
|
index 11ddf37..7058b07 100644
|
|
--- a/bl2/aarch32/bl2_el3_exceptions.S
|
|
+++ b/bl2/aarch32/bl2_el3_exceptions.S
|
|
@@ -12,10 +12,19 @@
|
|
|
|
vector_base bl2_vector_table
|
|
b bl2_entrypoint
|
|
+#if AARCH32_EXCEPTION_DEBUG
|
|
+ b report_undef_inst /* Undef */
|
|
+#else
|
|
b report_exception /* Undef */
|
|
+#endif
|
|
b report_exception /* SVC call */
|
|
+#if AARCH32_EXCEPTION_DEBUG
|
|
+ b report_prefetch_abort /* Prefetch abort */
|
|
+ b report_data_abort /* Data abort */
|
|
+#else
|
|
b report_exception /* Prefetch abort */
|
|
b report_exception /* Data abort */
|
|
+#endif
|
|
b report_exception /* Reserved */
|
|
b report_exception /* IRQ */
|
|
b report_exception /* FIQ */
|
|
diff --git a/bl2/aarch32/bl2_entrypoint.S b/bl2/aarch32/bl2_entrypoint.S
|
|
index d215f48..f76c1c9 100644
|
|
--- a/bl2/aarch32/bl2_entrypoint.S
|
|
+++ b/bl2/aarch32/bl2_entrypoint.S
|
|
@@ -15,10 +15,19 @@
|
|
|
|
vector_base bl2_vector_table
|
|
b bl2_entrypoint
|
|
+#if AARCH32_EXCEPTION_DEBUG
|
|
+ b report_undef_inst /* Undef */
|
|
+#else
|
|
b report_exception /* Undef */
|
|
+#endif
|
|
b report_exception /* SVC call */
|
|
+#if AARCH32_EXCEPTION_DEBUG
|
|
+ b report_prefetch_abort /* Prefetch abort */
|
|
+ b report_data_abort /* Data abort */
|
|
+#else
|
|
b report_exception /* Prefetch abort */
|
|
b report_exception /* Data abort */
|
|
+#endif
|
|
b report_exception /* Reserved */
|
|
b report_exception /* IRQ */
|
|
b report_exception /* FIQ */
|
|
diff --git a/bl2/bl2_image_load_v2.c b/bl2/bl2_image_load_v2.c
|
|
index 0f40785..2e3e145 100644
|
|
--- a/bl2/bl2_image_load_v2.c
|
|
+++ b/bl2/bl2_image_load_v2.c
|
|
@@ -69,17 +69,17 @@ struct entry_point_info *bl2_load_images(void)
|
|
ERROR("BL2: Failed to load image (%i)\n", err);
|
|
plat_error_handler(err);
|
|
}
|
|
+
|
|
+ /* Allow platform to handle image information. */
|
|
+ err = bl2_plat_handle_post_image_load(bl2_node_info->image_id);
|
|
+ if (err) {
|
|
+ ERROR("BL2: Failure in post image load handling (%i)\n", err);
|
|
+ plat_error_handler(err);
|
|
+ }
|
|
} else {
|
|
INFO("BL2: Skip loading image id %d\n", bl2_node_info->image_id);
|
|
}
|
|
|
|
- /* Allow platform to handle image information. */
|
|
- err = bl2_plat_handle_post_image_load(bl2_node_info->image_id);
|
|
- if (err) {
|
|
- ERROR("BL2: Failure in post image load handling (%i)\n", err);
|
|
- plat_error_handler(err);
|
|
- }
|
|
-
|
|
/* Go to next image */
|
|
bl2_node_info = bl2_node_info->next_load_info;
|
|
}
|
|
diff --git a/bl2/bl2_private.h b/bl2/bl2_private.h
|
|
index f93a179..8e602ff 100644
|
|
--- a/bl2/bl2_private.h
|
|
+++ b/bl2/bl2_private.h
|
|
@@ -8,6 +8,9 @@
|
|
#define __BL2_PRIVATE_H__
|
|
|
|
#if BL2_IN_XIP_MEM
|
|
+
|
|
+#include <stdint.h>
|
|
+
|
|
/*******************************************************************************
|
|
* Declarations of linker defined symbols which will tell us where BL2 lives
|
|
* in Trusted ROM and RAM
|
|
diff --git a/bl2u/aarch32/bl2u_entrypoint.S b/bl2u/aarch32/bl2u_entrypoint.S
|
|
index 7fb64f3..b511499 100644
|
|
--- a/bl2u/aarch32/bl2u_entrypoint.S
|
|
+++ b/bl2u/aarch32/bl2u_entrypoint.S
|
|
@@ -15,10 +15,19 @@
|
|
|
|
vector_base bl2u_vector_table
|
|
b bl2u_entrypoint
|
|
+#if AARCH32_EXCEPTION_DEBUG
|
|
+ b report_undef_inst /* Undef */
|
|
+#else
|
|
b report_exception /* Undef */
|
|
+#endif
|
|
b report_exception /* SVC call */
|
|
+#if AARCH32_EXCEPTION_DEBUG
|
|
+ b report_prefetch_abort /* Prefetch abort */
|
|
+ b report_data_abort /* Data abort */
|
|
+#else
|
|
b report_exception /* Prefetch abort */
|
|
b report_exception /* Data abort */
|
|
+#endif
|
|
b report_exception /* Reserved */
|
|
b report_exception /* IRQ */
|
|
b report_exception /* FIQ */
|
|
diff --git a/bl32/sp_min/aarch32/entrypoint.S b/bl32/sp_min/aarch32/entrypoint.S
|
|
index d6853cc..2d67af3 100644
|
|
--- a/bl32/sp_min/aarch32/entrypoint.S
|
|
+++ b/bl32/sp_min/aarch32/entrypoint.S
|
|
@@ -44,10 +44,19 @@
|
|
|
|
vector_base sp_min_vector_table
|
|
b sp_min_entrypoint
|
|
+#if AARCH32_EXCEPTION_DEBUG
|
|
+ b report_undef_inst /* Undef */
|
|
+#else
|
|
b plat_panic_handler /* Undef */
|
|
+#endif
|
|
b sp_min_handle_smc /* Syscall */
|
|
+#if AARCH32_EXCEPTION_DEBUG
|
|
+ b report_prefetch_abort /* Prefetch abort */
|
|
+ b report_data_abort /* Data abort */
|
|
+#else
|
|
b plat_panic_handler /* Prefetch abort */
|
|
b plat_panic_handler /* Data abort */
|
|
+#endif
|
|
b plat_panic_handler /* Reserved */
|
|
b plat_panic_handler /* IRQ */
|
|
b sp_min_handle_fiq /* FIQ */
|
|
diff --git a/common/aarch32/debug.S b/common/aarch32/debug.S
|
|
index f506356..a058645 100644
|
|
--- a/common/aarch32/debug.S
|
|
+++ b/common/aarch32/debug.S
|
|
@@ -7,9 +7,16 @@
|
|
#include <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/docs/devicetree/bindings/arm/secure.txt b/docs/devicetree/bindings/arm/secure.txt
|
|
new file mode 100644
|
|
index 0000000..e31303f
|
|
--- /dev/null
|
|
+++ b/docs/devicetree/bindings/arm/secure.txt
|
|
@@ -0,0 +1,53 @@
|
|
+* ARM Secure world bindings
|
|
+
|
|
+ARM CPUs with TrustZone support have two distinct address spaces,
|
|
+"Normal" and "Secure". Most devicetree consumers (including the Linux
|
|
+kernel) are not TrustZone aware and run entirely in either the Normal
|
|
+world or the Secure world. However some devicetree consumers are
|
|
+TrustZone aware and need to be able to determine whether devices are
|
|
+visible only in the Secure address space, only in the Normal address
|
|
+space, or visible in both. (One example of that situation would be a
|
|
+virtual machine which boots Secure firmware and wants to tell the
|
|
+firmware about the layout of the machine via devicetree.)
|
|
+
|
|
+The general principle of the naming scheme for Secure world bindings
|
|
+is that any property that needs a different value in the Secure world
|
|
+can be supported by prefixing the property name with "secure-". So for
|
|
+instance "secure-foo" would override "foo". For property names with
|
|
+a vendor prefix, the Secure variant of "vendor,foo" would be
|
|
+"vendor,secure-foo". If there is no "secure-" property then the Secure
|
|
+world value is the same as specified for the Normal world by the
|
|
+non-prefixed property. However, only the properties listed below may
|
|
+validly have "secure-" versions; this list will be enlarged on a
|
|
+case-by-case basis.
|
|
+
|
|
+Defining the bindings in this way means that a device tree which has
|
|
+been annotated to indicate the presence of Secure-only devices can
|
|
+still be processed unmodified by existing Non-secure software (and in
|
|
+particular by the kernel).
|
|
+
|
|
+Note that it is still valid for bindings intended for purely Secure
|
|
+world consumers (like kernels that run entirely in Secure) to simply
|
|
+describe the view of Secure world using the standard bindings. These
|
|
+secure- bindings only need to be used where both the Secure and Normal
|
|
+world views need to be described in a single device tree.
|
|
+
|
|
+Valid Secure world properties:
|
|
+
|
|
+- secure-status : specifies whether the device is present and usable
|
|
+ in the secure world. The combination of this with "status" allows
|
|
+ the various possible combinations of device visibility to be
|
|
+ specified. If "secure-status" is not specified it defaults to the
|
|
+ same value as "status"; if "status" is not specified either then
|
|
+ both default to "okay". This means the following combinations are
|
|
+ possible:
|
|
+
|
|
+ /* Neither specified: default to visible in both S and NS */
|
|
+ secure-status = "okay"; /* visible in both */
|
|
+ status = "okay"; /* visible in both */
|
|
+ status = "okay"; secure-status = "okay"; /* visible in both */
|
|
+ secure-status = "disabled"; /* NS-only */
|
|
+ status = "okay"; secure-status = "disabled"; /* NS-only */
|
|
+ status = "disabled"; secure-status = "okay"; /* S-only */
|
|
+ status = "disabled"; /* disabled in both */
|
|
+ status = "disabled"; secure-status = "disabled"; /* disabled in both */
|
|
diff --git a/docs/devicetree/bindings/clock/st,stm32mp1-rcc.txt b/docs/devicetree/bindings/clock/st,stm32mp1-rcc.txt
|
|
new file mode 100644
|
|
index 0000000..7021486
|
|
--- /dev/null
|
|
+++ b/docs/devicetree/bindings/clock/st,stm32mp1-rcc.txt
|
|
@@ -0,0 +1,324 @@
|
|
+STMicroelectronics STM32 Peripheral Reset Clock Controller
|
|
+==========================================================
|
|
+
|
|
+The RCC IP is both a reset and a clock controller.
|
|
+
|
|
+RCC makes also power management (resume/supend and wakeup interrupt).
|
|
+
|
|
+Please also refer to reset.txt for common reset controller binding usage.
|
|
+
|
|
+Please also refer to clock-bindings.txt for common clock controller
|
|
+binding usage.
|
|
+
|
|
+
|
|
+Required properties:
|
|
+- compatible: "st,stm32mp1-rcc", "syscon"
|
|
+- reg: should be register base and length as documented in the datasheet
|
|
+- #clock-cells: 1, device nodes should specify the clock in their
|
|
+ "clocks" property, containing a phandle to the clock device node,
|
|
+ an index specifying the clock to use.
|
|
+- #reset-cells: Shall be 1
|
|
+- interrupts: Should contain a general interrupt line and a interrupt line
|
|
+ to the wake-up of processor (CSTOP).
|
|
+
|
|
+Example:
|
|
+ rcc: rcc@50000000 {
|
|
+ compatible = "st,stm32mp1-rcc", "syscon";
|
|
+ reg = <0x50000000 0x1000>;
|
|
+ #clock-cells = <1>;
|
|
+ #reset-cells = <1>;
|
|
+ interrupts = <GIC_SPI 5 IRQ_TYPE_NONE>,
|
|
+ <GIC_SPI 145 IRQ_TYPE_NONE>;
|
|
+ };
|
|
+
|
|
+Other properties:
|
|
+- secure-status: Relates to RCC TZ_ENABLE configuration to restrict RCC access.
|
|
+- st,clksrc : The clock sources configuration array in a platform specific order.
|
|
+- st,clkdiv : The clock dividers configuration array in a paltform specific order.
|
|
+- st,pll : A specific PLL configuration
|
|
+- st,pkcs : The peripheral kernel clock distribution configuration array.
|
|
+
|
|
+Specifying clocks
|
|
+=================
|
|
+
|
|
+All available clocks are defined as preprocessor macros in
|
|
+dt-bindings/clock/stm32mp1-clks.h header and can be used in device
|
|
+tree sources.
|
|
+
|
|
+Specifying softreset control of devices
|
|
+=======================================
|
|
+
|
|
+Device nodes should specify the reset channel required in their "resets"
|
|
+property, containing a phandle to the reset device node and an index specifying
|
|
+which channel to use.
|
|
+The index is the bit number within the RCC registers bank, starting from RCC
|
|
+base address.
|
|
+It is calculated as: index = register_offset / 4 * 32 + bit_offset.
|
|
+Where bit_offset is the bit offset within the register.
|
|
+
|
|
+For example on STM32MP1, for LTDC reset:
|
|
+ ltdc = APB4_RSTSETR_offset / 4 * 32 + LTDC_bit_offset
|
|
+ = 0x180 / 4 * 32 + 0 = 3072
|
|
+
|
|
+The list of valid indices for STM32MP1 is available in:
|
|
+include/dt-bindings/reset-controller/stm32mp1-resets.h
|
|
+
|
|
+This file implements defines like:
|
|
+#define LTDC_R 3072
|
|
+
|
|
+
|
|
+Defining clock source distribution with property st,clksrc
|
|
+==========================================================
|
|
+
|
|
+Property can be used to configure the clock distribution tree.
|
|
+When used, it shall describe the whole distribution tree.
|
|
+
|
|
+For the STM32MP15x family there are 9 clock sources selector which are
|
|
+configured in the following order:
|
|
+ MPU AXI MCU PLL12 PLL3 PLL4 RTC MCO1 MCO2
|
|
+
|
|
+Clock source configuration values are defined by macros CLK_<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
|
|
+===============================================
|
|
+
|
|
+Property can be used to configure the clock main dividers value.
|
|
+When used, it shall describe the whole clock dividers tree.
|
|
+
|
|
+For the STM32MP15x family there are 11 dividers values expected.
|
|
+They shall be configured in the following order:
|
|
+ MPU AXI MCU APB1 APB2 APB3 APB4 APB5 RTC MCO1 MCO2
|
|
+
|
|
+The each divider value uses the DIV coding defined in RCC associated
|
|
+register RCC_xxxDIVR. In most cases, it is:
|
|
+ 0x0: not divided
|
|
+ 0x1: division by 2
|
|
+ 0x2: division by 4
|
|
+ 0x3: division by 8
|
|
+ ...
|
|
+
|
|
+Note that for RTC MCO1 MCO2, the coding is different:
|
|
+ 0x0: not divided
|
|
+ 0x1: division by 2
|
|
+ 0x2: division by 3
|
|
+ 0x3: division by 4
|
|
+ ...
|
|
+
|
|
+Example:
|
|
+ st,clkdiv = <
|
|
+ 1 /*MPU*/
|
|
+ 0 /*AXI*/
|
|
+ 0 /*MCU*/
|
|
+ 1 /*APB1*/
|
|
+ 1 /*APB2*/
|
|
+ 1 /*APB3*/
|
|
+ 1 /*APB4*/
|
|
+ 2 /*APB5*/
|
|
+ 23 /*RTC*/
|
|
+ 0 /*MCO1*/
|
|
+ 0 /*MCO2*/
|
|
+ >;
|
|
+
|
|
+Defining peripheral PLL frequencies with property st,pll
|
|
+========================================================
|
|
+
|
|
+This property can be used to configure PLL frequencies.
|
|
+
|
|
+PLL children nodes for PLL1 to PLL4 (see ref manual for details)
|
|
+are listed with associated index 0 to 3 (st,pll@0 to st,pll@3).
|
|
+PLLx is off when the associated node is absent.
|
|
+
|
|
+Here are the available properties for each PLL node:
|
|
+
|
|
+- cfg: The parameters for PLL configuration in the following order:
|
|
+ DIVM DIVN DIVP DIVQ DIVR Output.
|
|
+
|
|
+ DIVx values are defined as in RCC spec:
|
|
+ 0x0: bypass (division by 1)
|
|
+ 0x1: division by 2
|
|
+ 0x2: division by 3
|
|
+ 0x3: division by 4
|
|
+ ...
|
|
+
|
|
+ Output contains a bitfield for each output value (1:ON/0:OFF)
|
|
+ BIT(0) => output P : DIVPEN
|
|
+ BIT(1) => output Q : DIVQEN
|
|
+ BIT(2) => output R : DIVREN
|
|
+ NB: macro PQR(p,q,r) can be used to build this value
|
|
+ with p,q,r = 0 or 1.
|
|
+
|
|
+- frac: Fractional part of the multiplication factor
|
|
+ (optional, PLL is in integer mode when absent).
|
|
+
|
|
+- csg: Clock Spreading Generator (optional) with parameters in the following
|
|
+ order: MOD_PER INC_STEP SSCG_MODE.
|
|
+
|
|
+ MOD_PER: Modulation Period Adjustment
|
|
+ INC_STEP: Modulation Depth Adjustment
|
|
+ SSCG_MODE: Spread spectrum clock generator mode, with associated
|
|
+ defined from stm32mp1-clksrc.h:
|
|
+ - SSCG_MODE_CENTER_SPREAD = 0
|
|
+ - SSCG_MODE_DOWN_SPREAD = 1
|
|
+
|
|
+Example:
|
|
+ st,pll@0 {
|
|
+ cfg = < 1 53 0 0 0 1 >;
|
|
+ frac = < 0x810 >;
|
|
+ };
|
|
+ st,pll@1 {
|
|
+ cfg = < 1 43 1 0 0 PQR(0,1,1) >;
|
|
+ csg = < 10 20 1 >;
|
|
+ };
|
|
+ st,pll@2 {
|
|
+ cfg = < 2 85 3 13 3 0 >;
|
|
+ csg = < 10 20 SSCG_MODE_CENTER_SPREAD >;
|
|
+ };
|
|
+ st,pll@3 {
|
|
+ cfg = < 2 78 4 7 9 3 >;
|
|
+ };
|
|
+
|
|
+Defining peripherals kernel clock tree distribution with property st,pkcs
|
|
+=========================================================================
|
|
+
|
|
+This property can be used to configure the peripherals kernel clock selection.
|
|
+
|
|
+The property is a list of peripheral kernel clock source identifiers defined
|
|
+by macros CLK_<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
|
|
+ >;
|
|
+
|
|
+Fixed clocks description
|
|
+========================
|
|
+
|
|
+The clock tree is also based on 5 fixed-clock in clocks node
|
|
+used to define the state of associated ST32MP1 oscillators:
|
|
+- clk-lsi
|
|
+- clk-lse
|
|
+- clk-hsi
|
|
+- clk-hse
|
|
+- clk-csi
|
|
+
|
|
+At boot the clock tree initialization will
|
|
+- enable oscillators present in device tree
|
|
+- disable HSI oscillator if the node is absent (always activated by bootrom)
|
|
+
|
|
+Optional properties :
|
|
+
|
|
+a) for external oscillator: "clk-lse", "clk-hse"
|
|
+
|
|
+ 4 optional fields are managed
|
|
+ - "st,bypass" configures the oscillator bypass mode (HSEBYP, LSEBYP)
|
|
+ - "st,digbypass" configures the bypass mode as full-swing digital
|
|
+ signal (DIGBYP)
|
|
+ - "st,css" activates the clock security system (HSECSSON, LSECSSON)
|
|
+ - "st,drive" (only for LSE) contains the value of the drive for the
|
|
+ oscillator (see LSEDRV_ defined in the file
|
|
+ dt-bindings/clock/stm32mp1-clksrc.h)
|
|
+
|
|
+ Example board file:
|
|
+
|
|
+ / {
|
|
+ clocks {
|
|
+ clk_hse: clk-hse {
|
|
+ #clock-cells = <0>;
|
|
+ compatible = "fixed-clock";
|
|
+ clock-frequency = <64000000>;
|
|
+ st,bypass;
|
|
+ };
|
|
+
|
|
+ clk_lse: clk-lse {
|
|
+ #clock-cells = <0>;
|
|
+ compatible = "fixed-clock";
|
|
+ clock-frequency = <32768>;
|
|
+ st,css;
|
|
+ st,drive = <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 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>;
|
|
+ interrupt-names = "mcu_sev", "wakeup";
|
|
+ };
|
|
diff --git a/docs/devicetree/bindings/i2c/i2c-stm32.txt b/docs/devicetree/bindings/i2c/i2c-stm32.txt
|
|
new file mode 100644
|
|
index 0000000..68aefa6
|
|
--- /dev/null
|
|
+++ b/docs/devicetree/bindings/i2c/i2c-stm32.txt
|
|
@@ -0,0 +1,54 @@
|
|
+* I2C controller embedded in STMicroelectronics STM32 I2C platform
|
|
+
|
|
+Required properties :
|
|
+- compatible : Must be one of the following
|
|
+ - "st,stm32f7-i2c"
|
|
+- reg : Offset and length of the register set for the device
|
|
+- resets: Must contain the phandle to the reset controller.
|
|
+- clocks: Must contain the input clock of the I2C instance.
|
|
+- A pinctrl state named "default" must be defined to set pins in mode of
|
|
+ operation for I2C transfer. An optional pinctrl state named "sleep" has to
|
|
+ be defined as well as to put I2C in low power mode in suspend mode.
|
|
+- #address-cells = <1>;
|
|
+- #size-cells = <0>;
|
|
+
|
|
+Optional properties :
|
|
+- clock-frequency : Desired I2C bus clock frequency in Hz. If not specified,
|
|
+ the default 100 kHz frequency will be used.
|
|
+- i2c-scl-rising-time-ns : Only for STM32F7, I2C SCL Rising time for the board
|
|
+ (default: 25)
|
|
+- i2c-scl-falling-time-ns : Only for STM32F7, I2C SCL Falling time for the board
|
|
+ (default: 10)
|
|
+ I2C Timings are derived from these 2 values
|
|
+- st,syscfg-fmp: Only for STM32F7, use to set Fast Mode Plus bit within SYSCFG
|
|
+ whether Fast Mode Plus speed is selected by slave.
|
|
+ 1st cell : phandle to syscfg
|
|
+ 2nd cell : register offset within SYSCFG
|
|
+ 3rd cell : register bitmask for FMP bit
|
|
+
|
|
+Example :
|
|
+
|
|
+ i2c@40005400 {
|
|
+ compatible = "st,stm32f4-i2c";
|
|
+ #address-cells = <1>;
|
|
+ #size-cells = <0>;
|
|
+ reg = <0x40005400 0x400>;
|
|
+ resets = <&rcc 277>;
|
|
+ clocks = <&rcc 0 149>;
|
|
+ pinctrl-0 = <&i2c1_sda_pin>, <&i2c1_scl_pin>;
|
|
+ pinctrl-names = "default";
|
|
+ };
|
|
+
|
|
+ i2c@40005400 {
|
|
+ compatible = "st,stm32f7-i2c";
|
|
+ #address-cells = <1>;
|
|
+ #size-cells = <0>;
|
|
+ reg = <0x40005400 0x400>;
|
|
+ resets = <&rcc STM32F7_APB1_RESET(I2C1)>;
|
|
+ clocks = <&rcc 1 CLK_I2C1>;
|
|
+ pinctrl-0 = <&i2c1_sda_pin>, <&i2c1_scl_pin>;
|
|
+ pinctrl-1 = <&i2c1_sda_pin_sleep>, <&i2c1_scl_pin_sleep>;
|
|
+ pinctrl-names = "default", "sleep";
|
|
+ st,syscfg-fmp = <&syscfg 0x4 0x1>;
|
|
+ };
|
|
+
|
|
diff --git a/docs/devicetree/bindings/mmc/mmci.txt b/docs/devicetree/bindings/mmc/mmci.txt
|
|
new file mode 100644
|
|
index 0000000..6d3c626
|
|
--- /dev/null
|
|
+++ b/docs/devicetree/bindings/mmc/mmci.txt
|
|
@@ -0,0 +1,72 @@
|
|
+* ARM PrimeCell MultiMedia Card Interface (MMCI) PL180/1
|
|
+
|
|
+The ARM PrimeCell MMCI PL180 and PL181 provides an interface for
|
|
+reading and writing to MultiMedia and SD cards alike.
|
|
+
|
|
+This file documents differences between the core properties described
|
|
+by mmc.txt and the properties used by the mmci driver. Using "st" as
|
|
+the prefix for a property, indicates support by the ST Micro variant.
|
|
+
|
|
+Required properties:
|
|
+- compatible : contains "arm,pl18x", "arm,primecell".
|
|
+- vmmc-supply : phandle to the regulator device tree node, mentioned
|
|
+ as the VCC/VDD supply in the eMMC/SD specs.
|
|
+
|
|
+Optional properties:
|
|
+- arm,primecell-periphid : contains the PrimeCell Peripheral ID, it overrides
|
|
+ the ID provided by the HW
|
|
+- resets : phandle to internal reset line.
|
|
+ Should be defined for sdmmc variant.
|
|
+- vqmmc-supply : phandle to the regulator device tree node, mentioned
|
|
+ as the VCCQ/VDD_IO supply in the eMMC/SD specs.
|
|
+specific for ux500 variant:
|
|
+- st,sig-dir-dat0 : bus signal direction pin used for DAT[0].
|
|
+- st,sig-dir-dat2 : bus signal direction pin used for DAT[2].
|
|
+- st,sig-dir-dat31 : bus signal direction pin used for DAT[3] and DAT[1].
|
|
+- st,sig-dir-dat74 : bus signal direction pin used for DAT[4] to DAT[7].
|
|
+- st,sig-dir-cmd : cmd signal direction pin used for CMD.
|
|
+- st,sig-pin-fbclk : feedback clock signal pin used.
|
|
+
|
|
+specific for sdmmc variant:
|
|
+- st,sig-dir : signal direction polarity used for cmd, dat0 dat123.
|
|
+- st,neg-edge : data & command phase relation, generated on
|
|
+ sd clock falling edge.
|
|
+- st,use-ckin : use ckin pin from an external driver to sample
|
|
+ the receive data (example: with voltage
|
|
+ switch transceiver).
|
|
+
|
|
+Deprecated properties:
|
|
+- mmc-cap-mmc-highspeed : indicates whether MMC is high speed capable.
|
|
+- mmc-cap-sd-highspeed : indicates whether SD is high speed capable.
|
|
+
|
|
+Example:
|
|
+
|
|
+sdi0_per1@80126000 {
|
|
+ compatible = "arm,pl18x", "arm,primecell";
|
|
+ reg = <0x80126000 0x1000>;
|
|
+ interrupts = <0 60 IRQ_TYPE_LEVEL_HIGH>;
|
|
+
|
|
+ dmas = <&dma 29 0 0x2>, /* Logical - DevToMem */
|
|
+ <&dma 29 0 0x0>; /* Logical - MemToDev */
|
|
+ dma-names = "rx", "tx";
|
|
+
|
|
+ clocks = <&prcc_kclk 1 5>, <&prcc_pclk 1 5>;
|
|
+ clock-names = "sdi", "apb_pclk";
|
|
+
|
|
+ max-frequency = <100000000>;
|
|
+ bus-width = <4>;
|
|
+ cap-sd-highspeed;
|
|
+ cap-mmc-highspeed;
|
|
+ cd-gpios = <&gpio2 31 0x4>; // 95
|
|
+ st,sig-dir-dat0;
|
|
+ st,sig-dir-dat2;
|
|
+ st,sig-dir-cmd;
|
|
+ st,sig-pin-fbclk;
|
|
+
|
|
+ vmmc-supply = <&ab8500_ldo_aux3_reg>;
|
|
+ vqmmc-supply = <&vmmci>;
|
|
+
|
|
+ pinctrl-names = "default", "sleep";
|
|
+ pinctrl-0 = <&sdi0_default_mode>;
|
|
+ pinctrl-1 = <&sdi0_sleep_mode>;
|
|
+};
|
|
diff --git a/docs/devicetree/bindings/mmc/st,stm32-sdmmc2.txt b/docs/devicetree/bindings/mmc/st,stm32-sdmmc2.txt
|
|
new file mode 100644
|
|
index 0000000..51576a3
|
|
--- /dev/null
|
|
+++ b/docs/devicetree/bindings/mmc/st,stm32-sdmmc2.txt
|
|
@@ -0,0 +1,22 @@
|
|
+* STMicroelectronics STM32 SDMMC2 controller
|
|
+
|
|
+The highspeed MMC host controller on STM32 soc family
|
|
+provides an interface for MMC, SD and SDIO types of memory cards.
|
|
+
|
|
+This file documents differences between the core properties described
|
|
+by mmci.txt and the properties used by the sdmmc2 driver.
|
|
+
|
|
+Required properties:
|
|
+ - compatible: should be one of:
|
|
+ "st,stm32-sdmmc2"
|
|
+
|
|
+Example:
|
|
+ sdmmc1: sdmmc@0x58005000 {
|
|
+ compatible = "st,stm32-sdmmc2";
|
|
+ reg = <0x58005000 0x1000>;
|
|
+ clocks = <&rcc SDMMC1_K>;
|
|
+ resets = <&rcc SDMMC1_R>;
|
|
+ cap-sd-highspeed;
|
|
+ cap-mmc-highspeed;
|
|
+ status = "disabled";
|
|
+ };
|
|
diff --git a/docs/devicetree/bindings/power/st,stm32mp1-pwr.txt b/docs/devicetree/bindings/power/st,stm32mp1-pwr.txt
|
|
new file mode 100644
|
|
index 0000000..bd56e19
|
|
--- /dev/null
|
|
+++ b/docs/devicetree/bindings/power/st,stm32mp1-pwr.txt
|
|
@@ -0,0 +1,42 @@
|
|
+STMicroelectronics STM32MP1 Power Management Controller
|
|
+=======================================================
|
|
+
|
|
+The PWR IP is responsible for handling the power related resources such as
|
|
+clocks, power supplies and resets. It provides 6 wake-up pins that are handled
|
|
+by an interrupt-controller. Wake-up pin can be used to wake-up from STANDBY SoC
|
|
+state.
|
|
+
|
|
+Required properties:
|
|
+- compatible should be: "st,stm32mp1-pwr", "st,stm32-pwr"
|
|
+- reg: should be register base and length as documented in the
|
|
+ datasheet
|
|
+
|
|
+Optional Properties:
|
|
+- Nodes corresponding to PSCI commands issued by kernel:
|
|
+ - system_suspend_supported_soc_modes: list of supported SoC modes in suspend
|
|
+ - system_off_soc_mode: SoC mode for shutdown
|
|
+
|
|
+The list of SoC modes is in include/dt-bindings/power/stm32mp1-power.h:
|
|
+ - modes for system_suspend
|
|
+ 1 -> STM32_PM_CSTOP_ALLOW_STOP
|
|
+ 2 -> STM32_PM_CSTOP_ALLOW_LP_STOP
|
|
+ 3 -> STM32_PM_CSTOP_ALLOW_LPLV_STOP
|
|
+ 4 -> STM32_PM_CSTOP_ALLOW_STANDBY_DDR_SR
|
|
+ - modes for system_off
|
|
+ 6 -> STM32_PM_CSTOP_ALLOW_STANDBY_DDR_OFF
|
|
+ 7 -> STM32_PM_SHUTDOWN
|
|
+
|
|
+Example:
|
|
+
|
|
+pwr: pwr@50001000 {
|
|
+ compatible = "st,stm32mp1-pwr", "st,stm32-pwr", "syscon", "simple-mfd";
|
|
+ reg = <0x50001000 0x400>;
|
|
+
|
|
+ system_suspend_supported_soc_modes = <
|
|
+ STM32_PM_CSLEEP_RUN
|
|
+ STM32_PM_CSTOP_ALLOW_LP_STOP
|
|
+ STM32_PM_CSTOP_ALLOW_STANDBY_DDR_SR
|
|
+ >;
|
|
+
|
|
+ system_off_soc_mode = <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 0000000..54b64e2
|
|
--- /dev/null
|
|
+++ b/docs/devicetree/bindings/power/st,stpmic1.txt
|
|
@@ -0,0 +1,132 @@
|
|
+* STMicroelectronics STPMIC1 Power Management IC
|
|
+
|
|
+Required parent device properties:
|
|
+- compatible: "st,stpmic1"
|
|
+- reg: The I2C slave address for the STPMIC1 chip.
|
|
+- interrupts: The interrupt lines the device is connected to.
|
|
+ The second interrupt is used for wake-up.
|
|
+- #interrupt-cells: Should be 2.
|
|
+- interrupt-controller: Describes the STPMIC1 as an interrupt
|
|
+ controller (has its own domain). Interrupt number are the following:
|
|
+ /* Interrupt Register 1 (0x50 for latch) */
|
|
+ IT_SWOUT_R=0
|
|
+ IT_SWOUT_F=1
|
|
+ IT_VBUS_OTG_R=2
|
|
+ IT_VBUS_OTG_F=3
|
|
+ IT_WAKEUP_R=4
|
|
+ IT_WAKEUP_F=5
|
|
+ IT_PONKEY_R=6
|
|
+ IT_PONKEY_F=7
|
|
+ /* Interrupt Register 2 (0x51 for latch) */
|
|
+ IT_OVP_BOOST=8
|
|
+ IT_OCP_BOOST=9
|
|
+ IT_OCP_SWOUT=10
|
|
+ IT_OCP_OTG=11
|
|
+ IT_CURLIM_BUCK4=12
|
|
+ IT_CURLIM_BUCK3=13
|
|
+ IT_CURLIM_BUCK2=14
|
|
+ IT_CURLIM_BUCK1=15
|
|
+ /* Interrupt Register 3 (0x52 for latch) */
|
|
+ IT_SHORT_SWOUT=16
|
|
+ IT_SHORT_SWOTG=17
|
|
+ IT_CURLIM_LDO6=18
|
|
+ IT_CURLIM_LDO5=19
|
|
+ IT_CURLIM_LDO4=20
|
|
+ IT_CURLIM_LDO3=21
|
|
+ IT_CURLIM_LDO2=22
|
|
+ IT_CURLIM_LDO1=23
|
|
+ /* Interrupt Register 3 (0x52 for latch) */
|
|
+ IT_SWIN_R=24
|
|
+ IT_SWIN_F=25
|
|
+ IT_RESERVED_1=26
|
|
+ IT_RESERVED_2=27
|
|
+ IT_VINLOW_R=28
|
|
+ IT_VINLOW_F=29
|
|
+ IT_TWARN_R=30
|
|
+ IT_TWARN_F=31
|
|
+
|
|
+Optional parent device properties:
|
|
+- st,main-control-register:
|
|
+ -bit 1: Power cycling will be performed on turn OFF condition
|
|
+ -bit 2: PWRCTRL is functional
|
|
+ -bit 3: PWRCTRL active high
|
|
+- st,pads-pull-register:
|
|
+ -bit 1: WAKEUP pull down is not active
|
|
+ -bit 2: PWRCTRL pull up is active
|
|
+ -bit 3: PWRCTRL pull down is active
|
|
+ -bit 4: WAKEUP detector is disabled
|
|
+- st,vin-control-register:
|
|
+ -bit 0: VINLOW monitoring is enabled
|
|
+ -bit [1...3]: VINLOW rising threshold
|
|
+ 000 VINOK_f + 50mV
|
|
+ 001 VINOK_f + 100mV
|
|
+ 010 VINOK_f + 150mV
|
|
+ 011 VINOK_f + 200mV
|
|
+ 100 VINOK_f + 250mV
|
|
+ 101 VINOK_f + 300mV
|
|
+ 110 VINOK_f + 350mV
|
|
+ 111 VINOK_f + 400mV
|
|
+ -bit [4...5]: VINLOW hyst
|
|
+ 00 100mV
|
|
+ 01 200mV
|
|
+ 10 300mV
|
|
+ 11 400mV
|
|
+ -bit 6: SW_OUT detector is disabled
|
|
+ -bit 7: SW_IN detector is enabled.
|
|
+- st,usb-control-register:
|
|
+ -bit 3: SW_OUT current limit
|
|
+ 0: 600mA
|
|
+ 1: 1.1A
|
|
+ -bit 4: VBUS_OTG discharge is enabled
|
|
+ -bit 5: SW_OUT discharge is enabled
|
|
+ -bit 6: VBUS_OTG detection is enabled
|
|
+ -bit 7: BOOST_OVP is disabled
|
|
+
|
|
+STPMIC1 consists in a varied group of sub-devices.
|
|
+Each sub-device binding is be described in own documentation file.
|
|
+
|
|
+Device Description
|
|
+------ ------------
|
|
+st,stpmic1-onkey : Power on key, see ../input/st,stpmic1-onkey.txt
|
|
+st,stpmic1-regulators : Regulators, see ../regulator/st,stpmic1-regulator.txt
|
|
+st,stpmic1-wdt : Watchdog, see ../watchdog/st,stpmic1-wdt.txt
|
|
+
|
|
+Example:
|
|
+
|
|
+pmic: pmic@33 {
|
|
+ compatible = "st,stpmic1";
|
|
+ reg = <0x33>;
|
|
+ interrupt-parent = <&gpioa>;
|
|
+ interrupts = <0 2>;
|
|
+ st,main-control-register=<0x0c>;
|
|
+ interrupt-controller;
|
|
+ #interrupt-cells = <2>;
|
|
+
|
|
+ onkey {
|
|
+ compatible = "st,stpmic1-onkey";
|
|
+ interrupts = <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 0000000..b4edaf7
|
|
--- /dev/null
|
|
+++ b/docs/devicetree/bindings/reset/st,stm32mp1-rcc.txt
|
|
@@ -0,0 +1,6 @@
|
|
+STMicroelectronics STM32MP1 Peripheral Reset Controller
|
|
+=======================================================
|
|
+
|
|
+The RCC IP is both a reset and a clock controller.
|
|
+
|
|
+Please see Documentation/devicetree/bindings/clock/st,stm32mp1-rcc.txt
|
|
diff --git a/docs/devicetree/bindings/rng/st,stm32-rng.txt b/docs/devicetree/bindings/rng/st,stm32-rng.txt
|
|
new file mode 100644
|
|
index 0000000..3c613d7
|
|
--- /dev/null
|
|
+++ b/docs/devicetree/bindings/rng/st,stm32-rng.txt
|
|
@@ -0,0 +1,23 @@
|
|
+STMicroelectronics STM32 HW RNG
|
|
+===============================
|
|
+
|
|
+The STM32 hardware random number generator is a simple fixed purpose IP and
|
|
+is fully separated from other crypto functions.
|
|
+
|
|
+Required properties:
|
|
+
|
|
+- compatible : Should be "st,stm32-rng"
|
|
+- reg : Should be register base and length as documented in the datasheet
|
|
+- clocks : The clock needed to enable the RNG
|
|
+
|
|
+Optional properties:
|
|
+- resets : The reset to properly start RNG
|
|
+- clock-error-detect : Enable the clock detection management
|
|
+
|
|
+Example:
|
|
+
|
|
+ rng: rng@50060800 {
|
|
+ compatible = "st,stm32-rng";
|
|
+ reg = <0x50060800 0x400>;
|
|
+ clocks = <&rcc 0 38>;
|
|
+ };
|
|
diff --git a/docs/devicetree/bindings/serial/st,stm32-usart.txt b/docs/devicetree/bindings/serial/st,stm32-usart.txt
|
|
new file mode 100644
|
|
index 0000000..08b4990
|
|
--- /dev/null
|
|
+++ b/docs/devicetree/bindings/serial/st,stm32-usart.txt
|
|
@@ -0,0 +1,88 @@
|
|
+* STMicroelectronics STM32 USART
|
|
+
|
|
+Required properties:
|
|
+- compatible: can be either:
|
|
+ - "st,stm32-uart",
|
|
+ - "st,stm32f7-uart",
|
|
+ - "st,stm32h7-uart".
|
|
+ depending is compatible with stm32(f4), stm32f7 or stm32h7.
|
|
+- reg: The address and length of the peripheral registers space
|
|
+- interrupts:
|
|
+ - The interrupt line for the USART instance,
|
|
+ - An optional wake-up interrupt.
|
|
+- interrupt-names: Contains "event" for the USART interrupt line.
|
|
+- clocks: The input clock of the USART instance
|
|
+
|
|
+Optional properties:
|
|
+- resets: Must contain the phandle to the reset controller.
|
|
+- pinctrl-names: Set to "default". An additional "sleep" state can be defined
|
|
+ to set pins in sleep state when in low power. In case the device is used as
|
|
+ a wakeup source, "idle" state is defined in order to keep RX pin active.
|
|
+ For a console device, an optional state "no_console_suspend" can be defined
|
|
+ to enable console messages during suspend. Typically, "no_console_suspend" and
|
|
+ "default" states can refer to the same pin configuration.
|
|
+- pinctrl-n: Phandle(s) pointing to pin configuration nodes.
|
|
+ For Pinctrl properties see ../pinctrl/pinctrl-bindings.txt
|
|
+- st,hw-flow-ctrl: bool flag to enable hardware flow control.
|
|
+- rs485-rts-delay, rs485-rx-during-tx, rs485-rts-active-low,
|
|
+ linux,rs485-enabled-at-boot-time: see rs485.txt.
|
|
+- dmas: phandle(s) to DMA controller node(s). Refer to stm32-dma.txt
|
|
+- dma-names: "rx" and/or "tx"
|
|
+- wakeup-source: bool flag to indicate this device has wakeup capabilities
|
|
+- interrupt-names : Should contain "wakeup" if optional wake-up interrupt is
|
|
+ used.
|
|
+
|
|
+Note for dma using:
|
|
+- "tx" dma can be used without any constraint since it uses single
|
|
+dma transfers.
|
|
+- "rx" dma using requires some attention:
|
|
+ 1) if you cannot anticipate the length of your received packets
|
|
+ and if your usart device embeds an internal fifo, then DON'T use
|
|
+ dma mode.
|
|
+ 2) if you enable dma mode WITHOUT mdma intermediate copy (cf.
|
|
+ stm32-dma.txt), then the availability of the received data will
|
|
+ depend on the dma driver policy and it may be delayed until dma
|
|
+ internal fifo is full. The usart driver will see this checking
|
|
+ the dma residue when rx interrupt (RXNE or RTO) occurs.
|
|
+ 3) if you enable dma mode WITH mdma intermediate copy (cf.
|
|
+ stm32-dma.txt) then the usart driver will never see the dma
|
|
+ residue becoming smaller than RX_BUF_P but it will get its
|
|
+ rx dma complete callback called when the cyclic transfer period
|
|
+ (RX_BUF_P) is reached.
|
|
+The three possibilities above are ordered from the most cpu time
|
|
+consuming one to the least one. The counterpart of this optimisation
|
|
+is the reception granularity achievable by the usart driver, from
|
|
+one byte up to RX_BUF_P.
|
|
+
|
|
+Examples:
|
|
+usart4: serial@40004c00 {
|
|
+ compatible = "st,stm32-uart";
|
|
+ reg = <0x40004c00 0x400>;
|
|
+ interrupts = <52>;
|
|
+ clocks = <&clk_pclk1>;
|
|
+ pinctrl-names = "default", "sleep", "idle", "no_console_suspend";
|
|
+ pinctrl-0 = <&pinctrl_usart4>;
|
|
+ pinctrl-1 = <&pinctrl_usart4_sleep>;
|
|
+ pinctrl-2 = <&pinctrl_usart4_idle>;
|
|
+ pinctrl-3 = <&pinctrl_usart4>;
|
|
+};
|
|
+
|
|
+usart2: serial@40004400 {
|
|
+ compatible = "st,stm32-uart";
|
|
+ reg = <0x40004400 0x400>;
|
|
+ interrupts = <38>;
|
|
+ clocks = <&clk_pclk1>;
|
|
+ st,hw-flow-ctrl;
|
|
+ pinctrl-names = "default";
|
|
+ pinctrl-0 = <&pinctrl_usart2 &pinctrl_usart2_rtscts>;
|
|
+};
|
|
+
|
|
+usart1: serial@40011000 {
|
|
+ compatible = "st,stm32-uart";
|
|
+ reg = <0x40011000 0x400>;
|
|
+ interrupts = <37>;
|
|
+ clocks = <&rcc 0 164>;
|
|
+ dmas = <&dma2 2 4 0x414 0x0>,
|
|
+ <&dma2 7 4 0x414 0x0>;
|
|
+ dma-names = "rx", "tx";
|
|
+};
|
|
diff --git a/docs/devicetree/bindings/soc/st,stm32-etzpc.txt b/docs/devicetree/bindings/soc/st,stm32-etzpc.txt
|
|
new file mode 100644
|
|
index 0000000..a2ac263
|
|
--- /dev/null
|
|
+++ b/docs/devicetree/bindings/soc/st,stm32-etzpc.txt
|
|
@@ -0,0 +1,56 @@
|
|
+STM32 ETZPC
|
|
+---------------------------------
|
|
+
|
|
+Required properties:
|
|
+- compatible: should be "st,stm32-etzpc"
|
|
+- reg: physical base address and length of the registers set for the device
|
|
+- clocks: reference to the clock entry
|
|
+
|
|
+Optional property:
|
|
+- st,decprot: Configure option to properly set firewall for IPs.
|
|
+
|
|
+Examples:
|
|
+etzpc: etzpc@5C007000 {
|
|
+ compatible = "st,stm32-etzpc";
|
|
+ reg = <0x5C007000 0x400>;
|
|
+ clocks = <&rcc TZPC>;
|
|
+ status = "disabled";
|
|
+ secure-status = "okay";
|
|
+ };
|
|
+
|
|
+Firewall specifications
|
|
+=======================
|
|
+
|
|
+DECPROT macro must be used to properly configure IP firewalling. It must
|
|
+specify ID, domain and locking register status.
|
|
+
|
|
+The macro is defined in the binding header file [1].
|
|
+
|
|
+Example:
|
|
+ ... {
|
|
+ st,decprot = <
|
|
+ DECPROT(STM32MP1_ETZPC_I2C4_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
|
|
+ DECPROT(STM32MP1_ETZPC_RNG1_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
|
|
+ DECPROT(STM32MP1_ETZPC_HASH1_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
|
|
+ DECPROT(STM32MP1_ETZPC_CRYP1_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
|
|
+ DECPROT(STM32MP1_ETZPC_GPIOZ_ID, DECPROT_NS_RW, DECPROT_UNLOCK)>;
|
|
+ };
|
|
+
|
|
+Specify Peripheral IDs
|
|
+=======================
|
|
+
|
|
+Each peripheral is identified with a specific ID. Each platform defines the
|
|
+identifiers relevant to that platform. Peripheral IDs are defined in [1].
|
|
+
|
|
+Specify domain
|
|
+==============
|
|
+Firewall controls peripherals in specific domains:
|
|
+
|
|
+DECPROT_S_RW 0x0 -> Read/write Secure
|
|
+DECPROT_NS_R_S_W 0x1 -> Non secure read / Read/write Secure
|
|
+DECPROT_MCU_ISOLATION 0x2 -> MCU access only
|
|
+DECPROT_NS_RW 0x3 -> Non secure read/write
|
|
+
|
|
+
|
|
+[1] include/dt-bindings/soc/st,stm32-etzpc.h
|
|
+
|
|
diff --git a/docs/devicetree/bindings/soc/st,stm32-romem.txt b/docs/devicetree/bindings/soc/st,stm32-romem.txt
|
|
new file mode 100644
|
|
index 0000000..fbff52e
|
|
--- /dev/null
|
|
+++ b/docs/devicetree/bindings/soc/st,stm32-romem.txt
|
|
@@ -0,0 +1,31 @@
|
|
+STMicroelectronics STM32 Factory-programmed data device tree bindings
|
|
+
|
|
+This represents STM32 Factory-programmed read only non-volatile area: locked
|
|
+flash, OTP, read-only HW regs... This contains various information such as:
|
|
+analog calibration data for temperature sensor (e.g. TS_CAL1, TS_CAL2),
|
|
+internal vref (VREFIN_CAL), unique device ID...
|
|
+
|
|
+Required properties:
|
|
+- compatible: Should be one of:
|
|
+ "st,stm32-romem"
|
|
+ "st,stm32mp15-bsec"
|
|
+- reg: Offset and length of factory-programmed area.
|
|
+- #address-cells: Should be '<1>'.
|
|
+- #size-cells: Should be '<1>'.
|
|
+
|
|
+Optional Data cells:
|
|
+- Must be child nodes as described in nvmem.txt.
|
|
+
|
|
+Example on stm32f4:
|
|
+ romem: nvmem@1fff7800 {
|
|
+ compatible = "st,stm32-romem";
|
|
+ reg = <0x1fff7800 0x400>;
|
|
+ #address-cells = <1>;
|
|
+ #size-cells = <1>;
|
|
+
|
|
+ /* Data cells: ts_cal1 at 0x1fff7a2c */
|
|
+ ts_cal1: calib@22c {
|
|
+ reg = <0x22c 0x2>;
|
|
+ };
|
|
+ ...
|
|
+ };
|
|
diff --git a/docs/devicetree/bindings/soc/st,stm32-stgen.txt b/docs/devicetree/bindings/soc/st,stm32-stgen.txt
|
|
new file mode 100644
|
|
index 0000000..dbd962e
|
|
--- /dev/null
|
|
+++ b/docs/devicetree/bindings/soc/st,stm32-stgen.txt
|
|
@@ -0,0 +1,18 @@
|
|
+STMicroelectronics STM32 STGEN
|
|
+===============================
|
|
+
|
|
+The STM32 System Generic Counter generate a time count value. This
|
|
+is a 64 bits wide counter.
|
|
+
|
|
+Required properties:
|
|
+
|
|
+- compatible : Should be "st,stm32-stgen"
|
|
+- reg : Should be register base and length as documented in the datasheet
|
|
+
|
|
+Example:
|
|
+
|
|
+ stgen: stgen@5C008000 {
|
|
+ compatible = "st,stm32-stgen";
|
|
+ reg = <0x5C008000 0x1000>;
|
|
+ status = "okay";
|
|
+ };
|
|
diff --git a/docs/devicetree/bindings/soc/st,stm32-tamp.txt b/docs/devicetree/bindings/soc/st,stm32-tamp.txt
|
|
new file mode 100644
|
|
index 0000000..4d21c6b
|
|
--- /dev/null
|
|
+++ b/docs/devicetree/bindings/soc/st,stm32-tamp.txt
|
|
@@ -0,0 +1,22 @@
|
|
+STM32 TAMPER
|
|
+---------------------------------
|
|
+
|
|
+Required properties:
|
|
+- compatible: should be "st,stm32-tamp"
|
|
+- reg: physical base address and length of the registers set for the device
|
|
+- clocks: reference to the clock entry
|
|
+- secure-status: Required to properly disable/enable secure IP
|
|
+
|
|
+Optional property:
|
|
+- st,out3-pc13: Configure option register to map OUT3 on PC13
|
|
+- wakeup-source : Configure tamp as wakeup-src
|
|
+
|
|
+Examples:
|
|
+tamp: tamp@5C00A000 {
|
|
+ compatible = "st,stm32-tamp";
|
|
+ reg = <0x5C00A000 0x100>;
|
|
+ clocks = <&rcc_clk RTCAPB>;
|
|
+ st,out3-pc13;
|
|
+ wakeup-source;
|
|
+ secure-status = "okay";
|
|
+};
|
|
diff --git a/docs/devicetree/bindings/watchdog/st,stm32-iwdg.txt b/docs/devicetree/bindings/watchdog/st,stm32-iwdg.txt
|
|
new file mode 100644
|
|
index 0000000..2453603
|
|
--- /dev/null
|
|
+++ b/docs/devicetree/bindings/watchdog/st,stm32-iwdg.txt
|
|
@@ -0,0 +1,28 @@
|
|
+STM32 Independent WatchDoG (IWDG)
|
|
+---------------------------------
|
|
+
|
|
+Required properties:
|
|
+- compatible: should be "st,stm32mp1-iwdg".
|
|
+- reg: physical base address and length of the registers set for the device.
|
|
+- clocks: reference to the clock entry lsi. Additional pclk clock entry.
|
|
+ is required only for st,stm32mp1-iwdg.
|
|
+- clock-names: name of the clocks used.
|
|
+ "pclk", "lsi" for st,stm32mp1-iwdg.
|
|
+
|
|
+Optional properties:
|
|
+- timeout-sec: Watchdog timeout value in seconds.
|
|
+- secure-timeout-sec: Watchdog early timeout management in seconds.
|
|
+- stm32,enable-on-stop: Keep watchdog enable during stop.
|
|
+- stm32,enable-on-standby: Keep watchdog enable durung standby.
|
|
+- secure-status: Required to properly enable/disable secure IP.
|
|
+
|
|
+Examples:
|
|
+
|
|
+iwdg2: iwdg@5a002000 {
|
|
+ compatible = "st,stm32mp1-iwdg";
|
|
+ reg = <0x5a002000 0x400>;
|
|
+ clocks = <&rcc IWDG2>, <&clk_lsi>;
|
|
+ clock-names = "pclk", "lsi";
|
|
+ instance = <2>;
|
|
+ timeout-sec = <30>;
|
|
+};
|
|
diff --git a/docs/plat/stm32mp1.rst b/docs/plat/stm32mp1.rst
|
|
index 9e731a4..10ad00e 100644
|
|
--- a/docs/plat/stm32mp1.rst
|
|
+++ b/docs/plat/stm32mp1.rst
|
|
@@ -76,7 +76,23 @@ To build:
|
|
.. code:: bash
|
|
|
|
make CROSS_COMPILE=arm-linux-gnueabihf- PLAT=stm32mp1 ARCH=aarch32 ARM_ARCH_MAJOR=7 AARCH32_SP=sp_min
|
|
+ cd <u-boot_directory>
|
|
+ make stm32mp15_trusted_defconfig
|
|
+ make DEVICE_TREE=stm32mp157c_ev1 all
|
|
+ ./tools/mkimage -T stm32image -a 0xC0100000 -e 0xC0100000 -d u-boot.bin u-boot.stm32
|
|
|
|
The following build options are supported:
|
|
|
|
- ``ENABLE_STACK_PROTECTOR``: To enable the stack protection.
|
|
+
|
|
+
|
|
+Populate SD-card
|
|
+----------------
|
|
+
|
|
+The SD-card has to be formated with GPT.
|
|
+It should contain at least those partitions:
|
|
+
|
|
+- fsbl: to copy the tf-a-stm32mp157c-ev1.stm32 binary
|
|
+- ssbl: to copy the u-boot.stm32 binary
|
|
+
|
|
+Usually, two copies of fsbl are used (fsbl1 and fsbl2) instead of one partition fsbl.
|
|
diff --git a/docs/porting-guide.rst b/docs/porting-guide.rst
|
|
index 1667cce..bef4af6 100644
|
|
--- a/docs/porting-guide.rst
|
|
+++ b/docs/porting-guide.rst
|
|
@@ -2554,8 +2554,13 @@ NOTE: This section assumes that your platform is enabling the MULTI_CONSOLE_API
|
|
flag in its platform.mk. Not using this flag is deprecated for new platforms.
|
|
|
|
BL31 implements a crash reporting mechanism which prints the various registers
|
|
-of the CPU to enable quick crash analysis and debugging. By default, the
|
|
-definitions in ``plat/common/aarch64/platform\_helpers.S`` will cause the crash
|
|
+of the CPU to enable quick crash analysis and debugging. This mechanism relies
|
|
+on the platform implementating ``plat_crash_console_init``,
|
|
+``plat_crash_console_putc`` and ``plat_crash_console_flush``.
|
|
+
|
|
+The file ``plat/common/aarch64/crash_console_helpers.S`` contains sample
|
|
+implementation of all of them. Platforms may include this file to their
|
|
+makefiles in order to benefit from them. By default, they will cause the crash
|
|
output to be routed over the normal console infrastructure and get printed on
|
|
consoles configured to output in crash state. ``console_set_scope()`` can be
|
|
used to control whether a console is used for crash output.
|
|
@@ -2565,8 +2570,12 @@ normal boot console can be set up), platforms may want to control crash output
|
|
more explicitly. For these, the following functions can be overridden by
|
|
platform code. They are executed outside of a C environment and without a stack.
|
|
|
|
-Function : plat\_crash\_console\_init
|
|
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
+If this behaviour is not desirable, the platform may implement functions that
|
|
+redirect the prints to the console driver (``console_xxx_core_init``, etc). Most
|
|
+platforms (including Arm platforms) do this and they can be used as an example.
|
|
+
|
|
+Function : plat\_crash\_console\_init [mandatory]
|
|
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
::
|
|
|
|
@@ -2577,9 +2586,10 @@ This API is used by the crash reporting mechanism to initialize the crash
|
|
console. It must only use the general purpose registers x0 through x7 to do the
|
|
initialization and returns 1 on success.
|
|
|
|
-If you are trying to debug crashes before the console driver would normally get
|
|
-registered, you can use this to register a driver from assembly with hardcoded
|
|
-parameters. For example, you could register the 16550 driver like this:
|
|
+When using the sample implementation, if you are trying to debug crashes before
|
|
+the console driver would normally get registered, you can use this to register a
|
|
+driver from assembly with hardcoded parameters. For example, you could register
|
|
+the 16550 driver like this:
|
|
|
|
::
|
|
|
|
@@ -2595,11 +2605,11 @@ parameters. For example, you could register the 16550 driver like this:
|
|
b console_16550_register /* tail call, returns 1 on success */
|
|
endfunc plat_crash_console_init
|
|
|
|
-If you're trying to debug crashes in BL1, you can call the console_xxx_core_init
|
|
-function exported by some console drivers from here.
|
|
+If you're trying to debug crashes in BL1, you can call the
|
|
+``console_xxx_core_init`` function exported by some console drivers from here.
|
|
|
|
-Function : plat\_crash\_console\_putc
|
|
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
+Function : plat\_crash\_console\_putc [mandatory]
|
|
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
::
|
|
|
|
@@ -2612,13 +2622,13 @@ x2 to do its work. The parameter and the return value are in general purpose
|
|
register x0.
|
|
|
|
If you have registered a normal console driver in ``plat_crash_console_init``,
|
|
-you can keep the default implementation here (which calls ``console_putc()``).
|
|
+you can keep the sample implementation here (which calls ``console_putc()``).
|
|
|
|
-If you're trying to debug crashes in BL1, you can call the console_xxx_core_putc
|
|
-function exported by some console drivers from here.
|
|
+If you're trying to debug crashes in BL1, you can call the
|
|
+``console_xxx_core_putc`` function exported by some console drivers from here.
|
|
|
|
-Function : plat\_crash\_console\_flush
|
|
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
+Function : plat\_crash\_console\_flush [mandatory]
|
|
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
::
|
|
|
|
@@ -2631,7 +2641,7 @@ registers x0 through x5 to do its work. The return value is 0 on successful
|
|
completion; otherwise the return value is -1.
|
|
|
|
If you have registered a normal console driver in ``plat_crash_console_init``,
|
|
-you can keep the default implementation here (which calls ``console_flush()``).
|
|
+you can keep the sample implementation here (which calls ``console_flush()``).
|
|
|
|
If you're trying to debug crashes in BL1, you can call the console_xx_core_flush
|
|
function exported by some console drivers from here.
|
|
diff --git a/drivers/arm/pl011/aarch32/pl011_console.S b/drivers/arm/pl011/aarch32/pl011_console.S
|
|
index 3718fff..edadaa4 100644
|
|
--- a/drivers/arm/pl011/aarch32/pl011_console.S
|
|
+++ b/drivers/arm/pl011/aarch32/pl011_console.S
|
|
@@ -1,10 +1,13 @@
|
|
/*
|
|
- * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved.
|
|
+ * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved.
|
|
*
|
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
*/
|
|
#include <arch.h>
|
|
#include <asm_macros.S>
|
|
+#include <assert_macros.S>
|
|
+#define USE_FINISH_CONSOLE_REG_2
|
|
+#include <console_macros.S>
|
|
#include <pl011.h>
|
|
|
|
/*
|
|
@@ -13,10 +16,18 @@
|
|
*/
|
|
#include "../../../console/aarch32/console.S"
|
|
|
|
- .globl console_core_init
|
|
- .globl console_core_putc
|
|
- .globl console_core_getc
|
|
- .globl console_core_flush
|
|
+ /*
|
|
+ * "core" functions are low-level implementations that don't require
|
|
+ * writeable memory and are thus safe to call in BL1 crash context.
|
|
+ */
|
|
+ .globl console_pl011_core_init
|
|
+ .globl console_pl011_core_putc
|
|
+ .globl console_pl011_core_getc
|
|
+ .globl console_pl011_core_flush
|
|
+
|
|
+ .globl console_pl011_putc
|
|
+ .globl console_pl011_getc
|
|
+ .globl console_pl011_flush
|
|
|
|
|
|
/* -----------------------------------------------
|
|
@@ -33,7 +44,7 @@
|
|
* Clobber list : r1, r2, r3
|
|
* -----------------------------------------------
|
|
*/
|
|
-func console_core_init
|
|
+func console_pl011_core_init
|
|
/* Check the input base address */
|
|
cmp r0, #0
|
|
beq core_init_fail
|
|
@@ -73,7 +84,53 @@ func console_core_init
|
|
core_init_fail:
|
|
mov r0, #0
|
|
bx lr
|
|
-endfunc console_core_init
|
|
+endfunc console_pl011_core_init
|
|
+
|
|
+#if MULTI_CONSOLE_API
|
|
+ .globl console_pl011_register
|
|
+
|
|
+ /* -------------------------------------------------------
|
|
+ * init console_pl011_register(console_pl011_t *console,
|
|
+ * uintptr_t base, uint32_t clk, uint32_t baud)
|
|
+ * Function to initialize and register a new PL011
|
|
+ * console. Storage passed in for the console struct
|
|
+ * *must* be persistent (i.e. not from the stack).
|
|
+ * In: r0 - UART register base address
|
|
+ * r1 - UART clock in Hz
|
|
+ * r2 - Baud rate
|
|
+ * r3 - pointer to empty console_pl011_t struct
|
|
+ * Out: return 1 on success, 0 on error
|
|
+ * Clobber list : r0, r1, r2
|
|
+ * -------------------------------------------------------
|
|
+ */
|
|
+func console_pl011_register
|
|
+ push {r4, lr}
|
|
+ mov r4, r3
|
|
+ cmp r4, #0
|
|
+ beq register_fail
|
|
+ str r0, [r4, #CONSOLE_T_PL011_BASE]
|
|
+
|
|
+ bl console_pl011_core_init
|
|
+ cmp r0, #0
|
|
+ beq register_fail
|
|
+
|
|
+ mov r0, r4
|
|
+ pop {r4, lr}
|
|
+ finish_console_register pl011 putc=1, getc=1, flush=1
|
|
+
|
|
+register_fail:
|
|
+ pop {r4, pc}
|
|
+endfunc console_pl011_register
|
|
+#else
|
|
+ .globl console_core_init
|
|
+ .globl console_core_putc
|
|
+ .globl console_core_getc
|
|
+ .globl console_core_flush
|
|
+ .equ console_core_init, console_pl011_core_init
|
|
+ .equ console_core_putc, console_pl011_core_putc
|
|
+ .equ console_core_getc, console_pl011_core_getc
|
|
+ .equ console_core_flush, console_pl011_core_flush
|
|
+#endif
|
|
|
|
/* --------------------------------------------------------
|
|
* int console_core_putc(int c, uintptr_t base_addr)
|
|
@@ -85,7 +142,7 @@ endfunc console_core_init
|
|
* Clobber list : r2
|
|
* --------------------------------------------------------
|
|
*/
|
|
-func console_core_putc
|
|
+func console_pl011_core_putc
|
|
/* Check the input parameter */
|
|
cmp r1, #0
|
|
beq putc_error
|
|
@@ -109,7 +166,26 @@ func console_core_putc
|
|
putc_error:
|
|
mov r0, #-1
|
|
bx lr
|
|
-endfunc console_core_putc
|
|
+endfunc console_pl011_core_putc
|
|
+
|
|
+ /* --------------------------------------------------------
|
|
+ * int console_pl011_putc(int c, console_pl011_t *console)
|
|
+ * Function to output a character over the console. It
|
|
+ * returns the character printed on success or -1 on error.
|
|
+ * In: r0 - character to be printed
|
|
+ * r1 - pointer to console_t structure
|
|
+ * Out : return -1 on error else return character.
|
|
+ * Clobber list: r2
|
|
+ * -------------------------------------------------------
|
|
+ */
|
|
+func console_pl011_putc
|
|
+#if ENABLE_ASSERTIONS
|
|
+ cmp r1, #0
|
|
+ ASM_ASSERT(ne)
|
|
+#endif /* ENABLE_ASSERTIONS */
|
|
+ ldr r1, [r1, #CONSOLE_T_PL011_BASE]
|
|
+ b console_pl011_core_putc
|
|
+endfunc console_pl011_putc
|
|
|
|
/* ---------------------------------------------
|
|
* int console_core_getc(uintptr_t base_addr)
|
|
@@ -120,7 +196,7 @@ endfunc console_core_putc
|
|
* Clobber list : r0, r1
|
|
* ---------------------------------------------
|
|
*/
|
|
-func console_core_getc
|
|
+func console_pl011_core_getc
|
|
cmp r0, #0
|
|
beq getc_error
|
|
1:
|
|
@@ -134,7 +210,26 @@ func console_core_getc
|
|
getc_error:
|
|
mov r0, #-1
|
|
bx lr
|
|
-endfunc console_core_getc
|
|
+endfunc console_pl011_core_getc
|
|
+
|
|
+ /* ------------------------------------------------
|
|
+ * int console_pl011_getc(console_pl011_t *console)
|
|
+ * Function to get a character from the console.
|
|
+ * It returns the character grabbed on success
|
|
+ * or -1 if no character is available.
|
|
+ * In : r0 - pointer to console_t structure
|
|
+ * Out: r0 - character if available, else -1
|
|
+ * Clobber list: r0, r1
|
|
+ * ------------------------------------------------
|
|
+ */
|
|
+func console_pl011_getc
|
|
+#if ENABLE_ASSERTIONS
|
|
+ cmp r0, #0
|
|
+ ASM_ASSERT(ne)
|
|
+#endif /* ENABLE_ASSERTIONS */
|
|
+ ldr r0, [r0, #CONSOLE_T_PL011_BASE]
|
|
+ b console_pl011_core_getc
|
|
+endfunc console_pl011_getc
|
|
|
|
/* ---------------------------------------------
|
|
* int console_core_flush(uintptr_t base_addr)
|
|
@@ -145,7 +240,7 @@ endfunc console_core_getc
|
|
* Clobber list : r0, r1
|
|
* ---------------------------------------------
|
|
*/
|
|
-func console_core_flush
|
|
+func console_pl011_core_flush
|
|
cmp r0, #0
|
|
beq flush_error
|
|
|
|
@@ -160,4 +255,22 @@ func console_core_flush
|
|
flush_error:
|
|
mov r0, #-1
|
|
bx lr
|
|
-endfunc console_core_flush
|
|
+endfunc console_pl011_core_flush
|
|
+
|
|
+ /* ---------------------------------------------
|
|
+ * int console_pl011_flush(console_pl011_t *console)
|
|
+ * Function to force a write of all buffered
|
|
+ * data that hasn't been output.
|
|
+ * In : r0 - pointer to console_t structure
|
|
+ * Out : return -1 on error else return 0.
|
|
+ * Clobber list: r0, r1
|
|
+ * ---------------------------------------------
|
|
+ */
|
|
+func console_pl011_flush
|
|
+#if ENABLE_ASSERTIONS
|
|
+ cmp r0, #0
|
|
+ ASM_ASSERT(ne)
|
|
+#endif /* ENABLE_ASSERTIONS */
|
|
+ ldr r0, [r0, #CONSOLE_T_PL011_BASE]
|
|
+ b console_pl011_core_flush
|
|
+endfunc console_pl011_flush
|
|
diff --git a/drivers/arm/pl011/aarch64/pl011_console.S b/drivers/arm/pl011/aarch64/pl011_console.S
|
|
index 448501a..c4d51c8 100644
|
|
--- a/drivers/arm/pl011/aarch64/pl011_console.S
|
|
+++ b/drivers/arm/pl011/aarch64/pl011_console.S
|
|
@@ -6,6 +6,7 @@
|
|
#include <arch.h>
|
|
#include <asm_macros.S>
|
|
#include <assert_macros.S>
|
|
+#define USE_FINISH_CONSOLE_REG_2
|
|
#include <console_macros.S>
|
|
#include <pl011.h>
|
|
|
|
@@ -109,7 +110,7 @@ func console_pl011_register
|
|
|
|
mov x0, x6
|
|
mov x30, x7
|
|
- finish_console_register pl011
|
|
+ finish_console_register pl011 putc=1, getc=1, flush=1
|
|
|
|
register_fail:
|
|
ret x7
|
|
diff --git a/drivers/arm/tzc/tzc400.c b/drivers/arm/tzc/tzc400.c
|
|
index db4f88a..1849e5a 100644
|
|
--- a/drivers/arm/tzc/tzc400.c
|
|
+++ b/drivers/arm/tzc/tzc400.c
|
|
@@ -68,6 +68,59 @@ DEFINE_TZC_COMMON_WRITE_REGION_ID_ACCESS(400, 400)
|
|
DEFINE_TZC_COMMON_CONFIGURE_REGION0(400)
|
|
DEFINE_TZC_COMMON_CONFIGURE_REGION(400)
|
|
|
|
+static inline void tzc400_clear_it(long base, uint32_t filter)
|
|
+{
|
|
+ mmio_write_32(base + INT_CLEAR, 1 << filter);
|
|
+}
|
|
+
|
|
+static inline uint32_t tzc400_get_int_by_filter(long base, uint32_t filter)
|
|
+{
|
|
+ return (mmio_read_32(base + INT_STATUS) & (1 << filter));
|
|
+}
|
|
+
|
|
+#if DEBUG
|
|
+static long tzc400_get_fail_address(long base, uint32_t filter)
|
|
+{
|
|
+ long fail_address = 0;
|
|
+
|
|
+ if (sizeof(long) == sizeof(uint32_t)) {
|
|
+ if (filter) {
|
|
+ fail_address = mmio_read_32(base +
|
|
+ FAIL_ADDRESS_LOW_OFF +
|
|
+ FILTER_OFFSET);
|
|
+ } else {
|
|
+ fail_address = mmio_read_32(base +
|
|
+ FAIL_ADDRESS_LOW_OFF);
|
|
+ }
|
|
+ } else {
|
|
+ if (filter) {
|
|
+ fail_address = mmio_read_32(base +
|
|
+ FAIL_ADDRESS_LOW_OFF +
|
|
+ FILTER_OFFSET) +
|
|
+ mmio_read_32(base +
|
|
+ FAIL_ADDRESS_HIGH_OFF +
|
|
+ FILTER_OFFSET);
|
|
+ } else {
|
|
+ fail_address = mmio_read_32(base +
|
|
+ FAIL_ADDRESS_LOW_OFF) +
|
|
+ mmio_read_32(base +
|
|
+ FAIL_ADDRESS_HIGH_OFF);
|
|
+ }
|
|
+ }
|
|
+ return fail_address;
|
|
+}
|
|
+#endif
|
|
+
|
|
+static inline uint32_t tzc400_get_fail_control(long base, uint32_t filter)
|
|
+{
|
|
+ if (filter) {
|
|
+ return mmio_read_32(base + FAIL_CONTROL_OFF +
|
|
+ FILTER_OFFSET);
|
|
+ } else {
|
|
+ return mmio_read_32(base + FAIL_CONTROL_OFF);
|
|
+ }
|
|
+}
|
|
+
|
|
static unsigned int _tzc400_get_gate_keeper(uintptr_t base,
|
|
unsigned int filter)
|
|
{
|
|
@@ -236,3 +289,79 @@ void tzc400_disable_filters(void)
|
|
for (filter = 0; filter < tzc400.num_filters; filter++)
|
|
_tzc400_set_gate_keeper(tzc400.base, filter, 0);
|
|
}
|
|
+
|
|
+void tzc400_clear_all_interrupts(void)
|
|
+{
|
|
+ unsigned int filter;
|
|
+
|
|
+ assert(tzc400.base);
|
|
+ for (filter = 0; filter < tzc400.num_filters; filter++) {
|
|
+ mmio_write_32(tzc400.base + INT_CLEAR, 1 << filter);
|
|
+ }
|
|
+}
|
|
+
|
|
+int tzc400_is_pending_interrupt(void)
|
|
+{
|
|
+ unsigned int filter;
|
|
+
|
|
+ assert(tzc400.base);
|
|
+ for (filter = 0; filter < tzc400.num_filters; filter++) {
|
|
+ if (mmio_read_32(tzc400.base + INT_STATUS) & (1 << filter)) {
|
|
+ return 1;
|
|
+ }
|
|
+ }
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+void tzc400_it_handler(void)
|
|
+{
|
|
+ uint32_t filter = 0;
|
|
+ uint32_t filter_it_pending = tzc400.num_filters;
|
|
+ uint32_t control_fail = 0;
|
|
+#if DEBUG
|
|
+ long address_fail = 0;
|
|
+#endif
|
|
+
|
|
+ assert(tzc400.base);
|
|
+
|
|
+ /* first display information conerning the fault access */
|
|
+ for (filter = 0; (filter < tzc400.num_filters) &&
|
|
+ (filter_it_pending == tzc400.num_filters); filter++) {
|
|
+ if (tzc400_get_int_by_filter(tzc400.base, filter))
|
|
+ filter_it_pending = filter;
|
|
+ }
|
|
+
|
|
+ if (filter_it_pending == tzc400.num_filters) {
|
|
+ ERROR("Error no it pending!!");
|
|
+ panic();
|
|
+ }
|
|
+
|
|
+#if DEBUG
|
|
+ address_fail = tzc400_get_fail_address(tzc400.base, filter_it_pending);
|
|
+ ERROR("Illegal access to 0x%lx in :\n",address_fail);
|
|
+#endif
|
|
+
|
|
+ control_fail = tzc400_get_fail_control(tzc400.base, filter_it_pending);
|
|
+
|
|
+
|
|
+
|
|
+ if ((control_fail & FAIL_CONTROL_NS_SHIFT) == FAIL_CONTROL_NS_SECURE) {
|
|
+ ERROR("\tSecure\n");
|
|
+ } else {
|
|
+ ERROR("\tNo Secure\n");
|
|
+ }
|
|
+
|
|
+ if ((control_fail & FAIL_CONTROL_PRIV_SHIFT) == FAIL_CONTROL_PRIV_PRIV) {
|
|
+ ERROR("\tPrivilege\n");
|
|
+ } else {
|
|
+ ERROR("\tUnprivilege\n");
|
|
+ }
|
|
+
|
|
+ if ((control_fail & FAIL_CONTROL_DIR_SHIFT) == FAIL_CONTROL_DIR_READ) {
|
|
+ ERROR("\tRead\n");
|
|
+ } else {
|
|
+ ERROR("\tWrite\n");
|
|
+ }
|
|
+
|
|
+ tzc400_clear_it(tzc400.base, filter_it_pending);
|
|
+}
|
|
diff --git a/drivers/cadence/uart/aarch64/cdns_console.S b/drivers/cadence/uart/aarch64/cdns_console.S
|
|
index 6732631..116c9d8 100644
|
|
--- a/drivers/cadence/uart/aarch64/cdns_console.S
|
|
+++ b/drivers/cadence/uart/aarch64/cdns_console.S
|
|
@@ -7,6 +7,8 @@
|
|
#include <asm_macros.S>
|
|
#include <assert_macros.S>
|
|
#include <cadence/cdns_uart.h>
|
|
+#define USE_FINISH_CONSOLE_REG_2
|
|
+#include <console_macros.S>
|
|
|
|
/*
|
|
* "core" functions are low-level implementations that don't require
|
|
@@ -76,7 +78,7 @@ func console_cdns_register
|
|
|
|
mov x0, x6
|
|
mov x30, v7
|
|
- finish_console_register cdns
|
|
+ finish_console_register cdns putc=1, getc=1, flush=1
|
|
|
|
register_fail:
|
|
ret x7
|
|
diff --git a/drivers/console/aarch32/console.S b/drivers/console/aarch32/console.S
|
|
index a3c6546..f909609 100644
|
|
--- a/drivers/console/aarch32/console.S
|
|
+++ b/drivers/console/aarch32/console.S
|
|
@@ -3,104 +3,9 @@
|
|
*
|
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
*/
|
|
-#include <asm_macros.S>
|
|
|
|
- .globl console_init
|
|
- .globl console_uninit
|
|
- .globl console_putc
|
|
- .globl console_getc
|
|
- .globl console_flush
|
|
-
|
|
- /*
|
|
- * The console base is in the data section and not in .bss
|
|
- * even though it is zero-init. In particular, this allows
|
|
- * the console functions to start using this variable before
|
|
- * the runtime memory is initialized for images which do not
|
|
- * need to copy the .data section from ROM to RAM.
|
|
- */
|
|
-.section .data.console_base ; .align 2
|
|
- console_base: .word 0x0
|
|
-
|
|
- /* -----------------------------------------------
|
|
- * int console_init(uintptr_t base_addr,
|
|
- * unsigned int uart_clk, unsigned int baud_rate)
|
|
- * Function to initialize the console without a
|
|
- * C Runtime to print debug information. It saves
|
|
- * the console base to the data section.
|
|
- * In: r0 - console base address
|
|
- * r1 - Uart clock in Hz
|
|
- * r2 - Baud rate
|
|
- * out: return 1 on success else 0 on error
|
|
- * Clobber list : r1 - r3
|
|
- * -----------------------------------------------
|
|
- */
|
|
-func console_init
|
|
- /* Check the input base address */
|
|
- cmp r0, #0
|
|
- beq init_fail
|
|
- ldr r3, =console_base
|
|
- str r0, [r3]
|
|
- b console_core_init
|
|
-init_fail:
|
|
- bx lr
|
|
-endfunc console_init
|
|
-
|
|
- /* -----------------------------------------------
|
|
- * void console_uninit(void)
|
|
- * Function to finish the use of console driver.
|
|
- * It sets the console_base as NULL so that any
|
|
- * further invocation of `console_putc` or
|
|
- * `console_getc` APIs would return error.
|
|
- * -----------------------------------------------
|
|
- */
|
|
-func console_uninit
|
|
- mov r0, #0
|
|
- ldr r3, =console_base
|
|
- str r0, [r3]
|
|
- bx lr
|
|
-endfunc console_uninit
|
|
-
|
|
- /* ---------------------------------------------
|
|
- * int console_putc(int c)
|
|
- * Function to output a character over the
|
|
- * console. It returns the character printed on
|
|
- * success or -1 on error.
|
|
- * In : r0 - character to be printed
|
|
- * Out : return -1 on error else return character.
|
|
- * Clobber list : r1, r2
|
|
- * ---------------------------------------------
|
|
- */
|
|
-func console_putc
|
|
- ldr r2, =console_base
|
|
- ldr r1, [r2]
|
|
- b console_core_putc
|
|
-endfunc console_putc
|
|
-
|
|
- /* ---------------------------------------------
|
|
- * int console_getc(void)
|
|
- * Function to get a character from the console.
|
|
- * It returns the character grabbed on success
|
|
- * or -1 on error.
|
|
- * Clobber list : r0, r1
|
|
- * ---------------------------------------------
|
|
- */
|
|
-func console_getc
|
|
- ldr r1, =console_base
|
|
- ldr r0, [r1]
|
|
- b console_core_getc
|
|
-endfunc console_getc
|
|
-
|
|
- /* ---------------------------------------------
|
|
- * int console_flush(void)
|
|
- * Function to force a write of all buffered
|
|
- * data that hasn't been output. It returns 0
|
|
- * upon successful completion, otherwise it
|
|
- * returns -1.
|
|
- * Clobber list : r0, r1
|
|
- * ---------------------------------------------
|
|
- */
|
|
-func console_flush
|
|
- ldr r1, =console_base
|
|
- ldr r0, [r1]
|
|
- b console_core_flush
|
|
-endfunc console_flush
|
|
+ #if MULTI_CONSOLE_API
|
|
+ #include "multi_console.S"
|
|
+ #else
|
|
+ #include "deprecated_console.S"
|
|
+ #endif
|
|
diff --git a/drivers/console/aarch32/deprecated_console.S b/drivers/console/aarch32/deprecated_console.S
|
|
new file mode 100644
|
|
index 0000000..f7e3c4f
|
|
--- /dev/null
|
|
+++ b/drivers/console/aarch32/deprecated_console.S
|
|
@@ -0,0 +1,112 @@
|
|
+/*
|
|
+ * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved.
|
|
+ *
|
|
+ * SPDX-License-Identifier: BSD-3-Clause
|
|
+ */
|
|
+#include <asm_macros.S>
|
|
+
|
|
+/*
|
|
+ * This is the common console core code for the deprecated single-console API.
|
|
+ * New platforms should set MULTI_CONSOLE_API=1 and not use this file.
|
|
+ */
|
|
+#warning "Using deprecated console implementation. Please migrate to MULTI_CONSOLE_API"
|
|
+
|
|
+ .globl console_init
|
|
+ .globl console_uninit
|
|
+ .globl console_putc
|
|
+ .globl console_getc
|
|
+ .globl console_flush
|
|
+
|
|
+ /*
|
|
+ * The console base is in the data section and not in .bss
|
|
+ * even though it is zero-init. In particular, this allows
|
|
+ * the console functions to start using this variable before
|
|
+ * the runtime memory is initialized for images which do not
|
|
+ * need to copy the .data section from ROM to RAM.
|
|
+ */
|
|
+.section .data.console_base ; .align 2
|
|
+ console_base: .word 0x0
|
|
+
|
|
+ /* -----------------------------------------------
|
|
+ * int console_init(uintptr_t base_addr,
|
|
+ * unsigned int uart_clk, unsigned int baud_rate)
|
|
+ * Function to initialize the console without a
|
|
+ * C Runtime to print debug information. It saves
|
|
+ * the console base to the data section.
|
|
+ * In: r0 - console base address
|
|
+ * r1 - Uart clock in Hz
|
|
+ * r2 - Baud rate
|
|
+ * out: return 1 on success else 0 on error
|
|
+ * Clobber list : r1 - r3
|
|
+ * -----------------------------------------------
|
|
+ */
|
|
+func console_init
|
|
+ /* Check the input base address */
|
|
+ cmp r0, #0
|
|
+ beq init_fail
|
|
+ ldr r3, =console_base
|
|
+ str r0, [r3]
|
|
+ b console_core_init
|
|
+init_fail:
|
|
+ bx lr
|
|
+endfunc console_init
|
|
+
|
|
+ /* -----------------------------------------------
|
|
+ * void console_uninit(void)
|
|
+ * Function to finish the use of console driver.
|
|
+ * It sets the console_base as NULL so that any
|
|
+ * further invocation of `console_putc` or
|
|
+ * `console_getc` APIs would return error.
|
|
+ * -----------------------------------------------
|
|
+ */
|
|
+func console_uninit
|
|
+ mov r0, #0
|
|
+ ldr r3, =console_base
|
|
+ str r0, [r3]
|
|
+ bx lr
|
|
+endfunc console_uninit
|
|
+
|
|
+ /* ---------------------------------------------
|
|
+ * int console_putc(int c)
|
|
+ * Function to output a character over the
|
|
+ * console. It returns the character printed on
|
|
+ * success or -1 on error.
|
|
+ * In : r0 - character to be printed
|
|
+ * Out : return -1 on error else return character.
|
|
+ * Clobber list : r1, r2
|
|
+ * ---------------------------------------------
|
|
+ */
|
|
+func console_putc
|
|
+ ldr r2, =console_base
|
|
+ ldr r1, [r2]
|
|
+ b console_core_putc
|
|
+endfunc console_putc
|
|
+
|
|
+ /* ---------------------------------------------
|
|
+ * int console_getc(void)
|
|
+ * Function to get a character from the console.
|
|
+ * It returns the character grabbed on success
|
|
+ * or -1 on error.
|
|
+ * Clobber list : r0, r1
|
|
+ * ---------------------------------------------
|
|
+ */
|
|
+func console_getc
|
|
+ ldr r1, =console_base
|
|
+ ldr r0, [r1]
|
|
+ b console_core_getc
|
|
+endfunc console_getc
|
|
+
|
|
+ /* ---------------------------------------------
|
|
+ * int console_flush(void)
|
|
+ * Function to force a write of all buffered
|
|
+ * data that hasn't been output. It returns 0
|
|
+ * upon successful completion, otherwise it
|
|
+ * returns -1.
|
|
+ * Clobber list : r0, r1
|
|
+ * ---------------------------------------------
|
|
+ */
|
|
+func console_flush
|
|
+ ldr r1, =console_base
|
|
+ ldr r0, [r1]
|
|
+ b console_core_flush
|
|
+endfunc console_flush
|
|
diff --git a/drivers/console/aarch32/multi_console.S b/drivers/console/aarch32/multi_console.S
|
|
new file mode 100644
|
|
index 0000000..e23b20e
|
|
--- /dev/null
|
|
+++ b/drivers/console/aarch32/multi_console.S
|
|
@@ -0,0 +1,318 @@
|
|
+/*
|
|
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
|
|
+ *
|
|
+ * SPDX-License-Identifier: BSD-3-Clause
|
|
+ */
|
|
+
|
|
+#include <asm_macros.S>
|
|
+#include <assert_macros.S>
|
|
+#include <console.h>
|
|
+
|
|
+ .globl console_register
|
|
+ .globl console_unregister
|
|
+ .globl console_is_registered
|
|
+ .globl console_set_scope
|
|
+ .globl console_switch_state
|
|
+ .globl console_putc
|
|
+ .globl console_getc
|
|
+ .globl console_flush
|
|
+
|
|
+ /*
|
|
+ * The console list pointer is in the data section and not in
|
|
+ * .bss even though it is zero-init. In particular, this allows
|
|
+ * the console functions to start using this variable before
|
|
+ * the runtime memory is initialized for images which do not
|
|
+ * need to copy the .data section from ROM to RAM.
|
|
+ */
|
|
+.section .data.console_list ; .align 2
|
|
+ console_list: .word 0x0
|
|
+.section .data.console_state ; .align 0
|
|
+ console_state: .byte CONSOLE_FLAG_BOOT
|
|
+
|
|
+ /* -----------------------------------------------
|
|
+ * int console_register(console_t *console)
|
|
+ * Function to insert a new console structure into
|
|
+ * the console list. Should usually be called by
|
|
+ * console_<driver>_register implementations. The
|
|
+ * data structure passed will be taken over by the
|
|
+ * console framework and *MUST* be allocated in
|
|
+ * persistent memory (e.g. the data section).
|
|
+ * In : r0 - address of console_t structure
|
|
+ * Out: r0 - Always 1 (for easier tail calling)
|
|
+ * Clobber list: r0, r1
|
|
+ * -----------------------------------------------
|
|
+ */
|
|
+func console_register
|
|
+ push {r6, lr}
|
|
+#if ENABLE_ASSERTIONS
|
|
+ /* Assert that r0 isn't a NULL pointer */
|
|
+ cmp r0, #0
|
|
+ ASM_ASSERT(ne)
|
|
+ /* Assert that the struct isn't in the stack */
|
|
+ ldr r1, =__STACKS_START__
|
|
+ cmp r0, r1
|
|
+ blo not_on_stack
|
|
+ ldr r1, =__STACKS_END__
|
|
+ cmp r0, r1
|
|
+ ASM_ASSERT(hs)
|
|
+not_on_stack:
|
|
+ /* Assert that this struct isn't in the list */
|
|
+ mov r1, r0 /* Preserve r0 and lr */
|
|
+ bl console_is_registered
|
|
+ cmp r0, #0
|
|
+ ASM_ASSERT(eq)
|
|
+ mov r0, r1
|
|
+#endif /* ENABLE_ASSERTIONS */
|
|
+ ldr r6, =console_list
|
|
+ ldr r1, [r6] /* R1 = first struct in list */
|
|
+ str r0, [r6] /* list head = new console */
|
|
+ str r1, [r0, #CONSOLE_T_NEXT] /* new console next ptr = R1 */
|
|
+ mov r0, #1
|
|
+ pop {r6, pc}
|
|
+endfunc console_register
|
|
+
|
|
+ /* -----------------------------------------------
|
|
+ * int console_unregister(console_t *console)
|
|
+ * Function to find a specific console in the list
|
|
+ * of currently active consoles and remove it.
|
|
+ * In: r0 - address of console_t struct to remove
|
|
+ * Out: r0 - removed address, or NULL if not found
|
|
+ * Clobber list: r0, r1
|
|
+ * -----------------------------------------------
|
|
+ */
|
|
+func console_unregister
|
|
+#if ENABLE_ASSERTIONS
|
|
+ /* Assert that r0 isn't a NULL pointer */
|
|
+ cmp r0, #0
|
|
+ ASM_ASSERT(ne)
|
|
+#endif /* ENABLE_ASSERTIONS */
|
|
+ push {r6}
|
|
+ ldr r6, =console_list /* R6 = ptr to first struct */
|
|
+ ldr r1, [r6] /* R1 = first struct */
|
|
+
|
|
+unregister_loop:
|
|
+ cmp r1, #0
|
|
+ beq unregister_not_found
|
|
+ cmp r0, r1
|
|
+ beq unregister_found
|
|
+ ldr r6, [r6] /* R6 = next ptr of struct */
|
|
+ ldr r1, [r6] /* R1 = next struct */
|
|
+ b unregister_loop
|
|
+
|
|
+unregister_found:
|
|
+ ldr r1, [r1] /* R1 = next struct */
|
|
+ str r1, [r6] /* prev->next = cur->next */
|
|
+ pop {r6}
|
|
+ bx lr
|
|
+
|
|
+unregister_not_found:
|
|
+ mov r0, #0 /* return NULL if not found */
|
|
+ pop {r6}
|
|
+ bx lr
|
|
+endfunc console_unregister
|
|
+
|
|
+ /* -----------------------------------------------
|
|
+ * int console_is_registered(console_t *console)
|
|
+ * Function to detect if a specific console is
|
|
+ * registered or not.
|
|
+ * In: r0 - address of console_t struct to remove
|
|
+ * Out: r0 - 1 if it is registered, 0 if not.
|
|
+ * Clobber list: r0
|
|
+ * -----------------------------------------------
|
|
+ */
|
|
+func console_is_registered
|
|
+#if ENABLE_ASSERTIONS
|
|
+ /* Assert that r0 isn't a NULL pointer */
|
|
+ cmp r0, #0
|
|
+ ASM_ASSERT(ne)
|
|
+#endif /* ENABLE_ASSERTIONS */
|
|
+ push {r6}
|
|
+ ldr r6, =console_list
|
|
+ ldr r6, [r6] /* R6 = first console struct */
|
|
+check_registered_loop:
|
|
+ cmp r6, #0 /* Check if end of list */
|
|
+ beq console_not_registered
|
|
+ cmp r0, r6 /* Check if the pointers are different */
|
|
+ beq console_registered
|
|
+ ldr r6, [r6, #CONSOLE_T_NEXT] /* Get pointer to next struct */
|
|
+ b check_registered_loop
|
|
+console_not_registered:
|
|
+ mov r0, #0
|
|
+ pop {r6}
|
|
+ bx lr
|
|
+console_registered:
|
|
+ mov r0, #1
|
|
+ pop {r6}
|
|
+ bx lr
|
|
+endfunc console_is_registered
|
|
+
|
|
+ /* -----------------------------------------------
|
|
+ * void console_switch_state(unsigned int new_state)
|
|
+ * Function to switch the current console state.
|
|
+ * The console state determines which of the
|
|
+ * registered consoles are actually used at a time.
|
|
+ * In : r0 - global console state to move to
|
|
+ * Clobber list: r0, r1
|
|
+ * -----------------------------------------------
|
|
+ */
|
|
+func console_switch_state
|
|
+ ldr r1, =console_state
|
|
+ strb r0, [r1]
|
|
+ bx lr
|
|
+endfunc console_switch_state
|
|
+
|
|
+ /* -----------------------------------------------
|
|
+ * void console_set_scope(console_t *console,
|
|
+ * unsigned int scope)
|
|
+ * Function to update the states that a given console
|
|
+ * may be active in.
|
|
+ * In : r0 - pointer to console_t struct
|
|
+ * : r1 - new active state mask
|
|
+ * Clobber list: r0, r1, r2
|
|
+ * -----------------------------------------------
|
|
+ */
|
|
+func console_set_scope
|
|
+#if ENABLE_ASSERTIONS
|
|
+ ands r2, r1, #~CONSOLE_FLAG_SCOPE_MASK
|
|
+ ASM_ASSERT(eq)
|
|
+#endif /* ENABLE_ASSERTIONS */
|
|
+ ldr r2, [r0, #CONSOLE_T_FLAGS]
|
|
+ and r2, r2, #~CONSOLE_FLAG_SCOPE_MASK
|
|
+ orr r2, r2, r1
|
|
+ str r2, [r0, #CONSOLE_T_FLAGS]
|
|
+ bx lr
|
|
+endfunc console_set_scope
|
|
+
|
|
+ /* ---------------------------------------------
|
|
+ * int console_putc(int c)
|
|
+ * Function to output a character. Calls all
|
|
+ * active console's putc() handlers in succession.
|
|
+ * In : r0 - character to be printed
|
|
+ * Out: r0 - printed character on success, or < 0
|
|
+ if at least one console had an error
|
|
+ * Clobber list : r0, r1, r2
|
|
+ * ---------------------------------------------
|
|
+ */
|
|
+func console_putc
|
|
+ push {r4-r6, lr}
|
|
+ mov r5, #ERROR_NO_VALID_CONSOLE /* R5 = current return value */
|
|
+ mov r4, r0 /* R4 = character to print */
|
|
+ ldr r6, =console_list
|
|
+ ldr r6, [r6] /* R6 = first console struct */
|
|
+
|
|
+putc_loop:
|
|
+ cmp r6, #0
|
|
+ beq putc_done
|
|
+ ldr r1, =console_state
|
|
+ ldrb r1, [r1]
|
|
+ ldr r2, [r6, #CONSOLE_T_FLAGS]
|
|
+ tst r1, r2
|
|
+ beq putc_continue
|
|
+ ldr r2, [r6, #CONSOLE_T_PUTC]
|
|
+ cmp r2, #0
|
|
+ beq putc_continue
|
|
+ mov r0, r4
|
|
+ mov r1, r6
|
|
+ blx r2
|
|
+ cmp r5, #ERROR_NO_VALID_CONSOLE /* update R5 if it's NOVALID */
|
|
+ cmpne r0, #0 /* else update it if R0 < 0 */
|
|
+ movlt r5, r0
|
|
+putc_continue:
|
|
+ ldr r6, [r6] /* R6 = next struct */
|
|
+ b putc_loop
|
|
+
|
|
+putc_done:
|
|
+ mov r0, r5
|
|
+ pop {r4-r6, pc}
|
|
+endfunc console_putc
|
|
+
|
|
+ /* ---------------------------------------------
|
|
+ * int console_getc(void)
|
|
+ * Function to get a character from any console.
|
|
+ * Keeps looping through all consoles' getc()
|
|
+ * handlers until one of them returns a
|
|
+ * character, then stops iterating and returns
|
|
+ * that character to the caller. Will stop looping
|
|
+ * if all active consoles report real errors
|
|
+ * (other than just not having a char available).
|
|
+ * Out : r0 - read character, or < 0 on error
|
|
+ * Clobber list : r0, r1
|
|
+ * ---------------------------------------------
|
|
+ */
|
|
+func console_getc
|
|
+ push {r5-r6, lr}
|
|
+getc_try_again:
|
|
+ mov r5, #ERROR_NO_VALID_CONSOLE /* R5 = current return value */
|
|
+ ldr r6, =console_list
|
|
+ ldr r6, [r6] /* R6 = first console struct */
|
|
+ cmp r6, #0
|
|
+ bne getc_loop
|
|
+ mov r0, r5 /* If no consoles registered */
|
|
+ pop {r5-r6, pc} /* return immediately. */
|
|
+
|
|
+getc_loop:
|
|
+ ldr r0, =console_state
|
|
+ ldrb r0, [r0]
|
|
+ ldr r1, [r6, #CONSOLE_T_FLAGS]
|
|
+ tst r0, r1
|
|
+ beq getc_continue
|
|
+ ldr r1, [r6, #CONSOLE_T_GETC]
|
|
+ cmp r1, #0
|
|
+ beq getc_continue
|
|
+ mov r0, r6
|
|
+ blx r1
|
|
+ cmp r0, #0 /* if R0 >= 0: return */
|
|
+ bge getc_found
|
|
+ cmp r5, #ERROR_NO_PENDING_CHAR /* may update R5 (NOCHAR has */
|
|
+ movne r5, r0 /* precedence vs real errors) */
|
|
+getc_continue:
|
|
+ ldr r6, [r6] /* R6 = next struct */
|
|
+ cmp r6, #0
|
|
+ bne getc_loop
|
|
+ cmp r5, #ERROR_NO_PENDING_CHAR /* Keep scanning if at least */
|
|
+ beq getc_try_again /* one console returns NOCHAR */
|
|
+ mov r0, r5
|
|
+
|
|
+getc_found:
|
|
+ pop {r5-r6, pc}
|
|
+endfunc console_getc
|
|
+
|
|
+ /* ---------------------------------------------
|
|
+ * int console_flush(void)
|
|
+ * Function to force a write of all buffered
|
|
+ * data that hasn't been output. Calls all
|
|
+ * console's flush() handlers in succession.
|
|
+ * Out: r0 - 0 on success, < 0 if at least one error
|
|
+ * Clobber list : r0, r1, r2
|
|
+ * ---------------------------------------------
|
|
+ */
|
|
+func console_flush
|
|
+ push {r5-r6, lr}
|
|
+ mov r5, #ERROR_NO_VALID_CONSOLE /* R5 = current return value */
|
|
+ ldr r6, =console_list
|
|
+ ldr r6, [r6] /* R6 = first console struct */
|
|
+
|
|
+flush_loop:
|
|
+ cmp r6, #0
|
|
+ beq flush_done
|
|
+ ldr r1, =console_state
|
|
+ ldrb r1, [r1]
|
|
+ ldr r2, [r6, #CONSOLE_T_FLAGS]
|
|
+ tst r1, r2
|
|
+ beq flush_continue
|
|
+ ldr r1, [r6, #CONSOLE_T_FLUSH]
|
|
+ cmp r1, #0
|
|
+ beq flush_continue
|
|
+ mov r0, r6
|
|
+ blx r1
|
|
+ cmp r5, #ERROR_NO_VALID_CONSOLE /* update R5 if it's NOVALID */
|
|
+ cmpne r0, #0 /* else update it if R0 < 0 */
|
|
+ movlt r5, r0
|
|
+flush_continue:
|
|
+ ldr r6, [r6] /* R6 = next struct */
|
|
+ b flush_loop
|
|
+
|
|
+flush_done:
|
|
+ mov r0, r5
|
|
+ pop {r5-r6, pc}
|
|
+endfunc console_flush
|
|
diff --git a/drivers/console/aarch64/skeleton_console.S b/drivers/console/aarch64/skeleton_console.S
|
|
index 1b5d739..3993eef 100644
|
|
--- a/drivers/console/aarch64/skeleton_console.S
|
|
+++ b/drivers/console/aarch64/skeleton_console.S
|
|
@@ -4,6 +4,7 @@
|
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
*/
|
|
#include <asm_macros.S>
|
|
+#define USE_FINISH_CONSOLE_REG_2
|
|
#include <console_macros.S>
|
|
|
|
/*
|
|
@@ -60,8 +61,12 @@ func console_xxx_register
|
|
* Keep console_t pointer in x0 for later.
|
|
*/
|
|
|
|
- /* Macro to finish up registration and return (needs valid x0 + x30). */
|
|
- finish_console_register xxx
|
|
+ /*
|
|
+ * Macro to finish up registration and return (needs valid x0 + x30).
|
|
+ * If any of the argument is unspecified, then the corresponding
|
|
+ * entry in console_t is set to 0.
|
|
+ */
|
|
+ finish_console_register xxx putc=1, getc=1, flush=1
|
|
|
|
/* Jump here if hardware init fails or parameters are invalid. */
|
|
register_fail:
|
|
diff --git a/drivers/coreboot/cbmem_console/aarch64/cbmem_console.S b/drivers/coreboot/cbmem_console/aarch64/cbmem_console.S
|
|
index 2fc0603..ae9a25b 100644
|
|
--- a/drivers/coreboot/cbmem_console/aarch64/cbmem_console.S
|
|
+++ b/drivers/coreboot/cbmem_console/aarch64/cbmem_console.S
|
|
@@ -6,6 +6,7 @@
|
|
|
|
#include <asm_macros.S>
|
|
#include <cbmem_console.h>
|
|
+#define USE_FINISH_CONSOLE_REG_2
|
|
#include <console_macros.S>
|
|
|
|
/*
|
|
@@ -39,7 +40,7 @@ func console_cbmc_register
|
|
ldr w2, [x0]
|
|
str w2, [x1, #CONSOLE_T_CBMC_SIZE]
|
|
mov x0, x1
|
|
- finish_console_register cbmc
|
|
+ finish_console_register cbmc putc=1, flush=1
|
|
endfunc console_cbmc_register
|
|
|
|
/* -----------------------------------------------
|
|
diff --git a/drivers/io/io_block.c b/drivers/io/io_block.c
|
|
index 8226554..3a2f403 100644
|
|
--- a/drivers/io/io_block.c
|
|
+++ b/drivers/io/io_block.c
|
|
@@ -27,7 +27,7 @@ io_type_t device_type_block(void);
|
|
|
|
static int block_open(io_dev_info_t *dev_info, const uintptr_t spec,
|
|
io_entity_t *entity);
|
|
-static int block_seek(io_entity_t *entity, int mode, ssize_t offset);
|
|
+static int block_seek(io_entity_t *entity, int mode, signed long long offset);
|
|
static int block_read(io_entity_t *entity, uintptr_t buffer, size_t length,
|
|
size_t *length_read);
|
|
static int block_write(io_entity_t *entity, const uintptr_t buffer,
|
|
@@ -67,8 +67,10 @@ io_type_t device_type_block(void)
|
|
static int find_first_block_state(const io_block_dev_spec_t *dev_spec,
|
|
unsigned int *index_out)
|
|
{
|
|
+ unsigned int index;
|
|
int result = -ENOENT;
|
|
- for (int index = 0; index < MAX_IO_BLOCK_DEVICES; ++index) {
|
|
+
|
|
+ for (index = 0U; index < MAX_IO_BLOCK_DEVICES; ++index) {
|
|
/* dev_spec is used as identifier since it's unique */
|
|
if (state_pool[index].dev_spec == dev_spec) {
|
|
result = 0;
|
|
@@ -144,7 +146,7 @@ static int block_open(io_dev_info_t *dev_info, const uintptr_t spec,
|
|
}
|
|
|
|
/* parameter offset is relative address at here */
|
|
-static int block_seek(io_entity_t *entity, int mode, ssize_t offset)
|
|
+static int block_seek(io_entity_t *entity, int mode, signed long long offset)
|
|
{
|
|
block_dev_state_t *cur;
|
|
|
|
diff --git a/drivers/io/io_memmap.c b/drivers/io/io_memmap.c
|
|
index 5595e60..8add0b8 100644
|
|
--- a/drivers/io/io_memmap.c
|
|
+++ b/drivers/io/io_memmap.c
|
|
@@ -40,7 +40,7 @@ static int memmap_dev_open(const uintptr_t dev_spec, io_dev_info_t **dev_info);
|
|
static int memmap_block_open(io_dev_info_t *dev_info, const uintptr_t spec,
|
|
io_entity_t *entity);
|
|
static int memmap_block_seek(io_entity_t *entity, int mode,
|
|
- ssize_t offset);
|
|
+ signed long long offset);
|
|
static int memmap_block_len(io_entity_t *entity, size_t *length);
|
|
static int memmap_block_read(io_entity_t *entity, uintptr_t buffer,
|
|
size_t length, size_t *length_read);
|
|
@@ -127,7 +127,8 @@ static int memmap_block_open(io_dev_info_t *dev_info, const uintptr_t spec,
|
|
|
|
|
|
/* Seek to a particular file offset on the memmap device */
|
|
-static int memmap_block_seek(io_entity_t *entity, int mode, ssize_t offset)
|
|
+static int memmap_block_seek(io_entity_t *entity, int mode,
|
|
+ signed long long offset)
|
|
{
|
|
int result = -ENOENT;
|
|
file_state_t *fp;
|
|
diff --git a/drivers/io/io_semihosting.c b/drivers/io/io_semihosting.c
|
|
index 9ca0a9d..125fea9 100644
|
|
--- a/drivers/io/io_semihosting.c
|
|
+++ b/drivers/io/io_semihosting.c
|
|
@@ -25,7 +25,7 @@ static io_type_t device_type_sh(void)
|
|
static int sh_dev_open(const uintptr_t dev_spec, io_dev_info_t **dev_info);
|
|
static int sh_file_open(io_dev_info_t *dev_info, const uintptr_t spec,
|
|
io_entity_t *entity);
|
|
-static int sh_file_seek(io_entity_t *entity, int mode, ssize_t offset);
|
|
+static int sh_file_seek(io_entity_t *entity, int mode, signed long long offset);
|
|
static int sh_file_len(io_entity_t *entity, size_t *length);
|
|
static int sh_file_read(io_entity_t *entity, uintptr_t buffer, size_t length,
|
|
size_t *length_read);
|
|
@@ -90,7 +90,7 @@ static int sh_file_open(io_dev_info_t *dev_info __unused,
|
|
|
|
|
|
/* Seek to a particular file offset on the semi-hosting device */
|
|
-static int sh_file_seek(io_entity_t *entity, int mode, ssize_t offset)
|
|
+static int sh_file_seek(io_entity_t *entity, int mode, signed long long offset)
|
|
{
|
|
long file_handle, sh_result;
|
|
|
|
diff --git a/drivers/io/io_storage.c b/drivers/io/io_storage.c
|
|
index 948f848..90282a2 100644
|
|
--- a/drivers/io/io_storage.c
|
|
+++ b/drivers/io/io_storage.c
|
|
@@ -239,7 +239,7 @@ int io_open(uintptr_t dev_handle, const uintptr_t spec, uintptr_t *handle)
|
|
|
|
|
|
/* Seek to a specific position in an IO entity */
|
|
-int io_seek(uintptr_t handle, io_seek_mode_t mode, ssize_t offset)
|
|
+int io_seek(uintptr_t handle, io_seek_mode_t mode, signed long long offset)
|
|
{
|
|
int result = -ENODEV;
|
|
assert(is_valid_entity(handle) && is_valid_seek_mode(mode));
|
|
diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c
|
|
index 418ab11..4f9cecf 100644
|
|
--- a/drivers/mmc/mmc.c
|
|
+++ b/drivers/mmc/mmc.c
|
|
@@ -1,5 +1,5 @@
|
|
/*
|
|
- * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
|
|
+ * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
|
|
*
|
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
*/
|
|
@@ -246,6 +246,13 @@ static int mmc_fill_device_info(void)
|
|
return ret;
|
|
}
|
|
|
|
+ do {
|
|
+ ret = mmc_device_state();
|
|
+ if (ret < 0) {
|
|
+ return ret;
|
|
+ }
|
|
+ } while (ret != MMC_STATE_TRAN);
|
|
+
|
|
nb_blocks = (mmc_ext_csd[CMD_EXTCSD_SEC_CNT] << 0) |
|
|
(mmc_ext_csd[CMD_EXTCSD_SEC_CNT + 1] << 8) |
|
|
(mmc_ext_csd[CMD_EXTCSD_SEC_CNT + 2] << 16) |
|
|
@@ -292,7 +299,7 @@ static int mmc_fill_device_info(void)
|
|
break;
|
|
}
|
|
|
|
- if (ret != 0) {
|
|
+ if (ret < 0) {
|
|
return ret;
|
|
}
|
|
|
|
@@ -379,7 +386,10 @@ static int mmc_send_op_cond(void)
|
|
int ret, n;
|
|
unsigned int resp_data[4];
|
|
|
|
- mmc_reset_to_idle();
|
|
+ ret = mmc_reset_to_idle();
|
|
+ if (ret != 0) {
|
|
+ return ret;
|
|
+ };
|
|
|
|
for (n = 0; n < SEND_OP_COND_MAX_RETRIES; n++) {
|
|
ret = mmc_send_cmd(MMC_CMD(1), OCR_SECTOR_MODE |
|
|
@@ -394,7 +404,7 @@ static int mmc_send_op_cond(void)
|
|
return 0;
|
|
}
|
|
|
|
- mdelay(1);
|
|
+ mdelay(10);
|
|
}
|
|
|
|
ERROR("CMD1 failed after %d retries\n", SEND_OP_COND_MAX_RETRIES);
|
|
@@ -409,7 +419,10 @@ static int mmc_enumerate(unsigned int clk, unsigned int bus_width)
|
|
|
|
ops->init();
|
|
|
|
- mmc_reset_to_idle();
|
|
+ ret = mmc_reset_to_idle();
|
|
+ if (ret != 0) {
|
|
+ return ret;
|
|
+ };
|
|
|
|
if (mmc_dev_info->mmc_dev_type == MMC_IS_EMMC) {
|
|
ret = mmc_send_op_cond();
|
|
diff --git a/drivers/partition/gpt.c b/drivers/partition/gpt.c
|
|
index 9cc917d..0c51e62 100644
|
|
--- a/drivers/partition/gpt.c
|
|
+++ b/drivers/partition/gpt.c
|
|
@@ -13,10 +13,14 @@
|
|
|
|
static int unicode_to_ascii(unsigned short *str_in, unsigned char *str_out)
|
|
{
|
|
- uint8_t *name = (uint8_t *)str_in;
|
|
+ uint8_t *name;
|
|
int i;
|
|
|
|
- assert((str_in != NULL) && (str_out != NULL) && (name[0] != '\0'));
|
|
+ assert((str_in != NULL) && (str_out != NULL));
|
|
+
|
|
+ name = (uint8_t *)str_in;
|
|
+
|
|
+ assert(name[0] != '\0');
|
|
|
|
/* check whether the unicode string is valid */
|
|
for (i = 1; i < (EFI_NAMELEN << 1); i += 2) {
|
|
@@ -36,7 +40,7 @@ int parse_gpt_entry(gpt_entry_t *gpt_entry, partition_entry_t *entry)
|
|
{
|
|
int result;
|
|
|
|
- assert((gpt_entry != 0) && (entry != 0));
|
|
+ assert((gpt_entry != NULL) && (entry != NULL));
|
|
|
|
if ((gpt_entry->first_lba == 0) && (gpt_entry->last_lba == 0)) {
|
|
return -EINVAL;
|
|
diff --git a/drivers/partition/partition.c b/drivers/partition/partition.c
|
|
index d6fb4b8..6085b86 100644
|
|
--- a/drivers/partition/partition.c
|
|
+++ b/drivers/partition/partition.c
|
|
@@ -30,7 +30,7 @@ static void dump_entries(int num)
|
|
name[len + j] = ' ';
|
|
}
|
|
name[EFI_NAMELEN - 1] = '\0';
|
|
- VERBOSE("%d: %s %lx-%lx\n", i + 1, name, list.list[i].start,
|
|
+ VERBOSE("%d: %s %llx-%llx\n", i + 1, name, list.list[i].start,
|
|
list.list[i].start + list.list[i].length - 4);
|
|
}
|
|
}
|
|
diff --git a/drivers/st/bsec/bsec.c b/drivers/st/bsec/bsec.c
|
|
new file mode 100644
|
|
index 0000000..c579c41
|
|
--- /dev/null
|
|
+++ b/drivers/st/bsec/bsec.c
|
|
@@ -0,0 +1,911 @@
|
|
+/*
|
|
+ * Copyright (c) 2017-2018, STMicroelectronics - All Rights Reserved
|
|
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
|
|
+ *
|
|
+ * SPDX-License-Identifier: BSD-3-Clause
|
|
+ */
|
|
+
|
|
+#include <arch_helpers.h>
|
|
+#include <assert.h>
|
|
+#include <bsec.h>
|
|
+#include <debug.h>
|
|
+#include <limits.h>
|
|
+#include <mmio.h>
|
|
+#include <spinlock.h>
|
|
+#include <stdint.h>
|
|
+#include <stm32mp_dt.h>
|
|
+
|
|
+#define BSEC_IP_VERSION_1_0 0x10
|
|
+#define BSEC_COMPAT "st,stm32mp15-bsec"
|
|
+
|
|
+#define OTP_ACCESS_SIZE (round_up(OTP_MAX_SIZE, __WORD_BIT) / __WORD_BIT)
|
|
+
|
|
+static uint32_t otp_nsec_access[OTP_ACCESS_SIZE] __unused;
|
|
+
|
|
+static uint32_t bsec_power_safmem(bool power);
|
|
+
|
|
+/* BSEC access protection */
|
|
+static spinlock_t bsec_spinlock;
|
|
+static uintptr_t bsec_base;
|
|
+
|
|
+static void bsec_lock(void)
|
|
+{
|
|
+ const uint32_t mask = SCTLR_M_BIT | SCTLR_C_BIT;
|
|
+
|
|
+ /* Lock is currently required only when MMU and cache are enabled */
|
|
+ if ((read_sctlr() & mask) == mask) {
|
|
+ spin_lock(&bsec_spinlock);
|
|
+ }
|
|
+}
|
|
+
|
|
+static void bsec_unlock(void)
|
|
+{
|
|
+ const uint32_t mask = SCTLR_M_BIT | SCTLR_C_BIT;
|
|
+
|
|
+ /* Unlock is required only when MMU and cache are enabled */
|
|
+ if ((read_sctlr() & mask) == mask) {
|
|
+ spin_unlock(&bsec_spinlock);
|
|
+ }
|
|
+}
|
|
+
|
|
+static int bsec_get_dt_node(struct dt_node_info *info)
|
|
+{
|
|
+ int node;
|
|
+
|
|
+ node = dt_get_node(info, -1, BSEC_COMPAT);
|
|
+ if (node < 0) {
|
|
+ return -FDT_ERR_NOTFOUND;
|
|
+ }
|
|
+
|
|
+ return node;
|
|
+}
|
|
+
|
|
+#if defined(IMAGE_BL32)
|
|
+static void enable_non_secure_access(uint32_t otp)
|
|
+{
|
|
+ otp_nsec_access[otp / __WORD_BIT] |= BIT(otp % __WORD_BIT);
|
|
+
|
|
+ if (bsec_shadow_register(otp) != BSEC_OK) {
|
|
+ panic();
|
|
+ }
|
|
+}
|
|
+
|
|
+static bool non_secure_can_access(uint32_t otp)
|
|
+{
|
|
+ return (otp_nsec_access[otp / __WORD_BIT] &
|
|
+ BIT(otp % __WORD_BIT)) != 0;
|
|
+}
|
|
+
|
|
+static int bsec_dt_otp_nsec_access(void *fdt, int bsec_node)
|
|
+{
|
|
+ int bsec_subnode;
|
|
+
|
|
+ fdt_for_each_subnode(bsec_subnode, fdt, bsec_node) {
|
|
+ const fdt32_t *cuint;
|
|
+ uint32_t reg;
|
|
+ uint32_t i;
|
|
+ uint32_t size;
|
|
+ uint8_t status;
|
|
+
|
|
+ cuint = fdt_getprop(fdt, bsec_subnode, "reg", NULL);
|
|
+ if (cuint == NULL) {
|
|
+ panic();
|
|
+ }
|
|
+
|
|
+ reg = fdt32_to_cpu(*cuint) / sizeof(uint32_t);
|
|
+ if (reg < STM32MP1_UPPER_OTP_START) {
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ status = fdt_get_status(bsec_subnode);
|
|
+ if ((status & DT_NON_SECURE) == 0U) {
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ size = fdt32_to_cpu(*(cuint + 1)) / sizeof(uint32_t);
|
|
+
|
|
+ if ((fdt32_to_cpu(*(cuint + 1)) % sizeof(uint32_t)) != 0) {
|
|
+ size++;
|
|
+ }
|
|
+
|
|
+ for (i = reg; i < (reg + size); i++) {
|
|
+ enable_non_secure_access(i);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+#endif
|
|
+
|
|
+static uint32_t otp_bank_offset(uint32_t otp)
|
|
+{
|
|
+ assert(otp <= STM32MP1_OTP_MAX_ID);
|
|
+
|
|
+ return ((otp & ~BSEC_OTP_MASK) >> BSEC_OTP_BANK_SHIFT) *
|
|
+ sizeof(uint32_t);
|
|
+}
|
|
+
|
|
+static uint32_t bsec_check_error(uint32_t otp)
|
|
+{
|
|
+ uint32_t bit = BIT(otp & BSEC_OTP_MASK);
|
|
+ uint32_t bank = otp_bank_offset(otp);
|
|
+
|
|
+ if ((mmio_read_32(bsec_base + BSEC_DISTURBED_OFF + bank) & bit) != 0U) {
|
|
+ return BSEC_DISTURBED;
|
|
+ }
|
|
+
|
|
+ if ((mmio_read_32(bsec_base + BSEC_ERROR_OFF + bank) & bit) != 0U) {
|
|
+ return BSEC_ERROR;
|
|
+ }
|
|
+
|
|
+ return BSEC_OK;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * bsec_probe: initialize BSEC driver.
|
|
+ * return value: BSEC_OK if no error.
|
|
+ */
|
|
+uint32_t bsec_probe(void)
|
|
+{
|
|
+ void *fdt;
|
|
+ int node;
|
|
+ struct dt_node_info bsec_info;
|
|
+
|
|
+ if (fdt_get_address(&fdt) == 0) {
|
|
+ panic();
|
|
+ }
|
|
+
|
|
+ node = bsec_get_dt_node(&bsec_info);
|
|
+ if (node < 0) {
|
|
+ panic();
|
|
+ }
|
|
+
|
|
+ bsec_base = bsec_info.base;
|
|
+
|
|
+#if defined(IMAGE_BL32)
|
|
+ bsec_dt_otp_nsec_access(fdt, node);
|
|
+#endif
|
|
+ return BSEC_OK;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * bsec_get_base: return BSEC base address.
|
|
+ */
|
|
+uint32_t bsec_get_base(void)
|
|
+{
|
|
+ return bsec_base;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * bsec_set_config: enable and configure BSEC.
|
|
+ * cfg: pointer to param structure used to set register.
|
|
+ * return value: BSEC_OK if no error.
|
|
+ */
|
|
+uint32_t bsec_set_config(struct bsec_config *cfg)
|
|
+{
|
|
+ uint32_t value;
|
|
+ int32_t result;
|
|
+
|
|
+ value = ((((uint32_t)cfg->freq << BSEC_CONF_FRQ_SHIFT) &
|
|
+ BSEC_CONF_FRQ_MASK) |
|
|
+ (((uint32_t)cfg->pulse_width << BSEC_CONF_PRG_WIDTH_SHIFT) &
|
|
+ BSEC_CONF_PRG_WIDTH_MASK) |
|
|
+ (((uint32_t)cfg->tread << BSEC_CONF_TREAD_SHIFT) &
|
|
+ BSEC_CONF_TREAD_MASK));
|
|
+
|
|
+ bsec_lock();
|
|
+
|
|
+ mmio_write_32(bsec_base + BSEC_OTP_CONF_OFF, value);
|
|
+
|
|
+ bsec_unlock();
|
|
+
|
|
+ result = bsec_power_safmem((bool)cfg->power &
|
|
+ BSEC_CONF_POWER_UP_MASK);
|
|
+ if (result != BSEC_OK) {
|
|
+ return result;
|
|
+ }
|
|
+
|
|
+ value = ((((uint32_t)cfg->upper_otp_lock << UPPER_OTP_LOCK_SHIFT) &
|
|
+ UPPER_OTP_LOCK_MASK) |
|
|
+ (((uint32_t)cfg->den_lock << DENREG_LOCK_SHIFT) &
|
|
+ DENREG_LOCK_MASK) |
|
|
+ (((uint32_t)cfg->prog_lock << GPLOCK_LOCK_SHIFT) &
|
|
+ GPLOCK_LOCK_MASK));
|
|
+
|
|
+ bsec_lock();
|
|
+
|
|
+ mmio_write_32(bsec_base + BSEC_OTP_LOCK_OFF, value);
|
|
+
|
|
+ bsec_unlock();
|
|
+
|
|
+ return BSEC_OK;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * bsec_get_config: return config parameters set in BSEC registers.
|
|
+ * cfg: config param return.
|
|
+ * return value: BSEC_OK if no error.
|
|
+ */
|
|
+uint32_t bsec_get_config(struct bsec_config *cfg)
|
|
+{
|
|
+ uint32_t value;
|
|
+
|
|
+ if (cfg == NULL) {
|
|
+ return BSEC_INVALID_PARAM;
|
|
+ }
|
|
+
|
|
+ value = mmio_read_32(bsec_base + BSEC_OTP_CONF_OFF);
|
|
+ cfg->power = (uint8_t)((value & BSEC_CONF_POWER_UP_MASK) >>
|
|
+ BSEC_CONF_POWER_UP_SHIFT);
|
|
+ cfg->freq = (uint8_t)((value & BSEC_CONF_FRQ_MASK) >>
|
|
+ BSEC_CONF_FRQ_SHIFT);
|
|
+ cfg->pulse_width = (uint8_t)((value & BSEC_CONF_PRG_WIDTH_MASK) >>
|
|
+ BSEC_CONF_PRG_WIDTH_SHIFT);
|
|
+ cfg->tread = (uint8_t)((value & BSEC_CONF_TREAD_MASK) >>
|
|
+ BSEC_CONF_TREAD_SHIFT);
|
|
+
|
|
+ value = mmio_read_32(bsec_base + BSEC_OTP_LOCK_OFF);
|
|
+ cfg->upper_otp_lock = (uint8_t)((value & UPPER_OTP_LOCK_MASK) >>
|
|
+ UPPER_OTP_LOCK_SHIFT);
|
|
+ cfg->den_lock = (uint8_t)((value & DENREG_LOCK_MASK) >>
|
|
+ DENREG_LOCK_SHIFT);
|
|
+ cfg->prog_lock = (uint8_t)((value & GPLOCK_LOCK_MASK) >>
|
|
+ GPLOCK_LOCK_SHIFT);
|
|
+
|
|
+ return BSEC_OK;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * bsec_shadow_register: copy SAFMEM OTP to BSEC data.
|
|
+ * otp: OTP number.
|
|
+ * return value: BSEC_OK if no error.
|
|
+ */
|
|
+uint32_t bsec_shadow_register(uint32_t otp)
|
|
+{
|
|
+ uint32_t result;
|
|
+ bool power_up = false;
|
|
+
|
|
+ if (otp > STM32MP1_OTP_MAX_ID) {
|
|
+ return BSEC_INVALID_PARAM;
|
|
+ }
|
|
+
|
|
+ /* Check if shadowing of OTP is locked */
|
|
+ if (bsec_read_sr_lock(otp)) {
|
|
+ VERBOSE("BSEC: OTP %i is locked and will not be refreshed\n",
|
|
+ otp);
|
|
+ }
|
|
+
|
|
+ if ((bsec_get_status() & BSEC_MODE_PWR_MASK) == 0U) {
|
|
+ result = bsec_power_safmem(true);
|
|
+
|
|
+ if (result != BSEC_OK) {
|
|
+ return result;
|
|
+ }
|
|
+
|
|
+ power_up = true;
|
|
+ }
|
|
+
|
|
+ bsec_lock();
|
|
+
|
|
+ /* Set BSEC_OTP_CTRL_OFF and set ADDR with the OTP value */
|
|
+ mmio_write_32(bsec_base + BSEC_OTP_CTRL_OFF, otp | BSEC_READ);
|
|
+
|
|
+ while ((bsec_get_status() & BSEC_MODE_BUSY_MASK) != 0U) {
|
|
+ ;
|
|
+ }
|
|
+
|
|
+ result = bsec_check_error(otp);
|
|
+
|
|
+ bsec_unlock();
|
|
+
|
|
+ if (power_up) {
|
|
+ if (bsec_power_safmem(false) != BSEC_OK) {
|
|
+ panic();
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return result;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * bsec_read_otp: read an OTP data value.
|
|
+ * val: read value.
|
|
+ * otp: OTP number.
|
|
+ * return value: BSEC_OK if no error.
|
|
+ */
|
|
+uint32_t bsec_read_otp(uint32_t *val, uint32_t otp)
|
|
+{
|
|
+ uint32_t result;
|
|
+
|
|
+ if (otp > STM32MP1_OTP_MAX_ID) {
|
|
+ return BSEC_INVALID_PARAM;
|
|
+ }
|
|
+
|
|
+ bsec_lock();
|
|
+
|
|
+ *val = mmio_read_32(bsec_base + BSEC_OTP_DATA_OFF +
|
|
+ (otp * sizeof(uint32_t)));
|
|
+
|
|
+ result = bsec_check_error(otp);
|
|
+
|
|
+ bsec_unlock();
|
|
+
|
|
+ return result;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * bsec_write_otp: write value in BSEC data register.
|
|
+ * val: value to write.
|
|
+ * otp: OTP number.
|
|
+ * return value: BSEC_OK if no error.
|
|
+ */
|
|
+uint32_t bsec_write_otp(uint32_t val, uint32_t otp)
|
|
+{
|
|
+ uint32_t result;
|
|
+
|
|
+ if (otp > STM32MP1_OTP_MAX_ID) {
|
|
+ return BSEC_INVALID_PARAM;
|
|
+ }
|
|
+
|
|
+ /* Check if programming of OTP is locked */
|
|
+ if (bsec_read_sw_lock(otp)) {
|
|
+ VERBOSE("BSEC: OTP %i is locked and write will be ignored\n",
|
|
+ otp);
|
|
+ }
|
|
+
|
|
+ bsec_lock();
|
|
+
|
|
+ mmio_write_32(bsec_base + BSEC_OTP_DATA_OFF +
|
|
+ (otp * sizeof(uint32_t)), val);
|
|
+
|
|
+ result = bsec_check_error(otp);
|
|
+
|
|
+ bsec_unlock();
|
|
+
|
|
+ return result;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * bsec_program_otp: program a bit in SAFMEM after the prog.
|
|
+ * The OTP data is not refreshed.
|
|
+ * val: value to program.
|
|
+ * otp: OTP number.
|
|
+ * return value: BSEC_OK if no error.
|
|
+ */
|
|
+uint32_t bsec_program_otp(uint32_t val, uint32_t otp)
|
|
+{
|
|
+ uint32_t result;
|
|
+ bool power_up = false;
|
|
+
|
|
+ if (otp > STM32MP1_OTP_MAX_ID) {
|
|
+ return BSEC_INVALID_PARAM;
|
|
+ }
|
|
+
|
|
+ /* Check if programming of OTP is locked */
|
|
+ if (bsec_read_sp_lock(otp)) {
|
|
+ WARN("BSEC: OTP locked, prog will be ignored\n");
|
|
+ }
|
|
+
|
|
+ if ((mmio_read_32(bsec_base + BSEC_OTP_LOCK_OFF) &
|
|
+ BIT(BSEC_LOCK_PROGRAM)) != 0U) {
|
|
+ WARN("BSEC: GPLOCK activated, prog will be ignored\n");
|
|
+ }
|
|
+
|
|
+ if ((bsec_get_status() & BSEC_MODE_PWR_MASK) == 0U) {
|
|
+ result = bsec_power_safmem(true);
|
|
+
|
|
+ if (result != BSEC_OK) {
|
|
+ return result;
|
|
+ }
|
|
+
|
|
+ power_up = true;
|
|
+ }
|
|
+
|
|
+ bsec_lock();
|
|
+
|
|
+ /* Set value in write register */
|
|
+ mmio_write_32(bsec_base + BSEC_OTP_WRDATA_OFF, val);
|
|
+
|
|
+ /* Set BSEC_OTP_CTRL_OFF and set ADDR with the OTP value */
|
|
+ mmio_write_32(bsec_base + BSEC_OTP_CTRL_OFF, otp | BSEC_WRITE);
|
|
+
|
|
+ while ((bsec_get_status() & BSEC_MODE_BUSY_MASK) != 0U) {
|
|
+ ;
|
|
+ }
|
|
+
|
|
+ if ((bsec_get_status() & BSEC_MODE_PROGFAIL_MASK) != 0U) {
|
|
+ result = BSEC_PROG_FAIL;
|
|
+ } else {
|
|
+ result = bsec_check_error(otp);
|
|
+ }
|
|
+
|
|
+ bsec_unlock();
|
|
+
|
|
+ if (power_up) {
|
|
+ if (bsec_power_safmem(false) != BSEC_OK) {
|
|
+ panic();
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return result;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * bsec_permanent_lock_otp: permanent lock of OTP in SAFMEM.
|
|
+ * otp: OTP number.
|
|
+ * return value: BSEC_OK if no error.
|
|
+ */
|
|
+uint32_t bsec_permanent_lock_otp(uint32_t otp)
|
|
+{
|
|
+ uint32_t result;
|
|
+ bool power_up = false;
|
|
+ uint32_t data;
|
|
+ uint32_t addr;
|
|
+
|
|
+ if (otp > STM32MP1_OTP_MAX_ID) {
|
|
+ return BSEC_INVALID_PARAM;
|
|
+ }
|
|
+
|
|
+ if ((bsec_get_status() & BSEC_MODE_PWR_MASK) == 0U) {
|
|
+ result = bsec_power_safmem(true);
|
|
+
|
|
+ if (result != BSEC_OK) {
|
|
+ return result;
|
|
+ }
|
|
+
|
|
+ power_up = true;
|
|
+ }
|
|
+
|
|
+ if (otp < STM32MP1_UPPER_OTP_START) {
|
|
+ addr = otp >> ADDR_LOWER_OTP_PERLOCK_SHIFT;
|
|
+ data = DATA_LOWER_OTP_PERLOCK_BIT <<
|
|
+ ((otp & DATA_LOWER_OTP_PERLOCK_MASK) << 1U);
|
|
+ } else {
|
|
+ addr = (otp >> ADDR_UPPER_OTP_PERLOCK_SHIFT) + 2U;
|
|
+ data = DATA_UPPER_OTP_PERLOCK_BIT <<
|
|
+ (otp & DATA_UPPER_OTP_PERLOCK_MASK);
|
|
+ }
|
|
+
|
|
+ bsec_lock();
|
|
+
|
|
+ /* Set value in write register */
|
|
+ mmio_write_32(bsec_base + BSEC_OTP_WRDATA_OFF, data);
|
|
+
|
|
+ /* Set BSEC_OTP_CTRL_OFF and set ADDR with the OTP value */
|
|
+ mmio_write_32(bsec_base + BSEC_OTP_CTRL_OFF,
|
|
+ addr | BSEC_WRITE | BSEC_LOCK);
|
|
+
|
|
+ while ((bsec_get_status() & BSEC_MODE_BUSY_MASK) != 0U) {
|
|
+ ;
|
|
+ }
|
|
+
|
|
+ if ((bsec_get_status() & BSEC_MODE_PROGFAIL_MASK) != 0U) {
|
|
+ result = BSEC_PROG_FAIL;
|
|
+ } else {
|
|
+ result = bsec_check_error(otp);
|
|
+ }
|
|
+
|
|
+ bsec_unlock();
|
|
+
|
|
+ if (power_up) {
|
|
+ if (bsec_power_safmem(false) != BSEC_OK) {
|
|
+ panic();
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return result;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * bsec_write_debug_conf: write value in debug feature
|
|
+ * to enable/disable debug service.
|
|
+ * val: value to write.
|
|
+ * return value: BSEC_OK if no error.
|
|
+ */
|
|
+uint32_t bsec_write_debug_conf(uint32_t val)
|
|
+{
|
|
+ uint32_t result = BSEC_ERROR;
|
|
+ uint32_t masked_val = val & BSEC_DEN_ALL_MSK;
|
|
+
|
|
+ bsec_lock();
|
|
+
|
|
+ mmio_write_32(bsec_base + BSEC_DEN_OFF, masked_val);
|
|
+
|
|
+ if ((mmio_read_32(bsec_base + BSEC_DEN_OFF) ^ masked_val) == 0U) {
|
|
+ result = BSEC_OK;
|
|
+ }
|
|
+
|
|
+ bsec_unlock();
|
|
+
|
|
+ return result;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * bsec_read_debug_conf: read debug configuration.
|
|
+ */
|
|
+uint32_t bsec_read_debug_conf(void)
|
|
+{
|
|
+ return mmio_read_32(bsec_base + BSEC_DEN_OFF);
|
|
+}
|
|
+
|
|
+/*
|
|
+ * bsec_get_status: return status register value.
|
|
+ */
|
|
+uint32_t bsec_get_status(void)
|
|
+{
|
|
+ return mmio_read_32(bsec_base + BSEC_OTP_STATUS_OFF);
|
|
+}
|
|
+
|
|
+/*
|
|
+ * bsec_get_hw_conf: return hardware configuration.
|
|
+ */
|
|
+uint32_t bsec_get_hw_conf(void)
|
|
+{
|
|
+ return mmio_read_32(bsec_base + BSEC_IPHW_CFG_OFF);
|
|
+}
|
|
+
|
|
+/*
|
|
+ * bsec_get_version: return BSEC version.
|
|
+ */
|
|
+uint32_t bsec_get_version(void)
|
|
+{
|
|
+ return mmio_read_32(bsec_base + BSEC_IPVR_OFF);
|
|
+}
|
|
+
|
|
+/*
|
|
+ * bsec_get_id: return BSEC ID.
|
|
+ */
|
|
+uint32_t bsec_get_id(void)
|
|
+{
|
|
+ return mmio_read_32(bsec_base + BSEC_IP_ID_OFF);
|
|
+}
|
|
+
|
|
+/*
|
|
+ * bsec_get_magic_id: return BSEC magic number.
|
|
+ */
|
|
+uint32_t bsec_get_magic_id(void)
|
|
+{
|
|
+ return mmio_read_32(bsec_base + BSEC_IP_MAGIC_ID_OFF);
|
|
+}
|
|
+
|
|
+/*
|
|
+ * bsec_write_sr_lock: write shadow-read lock.
|
|
+ * otp: OTP number.
|
|
+ * value: value to write in the register.
|
|
+ * Must be always 1.
|
|
+ * return: true if OTP is locked, else false.
|
|
+ */
|
|
+bool bsec_write_sr_lock(uint32_t otp, uint32_t value)
|
|
+{
|
|
+ bool result = false;
|
|
+ uint32_t bank = otp_bank_offset(otp);
|
|
+ uint32_t bank_value;
|
|
+ uint32_t otp_mask = BIT(otp & BSEC_OTP_MASK);
|
|
+
|
|
+ bsec_lock();
|
|
+
|
|
+ bank_value = mmio_read_32(bsec_base + BSEC_SRLOCK_OFF + bank);
|
|
+
|
|
+ if ((bank_value & otp_mask) == value) {
|
|
+ /*
|
|
+ * In case of write don't need to write,
|
|
+ * the lock is already set.
|
|
+ */
|
|
+ if (value != 0U) {
|
|
+ result = true;
|
|
+ }
|
|
+ } else {
|
|
+ if (value != 0U) {
|
|
+ bank_value = bank_value | otp_mask;
|
|
+ } else {
|
|
+ bank_value = bank_value & ~otp_mask;
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * We can write 0 in all other OTP
|
|
+ * if the lock is activated in one of other OTP.
|
|
+ * Write 0 has no effect.
|
|
+ */
|
|
+ mmio_write_32(bsec_base + BSEC_SRLOCK_OFF + bank, bank_value);
|
|
+ result = true;
|
|
+ }
|
|
+
|
|
+ bsec_unlock();
|
|
+
|
|
+ return result;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * bsec_read_sr_lock: read shadow-read lock.
|
|
+ * otp: OTP number.
|
|
+ * return: true if otp is locked, else false.
|
|
+ */
|
|
+bool bsec_read_sr_lock(uint32_t otp)
|
|
+{
|
|
+ uint32_t bank = otp_bank_offset(otp);
|
|
+ uint32_t otp_mask = BIT(otp & BSEC_OTP_MASK);
|
|
+ uint32_t bank_value = mmio_read_32(bsec_base + BSEC_SRLOCK_OFF + bank);
|
|
+
|
|
+ return (bank_value & otp_mask) != 0U;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * bsec_write_sw_lock: write shadow-write lock.
|
|
+ * otp: OTP number.
|
|
+ * value: Value to write in the register.
|
|
+ * Must be always 1.
|
|
+ * return: true if OTP is locked, else false.
|
|
+ */
|
|
+bool bsec_write_sw_lock(uint32_t otp, uint32_t value)
|
|
+{
|
|
+ bool result = false;
|
|
+ uint32_t bank = otp_bank_offset(otp);
|
|
+ uint32_t otp_mask = BIT(otp & BSEC_OTP_MASK);
|
|
+ uint32_t bank_value;
|
|
+
|
|
+ bsec_lock();
|
|
+
|
|
+ bank_value = mmio_read_32(bsec_base + BSEC_SWLOCK_OFF + bank);
|
|
+
|
|
+ if ((bank_value & otp_mask) == value) {
|
|
+ /*
|
|
+ * In case of write don't need to write,
|
|
+ * the lock is already set.
|
|
+ */
|
|
+ if (value != 0U) {
|
|
+ result = true;
|
|
+ }
|
|
+ } else {
|
|
+ if (value != 0U) {
|
|
+ bank_value = bank_value | otp_mask;
|
|
+ } else {
|
|
+ bank_value = bank_value & ~otp_mask;
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * We can write 0 in all other OTP
|
|
+ * if the lock is activated in one of other OTP.
|
|
+ * Write 0 has no effect.
|
|
+ */
|
|
+ mmio_write_32(bsec_base + BSEC_SWLOCK_OFF + bank, bank_value);
|
|
+ result = true;
|
|
+ }
|
|
+
|
|
+ bsec_unlock();
|
|
+
|
|
+ return result;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * bsec_read_sw_lock: read shadow-write lock.
|
|
+ * otp: OTP number.
|
|
+ * return: true if OTP is locked, else false.
|
|
+ */
|
|
+bool bsec_read_sw_lock(uint32_t otp)
|
|
+{
|
|
+ uint32_t bank = otp_bank_offset(otp);
|
|
+ uint32_t otp_mask = BIT(otp & BSEC_OTP_MASK);
|
|
+ uint32_t bank_value = mmio_read_32(bsec_base + BSEC_SWLOCK_OFF + bank);
|
|
+
|
|
+ return (bank_value & otp_mask) != 0U;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * bsec_write_sp_lock: write shadow-program lock.
|
|
+ * otp: OTP number.
|
|
+ * value: Value to write in the register.
|
|
+ * Must be always 1.
|
|
+ * return: true if OTP is locked, else false.
|
|
+ */
|
|
+bool bsec_write_sp_lock(uint32_t otp, uint32_t value)
|
|
+{
|
|
+ bool result = false;
|
|
+ uint32_t bank = otp_bank_offset(otp);
|
|
+ uint32_t bank_value;
|
|
+ uint32_t otp_mask = BIT(otp & BSEC_OTP_MASK);
|
|
+
|
|
+ bsec_lock();
|
|
+
|
|
+ bank_value = mmio_read_32(bsec_base + BSEC_SPLOCK_OFF + bank);
|
|
+
|
|
+ if ((bank_value & otp_mask) == value) {
|
|
+ /*
|
|
+ * In case of write don't need to write,
|
|
+ * the lock is already set.
|
|
+ */
|
|
+ if (value != 0U) {
|
|
+ result = true;
|
|
+ }
|
|
+ } else {
|
|
+ if (value != 0U) {
|
|
+ bank_value = bank_value | otp_mask;
|
|
+ } else {
|
|
+ bank_value = bank_value & ~otp_mask;
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * We can write 0 in all other OTP
|
|
+ * if the lock is activated in one of other OTP.
|
|
+ * Write 0 has no effect.
|
|
+ */
|
|
+ mmio_write_32(bsec_base + BSEC_SPLOCK_OFF + bank, bank_value);
|
|
+ result = true;
|
|
+ }
|
|
+
|
|
+ bsec_unlock();
|
|
+
|
|
+ return result;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * bsec_read_sp_lock: read shadow-program lock.
|
|
+ * otp: OTP number.
|
|
+ * return: true if OTP is locked, else false.
|
|
+ */
|
|
+bool bsec_read_sp_lock(uint32_t otp)
|
|
+{
|
|
+ uint32_t bank = otp_bank_offset(otp);
|
|
+ uint32_t otp_mask = BIT(otp & BSEC_OTP_MASK);
|
|
+ uint32_t bank_value = mmio_read_32(bsec_base + BSEC_SPLOCK_OFF + bank);
|
|
+
|
|
+ return (bank_value & otp_mask) != 0U;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * bsec_wr_lock: Read permanent lock status.
|
|
+ * otp: OTP number.
|
|
+ * return: true if OTP is locked, else false.
|
|
+ */
|
|
+bool bsec_wr_lock(uint32_t otp)
|
|
+{
|
|
+ uint32_t bank = otp_bank_offset(otp);
|
|
+ uint32_t lock_bit = BIT(otp & BSEC_OTP_MASK);
|
|
+
|
|
+ if ((mmio_read_32(bsec_base + BSEC_WRLOCK_OFF + bank) &
|
|
+ lock_bit) != 0U) {
|
|
+ /*
|
|
+ * In case of write don't need to write,
|
|
+ * the lock is already set.
|
|
+ */
|
|
+ return true;
|
|
+ }
|
|
+
|
|
+ return false;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * bsec_otp_lock: Lock Upper OTP or Global programming or debug enable
|
|
+ * service: Service to lock see header file.
|
|
+ * value: Value to write must always set to 1 (only use for debug purpose).
|
|
+ * return: BSEC_OK if succeed.
|
|
+ */
|
|
+uint32_t bsec_otp_lock(uint32_t service, uint32_t value)
|
|
+{
|
|
+ uintptr_t reg = bsec_base + BSEC_OTP_LOCK_OFF;
|
|
+
|
|
+ switch (service) {
|
|
+ case BSEC_LOCK_UPPER_OTP:
|
|
+ mmio_write_32(reg, value << BSEC_LOCK_UPPER_OTP);
|
|
+ break;
|
|
+ case BSEC_LOCK_DEBUG:
|
|
+ mmio_write_32(reg, value << BSEC_LOCK_DEBUG);
|
|
+ break;
|
|
+ case BSEC_LOCK_PROGRAM:
|
|
+ mmio_write_32(reg, value << BSEC_LOCK_PROGRAM);
|
|
+ break;
|
|
+ default:
|
|
+ return BSEC_INVALID_PARAM;
|
|
+ }
|
|
+
|
|
+ return BSEC_OK;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * bsec_power_safmem: Activate or deactivate SAFMEM power.
|
|
+ * power: true to power up, false to power down.
|
|
+ * return: BSEC_OK if succeed.
|
|
+ */
|
|
+static uint32_t bsec_power_safmem(bool power)
|
|
+{
|
|
+ uint32_t register_val;
|
|
+ uint32_t timeout = BSEC_TIMEOUT_VALUE;
|
|
+
|
|
+ bsec_lock();
|
|
+
|
|
+ register_val = mmio_read_32(bsec_base + BSEC_OTP_CONF_OFF);
|
|
+
|
|
+ if (power) {
|
|
+ register_val |= BSEC_CONF_POWER_UP_MASK;
|
|
+ } else {
|
|
+ register_val &= ~BSEC_CONF_POWER_UP_MASK;
|
|
+ }
|
|
+
|
|
+ mmio_write_32(bsec_base + BSEC_OTP_CONF_OFF, register_val);
|
|
+
|
|
+ /* Waiting loop */
|
|
+ if (power) {
|
|
+ while (((bsec_get_status() & BSEC_MODE_PWR_MASK) == 0U) &&
|
|
+ (timeout != 0U)) {
|
|
+ timeout--;
|
|
+ }
|
|
+ } else {
|
|
+ while (((bsec_get_status() & BSEC_MODE_PWR_MASK) != 0U) &&
|
|
+ (timeout != 0U)) {
|
|
+ timeout--;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ bsec_unlock();
|
|
+
|
|
+ if (timeout == 0U) {
|
|
+ return BSEC_TIMEOUT;
|
|
+ }
|
|
+
|
|
+ return BSEC_OK;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * bsec_mode_is_closed_device: read OTP secure sub-mode.
|
|
+ * return: false if open_device and true of closed_device.
|
|
+ */
|
|
+bool bsec_mode_is_closed_device(void)
|
|
+{
|
|
+ uint32_t value;
|
|
+
|
|
+ if ((bsec_shadow_register(DATA0_OTP) != BSEC_OK) ||
|
|
+ (bsec_read_otp(&value, DATA0_OTP) != BSEC_OK)) {
|
|
+ return true;
|
|
+ }
|
|
+
|
|
+ return (value & DATA0_OTP_SECURED) == DATA0_OTP_SECURED;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * bsec_shadow_read_otp: Load OTP from SAFMEM and provide its value
|
|
+ * otp_value: read value.
|
|
+ * word: OTP number.
|
|
+ * return value: BSEC_OK if no error.
|
|
+ */
|
|
+uint32_t bsec_shadow_read_otp(uint32_t *otp_value, uint32_t word)
|
|
+{
|
|
+ uint32_t result;
|
|
+
|
|
+ result = bsec_shadow_register(word);
|
|
+ if (result != BSEC_OK) {
|
|
+ ERROR("BSEC: %u Shadowing Error %i\n", word, result);
|
|
+ return result;
|
|
+ }
|
|
+
|
|
+ result = bsec_read_otp(otp_value, word);
|
|
+ if (result != BSEC_OK) {
|
|
+ ERROR("BSEC: %u Read Error %i\n", word, result);
|
|
+ }
|
|
+
|
|
+ return result;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * bsec_check_nsec_access_rights: check non-secure access rights to target OTP.
|
|
+ * otp: OTP number.
|
|
+ * return: BSEC_OK if authorized access.
|
|
+ */
|
|
+uint32_t bsec_check_nsec_access_rights(uint32_t otp)
|
|
+{
|
|
+#if defined(IMAGE_BL32)
|
|
+ if (otp > STM32MP1_OTP_MAX_ID) {
|
|
+ return BSEC_INVALID_PARAM;
|
|
+ }
|
|
+
|
|
+ if (otp >= STM32MP1_UPPER_OTP_START) {
|
|
+ /* Check if BSEC is in OTP-SECURED closed_device state. */
|
|
+ if (bsec_mode_is_closed_device()) {
|
|
+ if (!non_secure_can_access(otp)) {
|
|
+ return BSEC_ERROR;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+#endif
|
|
+
|
|
+ return BSEC_OK;
|
|
+}
|
|
+
|
|
diff --git a/drivers/st/clk/stm32mp1_clk.c b/drivers/st/clk/stm32mp1_clk.c
|
|
index f0bf363..b304315 100644
|
|
--- a/drivers/st/clk/stm32mp1_clk.c
|
|
+++ b/drivers/st/clk/stm32mp1_clk.c
|
|
@@ -9,26 +9,34 @@
|
|
#include <assert.h>
|
|
#include <debug.h>
|
|
#include <delay_timer.h>
|
|
-#include <dt-bindings/clock/stm32mp1-clks.h>
|
|
#include <dt-bindings/clock/stm32mp1-clksrc.h>
|
|
#include <errno.h>
|
|
#include <generic_delay_timer.h>
|
|
#include <libfdt.h>
|
|
#include <mmio.h>
|
|
#include <platform.h>
|
|
+#include <spinlock.h>
|
|
#include <stdint.h>
|
|
#include <stdio.h>
|
|
+#include <stm32mp_clkfunc.h>
|
|
+#include <stm32mp_common.h>
|
|
+#include <stm32mp_dt.h>
|
|
+#include <stm32mp_shres_helpers.h>
|
|
#include <stm32mp1_clk.h>
|
|
#include <stm32mp1_clkfunc.h>
|
|
-#include <stm32mp1_dt.h>
|
|
#include <stm32mp1_private.h>
|
|
#include <stm32mp1_rcc.h>
|
|
+#include <stm32mp1_shared_resources.h>
|
|
+#if defined(IMAGE_BL32)
|
|
+#include <stm32_timer.h>
|
|
+#endif
|
|
#include <utils_def.h>
|
|
|
|
#define MAX_HSI_HZ 64000000
|
|
+#define USB_PHY_48_MHZ 48000000
|
|
|
|
-#define TIMEOUT_200MS (plat_get_syscnt_freq2() / 5U)
|
|
-#define TIMEOUT_1S plat_get_syscnt_freq2()
|
|
+#define TIMEOUT_200MS ms2tick(200)
|
|
+#define TIMEOUT_1S s2tick(1)
|
|
|
|
#define PLLRDY_TIMEOUT TIMEOUT_200MS
|
|
#define CLKSRC_TIMEOUT TIMEOUT_200MS
|
|
@@ -36,6 +44,10 @@
|
|
#define HSIDIV_TIMEOUT TIMEOUT_200MS
|
|
#define OSCRDY_TIMEOUT TIMEOUT_1S
|
|
|
|
+#if defined(IMAGE_BL32)
|
|
+#define CAL_MAX_RETRY 20U
|
|
+#endif
|
|
+
|
|
enum stm32mp1_parent_id {
|
|
/* Oscillators are defined in enum stm32mp_osc_id */
|
|
|
|
@@ -66,12 +78,21 @@ enum stm32mp1_parent_id {
|
|
_HCLK2,
|
|
_CK_PER,
|
|
_CK_MPU,
|
|
+ _CK_MCU,
|
|
+ _USB_PHY_48,
|
|
_PARENT_NB,
|
|
_UNKNOWN_ID = 0xff,
|
|
};
|
|
|
|
+/* Lists only the parent clock we are interested in */
|
|
enum stm32mp1_parent_sel {
|
|
+ _I2C12_SEL,
|
|
+ _I2C35_SEL,
|
|
+ _STGEN_SEL,
|
|
_I2C46_SEL,
|
|
+ _SPI6_SEL,
|
|
+ _USART1_SEL,
|
|
+ _RNG1_SEL,
|
|
_UART6_SEL,
|
|
_UART24_SEL,
|
|
_UART35_SEL,
|
|
@@ -80,9 +101,10 @@ enum stm32mp1_parent_sel {
|
|
_SDMMC3_SEL,
|
|
_QSPI_SEL,
|
|
_FMC_SEL,
|
|
+ _ASS_SEL,
|
|
+ _MSS_SEL,
|
|
_USBPHY_SEL,
|
|
_USBO_SEL,
|
|
- _STGEN_SEL,
|
|
_PARENT_SEL_NB,
|
|
_UNKNOWN_SEL = 0xff,
|
|
};
|
|
@@ -105,6 +127,7 @@ enum stm32mp1_div_id {
|
|
enum stm32mp1_clksrc_id {
|
|
CLKSRC_MPU,
|
|
CLKSRC_AXI,
|
|
+ CLKSRC_MCU,
|
|
CLKSRC_PLL12,
|
|
CLKSRC_PLL3,
|
|
CLKSRC_PLL4,
|
|
@@ -117,6 +140,7 @@ enum stm32mp1_clksrc_id {
|
|
enum stm32mp1_clkdiv_id {
|
|
CLKDIV_MPU,
|
|
CLKDIV_AXI,
|
|
+ CLKDIV_MCU,
|
|
CLKDIV_APB1,
|
|
CLKDIV_APB2,
|
|
CLKDIV_APB3,
|
|
@@ -162,9 +186,8 @@ struct stm32mp1_clk_gate {
|
|
uint8_t bit;
|
|
uint8_t index;
|
|
uint8_t set_clr;
|
|
- enum stm32mp1_parent_sel sel;
|
|
- enum stm32mp1_parent_id fixed;
|
|
- bool secure;
|
|
+ uint8_t sel; /* Relates to enum stm32mp1_parent_sel */
|
|
+ uint8_t fixed; /* Relates to enum stm32mp1_parent_id */
|
|
};
|
|
|
|
struct stm32mp1_clk_sel {
|
|
@@ -187,21 +210,34 @@ struct stm32mp1_clk_pll {
|
|
enum stm32mp_osc_id refclk[REFCLK_SIZE];
|
|
};
|
|
|
|
-struct stm32mp1_clk_data {
|
|
- const struct stm32mp1_clk_gate *gate;
|
|
- const struct stm32mp1_clk_sel *sel;
|
|
- const struct stm32mp1_clk_pll *pll;
|
|
- const int nb_gate;
|
|
+#if defined(IMAGE_BL32)
|
|
+struct stm32mp1_trim_boundary_t {
|
|
+ /* Max boundary trim value around forbidden value */
|
|
+ unsigned int x1;
|
|
+ /* Min boundary trim value around forbidden value */
|
|
+ unsigned int x2;
|
|
};
|
|
|
|
-struct stm32mp1_clk_priv {
|
|
- uint32_t base;
|
|
- const struct stm32mp1_clk_data *data;
|
|
- unsigned long osc[NB_OSC];
|
|
- uint32_t pkcs_usb_value;
|
|
+struct stm32mp1_clk_cal {
|
|
+ uint16_t *fbv;
|
|
+ unsigned int cal_ref;
|
|
+ int trim_max;
|
|
+ int trim_min;
|
|
+ unsigned int boundary_max;
|
|
+ unsigned long ref_freq;
|
|
+ unsigned int freq_margin;
|
|
+ unsigned long (*get_freq)(void);
|
|
+ void (*set_trim)(unsigned int cal);
|
|
+ unsigned int (*get_trim)(void);
|
|
+ struct stm32mp1_trim_boundary_t boundary[16];
|
|
};
|
|
|
|
-#define STM32MP1_CLK(off, b, idx, s) \
|
|
+/* RCC Wakeup status */
|
|
+static bool rcc_wakeup;
|
|
+#endif
|
|
+
|
|
+/* Clocks with selectable source and non set/clr register access */
|
|
+#define _CLK_SELEC(off, b, idx, s) \
|
|
{ \
|
|
.offset = (off), \
|
|
.bit = (b), \
|
|
@@ -209,10 +245,10 @@ struct stm32mp1_clk_priv {
|
|
.set_clr = 0, \
|
|
.sel = (s), \
|
|
.fixed = _UNKNOWN_ID, \
|
|
- .secure = 0, \
|
|
}
|
|
|
|
-#define STM32MP1_CLK_F(off, b, idx, f) \
|
|
+/* Clocks with fixed source and non set/clr register access */
|
|
+#define _CLK_FIXED(off, b, idx, f) \
|
|
{ \
|
|
.offset = (off), \
|
|
.bit = (b), \
|
|
@@ -220,10 +256,10 @@ struct stm32mp1_clk_priv {
|
|
.set_clr = 0, \
|
|
.sel = _UNKNOWN_SEL, \
|
|
.fixed = (f), \
|
|
- .secure = 0, \
|
|
}
|
|
|
|
-#define STM32MP1_CLK_SET_CLR(off, b, idx, s) \
|
|
+/* Clocks with selectable source and set/clr register access */
|
|
+#define _CLK_SC_SELEC(off, b, idx, s) \
|
|
{ \
|
|
.offset = (off), \
|
|
.bit = (b), \
|
|
@@ -231,10 +267,10 @@ struct stm32mp1_clk_priv {
|
|
.set_clr = 1, \
|
|
.sel = (s), \
|
|
.fixed = _UNKNOWN_ID, \
|
|
- .secure = 0, \
|
|
}
|
|
|
|
-#define STM32MP1_CLK_SET_CLR_F(off, b, idx, f) \
|
|
+/* Clocks with fixed source and set/clr register access */
|
|
+#define _CLK_SC_FIXED(off, b, idx, f) \
|
|
{ \
|
|
.offset = (off), \
|
|
.bit = (b), \
|
|
@@ -242,32 +278,20 @@ struct stm32mp1_clk_priv {
|
|
.set_clr = 1, \
|
|
.sel = _UNKNOWN_SEL, \
|
|
.fixed = (f), \
|
|
- .secure = 0, \
|
|
- }
|
|
-
|
|
-#define STM32MP1_CLK_SEC_SET_CLR(off, b, idx, s) \
|
|
- { \
|
|
- .offset = (off), \
|
|
- .bit = (b), \
|
|
- .index = (idx), \
|
|
- .set_clr = 1, \
|
|
- .sel = (s), \
|
|
- .fixed = _UNKNOWN_ID, \
|
|
- .secure = 1, \
|
|
}
|
|
|
|
-#define STM32MP1_CLK_PARENT(idx, off, s, m, p) \
|
|
+#define _CLK_PARENT(idx, off, s, m, p) \
|
|
[(idx)] = { \
|
|
.offset = (off), \
|
|
.src = (s), \
|
|
.msk = (m), \
|
|
.parent = (p), \
|
|
- .nb_parent = ARRAY_SIZE((p)) \
|
|
+ .nb_parent = ARRAY_SIZE(p) \
|
|
}
|
|
|
|
-#define STM32MP1_CLK_PLL(idx, type, off1, off2, off3, \
|
|
- off4, off5, off6, \
|
|
- p1, p2, p3, p4) \
|
|
+#define _CLK_PLL(idx, type, off1, off2, off3, \
|
|
+ off4, off5, off6, \
|
|
+ p1, p2, p3, p4) \
|
|
[(idx)] = { \
|
|
.plltype = (type), \
|
|
.rckxselr = (off1), \
|
|
@@ -283,113 +307,180 @@ struct stm32mp1_clk_priv {
|
|
}
|
|
|
|
static const uint8_t stm32mp1_clks[][2] = {
|
|
- {CK_PER, _CK_PER},
|
|
- {CK_MPU, _CK_MPU},
|
|
- {CK_AXI, _ACLK},
|
|
- {CK_HSE, _HSE},
|
|
- {CK_CSI, _CSI},
|
|
- {CK_LSI, _LSI},
|
|
- {CK_LSE, _LSE},
|
|
- {CK_HSI, _HSI},
|
|
- {CK_HSE_DIV2, _HSE_KER_DIV2},
|
|
+ { CK_PER, _CK_PER },
|
|
+ { CK_MPU, _CK_MPU },
|
|
+ { CK_AXI, _ACLK },
|
|
+ { CK_MCU, _CK_MCU },
|
|
+ { CK_HSE, _HSE },
|
|
+ { CK_CSI, _CSI },
|
|
+ { CK_LSI, _LSI },
|
|
+ { CK_LSE, _LSE },
|
|
+ { CK_HSI, _HSI },
|
|
+ { CK_HSE_DIV2, _HSE_KER_DIV2 },
|
|
};
|
|
|
|
+#define NB_GATES ARRAY_SIZE(stm32mp1_clk_gate)
|
|
+
|
|
static const struct stm32mp1_clk_gate stm32mp1_clk_gate[] = {
|
|
- STM32MP1_CLK(RCC_DDRITFCR, 0, DDRC1, _UNKNOWN_SEL),
|
|
- STM32MP1_CLK(RCC_DDRITFCR, 1, DDRC1LP, _UNKNOWN_SEL),
|
|
- STM32MP1_CLK(RCC_DDRITFCR, 2, DDRC2, _UNKNOWN_SEL),
|
|
- STM32MP1_CLK(RCC_DDRITFCR, 3, DDRC2LP, _UNKNOWN_SEL),
|
|
- STM32MP1_CLK_F(RCC_DDRITFCR, 4, DDRPHYC, _PLL2_R),
|
|
- STM32MP1_CLK(RCC_DDRITFCR, 5, DDRPHYCLP, _UNKNOWN_SEL),
|
|
- STM32MP1_CLK(RCC_DDRITFCR, 6, DDRCAPB, _UNKNOWN_SEL),
|
|
- STM32MP1_CLK(RCC_DDRITFCR, 7, DDRCAPBLP, _UNKNOWN_SEL),
|
|
- STM32MP1_CLK(RCC_DDRITFCR, 8, AXIDCG, _UNKNOWN_SEL),
|
|
- STM32MP1_CLK(RCC_DDRITFCR, 9, DDRPHYCAPB, _UNKNOWN_SEL),
|
|
- STM32MP1_CLK(RCC_DDRITFCR, 10, DDRPHYCAPBLP, _UNKNOWN_SEL),
|
|
-
|
|
- STM32MP1_CLK_SET_CLR(RCC_MP_APB1ENSETR, 14, USART2_K, _UART24_SEL),
|
|
- STM32MP1_CLK_SET_CLR(RCC_MP_APB1ENSETR, 15, USART3_K, _UART35_SEL),
|
|
- STM32MP1_CLK_SET_CLR(RCC_MP_APB1ENSETR, 16, UART4_K, _UART24_SEL),
|
|
- STM32MP1_CLK_SET_CLR(RCC_MP_APB1ENSETR, 17, UART5_K, _UART35_SEL),
|
|
- STM32MP1_CLK_SET_CLR(RCC_MP_APB1ENSETR, 18, UART7_K, _UART78_SEL),
|
|
- STM32MP1_CLK_SET_CLR(RCC_MP_APB1ENSETR, 19, UART8_K, _UART78_SEL),
|
|
-
|
|
- STM32MP1_CLK_SET_CLR(RCC_MP_APB2ENSETR, 13, USART6_K, _UART6_SEL),
|
|
-
|
|
- STM32MP1_CLK_SET_CLR(RCC_MP_APB4ENSETR, 8, DDRPERFM, _UNKNOWN_SEL),
|
|
- STM32MP1_CLK_SET_CLR(RCC_MP_APB4ENSETR, 15, IWDG2, _UNKNOWN_SEL),
|
|
- STM32MP1_CLK_SET_CLR(RCC_MP_APB4ENSETR, 16, USBPHY_K, _USBPHY_SEL),
|
|
-
|
|
- STM32MP1_CLK_SEC_SET_CLR(RCC_MP_APB5ENSETR, 2, I2C4_K, _I2C46_SEL),
|
|
- STM32MP1_CLK_SEC_SET_CLR(RCC_MP_APB5ENSETR, 8, RTCAPB, _PCLK5),
|
|
- STM32MP1_CLK_SEC_SET_CLR(RCC_MP_APB5ENSETR, 11, TZC1, _UNKNOWN_SEL),
|
|
- STM32MP1_CLK_SEC_SET_CLR(RCC_MP_APB5ENSETR, 12, TZC2, _UNKNOWN_SEL),
|
|
- STM32MP1_CLK_SEC_SET_CLR(RCC_MP_APB5ENSETR, 20, STGEN_K, _STGEN_SEL),
|
|
-
|
|
- STM32MP1_CLK_SET_CLR(RCC_MP_AHB2ENSETR, 8, USBO_K, _USBO_SEL),
|
|
- STM32MP1_CLK_SET_CLR(RCC_MP_AHB2ENSETR, 16, SDMMC3_K, _SDMMC3_SEL),
|
|
-
|
|
- STM32MP1_CLK_SET_CLR(RCC_MP_AHB4ENSETR, 0, GPIOA, _UNKNOWN_SEL),
|
|
- STM32MP1_CLK_SET_CLR(RCC_MP_AHB4ENSETR, 1, GPIOB, _UNKNOWN_SEL),
|
|
- STM32MP1_CLK_SET_CLR(RCC_MP_AHB4ENSETR, 2, GPIOC, _UNKNOWN_SEL),
|
|
- STM32MP1_CLK_SET_CLR(RCC_MP_AHB4ENSETR, 3, GPIOD, _UNKNOWN_SEL),
|
|
- STM32MP1_CLK_SET_CLR(RCC_MP_AHB4ENSETR, 4, GPIOE, _UNKNOWN_SEL),
|
|
- STM32MP1_CLK_SET_CLR(RCC_MP_AHB4ENSETR, 5, GPIOF, _UNKNOWN_SEL),
|
|
- STM32MP1_CLK_SET_CLR(RCC_MP_AHB4ENSETR, 6, GPIOG, _UNKNOWN_SEL),
|
|
- STM32MP1_CLK_SET_CLR(RCC_MP_AHB4ENSETR, 7, GPIOH, _UNKNOWN_SEL),
|
|
- STM32MP1_CLK_SET_CLR(RCC_MP_AHB4ENSETR, 8, GPIOI, _UNKNOWN_SEL),
|
|
- STM32MP1_CLK_SET_CLR(RCC_MP_AHB4ENSETR, 9, GPIOJ, _UNKNOWN_SEL),
|
|
- STM32MP1_CLK_SET_CLR(RCC_MP_AHB4ENSETR, 10, GPIOK, _UNKNOWN_SEL),
|
|
-
|
|
- STM32MP1_CLK_SEC_SET_CLR(RCC_MP_AHB5ENSETR, 0, GPIOZ, _UNKNOWN_SEL),
|
|
- STM32MP1_CLK_SEC_SET_CLR(RCC_MP_AHB5ENSETR, 5, HASH1, _UNKNOWN_SEL),
|
|
- STM32MP1_CLK_SEC_SET_CLR(RCC_MP_AHB5ENSETR, 6, RNG1_K, _CSI_KER),
|
|
- STM32MP1_CLK_SEC_SET_CLR(RCC_MP_AHB5ENSETR, 8, BKPSRAM, _UNKNOWN_SEL),
|
|
-
|
|
- STM32MP1_CLK_SET_CLR(RCC_MP_AHB6ENSETR, 12, FMC_K, _FMC_SEL),
|
|
- STM32MP1_CLK_SET_CLR(RCC_MP_AHB6ENSETR, 14, QSPI_K, _QSPI_SEL),
|
|
- STM32MP1_CLK_SET_CLR(RCC_MP_AHB6ENSETR, 16, SDMMC1_K, _SDMMC12_SEL),
|
|
- STM32MP1_CLK_SET_CLR(RCC_MP_AHB6ENSETR, 17, SDMMC2_K, _SDMMC12_SEL),
|
|
- STM32MP1_CLK_SET_CLR(RCC_MP_AHB6ENSETR, 24, USBH, _UNKNOWN_SEL),
|
|
-
|
|
- STM32MP1_CLK(RCC_DBGCFGR, 8, CK_DBG, _UNKNOWN_SEL),
|
|
+ _CLK_FIXED(RCC_DDRITFCR, 0, DDRC1, _ACLK),
|
|
+ _CLK_FIXED(RCC_DDRITFCR, 1, DDRC1LP, _ACLK),
|
|
+ _CLK_FIXED(RCC_DDRITFCR, 2, DDRC2, _ACLK),
|
|
+ _CLK_FIXED(RCC_DDRITFCR, 3, DDRC2LP, _ACLK),
|
|
+ _CLK_FIXED(RCC_DDRITFCR, 4, DDRPHYC, _PLL2_R),
|
|
+ _CLK_FIXED(RCC_DDRITFCR, 5, DDRPHYCLP, _PLL2_R),
|
|
+ _CLK_FIXED(RCC_DDRITFCR, 6, DDRCAPB, _PCLK4),
|
|
+ _CLK_FIXED(RCC_DDRITFCR, 7, DDRCAPBLP, _PCLK4),
|
|
+ _CLK_FIXED(RCC_DDRITFCR, 8, AXIDCG, _ACLK),
|
|
+ _CLK_FIXED(RCC_DDRITFCR, 9, DDRPHYCAPB, _PCLK4),
|
|
+ _CLK_FIXED(RCC_DDRITFCR, 10, DDRPHYCAPBLP, _PCLK4),
|
|
+ _CLK_SC_FIXED(RCC_MP_APB1ENSETR, 6, TIM12_K, _PCLK1),
|
|
+ _CLK_SC_SELEC(RCC_MP_APB1ENSETR, 14, USART2_K, _UART24_SEL),
|
|
+ _CLK_SC_SELEC(RCC_MP_APB1ENSETR, 15, USART3_K, _UART35_SEL),
|
|
+ _CLK_SC_SELEC(RCC_MP_APB1ENSETR, 16, UART4_K, _UART24_SEL),
|
|
+ _CLK_SC_SELEC(RCC_MP_APB1ENSETR, 17, UART5_K, _UART35_SEL),
|
|
+ _CLK_SC_SELEC(RCC_MP_APB1ENSETR, 18, UART7_K, _UART78_SEL),
|
|
+ _CLK_SC_SELEC(RCC_MP_APB1ENSETR, 19, UART8_K, _UART78_SEL),
|
|
+ _CLK_SC_SELEC(RCC_MP_APB1ENSETR, 21, I2C1_K, _I2C12_SEL),
|
|
+ _CLK_SC_SELEC(RCC_MP_APB1ENSETR, 22, I2C2_K, _I2C12_SEL),
|
|
+ _CLK_SC_SELEC(RCC_MP_APB1ENSETR, 23, I2C3_K, _I2C35_SEL),
|
|
+ _CLK_SC_SELEC(RCC_MP_APB1ENSETR, 24, I2C5_K, _I2C35_SEL),
|
|
+ _CLK_SC_FIXED(RCC_MP_APB2ENSETR, 2, TIM15_K, _PCLK2),
|
|
+ _CLK_SC_SELEC(RCC_MP_APB2ENSETR, 13, USART6_K, _UART6_SEL),
|
|
+
|
|
+ _CLK_SC_SELEC(RCC_MP_APB4ENSETR, 8, DDRPERFM, _UNKNOWN_SEL),
|
|
+ _CLK_SC_SELEC(RCC_MP_APB4ENSETR, 15, IWDG2, _UNKNOWN_SEL),
|
|
+ _CLK_SC_SELEC(RCC_MP_APB4ENSETR, 16, USBPHY_K, _USBPHY_SEL),
|
|
+
|
|
+ _CLK_SC_SELEC(RCC_MP_APB5ENSETR, 0, SPI6_K, _SPI6_SEL),
|
|
+ _CLK_SC_SELEC(RCC_MP_APB5ENSETR, 2, I2C4_K, _I2C46_SEL),
|
|
+ _CLK_SC_SELEC(RCC_MP_APB5ENSETR, 3, I2C6_K, _I2C46_SEL),
|
|
+ _CLK_SC_SELEC(RCC_MP_APB5ENSETR, 4, USART1_K, _USART1_SEL),
|
|
+ _CLK_SC_FIXED(RCC_MP_APB5ENSETR, 8, RTCAPB, _PCLK5),
|
|
+ _CLK_SC_FIXED(RCC_MP_APB5ENSETR, 11, TZC1, _PCLK5),
|
|
+ _CLK_SC_FIXED(RCC_MP_APB5ENSETR, 12, TZC2, _PCLK5),
|
|
+ _CLK_SC_FIXED(RCC_MP_APB5ENSETR, 13, TZPC, _PCLK5),
|
|
+ _CLK_SC_FIXED(RCC_MP_APB5ENSETR, 15, IWDG1, _PCLK5),
|
|
+ _CLK_SC_FIXED(RCC_MP_APB5ENSETR, 16, BSEC, _PCLK5),
|
|
+ _CLK_SC_SELEC(RCC_MP_APB5ENSETR, 20, STGEN_K, _STGEN_SEL),
|
|
+
|
|
+ _CLK_SC_SELEC(RCC_MP_AHB2ENSETR, 8, USBO_K, _USBO_SEL),
|
|
+ _CLK_SC_SELEC(RCC_MP_AHB2ENSETR, 16, SDMMC3_K, _SDMMC3_SEL),
|
|
+
|
|
+ _CLK_SC_SELEC(RCC_MP_AHB4ENSETR, 0, GPIOA, _UNKNOWN_SEL),
|
|
+ _CLK_SC_SELEC(RCC_MP_AHB4ENSETR, 1, GPIOB, _UNKNOWN_SEL),
|
|
+ _CLK_SC_SELEC(RCC_MP_AHB4ENSETR, 2, GPIOC, _UNKNOWN_SEL),
|
|
+ _CLK_SC_SELEC(RCC_MP_AHB4ENSETR, 3, GPIOD, _UNKNOWN_SEL),
|
|
+ _CLK_SC_SELEC(RCC_MP_AHB4ENSETR, 4, GPIOE, _UNKNOWN_SEL),
|
|
+ _CLK_SC_SELEC(RCC_MP_AHB4ENSETR, 5, GPIOF, _UNKNOWN_SEL),
|
|
+ _CLK_SC_SELEC(RCC_MP_AHB4ENSETR, 6, GPIOG, _UNKNOWN_SEL),
|
|
+ _CLK_SC_SELEC(RCC_MP_AHB4ENSETR, 7, GPIOH, _UNKNOWN_SEL),
|
|
+ _CLK_SC_SELEC(RCC_MP_AHB4ENSETR, 8, GPIOI, _UNKNOWN_SEL),
|
|
+ _CLK_SC_SELEC(RCC_MP_AHB4ENSETR, 9, GPIOJ, _UNKNOWN_SEL),
|
|
+ _CLK_SC_SELEC(RCC_MP_AHB4ENSETR, 10, GPIOK, _UNKNOWN_SEL),
|
|
+
|
|
+ _CLK_SC_FIXED(RCC_MP_AHB5ENSETR, 0, GPIOZ, _PCLK5),
|
|
+ _CLK_SC_FIXED(RCC_MP_AHB5ENSETR, 4, CRYP1, _PCLK5),
|
|
+ _CLK_SC_FIXED(RCC_MP_AHB5ENSETR, 5, HASH1, _PCLK5),
|
|
+ _CLK_SC_SELEC(RCC_MP_AHB5ENSETR, 6, RNG1_K, _RNG1_SEL),
|
|
+ _CLK_SC_FIXED(RCC_MP_AHB5ENSETR, 8, BKPSRAM, _PCLK5),
|
|
+
|
|
+ _CLK_SC_SELEC(RCC_MP_AHB6ENSETR, 12, FMC_K, _FMC_SEL),
|
|
+ _CLK_SC_SELEC(RCC_MP_AHB6ENSETR, 14, QSPI_K, _QSPI_SEL),
|
|
+ _CLK_SC_SELEC(RCC_MP_AHB6ENSETR, 16, SDMMC1_K, _SDMMC12_SEL),
|
|
+ _CLK_SC_SELEC(RCC_MP_AHB6ENSETR, 17, SDMMC2_K, _SDMMC12_SEL),
|
|
+ _CLK_SC_SELEC(RCC_MP_AHB6ENSETR, 24, USBH, _UNKNOWN_SEL),
|
|
+
|
|
+ _CLK_SELEC(RCC_DBGCFGR, 8, CK_DBG, _UNKNOWN_SEL),
|
|
+};
|
|
+
|
|
+static const uint8_t i2c12_parents[] = {
|
|
+ _PCLK1, _PLL4_R, _HSI_KER, _CSI_KER
|
|
+};
|
|
+
|
|
+static const uint8_t i2c35_parents[] = {
|
|
+ _PCLK1, _PLL4_R, _HSI_KER, _CSI_KER
|
|
+};
|
|
+
|
|
+static const uint8_t stgen_parents[] = {
|
|
+ _HSI_KER, _HSE_KER
|
|
+};
|
|
+
|
|
+static const uint8_t i2c46_parents[] = {
|
|
+ _PCLK5, _PLL3_Q, _HSI_KER, _CSI_KER
|
|
+};
|
|
+
|
|
+static const uint8_t spi6_parents[] = {
|
|
+ _PCLK5, _PLL4_Q, _HSI_KER, _CSI_KER, _HSE_KER, _PLL3_Q
|
|
+};
|
|
+
|
|
+static const uint8_t usart1_parents[] = {
|
|
+ _PCLK5, _PLL3_Q, _HSI_KER, _CSI_KER, _PLL4_Q, _HSE_KER
|
|
+};
|
|
+
|
|
+static const uint8_t rng1_parents[] = {
|
|
+ _CSI, _PLL4_R, _LSE, _LSI
|
|
+};
|
|
+
|
|
+static const uint8_t uart6_parents[] = {
|
|
+ _PCLK2, _PLL4_Q, _HSI_KER, _CSI_KER, _HSE_KER
|
|
};
|
|
|
|
-static const uint8_t i2c46_parents[] = {_PCLK5, _PLL3_Q, _HSI_KER, _CSI_KER};
|
|
-static const uint8_t uart6_parents[] = {_PCLK2, _PLL4_Q, _HSI_KER, _CSI_KER,
|
|
- _HSE_KER};
|
|
-static const uint8_t uart24_parents[] = {_PCLK1, _PLL4_Q, _HSI_KER, _CSI_KER,
|
|
- _HSE_KER};
|
|
-static const uint8_t uart35_parents[] = {_PCLK1, _PLL4_Q, _HSI_KER, _CSI_KER,
|
|
- _HSE_KER};
|
|
-static const uint8_t uart78_parents[] = {_PCLK1, _PLL4_Q, _HSI_KER, _CSI_KER,
|
|
- _HSE_KER};
|
|
-static const uint8_t sdmmc12_parents[] = {_HCLK6, _PLL3_R, _PLL4_P, _HSI_KER};
|
|
-static const uint8_t sdmmc3_parents[] = {_HCLK2, _PLL3_R, _PLL4_P, _HSI_KER};
|
|
-static const uint8_t qspi_parents[] = {_ACLK, _PLL3_R, _PLL4_P, _CK_PER};
|
|
-static const uint8_t fmc_parents[] = {_ACLK, _PLL3_R, _PLL4_P, _CK_PER};
|
|
-static const uint8_t usbphy_parents[] = {_HSE_KER, _PLL4_R, _HSE_KER_DIV2};
|
|
-static const uint8_t usbo_parents[] = {_PLL4_R, _USB_PHY_48};
|
|
-static const uint8_t stgen_parents[] = {_HSI_KER, _HSE_KER};
|
|
+static const uint8_t uart234578_parents[] = {
|
|
+ _PCLK1, _PLL4_Q, _HSI_KER, _CSI_KER, _HSE_KER
|
|
+};
|
|
+
|
|
+static const uint8_t sdmmc12_parents[] = {
|
|
+ _HCLK6, _PLL3_R, _PLL4_P, _HSI_KER
|
|
+};
|
|
+
|
|
+static const uint8_t sdmmc3_parents[] = {
|
|
+ _HCLK2, _PLL3_R, _PLL4_P, _HSI_KER
|
|
+};
|
|
+
|
|
+static const uint8_t qspi_parents[] = {
|
|
+ _ACLK, _PLL3_R, _PLL4_P, _CK_PER
|
|
+};
|
|
+
|
|
+static const uint8_t fmc_parents[] = {
|
|
+ _ACLK, _PLL3_R, _PLL4_P, _CK_PER
|
|
+};
|
|
+
|
|
+static const uint8_t ass_parents[] = {
|
|
+ _HSI, _HSE, _PLL2
|
|
+};
|
|
+
|
|
+static const uint8_t mss_parents[] = {
|
|
+ _HSI, _HSE, _CSI, _PLL3
|
|
+};
|
|
+
|
|
+static const uint8_t usbphy_parents[] = {
|
|
+ _HSE_KER, _PLL4_R, _HSE_KER_DIV2
|
|
+};
|
|
+
|
|
+static const uint8_t usbo_parents[] = {
|
|
+ _PLL4_R, _USB_PHY_48
|
|
+};
|
|
|
|
static const struct stm32mp1_clk_sel stm32mp1_clk_sel[_PARENT_SEL_NB] = {
|
|
- STM32MP1_CLK_PARENT(_I2C46_SEL, RCC_I2C46CKSELR, 0, 0x7, i2c46_parents),
|
|
- STM32MP1_CLK_PARENT(_UART6_SEL, RCC_UART6CKSELR, 0, 0x7, uart6_parents),
|
|
- STM32MP1_CLK_PARENT(_UART24_SEL, RCC_UART24CKSELR, 0, 0x7,
|
|
- uart24_parents),
|
|
- STM32MP1_CLK_PARENT(_UART35_SEL, RCC_UART35CKSELR, 0, 0x7,
|
|
- uart35_parents),
|
|
- STM32MP1_CLK_PARENT(_UART78_SEL, RCC_UART78CKSELR, 0, 0x7,
|
|
- uart78_parents),
|
|
- STM32MP1_CLK_PARENT(_SDMMC12_SEL, RCC_SDMMC12CKSELR, 0, 0x7,
|
|
- sdmmc12_parents),
|
|
- STM32MP1_CLK_PARENT(_SDMMC3_SEL, RCC_SDMMC3CKSELR, 0, 0x7,
|
|
- sdmmc3_parents),
|
|
- STM32MP1_CLK_PARENT(_QSPI_SEL, RCC_QSPICKSELR, 0, 0xf, qspi_parents),
|
|
- STM32MP1_CLK_PARENT(_FMC_SEL, RCC_FMCCKSELR, 0, 0xf, fmc_parents),
|
|
- STM32MP1_CLK_PARENT(_USBPHY_SEL, RCC_USBCKSELR, 0, 0x3, usbphy_parents),
|
|
- STM32MP1_CLK_PARENT(_USBO_SEL, RCC_USBCKSELR, 4, 0x1, usbo_parents),
|
|
- STM32MP1_CLK_PARENT(_STGEN_SEL, RCC_STGENCKSELR, 0, 0x3, stgen_parents),
|
|
+ _CLK_PARENT(_I2C12_SEL, RCC_I2C12CKSELR, 0, 0x7, i2c12_parents),
|
|
+ _CLK_PARENT(_I2C35_SEL, RCC_I2C35CKSELR, 0, 0x7, i2c35_parents),
|
|
+ _CLK_PARENT(_STGEN_SEL, RCC_STGENCKSELR, 0, 0x3, stgen_parents),
|
|
+ _CLK_PARENT(_I2C46_SEL, RCC_I2C46CKSELR, 0, 0x7, i2c46_parents),
|
|
+ _CLK_PARENT(_SPI6_SEL, RCC_SPI6CKSELR, 0, 0x7, spi6_parents),
|
|
+ _CLK_PARENT(_USART1_SEL, RCC_UART1CKSELR, 0, 0x7, usart1_parents),
|
|
+ _CLK_PARENT(_RNG1_SEL, RCC_RNG1CKSELR, 0, 0x3, rng1_parents),
|
|
+ _CLK_PARENT(_UART6_SEL, RCC_UART6CKSELR, 0, 0x7, uart6_parents),
|
|
+ _CLK_PARENT(_UART24_SEL, RCC_UART24CKSELR, 0, 0x7, uart234578_parents),
|
|
+ _CLK_PARENT(_UART35_SEL, RCC_UART35CKSELR, 0, 0x7, uart234578_parents),
|
|
+ _CLK_PARENT(_UART78_SEL, RCC_UART78CKSELR, 0, 0x7, uart234578_parents),
|
|
+ _CLK_PARENT(_SDMMC12_SEL, RCC_SDMMC12CKSELR, 0, 0x7, sdmmc12_parents),
|
|
+ _CLK_PARENT(_SDMMC3_SEL, RCC_SDMMC3CKSELR, 0, 0x7, sdmmc3_parents),
|
|
+ _CLK_PARENT(_QSPI_SEL, RCC_QSPICKSELR, 0, 0xf, qspi_parents),
|
|
+ _CLK_PARENT(_FMC_SEL, RCC_FMCCKSELR, 0, 0xf, fmc_parents),
|
|
+ _CLK_PARENT(_ASS_SEL, RCC_ASSCKSELR, 0, 0x3, ass_parents),
|
|
+ _CLK_PARENT(_MSS_SEL, RCC_MSSCKSELR, 0, 0x3, mss_parents),
|
|
+ _CLK_PARENT(_USBPHY_SEL, RCC_USBCKSELR, 0, 0x3, usbphy_parents),
|
|
+ _CLK_PARENT(_USBO_SEL, RCC_USBCKSELR, 4, 0x1, usbo_parents),
|
|
};
|
|
|
|
/* Define characteristic of PLL according type */
|
|
@@ -411,29 +502,33 @@ static const struct stm32mp1_pll stm32mp1_pll[PLL_TYPE_NB] = {
|
|
static const uint8_t pllncfgr2[_DIV_NB] = {
|
|
[_DIV_P] = RCC_PLLNCFGR2_DIVP_SHIFT,
|
|
[_DIV_Q] = RCC_PLLNCFGR2_DIVQ_SHIFT,
|
|
- [_DIV_R] = RCC_PLLNCFGR2_DIVR_SHIFT
|
|
+ [_DIV_R] = RCC_PLLNCFGR2_DIVR_SHIFT,
|
|
};
|
|
|
|
static const struct stm32mp1_clk_pll stm32mp1_clk_pll[_PLL_NB] = {
|
|
- STM32MP1_CLK_PLL(_PLL1, PLL_1600,
|
|
- RCC_RCK12SELR, RCC_PLL1CFGR1, RCC_PLL1CFGR2,
|
|
- RCC_PLL1FRACR, RCC_PLL1CR, RCC_PLL1CSGR,
|
|
- _HSI, _HSE, _UNKNOWN_OSC_ID, _UNKNOWN_OSC_ID),
|
|
- STM32MP1_CLK_PLL(_PLL2, PLL_1600,
|
|
- RCC_RCK12SELR, RCC_PLL2CFGR1, RCC_PLL2CFGR2,
|
|
- RCC_PLL2FRACR, RCC_PLL2CR, RCC_PLL2CSGR,
|
|
- _HSI, _HSE, _UNKNOWN_OSC_ID, _UNKNOWN_OSC_ID),
|
|
- STM32MP1_CLK_PLL(_PLL3, PLL_800,
|
|
- RCC_RCK3SELR, RCC_PLL3CFGR1, RCC_PLL3CFGR2,
|
|
- RCC_PLL3FRACR, RCC_PLL3CR, RCC_PLL3CSGR,
|
|
- _HSI, _HSE, _CSI, _UNKNOWN_OSC_ID),
|
|
- STM32MP1_CLK_PLL(_PLL4, PLL_800,
|
|
- RCC_RCK4SELR, RCC_PLL4CFGR1, RCC_PLL4CFGR2,
|
|
- RCC_PLL4FRACR, RCC_PLL4CR, RCC_PLL4CSGR,
|
|
- _HSI, _HSE, _CSI, _I2S_CKIN),
|
|
+ _CLK_PLL(_PLL1, PLL_1600,
|
|
+ RCC_RCK12SELR, RCC_PLL1CFGR1, RCC_PLL1CFGR2,
|
|
+ RCC_PLL1FRACR, RCC_PLL1CR, RCC_PLL1CSGR,
|
|
+ _HSI, _HSE, _UNKNOWN_OSC_ID, _UNKNOWN_OSC_ID),
|
|
+ _CLK_PLL(_PLL2, PLL_1600,
|
|
+ RCC_RCK12SELR, RCC_PLL2CFGR1, RCC_PLL2CFGR2,
|
|
+ RCC_PLL2FRACR, RCC_PLL2CR, RCC_PLL2CSGR,
|
|
+ _HSI, _HSE, _UNKNOWN_OSC_ID, _UNKNOWN_OSC_ID),
|
|
+ _CLK_PLL(_PLL3, PLL_800,
|
|
+ RCC_RCK3SELR, RCC_PLL3CFGR1, RCC_PLL3CFGR2,
|
|
+ RCC_PLL3FRACR, RCC_PLL3CR, RCC_PLL3CSGR,
|
|
+ _HSI, _HSE, _CSI, _UNKNOWN_OSC_ID),
|
|
+ _CLK_PLL(_PLL4, PLL_800,
|
|
+ RCC_RCK4SELR, RCC_PLL4CFGR1, RCC_PLL4CFGR2,
|
|
+ RCC_PLL4FRACR, RCC_PLL4CR, RCC_PLL4CSGR,
|
|
+ _HSI, _HSE, _CSI, _I2S_CKIN),
|
|
};
|
|
|
|
/* Prescaler table lookups for clock computation */
|
|
+/* div = /1 /2 /4 /8 / 16 /64 /128 /512 */
|
|
+static const uint8_t stm32mp1_mcu_div[16] = {
|
|
+ 0, 1, 2, 3, 4, 6, 7, 8, 9, 9, 9, 9, 9, 9, 9, 9
|
|
+};
|
|
|
|
/* div = /1 /2 /4 /8 /16 : same divider for PMU and APBX */
|
|
#define stm32mp1_mpu_div stm32mp1_mpu_apbx_div
|
|
@@ -447,33 +542,210 @@ static const uint8_t stm32mp1_axi_div[8] = {
|
|
1, 2, 3, 4, 4, 4, 4, 4
|
|
};
|
|
|
|
-static const struct stm32mp1_clk_data stm32mp1_data = {
|
|
- .gate = stm32mp1_clk_gate,
|
|
- .sel = stm32mp1_clk_sel,
|
|
- .pll = stm32mp1_clk_pll,
|
|
- .nb_gate = ARRAY_SIZE(stm32mp1_clk_gate),
|
|
+#if LOG_LEVEL >= LOG_LEVEL_VERBOSE
|
|
+static const char * const stm32mp1_clk_parent_name[_PARENT_NB] __unused = {
|
|
+ [_HSI] = "HSI",
|
|
+ [_HSE] = "HSE",
|
|
+ [_CSI] = "CSI",
|
|
+ [_LSI] = "LSI",
|
|
+ [_LSE] = "LSE",
|
|
+ [_I2S_CKIN] = "I2S_CKIN",
|
|
+ [_HSI_KER] = "HSI_KER",
|
|
+ [_HSE_KER] = "HSE_KER",
|
|
+ [_HSE_KER_DIV2] = "HSE_KER_DIV2",
|
|
+ [_CSI_KER] = "CSI_KER",
|
|
+ [_PLL1_P] = "PLL1_P",
|
|
+ [_PLL1_Q] = "PLL1_Q",
|
|
+ [_PLL1_R] = "PLL1_R",
|
|
+ [_PLL2_P] = "PLL2_P",
|
|
+ [_PLL2_Q] = "PLL2_Q",
|
|
+ [_PLL2_R] = "PLL2_R",
|
|
+ [_PLL3_P] = "PLL3_P",
|
|
+ [_PLL3_Q] = "PLL3_Q",
|
|
+ [_PLL3_R] = "PLL3_R",
|
|
+ [_PLL4_P] = "PLL4_P",
|
|
+ [_PLL4_Q] = "PLL4_Q",
|
|
+ [_PLL4_R] = "PLL4_R",
|
|
+ [_ACLK] = "ACLK",
|
|
+ [_PCLK1] = "PCLK1",
|
|
+ [_PCLK2] = "PCLK2",
|
|
+ [_PCLK3] = "PCLK3",
|
|
+ [_PCLK4] = "PCLK4",
|
|
+ [_PCLK5] = "PCLK5",
|
|
+ [_HCLK6] = "KCLK6",
|
|
+ [_HCLK2] = "HCLK2",
|
|
+ [_CK_PER] = "CK_PER",
|
|
+ [_CK_MPU] = "CK_MPU",
|
|
+ [_CK_MCU] = "CK_MCU",
|
|
+ [_USB_PHY_48] = "USB_PHY_48",
|
|
+};
|
|
+
|
|
+static const char *
|
|
+const stm32mp1_clk_parent_sel_name[_PARENT_SEL_NB] __unused = {
|
|
+ [_I2C12_SEL] = "I2C12",
|
|
+ [_I2C35_SEL] = "I2C35",
|
|
+ [_STGEN_SEL] = "STGEN",
|
|
+ [_I2C46_SEL] = "I2C46",
|
|
+ [_SPI6_SEL] = "SPI6",
|
|
+ [_USART1_SEL] = "USART1",
|
|
+ [_RNG1_SEL] = "RNG1",
|
|
+ [_UART6_SEL] = "UART6",
|
|
+ [_UART24_SEL] = "UART24",
|
|
+ [_UART35_SEL] = "UART35",
|
|
+ [_UART78_SEL] = "UART78",
|
|
+ [_SDMMC12_SEL] = "SDMMC12",
|
|
+ [_SDMMC3_SEL] = "SDMMC3",
|
|
+ [_QSPI_SEL] = "QSPI",
|
|
+ [_FMC_SEL] = "FMC",
|
|
+ [_ASS_SEL] = "ASS",
|
|
+ [_MSS_SEL] = "MSS",
|
|
+ [_USBPHY_SEL] = "USBPHY",
|
|
+ [_USBO_SEL] = "USBO",
|
|
+};
|
|
+#endif
|
|
+
|
|
+/* RCC clock device driver private */
|
|
+static unsigned long stm32mp1_osc[NB_OSC];
|
|
+static struct spinlock reg_lock;
|
|
+static unsigned int gate_refcounts[NB_GATES];
|
|
+static struct spinlock refcount_lock;
|
|
+
|
|
+static const struct stm32mp1_clk_gate *gate_ref(unsigned int idx)
|
|
+{
|
|
+ return &stm32mp1_clk_gate[idx];
|
|
+}
|
|
+
|
|
+static const struct stm32mp1_clk_sel *clk_sel_ref(unsigned int idx)
|
|
+{
|
|
+ return &stm32mp1_clk_sel[idx];
|
|
+}
|
|
+
|
|
+static const struct stm32mp1_clk_pll *pll_ref(unsigned int idx)
|
|
+{
|
|
+ return &stm32mp1_clk_pll[idx];
|
|
+}
|
|
+
|
|
+#if defined(IMAGE_BL32)
|
|
+/* List of forbiden values for hsi */
|
|
+static uint16_t fbv_hsi[] = { 512, 480, 448, 416, 384, 352, 320, 288, 256, 224,
|
|
+ 192, 160, 128, 96, 64, 32, 0 };
|
|
+static uint16_t fbv_csi[] = { 256, 240, 224, 208, 192, 176, 160, 144, 128, 112,
|
|
+ 96, 80, 64, 48, 32, 16, 0 };
|
|
+
|
|
+static void hsi_set_trim(unsigned int cal);
|
|
+static unsigned int hsi_get_trimed_cal(void);
|
|
+static void csi_set_trim(unsigned int cal);
|
|
+static unsigned int csi_get_trimed_cal(void);
|
|
+
|
|
+static struct stm32mp1_clk_cal stm32mp1_clk_cal_hsi = {
|
|
+ .fbv = fbv_hsi,
|
|
+ .trim_max = 63,
|
|
+ .trim_min = -64,
|
|
+ .ref_freq = 0,
|
|
+ .freq_margin = 1,
|
|
+ .set_trim = hsi_set_trim,
|
|
+ .get_trim = hsi_get_trimed_cal,
|
|
+};
|
|
+
|
|
+static struct stm32mp1_clk_cal stm32mp1_clk_cal_csi = {
|
|
+ .fbv = fbv_csi,
|
|
+ .trim_max = 15,
|
|
+ .trim_min = -16,
|
|
+ .ref_freq = 0,
|
|
+ .freq_margin = 2,
|
|
+ .set_trim = csi_set_trim,
|
|
+ .get_trim = csi_get_trimed_cal,
|
|
};
|
|
|
|
-static struct stm32mp1_clk_priv stm32mp1_clk_priv_data;
|
|
+static uint32_t timer_val;
|
|
+#endif
|
|
+
|
|
+static int stm32mp1_lock_available(void)
|
|
+{
|
|
+ /* The spinlocks are used only when MMU is enabled */
|
|
+ return (read_sctlr() & SCTLR_M_BIT) && (read_sctlr() & SCTLR_C_BIT);
|
|
+}
|
|
+
|
|
+static void stm32mp1_clk_lock(struct spinlock *lock)
|
|
+{
|
|
+ if (stm32mp1_lock_available() == 0U) {
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ /* Assume interrupts are masked */
|
|
+ spin_lock(lock);
|
|
+}
|
|
+
|
|
+static void stm32mp1_clk_unlock(struct spinlock *lock)
|
|
+{
|
|
+ if (stm32mp1_lock_available() == 0U) {
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ spin_unlock(lock);
|
|
+}
|
|
+
|
|
+bool stm32mp1_rcc_is_secure(void)
|
|
+{
|
|
+ uintptr_t rcc_base = stm32mp_rcc_base();
|
|
+
|
|
+ return (mmio_read_32(rcc_base + RCC_TZCR) & RCC_TZCR_TZEN) != 0;
|
|
+}
|
|
+
|
|
+bool stm32mp1_rcc_is_mckprot(void)
|
|
+{
|
|
+ uintptr_t rcc_base = stm32mp_rcc_base();
|
|
+
|
|
+ return (mmio_read_32(rcc_base + RCC_TZCR) & RCC_TZCR_MCKPROT) != 0;
|
|
+}
|
|
+
|
|
+void stm32mp1_clk_rcc_regs_lock(void)
|
|
+{
|
|
+ stm32mp1_clk_lock(®_lock);
|
|
+}
|
|
+
|
|
+void stm32mp1_clk_rcc_regs_unlock(void)
|
|
+{
|
|
+ stm32mp1_clk_unlock(®_lock);
|
|
+}
|
|
+
|
|
+static unsigned int get_id_from_rcc_bit(unsigned int offset, unsigned int bit)
|
|
+{
|
|
+ unsigned int idx;
|
|
+
|
|
+ for (idx = 0U; idx < NB_GATES; idx++) {
|
|
+ const struct stm32mp1_clk_gate *gate = gate_ref(idx);
|
|
|
|
-static unsigned long stm32mp1_clk_get_fixed(struct stm32mp1_clk_priv *priv,
|
|
- enum stm32mp_osc_id idx)
|
|
+ if ((offset == gate->offset) && (bit == gate->bit)) {
|
|
+ return gate->index;
|
|
+ }
|
|
+
|
|
+ if ((gate->set_clr != 0U) &&
|
|
+ (offset == (gate->offset + RCC_MP_ENCLRR_OFFSET)) &&
|
|
+ (bit == gate->bit)) {
|
|
+ return gate->index;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /* Currently only supported gated clocks */
|
|
+ return ~0U;
|
|
+}
|
|
+
|
|
+static unsigned long stm32mp1_clk_get_fixed(enum stm32mp_osc_id idx)
|
|
{
|
|
if (idx >= NB_OSC) {
|
|
return 0;
|
|
}
|
|
|
|
- return priv->osc[idx];
|
|
+ return stm32mp1_osc[idx];
|
|
}
|
|
|
|
-static int stm32mp1_clk_get_id(struct stm32mp1_clk_priv *priv, unsigned long id)
|
|
+static int stm32mp1_clk_get_gated_id(unsigned long id)
|
|
{
|
|
- const struct stm32mp1_clk_gate *gate = priv->data->gate;
|
|
- int i;
|
|
- int nb_clks = priv->data->nb_gate;
|
|
+ unsigned int i;
|
|
|
|
- for (i = 0; i < nb_clks; i++) {
|
|
- if (gate[i].index == id) {
|
|
+ for (i = 0U; i < NB_GATES; i++) {
|
|
+ if (gate_ref(i)->index == id) {
|
|
return i;
|
|
}
|
|
}
|
|
@@ -483,77 +755,70 @@ static int stm32mp1_clk_get_id(struct stm32mp1_clk_priv *priv, unsigned long id)
|
|
return -EINVAL;
|
|
}
|
|
|
|
-static enum stm32mp1_parent_sel
|
|
-stm32mp1_clk_get_sel(struct stm32mp1_clk_priv *priv, int i)
|
|
+static enum stm32mp1_parent_sel stm32mp1_clk_get_sel(int i)
|
|
{
|
|
- const struct stm32mp1_clk_gate *gate = priv->data->gate;
|
|
-
|
|
- return gate[i].sel;
|
|
+ return (enum stm32mp1_parent_sel)(gate_ref(i)->sel);
|
|
}
|
|
|
|
-static enum stm32mp1_parent_id
|
|
-stm32mp1_clk_get_fixed_parent(struct stm32mp1_clk_priv *priv, int i)
|
|
+static enum stm32mp1_parent_id stm32mp1_clk_get_fixed_parent(int i)
|
|
{
|
|
- const struct stm32mp1_clk_gate *gate = priv->data->gate;
|
|
-
|
|
- return gate[i].fixed;
|
|
+ return (enum stm32mp1_parent_id)gate_ref(i)->fixed;
|
|
}
|
|
|
|
-static int stm32mp1_clk_get_parent(struct stm32mp1_clk_priv *priv,
|
|
- unsigned long id)
|
|
+static int stm32mp1_clk_get_parent(unsigned long id)
|
|
{
|
|
- const struct stm32mp1_clk_sel *sel = priv->data->sel;
|
|
+ const struct stm32mp1_clk_sel *sel;
|
|
uint32_t j, p_sel;
|
|
int i;
|
|
enum stm32mp1_parent_id p;
|
|
enum stm32mp1_parent_sel s;
|
|
+ uintptr_t rcc_base = stm32mp_rcc_base();
|
|
|
|
- for (j = 0; j < ARRAY_SIZE(stm32mp1_clks); j++) {
|
|
+ for (j = 0U; j < ARRAY_SIZE(stm32mp1_clks); j++) {
|
|
if (stm32mp1_clks[j][0] == id) {
|
|
return (int)stm32mp1_clks[j][1];
|
|
}
|
|
}
|
|
|
|
- i = stm32mp1_clk_get_id(priv, id);
|
|
+ i = stm32mp1_clk_get_gated_id(id);
|
|
if (i < 0) {
|
|
- return i;
|
|
+ panic();
|
|
}
|
|
|
|
- p = stm32mp1_clk_get_fixed_parent(priv, i);
|
|
+ p = stm32mp1_clk_get_fixed_parent(i);
|
|
if (p < _PARENT_NB) {
|
|
return (int)p;
|
|
}
|
|
|
|
- s = stm32mp1_clk_get_sel(priv, i);
|
|
- if (s >= _PARENT_SEL_NB) {
|
|
+ s = stm32mp1_clk_get_sel(i);
|
|
+ if (s == _UNKNOWN_SEL) {
|
|
return -EINVAL;
|
|
}
|
|
-
|
|
- p_sel = (mmio_read_32(priv->base + sel[s].offset) >> sel[s].src) &
|
|
- sel[s].msk;
|
|
-
|
|
- if (p_sel < sel[s].nb_parent) {
|
|
- return (int)sel[s].parent[p_sel];
|
|
+ if (s >= _PARENT_SEL_NB) {
|
|
+ panic();
|
|
}
|
|
|
|
- ERROR("%s: no parents defined for clk id %ld\n", __func__, id);
|
|
+ sel = clk_sel_ref(s);
|
|
+ p_sel = (mmio_read_32(rcc_base + sel->offset) >> sel->src) & sel->msk;
|
|
+ if (p_sel < sel->nb_parent) {
|
|
+#if LOG_LEVEL >= LOG_LEVEL_VERBOSE
|
|
+ VERBOSE("%s: %s clock is the parent %s of clk id %ld\n",
|
|
+ __func__,
|
|
+ stm32mp1_clk_parent_name[sel->parent[p_sel]],
|
|
+ stm32mp1_clk_parent_sel_name[s], id);
|
|
+#endif
|
|
+ return (int)sel->parent[p_sel];
|
|
+ }
|
|
|
|
return -EINVAL;
|
|
}
|
|
|
|
-static unsigned long stm32mp1_pll_get_fref_ck(struct stm32mp1_clk_priv *priv,
|
|
- enum stm32mp1_pll_id pll_id)
|
|
+static unsigned long stm32mp1_pll_get_fref(const struct stm32mp1_clk_pll *pll)
|
|
{
|
|
- const struct stm32mp1_clk_pll *pll = priv->data->pll;
|
|
- uint32_t selr, src;
|
|
- unsigned long refclk;
|
|
-
|
|
- selr = mmio_read_32(priv->base + pll[pll_id].rckxselr);
|
|
- src = selr & RCC_SELR_REFCLK_SRC_MASK;
|
|
+ uint32_t selr = mmio_read_32(stm32mp_rcc_base() + pll->rckxselr);
|
|
+ uint32_t src = selr & RCC_SELR_REFCLK_SRC_MASK;
|
|
|
|
- refclk = stm32mp1_clk_get_fixed(priv, pll[pll_id].refclk[src]);
|
|
-
|
|
- return refclk;
|
|
+ return stm32mp1_clk_get_fixed(pll->refclk[src]);
|
|
}
|
|
|
|
/*
|
|
@@ -562,20 +827,19 @@ static unsigned long stm32mp1_pll_get_fref_ck(struct stm32mp1_clk_priv *priv,
|
|
* - PLL3 & PLL4 => return VCO with Fpll_y_ck = FVCO / (DIVy + 1)
|
|
* => in all cases Fpll_y_ck = pll_get_fvco() / (DIVy + 1)
|
|
*/
|
|
-static unsigned long stm32mp1_pll_get_fvco(struct stm32mp1_clk_priv *priv,
|
|
- enum stm32mp1_pll_id pll_id)
|
|
+static unsigned long stm32mp1_pll_get_fvco(const struct stm32mp1_clk_pll *pll)
|
|
{
|
|
- const struct stm32mp1_clk_pll *pll = priv->data->pll;
|
|
unsigned long refclk, fvco;
|
|
uint32_t cfgr1, fracr, divm, divn;
|
|
+ uintptr_t rcc_base = stm32mp_rcc_base();
|
|
|
|
- cfgr1 = mmio_read_32(priv->base + pll[pll_id].pllxcfgr1);
|
|
- fracr = mmio_read_32(priv->base + pll[pll_id].pllxfracr);
|
|
+ cfgr1 = mmio_read_32(rcc_base + pll->pllxcfgr1);
|
|
+ fracr = mmio_read_32(rcc_base + pll->pllxfracr);
|
|
|
|
divm = (cfgr1 & (RCC_PLLNCFGR1_DIVM_MASK)) >> RCC_PLLNCFGR1_DIVM_SHIFT;
|
|
divn = cfgr1 & RCC_PLLNCFGR1_DIVN_MASK;
|
|
|
|
- refclk = stm32mp1_pll_get_fref_ck(priv, pll_id);
|
|
+ refclk = stm32mp1_pll_get_fref(pll);
|
|
|
|
/*
|
|
* With FRACV :
|
|
@@ -584,13 +848,13 @@ static unsigned long stm32mp1_pll_get_fvco(struct stm32mp1_clk_priv *priv,
|
|
* Fvco = Fck_ref * ((DIVN + 1) / (DIVM + 1)
|
|
*/
|
|
if ((fracr & RCC_PLLNFRACR_FRACLE) != 0U) {
|
|
- uint32_t fracv = (fracr & RCC_PLLNFRACR_FRACV_MASK)
|
|
- >> RCC_PLLNFRACR_FRACV_SHIFT;
|
|
+ uint32_t fracv = (fracr & RCC_PLLNFRACR_FRACV_MASK) >>
|
|
+ RCC_PLLNFRACR_FRACV_SHIFT;
|
|
unsigned long long numerator, denominator;
|
|
|
|
- numerator = ((unsigned long long)divn + 1U) << 13;
|
|
- numerator = (refclk * numerator) + fracv;
|
|
- denominator = ((unsigned long long)divm + 1U) << 13;
|
|
+ numerator = (((unsigned long long)divn + 1U) << 13) + fracv;
|
|
+ numerator = refclk * numerator;
|
|
+ denominator = ((unsigned long long)divm + 1U) << 13;
|
|
fvco = (unsigned long)(numerator / denominator);
|
|
} else {
|
|
fvco = (unsigned long)(refclk * (divn + 1U) / (divm + 1U));
|
|
@@ -599,11 +863,10 @@ static unsigned long stm32mp1_pll_get_fvco(struct stm32mp1_clk_priv *priv,
|
|
return fvco;
|
|
}
|
|
|
|
-static unsigned long stm32mp1_read_pll_freq(struct stm32mp1_clk_priv *priv,
|
|
- enum stm32mp1_pll_id pll_id,
|
|
+static unsigned long stm32mp1_read_pll_freq(enum stm32mp1_pll_id pll_id,
|
|
enum stm32mp1_div_id div_id)
|
|
{
|
|
- const struct stm32mp1_clk_pll *pll = priv->data->pll;
|
|
+ const struct stm32mp1_clk_pll *pll = pll_ref(pll_id);
|
|
unsigned long dfout;
|
|
uint32_t cfgr2, divy;
|
|
|
|
@@ -611,42 +874,43 @@ static unsigned long stm32mp1_read_pll_freq(struct stm32mp1_clk_priv *priv,
|
|
return 0;
|
|
}
|
|
|
|
- cfgr2 = mmio_read_32(priv->base + pll[pll_id].pllxcfgr2);
|
|
+ cfgr2 = mmio_read_32(stm32mp_rcc_base() + pll->pllxcfgr2);
|
|
divy = (cfgr2 >> pllncfgr2[div_id]) & RCC_PLLNCFGR2_DIVX_MASK;
|
|
|
|
- dfout = stm32mp1_pll_get_fvco(priv, pll_id) / (divy + 1U);
|
|
+ dfout = stm32mp1_pll_get_fvco(pll) / (divy + 1U);
|
|
+
|
|
|
|
return dfout;
|
|
}
|
|
|
|
-static unsigned long stm32mp1_clk_get(struct stm32mp1_clk_priv *priv, int p)
|
|
+static unsigned long get_clock_rate(int p)
|
|
{
|
|
uint32_t reg, clkdiv;
|
|
unsigned long clock = 0;
|
|
+ uintptr_t rcc_base = stm32mp_rcc_base();
|
|
|
|
switch (p) {
|
|
case _CK_MPU:
|
|
/* MPU sub system */
|
|
- reg = mmio_read_32(priv->base + RCC_MPCKSELR);
|
|
+ reg = mmio_read_32(rcc_base + RCC_MPCKSELR);
|
|
switch (reg & RCC_SELR_SRC_MASK) {
|
|
case RCC_MPCKSELR_HSI:
|
|
- clock = stm32mp1_clk_get_fixed(priv, _HSI);
|
|
+ clock = stm32mp1_clk_get_fixed(_HSI);
|
|
break;
|
|
case RCC_MPCKSELR_HSE:
|
|
- clock = stm32mp1_clk_get_fixed(priv, _HSE);
|
|
+ clock = stm32mp1_clk_get_fixed(_HSE);
|
|
break;
|
|
case RCC_MPCKSELR_PLL:
|
|
- clock = stm32mp1_read_pll_freq(priv, _PLL1, _DIV_P);
|
|
+ clock = stm32mp1_read_pll_freq(_PLL1, _DIV_P);
|
|
break;
|
|
case RCC_MPCKSELR_PLL_MPUDIV:
|
|
- clock = stm32mp1_read_pll_freq(priv, _PLL1, _DIV_P);
|
|
+ clock = stm32mp1_read_pll_freq(_PLL1, _DIV_P);
|
|
|
|
- reg = mmio_read_32(priv->base + RCC_MPCKDIVR);
|
|
+ reg = mmio_read_32(rcc_base + RCC_MPCKDIVR);
|
|
clkdiv = reg & RCC_MPUDIV_MASK;
|
|
if (clkdiv != 0U) {
|
|
clock /= stm32mp1_mpu_div[clkdiv];
|
|
}
|
|
-
|
|
break;
|
|
default:
|
|
break;
|
|
@@ -658,49 +922,94 @@ static unsigned long stm32mp1_clk_get(struct stm32mp1_clk_priv *priv, int p)
|
|
case _HCLK6:
|
|
case _PCLK4:
|
|
case _PCLK5:
|
|
- reg = mmio_read_32(priv->base + RCC_ASSCKSELR);
|
|
+ reg = mmio_read_32(rcc_base + RCC_ASSCKSELR);
|
|
switch (reg & RCC_SELR_SRC_MASK) {
|
|
case RCC_ASSCKSELR_HSI:
|
|
- clock = stm32mp1_clk_get_fixed(priv, _HSI);
|
|
+ clock = stm32mp1_clk_get_fixed(_HSI);
|
|
break;
|
|
case RCC_ASSCKSELR_HSE:
|
|
- clock = stm32mp1_clk_get_fixed(priv, _HSE);
|
|
+ clock = stm32mp1_clk_get_fixed(_HSE);
|
|
break;
|
|
case RCC_ASSCKSELR_PLL:
|
|
- clock = stm32mp1_read_pll_freq(priv, _PLL2, _DIV_P);
|
|
+ clock = stm32mp1_read_pll_freq(_PLL2, _DIV_P);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
/* System clock divider */
|
|
- reg = mmio_read_32(priv->base + RCC_AXIDIVR);
|
|
+ reg = mmio_read_32(rcc_base + RCC_AXIDIVR);
|
|
clock /= stm32mp1_axi_div[reg & RCC_AXIDIV_MASK];
|
|
|
|
switch (p) {
|
|
case _PCLK4:
|
|
- reg = mmio_read_32(priv->base + RCC_APB4DIVR);
|
|
+ reg = mmio_read_32(rcc_base + RCC_APB4DIVR);
|
|
clock >>= stm32mp1_apbx_div[reg & RCC_APBXDIV_MASK];
|
|
break;
|
|
case _PCLK5:
|
|
- reg = mmio_read_32(priv->base + RCC_APB5DIVR);
|
|
+ reg = mmio_read_32(rcc_base + RCC_APB5DIVR);
|
|
+ clock >>= stm32mp1_apbx_div[reg & RCC_APBXDIV_MASK];
|
|
+ break;
|
|
+ default:
|
|
+ break;
|
|
+ }
|
|
+ break;
|
|
+ /* MCU sub system */
|
|
+ case _CK_MCU:
|
|
+ case _PCLK1:
|
|
+ case _PCLK2:
|
|
+ case _PCLK3:
|
|
+ reg = mmio_read_32(rcc_base + RCC_MSSCKSELR);
|
|
+ switch (reg & RCC_SELR_SRC_MASK) {
|
|
+ case RCC_MSSCKSELR_HSI:
|
|
+ clock = stm32mp1_clk_get_fixed(_HSI);
|
|
+ break;
|
|
+ case RCC_MSSCKSELR_HSE:
|
|
+ clock = stm32mp1_clk_get_fixed(_HSE);
|
|
+ break;
|
|
+ case RCC_MSSCKSELR_CSI:
|
|
+ clock = stm32mp1_clk_get_fixed(_CSI);
|
|
+ break;
|
|
+ case RCC_MSSCKSELR_PLL:
|
|
+ clock = stm32mp1_read_pll_freq(_PLL3, _DIV_P);
|
|
+ break;
|
|
+ default:
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ /* MCU clock divider */
|
|
+ reg = mmio_read_32(rcc_base + RCC_MCUDIVR);
|
|
+ clock >>= stm32mp1_mcu_div[reg & RCC_MCUDIV_MASK];
|
|
+
|
|
+ switch (p) {
|
|
+ case _PCLK1:
|
|
+ reg = mmio_read_32(rcc_base + RCC_APB1DIVR);
|
|
clock >>= stm32mp1_apbx_div[reg & RCC_APBXDIV_MASK];
|
|
break;
|
|
+ case _PCLK2:
|
|
+ reg = mmio_read_32(rcc_base + RCC_APB2DIVR);
|
|
+ clock >>= stm32mp1_apbx_div[reg & RCC_APBXDIV_MASK];
|
|
+ break;
|
|
+ case _PCLK3:
|
|
+ reg = mmio_read_32(rcc_base + RCC_APB3DIVR);
|
|
+ clock >>= stm32mp1_apbx_div[reg & RCC_APBXDIV_MASK];
|
|
+ break;
|
|
+ case _CK_MCU:
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
case _CK_PER:
|
|
- reg = mmio_read_32(priv->base + RCC_CPERCKSELR);
|
|
+ reg = mmio_read_32(rcc_base + RCC_CPERCKSELR);
|
|
switch (reg & RCC_SELR_SRC_MASK) {
|
|
case RCC_CPERCKSELR_HSI:
|
|
- clock = stm32mp1_clk_get_fixed(priv, _HSI);
|
|
+ clock = stm32mp1_clk_get_fixed(_HSI);
|
|
break;
|
|
case RCC_CPERCKSELR_HSE:
|
|
- clock = stm32mp1_clk_get_fixed(priv, _HSE);
|
|
+ clock = stm32mp1_clk_get_fixed(_HSE);
|
|
break;
|
|
case RCC_CPERCKSELR_CSI:
|
|
- clock = stm32mp1_clk_get_fixed(priv, _CSI);
|
|
+ clock = stm32mp1_clk_get_fixed(_CSI);
|
|
break;
|
|
default:
|
|
break;
|
|
@@ -708,65 +1017,65 @@ static unsigned long stm32mp1_clk_get(struct stm32mp1_clk_priv *priv, int p)
|
|
break;
|
|
case _HSI:
|
|
case _HSI_KER:
|
|
- clock = stm32mp1_clk_get_fixed(priv, _HSI);
|
|
+ clock = stm32mp1_clk_get_fixed(_HSI);
|
|
break;
|
|
case _CSI:
|
|
case _CSI_KER:
|
|
- clock = stm32mp1_clk_get_fixed(priv, _CSI);
|
|
+ clock = stm32mp1_clk_get_fixed(_CSI);
|
|
break;
|
|
case _HSE:
|
|
case _HSE_KER:
|
|
- clock = stm32mp1_clk_get_fixed(priv, _HSE);
|
|
+ clock = stm32mp1_clk_get_fixed(_HSE);
|
|
break;
|
|
case _HSE_KER_DIV2:
|
|
- clock = stm32mp1_clk_get_fixed(priv, _HSE) >> 1;
|
|
+ clock = stm32mp1_clk_get_fixed(_HSE) >> 1;
|
|
break;
|
|
case _LSI:
|
|
- clock = stm32mp1_clk_get_fixed(priv, _LSI);
|
|
+ clock = stm32mp1_clk_get_fixed(_LSI);
|
|
break;
|
|
case _LSE:
|
|
- clock = stm32mp1_clk_get_fixed(priv, _LSE);
|
|
+ clock = stm32mp1_clk_get_fixed(_LSE);
|
|
break;
|
|
/* PLL */
|
|
case _PLL1_P:
|
|
- clock = stm32mp1_read_pll_freq(priv, _PLL1, _DIV_P);
|
|
+ clock = stm32mp1_read_pll_freq(_PLL1, _DIV_P);
|
|
break;
|
|
case _PLL1_Q:
|
|
- clock = stm32mp1_read_pll_freq(priv, _PLL1, _DIV_Q);
|
|
+ clock = stm32mp1_read_pll_freq(_PLL1, _DIV_Q);
|
|
break;
|
|
case _PLL1_R:
|
|
- clock = stm32mp1_read_pll_freq(priv, _PLL1, _DIV_R);
|
|
+ clock = stm32mp1_read_pll_freq(_PLL1, _DIV_R);
|
|
break;
|
|
case _PLL2_P:
|
|
- clock = stm32mp1_read_pll_freq(priv, _PLL2, _DIV_P);
|
|
+ clock = stm32mp1_read_pll_freq(_PLL2, _DIV_P);
|
|
break;
|
|
case _PLL2_Q:
|
|
- clock = stm32mp1_read_pll_freq(priv, _PLL2, _DIV_Q);
|
|
+ clock = stm32mp1_read_pll_freq(_PLL2, _DIV_Q);
|
|
break;
|
|
case _PLL2_R:
|
|
- clock = stm32mp1_read_pll_freq(priv, _PLL2, _DIV_R);
|
|
+ clock = stm32mp1_read_pll_freq(_PLL2, _DIV_R);
|
|
break;
|
|
case _PLL3_P:
|
|
- clock = stm32mp1_read_pll_freq(priv, _PLL3, _DIV_P);
|
|
+ clock = stm32mp1_read_pll_freq(_PLL3, _DIV_P);
|
|
break;
|
|
case _PLL3_Q:
|
|
- clock = stm32mp1_read_pll_freq(priv, _PLL3, _DIV_Q);
|
|
+ clock = stm32mp1_read_pll_freq(_PLL3, _DIV_Q);
|
|
break;
|
|
case _PLL3_R:
|
|
- clock = stm32mp1_read_pll_freq(priv, _PLL3, _DIV_R);
|
|
+ clock = stm32mp1_read_pll_freq(_PLL3, _DIV_R);
|
|
break;
|
|
case _PLL4_P:
|
|
- clock = stm32mp1_read_pll_freq(priv, _PLL4, _DIV_P);
|
|
+ clock = stm32mp1_read_pll_freq(_PLL4, _DIV_P);
|
|
break;
|
|
case _PLL4_Q:
|
|
- clock = stm32mp1_read_pll_freq(priv, _PLL4, _DIV_Q);
|
|
+ clock = stm32mp1_read_pll_freq(_PLL4, _DIV_Q);
|
|
break;
|
|
case _PLL4_R:
|
|
- clock = stm32mp1_read_pll_freq(priv, _PLL4, _DIV_R);
|
|
+ clock = stm32mp1_read_pll_freq(_PLL4, _DIV_R);
|
|
break;
|
|
/* Other */
|
|
case _USB_PHY_48:
|
|
- clock = stm32mp1_clk_get_fixed(priv, _USB_PHY_48);
|
|
+ clock = USB_PHY_48_MHZ;
|
|
break;
|
|
default:
|
|
break;
|
|
@@ -775,112 +1084,155 @@ static unsigned long stm32mp1_clk_get(struct stm32mp1_clk_priv *priv, int p)
|
|
return clock;
|
|
}
|
|
|
|
-bool stm32mp1_clk_is_enabled(unsigned long id)
|
|
+static void __clk_enable(struct stm32mp1_clk_gate const *gate)
|
|
+{
|
|
+ uintptr_t rcc_base = stm32mp_rcc_base();
|
|
+
|
|
+ if (gate->set_clr != 0U) {
|
|
+ mmio_write_32(rcc_base + gate->offset, BIT(gate->bit));
|
|
+ } else {
|
|
+ stm32mp_mmio_setbits_32_shregs(rcc_base + gate->offset,
|
|
+ BIT(gate->bit));
|
|
+ }
|
|
+
|
|
+ VERBOSE("Clock %d has been enabled", gate->index);
|
|
+}
|
|
+
|
|
+static void __clk_disable(struct stm32mp1_clk_gate const *gate)
|
|
+{
|
|
+ uintptr_t rcc_base = stm32mp_rcc_base();
|
|
+
|
|
+ if (gate->set_clr != 0U) {
|
|
+ mmio_write_32(rcc_base + gate->offset + RCC_MP_ENCLRR_OFFSET,
|
|
+ BIT(gate->bit));
|
|
+ } else {
|
|
+ stm32mp_mmio_clrbits_32_shregs(rcc_base + gate->offset,
|
|
+ BIT(gate->bit));
|
|
+ }
|
|
+
|
|
+ VERBOSE("Clock %d has been disabled", gate->index);
|
|
+}
|
|
+
|
|
+static bool __clk_is_enabled(struct stm32mp1_clk_gate const *gate)
|
|
+{
|
|
+ uintptr_t rcc_base = stm32mp_rcc_base();
|
|
+
|
|
+ return mmio_read_32(rcc_base + gate->offset) & BIT(gate->bit);
|
|
+}
|
|
+
|
|
+unsigned int stm32mp1_clk_get_refcount(unsigned long id)
|
|
{
|
|
- struct stm32mp1_clk_priv *priv = &stm32mp1_clk_priv_data;
|
|
- const struct stm32mp1_clk_gate *gate = priv->data->gate;
|
|
- int i = stm32mp1_clk_get_id(priv, id);
|
|
+ int i = stm32mp1_clk_get_gated_id(id);
|
|
|
|
if (i < 0) {
|
|
- return false;
|
|
+ panic();
|
|
}
|
|
|
|
- return ((mmio_read_32(priv->base + gate[i].offset) &
|
|
- BIT(gate[i].bit)) != 0U);
|
|
+ return gate_refcounts[i];
|
|
}
|
|
|
|
-int stm32mp1_clk_enable(unsigned long id)
|
|
+void __stm32mp1_clk_enable(unsigned long id, bool secure)
|
|
{
|
|
- struct stm32mp1_clk_priv *priv = &stm32mp1_clk_priv_data;
|
|
- const struct stm32mp1_clk_gate *gate = priv->data->gate;
|
|
- int i = stm32mp1_clk_get_id(priv, id);
|
|
+ const struct stm32mp1_clk_gate *gate;
|
|
+ int i = stm32mp1_clk_get_gated_id(id);
|
|
+ unsigned int *refcnt;
|
|
|
|
if (i < 0) {
|
|
- return i;
|
|
+ ERROR("Clock %d can't be enabled\n", (uint32_t)id);
|
|
+ panic();
|
|
}
|
|
|
|
- if (gate[i].set_clr != 0U) {
|
|
- mmio_write_32(priv->base + gate[i].offset, BIT(gate[i].bit));
|
|
- } else {
|
|
- mmio_setbits_32(priv->base + gate[i].offset, BIT(gate[i].bit));
|
|
+ gate = gate_ref(i);
|
|
+ refcnt = &gate_refcounts[i];
|
|
+
|
|
+ stm32mp1_clk_lock(&refcount_lock);
|
|
+
|
|
+ if (stm32mp_incr_shrefcnt(refcnt, secure) != 0) {
|
|
+ __clk_enable(gate);
|
|
}
|
|
|
|
- return 0;
|
|
+ stm32mp1_clk_unlock(&refcount_lock);
|
|
}
|
|
|
|
-int stm32mp1_clk_disable(unsigned long id)
|
|
+void __stm32mp1_clk_disable(unsigned long id, bool secure)
|
|
{
|
|
- struct stm32mp1_clk_priv *priv = &stm32mp1_clk_priv_data;
|
|
- const struct stm32mp1_clk_gate *gate = priv->data->gate;
|
|
- int i = stm32mp1_clk_get_id(priv, id);
|
|
+ const struct stm32mp1_clk_gate *gate;
|
|
+ int i = stm32mp1_clk_get_gated_id(id);
|
|
+ unsigned int *refcnt;
|
|
|
|
if (i < 0) {
|
|
- return i;
|
|
+ ERROR("Clock %d can't be disabled\n", (uint32_t)id);
|
|
+ panic();
|
|
}
|
|
|
|
- if (gate[i].set_clr != 0U) {
|
|
- mmio_write_32(priv->base + gate[i].offset
|
|
- + RCC_MP_ENCLRR_OFFSET,
|
|
- BIT(gate[i].bit));
|
|
- } else {
|
|
- mmio_clrbits_32(priv->base + gate[i].offset, BIT(gate[i].bit));
|
|
+ gate = gate_ref(i);
|
|
+ refcnt = &gate_refcounts[i];
|
|
+
|
|
+ stm32mp1_clk_lock(&refcount_lock);
|
|
+
|
|
+ if (stm32mp_decr_shrefcnt(refcnt, secure) != 0) {
|
|
+ __clk_disable(gate);
|
|
}
|
|
|
|
- return 0;
|
|
+ stm32mp1_clk_unlock(&refcount_lock);
|
|
}
|
|
|
|
-unsigned long stm32mp1_clk_get_rate(unsigned long id)
|
|
+bool stm32mp1_clk_is_enabled(unsigned long id)
|
|
{
|
|
- struct stm32mp1_clk_priv *priv = &stm32mp1_clk_priv_data;
|
|
- int p = stm32mp1_clk_get_parent(priv, id);
|
|
- unsigned long rate;
|
|
+ int i = stm32mp1_clk_get_gated_id(id);
|
|
+
|
|
+ if (i < 0) {
|
|
+ panic();
|
|
+ }
|
|
+
|
|
+ return __clk_is_enabled(gate_ref(i));
|
|
+}
|
|
+
|
|
+unsigned long stm32mp_clk_get_rate(unsigned long id)
|
|
+{
|
|
+ int p = stm32mp1_clk_get_parent(id);
|
|
|
|
if (p < 0) {
|
|
return 0;
|
|
}
|
|
|
|
- rate = stm32mp1_clk_get(priv, p);
|
|
-
|
|
- return rate;
|
|
+ return get_clock_rate(p);
|
|
}
|
|
|
|
-static void stm32mp1_ls_osc_set(int enable, uint32_t rcc, uint32_t offset,
|
|
- uint32_t mask_on)
|
|
+static void stm32mp1_ls_osc_set(bool enable, uint32_t offset, uint32_t mask_on)
|
|
{
|
|
- uint32_t address = rcc + offset;
|
|
+ uint32_t address = stm32mp_rcc_base() + offset;
|
|
|
|
- if (enable != 0) {
|
|
+ if (enable) {
|
|
mmio_setbits_32(address, mask_on);
|
|
} else {
|
|
mmio_clrbits_32(address, mask_on);
|
|
}
|
|
}
|
|
|
|
-static void stm32mp1_hs_ocs_set(int enable, uint32_t rcc, uint32_t mask_on)
|
|
+static void stm32mp1_hs_ocs_set(bool enable, uint32_t mask_on)
|
|
{
|
|
- if (enable != 0) {
|
|
- mmio_setbits_32(rcc + RCC_OCENSETR, mask_on);
|
|
- } else {
|
|
- mmio_setbits_32(rcc + RCC_OCENCLRR, mask_on);
|
|
- }
|
|
+ uint32_t offset = enable ? RCC_OCENSETR : RCC_OCENCLRR;
|
|
+ uint32_t address = stm32mp_rcc_base() + offset;
|
|
+
|
|
+ mmio_write_32(address, mask_on);
|
|
}
|
|
|
|
-static int stm32mp1_osc_wait(int enable, uint32_t rcc, uint32_t offset,
|
|
- uint32_t mask_rdy)
|
|
+static int stm32mp1_osc_wait(bool enable, uint32_t offset, uint32_t mask_rdy)
|
|
{
|
|
- unsigned long start;
|
|
+ uint64_t start;
|
|
uint32_t mask_test;
|
|
- uint32_t address = rcc + offset;
|
|
+ uint32_t address = stm32mp_rcc_base() + offset;
|
|
|
|
- if (enable != 0) {
|
|
+ if (enable) {
|
|
mask_test = mask_rdy;
|
|
} else {
|
|
mask_test = 0;
|
|
}
|
|
|
|
- start = get_timer(0);
|
|
+ start = timeout_start();
|
|
while ((mmio_read_32(address) & mask_rdy) != mask_test) {
|
|
- if (get_timer(start) > OSCRDY_TIMEOUT) {
|
|
+ if (timeout_elapsed(start, OSCRDY_TIMEOUT)) {
|
|
ERROR("OSC %x @ %x timeout for enable=%d : 0x%x\n",
|
|
mask_rdy, address, enable, mmio_read_32(address));
|
|
return -ETIMEDOUT;
|
|
@@ -890,19 +1242,24 @@ static int stm32mp1_osc_wait(int enable, uint32_t rcc, uint32_t offset,
|
|
return 0;
|
|
}
|
|
|
|
-static void stm32mp1_lse_enable(uint32_t rcc, bool bypass, uint32_t lsedrv)
|
|
+static void stm32mp1_lse_enable(bool bypass, bool digbyp, uint32_t lsedrv)
|
|
{
|
|
uint32_t value;
|
|
+ uintptr_t rcc_base = stm32mp_rcc_base();
|
|
+
|
|
+ if (digbyp) {
|
|
+ mmio_setbits_32(rcc_base + RCC_BDCR, RCC_BDCR_DIGBYP);
|
|
+ }
|
|
|
|
- if (bypass) {
|
|
- mmio_setbits_32(rcc + RCC_BDCR, RCC_BDCR_LSEBYP);
|
|
+ if (bypass || digbyp) {
|
|
+ mmio_setbits_32(rcc_base + RCC_BDCR, RCC_BDCR_LSEBYP);
|
|
}
|
|
|
|
/*
|
|
* Warning: not recommended to switch directly from "high drive"
|
|
* to "medium low drive", and vice-versa.
|
|
*/
|
|
- value = (mmio_read_32(rcc + RCC_BDCR) & RCC_BDCR_LSEDRV_MASK) >>
|
|
+ value = (mmio_read_32(rcc_base + RCC_BDCR) & RCC_BDCR_LSEDRV_MASK) >>
|
|
RCC_BDCR_LSEDRV_SHIFT;
|
|
|
|
while (value != lsedrv) {
|
|
@@ -912,77 +1269,85 @@ static void stm32mp1_lse_enable(uint32_t rcc, bool bypass, uint32_t lsedrv)
|
|
value++;
|
|
}
|
|
|
|
- mmio_clrsetbits_32(rcc + RCC_BDCR,
|
|
+ mmio_clrsetbits_32(rcc_base + RCC_BDCR,
|
|
RCC_BDCR_LSEDRV_MASK,
|
|
value << RCC_BDCR_LSEDRV_SHIFT);
|
|
}
|
|
|
|
- stm32mp1_ls_osc_set(1, rcc, RCC_BDCR, RCC_BDCR_LSEON);
|
|
+ stm32mp1_ls_osc_set(true, RCC_BDCR, RCC_BDCR_LSEON);
|
|
}
|
|
|
|
-static void stm32mp1_lse_wait(uint32_t rcc)
|
|
+static void stm32mp1_lse_wait(void)
|
|
{
|
|
- if (stm32mp1_osc_wait(1, rcc, RCC_BDCR, RCC_BDCR_LSERDY) != 0) {
|
|
+ if (stm32mp1_osc_wait(true, RCC_BDCR, RCC_BDCR_LSERDY) != 0) {
|
|
VERBOSE("%s: failed\n", __func__);
|
|
}
|
|
}
|
|
|
|
-static void stm32mp1_lsi_set(uint32_t rcc, int enable)
|
|
+static void stm32mp1_lsi_set(bool enable)
|
|
{
|
|
- stm32mp1_ls_osc_set(enable, rcc, RCC_RDLSICR, RCC_RDLSICR_LSION);
|
|
- if (stm32mp1_osc_wait(enable, rcc, RCC_RDLSICR, RCC_RDLSICR_LSIRDY) !=
|
|
+ stm32mp1_ls_osc_set(enable, RCC_RDLSICR, RCC_RDLSICR_LSION);
|
|
+
|
|
+ if (stm32mp1_osc_wait(enable, RCC_RDLSICR, RCC_RDLSICR_LSIRDY) !=
|
|
0) {
|
|
VERBOSE("%s: failed\n", __func__);
|
|
}
|
|
}
|
|
|
|
-static void stm32mp1_hse_enable(uint32_t rcc, bool bypass, bool css)
|
|
+static void stm32mp1_hse_enable(bool bypass, bool digbyp, bool css)
|
|
{
|
|
- if (bypass) {
|
|
- mmio_setbits_32(rcc + RCC_OCENSETR, RCC_OCENR_HSEBYP);
|
|
+ uintptr_t rcc_base = stm32mp_rcc_base();
|
|
+
|
|
+ if (digbyp) {
|
|
+ mmio_write_32(rcc_base + RCC_OCENSETR, RCC_OCENR_DIGBYP);
|
|
+ }
|
|
+
|
|
+ if (bypass || digbyp) {
|
|
+ mmio_write_32(rcc_base + RCC_OCENSETR, RCC_OCENR_HSEBYP);
|
|
}
|
|
|
|
- stm32mp1_hs_ocs_set(1, rcc, RCC_OCENR_HSEON);
|
|
- if (stm32mp1_osc_wait(1, rcc, RCC_OCRDYR, RCC_OCRDYR_HSERDY) !=
|
|
+ stm32mp1_hs_ocs_set(true, RCC_OCENR_HSEON);
|
|
+ if (stm32mp1_osc_wait(true, RCC_OCRDYR, RCC_OCRDYR_HSERDY) !=
|
|
0) {
|
|
VERBOSE("%s: failed\n", __func__);
|
|
}
|
|
|
|
if (css) {
|
|
- mmio_setbits_32(rcc + RCC_OCENSETR, RCC_OCENR_HSECSSON);
|
|
+ mmio_write_32(rcc_base + RCC_OCENSETR, RCC_OCENR_HSECSSON);
|
|
}
|
|
}
|
|
|
|
-static void stm32mp1_csi_set(uint32_t rcc, int enable)
|
|
+static void stm32mp1_csi_set(bool enable)
|
|
{
|
|
- stm32mp1_ls_osc_set(enable, rcc, RCC_OCENSETR, RCC_OCENR_CSION);
|
|
- if (stm32mp1_osc_wait(enable, rcc, RCC_OCRDYR, RCC_OCRDYR_CSIRDY) !=
|
|
+ stm32mp1_hs_ocs_set(enable, RCC_OCENR_CSION);
|
|
+ if (stm32mp1_osc_wait(enable, RCC_OCRDYR, RCC_OCRDYR_CSIRDY) !=
|
|
0) {
|
|
VERBOSE("%s: failed\n", __func__);
|
|
}
|
|
}
|
|
|
|
-static void stm32mp1_hsi_set(uint32_t rcc, int enable)
|
|
+static void stm32mp1_hsi_set(bool enable)
|
|
{
|
|
- stm32mp1_hs_ocs_set(enable, rcc, RCC_OCENR_HSION);
|
|
- if (stm32mp1_osc_wait(enable, rcc, RCC_OCRDYR, RCC_OCRDYR_HSIRDY) !=
|
|
+ stm32mp1_hs_ocs_set(enable, RCC_OCENR_HSION);
|
|
+ if (stm32mp1_osc_wait(enable, RCC_OCRDYR, RCC_OCRDYR_HSIRDY) !=
|
|
0) {
|
|
VERBOSE("%s: failed\n", __func__);
|
|
}
|
|
}
|
|
|
|
-static int stm32mp1_set_hsidiv(uint32_t rcc, uint8_t hsidiv)
|
|
+static int stm32mp1_set_hsidiv(uint8_t hsidiv)
|
|
{
|
|
- unsigned long start;
|
|
- uint32_t address = rcc + RCC_OCRDYR;
|
|
+ uint64_t start;
|
|
+ uintptr_t rcc_base = stm32mp_rcc_base();
|
|
+ uint32_t address = rcc_base + RCC_OCRDYR;
|
|
|
|
- mmio_clrsetbits_32(rcc + RCC_HSICFGR,
|
|
+ mmio_clrsetbits_32(rcc_base + RCC_HSICFGR,
|
|
RCC_HSICFGR_HSIDIV_MASK,
|
|
RCC_HSICFGR_HSIDIV_MASK & (uint32_t)hsidiv);
|
|
|
|
- start = get_timer(0);
|
|
+ start = timeout_start();
|
|
while ((mmio_read_32(address) & RCC_OCRDYR_HSIDIVRDY) == 0U) {
|
|
- if (get_timer(start) > HSIDIV_TIMEOUT) {
|
|
+ if (timeout_elapsed(start, HSIDIV_TIMEOUT)) {
|
|
ERROR("HSIDIV failed @ 0x%x: 0x%x\n",
|
|
address, mmio_read_32(address));
|
|
return -ETIMEDOUT;
|
|
@@ -992,7 +1357,7 @@ static int stm32mp1_set_hsidiv(uint32_t rcc, uint8_t hsidiv)
|
|
return 0;
|
|
}
|
|
|
|
-static int stm32mp1_hsidiv(uint32_t rcc, unsigned long hsifreq)
|
|
+static int stm32mp1_hsidiv(unsigned long hsifreq)
|
|
{
|
|
uint8_t hsidiv;
|
|
uint32_t hsidivfreq = MAX_HSI_HZ;
|
|
@@ -1011,31 +1376,103 @@ static int stm32mp1_hsidiv(uint32_t rcc, unsigned long hsifreq)
|
|
}
|
|
|
|
if (hsidiv != 0U) {
|
|
- return stm32mp1_set_hsidiv(rcc, hsidiv);
|
|
+ return stm32mp1_set_hsidiv(hsidiv);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
-static void stm32mp1_pll_start(struct stm32mp1_clk_priv *priv,
|
|
- enum stm32mp1_pll_id pll_id)
|
|
+static bool stm32mp1_check_pll_conf(enum stm32mp1_pll_id pll_id,
|
|
+ unsigned int clksrc,
|
|
+ uint32_t *pllcfg, int plloff)
|
|
+{
|
|
+ const struct stm32mp1_clk_pll *pll = pll_ref(pll_id);
|
|
+ uintptr_t rcc_base = stm32mp_rcc_base();
|
|
+ uint32_t pllxcr = rcc_base + pll->pllxcr;
|
|
+ enum stm32mp1_plltype type = pll->plltype;
|
|
+ uint32_t address = rcc_base + (clksrc >> 4);
|
|
+ unsigned long refclk;
|
|
+ uint32_t ifrge = 0U;
|
|
+ uint32_t src, value, fracv;
|
|
+
|
|
+ /* Check PLL output */
|
|
+ if (mmio_read_32(pllxcr) != RCC_PLLNCR_PLLON) {
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ /* Check current clksrc */
|
|
+ src = mmio_read_32(address) & RCC_SELR_SRC_MASK;
|
|
+ if (src != (clksrc & RCC_SELR_SRC_MASK)) {
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ /* Check Div */
|
|
+ src = mmio_read_32(rcc_base + pll->rckxselr) &
|
|
+ RCC_SELR_REFCLK_SRC_MASK;
|
|
+
|
|
+ refclk = stm32mp1_clk_get_fixed(pll->refclk[src]) /
|
|
+ (pllcfg[PLLCFG_M] + 1U);
|
|
+
|
|
+ if ((refclk < (stm32mp1_pll[type].refclk_min * 1000000U)) ||
|
|
+ (refclk > (stm32mp1_pll[type].refclk_max * 1000000U))) {
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ if ((type == PLL_800) && (refclk >= 8000000U)) {
|
|
+ ifrge = 1U;
|
|
+ }
|
|
+
|
|
+ value = (pllcfg[PLLCFG_N] << RCC_PLLNCFGR1_DIVN_SHIFT) &
|
|
+ RCC_PLLNCFGR1_DIVN_MASK;
|
|
+ value |= (pllcfg[PLLCFG_M] << RCC_PLLNCFGR1_DIVM_SHIFT) &
|
|
+ RCC_PLLNCFGR1_DIVM_MASK;
|
|
+ value |= (ifrge << RCC_PLLNCFGR1_IFRGE_SHIFT) &
|
|
+ RCC_PLLNCFGR1_IFRGE_MASK;
|
|
+ if (mmio_read_32(rcc_base + pll->pllxcfgr1) != value) {
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ /* Fractional configuration */
|
|
+ fracv = fdt_read_uint32_default(plloff, "frac", 0);
|
|
+
|
|
+ value = fracv << RCC_PLLNFRACR_FRACV_SHIFT;
|
|
+ value |= RCC_PLLNFRACR_FRACLE;
|
|
+ if (mmio_read_32(rcc_base + pll->pllxfracr) != value) {
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ /* Output config */
|
|
+ value = (pllcfg[PLLCFG_P] << RCC_PLLNCFGR2_DIVP_SHIFT) &
|
|
+ RCC_PLLNCFGR2_DIVP_MASK;
|
|
+ value |= (pllcfg[PLLCFG_Q] << RCC_PLLNCFGR2_DIVQ_SHIFT) &
|
|
+ RCC_PLLNCFGR2_DIVQ_MASK;
|
|
+ value |= (pllcfg[PLLCFG_R] << RCC_PLLNCFGR2_DIVR_SHIFT) &
|
|
+ RCC_PLLNCFGR2_DIVR_MASK;
|
|
+ if (mmio_read_32(rcc_base + pll->pllxcfgr2) != value) {
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ return true;
|
|
+}
|
|
+
|
|
+static void stm32mp1_pll_start(enum stm32mp1_pll_id pll_id)
|
|
{
|
|
- const struct stm32mp1_clk_pll *pll = priv->data->pll;
|
|
+ const struct stm32mp1_clk_pll *pll = pll_ref(pll_id);
|
|
+ uint32_t pllxcr = stm32mp_rcc_base() + pll->pllxcr;
|
|
|
|
- mmio_write_32(priv->base + pll[pll_id].pllxcr, RCC_PLLNCR_PLLON);
|
|
+ mmio_write_32(pllxcr, RCC_PLLNCR_PLLON);
|
|
}
|
|
|
|
-static int stm32mp1_pll_output(struct stm32mp1_clk_priv *priv,
|
|
- enum stm32mp1_pll_id pll_id, uint32_t output)
|
|
+static int stm32mp1_pll_output(enum stm32mp1_pll_id pll_id, uint32_t output)
|
|
{
|
|
- const struct stm32mp1_clk_pll *pll = priv->data->pll;
|
|
- uint32_t pllxcr = priv->base + pll[pll_id].pllxcr;
|
|
- unsigned long start;
|
|
+ const struct stm32mp1_clk_pll *pll = pll_ref(pll_id);
|
|
+ uint32_t pllxcr = stm32mp_rcc_base() + pll->pllxcr;
|
|
+ uint64_t start;
|
|
|
|
- start = get_timer(0);
|
|
+ start = timeout_start();
|
|
/* Wait PLL lock */
|
|
while ((mmio_read_32(pllxcr) & RCC_PLLNCR_PLLRDY) == 0U) {
|
|
- if (get_timer(start) > PLLRDY_TIMEOUT) {
|
|
+ if (timeout_elapsed(start, PLLRDY_TIMEOUT)) {
|
|
ERROR("PLL%d start failed @ 0x%x: 0x%x\n",
|
|
pll_id, pllxcr, mmio_read_32(pllxcr));
|
|
return -ETIMEDOUT;
|
|
@@ -1048,12 +1485,11 @@ static int stm32mp1_pll_output(struct stm32mp1_clk_priv *priv,
|
|
return 0;
|
|
}
|
|
|
|
-static int stm32mp1_pll_stop(struct stm32mp1_clk_priv *priv,
|
|
- enum stm32mp1_pll_id pll_id)
|
|
+static int stm32mp1_pll_stop(enum stm32mp1_pll_id pll_id)
|
|
{
|
|
- const struct stm32mp1_clk_pll *pll = priv->data->pll;
|
|
- uint32_t pllxcr = priv->base + pll[pll_id].pllxcr;
|
|
- unsigned long start;
|
|
+ const struct stm32mp1_clk_pll *pll = pll_ref(pll_id);
|
|
+ uint32_t pllxcr = stm32mp_rcc_base() + pll->pllxcr;
|
|
+ uint64_t start;
|
|
|
|
/* Stop all output */
|
|
mmio_clrbits_32(pllxcr, RCC_PLLNCR_DIVPEN | RCC_PLLNCR_DIVQEN |
|
|
@@ -1062,10 +1498,10 @@ static int stm32mp1_pll_stop(struct stm32mp1_clk_priv *priv,
|
|
/* Stop PLL */
|
|
mmio_clrbits_32(pllxcr, RCC_PLLNCR_PLLON);
|
|
|
|
- start = get_timer(0);
|
|
+ start = timeout_start();
|
|
/* Wait PLL stopped */
|
|
while ((mmio_read_32(pllxcr) & RCC_PLLNCR_PLLRDY) != 0U) {
|
|
- if (get_timer(start) > PLLRDY_TIMEOUT) {
|
|
+ if (timeout_elapsed(start, PLLRDY_TIMEOUT)) {
|
|
ERROR("PLL%d stop failed @ 0x%x: 0x%x\n",
|
|
pll_id, pllxcr, mmio_read_32(pllxcr));
|
|
return -ETIMEDOUT;
|
|
@@ -1075,12 +1511,11 @@ static int stm32mp1_pll_stop(struct stm32mp1_clk_priv *priv,
|
|
return 0;
|
|
}
|
|
|
|
-static void stm32mp1_pll_config_output(struct stm32mp1_clk_priv *priv,
|
|
- enum stm32mp1_pll_id pll_id,
|
|
+static void stm32mp1_pll_config_output(enum stm32mp1_pll_id pll_id,
|
|
uint32_t *pllcfg)
|
|
{
|
|
- const struct stm32mp1_clk_pll *pll = priv->data->pll;
|
|
- uint32_t rcc = priv->base;
|
|
+ const struct stm32mp1_clk_pll *pll = pll_ref(pll_id);
|
|
+ uintptr_t rcc_base = stm32mp_rcc_base();
|
|
uint32_t value;
|
|
|
|
value = (pllcfg[PLLCFG_P] << RCC_PLLNCFGR2_DIVP_SHIFT) &
|
|
@@ -1089,24 +1524,23 @@ static void stm32mp1_pll_config_output(struct stm32mp1_clk_priv *priv,
|
|
RCC_PLLNCFGR2_DIVQ_MASK;
|
|
value |= (pllcfg[PLLCFG_R] << RCC_PLLNCFGR2_DIVR_SHIFT) &
|
|
RCC_PLLNCFGR2_DIVR_MASK;
|
|
- mmio_write_32(rcc + pll[pll_id].pllxcfgr2, value);
|
|
+ mmio_write_32(rcc_base + pll->pllxcfgr2, value);
|
|
}
|
|
|
|
-static int stm32mp1_pll_config(struct stm32mp1_clk_priv *priv,
|
|
- enum stm32mp1_pll_id pll_id,
|
|
+static int stm32mp1_pll_config(enum stm32mp1_pll_id pll_id,
|
|
uint32_t *pllcfg, uint32_t fracv)
|
|
{
|
|
- const struct stm32mp1_clk_pll *pll = priv->data->pll;
|
|
- uint32_t rcc = priv->base;
|
|
- enum stm32mp1_plltype type = pll[pll_id].plltype;
|
|
+ const struct stm32mp1_clk_pll *pll = pll_ref(pll_id);
|
|
+ uint32_t rcc_base = stm32mp_rcc_base();
|
|
+ enum stm32mp1_plltype type = pll->plltype;
|
|
unsigned long refclk;
|
|
uint32_t ifrge = 0;
|
|
uint32_t src, value;
|
|
|
|
- src = mmio_read_32(priv->base + pll[pll_id].rckxselr) &
|
|
+ src = mmio_read_32(rcc_base + pll->rckxselr) &
|
|
RCC_SELR_REFCLK_SRC_MASK;
|
|
|
|
- refclk = stm32mp1_clk_get_fixed(priv, pll[pll_id].refclk[src]) /
|
|
+ refclk = stm32mp1_clk_get_fixed(pll->refclk[src]) /
|
|
(pllcfg[PLLCFG_M] + 1U);
|
|
|
|
if ((refclk < (stm32mp1_pll[type].refclk_min * 1000000U)) ||
|
|
@@ -1124,28 +1558,26 @@ static int stm32mp1_pll_config(struct stm32mp1_clk_priv *priv,
|
|
RCC_PLLNCFGR1_DIVM_MASK;
|
|
value |= (ifrge << RCC_PLLNCFGR1_IFRGE_SHIFT) &
|
|
RCC_PLLNCFGR1_IFRGE_MASK;
|
|
- mmio_write_32(rcc + pll[pll_id].pllxcfgr1, value);
|
|
+ mmio_write_32(rcc_base + pll->pllxcfgr1, value);
|
|
|
|
/* Fractional configuration */
|
|
value = 0;
|
|
- mmio_write_32(rcc + pll[pll_id].pllxfracr, value);
|
|
+ mmio_write_32(rcc_base + pll->pllxfracr, value);
|
|
|
|
value = fracv << RCC_PLLNFRACR_FRACV_SHIFT;
|
|
- mmio_write_32(rcc + pll[pll_id].pllxfracr, value);
|
|
+ mmio_write_32(rcc_base + pll->pllxfracr, value);
|
|
|
|
value |= RCC_PLLNFRACR_FRACLE;
|
|
- mmio_write_32(rcc + pll[pll_id].pllxfracr, value);
|
|
+ mmio_write_32(rcc_base + pll->pllxfracr, value);
|
|
|
|
- stm32mp1_pll_config_output(priv, pll_id, pllcfg);
|
|
+ stm32mp1_pll_config_output(pll_id, pllcfg);
|
|
|
|
return 0;
|
|
}
|
|
|
|
-static void stm32mp1_pll_csg(struct stm32mp1_clk_priv *priv,
|
|
- enum stm32mp1_pll_id pll_id,
|
|
- uint32_t *csg)
|
|
+static void stm32mp1_pll_csg(enum stm32mp1_pll_id pll_id, uint32_t *csg)
|
|
{
|
|
- const struct stm32mp1_clk_pll *pll = priv->data->pll;
|
|
+ const struct stm32mp1_clk_pll *pll = pll_ref(pll_id);
|
|
uint32_t pllxcsg = 0;
|
|
|
|
pllxcsg |= (csg[PLLCSG_MOD_PER] << RCC_PLLNCSGR_MOD_PER_SHIFT) &
|
|
@@ -1157,21 +1589,20 @@ static void stm32mp1_pll_csg(struct stm32mp1_clk_priv *priv,
|
|
pllxcsg |= (csg[PLLCSG_SSCG_MODE] << RCC_PLLNCSGR_SSCG_MODE_SHIFT) &
|
|
RCC_PLLNCSGR_SSCG_MODE_MASK;
|
|
|
|
- mmio_write_32(priv->base + pll[pll_id].pllxcsgr, pllxcsg);
|
|
+ mmio_write_32(stm32mp_rcc_base() + pll->pllxcsgr, pllxcsg);
|
|
}
|
|
|
|
-static int stm32mp1_set_clksrc(struct stm32mp1_clk_priv *priv,
|
|
- unsigned int clksrc)
|
|
+static int stm32mp1_set_clksrc(unsigned int clksrc)
|
|
{
|
|
- uint32_t address = priv->base + (clksrc >> 4);
|
|
- unsigned long start;
|
|
+ uint32_t address = stm32mp_rcc_base() + (clksrc >> 4);
|
|
+ uint64_t start;
|
|
|
|
mmio_clrsetbits_32(address, RCC_SELR_SRC_MASK,
|
|
clksrc & RCC_SELR_SRC_MASK);
|
|
|
|
- start = get_timer(0);
|
|
+ start = timeout_start();
|
|
while ((mmio_read_32(address) & RCC_SELR_SRCRDY) == 0U) {
|
|
- if (get_timer(start) > CLKSRC_TIMEOUT) {
|
|
+ if (timeout_elapsed(start, CLKSRC_TIMEOUT)) {
|
|
ERROR("CLKSRC %x start failed @ 0x%x: 0x%x\n",
|
|
clksrc, address, mmio_read_32(address));
|
|
return -ETIMEDOUT;
|
|
@@ -1183,14 +1614,14 @@ static int stm32mp1_set_clksrc(struct stm32mp1_clk_priv *priv,
|
|
|
|
static int stm32mp1_set_clkdiv(unsigned int clkdiv, uint32_t address)
|
|
{
|
|
- unsigned long start;
|
|
+ uint64_t start;
|
|
|
|
mmio_clrsetbits_32(address, RCC_DIVR_DIV_MASK,
|
|
clkdiv & RCC_DIVR_DIV_MASK);
|
|
|
|
- start = get_timer(0);
|
|
+ start = timeout_start();
|
|
while ((mmio_read_32(address) & RCC_DIVR_DIVRDY) == 0U) {
|
|
- if (get_timer(start) > CLKDIV_TIMEOUT) {
|
|
+ if (timeout_elapsed(start, CLKDIV_TIMEOUT)) {
|
|
ERROR("CLKDIV %x start failed @ 0x%x: 0x%x\n",
|
|
clkdiv, address, mmio_read_32(address));
|
|
return -ETIMEDOUT;
|
|
@@ -1200,10 +1631,9 @@ static int stm32mp1_set_clkdiv(unsigned int clkdiv, uint32_t address)
|
|
return 0;
|
|
}
|
|
|
|
-static void stm32mp1_mco_csg(struct stm32mp1_clk_priv *priv,
|
|
- uint32_t clksrc, uint32_t clkdiv)
|
|
+static void stm32mp1_mco_csg(uint32_t clksrc, uint32_t clkdiv)
|
|
{
|
|
- uint32_t address = priv->base + (clksrc >> 4);
|
|
+ uint32_t address = stm32mp_rcc_base() + (clksrc >> 4);
|
|
|
|
/*
|
|
* Binding clksrc :
|
|
@@ -1224,10 +1654,9 @@ static void stm32mp1_mco_csg(struct stm32mp1_clk_priv *priv,
|
|
}
|
|
}
|
|
|
|
-static void stm32mp1_set_rtcsrc(struct stm32mp1_clk_priv *priv,
|
|
- unsigned int clksrc, bool lse_css)
|
|
+static void stm32mp1_set_rtcsrc(unsigned int clksrc, bool lse_css)
|
|
{
|
|
- uint32_t address = priv->base + RCC_BDCR;
|
|
+ uint32_t address = stm32mp_rcc_base() + RCC_BDCR;
|
|
|
|
if (((mmio_read_32(address) & RCC_BDCR_RTCCKEN) == 0U) ||
|
|
(clksrc != (uint32_t)CLK_RTC_DISABLED)) {
|
|
@@ -1243,52 +1672,73 @@ static void stm32mp1_set_rtcsrc(struct stm32mp1_clk_priv *priv,
|
|
}
|
|
}
|
|
|
|
-#define CNTCVL_OFF 0x008
|
|
-#define CNTCVU_OFF 0x00C
|
|
-
|
|
-static void stm32mp1_stgen_config(struct stm32mp1_clk_priv *priv)
|
|
+static void stm32mp1_stgen_config(void)
|
|
{
|
|
uintptr_t stgen;
|
|
- int p;
|
|
uint32_t cntfid0;
|
|
unsigned long rate;
|
|
+ unsigned long long counter;
|
|
|
|
stgen = fdt_get_stgen_base();
|
|
-
|
|
cntfid0 = mmio_read_32(stgen + CNTFID_OFF);
|
|
- p = stm32mp1_clk_get_parent(priv, STGEN_K);
|
|
- rate = stm32mp1_clk_get(priv, p);
|
|
+ rate = get_clock_rate(stm32mp1_clk_get_parent(STGEN_K));
|
|
|
|
- if (cntfid0 != rate) {
|
|
- unsigned long long counter;
|
|
+ if (cntfid0 == rate) {
|
|
+ return;
|
|
+ }
|
|
|
|
- mmio_clrbits_32(stgen + CNTCR_OFF, CNTCR_EN);
|
|
- counter = (unsigned long long)
|
|
- mmio_read_32(stgen + CNTCVL_OFF);
|
|
- counter |= ((unsigned long long)
|
|
- (mmio_read_32(stgen + CNTCVU_OFF))) << 32;
|
|
- counter = (counter * rate / cntfid0);
|
|
- mmio_write_32(stgen + CNTCVL_OFF, (uint32_t)counter);
|
|
- mmio_write_32(stgen + CNTCVU_OFF, (uint32_t)(counter >> 32));
|
|
- mmio_write_32(stgen + CNTFID_OFF, rate);
|
|
- mmio_setbits_32(stgen + CNTCR_OFF, CNTCR_EN);
|
|
+ mmio_clrbits_32(stgen + CNTCR_OFF, CNTCR_EN);
|
|
+ counter = (unsigned long long)mmio_read_32(stgen + CNTCVL_OFF);
|
|
+ counter |= ((unsigned long long)mmio_read_32(stgen + CNTCVU_OFF)) << 32;
|
|
+ counter = (counter * rate / cntfid0);
|
|
|
|
- write_cntfrq((u_register_t)rate);
|
|
+ mmio_write_32(stgen + CNTCVL_OFF, (uint32_t)counter);
|
|
+ mmio_write_32(stgen + CNTCVU_OFF, (uint32_t)(counter >> 32));
|
|
+ mmio_write_32(stgen + CNTFID_OFF, rate);
|
|
+ mmio_setbits_32(stgen + CNTCR_OFF, CNTCR_EN);
|
|
|
|
- /* Need to update timer with new frequency */
|
|
- generic_delay_timer_init();
|
|
- }
|
|
+ write_cntfrq((u_register_t)rate);
|
|
+
|
|
+ /* Need to update timer with new frequency */
|
|
+ generic_delay_timer_init();
|
|
}
|
|
|
|
-void stm32mp1_stgen_increment(unsigned long long offset_in_ms)
|
|
+unsigned long stm32mp_clk_timer_get_rate(unsigned long id)
|
|
{
|
|
- uintptr_t stgen;
|
|
- unsigned long long cnt;
|
|
+ unsigned long parent_rate;
|
|
+ uint32_t prescaler, timpre;
|
|
+ uintptr_t rcc_base = stm32mp_rcc_base();
|
|
|
|
- stgen = fdt_get_stgen_base();
|
|
-
|
|
- cnt = ((unsigned long long)mmio_read_32(stgen + CNTCVU_OFF) << 32) |
|
|
- mmio_read_32(stgen + CNTCVL_OFF);
|
|
+ parent_rate = stm32mp_clk_get_rate(id);
|
|
+
|
|
+ if (id < TIM1_K) {
|
|
+ prescaler = mmio_read_32(rcc_base + RCC_APB1DIVR) &
|
|
+ RCC_APBXDIV_MASK;
|
|
+ timpre = mmio_read_32(rcc_base + RCC_TIMG1PRER) &
|
|
+ RCC_TIMGXPRER_TIMGXPRE;
|
|
+ } else {
|
|
+ prescaler = mmio_read_32(rcc_base + RCC_APB2DIVR) &
|
|
+ RCC_APBXDIV_MASK;
|
|
+ timpre = mmio_read_32(rcc_base + RCC_TIMG2PRER) &
|
|
+ RCC_TIMGXPRER_TIMGXPRE;
|
|
+ }
|
|
+
|
|
+ if (!prescaler) {
|
|
+ return parent_rate;
|
|
+ }
|
|
+
|
|
+ return parent_rate * (timpre + 1) * 2;
|
|
+}
|
|
+
|
|
+void stm32mp1_stgen_increment(unsigned long long offset_in_ms)
|
|
+{
|
|
+ uintptr_t stgen;
|
|
+ unsigned long long cnt;
|
|
+
|
|
+ stgen = fdt_get_stgen_base();
|
|
+
|
|
+ cnt = ((unsigned long long)mmio_read_32(stgen + CNTCVU_OFF) << 32) |
|
|
+ mmio_read_32(stgen + CNTCVL_OFF);
|
|
|
|
cnt += (offset_in_ms * mmio_read_32(stgen + CNTFID_OFF)) / 1000U;
|
|
|
|
@@ -1298,9 +1748,46 @@ void stm32mp1_stgen_increment(unsigned long long offset_in_ms)
|
|
mmio_setbits_32(stgen + CNTCR_OFF, CNTCR_EN);
|
|
}
|
|
|
|
-static void stm32mp1_pkcs_config(struct stm32mp1_clk_priv *priv, uint32_t pkcs)
|
|
+/*******************************************************************************
|
|
+ * This function determines the number of needed RTC calendar read operations
|
|
+ * to get consistent values (1 or 2 depending on clock frequencies).
|
|
+ * If APB1 frequency is lower than 7 times the RTC one, the software has to
|
|
+ * read the calendar time and date registers twice.
|
|
+ * Returns true if read twice is needed, false else.
|
|
+ ******************************************************************************/
|
|
+bool stm32mp1_rtc_get_read_twice(void)
|
|
{
|
|
- uint32_t address = priv->base + ((pkcs >> 4) & 0xFFFU);
|
|
+ unsigned long apb1_freq;
|
|
+ uint32_t rtc_freq;
|
|
+ uint32_t apb1_div;
|
|
+ uintptr_t rcc_base = stm32mp_rcc_base();
|
|
+
|
|
+ switch ((mmio_read_32(rcc_base + RCC_BDCR) &
|
|
+ RCC_BDCR_RTCSRC_MASK) >> RCC_BDCR_RTCSRC_SHIFT) {
|
|
+ case 1:
|
|
+ rtc_freq = stm32mp_clk_get_rate(CK_LSE);
|
|
+ break;
|
|
+ case 2:
|
|
+ rtc_freq = stm32mp_clk_get_rate(CK_LSI);
|
|
+ break;
|
|
+ case 3:
|
|
+ rtc_freq = stm32mp_clk_get_rate(CK_HSE);
|
|
+ rtc_freq /= (mmio_read_32(rcc_base + RCC_RTCDIVR) &
|
|
+ RCC_DIVR_DIV_MASK) + 1U;
|
|
+ break;
|
|
+ default:
|
|
+ panic();
|
|
+ }
|
|
+
|
|
+ apb1_div = mmio_read_32(rcc_base + RCC_APB1DIVR) & RCC_APBXDIV_MASK;
|
|
+ apb1_freq = stm32mp_clk_get_rate(CK_MCU) >> apb1_div;
|
|
+
|
|
+ return apb1_freq < (rtc_freq * 7U);
|
|
+}
|
|
+
|
|
+static void stm32mp1_pkcs_config(uint32_t pkcs)
|
|
+{
|
|
+ uint32_t address = stm32mp_rcc_base() + ((pkcs >> 4) & 0xFFFU);
|
|
uint32_t value = pkcs & 0xFU;
|
|
uint32_t mask = 0xFU;
|
|
|
|
@@ -1314,8 +1801,7 @@ static void stm32mp1_pkcs_config(struct stm32mp1_clk_priv *priv, uint32_t pkcs)
|
|
|
|
int stm32mp1_clk_init(void)
|
|
{
|
|
- struct stm32mp1_clk_priv *priv = &stm32mp1_clk_priv_data;
|
|
- uint32_t rcc = priv->base;
|
|
+ uint32_t rcc_base = stm32mp_rcc_base();
|
|
unsigned int clksrc[CLKSRC_NB];
|
|
unsigned int clkdiv[CLKDIV_NB];
|
|
unsigned int pllcfg[_PLL_NB][PLLCFG_NB];
|
|
@@ -1323,11 +1809,16 @@ int stm32mp1_clk_init(void)
|
|
int ret, len;
|
|
enum stm32mp1_pll_id i;
|
|
bool lse_css = false;
|
|
- const uint32_t *pkcs_cell;
|
|
+ bool pll3_preserve = false;
|
|
+ bool pll4_preserve = false;
|
|
+ bool pll4_bootrom = false;
|
|
+ const fdt32_t *pkcs_cell;
|
|
+ int stgen_p = stm32mp1_clk_get_parent((int)STGEN_K);
|
|
+ int usbphy_p = stm32mp1_clk_get_parent((int)USBPHY_K);
|
|
|
|
/* Check status field to disable security */
|
|
if (!fdt_get_rcc_secure_status()) {
|
|
- mmio_write_32(rcc + RCC_TZCR, 0);
|
|
+ mmio_write_32(rcc_base + RCC_TZCR, 0);
|
|
}
|
|
|
|
ret = fdt_rcc_read_uint32_array("st,clksrc", clksrc,
|
|
@@ -1359,113 +1850,149 @@ int stm32mp1_clk_init(void)
|
|
}
|
|
}
|
|
|
|
- stm32mp1_mco_csg(priv, clksrc[CLKSRC_MCO1], clkdiv[CLKDIV_MCO1]);
|
|
- stm32mp1_mco_csg(priv, clksrc[CLKSRC_MCO2], clkdiv[CLKDIV_MCO2]);
|
|
+ stm32mp1_mco_csg(clksrc[CLKSRC_MCO1], clkdiv[CLKDIV_MCO1]);
|
|
+ stm32mp1_mco_csg(clksrc[CLKSRC_MCO2], clkdiv[CLKDIV_MCO2]);
|
|
|
|
/*
|
|
* Switch ON oscillator found in device-tree.
|
|
* Note: HSI already ON after BootROM stage.
|
|
*/
|
|
- if (priv->osc[_LSI] != 0U) {
|
|
- stm32mp1_lsi_set(rcc, 1);
|
|
+ if (stm32mp1_osc[_LSI] != 0U) {
|
|
+ stm32mp1_lsi_set(true);
|
|
}
|
|
- if (priv->osc[_LSE] != 0U) {
|
|
- bool bypass;
|
|
+ if (stm32mp1_osc[_LSE] != 0U) {
|
|
+ bool bypass, digbyp;
|
|
uint32_t lsedrv;
|
|
|
|
bypass = fdt_osc_read_bool(_LSE, "st,bypass");
|
|
+ digbyp = fdt_osc_read_bool(_LSE, "st,digbypass");
|
|
lse_css = fdt_osc_read_bool(_LSE, "st,css");
|
|
lsedrv = fdt_osc_read_uint32_default(_LSE, "st,drive",
|
|
LSEDRV_MEDIUM_HIGH);
|
|
- stm32mp1_lse_enable(rcc, bypass, lsedrv);
|
|
+ stm32mp1_lse_enable(bypass, digbyp, lsedrv);
|
|
}
|
|
- if (priv->osc[_HSE] != 0U) {
|
|
- bool bypass, css;
|
|
+ if (stm32mp1_osc[_HSE] != 0U) {
|
|
+ bool bypass, digbyp, css;
|
|
|
|
- bypass = fdt_osc_read_bool(_LSE, "st,bypass");
|
|
- css = fdt_osc_read_bool(_LSE, "st,css");
|
|
- stm32mp1_hse_enable(rcc, bypass, css);
|
|
+ bypass = fdt_osc_read_bool(_HSE, "st,bypass");
|
|
+ digbyp = fdt_osc_read_bool(_HSE, "st,digbypass");
|
|
+ css = fdt_osc_read_bool(_HSE, "st,css");
|
|
+ stm32mp1_hse_enable(bypass, digbyp, css);
|
|
}
|
|
/*
|
|
* CSI is mandatory for automatic I/O compensation (SYSCFG_CMPCR)
|
|
* => switch on CSI even if node is not present in device tree
|
|
*/
|
|
- stm32mp1_csi_set(rcc, 1);
|
|
+ stm32mp1_csi_set(true);
|
|
|
|
/* Come back to HSI */
|
|
- ret = stm32mp1_set_clksrc(priv, CLK_MPU_HSI);
|
|
+ ret = stm32mp1_set_clksrc(CLK_MPU_HSI);
|
|
+ if (ret != 0) {
|
|
+ return ret;
|
|
+ }
|
|
+ ret = stm32mp1_set_clksrc(CLK_AXI_HSI);
|
|
if (ret != 0) {
|
|
return ret;
|
|
}
|
|
- ret = stm32mp1_set_clksrc(priv, CLK_AXI_HSI);
|
|
+ ret = stm32mp1_set_clksrc(CLK_MCU_HSI);
|
|
if (ret != 0) {
|
|
return ret;
|
|
}
|
|
|
|
+ if ((mmio_read_32(rcc_base + RCC_MP_RSTSCLRR) &
|
|
+ RCC_MP_RSTSCLRR_MPUP0RSTF) != 0) {
|
|
+ pll3_preserve = stm32mp1_check_pll_conf(_PLL3,
|
|
+ clksrc[CLKSRC_PLL3],
|
|
+ pllcfg[_PLL3],
|
|
+ plloff[_PLL3]);
|
|
+ pll4_preserve = stm32mp1_check_pll_conf(_PLL4,
|
|
+ clksrc[CLKSRC_PLL4],
|
|
+ pllcfg[_PLL4],
|
|
+ plloff[_PLL4]);
|
|
+ }
|
|
+ /* Don't initialize PLL4, when used by BOOTROM */
|
|
+ if ((get_boot_device() == BOOT_DEVICE_USB) &&
|
|
+ ((stgen_p == (int)_PLL4_R) || (usbphy_p == (int)_PLL4_R))) {
|
|
+ pll4_bootrom = true;
|
|
+ pll4_preserve = true;
|
|
+ }
|
|
+
|
|
for (i = (enum stm32mp1_pll_id)0; i < _PLL_NB; i++) {
|
|
- if (i == _PLL4)
|
|
+ if (((i == _PLL3) && pll3_preserve) ||
|
|
+ ((i == _PLL4) && pll4_preserve)) {
|
|
continue;
|
|
- ret = stm32mp1_pll_stop(priv, i);
|
|
+ }
|
|
+
|
|
+ ret = stm32mp1_pll_stop(i);
|
|
if (ret != 0) {
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
/* Configure HSIDIV */
|
|
- if (priv->osc[_HSI] != 0U) {
|
|
- ret = stm32mp1_hsidiv(rcc, priv->osc[_HSI]);
|
|
+ if (stm32mp1_osc[_HSI] != 0U) {
|
|
+ ret = stm32mp1_hsidiv(stm32mp1_osc[_HSI]);
|
|
if (ret != 0) {
|
|
return ret;
|
|
}
|
|
- stm32mp1_stgen_config(priv);
|
|
+ stm32mp1_stgen_config();
|
|
}
|
|
|
|
/* Select DIV */
|
|
/* No ready bit when MPUSRC != CLK_MPU_PLL1P_DIV, MPUDIV is disabled */
|
|
- mmio_write_32(rcc + RCC_MPCKDIVR,
|
|
+ mmio_write_32(rcc_base + RCC_MPCKDIVR,
|
|
clkdiv[CLKDIV_MPU] & RCC_DIVR_DIV_MASK);
|
|
- ret = stm32mp1_set_clkdiv(clkdiv[CLKDIV_AXI], rcc + RCC_AXIDIVR);
|
|
+ ret = stm32mp1_set_clkdiv(clkdiv[CLKDIV_AXI], rcc_base + RCC_AXIDIVR);
|
|
+ if (ret != 0) {
|
|
+ return ret;
|
|
+ }
|
|
+ ret = stm32mp1_set_clkdiv(clkdiv[CLKDIV_APB4], rcc_base + RCC_APB4DIVR);
|
|
if (ret != 0) {
|
|
return ret;
|
|
}
|
|
- ret = stm32mp1_set_clkdiv(clkdiv[CLKDIV_APB4], rcc + RCC_APB4DIVR);
|
|
+ ret = stm32mp1_set_clkdiv(clkdiv[CLKDIV_APB5], rcc_base + RCC_APB5DIVR);
|
|
if (ret != 0) {
|
|
return ret;
|
|
}
|
|
- ret = stm32mp1_set_clkdiv(clkdiv[CLKDIV_APB5], rcc + RCC_APB5DIVR);
|
|
+ ret = stm32mp1_set_clkdiv(clkdiv[CLKDIV_MCU], rcc_base + RCC_MCUDIVR);
|
|
if (ret != 0) {
|
|
return ret;
|
|
}
|
|
- ret = stm32mp1_set_clkdiv(clkdiv[CLKDIV_APB1], rcc + RCC_APB1DIVR);
|
|
+ ret = stm32mp1_set_clkdiv(clkdiv[CLKDIV_APB1], rcc_base + RCC_APB1DIVR);
|
|
if (ret != 0) {
|
|
return ret;
|
|
}
|
|
- ret = stm32mp1_set_clkdiv(clkdiv[CLKDIV_APB2], rcc + RCC_APB2DIVR);
|
|
+ ret = stm32mp1_set_clkdiv(clkdiv[CLKDIV_APB2], rcc_base + RCC_APB2DIVR);
|
|
if (ret != 0) {
|
|
return ret;
|
|
}
|
|
- ret = stm32mp1_set_clkdiv(clkdiv[CLKDIV_APB3], rcc + RCC_APB3DIVR);
|
|
+ ret = stm32mp1_set_clkdiv(clkdiv[CLKDIV_APB3], rcc_base + RCC_APB3DIVR);
|
|
if (ret != 0) {
|
|
return ret;
|
|
}
|
|
|
|
/* No ready bit for RTC */
|
|
- mmio_write_32(rcc + RCC_RTCDIVR,
|
|
+ mmio_write_32(rcc_base + RCC_RTCDIVR,
|
|
clkdiv[CLKDIV_RTC] & RCC_DIVR_DIV_MASK);
|
|
|
|
/* Configure PLLs source */
|
|
- ret = stm32mp1_set_clksrc(priv, clksrc[CLKSRC_PLL12]);
|
|
+ ret = stm32mp1_set_clksrc(clksrc[CLKSRC_PLL12]);
|
|
if (ret != 0) {
|
|
return ret;
|
|
}
|
|
- ret = stm32mp1_set_clksrc(priv, clksrc[CLKSRC_PLL3]);
|
|
- if (ret != 0) {
|
|
- return ret;
|
|
+
|
|
+ if (!pll3_preserve) {
|
|
+ ret = stm32mp1_set_clksrc(clksrc[CLKSRC_PLL3]);
|
|
+ if (ret != 0) {
|
|
+ return ret;
|
|
+ }
|
|
}
|
|
|
|
- ret = stm32mp1_set_clksrc(priv, clksrc[CLKSRC_PLL4]);
|
|
- if (ret != 0) {
|
|
- return ret;
|
|
+ if (!pll4_preserve) {
|
|
+ ret = stm32mp1_set_clksrc(clksrc[CLKSRC_PLL4]);
|
|
+ if (ret != 0) {
|
|
+ return ret;
|
|
+ }
|
|
}
|
|
|
|
/* Configure and start PLLs */
|
|
@@ -1473,25 +2000,36 @@ int stm32mp1_clk_init(void)
|
|
uint32_t fracv;
|
|
uint32_t csg[PLLCSG_NB];
|
|
|
|
+ if (((i == _PLL3) && pll3_preserve) ||
|
|
+ ((i == _PLL4) && pll4_preserve && !pll4_bootrom)) {
|
|
+ continue;
|
|
+ }
|
|
+
|
|
if (!fdt_check_node(plloff[i])) {
|
|
continue;
|
|
}
|
|
|
|
+ if ((i == _PLL4) && pll4_bootrom) {
|
|
+ /* Set output divider if not done by the Bootrom */
|
|
+ stm32mp1_pll_config_output(i, pllcfg[i]);
|
|
+ continue;
|
|
+ }
|
|
+
|
|
fracv = fdt_read_uint32_default(plloff[i], "frac", 0);
|
|
|
|
- ret = stm32mp1_pll_config(priv, i, pllcfg[i], fracv);
|
|
+ ret = stm32mp1_pll_config(i, pllcfg[i], fracv);
|
|
if (ret != 0) {
|
|
return ret;
|
|
}
|
|
ret = fdt_read_uint32_array(plloff[i], "csg", csg,
|
|
(uint32_t)PLLCSG_NB);
|
|
if (ret == 0) {
|
|
- stm32mp1_pll_csg(priv, i, csg);
|
|
+ stm32mp1_pll_csg(i, csg);
|
|
} else if (ret != -FDT_ERR_NOTFOUND) {
|
|
return ret;
|
|
}
|
|
|
|
- stm32mp1_pll_start(priv, i);
|
|
+ stm32mp1_pll_start(i);
|
|
}
|
|
/* Wait and start PLLs ouptut when ready */
|
|
for (i = (enum stm32mp1_pll_id)0; i < _PLL_NB; i++) {
|
|
@@ -1499,43 +2037,50 @@ int stm32mp1_clk_init(void)
|
|
continue;
|
|
}
|
|
|
|
- ret = stm32mp1_pll_output(priv, i, pllcfg[i][PLLCFG_O]);
|
|
+ ret = stm32mp1_pll_output(i, pllcfg[i][PLLCFG_O]);
|
|
if (ret != 0) {
|
|
return ret;
|
|
}
|
|
}
|
|
/* Wait LSE ready before to use it */
|
|
- if (priv->osc[_LSE] != 0U) {
|
|
- stm32mp1_lse_wait(rcc);
|
|
+ if (stm32mp1_osc[_LSE] != 0U) {
|
|
+ stm32mp1_lse_wait();
|
|
}
|
|
|
|
/* Configure with expected clock source */
|
|
- ret = stm32mp1_set_clksrc(priv, clksrc[CLKSRC_MPU]);
|
|
+ ret = stm32mp1_set_clksrc(clksrc[CLKSRC_MPU]);
|
|
if (ret != 0) {
|
|
return ret;
|
|
}
|
|
- ret = stm32mp1_set_clksrc(priv, clksrc[CLKSRC_AXI]);
|
|
+ ret = stm32mp1_set_clksrc(clksrc[CLKSRC_AXI]);
|
|
if (ret != 0) {
|
|
return ret;
|
|
}
|
|
- stm32mp1_set_rtcsrc(priv, clksrc[CLKSRC_RTC], lse_css);
|
|
+ ret = stm32mp1_set_clksrc(clksrc[CLKSRC_MCU]);
|
|
+ if (ret != 0) {
|
|
+ return ret;
|
|
+ }
|
|
+ stm32mp1_set_rtcsrc(clksrc[CLKSRC_RTC], lse_css);
|
|
|
|
/* Configure PKCK */
|
|
pkcs_cell = fdt_rcc_read_prop("st,pkcs", &len);
|
|
if (pkcs_cell != NULL) {
|
|
bool ckper_disabled = false;
|
|
uint32_t j;
|
|
+ uint32_t usbreg_bootrom = 0U;
|
|
|
|
- priv->pkcs_usb_value = 0;
|
|
+ if (pll4_bootrom) {
|
|
+ usbreg_bootrom = mmio_read_32(rcc_base + RCC_USBCKSELR);
|
|
+ }
|
|
|
|
for (j = 0; j < ((uint32_t)len / sizeof(uint32_t)); j++) {
|
|
- uint32_t pkcs = (uint32_t)fdt32_to_cpu(pkcs_cell[j]);
|
|
+ uint32_t pkcs = fdt32_to_cpu(pkcs_cell[j]);
|
|
|
|
if (pkcs == (uint32_t)CLK_CKPER_DISABLED) {
|
|
ckper_disabled = true;
|
|
continue;
|
|
}
|
|
- stm32mp1_pkcs_config(priv, pkcs);
|
|
+ stm32mp1_pkcs_config(pkcs);
|
|
}
|
|
|
|
/*
|
|
@@ -1545,18 +2090,37 @@ int stm32mp1_clk_init(void)
|
|
* => deactivated CKPER only after switching clock
|
|
*/
|
|
if (ckper_disabled) {
|
|
- stm32mp1_pkcs_config(priv, CLK_CKPER_DISABLED);
|
|
+ stm32mp1_pkcs_config(CLK_CKPER_DISABLED);
|
|
+ }
|
|
+
|
|
+ if (pll4_bootrom) {
|
|
+ uint32_t usbreg_value, usbreg_mask;
|
|
+ const struct stm32mp1_clk_sel *sel;
|
|
+
|
|
+ sel = clk_sel_ref(_USBPHY_SEL);
|
|
+ usbreg_mask = (uint32_t)sel->msk << sel->src;
|
|
+ sel = clk_sel_ref(_USBO_SEL);
|
|
+ usbreg_mask |= (uint32_t)sel->msk << sel->src;
|
|
+
|
|
+ usbreg_value = mmio_read_32(rcc_base + RCC_USBCKSELR) &
|
|
+ usbreg_mask;
|
|
+ usbreg_bootrom &= usbreg_mask;
|
|
+ if (usbreg_bootrom != usbreg_value) {
|
|
+ VERBOSE("forbidden new USB clk path\n");
|
|
+ VERBOSE("vs bootrom on USB boot\n");
|
|
+ return -FDT_ERR_BADVALUE;
|
|
+ }
|
|
}
|
|
}
|
|
|
|
/* Switch OFF HSI if not found in device-tree */
|
|
- if (priv->osc[_HSI] == 0U) {
|
|
- stm32mp1_hsi_set(rcc, 0);
|
|
+ if (stm32mp1_osc[_HSI] == 0U) {
|
|
+ stm32mp1_hsi_set(false);
|
|
}
|
|
- stm32mp1_stgen_config(priv);
|
|
+ stm32mp1_stgen_config();
|
|
|
|
/* Software Self-Refresh mode (SSR) during DDR initilialization */
|
|
- mmio_clrsetbits_32(priv->base + RCC_DDRITFCR,
|
|
+ mmio_clrsetbits_32(rcc_base + RCC_DDRITFCR,
|
|
RCC_DDRITFCR_DDRCKMOD_MASK,
|
|
RCC_DDRITFCR_DDRCKMOD_SSR <<
|
|
RCC_DDRITFCR_DDRCKMOD_SHIFT);
|
|
@@ -1565,48 +2129,711 @@ int stm32mp1_clk_init(void)
|
|
}
|
|
|
|
static void stm32mp1_osc_clk_init(const char *name,
|
|
- struct stm32mp1_clk_priv *priv,
|
|
enum stm32mp_osc_id index)
|
|
{
|
|
uint32_t frequency;
|
|
|
|
- priv->osc[index] = 0;
|
|
+ if (fdt_osc_read_freq(name, &frequency) == 0) {
|
|
+ stm32mp1_osc[index] = frequency;
|
|
+ }
|
|
+}
|
|
+
|
|
+#if defined(IMAGE_BL32)
|
|
+/*
|
|
+ * HSI Calibration part
|
|
+ */
|
|
+static void hsi_set_trim(unsigned int cal)
|
|
+{
|
|
+ int clk_trim = (int)cal - (int)stm32mp1_clk_cal_hsi.cal_ref;
|
|
+ uint32_t trim = ((uint32_t)clk_trim << RCC_HSICFGR_HSITRIM_SHIFT) &
|
|
+ RCC_HSICFGR_HSITRIM_MASK;
|
|
+
|
|
+ mmio_clrsetbits_32(stm32mp_rcc_base() + RCC_HSICFGR,
|
|
+ RCC_HSICFGR_HSITRIM_MASK, trim);
|
|
+}
|
|
+
|
|
+static unsigned int hsi_get_trimed_cal(void)
|
|
+{
|
|
+ uint32_t utrim = (mmio_read_32(stm32mp_rcc_base() + RCC_HSICFGR) &
|
|
+ RCC_HSICFGR_HSITRIM_MASK) >>
|
|
+ RCC_HSICFGR_HSITRIM_SHIFT;
|
|
+ int trim = (int)utrim - stm32mp1_clk_cal_hsi.trim_max;
|
|
+
|
|
+ if (trim + (int)stm32mp1_clk_cal_hsi.cal_ref < 0) {
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ return stm32mp1_clk_cal_hsi.cal_ref + trim;
|
|
+}
|
|
+
|
|
+static void csi_set_trim(unsigned int cal)
|
|
+{
|
|
+ int clk_trim = (int)cal - (int)stm32mp1_clk_cal_csi.cal_ref +
|
|
+ stm32mp1_clk_cal_csi.trim_max + 1;
|
|
+ uint32_t trim = ((uint32_t)clk_trim << RCC_CSICFGR_CSITRIM_SHIFT) &
|
|
+ RCC_CSICFGR_CSITRIM_MASK;
|
|
|
|
- if (fdt_osc_read_freq(name, &frequency) != 0) {
|
|
- ERROR("%s frequency request failed\n", name);
|
|
+ mmio_clrsetbits_32(stm32mp_rcc_base() + RCC_CSICFGR,
|
|
+ RCC_CSICFGR_CSITRIM_MASK, trim);
|
|
+}
|
|
+
|
|
+static unsigned int csi_get_trimed_cal(void)
|
|
+{
|
|
+ uint32_t trim = (mmio_read_32(stm32mp_rcc_base() + RCC_CSICFGR) &
|
|
+ RCC_CSICFGR_CSITRIM_MASK) >>
|
|
+ RCC_CSICFGR_CSITRIM_SHIFT;
|
|
+
|
|
+ return (int)trim - stm32mp1_clk_cal_csi.trim_max +
|
|
+ (int)stm32mp1_clk_cal_csi.cal_ref - 1;
|
|
+}
|
|
+
|
|
+static unsigned int trim_increase(struct stm32mp1_clk_cal *clk_cal,
|
|
+ unsigned int cal)
|
|
+{
|
|
+ struct stm32mp1_trim_boundary_t *boundary;
|
|
+ unsigned int new_cal;
|
|
+ int i;
|
|
+
|
|
+ /* By default: last calibration value */
|
|
+ new_cal = cal;
|
|
+
|
|
+ /* Start from Lowest cal value */
|
|
+ for (i = (int)clk_cal->boundary_max - 1; i >= 0; i--) {
|
|
+ boundary = &clk_cal->boundary[i];
|
|
+
|
|
+ if (cal < boundary->x2) {
|
|
+ new_cal = boundary->x2;
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ if ((cal >= boundary->x2) && (cal < boundary->x1)) {
|
|
+ new_cal = cal + 1;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return new_cal;
|
|
+}
|
|
+
|
|
+static unsigned int trim_decrease(struct stm32mp1_clk_cal *clk_cal,
|
|
+ unsigned int cal)
|
|
+{
|
|
+ struct stm32mp1_trim_boundary_t *boundary;
|
|
+ unsigned int new_cal;
|
|
+ unsigned int i;
|
|
+
|
|
+ /* By default: last calibration value */
|
|
+ new_cal = cal;
|
|
+
|
|
+ /* Start from Highest cal value */
|
|
+ for (i = 0; i < clk_cal->boundary_max; i++) {
|
|
+ boundary = &clk_cal->boundary[i];
|
|
+
|
|
+ if (cal > boundary->x1) {
|
|
+ new_cal = boundary->x1;
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ if ((cal > boundary->x2) && (cal <= boundary->x1)) {
|
|
+ new_cal = cal - 1;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return new_cal;
|
|
+}
|
|
+
|
|
+static void stm32mp1_rcc_calibration(struct stm32mp1_clk_cal *clk_cal)
|
|
+{
|
|
+ unsigned long freq = clk_cal->get_freq();
|
|
+ unsigned long min = clk_cal->ref_freq -
|
|
+ ((clk_cal->ref_freq * clk_cal->freq_margin) / 100);
|
|
+ unsigned long max = clk_cal->ref_freq +
|
|
+ ((clk_cal->ref_freq * clk_cal->freq_margin) / 100);
|
|
+ unsigned int nb_retries = CAL_MAX_RETRY;
|
|
+ int cal = clk_cal->get_trim();
|
|
+
|
|
+ VERBOSE("Freq is %lu min %lu max %lu\n", freq, min, max);
|
|
+
|
|
+ while (((freq < min) || (freq > max)) && (nb_retries != 0U)) {
|
|
+
|
|
+ if (freq < min) {
|
|
+ cal = trim_increase(clk_cal, cal);
|
|
+ } else {
|
|
+ cal = trim_decrease(clk_cal, cal);
|
|
+ }
|
|
+
|
|
+ clk_cal->set_trim(cal);
|
|
+
|
|
+ freq = clk_cal->get_freq();
|
|
+
|
|
+ nb_retries--;
|
|
+ }
|
|
+
|
|
+ if (nb_retries == 0U) {
|
|
+ ERROR("Calibration Failed\n");
|
|
panic();
|
|
- } else {
|
|
- priv->osc[index] = frequency;
|
|
}
|
|
}
|
|
|
|
+static void save_trim(struct stm32mp1_clk_cal *clk_cal,
|
|
+ unsigned int i, unsigned int x1, unsigned int x2)
|
|
+{
|
|
+ clk_cal->boundary[i].x1 = x1;
|
|
+ clk_cal->boundary[i].x2 = x2;
|
|
+}
|
|
+
|
|
+static int trim_find_prev_boundary(struct stm32mp1_clk_cal *clk_cal,
|
|
+ unsigned int x1)
|
|
+{
|
|
+ unsigned int x = x1;
|
|
+ unsigned long freq;
|
|
+
|
|
+ clk_cal->set_trim(x1 + 1);
|
|
+ freq = clk_cal->get_freq();
|
|
+
|
|
+ while (x >= (clk_cal->cal_ref + clk_cal->trim_min)) {
|
|
+ x--;
|
|
+ clk_cal->set_trim(x);
|
|
+
|
|
+ if (clk_cal->get_freq() <= freq) {
|
|
+ break;
|
|
+ }
|
|
+ };
|
|
+
|
|
+ return x;
|
|
+}
|
|
+
|
|
+static void trim_table_init(struct stm32mp1_clk_cal *clk_cal)
|
|
+{
|
|
+ uint16_t *trim_fbv = clk_cal->fbv;
|
|
+ unsigned int min;
|
|
+ unsigned int max;
|
|
+ int boundary = 0;
|
|
+ int i = 0;
|
|
+
|
|
+ max = clk_cal->cal_ref + clk_cal->trim_max;
|
|
+ min = clk_cal->cal_ref + clk_cal->trim_min;
|
|
+
|
|
+ while (trim_fbv[i]) {
|
|
+ unsigned int x;
|
|
+ unsigned int x1 = trim_fbv[i];
|
|
+ unsigned int x2 = trim_fbv[i + 1];
|
|
+
|
|
+ if ((max <= x2) || (min >= x1)) {
|
|
+ i++;
|
|
+ if (boundary != 0) {
|
|
+ goto out;
|
|
+ }
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ /* Take forbiden value + 1 */
|
|
+ x2 = x2 + 1;
|
|
+ if (x2 < min) {
|
|
+ x2 = min;
|
|
+ }
|
|
+
|
|
+ if (boundary == 0) {
|
|
+ /* Save first boundary */
|
|
+ save_trim(clk_cal, boundary, max, x2);
|
|
+ boundary++;
|
|
+ i++;
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ x = trim_find_prev_boundary(clk_cal, x1);
|
|
+ /* Save boundary values */
|
|
+ save_trim(clk_cal, boundary, x - 1, x2);
|
|
+ boundary++;
|
|
+ i++;
|
|
+ };
|
|
+out:
|
|
+ clk_cal->boundary_max = boundary;
|
|
+}
|
|
+
|
|
+bool stm32mp1_rcc_get_wakeup(void)
|
|
+{
|
|
+ return rcc_wakeup;
|
|
+}
|
|
+
|
|
+void stm32mp1_rcc_set_wakeup(bool state)
|
|
+{
|
|
+ rcc_wakeup = state;
|
|
+}
|
|
+
|
|
+void stm32mp1_rcc_it_handler(uint32_t id)
|
|
+{
|
|
+ uintptr_t rcc_base = stm32mp_rcc_base();
|
|
+
|
|
+ switch (id) {
|
|
+ case STM32MP1_IRQ_RCC_WAKEUP:
|
|
+ plat_ic_set_priority_mask(GIC_HIGHEST_NS_PRIORITY);
|
|
+ mmio_setbits_32(rcc_base + RCC_MP_CIFR, RCC_MP_CIFR_WKUPF);
|
|
+ stm32mp1_rcc_set_wakeup(true);
|
|
+ return;
|
|
+
|
|
+ case STM32MP1_IRQ_MCU_SEV:
|
|
+ stm32mp1_rcc_set_wakeup(false);
|
|
+ if ((mmio_read_32(EXTI_BASE + EXTI_RPR3) &
|
|
+ EXTI_RPR3_RPIF65) != 0U) {
|
|
+ mmio_setbits_32(EXTI_BASE + EXTI_RPR3,
|
|
+ EXTI_RPR3_RPIF65);
|
|
+ }
|
|
+
|
|
+ if ((mmio_read_32(EXTI_BASE + EXTI_FPR3) &
|
|
+ EXTI_FPR3_FPIF65) != 0U) {
|
|
+ mmio_setbits_32(EXTI_BASE + EXTI_FPR3,
|
|
+ EXTI_FPR3_FPIF65);
|
|
+ }
|
|
+
|
|
+ break;
|
|
+
|
|
+ case ARM_IRQ_SEC_PHY_TIMER:
|
|
+ default:
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ if (stm32mp1_clk_cal_hsi.ref_freq != 0U) {
|
|
+ stm32mp1_rcc_calibration(&stm32mp1_clk_cal_hsi);
|
|
+ }
|
|
+
|
|
+ if (stm32mp1_clk_cal_csi.ref_freq != 0U) {
|
|
+ stm32mp1_rcc_calibration(&stm32mp1_clk_cal_csi);
|
|
+ }
|
|
+
|
|
+ if (timer_val != 0U) {
|
|
+ write_cntptval(timer_val);
|
|
+ }
|
|
+}
|
|
+
|
|
+int stm32mp1_rcc_start_hsi_cal(void)
|
|
+{
|
|
+ if (stm32mp1_clk_cal_hsi.ref_freq == 0U) {
|
|
+ return -ENOENT;
|
|
+ }
|
|
+
|
|
+ stm32mp1_rcc_calibration(&stm32mp1_clk_cal_hsi);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+int stm32mp1_rcc_start_csi_cal(void)
|
|
+{
|
|
+ if (stm32mp1_clk_cal_csi.ref_freq == 0U) {
|
|
+ return -ENOENT;
|
|
+ }
|
|
+
|
|
+ stm32mp1_rcc_calibration(&stm32mp1_clk_cal_csi);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static void init_hsi_cal(void)
|
|
+{
|
|
+ int len;
|
|
+
|
|
+ if (fdt_rcc_read_prop("st,hsi-cal", &len) == NULL) {
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ stm32_timer_freq_func(&stm32mp1_clk_cal_hsi.get_freq, HSI_CAL);
|
|
+ assert(stm32mp1_clk_cal_hsi.get_freq);
|
|
+
|
|
+ stm32mp1_clk_cal_hsi.ref_freq = stm32mp_clk_get_rate(CK_HSI);
|
|
+
|
|
+ /* Read initial value */
|
|
+ stm32mp1_clk_cal_hsi.cal_ref =
|
|
+ ((mmio_read_32(stm32mp_rcc_base() + RCC_HSICFGR)
|
|
+ & RCC_HSICFGR_HSICAL_MASK) >> RCC_HSICFGR_HSICAL_SHIFT);
|
|
+
|
|
+ trim_table_init(&stm32mp1_clk_cal_hsi);
|
|
+
|
|
+ stm32mp1_clk_cal_hsi.set_trim(stm32mp1_clk_cal_hsi.cal_ref);
|
|
+
|
|
+ stm32mp1_rcc_calibration(&stm32mp1_clk_cal_hsi);
|
|
+}
|
|
+
|
|
+static void init_csi_cal(void)
|
|
+{
|
|
+ int len;
|
|
+
|
|
+ if (fdt_rcc_read_prop("st,csi-cal", &len) == NULL) {
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ stm32_timer_freq_func(&stm32mp1_clk_cal_csi.get_freq, CSI_CAL);
|
|
+ assert(stm32mp1_clk_cal_csi.get_freq);
|
|
+
|
|
+ stm32mp1_clk_cal_csi.ref_freq = stm32mp_clk_get_rate(CK_CSI);
|
|
+
|
|
+ /* Read initial value */
|
|
+ stm32mp1_clk_cal_csi.cal_ref =
|
|
+ ((mmio_read_32(stm32mp_rcc_base() + RCC_CSICFGR) &
|
|
+ RCC_CSICFGR_CSICAL_MASK) >> RCC_CSICFGR_CSICAL_SHIFT);
|
|
+
|
|
+ trim_table_init(&stm32mp1_clk_cal_csi);
|
|
+
|
|
+ stm32mp1_clk_cal_csi.set_trim(stm32mp1_clk_cal_csi.cal_ref);
|
|
+
|
|
+ stm32mp1_rcc_calibration(&stm32mp1_clk_cal_csi);
|
|
+}
|
|
+
|
|
+void stm32mp1_cal_init(void)
|
|
+{
|
|
+ init_hsi_cal();
|
|
+ init_csi_cal();
|
|
+
|
|
+ timer_val = fdt_rcc_read_uint32_default("st,cal-sec", 0) *
|
|
+ plat_get_syscnt_freq2();
|
|
+
|
|
+ if (timer_val != 0U) {
|
|
+ /* Load & enable timer */
|
|
+ write_cntptval(timer_val);
|
|
+ write_cntpctl(BIT(0));
|
|
+ };
|
|
+
|
|
+ if (fdt_rcc_enable_it("mcu_sev") < 0) {
|
|
+ VERBOSE("No MCU calibration\n");
|
|
+ }
|
|
+}
|
|
+#endif
|
|
+
|
|
static void stm32mp1_osc_init(void)
|
|
{
|
|
- struct stm32mp1_clk_priv *priv = &stm32mp1_clk_priv_data;
|
|
enum stm32mp_osc_id i;
|
|
|
|
for (i = (enum stm32mp_osc_id)0 ; i < NB_OSC; i++) {
|
|
- stm32mp1_osc_clk_init(stm32mp_osc_node_label[i], priv, i);
|
|
+ stm32mp1_osc_clk_init(stm32mp_osc_node_label[i], i);
|
|
}
|
|
}
|
|
|
|
-int stm32mp1_clk_probe(void)
|
|
+/*
|
|
+ * Lookup platform clock from enable bit location in RCC registers.
|
|
+ * Return a valid clock ID on success, return ~0 on error.
|
|
+ */
|
|
+unsigned long stm32mp1_clk_rcc2id(unsigned int offset, unsigned int bit)
|
|
{
|
|
- struct stm32mp1_clk_priv *priv = &stm32mp1_clk_priv_data;
|
|
+ return get_id_from_rcc_bit(offset, bit);
|
|
+}
|
|
|
|
- priv->base = fdt_rcc_read_addr();
|
|
- if (priv->base == 0U) {
|
|
- return -EINVAL;
|
|
+/*
|
|
+ * Get the parent ID of the target parent clock, for tagging as secure
|
|
+ * shared clock dependencies.
|
|
+ */
|
|
+static int get_parent_id_parent(unsigned int parent_id)
|
|
+{
|
|
+ enum stm32mp1_parent_sel s = _UNKNOWN_SEL;
|
|
+ enum stm32mp1_pll_id pll_id;
|
|
+ uint32_t p_sel;
|
|
+
|
|
+ switch (parent_id) {
|
|
+ case _ACLK:
|
|
+ case _PCLK4:
|
|
+ case _PCLK5:
|
|
+ s = _ASS_SEL;
|
|
+ break;
|
|
+ case _PLL1_P:
|
|
+ case _PLL1_Q:
|
|
+ case _PLL1_R:
|
|
+ pll_id = _PLL1;
|
|
+ break;
|
|
+ case _PLL2_P:
|
|
+ case _PLL2_Q:
|
|
+ case _PLL2_R:
|
|
+ pll_id = _PLL2;
|
|
+ break;
|
|
+ case _PLL3_P:
|
|
+ case _PLL3_Q:
|
|
+ case _PLL3_R:
|
|
+ pll_id = _PLL3;
|
|
+ break;
|
|
+ case _PLL4_P:
|
|
+ case _PLL4_Q:
|
|
+ case _PLL4_R:
|
|
+ pll_id = _PLL4;
|
|
+ break;
|
|
+ case _PCLK1:
|
|
+ case _PCLK2:
|
|
+ case _HCLK2:
|
|
+ case _HCLK6:
|
|
+ case _CK_PER:
|
|
+ case _CK_MPU:
|
|
+ case _CK_MCU:
|
|
+ case _USB_PHY_48:
|
|
+ /* We do not expected to access these */
|
|
+ panic();
|
|
+ break;
|
|
+ default:
|
|
+ /* Other parents have no parent */
|
|
+ return -1;
|
|
}
|
|
|
|
- priv->data = &stm32mp1_data;
|
|
+ if (s != _UNKNOWN_SEL) {
|
|
+ const struct stm32mp1_clk_sel *sel = clk_sel_ref(s);
|
|
+ uintptr_t rcc_base = stm32mp_rcc_base();
|
|
|
|
- if ((priv->data->gate == NULL) || (priv->data->sel == NULL) ||
|
|
- (priv->data->pll == NULL)) {
|
|
- return -EINVAL;
|
|
+ p_sel = (mmio_read_32(rcc_base + sel->offset) >> sel->src) &
|
|
+ sel->msk;
|
|
+
|
|
+ if (p_sel < sel->nb_parent) {
|
|
+ return (int)sel->parent[p_sel];
|
|
+ }
|
|
+ } else {
|
|
+ const struct stm32mp1_clk_pll *pll = pll_ref(pll_id);
|
|
+ uintptr_t rcc_base = stm32mp_rcc_base();
|
|
+
|
|
+ p_sel = mmio_read_32(rcc_base + pll->rckxselr) &
|
|
+ RCC_SELR_REFCLK_SRC_MASK;
|
|
+
|
|
+ if (pll->refclk[p_sel] != _UNKNOWN_OSC_ID) {
|
|
+ return (int)pll->refclk[p_sel];
|
|
+ }
|
|
}
|
|
|
|
+#if LOG_LEVEL >= LOG_LEVEL_VERBOSE
|
|
+ VERBOSE("No parent selected for %s",
|
|
+ stm32mp1_clk_parent_name[parent_id]);
|
|
+#endif
|
|
+
|
|
+ return -1;
|
|
+}
|
|
+
|
|
+static void secure_parent_clocks(unsigned long parent_id)
|
|
+{
|
|
+ int grandparent_id;
|
|
+
|
|
+ switch (parent_id) {
|
|
+ /* Secure only the parents for these clocks */
|
|
+ case _ACLK:
|
|
+ case _HCLK2:
|
|
+ case _HCLK6:
|
|
+ case _PCLK4:
|
|
+ case _PCLK5:
|
|
+ break;
|
|
+ /* PLLs */
|
|
+ case _PLL1_P:
|
|
+ stm32mp1_register_secure_periph(STM32MP1_SHRES_PLL1_P);
|
|
+ break;
|
|
+ case _PLL1_Q:
|
|
+ stm32mp1_register_secure_periph(STM32MP1_SHRES_PLL1_Q);
|
|
+ break;
|
|
+ case _PLL1_R:
|
|
+ stm32mp1_register_secure_periph(STM32MP1_SHRES_PLL1_R);
|
|
+ break;
|
|
+
|
|
+ case _PLL2_P:
|
|
+ stm32mp1_register_secure_periph(STM32MP1_SHRES_PLL2_P);
|
|
+ break;
|
|
+ case _PLL2_Q:
|
|
+ stm32mp1_register_secure_periph(STM32MP1_SHRES_PLL2_Q);
|
|
+ break;
|
|
+ case _PLL2_R:
|
|
+ stm32mp1_register_secure_periph(STM32MP1_SHRES_PLL2_R);
|
|
+ break;
|
|
+
|
|
+ case _PLL3_P:
|
|
+ stm32mp1_register_secure_periph(STM32MP1_SHRES_PLL3_P);
|
|
+ break;
|
|
+ case _PLL3_Q:
|
|
+ stm32mp1_register_secure_periph(STM32MP1_SHRES_PLL3_Q);
|
|
+ break;
|
|
+ case _PLL3_R:
|
|
+ stm32mp1_register_secure_periph(STM32MP1_SHRES_PLL3_R);
|
|
+ break;
|
|
+
|
|
+ /* Source clocks */
|
|
+ case _HSI:
|
|
+ case _HSI_KER:
|
|
+ stm32mp1_register_secure_periph(STM32MP1_SHRES_HSI);
|
|
+ break;
|
|
+ case _LSI:
|
|
+ stm32mp1_register_secure_periph(STM32MP1_SHRES_LSI);
|
|
+ break;
|
|
+ case _CSI:
|
|
+ case _CSI_KER:
|
|
+ stm32mp1_register_secure_periph(STM32MP1_SHRES_CSI);
|
|
+ break;
|
|
+ case _HSE:
|
|
+ case _HSE_KER:
|
|
+ case _HSE_KER_DIV2:
|
|
+ stm32mp1_register_secure_periph(STM32MP1_SHRES_HSE);
|
|
+ break;
|
|
+ case _LSE:
|
|
+ stm32mp1_register_secure_periph(STM32MP1_SHRES_LSE);
|
|
+ break;
|
|
+
|
|
+ default:
|
|
+ panic();
|
|
+ }
|
|
+
|
|
+ grandparent_id = get_parent_id_parent(parent_id);
|
|
+ if (grandparent_id >= 0) {
|
|
+ secure_parent_clocks(grandparent_id);
|
|
+ }
|
|
+}
|
|
+
|
|
+void stm32mp1_register_clock_parents_secure(unsigned long clock_id)
|
|
+{
|
|
+ int parent_id;
|
|
+
|
|
+ if (!stm32mp1_rcc_is_secure()) {
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ switch (clock_id) {
|
|
+ case PLL1:
|
|
+ parent_id = get_parent_id_parent(_PLL1_P);
|
|
+ break;
|
|
+ case PLL2:
|
|
+ parent_id = get_parent_id_parent(_PLL2_P);
|
|
+ break;
|
|
+ case PLL3:
|
|
+ parent_id = get_parent_id_parent(_PLL3_P);
|
|
+ break;
|
|
+ case PLL4:
|
|
+ ERROR("PLL4 cannot be secured\n");
|
|
+ panic();
|
|
+ break;
|
|
+ default:
|
|
+ /* Others are expected gateable clock */
|
|
+ parent_id = stm32mp1_clk_get_parent(clock_id);
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ if (parent_id < 0) {
|
|
+ ERROR("No parent for clock %lu", clock_id);
|
|
+ panic();
|
|
+ }
|
|
+
|
|
+ secure_parent_clocks(parent_id);
|
|
+}
|
|
+
|
|
+/* Sync secure clock refcount after all drivers probe/inits, */
|
|
+void stm32mp1_update_earlyboot_clocks_state(void)
|
|
+{
|
|
+ unsigned int idx;
|
|
+
|
|
+ for (idx = 0U; idx < NB_GATES; idx++) {
|
|
+ const struct stm32mp1_clk_gate *gate = gate_ref(idx);
|
|
+ unsigned long clock_id = gate_ref(idx)->index;
|
|
+
|
|
+ /* Drop non secure refcnt on non shared shareable clocks */
|
|
+ if (__clk_is_enabled(gate) &&
|
|
+ stm32mp1_clock_is_shareable(clock_id) &&
|
|
+ !stm32mp1_clock_is_shared(clock_id)) {
|
|
+ stm32mp1_clk_disable_non_secure(clock_id);
|
|
+ }
|
|
+ }
|
|
+
|
|
+#if LOG_LEVEL >= LOG_LEVEL_VERBOSE
|
|
+ /* Dump clocks state */
|
|
+ for (idx = 0U; idx < NB_GATES; idx++) {
|
|
+ const struct stm32mp1_clk_gate *gate = gate_ref(idx);
|
|
+ unsigned long __unused clock_id = gate->index;
|
|
+ unsigned int __unused refcnt = gate_refcounts[idx];
|
|
+ int __unused p = stm32mp1_clk_get_parent(clock_id);
|
|
+
|
|
+ VERBOSE("stm32mp1 clk %lu %sabled (refcnt %d) (parent %d %s)\n",
|
|
+ clock_id, __clk_is_enabled(gate) ? "en" : "dis",
|
|
+ refcnt, p,
|
|
+ p < 0 ? "n.a" : stm32mp1_clk_parent_sel_name[p]);
|
|
+ }
|
|
+#endif
|
|
+}
|
|
+
|
|
+static void sync_earlyboot_clocks_state(void)
|
|
+{
|
|
+ unsigned int idx;
|
|
+ int res;
|
|
+
|
|
+ for (idx = 0U; idx < NB_GATES; idx++) {
|
|
+ assert(gate_refcounts[idx] == 0);
|
|
+ }
|
|
+
|
|
+ /* Set a non secure refcnt for shareable clocks enabled from boot */
|
|
+ for (idx = 0U; idx < NB_GATES; idx++) {
|
|
+ struct stm32mp1_clk_gate const *gate = gate_ref(idx);
|
|
+
|
|
+ if (__clk_is_enabled(gate) &&
|
|
+ stm32mp1_clock_is_shareable(gate->index)) {
|
|
+ gate_refcounts[idx] = SHREFCNT_NONSECURE_FLAG;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * Register secure clock parents and init a refcount for
|
|
+ * secure only resources that are not registered from a driver probe.
|
|
+ * - DDR controller and phy clocks.
|
|
+ * - TZC400, ETZPC and STGEN clocks.
|
|
+ * - RTCAPB clocks on multi-core
|
|
+ */
|
|
+ stm32mp1_register_clock_parents_secure(DDRC1);
|
|
+ stm32mp1_clk_enable_secure(DDRC1);
|
|
+ stm32mp1_register_clock_parents_secure(DDRC1LP);
|
|
+ stm32mp1_clk_enable_secure(DDRC1LP);
|
|
+ stm32mp1_register_clock_parents_secure(DDRC2);
|
|
+ stm32mp1_clk_enable_secure(DDRC2);
|
|
+ stm32mp1_register_clock_parents_secure(DDRC2LP);
|
|
+ stm32mp1_clk_enable_secure(DDRC2LP);
|
|
+ stm32mp1_register_clock_parents_secure(DDRPHYC);
|
|
+ stm32mp1_clk_enable_secure(DDRPHYC);
|
|
+ stm32mp1_register_clock_parents_secure(DDRPHYCLP);
|
|
+ stm32mp1_clk_enable_secure(DDRPHYCLP);
|
|
+ stm32mp1_register_clock_parents_secure(DDRCAPB);
|
|
+ stm32mp1_clk_enable_secure(DDRCAPB);
|
|
+ stm32mp1_register_clock_parents_secure(AXIDCG);
|
|
+ stm32mp1_clk_enable_secure(AXIDCG);
|
|
+ stm32mp1_register_clock_parents_secure(DDRPHYCAPB);
|
|
+ stm32mp1_clk_enable_secure(DDRPHYCAPB);
|
|
+ stm32mp1_register_clock_parents_secure(DDRPHYCAPBLP);
|
|
+ stm32mp1_clk_enable_secure(DDRPHYCAPBLP);
|
|
+
|
|
+ stm32mp1_register_clock_parents_secure(TZPC);
|
|
+ stm32mp1_clk_enable_secure(TZPC);
|
|
+ stm32mp1_register_clock_parents_secure(TZC1);
|
|
+ stm32mp1_clk_enable_secure(TZC1);
|
|
+ stm32mp1_register_clock_parents_secure(TZC2);
|
|
+ stm32mp1_clk_enable_secure(TZC2);
|
|
+ stm32mp1_register_clock_parents_secure(STGEN_K);
|
|
+ stm32mp1_clk_enable_secure(STGEN_K);
|
|
+
|
|
+ stm32mp1_register_clock_parents_secure(BSEC);
|
|
+ stm32mp1_register_clock_parents_secure(BKPSRAM);
|
|
+
|
|
+ stm32mp1_register_clock_parents_secure(RTCAPB);
|
|
+
|
|
+ res = stm32mp_is_single_core();
|
|
+ if (res < 0) {
|
|
+ panic();
|
|
+ }
|
|
+
|
|
+ if (res == 0) {
|
|
+ stm32mp1_clk_enable_secure(RTCAPB);
|
|
+ }
|
|
+}
|
|
+
|
|
+void stm32mp1_rcc_init_late(void)
|
|
+{
|
|
+#if defined(IMAGE_BL32)
|
|
+ int irq_num;
|
|
+
|
|
+ if (!stm32mp1_rcc_is_secure()) {
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ irq_num = fdt_rcc_enable_it("wakeup");
|
|
+ if (irq_num < 0) {
|
|
+ panic();
|
|
+ }
|
|
+
|
|
+ plat_ic_set_interrupt_priority(irq_num, STM32MP1_IRQ_RCC_SEC_PRIO);
|
|
+#endif
|
|
+}
|
|
+
|
|
+int stm32mp1_clk_probe(void)
|
|
+{
|
|
stm32mp1_osc_init();
|
|
|
|
+ sync_earlyboot_clocks_state();
|
|
+
|
|
return 0;
|
|
}
|
|
diff --git a/drivers/st/clk/stm32mp1_clkfunc.c b/drivers/st/clk/stm32mp1_clkfunc.c
|
|
index d4c69cb..99a7360 100644
|
|
--- a/drivers/st/clk/stm32mp1_clkfunc.c
|
|
+++ b/drivers/st/clk/stm32mp1_clkfunc.c
|
|
@@ -7,16 +7,13 @@
|
|
#include <dt-bindings/clock/stm32mp1-clksrc.h>
|
|
#include <errno.h>
|
|
#include <libfdt.h>
|
|
+#include <platform_def.h>
|
|
+#include <stm32_gpio.h>
|
|
+#include <stm32mp_clkfunc.h>
|
|
+#include <stm32mp_common.h>
|
|
+#include <stm32mp_dt.h>
|
|
#include <stm32mp1_clk.h>
|
|
#include <stm32mp1_clkfunc.h>
|
|
-#include <stm32mp1_dt.h>
|
|
-
|
|
-#define DT_RCC_NODE_NAME "rcc@50000000"
|
|
-#define DT_RCC_CLK_COMPAT "st,stm32mp1-rcc"
|
|
-#define DT_RCC_COMPAT "syscon"
|
|
-#define DT_STGEN_COMPAT "st,stm32-stgen"
|
|
-#define DT_UART_COMPAT "st,stm32h7-uart"
|
|
-#define DT_USART_COMPAT "st,stm32h7-usart"
|
|
|
|
const char *stm32mp_osc_node_label[NB_OSC] = {
|
|
[_LSI] = "clk-lsi",
|
|
@@ -24,15 +21,14 @@ const char *stm32mp_osc_node_label[NB_OSC] = {
|
|
[_HSI] = "clk-hsi",
|
|
[_HSE] = "clk-hse",
|
|
[_CSI] = "clk-csi",
|
|
- [_I2S_CKIN] = "i2s_ckin",
|
|
- [_USB_PHY_48] = "ck_usbo_48m"
|
|
+ [_I2S_CKIN] = "i2s_ckin"
|
|
};
|
|
|
|
/*******************************************************************************
|
|
* This function reads the frequency of an oscillator from its name.
|
|
* It reads the value indicated inside the device tree.
|
|
- * Returns 0 if success, and a negative value else.
|
|
- * If success, value is stored in the second parameter.
|
|
+ * Returns 0 on success, and a negative FDT/ERRNO error code on failure.
|
|
+ * On success, value is stored in the second parameter.
|
|
******************************************************************************/
|
|
int fdt_osc_read_freq(const char *name, uint32_t *freq)
|
|
{
|
|
@@ -124,7 +120,7 @@ bool fdt_osc_read_bool(enum stm32mp_osc_id osc_id, const char *prop_name)
|
|
|
|
/*******************************************************************************
|
|
* This function reads a value of a oscillator property from its id.
|
|
- * Returns value if success, and a default value if property not found.
|
|
+ * Returns value on success, and a default value if property not found.
|
|
* Default value is passed as parameter.
|
|
******************************************************************************/
|
|
uint32_t fdt_osc_read_uint32_default(enum stm32mp_osc_id osc_id,
|
|
@@ -166,200 +162,19 @@ uint32_t fdt_osc_read_uint32_default(enum stm32mp_osc_id osc_id,
|
|
return dflt_value;
|
|
}
|
|
|
|
-/*******************************************************************************
|
|
- * This function reads the rcc base address.
|
|
- * It reads the value indicated inside the device tree.
|
|
- * Returns address if success, and 0 value else.
|
|
- ******************************************************************************/
|
|
-uint32_t fdt_rcc_read_addr(void)
|
|
-{
|
|
- int node, subnode;
|
|
- void *fdt;
|
|
-
|
|
- if (fdt_get_address(&fdt) == 0) {
|
|
- return 0;
|
|
- }
|
|
-
|
|
- node = fdt_path_offset(fdt, "/soc");
|
|
- if (node < 0) {
|
|
- return 0;
|
|
- }
|
|
-
|
|
- fdt_for_each_subnode(subnode, fdt, node) {
|
|
- const char *cchar;
|
|
- int ret;
|
|
-
|
|
- cchar = fdt_get_name(fdt, subnode, &ret);
|
|
- if (cchar == NULL) {
|
|
- return 0;
|
|
- }
|
|
-
|
|
- if (strncmp(cchar, DT_RCC_NODE_NAME, (size_t)ret) == 0) {
|
|
- const fdt32_t *cuint;
|
|
-
|
|
- cuint = fdt_getprop(fdt, subnode, "reg", NULL);
|
|
- if (cuint == NULL) {
|
|
- return 0;
|
|
- }
|
|
-
|
|
- return fdt32_to_cpu(*cuint);
|
|
- }
|
|
- }
|
|
-
|
|
- return 0;
|
|
-}
|
|
|
|
/*******************************************************************************
|
|
- * This function reads a series of parameters in rcc-clk section.
|
|
- * It reads the values indicated inside the device tree, from property name.
|
|
- * The number of parameters is also indicated as entry parameter.
|
|
+ * This function get interrupt name.
|
|
+ * It reads the values indicated the enabling status.
|
|
* Returns 0 if success, and a negative value else.
|
|
- * If success, values are stored at the second parameter address.
|
|
- ******************************************************************************/
|
|
-int fdt_rcc_read_uint32_array(const char *prop_name,
|
|
- uint32_t *array, uint32_t count)
|
|
-{
|
|
- int node;
|
|
- void *fdt;
|
|
-
|
|
- if (fdt_get_address(&fdt) == 0) {
|
|
- return -ENOENT;
|
|
- }
|
|
-
|
|
- node = fdt_node_offset_by_compatible(fdt, -1, DT_RCC_CLK_COMPAT);
|
|
- if (node < 0) {
|
|
- return -FDT_ERR_NOTFOUND;
|
|
- }
|
|
-
|
|
- return fdt_read_uint32_array(node, prop_name, array, count);
|
|
-}
|
|
-
|
|
-/*******************************************************************************
|
|
- * This function gets the subnode offset in rcc-clk section from its name.
|
|
- * It reads the values indicated inside the device tree.
|
|
- * Returns offset if success, and a negative value else.
|
|
- ******************************************************************************/
|
|
-int fdt_rcc_subnode_offset(const char *name)
|
|
-{
|
|
- int node, subnode;
|
|
- void *fdt;
|
|
-
|
|
- if (fdt_get_address(&fdt) == 0) {
|
|
- return -ENOENT;
|
|
- }
|
|
-
|
|
- node = fdt_node_offset_by_compatible(fdt, -1, DT_RCC_CLK_COMPAT);
|
|
- if (node < 0) {
|
|
- return -FDT_ERR_NOTFOUND;
|
|
- }
|
|
-
|
|
- subnode = fdt_subnode_offset(fdt, node, name);
|
|
- if (subnode <= 0) {
|
|
- return -FDT_ERR_NOTFOUND;
|
|
- }
|
|
-
|
|
- return subnode;
|
|
-}
|
|
-
|
|
-/*******************************************************************************
|
|
- * This function gets the pointer to a rcc-clk property from its name.
|
|
- * It reads the values indicated inside the device tree.
|
|
- * Length of the property is stored in the second parameter.
|
|
- * Returns pointer if success, and NULL value else.
|
|
- ******************************************************************************/
|
|
-const uint32_t *fdt_rcc_read_prop(const char *prop_name, int *lenp)
|
|
-{
|
|
- const uint32_t *cuint;
|
|
- int node, len;
|
|
- void *fdt;
|
|
-
|
|
- if (fdt_get_address(&fdt) == 0) {
|
|
- return NULL;
|
|
- }
|
|
-
|
|
- node = fdt_node_offset_by_compatible(fdt, -1, DT_RCC_CLK_COMPAT);
|
|
- if (node < 0) {
|
|
- return NULL;
|
|
- }
|
|
-
|
|
- cuint = fdt_getprop(fdt, node, prop_name, &len);
|
|
- if (cuint == NULL) {
|
|
- return NULL;
|
|
- }
|
|
-
|
|
- *lenp = len;
|
|
- return cuint;
|
|
-}
|
|
-
|
|
-/*******************************************************************************
|
|
- * This function gets the secure status for rcc node.
|
|
- * It reads secure-status in device tree.
|
|
- * Returns 1 if rcc is available from secure world, 0 else.
|
|
******************************************************************************/
|
|
-bool fdt_get_rcc_secure_status(void)
|
|
+int fdt_rcc_enable_it(const char *name)
|
|
{
|
|
- int node;
|
|
- void *fdt;
|
|
-
|
|
- if (fdt_get_address(&fdt) == 0) {
|
|
- return false;
|
|
- }
|
|
-
|
|
- node = fdt_node_offset_by_compatible(fdt, -1, DT_RCC_COMPAT);
|
|
- if (node < 0) {
|
|
- return false;
|
|
- }
|
|
-
|
|
- return fdt_check_secure_status(node);
|
|
-}
|
|
-
|
|
-/*******************************************************************************
|
|
- * This function reads the stgen base address.
|
|
- * It reads the value indicated inside the device tree.
|
|
- * Returns address if success, and NULL value else.
|
|
- ******************************************************************************/
|
|
-uintptr_t fdt_get_stgen_base(void)
|
|
-{
|
|
- int node;
|
|
- const fdt32_t *cuint;
|
|
- void *fdt;
|
|
-
|
|
- if (fdt_get_address(&fdt) == 0) {
|
|
- return 0;
|
|
- }
|
|
-
|
|
- node = fdt_node_offset_by_compatible(fdt, -1, DT_STGEN_COMPAT);
|
|
- if (node < 0) {
|
|
- return 0;
|
|
- }
|
|
-
|
|
- cuint = fdt_getprop(fdt, node, "reg", NULL);
|
|
- if (cuint == NULL) {
|
|
- return 0;
|
|
- }
|
|
-
|
|
- return fdt32_to_cpu(*cuint);
|
|
-}
|
|
-
|
|
-/*******************************************************************************
|
|
- * This function gets the clock ID of the given node.
|
|
- * It reads the value indicated inside the device tree.
|
|
- * Returns ID if success, and a negative value else.
|
|
- ******************************************************************************/
|
|
-int fdt_get_clock_id(int node)
|
|
-{
|
|
- const fdt32_t *cuint;
|
|
void *fdt;
|
|
|
|
if (fdt_get_address(&fdt) == 0) {
|
|
return -ENOENT;
|
|
}
|
|
|
|
- cuint = fdt_getprop(fdt, node, "clocks", NULL);
|
|
- if (cuint == NULL) {
|
|
- return -FDT_ERR_NOTFOUND;
|
|
- }
|
|
-
|
|
- cuint++;
|
|
- return (int)fdt32_to_cpu(*cuint);
|
|
+ return stm32_gic_enable_spi(fdt_get_rcc_node(fdt), name);
|
|
}
|
|
diff --git a/drivers/st/clk/stm32mp_clkfunc.c b/drivers/st/clk/stm32mp_clkfunc.c
|
|
new file mode 100644
|
|
index 0000000..5c7e202
|
|
--- /dev/null
|
|
+++ b/drivers/st/clk/stm32mp_clkfunc.c
|
|
@@ -0,0 +1,307 @@
|
|
+/*
|
|
+ * Copyright (c) 2017-2018, STMicroelectronics - All Rights Reserved
|
|
+ *
|
|
+ * SPDX-License-Identifier: BSD-3-Clause
|
|
+ */
|
|
+
|
|
+#include <errno.h>
|
|
+#include <libfdt.h>
|
|
+#include <platform_def.h>
|
|
+#include <stm32_gpio.h>
|
|
+#include <stm32mp_clkfunc.h>
|
|
+#include <stm32mp_common.h>
|
|
+#include <stm32mp_dt.h>
|
|
+
|
|
+#define DT_STGEN_COMPAT "st,stm32-stgen"
|
|
+#define DT_UART_COMPAT "st,stm32h7-uart"
|
|
+
|
|
+/*******************************************************************************
|
|
+ * This function returns the RCC node in the device tree.
|
|
+ ******************************************************************************/
|
|
+int fdt_get_rcc_node(void *fdt)
|
|
+{
|
|
+ return fdt_node_offset_by_compatible(fdt, -1, DT_RCC_CLK_COMPAT);
|
|
+}
|
|
+
|
|
+/*******************************************************************************
|
|
+ * This function reads the rcc base address.
|
|
+ * It reads the value indicated inside the device tree.
|
|
+ * Returns address on success, and 0 on failure.
|
|
+ ******************************************************************************/
|
|
+uint32_t fdt_rcc_read_addr(void)
|
|
+{
|
|
+ int node;
|
|
+ void *fdt;
|
|
+ const fdt32_t *cuint;
|
|
+
|
|
+ if (fdt_get_address(&fdt) == 0) {
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ node = fdt_get_rcc_node(fdt);
|
|
+ if (node < 0) {
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ cuint = fdt_getprop(fdt, node, "reg", NULL);
|
|
+ if (cuint == NULL) {
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ return fdt32_to_cpu(*cuint);
|
|
+}
|
|
+
|
|
+/*******************************************************************************
|
|
+ * This function reads a series of parameters in rcc-clk section.
|
|
+ * It reads the values indicated inside the device tree, from property name.
|
|
+ * The number of parameters is also indicated as entry parameter.
|
|
+ * Returns 0 on success, and a negative FDT/ERRNO error code on failure.
|
|
+ * On success, values are stored at the second parameter address.
|
|
+ ******************************************************************************/
|
|
+int fdt_rcc_read_uint32_array(const char *prop_name,
|
|
+ uint32_t *array, uint32_t count)
|
|
+{
|
|
+ int node;
|
|
+ void *fdt;
|
|
+
|
|
+ if (fdt_get_address(&fdt) == 0) {
|
|
+ return -ENOENT;
|
|
+ }
|
|
+
|
|
+ node = fdt_get_rcc_node(fdt);
|
|
+ if (node < 0) {
|
|
+ return -FDT_ERR_NOTFOUND;
|
|
+ }
|
|
+
|
|
+ return fdt_read_uint32_array(node, prop_name, array, count);
|
|
+}
|
|
+
|
|
+/*******************************************************************************
|
|
+ * This function reads a property rcc-clk section.
|
|
+ * It reads the values indicated inside the device tree, from property name.
|
|
+ * Returns dflt_value if property is not found, and a property value on
|
|
+ * success.
|
|
+ ******************************************************************************/
|
|
+uint32_t fdt_rcc_read_uint32_default(const char *prop_name, uint32_t dflt_value)
|
|
+{
|
|
+ int node;
|
|
+ void *fdt;
|
|
+
|
|
+ if (fdt_get_address(&fdt) == 0) {
|
|
+ return dflt_value;
|
|
+ }
|
|
+
|
|
+ node = fdt_node_offset_by_compatible(fdt, -1, DT_RCC_CLK_COMPAT);
|
|
+ if (node < 0) {
|
|
+ return dflt_value;
|
|
+ }
|
|
+
|
|
+ return fdt_read_uint32_default(node, prop_name, dflt_value);
|
|
+}
|
|
+
|
|
+/*******************************************************************************
|
|
+ * This function gets the subnode offset in rcc-clk section from its name.
|
|
+ * It reads the values indicated inside the device tree.
|
|
+ * Returns offset on success, and a negative FDT/ERRNO error code on failure.
|
|
+ ******************************************************************************/
|
|
+int fdt_rcc_subnode_offset(const char *name)
|
|
+{
|
|
+ int node, subnode;
|
|
+ void *fdt;
|
|
+
|
|
+ if (fdt_get_address(&fdt) == 0) {
|
|
+ return -ENOENT;
|
|
+ }
|
|
+
|
|
+ node = fdt_get_rcc_node(fdt);
|
|
+ if (node < 0) {
|
|
+ return -FDT_ERR_NOTFOUND;
|
|
+ }
|
|
+
|
|
+ subnode = fdt_subnode_offset(fdt, node, name);
|
|
+ if (subnode <= 0) {
|
|
+ return -FDT_ERR_NOTFOUND;
|
|
+ }
|
|
+
|
|
+ return subnode;
|
|
+}
|
|
+
|
|
+/*******************************************************************************
|
|
+ * This function gets the pointer to a rcc-clk property from its name.
|
|
+ * It reads the values indicated inside the device tree.
|
|
+ * Length of the property is stored in the second parameter.
|
|
+ * Returns pointer on success, and NULL value on failure.
|
|
+ ******************************************************************************/
|
|
+const fdt32_t *fdt_rcc_read_prop(const char *prop_name, int *lenp)
|
|
+{
|
|
+ const fdt32_t *cuint;
|
|
+ int node, len;
|
|
+ void *fdt;
|
|
+
|
|
+ if (fdt_get_address(&fdt) == 0) {
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ node = fdt_get_rcc_node(fdt);
|
|
+ if (node < 0) {
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ cuint = fdt_getprop(fdt, node, prop_name, &len);
|
|
+ if (cuint == NULL) {
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ *lenp = len;
|
|
+ return cuint;
|
|
+}
|
|
+
|
|
+/*******************************************************************************
|
|
+ * This function gets the secure status for rcc node.
|
|
+ * It reads secure-status in device tree.
|
|
+ * Returns true if rcc is available from secure world, false if not.
|
|
+ ******************************************************************************/
|
|
+bool fdt_get_rcc_secure_status(void)
|
|
+{
|
|
+ int node;
|
|
+ void *fdt;
|
|
+
|
|
+ if (fdt_get_address(&fdt) == 0) {
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ node = fdt_get_rcc_node(fdt);
|
|
+ if (node < 0) {
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ return !!(fdt_get_status(node) & DT_SECURE);
|
|
+}
|
|
+
|
|
+/*******************************************************************************
|
|
+ * This function reads the stgen base address.
|
|
+ * It reads the value indicated inside the device tree.
|
|
+ * Returns address on success, and NULL value on failure.
|
|
+ ******************************************************************************/
|
|
+uintptr_t fdt_get_stgen_base(void)
|
|
+{
|
|
+ int node;
|
|
+ const fdt32_t *cuint;
|
|
+ void *fdt;
|
|
+
|
|
+ if (fdt_get_address(&fdt) == 0) {
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ node = fdt_node_offset_by_compatible(fdt, -1, DT_STGEN_COMPAT);
|
|
+ if (node < 0) {
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ cuint = fdt_getprop(fdt, node, "reg", NULL);
|
|
+ if (cuint == NULL) {
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ return fdt32_to_cpu(*cuint);
|
|
+}
|
|
+
|
|
+/*******************************************************************************
|
|
+ * This function gets the clock ID of the given node.
|
|
+ * It reads the value indicated inside the device tree.
|
|
+ * Returns ID on success, and a negative FDT/ERRNO error code on failure.
|
|
+ ******************************************************************************/
|
|
+int fdt_get_clock_id(int node)
|
|
+{
|
|
+ const fdt32_t *cuint;
|
|
+ void *fdt;
|
|
+
|
|
+ if (fdt_get_address(&fdt) == 0) {
|
|
+ return -ENOENT;
|
|
+ }
|
|
+
|
|
+ cuint = fdt_getprop(fdt, node, "clocks", NULL);
|
|
+ if (cuint == NULL) {
|
|
+ return -FDT_ERR_NOTFOUND;
|
|
+ }
|
|
+
|
|
+ cuint++;
|
|
+ return (int)fdt32_to_cpu(*cuint);
|
|
+}
|
|
+
|
|
+/*******************************************************************************
|
|
+ * This function gets the clock ID of the given node using clock-names.
|
|
+ * It reads the value indicated inside the device tree.
|
|
+ * Returns ID on success, and a negative FDT/ERRNO error code on failure.
|
|
+ ******************************************************************************/
|
|
+int fdt_get_clock_id_by_name(int node, const char *name)
|
|
+{
|
|
+ const fdt32_t *cuint;
|
|
+ void *fdt;
|
|
+ int index, len;
|
|
+
|
|
+ if (fdt_get_address(&fdt) == 0) {
|
|
+ return -ENOENT;
|
|
+ }
|
|
+
|
|
+ index = fdt_stringlist_search(fdt, node, "clock-names", name);
|
|
+ if (index < 0) {
|
|
+ return index;
|
|
+ }
|
|
+
|
|
+ cuint = fdt_getprop(fdt, node, "clocks", &len);
|
|
+ if (cuint == NULL) {
|
|
+ return -FDT_ERR_NOTFOUND;
|
|
+ }
|
|
+
|
|
+ if ((index * (int)sizeof(uint32_t)) > len) {
|
|
+ return -FDT_ERR_BADVALUE;
|
|
+ }
|
|
+
|
|
+ cuint += (index << 1) + 1;
|
|
+ return (int)fdt32_to_cpu(*cuint);
|
|
+}
|
|
+
|
|
+/*******************************************************************************
|
|
+ * This function gets the frequency of the specified uart instance.
|
|
+ * From this instance, all the uarts nodes in DT are parsed, and the register
|
|
+ * base is compared to the instance. If match between these two values, then
|
|
+ * the clock source is read from the DT and we deduce the frequency.
|
|
+ * Returns clock frequency on success, 0 value on failure.
|
|
+ ******************************************************************************/
|
|
+unsigned long fdt_get_uart_clock_freq(uintptr_t instance)
|
|
+{
|
|
+ int node;
|
|
+ void *fdt;
|
|
+
|
|
+ if (fdt_get_address(&fdt) == 0) {
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ /* Check for UART nodes */
|
|
+ node = fdt_node_offset_by_compatible(fdt, -1, DT_UART_COMPAT);
|
|
+ while (node != -FDT_ERR_NOTFOUND) {
|
|
+ const fdt32_t *cuint;
|
|
+
|
|
+ cuint = fdt_getprop(fdt, node, "reg", NULL);
|
|
+ if (cuint == NULL)
|
|
+ goto next;
|
|
+
|
|
+ if ((uintptr_t)fdt32_to_cpu(*cuint) == instance) {
|
|
+ unsigned long clk_id;
|
|
+
|
|
+ cuint = fdt_getprop(fdt, node, "clocks", NULL);
|
|
+ if (cuint == NULL)
|
|
+ goto next;
|
|
+
|
|
+ cuint++;
|
|
+ clk_id = (unsigned long)(fdt32_to_cpu(*cuint));
|
|
+
|
|
+ return stm32mp_clk_get_rate(clk_id);
|
|
+ }
|
|
+next:
|
|
+ node = fdt_node_offset_by_compatible(fdt, node, DT_UART_COMPAT);
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
diff --git a/drivers/st/ddr/stm32mp1_ddr.c b/drivers/st/ddr/stm32mp1_ddr.c
|
|
index eed1d76..ae5668a 100644
|
|
--- a/drivers/st/ddr/stm32mp1_ddr.c
|
|
+++ b/drivers/st/ddr/stm32mp1_ddr.c
|
|
@@ -8,18 +8,14 @@
|
|
#include <arch_helpers.h>
|
|
#include <debug.h>
|
|
#include <delay_timer.h>
|
|
-#include <dt-bindings/clock/stm32mp1-clks.h>
|
|
+#include <errno.h>
|
|
#include <mmio.h>
|
|
#include <platform.h>
|
|
+#include <platform_def.h>
|
|
#include <stddef.h>
|
|
-#include <stm32mp1_clk.h>
|
|
-#include <stm32mp1_ddr.h>
|
|
-#include <stm32mp1_ddr_regs.h>
|
|
-#include <stm32mp1_dt.h>
|
|
-#include <stm32mp1_pmic.h>
|
|
-#include <stm32mp1_pwr.h>
|
|
-#include <stm32mp1_ram.h>
|
|
-#include <stm32mp1_rcc.h>
|
|
+#include <stm32mp_common.h>
|
|
+#include <stm32mp_dt.h>
|
|
+#include <stm32mp_pmic.h>
|
|
|
|
struct reg_desc {
|
|
const char *name;
|
|
@@ -29,7 +25,8 @@ struct reg_desc {
|
|
|
|
#define INVALID_OFFSET 0xFFU
|
|
|
|
-#define TIMESLOT_1US (plat_get_syscnt_freq2() / 1000000U)
|
|
+#define TIMESLOT_1US us2tick(1)
|
|
+#define TIMEOUT_1S s2tick(1)
|
|
|
|
#define DDRCTL_REG(x, y) \
|
|
{ \
|
|
@@ -231,40 +228,67 @@ struct ddr_reg_info {
|
|
|
|
static const struct ddr_reg_info ddr_registers[REG_TYPE_NB] = {
|
|
[REG_REG] = {
|
|
- "static", ddr_reg, ARRAY_SIZE(ddr_reg), DDR_BASE
|
|
+ .name = "static",
|
|
+ .desc = ddr_reg,
|
|
+ .size = ARRAY_SIZE(ddr_reg),
|
|
+ .base = DDR_BASE
|
|
},
|
|
[REG_TIMING] = {
|
|
- "timing", ddr_timing, ARRAY_SIZE(ddr_timing), DDR_BASE
|
|
+ .name = "timing",
|
|
+ .desc = ddr_timing,
|
|
+ .size = ARRAY_SIZE(ddr_timing),
|
|
+ .base = DDR_BASE
|
|
},
|
|
[REG_PERF] = {
|
|
- "perf", ddr_perf, ARRAY_SIZE(ddr_perf), DDR_BASE
|
|
+ .name = "perf",
|
|
+ .desc = ddr_perf,
|
|
+ .size = ARRAY_SIZE(ddr_perf),
|
|
+ .base = DDR_BASE
|
|
},
|
|
[REG_MAP] = {
|
|
- "map", ddr_map, ARRAY_SIZE(ddr_map), DDR_BASE
|
|
+ .name = "map",
|
|
+ .desc = ddr_map,
|
|
+ .size = ARRAY_SIZE(ddr_map),
|
|
+ .base = DDR_BASE
|
|
},
|
|
[REGPHY_REG] = {
|
|
- "static", ddrphy_reg, ARRAY_SIZE(ddrphy_reg), DDRPHY_BASE
|
|
+ .name = "static",
|
|
+ .desc = ddrphy_reg,
|
|
+ .size = ARRAY_SIZE(ddrphy_reg),
|
|
+ .base = DDRPHY_BASE
|
|
},
|
|
[REGPHY_TIMING] = {
|
|
- "timing", ddrphy_timing, ARRAY_SIZE(ddrphy_timing), DDRPHY_BASE
|
|
+ .name = "timing",
|
|
+ .desc = ddrphy_timing,
|
|
+ .size = ARRAY_SIZE(ddrphy_timing),
|
|
+ .base = DDRPHY_BASE
|
|
},
|
|
[REGPHY_CAL] = {
|
|
- "cal", ddrphy_cal, ARRAY_SIZE(ddrphy_cal), DDRPHY_BASE
|
|
+ .name = "cal",
|
|
+ .desc = ddrphy_cal,
|
|
+ .size = ARRAY_SIZE(ddrphy_cal),
|
|
+ .base = DDRPHY_BASE
|
|
},
|
|
[REG_DYN] = {
|
|
- "dyn", ddr_dyn, ARRAY_SIZE(ddr_dyn), DDR_BASE
|
|
+ .name = "dyn",
|
|
+ .desc = ddr_dyn,
|
|
+ .size = ARRAY_SIZE(ddr_dyn),
|
|
+ .base = DDR_BASE
|
|
},
|
|
[REGPHY_DYN] = {
|
|
- "dyn", ddrphy_dyn, ARRAY_SIZE(ddrphy_dyn), DDRPHY_BASE
|
|
+ .name = "dyn",
|
|
+ .desc = ddrphy_dyn,
|
|
+ .size = ARRAY_SIZE(ddrphy_dyn),
|
|
+ .base = DDRPHY_BASE
|
|
},
|
|
};
|
|
|
|
-static uint32_t get_base_addr(const struct ddr_info *priv, enum base_type base)
|
|
+static uintptr_t get_base_addr(const struct ddr_info *priv, enum base_type base)
|
|
{
|
|
if (base == DDRPHY_BASE) {
|
|
- return (uint32_t)priv->phy;
|
|
+ return (uintptr_t)priv->phy;
|
|
} else {
|
|
- return (uint32_t)priv->ctl;
|
|
+ return (uintptr_t)priv->ctl;
|
|
}
|
|
}
|
|
|
|
@@ -273,21 +297,22 @@ static void set_reg(const struct ddr_info *priv,
|
|
const void *param)
|
|
{
|
|
unsigned int i;
|
|
- unsigned int *ptr, value;
|
|
+ unsigned int value;
|
|
enum base_type base = ddr_registers[type].base;
|
|
- uint32_t base_addr = get_base_addr(priv, base);
|
|
+ uintptr_t base_addr = get_base_addr(priv, base);
|
|
const struct reg_desc *desc = ddr_registers[type].desc;
|
|
|
|
VERBOSE("init %s\n", ddr_registers[type].name);
|
|
for (i = 0; i < ddr_registers[type].size; i++) {
|
|
- ptr = (unsigned int *)(base_addr + desc[i].offset);
|
|
+ uintptr_t ptr = base_addr + desc[i].offset;
|
|
+
|
|
if (desc[i].par_offset == INVALID_OFFSET) {
|
|
ERROR("invalid parameter offset for %s", desc[i].name);
|
|
panic();
|
|
} else {
|
|
- value = *((uint32_t *)((uint32_t)param +
|
|
+ value = *((uint32_t *)((uintptr_t)param +
|
|
desc[i].par_offset));
|
|
- mmio_write_32((uint32_t)ptr, value);
|
|
+ mmio_write_32(ptr, value);
|
|
}
|
|
}
|
|
}
|
|
@@ -296,26 +321,27 @@ static void stm32mp1_ddrphy_idone_wait(struct stm32mp1_ddrphy *phy)
|
|
{
|
|
uint32_t pgsr;
|
|
int error = 0;
|
|
- unsigned long start;
|
|
- unsigned long time0, time;
|
|
+ uint64_t start, time0;
|
|
|
|
- start = get_timer(0);
|
|
+ start = timeout_start();
|
|
time0 = start;
|
|
|
|
do {
|
|
- pgsr = mmio_read_32((uint32_t)&phy->pgsr);
|
|
- time = get_timer(start);
|
|
+ uint64_t time;
|
|
+
|
|
+ pgsr = mmio_read_32((uintptr_t)&phy->pgsr);
|
|
+ time = timeout_start() - start;
|
|
if (time != time0) {
|
|
- VERBOSE(" > [0x%x] pgsr = 0x%x &\n",
|
|
- (uint32_t)&phy->pgsr, pgsr);
|
|
- VERBOSE(" [0x%x] pir = 0x%x (time=%x)\n",
|
|
- (uint32_t)&phy->pir,
|
|
- mmio_read_32((uint32_t)&phy->pir),
|
|
- (uint32_t)time);
|
|
+ VERBOSE(" > [0x%lx] pgsr = 0x%x &\n",
|
|
+ (uintptr_t)&phy->pgsr, pgsr);
|
|
+ VERBOSE(" [0x%lx] pir = 0x%x (time=%llx)\n",
|
|
+ (uintptr_t)&phy->pir,
|
|
+ mmio_read_32((uintptr_t)&phy->pir),
|
|
+ time);
|
|
}
|
|
|
|
time0 = time;
|
|
- if (time > plat_get_syscnt_freq2()) {
|
|
+ if (time > TIMEOUT_1S) {
|
|
panic();
|
|
}
|
|
if ((pgsr & DDRPHYC_PGSR_DTERR) != 0U) {
|
|
@@ -339,18 +365,18 @@ static void stm32mp1_ddrphy_idone_wait(struct stm32mp1_ddrphy *phy)
|
|
error++;
|
|
}
|
|
} while ((pgsr & DDRPHYC_PGSR_IDONE) == 0U && error == 0);
|
|
- VERBOSE("\n[0x%x] pgsr = 0x%x\n",
|
|
- (uint32_t)&phy->pgsr, pgsr);
|
|
+ VERBOSE("\n[0x%lx] pgsr = 0x%x\n",
|
|
+ (uintptr_t)&phy->pgsr, pgsr);
|
|
}
|
|
|
|
static void stm32mp1_ddrphy_init(struct stm32mp1_ddrphy *phy, uint32_t pir)
|
|
{
|
|
uint32_t pir_init = pir | DDRPHYC_PIR_INIT;
|
|
|
|
- mmio_write_32((uint32_t)&phy->pir, pir_init);
|
|
- VERBOSE("[0x%x] pir = 0x%x -> 0x%x\n",
|
|
- (uint32_t)&phy->pir, pir_init,
|
|
- mmio_read_32((uint32_t)&phy->pir));
|
|
+ mmio_write_32((uintptr_t)&phy->pir, pir_init);
|
|
+ VERBOSE("[0x%lx] pir = 0x%x -> 0x%x\n",
|
|
+ (uintptr_t)&phy->pir, pir_init,
|
|
+ mmio_read_32((uintptr_t)&phy->pir));
|
|
|
|
/* Need to wait 10 configuration clock before start polling */
|
|
udelay(10);
|
|
@@ -362,56 +388,57 @@ static void stm32mp1_ddrphy_init(struct stm32mp1_ddrphy *phy, uint32_t pir)
|
|
/* Start quasi dynamic register update */
|
|
static void stm32mp1_start_sw_done(struct stm32mp1_ddrctl *ctl)
|
|
{
|
|
- mmio_clrbits_32((uint32_t)&ctl->swctl, DDRCTRL_SWCTL_SW_DONE);
|
|
- VERBOSE("[0x%x] swctl = 0x%x\n",
|
|
- (uint32_t)&ctl->swctl, mmio_read_32((uint32_t)&ctl->swctl));
|
|
+ mmio_clrbits_32((uintptr_t)&ctl->swctl, DDRCTRL_SWCTL_SW_DONE);
|
|
+ VERBOSE("[0x%lx] swctl = 0x%x\n",
|
|
+ (uintptr_t)&ctl->swctl, mmio_read_32((uintptr_t)&ctl->swctl));
|
|
}
|
|
|
|
/* Wait quasi dynamic register update */
|
|
static void stm32mp1_wait_sw_done_ack(struct stm32mp1_ddrctl *ctl)
|
|
{
|
|
- unsigned long start;
|
|
+ uint64_t start;
|
|
uint32_t swstat;
|
|
|
|
- mmio_setbits_32((uint32_t)&ctl->swctl, DDRCTRL_SWCTL_SW_DONE);
|
|
- VERBOSE("[0x%x] swctl = 0x%x\n",
|
|
- (uint32_t)&ctl->swctl, mmio_read_32((uint32_t)&ctl->swctl));
|
|
+ mmio_setbits_32((uintptr_t)&ctl->swctl, DDRCTRL_SWCTL_SW_DONE);
|
|
+ VERBOSE("[0x%lx] swctl = 0x%x\n",
|
|
+ (uintptr_t)&ctl->swctl, mmio_read_32((uintptr_t)&ctl->swctl));
|
|
|
|
- start = get_timer(0);
|
|
+ start = timeout_start();
|
|
do {
|
|
- swstat = mmio_read_32((uint32_t)&ctl->swstat);
|
|
- VERBOSE("[0x%x] swstat = 0x%x ",
|
|
- (uint32_t)&ctl->swstat, swstat);
|
|
- VERBOSE("timer in ms 0x%x = start 0x%lx\r",
|
|
- get_timer(0), start);
|
|
- if (get_timer(start) > plat_get_syscnt_freq2()) {
|
|
+ swstat = mmio_read_32((uintptr_t)&ctl->swstat);
|
|
+ VERBOSE("[0x%lx] swstat = 0x%x ",
|
|
+ (uintptr_t)&ctl->swstat, swstat);
|
|
+ VERBOSE("timer in ms 0x%llx = start 0x%llx\r",
|
|
+ timeout_start(), start);
|
|
+ if (timeout_elapsed(start, TIMEOUT_1S)) {
|
|
panic();
|
|
}
|
|
} while ((swstat & DDRCTRL_SWSTAT_SW_DONE_ACK) == 0U);
|
|
|
|
- VERBOSE("[0x%x] swstat = 0x%x\n",
|
|
- (uint32_t)&ctl->swstat, swstat);
|
|
+ VERBOSE("[0x%lx] swstat = 0x%x\n",
|
|
+ (uintptr_t)&ctl->swstat, swstat);
|
|
}
|
|
|
|
/* Wait quasi dynamic register update */
|
|
static void stm32mp1_wait_operating_mode(struct ddr_info *priv, uint32_t mode)
|
|
{
|
|
- unsigned long start;
|
|
+ uint64_t start;
|
|
uint32_t stat;
|
|
- uint32_t operating_mode;
|
|
- uint32_t selref_type;
|
|
int break_loop = 0;
|
|
|
|
- start = get_timer(0);
|
|
+ start = timeout_start();
|
|
for ( ; ; ) {
|
|
- stat = mmio_read_32((uint32_t)&priv->ctl->stat);
|
|
+ uint32_t operating_mode;
|
|
+ uint32_t selref_type;
|
|
+
|
|
+ stat = mmio_read_32((uintptr_t)&priv->ctl->stat);
|
|
operating_mode = stat & DDRCTRL_STAT_OPERATING_MODE_MASK;
|
|
selref_type = stat & DDRCTRL_STAT_SELFREF_TYPE_MASK;
|
|
- VERBOSE("[0x%x] stat = 0x%x\n",
|
|
- (uint32_t)&priv->ctl->stat, stat);
|
|
- VERBOSE("timer in ms 0x%x = start 0x%lx\r",
|
|
- get_timer(0), start);
|
|
- if (get_timer(start) > plat_get_syscnt_freq2()) {
|
|
+ VERBOSE("[0x%lx] stat = 0x%x\n",
|
|
+ (uintptr_t)&priv->ctl->stat, stat);
|
|
+ VERBOSE("timer in ms 0x%llx = start 0x%llx\r",
|
|
+ timeout_start(), start);
|
|
+ if (timeout_elapsed(start, TIMEOUT_1S)) {
|
|
panic();
|
|
}
|
|
|
|
@@ -439,8 +466,8 @@ static void stm32mp1_wait_operating_mode(struct ddr_info *priv, uint32_t mode)
|
|
}
|
|
}
|
|
|
|
- VERBOSE("[0x%x] stat = 0x%x\n",
|
|
- (uint32_t)&priv->ctl->stat, stat);
|
|
+ VERBOSE("[0x%lx] stat = 0x%x\n",
|
|
+ (uintptr_t)&priv->ctl->stat, stat);
|
|
}
|
|
|
|
/* Mode Register Writes (MRW or MRS) */
|
|
@@ -457,7 +484,7 @@ static void stm32mp1_mode_register_write(struct ddr_info *priv, uint8_t addr,
|
|
* No write should be performed to MRCTRL0 and MRCTRL1
|
|
* if MRSTAT.mr_wr_busy = 1.
|
|
*/
|
|
- while ((mmio_read_32((uint32_t)&priv->ctl->mrstat) &
|
|
+ while ((mmio_read_32((uintptr_t)&priv->ctl->mrstat) &
|
|
DDRCTRL_MRSTAT_MR_WR_BUSY) != 0U) {
|
|
;
|
|
}
|
|
@@ -470,14 +497,14 @@ static void stm32mp1_mode_register_write(struct ddr_info *priv, uint8_t addr,
|
|
DDRCTRL_MRCTRL0_MR_RANK_ALL |
|
|
(((uint32_t)addr << DDRCTRL_MRCTRL0_MR_ADDR_SHIFT) &
|
|
DDRCTRL_MRCTRL0_MR_ADDR_MASK);
|
|
- mmio_write_32((uint32_t)&priv->ctl->mrctrl0, mrctrl0);
|
|
- VERBOSE("[0x%x] mrctrl0 = 0x%x (0x%x)\n",
|
|
- (uint32_t)&priv->ctl->mrctrl0,
|
|
- mmio_read_32((uint32_t)&priv->ctl->mrctrl0), mrctrl0);
|
|
- mmio_write_32((uint32_t)&priv->ctl->mrctrl1, data);
|
|
- VERBOSE("[0x%x] mrctrl1 = 0x%x\n",
|
|
- (uint32_t)&priv->ctl->mrctrl1,
|
|
- mmio_read_32((uint32_t)&priv->ctl->mrctrl1));
|
|
+ mmio_write_32((uintptr_t)&priv->ctl->mrctrl0, mrctrl0);
|
|
+ VERBOSE("[0x%lx] mrctrl0 = 0x%x (0x%x)\n",
|
|
+ (uintptr_t)&priv->ctl->mrctrl0,
|
|
+ mmio_read_32((uintptr_t)&priv->ctl->mrctrl0), mrctrl0);
|
|
+ mmio_write_32((uintptr_t)&priv->ctl->mrctrl1, data);
|
|
+ VERBOSE("[0x%lx] mrctrl1 = 0x%x\n",
|
|
+ (uintptr_t)&priv->ctl->mrctrl1,
|
|
+ mmio_read_32((uintptr_t)&priv->ctl->mrctrl1));
|
|
|
|
/*
|
|
* 3. In a separate APB transaction, write the MRCTRL0.mr_wr to 1. This
|
|
@@ -487,22 +514,22 @@ static void stm32mp1_mode_register_write(struct ddr_info *priv, uint8_t addr,
|
|
* initiated until it is deasserted.
|
|
*/
|
|
mrctrl0 |= DDRCTRL_MRCTRL0_MR_WR;
|
|
- mmio_write_32((uint32_t)&priv->ctl->mrctrl0, mrctrl0);
|
|
+ mmio_write_32((uintptr_t)&priv->ctl->mrctrl0, mrctrl0);
|
|
|
|
- while ((mmio_read_32((uint32_t)&priv->ctl->mrstat) &
|
|
+ while ((mmio_read_32((uintptr_t)&priv->ctl->mrstat) &
|
|
DDRCTRL_MRSTAT_MR_WR_BUSY) != 0U) {
|
|
;
|
|
}
|
|
|
|
- VERBOSE("[0x%x] mrctrl0 = 0x%x\n",
|
|
- (uint32_t)&priv->ctl->mrctrl0, mrctrl0);
|
|
+ VERBOSE("[0x%lx] mrctrl0 = 0x%x\n",
|
|
+ (uintptr_t)&priv->ctl->mrctrl0, mrctrl0);
|
|
}
|
|
|
|
/* Switch DDR3 from DLL-on to DLL-off */
|
|
static void stm32mp1_ddr3_dll_off(struct ddr_info *priv)
|
|
{
|
|
- uint32_t mr1 = mmio_read_32((uint32_t)&priv->phy->mr1);
|
|
- uint32_t mr2 = mmio_read_32((uint32_t)&priv->phy->mr2);
|
|
+ uint32_t mr1 = mmio_read_32((uintptr_t)&priv->phy->mr1);
|
|
+ uint32_t mr2 = mmio_read_32((uintptr_t)&priv->phy->mr2);
|
|
uint32_t dbgcam;
|
|
|
|
VERBOSE("mr1: 0x%x\n", mr1);
|
|
@@ -512,10 +539,10 @@ static void stm32mp1_ddr3_dll_off(struct ddr_info *priv)
|
|
* 1. Set the DBG1.dis_hif = 1.
|
|
* This prevents further reads/writes being received on the HIF.
|
|
*/
|
|
- mmio_setbits_32((uint32_t)&priv->ctl->dbg1, DDRCTRL_DBG1_DIS_HIF);
|
|
- VERBOSE("[0x%x] dbg1 = 0x%x\n",
|
|
- (uint32_t)&priv->ctl->dbg1,
|
|
- mmio_read_32((uint32_t)&priv->ctl->dbg1));
|
|
+ mmio_setbits_32((uintptr_t)&priv->ctl->dbg1, DDRCTRL_DBG1_DIS_HIF);
|
|
+ VERBOSE("[0x%lx] dbg1 = 0x%x\n",
|
|
+ (uintptr_t)&priv->ctl->dbg1,
|
|
+ mmio_read_32((uintptr_t)&priv->ctl->dbg1));
|
|
|
|
/*
|
|
* 2. Ensure all commands have been flushed from the uMCTL2 by polling
|
|
@@ -526,9 +553,9 @@ static void stm32mp1_ddr3_dll_off(struct ddr_info *priv)
|
|
* DBGCAM.dbg_hpr_q_depth = 0.
|
|
*/
|
|
do {
|
|
- dbgcam = mmio_read_32((uint32_t)&priv->ctl->dbgcam);
|
|
- VERBOSE("[0x%x] dbgcam = 0x%x\n",
|
|
- (uint32_t)&priv->ctl->dbgcam, dbgcam);
|
|
+ dbgcam = mmio_read_32((uintptr_t)&priv->ctl->dbgcam);
|
|
+ VERBOSE("[0x%lx] dbgcam = 0x%x\n",
|
|
+ (uintptr_t)&priv->ctl->dbgcam, dbgcam);
|
|
} while ((((dbgcam & DDRCTRL_DBGCAM_DATA_PIPELINE_EMPTY) ==
|
|
DDRCTRL_DBGCAM_DATA_PIPELINE_EMPTY)) &&
|
|
((dbgcam & DDRCTRL_DBGCAM_DBG_Q_DEPTH) == 0U));
|
|
@@ -572,11 +599,11 @@ static void stm32mp1_ddr3_dll_off(struct ddr_info *priv)
|
|
* PWRCTL.selfref_sw = 1, and polling STAT.operating_mode to ensure
|
|
* the DDRC has entered self-refresh.
|
|
*/
|
|
- mmio_setbits_32((uint32_t)&priv->ctl->pwrctl,
|
|
+ mmio_setbits_32((uintptr_t)&priv->ctl->pwrctl,
|
|
DDRCTRL_PWRCTL_SELFREF_SW);
|
|
- VERBOSE("[0x%x] pwrctl = 0x%x\n",
|
|
- (uint32_t)&priv->ctl->pwrctl,
|
|
- mmio_read_32((uint32_t)&priv->ctl->pwrctl));
|
|
+ VERBOSE("[0x%lx] pwrctl = 0x%x\n",
|
|
+ (uintptr_t)&priv->ctl->pwrctl,
|
|
+ mmio_read_32((uintptr_t)&priv->ctl->pwrctl));
|
|
|
|
/*
|
|
* 8. Wait until STAT.operating_mode[1:0]==11 indicating that the
|
|
@@ -592,10 +619,10 @@ static void stm32mp1_ddr3_dll_off(struct ddr_info *priv)
|
|
*/
|
|
stm32mp1_start_sw_done(priv->ctl);
|
|
|
|
- mmio_setbits_32((uint32_t)&priv->ctl->mstr, DDRCTRL_MSTR_DLL_OFF_MODE);
|
|
- VERBOSE("[0x%x] mstr = 0x%x\n",
|
|
- (uint32_t)&priv->ctl->mstr,
|
|
- mmio_read_32((uint32_t)&priv->ctl->mstr));
|
|
+ mmio_setbits_32((uintptr_t)&priv->ctl->mstr, DDRCTRL_MSTR_DLL_OFF_MODE);
|
|
+ VERBOSE("[0x%lx] mstr = 0x%x\n",
|
|
+ (uintptr_t)&priv->ctl->mstr,
|
|
+ mmio_read_32((uintptr_t)&priv->ctl->mstr));
|
|
|
|
stm32mp1_wait_sw_done_ack(priv->ctl);
|
|
|
|
@@ -608,27 +635,27 @@ static void stm32mp1_ddr3_dll_off(struct ddr_info *priv)
|
|
*/
|
|
|
|
/* Change Bypass Mode Frequency Range */
|
|
- if (stm32mp1_clk_get_rate(DDRPHYC) < 100000000U) {
|
|
- mmio_clrbits_32((uint32_t)&priv->phy->dllgcr,
|
|
+ if (stm32mp_clk_get_rate(DDRPHYC) < 100000000U) {
|
|
+ mmio_clrbits_32((uintptr_t)&priv->phy->dllgcr,
|
|
DDRPHYC_DLLGCR_BPS200);
|
|
} else {
|
|
- mmio_setbits_32((uint32_t)&priv->phy->dllgcr,
|
|
+ mmio_setbits_32((uintptr_t)&priv->phy->dllgcr,
|
|
DDRPHYC_DLLGCR_BPS200);
|
|
}
|
|
|
|
- mmio_setbits_32((uint32_t)&priv->phy->acdllcr, DDRPHYC_ACDLLCR_DLLDIS);
|
|
+ mmio_setbits_32((uintptr_t)&priv->phy->acdllcr, DDRPHYC_ACDLLCR_DLLDIS);
|
|
|
|
- mmio_setbits_32((uint32_t)&priv->phy->dx0dllcr,
|
|
+ mmio_setbits_32((uintptr_t)&priv->phy->dx0dllcr,
|
|
DDRPHYC_DXNDLLCR_DLLDIS);
|
|
- mmio_setbits_32((uint32_t)&priv->phy->dx1dllcr,
|
|
+ mmio_setbits_32((uintptr_t)&priv->phy->dx1dllcr,
|
|
DDRPHYC_DXNDLLCR_DLLDIS);
|
|
- mmio_setbits_32((uint32_t)&priv->phy->dx2dllcr,
|
|
+ mmio_setbits_32((uintptr_t)&priv->phy->dx2dllcr,
|
|
DDRPHYC_DXNDLLCR_DLLDIS);
|
|
- mmio_setbits_32((uint32_t)&priv->phy->dx3dllcr,
|
|
+ mmio_setbits_32((uintptr_t)&priv->phy->dx3dllcr,
|
|
DDRPHYC_DXNDLLCR_DLLDIS);
|
|
|
|
/* 12. Exit the self-refresh state by setting PWRCTL.selfref_sw = 0. */
|
|
- mmio_clrbits_32((uint32_t)&priv->ctl->pwrctl,
|
|
+ mmio_clrbits_32((uintptr_t)&priv->ctl->pwrctl,
|
|
DDRCTRL_PWRCTL_SELFREF_SW);
|
|
stm32mp1_wait_operating_mode(priv, DDRCTRL_STAT_OPERATING_MODE_NORMAL);
|
|
|
|
@@ -644,20 +671,20 @@ static void stm32mp1_ddr3_dll_off(struct ddr_info *priv)
|
|
*/
|
|
|
|
/* 15. Write DBG1.dis_hif = 0 to re-enable reads and writes. */
|
|
- mmio_clrbits_32((uint32_t)&priv->ctl->dbg1, DDRCTRL_DBG1_DIS_HIF);
|
|
- VERBOSE("[0x%x] dbg1 = 0x%x\n",
|
|
- (uint32_t)&priv->ctl->dbg1,
|
|
- mmio_read_32((uint32_t)&priv->ctl->dbg1));
|
|
+ mmio_clrbits_32((uintptr_t)&priv->ctl->dbg1, DDRCTRL_DBG1_DIS_HIF);
|
|
+ VERBOSE("[0x%lx] dbg1 = 0x%x\n",
|
|
+ (uintptr_t)&priv->ctl->dbg1,
|
|
+ mmio_read_32((uintptr_t)&priv->ctl->dbg1));
|
|
}
|
|
|
|
static void stm32mp1_refresh_disable(struct stm32mp1_ddrctl *ctl)
|
|
{
|
|
stm32mp1_start_sw_done(ctl);
|
|
/* Quasi-dynamic register update*/
|
|
- mmio_setbits_32((uint32_t)&ctl->rfshctl3,
|
|
+ mmio_setbits_32((uintptr_t)&ctl->rfshctl3,
|
|
DDRCTRL_RFSHCTL3_DIS_AUTO_REFRESH);
|
|
- mmio_clrbits_32((uint32_t)&ctl->pwrctl, DDRCTRL_PWRCTL_POWERDOWN_EN);
|
|
- mmio_clrbits_32((uint32_t)&ctl->dfimisc,
|
|
+ mmio_clrbits_32((uintptr_t)&ctl->pwrctl, DDRCTRL_PWRCTL_POWERDOWN_EN);
|
|
+ mmio_clrbits_32((uintptr_t)&ctl->dfimisc,
|
|
DDRCTRL_DFIMISC_DFI_INIT_COMPLETE_EN);
|
|
stm32mp1_wait_sw_done_ack(ctl);
|
|
}
|
|
@@ -667,21 +694,99 @@ static void stm32mp1_refresh_restore(struct stm32mp1_ddrctl *ctl,
|
|
{
|
|
stm32mp1_start_sw_done(ctl);
|
|
if ((rfshctl3 & DDRCTRL_RFSHCTL3_DIS_AUTO_REFRESH) == 0U) {
|
|
- mmio_clrbits_32((uint32_t)&ctl->rfshctl3,
|
|
+ mmio_clrbits_32((uintptr_t)&ctl->rfshctl3,
|
|
DDRCTRL_RFSHCTL3_DIS_AUTO_REFRESH);
|
|
}
|
|
if ((pwrctl & DDRCTRL_PWRCTL_POWERDOWN_EN) != 0U) {
|
|
- mmio_setbits_32((uint32_t)&ctl->pwrctl,
|
|
+ mmio_setbits_32((uintptr_t)&ctl->pwrctl,
|
|
DDRCTRL_PWRCTL_POWERDOWN_EN);
|
|
}
|
|
- mmio_setbits_32((uint32_t)&ctl->dfimisc,
|
|
+ mmio_setbits_32((uintptr_t)&ctl->dfimisc,
|
|
DDRCTRL_DFIMISC_DFI_INIT_COMPLETE_EN);
|
|
stm32mp1_wait_sw_done_ack(ctl);
|
|
}
|
|
|
|
+static void stm32mp1_refresh_cmd(struct stm32mp1_ddrctl *ctl)
|
|
+{
|
|
+ uint32_t dbgstat;
|
|
+
|
|
+ do {
|
|
+ dbgstat = mmio_read_32((uintptr_t)&ctl->dbgstat);
|
|
+ } while ((dbgstat & DDRCTRL_DBGSTAT_RANK0_REFRESH_BUSY) != 0U);
|
|
+
|
|
+ mmio_setbits_32((uintptr_t)&ctl->dbgcmd, DDRCTRL_DBGCMD_RANK0_REFRESH);
|
|
+}
|
|
+
|
|
+/* Refresh compensation by forcing refresh command
|
|
+ * Rule1: Tref should be always < tREFW ? R x tREBW/8
|
|
+ * Rule2: refcomp = RU(Tref/tREFI) = RU(RxTref/tREFW)
|
|
+ */
|
|
+static
|
|
+void stm32mp1_refresh_compensation(const struct stm32mp1_ddr_config *config,
|
|
+ struct stm32mp1_ddrctl *ctl,
|
|
+ uint64_t start)
|
|
+{
|
|
+ uint32_t tck_ps;
|
|
+ uint64_t time, time_us, tref, trefi, refcomp, i;
|
|
+
|
|
+ time = timeout_start() - start;
|
|
+ time_us = time / TIMESLOT_1US;
|
|
+ tck_ps = 1000000000U / config->info.speed;
|
|
+ if (tck_ps == 0U) {
|
|
+ return;
|
|
+ }
|
|
+ /* ref = refresh time in tck */
|
|
+ tref = time_us * 1000000U / tck_ps;
|
|
+ trefi = ((mmio_read_32((uintptr_t)&ctl->rfshtmg) &
|
|
+ DDRCTRL_RFSHTMG_T_RFC_NOM_X1_X32_MASK)
|
|
+ >> DDRCTRL_RFSHTMG_T_RFC_NOM_X1_X32_SHIFT) * 32U;
|
|
+ if (trefi == 0U) {
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ /* div round up : number of refresh to compensate */
|
|
+ refcomp = (tref + trefi - 1U) / trefi;
|
|
+
|
|
+ for (i = 0; i < refcomp; i++) {
|
|
+ stm32mp1_refresh_cmd(ctl);
|
|
+ }
|
|
+}
|
|
+
|
|
+static void stm32mp1_self_refresh_zcal(struct ddr_info *priv, uint32_t zdata)
|
|
+{
|
|
+ /* sequence for PUBL I/O Data Retention during Power-Down */
|
|
+
|
|
+ /* 10. Override ZQ calibration with previously (pre-retention)
|
|
+ * calibrated values. This is done by writing 1 to ZQ0CRN.ZDEN
|
|
+ * and the override data to ZQ0CRN.ZDATA.
|
|
+ */
|
|
+ mmio_setbits_32((uintptr_t)&priv->phy->zq0cr0, DDRPHYC_ZQ0CRN_ZDEN);
|
|
+
|
|
+ mmio_clrsetbits_32((uintptr_t)&priv->phy->zq0cr0,
|
|
+ DDRPHYC_ZQ0CRN_ZDATA_MASK,
|
|
+ zdata << DDRPHYC_ZQ0CRN_ZDATA_SHIFT);
|
|
+
|
|
+ /* 11. De-assert the PHY_top data retention enable signals
|
|
+ * (ret_en or ret_en_i/ret_en_n_i).
|
|
+ */
|
|
+ mmio_setbits_32((uintptr_t)(priv->pwr) + PWR_CR3, PWR_CR3_DDRSRDIS);
|
|
+ mmio_clrbits_32((uintptr_t)(priv->pwr) + PWR_CR3, PWR_CR3_DDRRETEN);
|
|
+
|
|
+ /* 12. Remove ZQ calibration override by writing 0 to ZQ0CRN.ZDEN. */
|
|
+ mmio_clrbits_32((uintptr_t)&priv->phy->zq0cr0, DDRPHYC_ZQ0CRN_ZDEN);
|
|
+
|
|
+ /* 13. Trigger ZQ calibration by writing 1 to PIR.INIT
|
|
+ * and '1' to PIR.ZCAL
|
|
+ */
|
|
+ /* 14. Wait for ZQ calibration to finish by polling a 1 status
|
|
+ * on PGSR.IDONE.
|
|
+ */
|
|
+ stm32mp1_ddrphy_init(priv->phy, DDRPHYC_PIR_ZCAL);
|
|
+}
|
|
+
|
|
static int board_ddr_power_init(enum ddr_type ddr_type)
|
|
{
|
|
- if (dt_check_pmic()) {
|
|
+ if (dt_pmic_status() > 0) {
|
|
return pmic_ddr_power_init(ddr_type);
|
|
}
|
|
|
|
@@ -691,13 +796,18 @@ static int board_ddr_power_init(enum ddr_type ddr_type)
|
|
void stm32mp1_ddr_init(struct ddr_info *priv,
|
|
struct stm32mp1_ddr_config *config)
|
|
{
|
|
- uint32_t pir;
|
|
- int ret;
|
|
+ uint32_t pir, ddr_reten;
|
|
+ int ret = -EINVAL;
|
|
+ uint64_t time;
|
|
|
|
if ((config->c_reg.mstr & DDRCTRL_MSTR_DDR3) != 0U) {
|
|
ret = board_ddr_power_init(STM32MP_DDR3);
|
|
- } else {
|
|
+ } else if ((config->c_reg.mstr & DDRCTRL_MSTR_LPDDR2) != 0U) {
|
|
ret = board_ddr_power_init(STM32MP_LPDDR2);
|
|
+ } else if ((config->c_reg.mstr & DDRCTRL_MSTR_LPDDR3) != 0U) {
|
|
+ ret = board_ddr_power_init(STM32MP_LPDDR3);
|
|
+ } else {
|
|
+ ERROR("DDR type not supported\n");
|
|
}
|
|
|
|
if (ret != 0) {
|
|
@@ -705,8 +815,29 @@ void stm32mp1_ddr_init(struct ddr_info *priv,
|
|
}
|
|
|
|
VERBOSE("name = %s\n", config->info.name);
|
|
- VERBOSE("speed = %d MHz\n", config->info.speed);
|
|
+ VERBOSE("speed = %d kHz\n", config->info.speed);
|
|
VERBOSE("size = 0x%x\n", config->info.size);
|
|
+ if (config->self_refresh) {
|
|
+ VERBOSE("sel-refresh exit (zdata = 0x%x)\n", config->zdata);
|
|
+ }
|
|
+
|
|
+ /* Check DDR PHY pads retention */
|
|
+ ddr_reten = mmio_read_32((uint32_t)(priv->pwr) + PWR_CR3) &
|
|
+ PWR_CR3_DDRRETEN;
|
|
+ if (config->self_refresh) {
|
|
+ if (ddr_reten == 0U) {
|
|
+ VERBOSE("self-refresh aborted: no retention\n");
|
|
+ config->self_refresh = false;
|
|
+ }
|
|
+ } else {
|
|
+ if (ddr_reten != 0U) {
|
|
+ VERBOSE("disable DDR PHY retention\n");
|
|
+ mmio_setbits_32((uint32_t)(priv->pwr) + PWR_CR3,
|
|
+ PWR_CR3_DDRSRDIS);
|
|
+ mmio_clrbits_32((uint32_t)(priv->pwr) + PWR_CR3,
|
|
+ PWR_CR3_DDRRETEN);
|
|
+ }
|
|
+ }
|
|
|
|
/* DDR INIT SEQUENCE */
|
|
|
|
@@ -744,11 +875,11 @@ void stm32mp1_ddr_init(struct ddr_info *priv,
|
|
|
|
/* 1.5. initialize registers ddr_umctl2 */
|
|
/* Stop uMCTL2 before PHY is ready */
|
|
- mmio_clrbits_32((uint32_t)&priv->ctl->dfimisc,
|
|
+ mmio_clrbits_32((uintptr_t)&priv->ctl->dfimisc,
|
|
DDRCTRL_DFIMISC_DFI_INIT_COMPLETE_EN);
|
|
- VERBOSE("[0x%x] dfimisc = 0x%x\n",
|
|
- (uint32_t)&priv->ctl->dfimisc,
|
|
- mmio_read_32((uint32_t)&priv->ctl->dfimisc));
|
|
+ VERBOSE("[0x%lx] dfimisc = 0x%x\n",
|
|
+ (uintptr_t)&priv->ctl->dfimisc,
|
|
+ mmio_read_32((uintptr_t)&priv->ctl->dfimisc));
|
|
|
|
set_reg(priv, REG_REG, &config->c_reg);
|
|
|
|
@@ -757,23 +888,31 @@ void stm32mp1_ddr_init(struct ddr_info *priv,
|
|
(DDRCTRL_MSTR_DDR3 | DDRCTRL_MSTR_DLL_OFF_MODE))
|
|
== (DDRCTRL_MSTR_DDR3 | DDRCTRL_MSTR_DLL_OFF_MODE)) {
|
|
VERBOSE("deactivate DLL OFF in mstr\n");
|
|
- mmio_clrbits_32((uint32_t)&priv->ctl->mstr,
|
|
+ mmio_clrbits_32((uintptr_t)&priv->ctl->mstr,
|
|
DDRCTRL_MSTR_DLL_OFF_MODE);
|
|
- VERBOSE("[0x%x] mstr = 0x%x\n",
|
|
- (uint32_t)&priv->ctl->mstr,
|
|
- mmio_read_32((uint32_t)&priv->ctl->mstr));
|
|
+ VERBOSE("[0x%lx] mstr = 0x%x\n",
|
|
+ (uintptr_t)&priv->ctl->mstr,
|
|
+ mmio_read_32((uintptr_t)&priv->ctl->mstr));
|
|
}
|
|
|
|
set_reg(priv, REG_TIMING, &config->c_timing);
|
|
set_reg(priv, REG_MAP, &config->c_map);
|
|
|
|
- /* Skip CTRL init, SDRAM init is done by PHY PUBL */
|
|
- mmio_clrsetbits_32((uint32_t)&priv->ctl->init0,
|
|
- DDRCTRL_INIT0_SKIP_DRAM_INIT_MASK,
|
|
- DDRCTRL_INIT0_SKIP_DRAM_INIT_NORMAL);
|
|
- VERBOSE("[0x%x] init0 = 0x%x\n",
|
|
- (uint32_t)&priv->ctl->init0,
|
|
- mmio_read_32((uint32_t)&priv->ctl->init0));
|
|
+ /* Keep the controller in self-refresh mode */
|
|
+ if (config->self_refresh) {
|
|
+ mmio_setbits_32((uintptr_t)&priv->ctl->pwrctl,
|
|
+ DDRCTRL_PWRCTL_SELFREF_SW);
|
|
+ }
|
|
+
|
|
+ {
|
|
+ /* Skip CTRL init, SDRAM init is done by PHY PUBL */
|
|
+ mmio_clrsetbits_32((uintptr_t)&priv->ctl->init0,
|
|
+ DDRCTRL_INIT0_SKIP_DRAM_INIT_MASK,
|
|
+ DDRCTRL_INIT0_SKIP_DRAM_INIT_NORMAL);
|
|
+ VERBOSE("[0x%lx] init0 = 0x%x\n",
|
|
+ (uintptr_t)&priv->ctl->init0,
|
|
+ mmio_read_32((uintptr_t)&priv->ctl->init0));
|
|
+ }
|
|
|
|
set_reg(priv, REG_PERF, &config->c_perf);
|
|
|
|
@@ -786,6 +925,7 @@ void stm32mp1_ddr_init(struct ddr_info *priv,
|
|
* 3. start PHY init by accessing relevant PUBL registers
|
|
* (DXGCR, DCR, PTR*, MR*, DTPR*)
|
|
*/
|
|
+
|
|
set_reg(priv, REGPHY_REG, &config->p_reg);
|
|
set_reg(priv, REGPHY_TIMING, &config->p_timing);
|
|
set_reg(priv, REGPHY_CAL, &config->p_cal);
|
|
@@ -795,10 +935,10 @@ void stm32mp1_ddr_init(struct ddr_info *priv,
|
|
(DDRCTRL_MSTR_DDR3 | DDRCTRL_MSTR_DLL_OFF_MODE))
|
|
== (DDRCTRL_MSTR_DDR3 | DDRCTRL_MSTR_DLL_OFF_MODE)) {
|
|
VERBOSE("deactivate DLL OFF in mr1\n");
|
|
- mmio_clrbits_32((uint32_t)&priv->phy->mr1, BIT(0));
|
|
- VERBOSE("[0x%x] mr1 = 0x%x\n",
|
|
- (uint32_t)&priv->phy->mr1,
|
|
- mmio_read_32((uint32_t)&priv->phy->mr1));
|
|
+ mmio_clrbits_32((uintptr_t)&priv->phy->mr1, BIT(0));
|
|
+ VERBOSE("[0x%lx] mr1 = 0x%x\n",
|
|
+ (uintptr_t)&priv->phy->mr1,
|
|
+ mmio_read_32((uintptr_t)&priv->phy->mr1));
|
|
}
|
|
|
|
/*
|
|
@@ -820,19 +960,31 @@ void stm32mp1_ddr_init(struct ddr_info *priv,
|
|
pir |= DDRPHYC_PIR_DRAMRST; /* Only for DDR3 */
|
|
}
|
|
|
|
+ /* Treat self-refresh exit : hot boot */
|
|
+ if (config->self_refresh) {
|
|
+ /* DDR in self refresh mode, remove zcal & reset & init */
|
|
+ pir &= ~(DDRPHYC_PIR_ZCAL & DDRPHYC_PIR_DRAMRST
|
|
+ & DDRPHYC_PIR_DRAMINIT);
|
|
+ pir |= DDRPHYC_PIR_ZCALBYP;
|
|
+ }
|
|
+
|
|
stm32mp1_ddrphy_init(priv->phy, pir);
|
|
|
|
+ if (config->self_refresh) {
|
|
+ stm32mp1_self_refresh_zcal(priv, config->zdata);
|
|
+ }
|
|
+
|
|
/*
|
|
* 6. SET DFIMISC.dfi_init_complete_en to 1
|
|
* Enable quasi-dynamic register programming.
|
|
*/
|
|
stm32mp1_start_sw_done(priv->ctl);
|
|
|
|
- mmio_setbits_32((uint32_t)&priv->ctl->dfimisc,
|
|
+ mmio_setbits_32((uintptr_t)&priv->ctl->dfimisc,
|
|
DDRCTRL_DFIMISC_DFI_INIT_COMPLETE_EN);
|
|
- VERBOSE("[0x%x] dfimisc = 0x%x\n",
|
|
- (uint32_t)&priv->ctl->dfimisc,
|
|
- mmio_read_32((uint32_t)&priv->ctl->dfimisc));
|
|
+ VERBOSE("[0x%lx] dfimisc = 0x%x\n",
|
|
+ (uintptr_t)&priv->ctl->dfimisc,
|
|
+ mmio_read_32((uintptr_t)&priv->ctl->dfimisc));
|
|
|
|
stm32mp1_wait_sw_done_ack(priv->ctl);
|
|
|
|
@@ -842,6 +994,13 @@ void stm32mp1_ddr_init(struct ddr_info *priv,
|
|
*/
|
|
|
|
/* Wait uMCTL2 ready */
|
|
+
|
|
+ /* Trigger self-refresh exit */
|
|
+ if (config->self_refresh) {
|
|
+ mmio_clrbits_32((uintptr_t)&priv->ctl->pwrctl,
|
|
+ DDRCTRL_PWRCTL_SELFREF_SW);
|
|
+ }
|
|
+
|
|
stm32mp1_wait_operating_mode(priv, DDRCTRL_STAT_OPERATING_MODE_NORMAL);
|
|
|
|
/* Switch to DLL OFF mode */
|
|
@@ -851,6 +1010,8 @@ void stm32mp1_ddr_init(struct ddr_info *priv,
|
|
|
|
VERBOSE("DDR DQS training : ");
|
|
|
|
+ time = timeout_start();
|
|
+
|
|
/*
|
|
* 8. Disable Auto refresh and power down by setting
|
|
* - RFSHCTL3.dis_au_refresh = 1
|
|
@@ -875,6 +1036,11 @@ void stm32mp1_ddr_init(struct ddr_info *priv,
|
|
/* 11. monitor PUB PGSR.IDONE to poll cpmpletion of training sequence */
|
|
stm32mp1_ddrphy_idone_wait(priv->phy);
|
|
|
|
+ /* Refresh compensation: forcing refresh command */
|
|
+ if (config->self_refresh) {
|
|
+ stm32mp1_refresh_compensation(config, priv->ctl, time);
|
|
+ }
|
|
+
|
|
/*
|
|
* 12. set back registers in step 8 to the orginal values if desidered
|
|
*/
|
|
@@ -882,14 +1048,16 @@ void stm32mp1_ddr_init(struct ddr_info *priv,
|
|
config->c_reg.pwrctl);
|
|
|
|
/* Enable uMCTL2 AXI port 0 */
|
|
- mmio_setbits_32((uint32_t)&priv->ctl->pctrl_0, DDRCTRL_PCTRL_N_PORT_EN);
|
|
- VERBOSE("[0x%x] pctrl_0 = 0x%x\n",
|
|
- (uint32_t)&priv->ctl->pctrl_0,
|
|
- mmio_read_32((uint32_t)&priv->ctl->pctrl_0));
|
|
+ mmio_setbits_32((uintptr_t)&priv->ctl->pctrl_0,
|
|
+ DDRCTRL_PCTRL_N_PORT_EN);
|
|
+ VERBOSE("[0x%lx] pctrl_0 = 0x%x\n",
|
|
+ (uintptr_t)&priv->ctl->pctrl_0,
|
|
+ mmio_read_32((uintptr_t)&priv->ctl->pctrl_0));
|
|
|
|
/* Enable uMCTL2 AXI port 1 */
|
|
- mmio_setbits_32((uint32_t)&priv->ctl->pctrl_1, DDRCTRL_PCTRL_N_PORT_EN);
|
|
- VERBOSE("[0x%x] pctrl_1 = 0x%x\n",
|
|
- (uint32_t)&priv->ctl->pctrl_1,
|
|
- mmio_read_32((uint32_t)&priv->ctl->pctrl_1));
|
|
+ mmio_setbits_32((uintptr_t)&priv->ctl->pctrl_1,
|
|
+ DDRCTRL_PCTRL_N_PORT_EN);
|
|
+ VERBOSE("[0x%lx] pctrl_1 = 0x%x\n",
|
|
+ (uintptr_t)&priv->ctl->pctrl_1,
|
|
+ mmio_read_32((uintptr_t)&priv->ctl->pctrl_1));
|
|
}
|
|
diff --git a/drivers/st/ddr/stm32mp1_ddr_helpers.c b/drivers/st/ddr/stm32mp1_ddr_helpers.c
|
|
index 325c0b8..63f254f 100644
|
|
--- a/drivers/st/ddr/stm32mp1_ddr_helpers.c
|
|
+++ b/drivers/st/ddr/stm32mp1_ddr_helpers.c
|
|
@@ -4,17 +4,521 @@
|
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
*/
|
|
|
|
+#include <arch_helpers.h>
|
|
+#include <debug.h>
|
|
+#include <delay_timer.h>
|
|
#include <mmio.h>
|
|
+#include <platform.h>
|
|
#include <platform_def.h>
|
|
-#include <stm32mp1_ddr_helpers.h>
|
|
-#include <stm32mp1_rcc.h>
|
|
+#include <stm32mp_common.h>
|
|
+
|
|
+#define TIMEOUT_500US us2tick(500)
|
|
|
|
void ddr_enable_clock(void)
|
|
{
|
|
- mmio_setbits_32(RCC_BASE + RCC_DDRITFCR,
|
|
+ stm32mp1_clk_rcc_regs_lock();
|
|
+
|
|
+ mmio_setbits_32(stm32mp_rcc_base() + RCC_DDRITFCR,
|
|
RCC_DDRITFCR_DDRC1EN |
|
|
RCC_DDRITFCR_DDRC2EN |
|
|
RCC_DDRITFCR_DDRPHYCEN |
|
|
RCC_DDRITFCR_DDRPHYCAPBEN |
|
|
RCC_DDRITFCR_DDRCAPBEN);
|
|
+
|
|
+ stm32mp1_clk_rcc_regs_unlock();
|
|
+}
|
|
+
|
|
+static void do_sw_handshake(void)
|
|
+{
|
|
+ uintptr_t ddrctrl_base = stm32mp_ddrctrl_base();
|
|
+
|
|
+ mmio_clrbits_32(ddrctrl_base + DDRCTRL_SWCTL, DDRCTRL_SWCTL_SW_DONE);
|
|
+}
|
|
+
|
|
+static void do_sw_ack(void)
|
|
+{
|
|
+ uint64_t start;
|
|
+ uintptr_t ddrctrl_base = stm32mp_ddrctrl_base();
|
|
+
|
|
+ mmio_setbits_32(ddrctrl_base + DDRCTRL_SWCTL, DDRCTRL_SWCTL_SW_DONE);
|
|
+
|
|
+ start = timeout_start();
|
|
+ while ((mmio_read_32(ddrctrl_base + DDRCTRL_SWSTAT) &
|
|
+ DDRCTRL_SWSTAT_SW_DONE_ACK) == 0U) {
|
|
+ if (timeout_elapsed(start, TIMEOUT_500US)) {
|
|
+ panic();
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
+static int ddr_sw_self_refresh_in(void)
|
|
+{
|
|
+ uint64_t start;
|
|
+ uint32_t stat;
|
|
+ uint32_t operating_mode;
|
|
+ uint32_t selref_type;
|
|
+ uint8_t op_mode_changed = 0;
|
|
+ uintptr_t rcc_base = stm32mp_rcc_base();
|
|
+ uintptr_t pwr_base = stm32mp_pwr_base();
|
|
+ uintptr_t ddrctrl_base = stm32mp_ddrctrl_base();
|
|
+ uintptr_t ddrphyc_base = stm32mp_ddrphyc_base();
|
|
+
|
|
+ stm32mp1_clk_rcc_regs_lock();
|
|
+
|
|
+ mmio_clrbits_32(rcc_base + RCC_DDRITFCR, RCC_DDRITFCR_AXIDCGEN);
|
|
+
|
|
+ stm32mp1_clk_rcc_regs_unlock();
|
|
+
|
|
+ /* Blocks AXI ports from taking anymore transactions */
|
|
+ mmio_clrbits_32(ddrctrl_base + DDRCTRL_PCTRL_0,
|
|
+ DDRCTRL_PCTRL_N_PORT_EN);
|
|
+ mmio_clrbits_32(ddrctrl_base + DDRCTRL_PCTRL_1,
|
|
+ DDRCTRL_PCTRL_N_PORT_EN);
|
|
+
|
|
+ /* Waits unit all AXI ports are idle
|
|
+ * Poll PSTAT.rd_port_busy_n = 0
|
|
+ * Poll PSTAT.wr_port_busy_n = 0
|
|
+ */
|
|
+ start = timeout_start();
|
|
+ while (mmio_read_32(ddrctrl_base + DDRCTRL_PSTAT)) {
|
|
+ if (timeout_elapsed(start, TIMEOUT_500US)) {
|
|
+ goto pstat_failed;
|
|
+ }
|
|
+ }
|
|
+ /* SW Self-Refresh entry */
|
|
+ mmio_setbits_32(ddrctrl_base + DDRCTRL_PWRCTL,
|
|
+ DDRCTRL_PWRCTL_SELFREF_SW);
|
|
+
|
|
+ /* Wait operating mode change in self-refresh mode
|
|
+ * with STAT.operating_mode[1:0]==11.
|
|
+ * Ensure transition to self-refresh was due to software
|
|
+ * by checking also that STAT.selfref_type[1:0]=2.
|
|
+ */
|
|
+ start = timeout_start();
|
|
+ while (!timeout_elapsed(start, TIMEOUT_500US)) {
|
|
+ stat = mmio_read_32(ddrctrl_base + DDRCTRL_STAT);
|
|
+ operating_mode = stat & DDRCTRL_STAT_OPERATING_MODE_MASK;
|
|
+ selref_type = stat & DDRCTRL_STAT_SELFREF_TYPE_MASK;
|
|
+
|
|
+ if ((operating_mode == DDRCTRL_STAT_OPERATING_MODE_SR) &&
|
|
+ (selref_type == DDRCTRL_STAT_SELFREF_TYPE_SR)) {
|
|
+ op_mode_changed = 1;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (op_mode_changed == 0U)
|
|
+ goto selfref_sw_failed;
|
|
+
|
|
+ /* IOs powering down (PUBL registers) */
|
|
+ mmio_setbits_32(ddrphyc_base + DDRPHYC_ACIOCR, DDRPHYC_ACIOCR_ACPDD);
|
|
+
|
|
+ mmio_setbits_32(ddrphyc_base + DDRPHYC_ACIOCR, DDRPHYC_ACIOCR_ACPDR);
|
|
+
|
|
+ mmio_clrsetbits_32(ddrphyc_base + DDRPHYC_ACIOCR,
|
|
+ DDRPHYC_ACIOCR_CKPDD_MASK,
|
|
+ DDRPHYC_ACIOCR_CKPDD_0);
|
|
+
|
|
+ mmio_clrsetbits_32(ddrphyc_base + DDRPHYC_ACIOCR,
|
|
+ DDRPHYC_ACIOCR_CKPDR_MASK,
|
|
+ DDRPHYC_ACIOCR_CKPDR_0);
|
|
+
|
|
+ mmio_clrsetbits_32(ddrphyc_base + DDRPHYC_ACIOCR,
|
|
+ DDRPHYC_ACIOCR_CSPDD_MASK,
|
|
+ DDRPHYC_ACIOCR_CSPDD_0);
|
|
+
|
|
+ mmio_setbits_32(ddrphyc_base + DDRPHYC_DXCCR, DDRPHYC_DXCCR_DXPDD);
|
|
+
|
|
+ mmio_setbits_32(ddrphyc_base + DDRPHYC_DXCCR, DDRPHYC_DXCCR_DXPDR);
|
|
+
|
|
+ mmio_clrsetbits_32(ddrphyc_base + DDRPHYC_DSGCR,
|
|
+ DDRPHYC_DSGCR_ODTPDD_MASK,
|
|
+ DDRPHYC_DSGCR_ODTPDD_0);
|
|
+
|
|
+ mmio_setbits_32(ddrphyc_base + DDRPHYC_DSGCR, DDRPHYC_DSGCR_NL2PD);
|
|
+
|
|
+ mmio_clrsetbits_32(ddrphyc_base + DDRPHYC_DSGCR,
|
|
+ DDRPHYC_DSGCR_CKEPDD_MASK,
|
|
+ DDRPHYC_DSGCR_CKEPDD_0);
|
|
+
|
|
+ /* Disable PZQ cell (PUBL register) */
|
|
+ mmio_setbits_32(ddrphyc_base + DDRPHYC_ZQ0CR0, DDRPHYC_ZQ0CRN_ZQPD);
|
|
+
|
|
+ /* Activate sw retention in PWRCTRL */
|
|
+ pwr_regs_lock();
|
|
+ mmio_setbits_32(pwr_base + PWR_CR3, PWR_CR3_DDRRETEN);
|
|
+ pwr_regs_unlock();
|
|
+
|
|
+ /* Switch controller clocks (uMCTL2/PUBL) to DLL ref clock */
|
|
+ stm32mp1_clk_rcc_regs_lock();
|
|
+ mmio_setbits_32(rcc_base + RCC_DDRITFCR, RCC_DDRITFCR_GSKPCTRL);
|
|
+ stm32mp1_clk_rcc_regs_unlock();
|
|
+
|
|
+ /* Disable all DLLs: GLITCH window */
|
|
+ mmio_setbits_32(ddrphyc_base + DDRPHYC_ACDLLCR,
|
|
+ DDRPHYC_ACDLLCR_DLLDIS);
|
|
+
|
|
+ mmio_setbits_32(ddrphyc_base + DDRPHYC_DX0DLLCR,
|
|
+ DDRPHYC_DXNDLLCR_DLLDIS);
|
|
+
|
|
+ mmio_setbits_32(ddrphyc_base + DDRPHYC_DX1DLLCR,
|
|
+ DDRPHYC_DXNDLLCR_DLLDIS);
|
|
+
|
|
+ mmio_setbits_32(ddrphyc_base + DDRPHYC_DX2DLLCR,
|
|
+ DDRPHYC_DXNDLLCR_DLLDIS);
|
|
+
|
|
+ mmio_setbits_32(ddrphyc_base + DDRPHYC_DX3DLLCR,
|
|
+ DDRPHYC_DXNDLLCR_DLLDIS);
|
|
+
|
|
+ stm32mp1_clk_rcc_regs_lock();
|
|
+
|
|
+ /* Switch controller clocks (uMCTL2/PUBL) to DLL output clock */
|
|
+ mmio_clrbits_32(rcc_base + RCC_DDRITFCR, RCC_DDRITFCR_GSKPCTRL);
|
|
+
|
|
+ /* Deactivate all DDR clocks */
|
|
+ mmio_clrbits_32(rcc_base + RCC_DDRITFCR,
|
|
+ RCC_DDRITFCR_DDRC1EN |
|
|
+ RCC_DDRITFCR_DDRC2EN |
|
|
+ RCC_DDRITFCR_DDRCAPBEN |
|
|
+ RCC_DDRITFCR_DDRPHYCAPBEN);
|
|
+
|
|
+ stm32mp1_clk_rcc_regs_unlock();
|
|
+
|
|
+ return 0;
|
|
+
|
|
+selfref_sw_failed:
|
|
+ /* This bit should be cleared to restore DDR in its previous state */
|
|
+ mmio_clrbits_32(ddrctrl_base + DDRCTRL_PWRCTL,
|
|
+ DDRCTRL_PWRCTL_SELFREF_SW);
|
|
+
|
|
+pstat_failed:
|
|
+ mmio_setbits_32(ddrctrl_base + DDRCTRL_PCTRL_0,
|
|
+ DDRCTRL_PCTRL_N_PORT_EN);
|
|
+ mmio_setbits_32(ddrctrl_base + DDRCTRL_PCTRL_1,
|
|
+ DDRCTRL_PCTRL_N_PORT_EN);
|
|
+
|
|
+ return -1;
|
|
+}
|
|
+
|
|
+int ddr_sw_self_refresh_exit(void)
|
|
+{
|
|
+ uint64_t start;
|
|
+ uintptr_t rcc_base = stm32mp_rcc_base();
|
|
+ uintptr_t pwr_base = stm32mp_pwr_base();
|
|
+ uintptr_t ddrctrl_base = stm32mp_ddrctrl_base();
|
|
+ uintptr_t ddrphyc_base = stm32mp_ddrphyc_base();
|
|
+
|
|
+ /* Enable all clocks */
|
|
+ ddr_enable_clock();
|
|
+
|
|
+ do_sw_handshake();
|
|
+
|
|
+ /* Mask dfi_init_complete_en */
|
|
+ mmio_clrbits_32(ddrctrl_base + DDRCTRL_DFIMISC,
|
|
+ DDRCTRL_DFIMISC_DFI_INIT_COMPLETE_EN);
|
|
+
|
|
+ do_sw_ack();
|
|
+
|
|
+ /* Switch controller clocks (uMCTL2/PUBL) to DLL ref clock */
|
|
+ stm32mp1_clk_rcc_regs_lock();
|
|
+ mmio_setbits_32(rcc_base + RCC_DDRITFCR, RCC_DDRITFCR_GSKPCTRL);
|
|
+ stm32mp1_clk_rcc_regs_unlock();
|
|
+
|
|
+ /* Enable all DLLs: GLITCH window */
|
|
+ mmio_clrbits_32(ddrphyc_base + DDRPHYC_ACDLLCR,
|
|
+ DDRPHYC_ACDLLCR_DLLDIS);
|
|
+
|
|
+ mmio_clrbits_32(ddrphyc_base + DDRPHYC_DX0DLLCR,
|
|
+ DDRPHYC_DXNDLLCR_DLLDIS);
|
|
+
|
|
+ mmio_clrbits_32(ddrphyc_base + DDRPHYC_DX1DLLCR,
|
|
+ DDRPHYC_DXNDLLCR_DLLDIS);
|
|
+
|
|
+ mmio_clrbits_32(ddrphyc_base + DDRPHYC_DX2DLLCR,
|
|
+ DDRPHYC_DXNDLLCR_DLLDIS);
|
|
+
|
|
+ mmio_clrbits_32(ddrphyc_base + DDRPHYC_DX3DLLCR,
|
|
+ DDRPHYC_DXNDLLCR_DLLDIS);
|
|
+
|
|
+ /* Additional delay to avoid early DLL clock switch */
|
|
+ udelay(10);
|
|
+
|
|
+ /* Switch controller clocks (uMCTL2/PUBL) to DLL ref clock */
|
|
+ stm32mp1_clk_rcc_regs_lock();
|
|
+ mmio_clrbits_32(rcc_base + RCC_DDRITFCR, RCC_DDRITFCR_GSKPCTRL);
|
|
+ stm32mp1_clk_rcc_regs_unlock();
|
|
+
|
|
+ mmio_clrbits_32(ddrphyc_base + DDRPHYC_ACDLLCR,
|
|
+ DDRPHYC_ACDLLCR_DLLSRST);
|
|
+
|
|
+ udelay(10);
|
|
+
|
|
+ mmio_setbits_32(ddrphyc_base + DDRPHYC_ACDLLCR,
|
|
+ DDRPHYC_ACDLLCR_DLLSRST);
|
|
+
|
|
+ /* PHY partial init: (DLL lock and ITM reset) */
|
|
+ mmio_write_32(ddrphyc_base + DDRPHYC_PIR,
|
|
+ DDRPHYC_PIR_DLLSRST | DDRPHYC_PIR_DLLLOCK |
|
|
+ DDRPHYC_PIR_ITMSRST | DDRPHYC_PIR_INIT);
|
|
+
|
|
+ /* Need to wait at least 10 clock cycles before accessing PGSR */
|
|
+ udelay(1);
|
|
+
|
|
+ /* Pool end of init */
|
|
+ start = timeout_start();
|
|
+
|
|
+ while ((mmio_read_32(ddrphyc_base + DDRPHYC_PGSR) &
|
|
+ DDRPHYC_PGSR_IDONE) == 0U) {
|
|
+ if (timeout_elapsed(start, TIMEOUT_500US)) {
|
|
+ return -1;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ do_sw_handshake();
|
|
+
|
|
+ /* Unmask dfi_init_complete_en to uMCTL2 */
|
|
+ mmio_setbits_32(ddrctrl_base + DDRCTRL_DFIMISC,
|
|
+ DDRCTRL_DFIMISC_DFI_INIT_COMPLETE_EN);
|
|
+
|
|
+ do_sw_ack();
|
|
+
|
|
+ /* Deactivate sw retention in PWR */
|
|
+ pwr_regs_lock();
|
|
+ mmio_clrbits_32(pwr_base + PWR_CR3, PWR_CR3_DDRRETEN);
|
|
+ pwr_regs_unlock();
|
|
+
|
|
+ /* Enable PZQ cell (PUBL register) */
|
|
+ mmio_clrbits_32(ddrphyc_base + DDRPHYC_ZQ0CR0, DDRPHYC_ZQ0CRN_ZQPD);
|
|
+
|
|
+ /* Enable pad drivers */
|
|
+ mmio_clrbits_32(ddrphyc_base + DDRPHYC_ACIOCR, DDRPHYC_ACIOCR_ACPDD);
|
|
+
|
|
+ mmio_clrbits_32(ddrphyc_base + DDRPHYC_ACIOCR,
|
|
+ DDRPHYC_ACIOCR_CKPDD_MASK);
|
|
+
|
|
+ mmio_clrbits_32(ddrphyc_base + DDRPHYC_ACIOCR,
|
|
+ DDRPHYC_ACIOCR_CSPDD_MASK);
|
|
+
|
|
+ mmio_clrbits_32(ddrphyc_base + DDRPHYC_DXCCR, DDRPHYC_DXCCR_DXPDD);
|
|
+
|
|
+ mmio_clrbits_32(ddrphyc_base + DDRPHYC_DXCCR, DDRPHYC_DXCCR_DXPDR);
|
|
+
|
|
+ mmio_clrbits_32(ddrphyc_base + DDRPHYC_DSGCR,
|
|
+ DDRPHYC_DSGCR_ODTPDD_MASK);
|
|
+
|
|
+ mmio_clrbits_32(ddrphyc_base + DDRPHYC_DSGCR, DDRPHYC_DSGCR_NL2PD);
|
|
+
|
|
+ mmio_clrbits_32(ddrphyc_base + DDRPHYC_DSGCR,
|
|
+ DDRPHYC_DSGCR_CKEPDD_MASK);
|
|
+
|
|
+ /* Remove selfrefresh */
|
|
+ mmio_clrbits_32(ddrctrl_base + DDRCTRL_PWRCTL,
|
|
+ DDRCTRL_PWRCTL_SELFREF_SW);
|
|
+
|
|
+ /* Wait operating_mode == normal */
|
|
+ start = timeout_start();
|
|
+ while ((mmio_read_32(ddrctrl_base + DDRCTRL_STAT) &
|
|
+ DDRCTRL_STAT_OPERATING_MODE_MASK) !=
|
|
+ DDRCTRL_STAT_OPERATING_MODE_NORMAL) {
|
|
+ if (timeout_elapsed(start, TIMEOUT_500US)) {
|
|
+ return -1;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /* AXI ports are no longer blocked from taking transactions */
|
|
+ mmio_setbits_32(ddrctrl_base + DDRCTRL_PCTRL_0,
|
|
+ DDRCTRL_PCTRL_N_PORT_EN);
|
|
+ mmio_setbits_32(ddrctrl_base + DDRCTRL_PCTRL_1,
|
|
+ DDRCTRL_PCTRL_N_PORT_EN);
|
|
+
|
|
+ stm32mp1_clk_rcc_regs_lock();
|
|
+
|
|
+ mmio_setbits_32(rcc_base + RCC_DDRITFCR, RCC_DDRITFCR_AXIDCGEN);
|
|
+
|
|
+ stm32mp1_clk_rcc_regs_unlock();
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+int ddr_standby_sr_entry(uint32_t *zq0cr0_zdata)
|
|
+{
|
|
+ uintptr_t pwr_base = stm32mp_pwr_base();
|
|
+ uintptr_t ddrphyc_base = stm32mp_ddrphyc_base();
|
|
+
|
|
+ /* Save IOs calibration values */
|
|
+ if (zq0cr0_zdata != NULL) {
|
|
+ *zq0cr0_zdata = mmio_read_32(ddrphyc_base + DDRPHYC_ZQ0CR0) &
|
|
+ DDRPHYC_ZQ0CRN_ZDATA_MASK;
|
|
+ }
|
|
+
|
|
+ /* Put DDR in Self-Refresh */
|
|
+ if (ddr_sw_self_refresh_in() != 0) {
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ /* Enable I/O retention mode in standby */
|
|
+ pwr_regs_lock();
|
|
+ mmio_setbits_32(pwr_base + PWR_CR3, PWR_CR3_DDRSREN);
|
|
+ pwr_regs_unlock();
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+void ddr_sr_mode_ssr(void)
|
|
+{
|
|
+ uintptr_t rcc_ddritfcr = stm32mp_rcc_base() + RCC_DDRITFCR;
|
|
+ uintptr_t ddrctrl_base = stm32mp_ddrctrl_base();
|
|
+
|
|
+ stm32mp1_clk_rcc_regs_lock();
|
|
+
|
|
+ mmio_setbits_32(rcc_ddritfcr, RCC_DDRITFCR_DDRC1LPEN);
|
|
+
|
|
+ mmio_setbits_32(rcc_ddritfcr, RCC_DDRITFCR_DDRC2LPEN);
|
|
+
|
|
+ mmio_setbits_32(rcc_ddritfcr, RCC_DDRITFCR_DDRC1EN);
|
|
+
|
|
+ mmio_setbits_32(rcc_ddritfcr, RCC_DDRITFCR_DDRC2EN);
|
|
+
|
|
+ mmio_setbits_32(rcc_ddritfcr, RCC_DDRITFCR_DDRCAPBLPEN);
|
|
+
|
|
+ mmio_setbits_32(rcc_ddritfcr, RCC_DDRITFCR_DDRPHYCAPBLPEN);
|
|
+
|
|
+ mmio_setbits_32(rcc_ddritfcr, RCC_DDRITFCR_DDRCAPBEN);
|
|
+
|
|
+ mmio_setbits_32(rcc_ddritfcr, RCC_DDRITFCR_DDRPHYCAPBEN);
|
|
+
|
|
+ mmio_setbits_32(rcc_ddritfcr, RCC_DDRITFCR_DDRPHYCEN);
|
|
+
|
|
+ mmio_clrbits_32(rcc_ddritfcr, RCC_DDRITFCR_AXIDCGEN);
|
|
+
|
|
+ mmio_clrbits_32(rcc_ddritfcr, RCC_DDRITFCR_DDRCKMOD_MASK);
|
|
+
|
|
+ stm32mp1_clk_rcc_regs_unlock();
|
|
+
|
|
+ /* Disable HW LP interface of uMCTL2 */
|
|
+ mmio_clrbits_32(ddrctrl_base + DDRCTRL_HWLPCTL,
|
|
+ DDRCTRL_HWLPCTL_HW_LP_EN);
|
|
+
|
|
+ /* Configure Automatic LP modes of uMCTL2 */
|
|
+ mmio_clrsetbits_32(ddrctrl_base + DDRCTRL_PWRTMG,
|
|
+ DDRCTRL_PWRTMG_SELFREF_TO_X32_MASK,
|
|
+ DDRCTRL_PWRTMG_SELFREF_TO_X32_0);
|
|
+
|
|
+ /*
|
|
+ * Disable Clock disable with LP modes
|
|
+ * (used in RUN mode for LPDDR2 with specific timing).
|
|
+ */
|
|
+ mmio_clrbits_32(ddrctrl_base + DDRCTRL_PWRCTL,
|
|
+ DDRCTRL_PWRCTL_EN_DFI_DRAM_CLK_DISABLE);
|
|
+
|
|
+ /* Disable automatic Self-Refresh mode */
|
|
+ mmio_clrbits_32(ddrctrl_base + DDRCTRL_PWRCTL,
|
|
+ DDRCTRL_PWRCTL_SELFREF_EN);
|
|
+}
|
|
+
|
|
+void ddr_sr_mode_asr(void)
|
|
+{
|
|
+ uintptr_t rcc_ddritfcr = stm32mp_rcc_base() + RCC_DDRITFCR;
|
|
+ uintptr_t ddrctrl_base = stm32mp_ddrctrl_base();
|
|
+
|
|
+ stm32mp1_clk_rcc_regs_lock();
|
|
+
|
|
+ mmio_setbits_32(rcc_ddritfcr, RCC_DDRITFCR_AXIDCGEN);
|
|
+
|
|
+ mmio_setbits_32(rcc_ddritfcr, RCC_DDRITFCR_DDRC1LPEN);
|
|
+
|
|
+ mmio_setbits_32(rcc_ddritfcr, RCC_DDRITFCR_DDRC2LPEN);
|
|
+
|
|
+ mmio_setbits_32(rcc_ddritfcr, RCC_DDRITFCR_DDRPHYCLPEN);
|
|
+
|
|
+ mmio_clrsetbits_32(rcc_ddritfcr, RCC_DDRITFCR_DDRCKMOD_MASK,
|
|
+ RCC_DDRITFCR_DDRCKMOD_ASR1);
|
|
+
|
|
+ stm32mp1_clk_rcc_regs_unlock();
|
|
+
|
|
+ /* Enable HW LP interface of uMCTL2 */
|
|
+ mmio_setbits_32(ddrctrl_base + DDRCTRL_HWLPCTL,
|
|
+ DDRCTRL_HWLPCTL_HW_LP_EN);
|
|
+
|
|
+ /* Configure Automatic LP modes of uMCTL2 */
|
|
+ mmio_clrsetbits_32(ddrctrl_base + DDRCTRL_PWRTMG,
|
|
+ DDRCTRL_PWRTMG_SELFREF_TO_X32_MASK,
|
|
+ DDRCTRL_PWRTMG_SELFREF_TO_X32_0);
|
|
+
|
|
+ /*
|
|
+ * Enable Clock disable with LP modes
|
|
+ * (used in RUN mode for LPDDR2 with specific timing).
|
|
+ */
|
|
+ mmio_setbits_32(ddrctrl_base + DDRCTRL_PWRCTL,
|
|
+ DDRCTRL_PWRCTL_EN_DFI_DRAM_CLK_DISABLE);
|
|
+
|
|
+ /* Enable automatic Self-Refresh for ASR mode */
|
|
+ mmio_setbits_32(ddrctrl_base + DDRCTRL_PWRCTL,
|
|
+ DDRCTRL_PWRCTL_SELFREF_EN);
|
|
+}
|
|
+
|
|
+void ddr_sr_mode_hsr(void)
|
|
+{
|
|
+ uintptr_t rcc_ddritfcr = stm32mp_rcc_base() + RCC_DDRITFCR;
|
|
+ uintptr_t ddrctrl_base = stm32mp_ddrctrl_base();
|
|
+
|
|
+ stm32mp1_clk_rcc_regs_lock();
|
|
+
|
|
+ mmio_setbits_32(rcc_ddritfcr, RCC_DDRITFCR_AXIDCGEN);
|
|
+
|
|
+ mmio_clrbits_32(rcc_ddritfcr, RCC_DDRITFCR_DDRC1LPEN);
|
|
+
|
|
+ mmio_clrbits_32(rcc_ddritfcr, RCC_DDRITFCR_DDRC2LPEN);
|
|
+
|
|
+ mmio_setbits_32(rcc_ddritfcr, RCC_DDRITFCR_DDRPHYCLPEN);
|
|
+
|
|
+ mmio_clrsetbits_32(rcc_ddritfcr, RCC_DDRITFCR_DDRCKMOD_MASK,
|
|
+ RCC_DDRITFCR_DDRCKMOD_HSR1);
|
|
+
|
|
+ stm32mp1_clk_rcc_regs_unlock();
|
|
+
|
|
+ /* Enable HW LP interface of uMCTL2 */
|
|
+ mmio_setbits_32(ddrctrl_base + DDRCTRL_HWLPCTL,
|
|
+ DDRCTRL_HWLPCTL_HW_LP_EN);
|
|
+
|
|
+ /* Configure Automatic LP modes of uMCTL2 */
|
|
+ mmio_clrsetbits_32(ddrctrl_base + DDRCTRL_PWRTMG,
|
|
+ DDRCTRL_PWRTMG_SELFREF_TO_X32_MASK,
|
|
+ DDRCTRL_PWRTMG_SELFREF_TO_X32_0);
|
|
+
|
|
+ /*
|
|
+ * Enable Clock disable with LP modes
|
|
+ * (used in RUN mode for LPDDR2 with specific timing).
|
|
+ */
|
|
+ mmio_setbits_32(ddrctrl_base + DDRCTRL_PWRCTL,
|
|
+ DDRCTRL_PWRCTL_EN_DFI_DRAM_CLK_DISABLE);
|
|
+}
|
|
+
|
|
+bool ddr_is_nonsecured_area(uintptr_t address, uint32_t length)
|
|
+{
|
|
+ uint64_t pa;
|
|
+
|
|
+ write_ats1cpw(address);
|
|
+
|
|
+ isb();
|
|
+
|
|
+ pa = read64_par();
|
|
+
|
|
+ if ((((pa >> PAR_NS_SHIFT) & PAR_NS_MASK) != PAR_NS_MASK) ||
|
|
+ (((pa >> PAR_F_SHIFT) & PAR_F_MASK) == PAR_F_MASK)) {
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ write_ats1cpw(address + length - 1U);
|
|
+
|
|
+ isb();
|
|
+
|
|
+ pa = read64_par();
|
|
+
|
|
+ if ((((pa >> PAR_NS_SHIFT) & PAR_NS_MASK) == PAR_NS_MASK) &&
|
|
+ (((pa >> PAR_F_SHIFT) & PAR_F_MASK) != PAR_F_MASK)) {
|
|
+ return true;
|
|
+ }
|
|
+
|
|
+ return false;
|
|
}
|
|
diff --git a/drivers/st/ddr/stm32mp1_ram.c b/drivers/st/ddr/stm32mp1_ram.c
|
|
index 6d515ec..82b8fda 100644
|
|
--- a/drivers/st/ddr/stm32mp1_ram.c
|
|
+++ b/drivers/st/ddr/stm32mp1_ram.c
|
|
@@ -7,36 +7,30 @@
|
|
#include <arch_helpers.h>
|
|
#include <boot_api.h>
|
|
#include <debug.h>
|
|
-#include <dt-bindings/clock/stm32mp1-clks.h>
|
|
#include <errno.h>
|
|
#include <libfdt.h>
|
|
#include <mmio.h>
|
|
#include <platform_def.h>
|
|
-#include <stm32mp1_clk.h>
|
|
-#include <stm32mp1_ddr.h>
|
|
-#include <stm32mp1_ddr_helpers.h>
|
|
-#include <stm32mp1_dt.h>
|
|
-#include <stm32mp1_private.h>
|
|
-#include <stm32mp1_ram.h>
|
|
-#include <stm32mp1_rcc.h>
|
|
+#include <stm32mp_common.h>
|
|
+#include <stm32mp_dt.h>
|
|
|
|
#define DDR_PATTERN 0xAAAAAAAAU
|
|
#define DDR_ANTIPATTERN 0x55555555U
|
|
|
|
static struct ddr_info ddr_priv_data;
|
|
|
|
-int stm32mp1_ddr_clk_enable(struct ddr_info *priv, uint16_t mem_speed)
|
|
+int stm32mp1_ddr_clk_enable(struct ddr_info *priv, uint32_t mem_speed)
|
|
{
|
|
unsigned long ddrphy_clk, ddr_clk, mem_speed_hz;
|
|
|
|
ddr_enable_clock();
|
|
|
|
- ddrphy_clk = stm32mp1_clk_get_rate(DDRPHYC);
|
|
+ ddrphy_clk = stm32mp_clk_get_rate(DDRPHYC);
|
|
|
|
- VERBOSE("DDR: mem_speed (%d MHz), RCC %ld MHz\n",
|
|
- mem_speed, ddrphy_clk / 1000U / 1000U);
|
|
+ VERBOSE("DDR: mem_speed (%d kHz), RCC %ld kHz\n",
|
|
+ mem_speed, ddrphy_clk / 1000U);
|
|
|
|
- mem_speed_hz = (uint32_t)mem_speed * 1000U * 1000U;
|
|
+ mem_speed_hz = mem_speed * 1000U;
|
|
|
|
/* Max 10% frequency delta */
|
|
if (ddrphy_clk > mem_speed_hz) {
|
|
@@ -44,15 +38,35 @@ int stm32mp1_ddr_clk_enable(struct ddr_info *priv, uint16_t mem_speed)
|
|
} else {
|
|
ddr_clk = mem_speed_hz - ddrphy_clk;
|
|
}
|
|
- if (ddr_clk > mem_speed_hz) {
|
|
- ERROR("DDR expected freq %d MHz, current is %ld MHz\n",
|
|
- mem_speed, ddrphy_clk / 1000U / 1000U);
|
|
+ if (ddr_clk > (mem_speed_hz / 10)) {
|
|
+ ERROR("DDR expected freq %d kHz, current is %ld kHz\n",
|
|
+ mem_speed, ddrphy_clk / 1000U);
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*******************************************************************************
|
|
+ * This function tests a simple read/write access to the DDR.
|
|
+ * Note that the previous content is restored after test.
|
|
+ * Returns 0 if success, and address value else.
|
|
+ ******************************************************************************/
|
|
+static uint32_t ddr_test_rw_access(void)
|
|
+{
|
|
+ uint32_t saved_value = mmio_read_32(STM32MP_DDR_BASE);
|
|
+
|
|
+ mmio_write_32(STM32MP_DDR_BASE, DDR_PATTERN);
|
|
+
|
|
+ if (mmio_read_32(STM32MP_DDR_BASE) != DDR_PATTERN) {
|
|
+ return (uint32_t)STM32MP_DDR_BASE;
|
|
+ }
|
|
+
|
|
+ mmio_write_32(STM32MP_DDR_BASE, saved_value);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/*******************************************************************************
|
|
* This function tests the DDR data bus wiring.
|
|
* This is inspired from the Data Bus Test algorithm written by Michael Barr
|
|
* in "Programming Embedded Systems in C and C++" book.
|
|
@@ -65,10 +79,10 @@ static uint32_t ddr_test_data_bus(void)
|
|
uint32_t pattern;
|
|
|
|
for (pattern = 1U; pattern != 0U; pattern <<= 1) {
|
|
- mmio_write_32(STM32MP1_DDR_BASE, pattern);
|
|
+ mmio_write_32(STM32MP_DDR_BASE, pattern);
|
|
|
|
- if (mmio_read_32(STM32MP1_DDR_BASE) != pattern) {
|
|
- return (uint32_t)STM32MP1_DDR_BASE;
|
|
+ if (mmio_read_32(STM32MP_DDR_BASE) != pattern) {
|
|
+ return (uint32_t)STM32MP_DDR_BASE;
|
|
}
|
|
}
|
|
|
|
@@ -92,44 +106,44 @@ static uint32_t ddr_test_addr_bus(void)
|
|
/* Write the default pattern at each of the power-of-two offsets. */
|
|
for (offset = sizeof(uint32_t); (offset & addressmask) != 0U;
|
|
offset <<= 1) {
|
|
- mmio_write_32(STM32MP1_DDR_BASE + (uint32_t)offset,
|
|
+ mmio_write_32(STM32MP_DDR_BASE + (uint32_t)offset,
|
|
DDR_PATTERN);
|
|
}
|
|
|
|
/* Check for address bits stuck high. */
|
|
- mmio_write_32(STM32MP1_DDR_BASE + (uint32_t)testoffset,
|
|
+ mmio_write_32(STM32MP_DDR_BASE + (uint32_t)testoffset,
|
|
DDR_ANTIPATTERN);
|
|
|
|
for (offset = sizeof(uint32_t); (offset & addressmask) != 0U;
|
|
offset <<= 1) {
|
|
- if (mmio_read_32(STM32MP1_DDR_BASE + (uint32_t)offset) !=
|
|
+ if (mmio_read_32(STM32MP_DDR_BASE + (uint32_t)offset) !=
|
|
DDR_PATTERN) {
|
|
- return (uint32_t)(STM32MP1_DDR_BASE + offset);
|
|
+ return (uint32_t)(STM32MP_DDR_BASE + offset);
|
|
}
|
|
}
|
|
|
|
- mmio_write_32(STM32MP1_DDR_BASE + (uint32_t)testoffset, DDR_PATTERN);
|
|
+ mmio_write_32(STM32MP_DDR_BASE + (uint32_t)testoffset, DDR_PATTERN);
|
|
|
|
/* Check for address bits stuck low or shorted. */
|
|
for (testoffset = sizeof(uint32_t); (testoffset & addressmask) != 0U;
|
|
testoffset <<= 1) {
|
|
- mmio_write_32(STM32MP1_DDR_BASE + (uint32_t)testoffset,
|
|
+ mmio_write_32(STM32MP_DDR_BASE + (uint32_t)testoffset,
|
|
DDR_ANTIPATTERN);
|
|
|
|
- if (mmio_read_32(STM32MP1_DDR_BASE) != DDR_PATTERN) {
|
|
- return STM32MP1_DDR_BASE;
|
|
+ if (mmio_read_32(STM32MP_DDR_BASE) != DDR_PATTERN) {
|
|
+ return STM32MP_DDR_BASE;
|
|
}
|
|
|
|
for (offset = sizeof(uint32_t); (offset & addressmask) != 0U;
|
|
offset <<= 1) {
|
|
- if ((mmio_read_32(STM32MP1_DDR_BASE +
|
|
+ if ((mmio_read_32(STM32MP_DDR_BASE +
|
|
(uint32_t)offset) != DDR_PATTERN) &&
|
|
(offset != testoffset)) {
|
|
- return (uint32_t)(STM32MP1_DDR_BASE + offset);
|
|
+ return (uint32_t)(STM32MP_DDR_BASE + offset);
|
|
}
|
|
}
|
|
|
|
- mmio_write_32(STM32MP1_DDR_BASE + (uint32_t)testoffset,
|
|
+ mmio_write_32(STM32MP_DDR_BASE + (uint32_t)testoffset,
|
|
DDR_PATTERN);
|
|
}
|
|
|
|
@@ -147,13 +161,13 @@ static uint32_t ddr_check_size(void)
|
|
{
|
|
uint32_t offset = sizeof(uint32_t);
|
|
|
|
- mmio_write_32(STM32MP1_DDR_BASE, DDR_PATTERN);
|
|
+ mmio_write_32(STM32MP_DDR_BASE, DDR_PATTERN);
|
|
|
|
- while (offset < STM32MP1_DDR_MAX_SIZE) {
|
|
- mmio_write_32(STM32MP1_DDR_BASE + offset, DDR_ANTIPATTERN);
|
|
+ while (offset < STM32MP_DDR_MAX_SIZE) {
|
|
+ mmio_write_32(STM32MP_DDR_BASE + offset, DDR_ANTIPATTERN);
|
|
dsb();
|
|
|
|
- if (mmio_read_32(STM32MP1_DDR_BASE) != DDR_PATTERN) {
|
|
+ if (mmio_read_32(STM32MP_DDR_BASE) != DDR_PATTERN) {
|
|
break;
|
|
}
|
|
|
|
@@ -171,8 +185,12 @@ static int stm32mp1_ddr_setup(void)
|
|
int ret;
|
|
struct stm32mp1_ddr_config config;
|
|
int node, len;
|
|
- uint32_t tamp_clk_off = 0, uret, idx;
|
|
+ uint32_t magic, uret, idx;
|
|
void *fdt;
|
|
+ uint32_t bkpr_core1_addr =
|
|
+ tamp_bkpr(BOOT_API_CORE1_BRANCH_ADDRESS_TAMP_BCK_REG_IDX);
|
|
+ uint32_t bkpr_core1_magic =
|
|
+ tamp_bkpr(BOOT_API_CORE1_MAGIC_NUMBER_TAMP_BCK_REG_IDX);
|
|
|
|
#define PARAM(x, y) \
|
|
{ \
|
|
@@ -208,11 +226,16 @@ static int stm32mp1_ddr_setup(void)
|
|
return -EINVAL;
|
|
}
|
|
|
|
- config.info.speed =
|
|
- (uint16_t)fdt_read_uint32_default(node, "st,mem-speed",
|
|
- STM32MP1_DDR_SPEED_DFLT);
|
|
- config.info.size = fdt_read_uint32_default(node, "st,mem-size",
|
|
- STM32MP1_DDR_SIZE_DFLT);
|
|
+ config.info.speed = fdt_read_uint32_default(node, "st,mem-speed", 0);
|
|
+ if (!config.info.speed) {
|
|
+ VERBOSE("%s: no st,mem-speed\n", __func__);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+ config.info.size = fdt_read_uint32_default(node, "st,mem-size", 0);
|
|
+ if (!config.info.size) {
|
|
+ VERBOSE("%s: no st,mem-size\n", __func__);
|
|
+ return -EINVAL;
|
|
+ }
|
|
config.info.name = fdt_getprop(fdt, node, "st,mem-name", &len);
|
|
if (config.info.name == NULL) {
|
|
VERBOSE("%s: no st,mem-name\n", __func__);
|
|
@@ -222,7 +245,7 @@ static int stm32mp1_ddr_setup(void)
|
|
|
|
for (idx = 0; idx < ARRAY_SIZE(param); idx++) {
|
|
ret = fdt_read_uint32_array(node, param[idx].name,
|
|
- (void *)((uint32_t)&config +
|
|
+ (void *)((uintptr_t)&config +
|
|
param[idx].offset),
|
|
param[idx].size);
|
|
|
|
@@ -235,19 +258,18 @@ static int stm32mp1_ddr_setup(void)
|
|
}
|
|
}
|
|
|
|
- if (!stm32mp1_clk_is_enabled(RTCAPB)) {
|
|
- tamp_clk_off = 1;
|
|
- if (stm32mp1_clk_enable(RTCAPB) != 0) {
|
|
- return -EINVAL;
|
|
- }
|
|
- }
|
|
+ config.self_refresh = false;
|
|
|
|
- if (tamp_clk_off != 0U) {
|
|
- if (stm32mp1_clk_disable(RTCAPB) != 0) {
|
|
- return -EINVAL;
|
|
- }
|
|
+ stm32mp_clk_enable(RTCAPB);
|
|
+
|
|
+ magic = mmio_read_32(bkpr_core1_magic);
|
|
+ if (magic == BOOT_API_A7_CORE0_MAGIC_NUMBER) {
|
|
+ config.self_refresh = true;
|
|
+ config.zdata = stm32_get_zdata_from_context();
|
|
}
|
|
|
|
+ stm32mp_clk_disable(RTCAPB);
|
|
+
|
|
/* Disable axidcg clock gating during init */
|
|
mmio_clrbits_32(priv->rcc + RCC_DDRITFCR, RCC_DDRITFCR_AXIDCGEN);
|
|
|
|
@@ -256,36 +278,60 @@ static int stm32mp1_ddr_setup(void)
|
|
/* Enable axidcg clock gating */
|
|
mmio_setbits_32(priv->rcc + RCC_DDRITFCR, RCC_DDRITFCR_AXIDCGEN);
|
|
|
|
+ /* check if DDR content is lost (self-refresh aborted) */
|
|
+ if ((magic == BOOT_API_A7_CORE0_MAGIC_NUMBER) && !config.self_refresh) {
|
|
+ /* clear Backup register */
|
|
+ mmio_write_32(bkpr_core1_addr, 0);
|
|
+ /* clear magic number */
|
|
+ mmio_write_32(bkpr_core1_magic, 0);
|
|
+ }
|
|
+
|
|
priv->info.size = config.info.size;
|
|
|
|
VERBOSE("%s : ram size(%x, %x)\n", __func__,
|
|
(uint32_t)priv->info.base, (uint32_t)priv->info.size);
|
|
|
|
- dcsw_op_all(DC_OP_CISW);
|
|
+#ifndef DCACHE_OFF
|
|
write_sctlr(read_sctlr() & ~SCTLR_C_BIT);
|
|
+ dcsw_op_all(DC_OP_CISW);
|
|
+#endif
|
|
+
|
|
+ if (config.self_refresh) {
|
|
+ uret = ddr_test_rw_access();
|
|
+ if (uret != 0U) {
|
|
+ ERROR("DDR rw test: Can't access memory @ 0x%x\n",
|
|
+ uret);
|
|
+ panic();
|
|
+ }
|
|
|
|
- uret = ddr_test_data_bus();
|
|
- if (uret != 0U) {
|
|
- ERROR("DDR data bus test: can't access memory @ 0x%x\n",
|
|
- uret);
|
|
- panic();
|
|
- }
|
|
+ /* Restore area overwritten by training */
|
|
+ stm32_restore_ddr_training_area();
|
|
+ } else {
|
|
+ uret = ddr_test_data_bus();
|
|
+ if (uret != 0U) {
|
|
+ ERROR("DDR data bus test: can't access memory @ 0x%x\n",
|
|
+ uret);
|
|
+ panic();
|
|
+ }
|
|
|
|
- uret = ddr_test_addr_bus();
|
|
- if (uret != 0U) {
|
|
- ERROR("DDR addr bus test: can't access memory @ 0x%x\n",
|
|
- uret);
|
|
- panic();
|
|
- }
|
|
+ uret = ddr_test_addr_bus();
|
|
+ if (uret != 0U) {
|
|
+ ERROR("DDR addr bus test: can't access memory @ 0x%x\n",
|
|
+ uret);
|
|
+ panic();
|
|
+ }
|
|
|
|
- uret = ddr_check_size();
|
|
- if (uret < config.info.size) {
|
|
- ERROR("DDR size: 0x%x does not match DT config: 0x%x\n",
|
|
- uret, config.info.size);
|
|
- panic();
|
|
+ uret = ddr_check_size();
|
|
+ if (uret < config.info.size) {
|
|
+ ERROR("DDR size: 0x%x does not match DT config: 0x%x\n",
|
|
+ uret, config.info.size);
|
|
+ panic();
|
|
+ }
|
|
}
|
|
|
|
+#ifndef DCACHE_OFF
|
|
write_sctlr(read_sctlr() | SCTLR_C_BIT);
|
|
+#endif
|
|
|
|
return 0;
|
|
}
|
|
@@ -296,12 +342,12 @@ int stm32mp1_ddr_probe(void)
|
|
|
|
VERBOSE("STM32MP DDR probe\n");
|
|
|
|
- priv->ctl = (struct stm32mp1_ddrctl *)DDRCTRL_BASE;
|
|
- priv->phy = (struct stm32mp1_ddrphy *)DDRPHYC_BASE;
|
|
- priv->pwr = PWR_BASE;
|
|
- priv->rcc = RCC_BASE;
|
|
+ priv->ctl = (struct stm32mp1_ddrctl *)stm32mp_ddrctrl_base();
|
|
+ priv->phy = (struct stm32mp1_ddrphy *)stm32mp_ddrphyc_base();
|
|
+ priv->pwr = stm32mp_pwr_base();
|
|
+ priv->rcc = stm32mp_rcc_base();
|
|
|
|
- priv->info.base = STM32MP1_DDR_BASE;
|
|
+ priv->info.base = STM32MP_DDR_BASE;
|
|
priv->info.size = 0;
|
|
|
|
return stm32mp1_ddr_setup();
|
|
diff --git a/drivers/st/etzpc/etzpc.c b/drivers/st/etzpc/etzpc.c
|
|
new file mode 100644
|
|
index 0000000..06c3282
|
|
--- /dev/null
|
|
+++ b/drivers/st/etzpc/etzpc.c
|
|
@@ -0,0 +1,310 @@
|
|
+/*
|
|
+ * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved.
|
|
+ * Copyright (c) 2017-2018, STMicroelectronics
|
|
+ *
|
|
+ * SPDX-License-Identifier: BSD-3-Clause
|
|
+ */
|
|
+
|
|
+#include <arch_helpers.h>
|
|
+#include <assert.h>
|
|
+#include <debug.h>
|
|
+#include <dt-bindings/soc/st,stm32-etzpc.h>
|
|
+#include <errno.h>
|
|
+#include <etzpc.h>
|
|
+#include <libfdt.h>
|
|
+#include <mmio.h>
|
|
+#include <platform_def.h>
|
|
+#include <stdint.h>
|
|
+#include <stm32mp_common.h>
|
|
+#include <stm32mp_dt.h>
|
|
+#include <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/gpio/stm32_gpio.c b/drivers/st/gpio/stm32_gpio.c
|
|
index 200b473..fc0dce8 100644
|
|
--- a/drivers/st/gpio/stm32_gpio.c
|
|
+++ b/drivers/st/gpio/stm32_gpio.c
|
|
@@ -4,83 +4,280 @@
|
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
*/
|
|
|
|
+#include <assert.h>
|
|
#include <bl_common.h>
|
|
#include <debug.h>
|
|
+#include <errno.h>
|
|
+#include <libfdt.h>
|
|
#include <mmio.h>
|
|
+#include <platform_def.h>
|
|
#include <stdbool.h>
|
|
#include <stm32_gpio.h>
|
|
+#include <stm32mp_clkfunc.h>
|
|
+#include <stm32mp_common.h>
|
|
+#include <stm32mp_dt.h>
|
|
|
|
-static bool check_gpio(uint32_t bank, uint32_t pin)
|
|
+#define DT_GPIO_BANK_SHIFT 12
|
|
+#define DT_GPIO_BANK_MASK 0x1F000U
|
|
+#define DT_GPIO_PIN_SHIFT 8
|
|
+#define DT_GPIO_PIN_MASK 0xF00U
|
|
+#define DT_GPIO_MODE_MASK 0xFFU
|
|
+
|
|
+/*******************************************************************************
|
|
+ * This function gets GPIO bank node in DT.
|
|
+ * Returns node offset if status is okay in DT, else return 0
|
|
+ ******************************************************************************/
|
|
+static int ckeck_gpio_bank(void *fdt, uint32_t bank, int pinctrl_node)
|
|
{
|
|
- if (pin > GPIO_PIN_MAX) {
|
|
- ERROR("%s: wrong pin number (%d)\n", __func__, pin);
|
|
- return false;
|
|
- }
|
|
+ int pinctrl_subnode;
|
|
+
|
|
+ fdt_for_each_subnode(pinctrl_subnode, fdt, pinctrl_node) {
|
|
+ uint32_t bank_offset;
|
|
+ const fdt32_t *cuint;
|
|
+
|
|
+ if (fdt_getprop(fdt, pinctrl_subnode,
|
|
+ "gpio-controller", NULL) == NULL) {
|
|
+ continue;
|
|
+ }
|
|
|
|
- if ((bank > GPIO_BANK_K) && (bank != GPIO_BANK_Z)) {
|
|
- ERROR("%s: wrong GPIO bank number (%d)\n", __func__, bank);
|
|
- return false;
|
|
+ cuint = fdt_getprop(fdt, pinctrl_subnode, "reg", NULL);
|
|
+ if (cuint == NULL) {
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ bank_offset = stm32_get_gpio_bank_offset(bank);
|
|
+
|
|
+ if ((fdt32_to_cpu(*cuint) == bank_offset) &&
|
|
+ (fdt_get_status(pinctrl_subnode) != DT_DISABLED)) {
|
|
+ return pinctrl_subnode;
|
|
+ }
|
|
}
|
|
|
|
- return true;
|
|
+ return 0;
|
|
}
|
|
|
|
-void set_gpio(uint32_t bank, uint32_t pin, uint32_t mode, uint32_t speed,
|
|
- uint32_t pull, uint32_t alternate)
|
|
+/*******************************************************************************
|
|
+ * This function gets the pin settings from DT information.
|
|
+ * When analyze and parsing is done, set the GPIO registers.
|
|
+ * Returns 0 on success and a negative FDT error code on failure.
|
|
+ ******************************************************************************/
|
|
+static int dt_set_gpio_config(void *fdt, int node, uint8_t status)
|
|
{
|
|
- volatile uint32_t bank_address;
|
|
+ const fdt32_t *cuint, *slewrate;
|
|
+ int len;
|
|
+ int pinctrl_node;
|
|
+ uint32_t i;
|
|
+ uint32_t speed = GPIO_SPEED_LOW;
|
|
+ uint32_t pull = GPIO_NO_PULL;
|
|
+
|
|
+ cuint = fdt_getprop(fdt, node, "pinmux", &len);
|
|
+ if (cuint == NULL) {
|
|
+ return -FDT_ERR_NOTFOUND;
|
|
+ }
|
|
+
|
|
+ pinctrl_node = fdt_parent_offset(fdt, fdt_parent_offset(fdt, node));
|
|
+ if (pinctrl_node < 0) {
|
|
+ return -FDT_ERR_NOTFOUND;
|
|
+ }
|
|
|
|
- if (!check_gpio(bank, pin)) {
|
|
- return;
|
|
+ slewrate = fdt_getprop(fdt, node, "slew-rate", NULL);
|
|
+ if (slewrate != NULL) {
|
|
+ speed = fdt32_to_cpu(*slewrate);
|
|
}
|
|
|
|
- if (bank == GPIO_BANK_Z) {
|
|
- bank_address = STM32_GPIOZ_BANK;
|
|
+ if (fdt_getprop(fdt, node, "bias-pull-up", NULL) != NULL) {
|
|
+ pull = GPIO_PULL_UP;
|
|
+ } else if (fdt_getprop(fdt, node, "bias-pull-down", NULL) != NULL) {
|
|
+ pull = GPIO_PULL_DOWN;
|
|
} else {
|
|
- bank_address = STM32_GPIOA_BANK +
|
|
- (bank * STM32_GPIO_BANK_OFFSET);
|
|
+ VERBOSE("No bias configured in node %d\n", node);
|
|
+ }
|
|
+
|
|
+ for (i = 0U; i < ((uint32_t)len / sizeof(uint32_t)); i++) {
|
|
+ uint32_t pincfg;
|
|
+ uint32_t bank;
|
|
+ uint32_t pin;
|
|
+ uint32_t mode;
|
|
+ uint32_t alternate = GPIO_ALTERNATE_(0);
|
|
+ int bank_node;
|
|
+ int clk;
|
|
+
|
|
+ pincfg = fdt32_to_cpu(*cuint);
|
|
+ cuint++;
|
|
+
|
|
+ bank = (pincfg & DT_GPIO_BANK_MASK) >> DT_GPIO_BANK_SHIFT;
|
|
+
|
|
+ pin = (pincfg & DT_GPIO_PIN_MASK) >> DT_GPIO_PIN_SHIFT;
|
|
+
|
|
+ mode = pincfg & DT_GPIO_MODE_MASK;
|
|
+
|
|
+ switch (mode) {
|
|
+ case 0:
|
|
+ mode = GPIO_MODE_INPUT;
|
|
+ break;
|
|
+ case 1 ... 16:
|
|
+ alternate = mode - 1U;
|
|
+ mode = GPIO_MODE_ALTERNATE;
|
|
+ break;
|
|
+ case 17:
|
|
+ mode = GPIO_MODE_ANALOG;
|
|
+ break;
|
|
+ default:
|
|
+ mode = GPIO_MODE_OUTPUT;
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ if (fdt_getprop(fdt, node, "drive-open-drain", NULL) != NULL) {
|
|
+ mode |= GPIO_OPEN_DRAIN;
|
|
+ }
|
|
+
|
|
+ bank_node = ckeck_gpio_bank(fdt, bank, pinctrl_node);
|
|
+ if (bank_node == 0) {
|
|
+ ERROR("PINCTRL inconsistent in DT\n");
|
|
+ panic();
|
|
+ }
|
|
+
|
|
+ clk = fdt_get_clock_id(bank_node);
|
|
+ if (clk < 0) {
|
|
+ return -FDT_ERR_NOTFOUND;
|
|
+ }
|
|
+
|
|
+ /* Platform knows the clock: assert it is okay */
|
|
+ assert(clk == stm32_get_gpio_bank_clock(bank));
|
|
+
|
|
+ set_gpio(bank, pin, mode, speed, pull, alternate, status);
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/*******************************************************************************
|
|
+ * This function gets the pin settings from DT information.
|
|
+ * When analyze and parsing is done, set the GPIO registers.
|
|
+ * Returns 0 on success and a negative FDT/ERRNO error code on failure.
|
|
+ ******************************************************************************/
|
|
+int dt_set_pinctrl_config(int node)
|
|
+{
|
|
+ const fdt32_t *cuint;
|
|
+ int lenp = 0;
|
|
+ uint32_t i;
|
|
+ uint8_t status = fdt_get_status(node);
|
|
+ void *fdt;
|
|
+
|
|
+ if (fdt_get_address(&fdt) == 0) {
|
|
+ return -ENOENT;
|
|
+ }
|
|
+
|
|
+ if (status == DT_DISABLED) {
|
|
+ return -FDT_ERR_NOTFOUND;
|
|
}
|
|
|
|
- mmio_clrbits_32(bank_address + GPIO_MODE_OFFSET,
|
|
+ cuint = fdt_getprop(fdt, node, "pinctrl-0", &lenp);
|
|
+ if (cuint == NULL) {
|
|
+ return -FDT_ERR_NOTFOUND;
|
|
+ }
|
|
+
|
|
+ for (i = 0; i < ((uint32_t)lenp / 4U); i++) {
|
|
+ int p_node, p_subnode;
|
|
+
|
|
+ p_node = fdt_node_offset_by_phandle(fdt, fdt32_to_cpu(*cuint));
|
|
+ if (p_node < 0) {
|
|
+ return -FDT_ERR_NOTFOUND;
|
|
+ }
|
|
+
|
|
+ fdt_for_each_subnode(p_subnode, fdt, p_node) {
|
|
+ int ret = dt_set_gpio_config(fdt, p_subnode, status);
|
|
+
|
|
+ if (ret < 0) {
|
|
+ return ret;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ cuint++;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+void set_gpio(uint32_t bank, uint32_t pin, uint32_t mode, uint32_t speed,
|
|
+ uint32_t pull, uint32_t alternate, uint8_t status)
|
|
+{
|
|
+ uintptr_t base = stm32_get_gpio_bank_base(bank);
|
|
+ int clock = stm32_get_gpio_bank_clock(bank);
|
|
+
|
|
+ assert(pin <= GPIO_PIN_MAX);
|
|
+
|
|
+ stm32mp_clk_enable((unsigned long)clock);
|
|
+
|
|
+ mmio_clrbits_32(base + GPIO_MODE_OFFSET,
|
|
((uint32_t)GPIO_MODE_MASK << (pin << 1)));
|
|
- mmio_setbits_32(bank_address + GPIO_MODE_OFFSET,
|
|
+ mmio_setbits_32(base + GPIO_MODE_OFFSET,
|
|
(mode & ~GPIO_OPEN_DRAIN) << (pin << 1));
|
|
|
|
if ((mode & GPIO_OPEN_DRAIN) != 0U) {
|
|
- mmio_setbits_32(bank_address + GPIO_TYPE_OFFSET,
|
|
- BIT(pin));
|
|
+ mmio_setbits_32(base + GPIO_TYPE_OFFSET, BIT(pin));
|
|
+ } else {
|
|
+ mmio_clrbits_32(base + GPIO_TYPE_OFFSET, BIT(pin));
|
|
}
|
|
|
|
- mmio_clrbits_32(bank_address + GPIO_SPEED_OFFSET,
|
|
+ mmio_clrbits_32(base + GPIO_SPEED_OFFSET,
|
|
((uint32_t)GPIO_SPEED_MASK << (pin << 1)));
|
|
- mmio_setbits_32(bank_address + GPIO_SPEED_OFFSET, speed << (pin << 1));
|
|
+ mmio_setbits_32(base + GPIO_SPEED_OFFSET, speed << (pin << 1));
|
|
|
|
- mmio_clrbits_32(bank_address + GPIO_PUPD_OFFSET,
|
|
+ mmio_clrbits_32(base + GPIO_PUPD_OFFSET,
|
|
((uint32_t)GPIO_PULL_MASK << (pin << 1)));
|
|
- mmio_setbits_32(bank_address + GPIO_PUPD_OFFSET, pull << (pin << 1));
|
|
+ mmio_setbits_32(base + GPIO_PUPD_OFFSET, pull << (pin << 1));
|
|
|
|
if (pin < GPIO_ALT_LOWER_LIMIT) {
|
|
- mmio_clrbits_32(bank_address + GPIO_AFRL_OFFSET,
|
|
+ mmio_clrbits_32(base + GPIO_AFRL_OFFSET,
|
|
((uint32_t)GPIO_ALTERNATE_MASK << (pin << 2)));
|
|
- mmio_setbits_32(bank_address + GPIO_AFRL_OFFSET,
|
|
+ mmio_setbits_32(base + GPIO_AFRL_OFFSET,
|
|
alternate << (pin << 2));
|
|
} else {
|
|
- mmio_clrbits_32(bank_address + GPIO_AFRH_OFFSET,
|
|
+ mmio_clrbits_32(base + GPIO_AFRH_OFFSET,
|
|
((uint32_t)GPIO_ALTERNATE_MASK <<
|
|
((pin - GPIO_ALT_LOWER_LIMIT) << 2)));
|
|
- mmio_setbits_32(bank_address + GPIO_AFRH_OFFSET,
|
|
+ mmio_setbits_32(base + GPIO_AFRH_OFFSET,
|
|
alternate << ((pin - GPIO_ALT_LOWER_LIMIT) <<
|
|
2));
|
|
}
|
|
|
|
VERBOSE("GPIO %u mode set to 0x%x\n", bank,
|
|
- mmio_read_32(bank_address + GPIO_MODE_OFFSET));
|
|
+ mmio_read_32(base + GPIO_MODE_OFFSET));
|
|
VERBOSE("GPIO %u speed set to 0x%x\n", bank,
|
|
- mmio_read_32(bank_address + GPIO_SPEED_OFFSET));
|
|
+ mmio_read_32(base + GPIO_SPEED_OFFSET));
|
|
VERBOSE("GPIO %u mode pull to 0x%x\n", bank,
|
|
- mmio_read_32(bank_address + GPIO_PUPD_OFFSET));
|
|
+ mmio_read_32(base + GPIO_PUPD_OFFSET));
|
|
VERBOSE("GPIO %u mode alternate low to 0x%x\n", bank,
|
|
- mmio_read_32(bank_address + GPIO_AFRL_OFFSET));
|
|
+ mmio_read_32(base + GPIO_AFRL_OFFSET));
|
|
VERBOSE("GPIO %u mode alternate high to 0x%x\n", bank,
|
|
- mmio_read_32(bank_address + GPIO_AFRH_OFFSET));
|
|
+ mmio_read_32(base + GPIO_AFRH_OFFSET));
|
|
+
|
|
+ stm32mp_clk_disable((unsigned long)clock);
|
|
+
|
|
+ if (status == DT_SECURE) {
|
|
+ stm32mp_register_secure_gpio(bank, pin);
|
|
+ } else {
|
|
+ stm32mp_register_non_secure_gpio(bank, pin);
|
|
+ }
|
|
+}
|
|
+
|
|
+void set_gpio_secure_cfg(uint32_t bank, uint32_t pin, bool secure)
|
|
+{
|
|
+ uintptr_t base = stm32_get_gpio_bank_base(bank);
|
|
+ int clock = stm32_get_gpio_bank_clock(bank);
|
|
+
|
|
+ assert(pin <= GPIO_PIN_MAX);
|
|
+
|
|
+ assert(!(secure && stm32mp_gpio_bank_is_non_secure(bank)));
|
|
+
|
|
+ stm32mp_clk_enable((unsigned long)clock);
|
|
+
|
|
+ if (secure) {
|
|
+ mmio_setbits_32(base + GPIO_SECR_OFFSET, BIT(pin));
|
|
+ } else {
|
|
+ mmio_clrbits_32(base + GPIO_SECR_OFFSET, BIT(pin));
|
|
+ }
|
|
+
|
|
+ stm32mp_clk_disable((unsigned long)clock);
|
|
}
|
|
diff --git a/drivers/st/hash/hash_sec.c b/drivers/st/hash/hash_sec.c
|
|
new file mode 100644
|
|
index 0000000..a3c588a
|
|
--- /dev/null
|
|
+++ b/drivers/st/hash/hash_sec.c
|
|
@@ -0,0 +1,369 @@
|
|
+/*
|
|
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
|
|
+ *
|
|
+ * SPDX-License-Identifier: BSD-3-Clause
|
|
+ */
|
|
+
|
|
+#include <arch_helpers.h>
|
|
+#include <assert.h>
|
|
+#include <debug.h>
|
|
+#include <hash_sec.h>
|
|
+#include <platform_def.h>
|
|
+#include <stdint.h>
|
|
+
|
|
+#define RESET 0
|
|
+
|
|
+#define timer_GetTimeSec() (uint32_t)read_cntpct_el0()
|
|
+
|
|
+static void HASH_WriteData(HASH_HandleTypeDef *hHash, const uint8_t *pInBuffer,
|
|
+ uint32_t SizeInBytes);
|
|
+static void HASH_GetDigest(HASH_HandleTypeDef *hHash, uint8_t *pMsgDigest);
|
|
+static uint32_t HASH_WaitBusyClearWithTimeout(HASH_HandleTypeDef *hHash,
|
|
+ uint32_t timeout);
|
|
+static uint32_t HASH_WaitDcisClearWithTimeout(HASH_HandleTypeDef *hHash,
|
|
+ uint32_t timeout);
|
|
+
|
|
+/*****************************************************************************
|
|
+ *
|
|
+ * Function: HASH_SHA256_Init
|
|
+ *
|
|
+ * Description: Initializes the HASH peripheral
|
|
+ *
|
|
+ * Parameters: hHash : pointer to a HASH_HandleTypeDef structure that contains
|
|
+ * the configuration information for HASH module
|
|
+ *
|
|
+ * Return: none
|
|
+ *
|
|
+ *****************************************************************************/
|
|
+Std_ReturnType HASH_SHA256_Init(HASH_HandleTypeDef *hHash)
|
|
+{
|
|
+ /* Check the hash handle allocation */
|
|
+ if (!hHash) {
|
|
+ return STD_NOT_OK;
|
|
+ }
|
|
+
|
|
+ hHash->Instance = (HASH_TypeDef *)HASH_BASE;
|
|
+
|
|
+ /* Enable HASH1 clock */
|
|
+ stm32mp_clk_enable(HASH1);
|
|
+
|
|
+ hHash->Error = HASH_INIT_NOT_DONE;
|
|
+
|
|
+ hHash->pHashInBuffPtr = NULL;
|
|
+
|
|
+ hHash->pHashOutBuffPtr = NULL;
|
|
+
|
|
+ /* Set the data type to 8 bits */
|
|
+ hHash->Instance->CR |= HASH_DATATYPE_8B;
|
|
+
|
|
+ /* Select the SHA256 mode and reset the HASH processor core,
|
|
+ * so that the HASH will be ready to compute the message digest
|
|
+ * of a new message
|
|
+ */
|
|
+ hHash->Instance->CR |= HASH_AlgoSelection_SHA256 | HASH_CR_INIT;
|
|
+
|
|
+ /* Return function status */
|
|
+ hHash->Error = HASH_INIT_DONE;
|
|
+
|
|
+ return STD_OK;
|
|
+}
|
|
+
|
|
+/*****************************************************************************
|
|
+ *
|
|
+ * Function: HASH_SHA256_Start
|
|
+ *
|
|
+ * Description: Initializes the HASH peripheral in SHA256 mode
|
|
+ * then processes pInBuffer.
|
|
+ * The digest is available in pOutBuffer.
|
|
+ *
|
|
+ * Parameters: hHash : pointer to a HASH_HandleTypeDef structure that contains
|
|
+ * the configuration information for HASH module
|
|
+ *
|
|
+ * pInBuffer: Pointer to the input buffer (buffer to be hashed).
|
|
+ *
|
|
+ * sizeInBytes: Length of the input buffer in bytes.
|
|
+ * If the Size is not multiple of 64 bytes,
|
|
+ * the padding is managed by hardware.
|
|
+ *
|
|
+ * pOutBuffer: Pointer to the computed digest.
|
|
+ * Its size must be 32 bytes.
|
|
+ *
|
|
+ * Timeout: Specify Timeout value
|
|
+ *
|
|
+ * Return: none
|
|
+ *
|
|
+ *****************************************************************************/
|
|
+Std_ReturnType HASH_SHA256_Start(HASH_HandleTypeDef *hHash,
|
|
+ const uint8_t *pInBuffer, uint32_t sizeInBytes,
|
|
+ uint8_t *pOutBuffer, uint32_t Timeout)
|
|
+{
|
|
+ uint32_t timeoutDetected = 0;
|
|
+
|
|
+ /* Check the hash handle allocation */
|
|
+ if (!hHash) {
|
|
+ return STD_NOT_OK;
|
|
+ }
|
|
+
|
|
+ hHash->pHashInBuffPtr = pInBuffer;
|
|
+ hHash->pHashOutBuffPtr = pOutBuffer;
|
|
+
|
|
+ /* Configure the number of valid bits in last word 32 bits
|
|
+ * of the bit stream
|
|
+ */
|
|
+ __HAL_HASH_SET_NBVALIDBITSINLAST32BITSWORD(sizeInBytes);
|
|
+
|
|
+ /* Fill in entire input buffer to be hashed in HASH DIN register
|
|
+ * Note : intermediate digest is computed each time 64 bytes are written
|
|
+ * in HASH_DIN register
|
|
+ */
|
|
+ HASH_WriteData(hHash, pInBuffer, sizeInBytes);
|
|
+
|
|
+ /* Start the Final Digest calculation */
|
|
+ hHash->Instance->STR |= HASH_STR_DCAL;
|
|
+
|
|
+ /* Check for timeout */
|
|
+ timeoutDetected = HASH_WaitBusyClearWithTimeout(hHash, Timeout);
|
|
+ if (timeoutDetected != 0) {
|
|
+ hHash->Error = HASH_TIMEOUT;
|
|
+ return STD_NOT_OK;
|
|
+ }
|
|
+
|
|
+ /* Read the message digest in output buffer */
|
|
+ HASH_GetDigest(hHash, pOutBuffer);
|
|
+
|
|
+ hHash->Error = HASH_DIGEST_DONE;
|
|
+
|
|
+ return STD_OK;
|
|
+}
|
|
+
|
|
+/*****************************************************************************
|
|
+ *
|
|
+ * Function: HASH_SHA256_Accumulate
|
|
+ *
|
|
+ * Description: Initializes the HASH peripheral in SHA256 mode then processes
|
|
+ * pInBuffer.
|
|
+ *
|
|
+ * Parameters: hHash: pointer to a HASH_HandleTypeDef structure that contains
|
|
+ * the configuration information for HASH module
|
|
+ *
|
|
+ * pInBuffer: Pointer to the input buffer (buffer to be hashed).
|
|
+ *
|
|
+ * sizeInBytes: Length of the input buffer in bytes.
|
|
+ * If the Size is not multiple of 64 bytes, the padding is managed
|
|
+ * by hardware.
|
|
+ *
|
|
+ * Return: none
|
|
+ *
|
|
+ *****************************************************************************/
|
|
+Std_ReturnType HASH_SHA256_Accumulate(HASH_HandleTypeDef *hHash,
|
|
+ const uint8_t *pInBuffer,
|
|
+ uint32_t sizeInBytes)
|
|
+{
|
|
+ /* Check the hash handle allocation */
|
|
+ if (!hHash) {
|
|
+ return STD_NOT_OK;
|
|
+ }
|
|
+
|
|
+ hHash->pHashInBuffPtr = pInBuffer;
|
|
+
|
|
+ /* Configure the number of valid bits in last 32 bits word
|
|
+ * of the message
|
|
+ */
|
|
+ __HAL_HASH_SET_NBVALIDBITSINLAST32BITSWORD(sizeInBytes);
|
|
+
|
|
+ /* Write input buffer in data register */
|
|
+ HASH_WriteData(hHash, pInBuffer, sizeInBytes);
|
|
+
|
|
+ /* Return function status */
|
|
+ hHash->Error = HASH_ACCU_DONE;
|
|
+
|
|
+ return STD_OK;
|
|
+}
|
|
+
|
|
+/*****************************************************************************
|
|
+ *
|
|
+ * Function: HASH_SHA256_Finish
|
|
+ *
|
|
+ * Description: Returns the computed digest in SHA256.
|
|
+ *
|
|
+ * Parameters: hHash: pointer to a HASH_HandleTypeDef structure that contains
|
|
+ * the configuration information for HASH module
|
|
+ *
|
|
+ * pOutBuffer: Pointer to the computed digest.
|
|
+ * Its size must be 32 bytes.
|
|
+ *
|
|
+ * Timeout: Timeout value
|
|
+ *
|
|
+ * Return: none
|
|
+ *
|
|
+ *****************************************************************************/
|
|
+Std_ReturnType HASH_SHA256_Finish(HASH_HandleTypeDef *hHash,
|
|
+ uint8_t *pOutBuffer, uint32_t Timeout)
|
|
+{
|
|
+ uint32_t timeoutDetected = 0;
|
|
+
|
|
+ /* Check the hash handle allocation */
|
|
+ if (!hHash) {
|
|
+ return STD_NOT_OK;
|
|
+ }
|
|
+
|
|
+ hHash->pHashOutBuffPtr = pOutBuffer;
|
|
+
|
|
+ /* Check for the Timeout */
|
|
+ timeoutDetected = HASH_WaitDcisClearWithTimeout(hHash, Timeout);
|
|
+ if (timeoutDetected != 0) {
|
|
+ hHash->Error = HASH_TIMEOUT;
|
|
+ return STD_NOT_OK;
|
|
+ }
|
|
+
|
|
+ /* Read the message digest */
|
|
+ HASH_GetDigest(hHash, pOutBuffer);
|
|
+
|
|
+ /* Return function status */
|
|
+ hHash->Error = HASH_FINISHED;
|
|
+
|
|
+ return STD_OK;
|
|
+}
|
|
+
|
|
+/* Static functions ----------------------------------------------------------*/
|
|
+
|
|
+/**
|
|
+ * @brief Writes the input buffer in HASH_DIN register.
|
|
+ * @param pInBuffer: Pointer to input buffer
|
|
+ * @param SizeInBytes : The size of input buffer (in bytes)
|
|
+ * @retval None
|
|
+ */
|
|
+static void HASH_WriteData(HASH_HandleTypeDef *hHash, const uint8_t *pInBuffer,
|
|
+ uint32_t SizeInBytes)
|
|
+{
|
|
+ uint32_t *pInWord32 = (uint32_t *)pInBuffer;
|
|
+ uint32_t nbBlocks = (SizeInBytes / HASH_BLOCK_SIZE_NB_BYTES);
|
|
+ uint32_t remainingBytesInLastBlock = (SizeInBytes %
|
|
+ HASH_BLOCK_SIZE_NB_BYTES);
|
|
+ uint32_t remainingBytesInLastWord = (SizeInBytes % 4);
|
|
+ uint32_t idxBlock = 0;
|
|
+ uint32_t idxWord32;
|
|
+
|
|
+ /* For all blocks */
|
|
+ for (idxBlock = 0; idxBlock < nbBlocks; idxBlock++) {
|
|
+ for (idxWord32 = 0; idxWord32 < (HASH_BLOCK_SIZE_NB_BYTES / 4);
|
|
+ idxWord32++) {
|
|
+ hHash->Instance->DIN = *pInWord32;
|
|
+ pInWord32++;
|
|
+ }
|
|
+
|
|
+ /* Wait until end of computation of intermediate digest */
|
|
+ while ((hHash->Instance->SR & HASH_SR_DINIS) == HASH_SR_DINIS) {
|
|
+ ;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (remainingBytesInLastBlock != 0) {
|
|
+ uint32_t nbWords32Remaining = (remainingBytesInLastBlock / 4);
|
|
+
|
|
+ for (idxWord32 = 0; idxWord32 < nbWords32Remaining;
|
|
+ idxWord32++) {
|
|
+ hHash->Instance->DIN = *pInWord32;
|
|
+ pInWord32++;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (remainingBytesInLastWord != 0) {
|
|
+ hHash->Instance->DIN = *pInWord32;
|
|
+ }
|
|
+}
|
|
+
|
|
+#ifndef __CC_ARM
|
|
+/* __rev is a builtin command in ARM compiler
|
|
+ * it needs to be remapped on __builtin_bswap32 for GCC
|
|
+ */
|
|
+#define __rev __builtin_bswap32
|
|
+#endif
|
|
+
|
|
+/**
|
|
+ * @brief Provides the message digest result.
|
|
+ * @param hHash: Hash handle
|
|
+ * @param pMsgDigest: Pointer to the message digest
|
|
+ * @retval None
|
|
+ */
|
|
+static void HASH_GetDigest(HASH_HandleTypeDef *hHash, uint8_t *pMsgDigest)
|
|
+{
|
|
+ uintptr_t msgdigest = (uintptr_t)pMsgDigest;
|
|
+
|
|
+ /* Read the message digest */
|
|
+ *(uintptr_t *)(msgdigest) = __rev(hHash->Instance->HR[0]);
|
|
+ msgdigest += 4;
|
|
+ *(uintptr_t *)(msgdigest) = __rev(hHash->Instance->HR[1]);
|
|
+ msgdigest += 4;
|
|
+ *(uintptr_t *)(msgdigest) = __rev(hHash->Instance->HR[2]);
|
|
+ msgdigest += 4;
|
|
+ *(uintptr_t *)(msgdigest) = __rev(hHash->Instance->HR[3]);
|
|
+ msgdigest += 4;
|
|
+ *(uintptr_t *)(msgdigest) = __rev(hHash->Instance->HR[4]);
|
|
+ msgdigest += 4;
|
|
+ *(uintptr_t *)(msgdigest) = __rev(HASH_DIGEST->HR[5]);
|
|
+ msgdigest += 4;
|
|
+ *(uintptr_t *)(msgdigest) = __rev(HASH_DIGEST->HR[6]);
|
|
+ msgdigest += 4;
|
|
+ *(uintptr_t *)(msgdigest) = __rev(HASH_DIGEST->HR[7]);
|
|
+}
|
|
+
|
|
+/**
|
|
+ * @brief This function waits until bit HASH_SR_BUSY is 1b0' before a timeout.
|
|
+ * @param [in] hHash : hash handle
|
|
+ * @param [in] timeout : timeout value
|
|
+ *
|
|
+ * @retval timeoutDetected : value 0x1 if timeout was detected while
|
|
+ * waiting for bit BUSY to be cleared.
|
|
+ ******************************************************************************
|
|
+ */
|
|
+
|
|
+static uint32_t HASH_WaitBusyClearWithTimeout(HASH_HandleTypeDef *hHash,
|
|
+ uint32_t timeout)
|
|
+{
|
|
+ uint32_t timerValInit = 0;
|
|
+ uint32_t timeoutDetected = 0;
|
|
+
|
|
+ /* Get timer current value at start of loop */
|
|
+ timerValInit = timer_GetTimeSec();
|
|
+
|
|
+ while (((hHash->Instance->SR & HASH_SR_BUSY) == HASH_SR_BUSY) &&
|
|
+ (timeoutDetected == 0)) {
|
|
+ /* Sense timeout occurrence */
|
|
+ if ((timer_GetTimeSec() - timerValInit) >= timeout) {
|
|
+ timeoutDetected = 1;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return timeoutDetected;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * @brief This function waits until bit HASH_SR_DCIS is 1b0' before a timeout.
|
|
+ * @param [in] hHash : hash handle
|
|
+ * @param [in] timeout : timeout value
|
|
+ *
|
|
+ * @retval timeoutDetected : value 0x1 if timeout was detected while
|
|
+ * waiting for bit DCIS to be cleared.
|
|
+ ******************************************************************************
|
|
+ */
|
|
+
|
|
+static uint32_t HASH_WaitDcisClearWithTimeout(HASH_HandleTypeDef *hHash,
|
|
+ uint32_t timeout)
|
|
+{
|
|
+ uint32_t timerValInit = 0;
|
|
+ uint32_t timeoutDetected = 0;
|
|
+
|
|
+ /* Get timer current value at start of loop */
|
|
+ timerValInit = timer_GetTimeSec();
|
|
+
|
|
+ while ((HAL_IS_BIT_CLR(hHash->Instance->SR, HASH_SR_DCIS)) &&
|
|
+ (timeoutDetected == 0)) {
|
|
+ /* Sense timeout occurrence */
|
|
+ if ((timer_GetTimeSec() - timerValInit) >= timeout) {
|
|
+ timeoutDetected = 1;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return timeoutDetected;
|
|
+}
|
|
diff --git a/drivers/st/i2c/stm32_i2c.c b/drivers/st/i2c/stm32_i2c.c
|
|
new file mode 100644
|
|
index 0000000..694a76a
|
|
--- /dev/null
|
|
+++ b/drivers/st/i2c/stm32_i2c.c
|
|
@@ -0,0 +1,1371 @@
|
|
+/*
|
|
+ * Copyright (c) 2016-2018, STMicroelectronics - All Rights Reserved
|
|
+ *
|
|
+ * SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
|
|
+ */
|
|
+
|
|
+#include <debug.h>
|
|
+#include <delay_timer.h>
|
|
+#include <errno.h>
|
|
+#include <libfdt.h>
|
|
+#include <limits.h>
|
|
+#include <mmio.h>
|
|
+#include <platform_def.h>
|
|
+#include <stdbool.h>
|
|
+#include <stdlib.h>
|
|
+#include <stm32_gpio.h>
|
|
+#include <stm32_i2c.h>
|
|
+#include <stm32mp_common.h>
|
|
+#include <utils.h>
|
|
+
|
|
+/* STM32 I2C registers offsets */
|
|
+#define I2C_CR1 0x00U
|
|
+#define I2C_CR2 0x04U
|
|
+#define I2C_OAR1 0x08U
|
|
+#define I2C_OAR2 0x0CU
|
|
+#define I2C_TIMINGR 0x10U
|
|
+#define I2C_TIMEOUTR 0x14U
|
|
+#define I2C_ISR 0x18U
|
|
+#define I2C_ICR 0x1CU
|
|
+#define I2C_PECR 0x20U
|
|
+#define I2C_RXDR 0x24U
|
|
+#define I2C_TXDR 0x28U
|
|
+
|
|
+#define TIMINGR_CLEAR_MASK 0xF0FFFFFFU
|
|
+
|
|
+#define MAX_NBYTE_SIZE 255U
|
|
+
|
|
+#define I2C_NSEC_PER_SEC 1000000000L
|
|
+
|
|
+/*
|
|
+ * struct i2c_spec_s - Private I2C timing specifications.
|
|
+ * @rate: I2C bus speed (Hz)
|
|
+ * @rate_min: 80% of I2C bus speed (Hz)
|
|
+ * @rate_max: 120% of I2C bus speed (Hz)
|
|
+ * @fall_max: Max fall time of both SDA and SCL signals (ns)
|
|
+ * @rise_max: Max rise time of both SDA and SCL signals (ns)
|
|
+ * @hddat_min: Min data hold time (ns)
|
|
+ * @vddat_max: Max data valid time (ns)
|
|
+ * @sudat_min: Min data setup time (ns)
|
|
+ * @l_min: Min low period of the SCL clock (ns)
|
|
+ * @h_min: Min high period of the SCL clock (ns)
|
|
+ */
|
|
+struct i2c_spec_s {
|
|
+ uint32_t rate;
|
|
+ uint32_t rate_min;
|
|
+ uint32_t rate_max;
|
|
+ uint32_t fall_max;
|
|
+ uint32_t rise_max;
|
|
+ uint32_t hddat_min;
|
|
+ uint32_t vddat_max;
|
|
+ uint32_t sudat_min;
|
|
+ uint32_t l_min;
|
|
+ uint32_t h_min;
|
|
+};
|
|
+
|
|
+/*
|
|
+ * struct i2c_timing_s - Private I2C output parameters.
|
|
+ * @scldel: Data setup time
|
|
+ * @sdadel: Data hold time
|
|
+ * @sclh: SCL high period (master mode)
|
|
+ * @sclh: SCL low period (master mode)
|
|
+ * @is_saved: True if relating to a configuration candidate
|
|
+ */
|
|
+struct i2c_timing_s {
|
|
+ uint8_t scldel;
|
|
+ uint8_t sdadel;
|
|
+ uint8_t sclh;
|
|
+ uint8_t scll;
|
|
+ bool is_saved;
|
|
+};
|
|
+
|
|
+/**
|
|
+ * All these values are coming from I2C Specification, Version 6.0, 4th of
|
|
+ * April 2014.
|
|
+ *
|
|
+ * Table10. Characteristics of the SDA and SCL bus lines for Standard, Fast,
|
|
+ * and Fast-mode Plus I2C-bus devices.
|
|
+ */
|
|
+static const struct i2c_spec_s i2c_specs[] = {
|
|
+ [I2C_SPEED_STANDARD] = {
|
|
+ .rate = STANDARD_RATE,
|
|
+ .rate_min = 8000,
|
|
+ .rate_max = 120000,
|
|
+ .fall_max = 300,
|
|
+ .rise_max = 1000,
|
|
+ .hddat_min = 0,
|
|
+ .vddat_max = 3450,
|
|
+ .sudat_min = 250,
|
|
+ .l_min = 4700,
|
|
+ .h_min = 4000,
|
|
+ },
|
|
+ [I2C_SPEED_FAST] = {
|
|
+ .rate = FAST_RATE,
|
|
+ .rate_min = 320000,
|
|
+ .rate_max = 480000,
|
|
+ .fall_max = 300,
|
|
+ .rise_max = 300,
|
|
+ .hddat_min = 0,
|
|
+ .vddat_max = 900,
|
|
+ .sudat_min = 100,
|
|
+ .l_min = 1300,
|
|
+ .h_min = 600,
|
|
+ },
|
|
+ [I2C_SPEED_FAST_PLUS] = {
|
|
+ .rate = FAST_PLUS_RATE,
|
|
+ .rate_min = 800000,
|
|
+ .rate_max = 1200000,
|
|
+ .fall_max = 100,
|
|
+ .rise_max = 120,
|
|
+ .hddat_min = 0,
|
|
+ .vddat_max = 450,
|
|
+ .sudat_min = 50,
|
|
+ .l_min = 500,
|
|
+ .h_min = 260,
|
|
+ },
|
|
+};
|
|
+
|
|
+static int i2c_request_memory_write(struct i2c_handle_s *hi2c,
|
|
+ uint16_t dev_addr, uint16_t mem_addr,
|
|
+ uint16_t mem_add_size,
|
|
+ uint64_t tick_to, uint64_t tick_start);
|
|
+static int i2c_request_memory_read(struct i2c_handle_s *hi2c, uint16_t dev_addr,
|
|
+ uint16_t mem_addr, uint16_t mem_add_size,
|
|
+ uint64_t tick_to, uint64_t tick_start);
|
|
+
|
|
+/* Private functions to handle flags during polling transfer */
|
|
+static int i2c_wait_flag(struct i2c_handle_s *hi2c, uint32_t flag,
|
|
+ uint8_t awaited_value,
|
|
+ uint64_t tick_to, uint64_t tick_start);
|
|
+static int i2c_wait_txis(struct i2c_handle_s *hi2c,
|
|
+ uint64_t tick_to, uint64_t tick_start);
|
|
+static int i2c_wait_stop(struct i2c_handle_s *hi2c,
|
|
+ uint64_t tick_to, uint64_t tick_start);
|
|
+static int i2c_ack_failed(struct i2c_handle_s *hi2c,
|
|
+ uint64_t tick_to, uint64_t tick_start);
|
|
+
|
|
+/* Private function to flush TXDR register */
|
|
+static void i2c_flush_txdr(struct i2c_handle_s *hi2c);
|
|
+
|
|
+/* Private function to start, restart or stop a transfer */
|
|
+static void i2c_transfer_config(struct i2c_handle_s *hi2c, uint16_t dev_addr,
|
|
+ uint16_t size, uint32_t i2c_mode,
|
|
+ uint32_t request);
|
|
+
|
|
+static void notif_i2c_timeout(struct i2c_handle_s *hi2c)
|
|
+{
|
|
+ hi2c->i2c_err |= I2C_ERROR_TIMEOUT;
|
|
+ hi2c->i2c_mode = I2C_MODE_NONE;
|
|
+ hi2c->i2c_state = I2C_STATE_READY;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * @brief Compute the I2C device timings.
|
|
+ * @param init: Ref to the initialization configuration structure
|
|
+ * @param clock_src: I2C clock source frequency (Hz)
|
|
+ * @param timing: Pointer to the final computed timing result
|
|
+ * @retval 0 if OK, negative value else
|
|
+ */
|
|
+static int i2c_compute_timing(struct stm32_i2c_init_s *init,
|
|
+ uint32_t clock_src, uint32_t *timing)
|
|
+{
|
|
+ enum i2c_speed_e mode = init->speed_mode;
|
|
+ uint32_t speed_freq;
|
|
+ uint32_t i2cclk = udiv_round_nearest(I2C_NSEC_PER_SEC, clock_src);
|
|
+ uint32_t i2cbus;
|
|
+ uint32_t p_prev = I2C_TIMINGR_PRESC_MAX;
|
|
+ uint32_t af_delay_min;
|
|
+ uint32_t af_delay_max;
|
|
+ uint32_t dnf_delay;
|
|
+ uint32_t tsync;
|
|
+ uint32_t clk_min;
|
|
+ uint32_t clk_max;
|
|
+ int clk_error_prev;
|
|
+ uint16_t p;
|
|
+ uint16_t l;
|
|
+ uint16_t a;
|
|
+ uint16_t h;
|
|
+ int sdadel_min;
|
|
+ int sdadel_max;
|
|
+ uint32_t sdadel_min_u;
|
|
+ uint32_t sdadel_max_u;
|
|
+ uint32_t scldel_min;
|
|
+ int s = -1;
|
|
+ struct i2c_timing_s solutions[I2C_TIMINGR_PRESC_MAX];
|
|
+
|
|
+ switch (mode) {
|
|
+ case I2C_SPEED_STANDARD ... I2C_SPEED_FAST_PLUS:
|
|
+ break;
|
|
+ default:
|
|
+ ERROR("I2C speed out of bound {%d/%d}\n",
|
|
+ mode, I2C_SPEED_FAST_PLUS);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ speed_freq = i2c_specs[mode].rate;
|
|
+ i2cbus = udiv_round_nearest(I2C_NSEC_PER_SEC, speed_freq);
|
|
+ clk_error_prev = INT_MAX;
|
|
+
|
|
+ if ((init->rise_time > i2c_specs[mode].rise_max) ||
|
|
+ (init->fall_time > i2c_specs[mode].fall_max)) {
|
|
+ ERROR(" I2C timings out of bound Rise{%d>%d}/Fall{%d>%d}\n",
|
|
+ init->rise_time, i2c_specs[mode].rise_max,
|
|
+ init->fall_time, i2c_specs[mode].fall_max);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ if (init->digital_filter_coef > STM32_I2C_DIGITAL_FILTER_MAX) {
|
|
+ ERROR("DNF out of bound %d/%d\n",
|
|
+ init->digital_filter_coef, STM32_I2C_DIGITAL_FILTER_MAX);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ /* Analog and Digital Filters */
|
|
+ af_delay_min = (init->analog_filter ?
|
|
+ STM32_I2C_ANALOG_FILTER_DELAY_MIN : 0);
|
|
+ af_delay_max = (init->analog_filter ?
|
|
+ STM32_I2C_ANALOG_FILTER_DELAY_MAX : 0);
|
|
+ dnf_delay = init->digital_filter_coef * i2cclk;
|
|
+
|
|
+ sdadel_min = i2c_specs[mode].hddat_min + init->fall_time -
|
|
+ af_delay_min - ((init->digital_filter_coef + 3) * i2cclk);
|
|
+
|
|
+ sdadel_max = i2c_specs[mode].vddat_max - init->rise_time -
|
|
+ af_delay_max - ((init->digital_filter_coef + 4) * i2cclk);
|
|
+
|
|
+ scldel_min = init->rise_time + i2c_specs[mode].sudat_min;
|
|
+
|
|
+ if (sdadel_min < 0) {
|
|
+ sdadel_min_u = 0;
|
|
+ } else {
|
|
+ sdadel_min_u = (uint32_t)sdadel_min;
|
|
+ }
|
|
+
|
|
+ if (sdadel_max < 0) {
|
|
+ sdadel_max_u = 0;
|
|
+ } else {
|
|
+ sdadel_max_u = (uint32_t)sdadel_max;
|
|
+ }
|
|
+
|
|
+ VERBOSE("I2C SDADEL(min/max): %u/%u, SCLDEL(Min): %u\n",
|
|
+ sdadel_min_u, sdadel_max_u, scldel_min);
|
|
+
|
|
+ zeromem(&solutions, sizeof(solutions));
|
|
+
|
|
+ /* Compute possible values for PRESC, SCLDEL and SDADEL */
|
|
+ for (p = 0; p < I2C_TIMINGR_PRESC_MAX; p++) {
|
|
+ for (l = 0; l < I2C_TIMINGR_SCLDEL_MAX; l++) {
|
|
+ uint32_t scldel = (l + 1) * (p + 1) * i2cclk;
|
|
+
|
|
+ if (scldel < scldel_min) {
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ for (a = 0; a < I2C_TIMINGR_SDADEL_MAX; a++) {
|
|
+ uint32_t sdadel = (a * (p + 1) + 1) * i2cclk;
|
|
+
|
|
+ if ((sdadel >= sdadel_min_u) &&
|
|
+ (sdadel <= sdadel_max_u) &&
|
|
+ (p != p_prev)) {
|
|
+ solutions[p].scldel = l;
|
|
+ solutions[p].sdadel = a;
|
|
+ solutions[p].is_saved = true;
|
|
+ p_prev = p;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (p_prev == p) {
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (p_prev == I2C_TIMINGR_PRESC_MAX) {
|
|
+ ERROR(" I2C no Prescaler solution\n");
|
|
+ return -EPERM;
|
|
+ }
|
|
+
|
|
+ tsync = af_delay_min + dnf_delay + (2 * i2cclk);
|
|
+ clk_max = I2C_NSEC_PER_SEC / i2c_specs[mode].rate_min;
|
|
+ clk_min = I2C_NSEC_PER_SEC / i2c_specs[mode].rate_max;
|
|
+
|
|
+ /*
|
|
+ * Among prescaler possibilities discovered above figures out SCL Low
|
|
+ * and High Period. Provided:
|
|
+ * - SCL Low Period has to be higher than Low Period of the SCL Clock
|
|
+ * defined by I2C Specification. I2C Clock has to be lower than
|
|
+ * (SCL Low Period - Analog/Digital filters) / 4.
|
|
+ * - SCL High Period has to be lower than High Period of the SCL Clock
|
|
+ * defined by I2C Specification.
|
|
+ * - I2C Clock has to be lower than SCL High Period.
|
|
+ */
|
|
+ for (p = 0; p < I2C_TIMINGR_PRESC_MAX; p++) {
|
|
+ uint32_t prescaler = (p + 1) * i2cclk;
|
|
+
|
|
+ if (!solutions[p].is_saved) {
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ for (l = 0; l < I2C_TIMINGR_SCLL_MAX; l++) {
|
|
+ uint32_t tscl_l = ((l + 1) * prescaler) + tsync;
|
|
+
|
|
+ if ((tscl_l < i2c_specs[mode].l_min) ||
|
|
+ (i2cclk >=
|
|
+ ((tscl_l - af_delay_min - dnf_delay) / 4))) {
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ for (h = 0; h < I2C_TIMINGR_SCLH_MAX; h++) {
|
|
+ uint32_t tscl_h = ((h + 1) * prescaler) + tsync;
|
|
+ uint32_t tscl = tscl_l + tscl_h +
|
|
+ init->rise_time +
|
|
+ init->fall_time;
|
|
+
|
|
+ if ((tscl >= clk_min) && (tscl <= clk_max) &&
|
|
+ (tscl_h >= i2c_specs[mode].h_min) &&
|
|
+ (i2cclk < tscl_h)) {
|
|
+ int clk_error = tscl - i2cbus;
|
|
+
|
|
+ if (clk_error < 0) {
|
|
+ clk_error = -clk_error;
|
|
+ }
|
|
+
|
|
+ if (clk_error < clk_error_prev) {
|
|
+ clk_error_prev = clk_error;
|
|
+ solutions[p].scll = l;
|
|
+ solutions[p].sclh = h;
|
|
+ s = p;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (s < 0) {
|
|
+ ERROR(" I2C no solution at all\n");
|
|
+ return -EPERM;
|
|
+ }
|
|
+
|
|
+ /* Finalize timing settings */
|
|
+ *timing = I2C_SET_TIMINGR_PRESC(s) |
|
|
+ I2C_SET_TIMINGR_SCLDEL(solutions[s].scldel) |
|
|
+ I2C_SET_TIMINGR_SDADEL(solutions[s].sdadel) |
|
|
+ I2C_SET_TIMINGR_SCLH(solutions[s].sclh) |
|
|
+ I2C_SET_TIMINGR_SCLL(solutions[s].scll);
|
|
+
|
|
+ VERBOSE("I2C TIMINGR (PRESC/SCLDEL/SDADEL): %i/%i/%i\n",
|
|
+ s, solutions[s].scldel, solutions[s].sdadel);
|
|
+ VERBOSE("I2C TIMINGR (SCLH/SCLL): %i/%i\n",
|
|
+ solutions[s].sclh, solutions[s].scll);
|
|
+ VERBOSE("I2C TIMINGR: 0x%x\n", *timing);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * @brief Setup the I2C device timings.
|
|
+ * @param hi2c: Pointer to a struct i2c_handle_s structure that contains
|
|
+ * the configuration information for the specified I2C.
|
|
+ * @param init: Ref to the initialization configuration structure
|
|
+ * @param timing: Pointer to the final computed timing result
|
|
+ * @retval 0 if OK, negative value else
|
|
+ */
|
|
+static int i2c_setup_timing(struct i2c_handle_s *hi2c,
|
|
+ struct stm32_i2c_init_s *init,
|
|
+ uint32_t *timing)
|
|
+{
|
|
+ int rc = 0;
|
|
+ uint32_t clock_src;
|
|
+
|
|
+ clock_src = stm32mp_clk_get_rate(hi2c->clock);
|
|
+ if (clock_src == 0U) {
|
|
+ ERROR("I2C clock rate is 0\n");
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ do {
|
|
+ rc = i2c_compute_timing(init, clock_src, timing);
|
|
+ if (rc != 0) {
|
|
+ ERROR("Failed to compute I2C timings\n");
|
|
+ if (init->speed_mode > I2C_SPEED_STANDARD) {
|
|
+ init->speed_mode--;
|
|
+ WARN("Downgrade I2C speed to %uHz)\n",
|
|
+ i2c_specs[init->speed_mode].rate);
|
|
+ } else {
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ } while (rc != 0);
|
|
+
|
|
+ if (rc != 0) {
|
|
+ ERROR("Impossible to compute I2C timings\n");
|
|
+ return rc;
|
|
+ }
|
|
+
|
|
+ VERBOSE("I2C Speed Mode(%i), Freq(%i), Clk Source(%i)\n",
|
|
+ init->speed_mode, i2c_specs[init->speed_mode].rate, clock_src);
|
|
+ VERBOSE("I2C Rise(%i) and Fall(%i) Time\n",
|
|
+ init->rise_time, init->fall_time);
|
|
+ VERBOSE("I2C Analog Filter(%s), DNF(%i)\n",
|
|
+ (init->analog_filter ? "On" : "Off"),
|
|
+ init->digital_filter_coef);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * @brief Configure I2C Analog noise filter.
|
|
+ * @param hi2c: Pointer to a struct i2c_handle_s structure that contains
|
|
+ * the configuration information for the specified I2C peripheral.
|
|
+ * @param analog_filter: New state of the Analog filter
|
|
+ * @retval 0 if OK, negative value else
|
|
+ */
|
|
+static int i2c_config_analog_filter(struct i2c_handle_s *hi2c,
|
|
+ uint32_t analog_filter)
|
|
+{
|
|
+ if ((hi2c->i2c_state != I2C_STATE_READY) || (hi2c->lock != 0U)) {
|
|
+ return -EBUSY;
|
|
+ }
|
|
+
|
|
+ hi2c->lock = 1;
|
|
+
|
|
+ hi2c->i2c_state = I2C_STATE_BUSY;
|
|
+
|
|
+ /* Disable the selected I2C peripheral */
|
|
+ mmio_clrbits_32(hi2c->i2c_base_addr + I2C_CR1, I2C_CR1_PE);
|
|
+
|
|
+ /* Reset I2Cx ANOFF bit */
|
|
+ mmio_clrbits_32(hi2c->i2c_base_addr + I2C_CR1, I2C_CR1_ANFOFF);
|
|
+
|
|
+ /* Set analog filter bit*/
|
|
+ mmio_setbits_32(hi2c->i2c_base_addr + I2C_CR1, analog_filter);
|
|
+
|
|
+ /* Enable the selected I2C peripheral */
|
|
+ mmio_setbits_32(hi2c->i2c_base_addr + I2C_CR1, I2C_CR1_PE);
|
|
+
|
|
+ hi2c->i2c_state = I2C_STATE_READY;
|
|
+
|
|
+ hi2c->lock = 0;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * @brief Get I2C setup information from the device tree and set pinctrl
|
|
+ * configuration.
|
|
+ * @param fdt: Pointer to the device tree
|
|
+ * @param node: I2C node offset
|
|
+ * @param init: Ref to the initialization configuration structure
|
|
+ * @retval 0 if OK, negative value else
|
|
+ */
|
|
+int stm32_i2c_get_setup_from_fdt(void *fdt, int node,
|
|
+ struct stm32_i2c_init_s *init)
|
|
+{
|
|
+ const fdt32_t *cuint;
|
|
+
|
|
+ cuint = fdt_getprop(fdt, node, "i2c-scl-rising-time-ns", NULL);
|
|
+ if (cuint == NULL) {
|
|
+ init->rise_time = STM32_I2C_RISE_TIME_DEFAULT;
|
|
+ } else {
|
|
+ init->rise_time = fdt32_to_cpu(*cuint);
|
|
+ }
|
|
+
|
|
+ cuint = fdt_getprop(fdt, node, "i2c-scl-falling-time-ns", NULL);
|
|
+ if (cuint == NULL) {
|
|
+ init->fall_time = STM32_I2C_FALL_TIME_DEFAULT;
|
|
+ } else {
|
|
+ init->fall_time = fdt32_to_cpu(*cuint);
|
|
+ }
|
|
+
|
|
+ cuint = fdt_getprop(fdt, node, "clock-frequency", NULL);
|
|
+ if (cuint == NULL) {
|
|
+ init->speed_mode = STM32_I2C_SPEED_DEFAULT;
|
|
+ } else {
|
|
+ switch (fdt32_to_cpu(*cuint)) {
|
|
+ case STANDARD_RATE:
|
|
+ init->speed_mode = I2C_SPEED_STANDARD;
|
|
+ break;
|
|
+ case FAST_RATE:
|
|
+ init->speed_mode = I2C_SPEED_FAST;
|
|
+ break;
|
|
+ case FAST_PLUS_RATE:
|
|
+ init->speed_mode = I2C_SPEED_FAST_PLUS;
|
|
+ break;
|
|
+ default:
|
|
+ init->speed_mode = STM32_I2C_SPEED_DEFAULT;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return dt_set_pinctrl_config(node);
|
|
+}
|
|
+
|
|
+/*
|
|
+ * @brief Initialize the I2C device.
|
|
+ * @param hi2c: Pointer to a struct i2c_handle_s structure that contains
|
|
+ * the configuration information for the specified I2C.
|
|
+ * @param init_data: Initialization configuration structure
|
|
+ * @retval 0 if OK, negative value else
|
|
+ */
|
|
+int stm32_i2c_init(struct i2c_handle_s *hi2c,
|
|
+ struct stm32_i2c_init_s *init_data)
|
|
+{
|
|
+ int rc = 0;
|
|
+ uint32_t timing;
|
|
+
|
|
+ if (hi2c == NULL) {
|
|
+ return -ENOENT;
|
|
+ }
|
|
+
|
|
+ if (hi2c->i2c_state == I2C_STATE_RESET) {
|
|
+ hi2c->lock = 0;
|
|
+ }
|
|
+
|
|
+ hi2c->i2c_state = I2C_STATE_BUSY;
|
|
+
|
|
+ rc = i2c_setup_timing(hi2c, init_data, &timing);
|
|
+ if (rc != 0) {
|
|
+ return rc;
|
|
+ }
|
|
+
|
|
+ stm32mp_clk_enable(hi2c->clock);
|
|
+
|
|
+ /* Disable the selected I2C peripheral */
|
|
+ mmio_clrbits_32(hi2c->i2c_base_addr + I2C_CR1, I2C_CR1_PE);
|
|
+
|
|
+ /* Configure I2Cx: Frequency range */
|
|
+ mmio_write_32(hi2c->i2c_base_addr + I2C_TIMINGR,
|
|
+ timing & TIMINGR_CLEAR_MASK);
|
|
+
|
|
+ /* Disable Own Address1 before set the Own Address1 configuration */
|
|
+ mmio_clrbits_32(hi2c->i2c_base_addr + I2C_OAR1, I2C_OAR1_OA1EN);
|
|
+
|
|
+ /* Configure I2Cx: Own Address1 and ack own address1 mode */
|
|
+ if (init_data->addressing_mode == I2C_ADDRESSINGMODE_7BIT) {
|
|
+ mmio_write_32(hi2c->i2c_base_addr + I2C_OAR1,
|
|
+ I2C_OAR1_OA1EN | init_data->own_address1);
|
|
+ } else { /* I2C_ADDRESSINGMODE_10BIT */
|
|
+ mmio_write_32(hi2c->i2c_base_addr + I2C_OAR1,
|
|
+ I2C_OAR1_OA1EN | I2C_OAR1_OA1MODE |
|
|
+ init_data->own_address1);
|
|
+ }
|
|
+
|
|
+ mmio_write_32(hi2c->i2c_base_addr + I2C_CR2, 0);
|
|
+
|
|
+ /* Configure I2Cx: Addressing Master mode */
|
|
+ if (init_data->addressing_mode == I2C_ADDRESSINGMODE_10BIT) {
|
|
+ mmio_setbits_32(hi2c->i2c_base_addr + I2C_CR2, I2C_CR2_ADD10);
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * Enable the AUTOEND by default, and enable NACK
|
|
+ * (should be disabled only during Slave process).
|
|
+ */
|
|
+ mmio_setbits_32(hi2c->i2c_base_addr + I2C_CR2,
|
|
+ I2C_CR2_AUTOEND | I2C_CR2_NACK);
|
|
+
|
|
+ /* Disable Own Address2 before set the Own Address2 configuration */
|
|
+ mmio_clrbits_32(hi2c->i2c_base_addr + I2C_OAR2, I2C_DUALADDRESS_ENABLE);
|
|
+
|
|
+ /* Configure I2Cx: Dual mode and Own Address2 */
|
|
+ mmio_write_32(hi2c->i2c_base_addr + I2C_OAR2,
|
|
+ init_data->dual_address_mode |
|
|
+ init_data->own_address2 |
|
|
+ (init_data->own_address2_masks << 8));
|
|
+
|
|
+ /* Configure I2Cx: Generalcall and NoStretch mode */
|
|
+ mmio_write_32(hi2c->i2c_base_addr + I2C_CR1,
|
|
+ init_data->general_call_mode |
|
|
+ init_data->no_stretch_mode);
|
|
+
|
|
+ /* Enable the selected I2C peripheral */
|
|
+ mmio_setbits_32(hi2c->i2c_base_addr + I2C_CR1, I2C_CR1_PE);
|
|
+
|
|
+ hi2c->i2c_err = I2C_ERROR_NONE;
|
|
+ hi2c->i2c_state = I2C_STATE_READY;
|
|
+ hi2c->i2c_mode = I2C_MODE_NONE;
|
|
+
|
|
+ rc = i2c_config_analog_filter(hi2c, init_data->analog_filter ?
|
|
+ I2C_ANALOGFILTER_ENABLE :
|
|
+ I2C_ANALOGFILTER_DISABLE);
|
|
+ if (rc != 0) {
|
|
+ ERROR("Cannot initialize I2C analog filter (%d)\n", rc);
|
|
+ stm32mp_clk_disable(hi2c->clock);
|
|
+ return rc;
|
|
+ }
|
|
+
|
|
+ stm32mp_clk_disable(hi2c->clock);
|
|
+
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * @brief Generic function to write an amount of data in blocking mode
|
|
+ * (for Memory Mode and Master Mode)
|
|
+ * @param hi2c: Pointer to a struct i2c_handle_s structure that contains
|
|
+ * the configuration information for the specified I2C.
|
|
+ * @param dev_addr: Target device address
|
|
+ * @param mem_addr: Internal memory address (if Memory Mode)
|
|
+ * @param mem_add_size: Size of internal memory address (if Memory Mode)
|
|
+ * @param p_data: Pointer to data buffer
|
|
+ * @param size: Amount of data to be sent
|
|
+ * @param timeout_ms: Timeout duration in milliseconds
|
|
+ * @param mode: Communication mode
|
|
+ * @retval 0 if OK, negative value else
|
|
+ */
|
|
+static int i2c_write(struct i2c_handle_s *hi2c, uint16_t dev_addr,
|
|
+ uint16_t mem_addr, uint16_t mem_add_size,
|
|
+ uint8_t *p_data, uint16_t size, uint32_t timeout_ms,
|
|
+ enum i2c_mode_e mode)
|
|
+{
|
|
+ uint64_t tick_start;
|
|
+ uint64_t tick_to = ms2tick(timeout_ms);
|
|
+ int rc = -EIO;
|
|
+ uint8_t *p_buff = p_data;
|
|
+ uint32_t xfer_size;
|
|
+ uint32_t xfer_count = size;
|
|
+
|
|
+ if ((mode != I2C_MODE_MASTER) && (mode != I2C_MODE_MEM)) {
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ if ((hi2c->i2c_state != I2C_STATE_READY) || (hi2c->lock != 0U)) {
|
|
+ return -EBUSY;
|
|
+ }
|
|
+
|
|
+ if ((p_data == NULL) || (size == 0U)) {
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ stm32mp_clk_enable(hi2c->clock);
|
|
+
|
|
+ hi2c->lock = 1;
|
|
+
|
|
+ tick_start = timeout_start();
|
|
+
|
|
+ if (i2c_wait_flag(hi2c, I2C_FLAG_BUSY, 1, ms2tick(I2C_TIMEOUT_BUSY_MS),
|
|
+ tick_start) != 0) {
|
|
+ goto bail;
|
|
+ }
|
|
+
|
|
+ hi2c->i2c_state = I2C_STATE_BUSY_TX;
|
|
+ hi2c->i2c_mode = mode;
|
|
+ hi2c->i2c_err = I2C_ERROR_NONE;
|
|
+
|
|
+ if (mode == I2C_MODE_MEM) {
|
|
+ /* In Memory Mode, Send Slave Address and Memory Address */
|
|
+ if (i2c_request_memory_write(hi2c, dev_addr,
|
|
+ mem_addr, mem_add_size,
|
|
+ tick_to, tick_start) != 0) {
|
|
+ goto bail;
|
|
+ }
|
|
+
|
|
+ if (xfer_count > MAX_NBYTE_SIZE) {
|
|
+ xfer_size = MAX_NBYTE_SIZE;
|
|
+ i2c_transfer_config(hi2c, dev_addr, xfer_size,
|
|
+ I2C_RELOAD_MODE, I2C_NO_STARTSTOP);
|
|
+ } else {
|
|
+ xfer_size = xfer_count;
|
|
+ i2c_transfer_config(hi2c, dev_addr, xfer_size,
|
|
+ I2C_AUTOEND_MODE, I2C_NO_STARTSTOP);
|
|
+ }
|
|
+ } else {
|
|
+ /* In Master Mode, Send Slave Address */
|
|
+ if (xfer_count > MAX_NBYTE_SIZE) {
|
|
+ xfer_size = MAX_NBYTE_SIZE;
|
|
+ i2c_transfer_config(hi2c, dev_addr, xfer_size,
|
|
+ I2C_RELOAD_MODE,
|
|
+ I2C_GENERATE_START_WRITE);
|
|
+ } else {
|
|
+ xfer_size = xfer_count;
|
|
+ i2c_transfer_config(hi2c, dev_addr, xfer_size,
|
|
+ I2C_AUTOEND_MODE,
|
|
+ I2C_GENERATE_START_WRITE);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ do {
|
|
+ if (i2c_wait_txis(hi2c, tick_to, tick_start) != 0) {
|
|
+ goto bail;
|
|
+ }
|
|
+
|
|
+ mmio_write_8(hi2c->i2c_base_addr + I2C_TXDR, *p_buff);
|
|
+ p_buff++;
|
|
+ xfer_count--;
|
|
+ xfer_size--;
|
|
+
|
|
+ if ((xfer_count != 0U) && (xfer_size == 0U)) {
|
|
+ /* Wait until TCR flag is set */
|
|
+ if (i2c_wait_flag(hi2c, I2C_FLAG_TCR, 0, tick_to,
|
|
+ tick_start) != 0) {
|
|
+ goto bail;
|
|
+ }
|
|
+
|
|
+ if (xfer_count > MAX_NBYTE_SIZE) {
|
|
+ xfer_size = MAX_NBYTE_SIZE;
|
|
+ i2c_transfer_config(hi2c, dev_addr,
|
|
+ xfer_size,
|
|
+ I2C_RELOAD_MODE,
|
|
+ I2C_NO_STARTSTOP);
|
|
+ } else {
|
|
+ xfer_size = xfer_count;
|
|
+ i2c_transfer_config(hi2c, dev_addr,
|
|
+ xfer_size,
|
|
+ I2C_AUTOEND_MODE,
|
|
+ I2C_NO_STARTSTOP);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ } while (xfer_count > 0U);
|
|
+
|
|
+ /*
|
|
+ * No need to Check TC flag, with AUTOEND mode the stop
|
|
+ * is automatically generated.
|
|
+ * Wait until STOPF flag is reset.
|
|
+ */
|
|
+ if (i2c_wait_stop(hi2c, tick_to, tick_start) != 0) {
|
|
+ goto bail;
|
|
+ }
|
|
+
|
|
+ mmio_write_32(hi2c->i2c_base_addr + I2C_ICR, I2C_FLAG_STOPF);
|
|
+
|
|
+ mmio_clrbits_32(hi2c->i2c_base_addr + I2C_CR2, I2C_RESET_CR2);
|
|
+
|
|
+ hi2c->i2c_state = I2C_STATE_READY;
|
|
+ hi2c->i2c_mode = I2C_MODE_NONE;
|
|
+
|
|
+ rc = 0;
|
|
+
|
|
+bail:
|
|
+ hi2c->lock = 0;
|
|
+ stm32mp_clk_disable(hi2c->clock);
|
|
+
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * @brief Write an amount of data in blocking mode to a specific memory
|
|
+ * address.
|
|
+ * @param hi2c: Pointer to a struct i2c_handle_s structure that contains
|
|
+ * the configuration information for the specified I2C.
|
|
+ * @param dev_addr: Target device address
|
|
+ * @param mem_addr: Internal memory address
|
|
+ * @param mem_add_size: Size of internal memory address
|
|
+ * @param p_data: Pointer to data buffer
|
|
+ * @param size: Amount of data to be sent
|
|
+ * @param timeout_ms: Timeout duration in milliseconds
|
|
+ * @retval 0 if OK, negative value else
|
|
+ */
|
|
+int stm32_i2c_mem_write(struct i2c_handle_s *hi2c, uint16_t dev_addr,
|
|
+ uint16_t mem_addr, uint16_t mem_add_size,
|
|
+ uint8_t *p_data, uint16_t size, uint32_t timeout_ms)
|
|
+{
|
|
+ return i2c_write(hi2c, dev_addr, mem_addr, mem_add_size,
|
|
+ p_data, size, timeout_ms, I2C_MODE_MEM);
|
|
+}
|
|
+
|
|
+/*
|
|
+ * @brief Transmits in master mode an amount of data in blocking mode.
|
|
+ * @param hi2c: Pointer to a struct i2c_handle_s structure that contains
|
|
+ * the configuration information for the specified I2C.
|
|
+ * @param dev_addr: Target device address
|
|
+ * @param p_data: Pointer to data buffer
|
|
+ * @param size: Amount of data to be sent
|
|
+ * @param timeout_ms: Timeout duration in milliseconds
|
|
+ * @retval 0 if OK, negative value else
|
|
+ */
|
|
+int stm32_i2c_master_transmit(struct i2c_handle_s *hi2c, uint16_t dev_addr,
|
|
+ uint8_t *p_data, uint16_t size,
|
|
+ uint32_t timeout_ms)
|
|
+{
|
|
+ return i2c_write(hi2c, dev_addr, 0, 0,
|
|
+ p_data, size, timeout_ms, I2C_MODE_MASTER);
|
|
+}
|
|
+
|
|
+/*
|
|
+ * @brief Generic function to read an amount of data in blocking mode
|
|
+ * (for Memory Mode and Master Mode)
|
|
+ * @param hi2c: Pointer to a struct i2c_handle_s structure that contains
|
|
+ * the configuration information for the specified I2C.
|
|
+ * @param dev_addr: Target device address
|
|
+ * @param mem_addr: Internal memory address (if Memory Mode)
|
|
+ * @param mem_add_size: Size of internal memory address (if Memory Mode)
|
|
+ * @param p_data: Pointer to data buffer
|
|
+ * @param size: Amount of data to be sent
|
|
+ * @param timeout_ms: Timeout duration in milliseconds
|
|
+ * @param mode: Communication mode
|
|
+ * @retval 0 if OK, negative value else
|
|
+ */
|
|
+static int i2c_read(struct i2c_handle_s *hi2c, uint16_t dev_addr,
|
|
+ uint16_t mem_addr, uint16_t mem_add_size,
|
|
+ uint8_t *p_data, uint16_t size, uint32_t timeout_ms,
|
|
+ enum i2c_mode_e mode)
|
|
+{
|
|
+ uint64_t tick_start;
|
|
+ uint64_t tick_to = ms2tick(timeout_ms);
|
|
+ int rc = -EIO;
|
|
+ uint8_t *p_buff = p_data;
|
|
+ uint32_t xfer_count = size;
|
|
+ uint32_t xfer_size;
|
|
+
|
|
+ if ((mode != I2C_MODE_MASTER) && (mode != I2C_MODE_MEM)) {
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ if ((hi2c->i2c_state != I2C_STATE_READY) || (hi2c->lock != 0U)) {
|
|
+ return -EBUSY;
|
|
+ }
|
|
+
|
|
+ if ((p_data == NULL) || (size == 0U)) {
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ stm32mp_clk_enable(hi2c->clock);
|
|
+
|
|
+ hi2c->lock = 1;
|
|
+
|
|
+ tick_start = timeout_start();
|
|
+ if (i2c_wait_flag(hi2c, I2C_FLAG_BUSY, 1, ms2tick(I2C_TIMEOUT_BUSY_MS),
|
|
+ tick_start) != 0) {
|
|
+ goto bail;
|
|
+ }
|
|
+
|
|
+ hi2c->i2c_state = I2C_STATE_BUSY_RX;
|
|
+ hi2c->i2c_mode = mode;
|
|
+ hi2c->i2c_err = I2C_ERROR_NONE;
|
|
+
|
|
+ if (mode == I2C_MODE_MEM) {
|
|
+ /* Send Memory Address */
|
|
+ if (i2c_request_memory_read(hi2c, dev_addr,
|
|
+ mem_addr, mem_add_size,
|
|
+ tick_to, tick_start) != 0) {
|
|
+ goto bail;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * Send Slave Address.
|
|
+ * Set NBYTES to write and reload if xfer_count > MAX_NBYTE_SIZE
|
|
+ * and generate RESTART.
|
|
+ */
|
|
+ if (xfer_count > MAX_NBYTE_SIZE) {
|
|
+ xfer_size = MAX_NBYTE_SIZE;
|
|
+ i2c_transfer_config(hi2c, dev_addr, xfer_size,
|
|
+ I2C_RELOAD_MODE, I2C_GENERATE_START_READ);
|
|
+ } else {
|
|
+ xfer_size = xfer_count;
|
|
+ i2c_transfer_config(hi2c, dev_addr, xfer_size,
|
|
+ I2C_AUTOEND_MODE, I2C_GENERATE_START_READ);
|
|
+ }
|
|
+
|
|
+ do {
|
|
+ if (i2c_wait_flag(hi2c, I2C_FLAG_RXNE, 0, tick_to,
|
|
+ tick_start) != 0) {
|
|
+ goto bail;
|
|
+ }
|
|
+
|
|
+ *p_buff = mmio_read_8(hi2c->i2c_base_addr + I2C_RXDR);
|
|
+ p_buff++;
|
|
+ xfer_size--;
|
|
+ xfer_count--;
|
|
+
|
|
+ if ((xfer_count != 0U) && (xfer_size == 0U)) {
|
|
+ if (i2c_wait_flag(hi2c, I2C_FLAG_TCR, 0, tick_to,
|
|
+ tick_start) != 0) {
|
|
+ goto bail;
|
|
+ }
|
|
+
|
|
+ if (xfer_count > MAX_NBYTE_SIZE) {
|
|
+ xfer_size = MAX_NBYTE_SIZE;
|
|
+ i2c_transfer_config(hi2c, dev_addr,
|
|
+ xfer_size,
|
|
+ I2C_RELOAD_MODE,
|
|
+ I2C_NO_STARTSTOP);
|
|
+ } else {
|
|
+ xfer_size = xfer_count;
|
|
+ i2c_transfer_config(hi2c, dev_addr,
|
|
+ xfer_size,
|
|
+ I2C_AUTOEND_MODE,
|
|
+ I2C_NO_STARTSTOP);
|
|
+ }
|
|
+ }
|
|
+ } while (xfer_count > 0U);
|
|
+
|
|
+ /*
|
|
+ * No need to Check TC flag, with AUTOEND mode the stop
|
|
+ * is automatically generated.
|
|
+ * Wait until STOPF flag is reset.
|
|
+ */
|
|
+ if (i2c_wait_stop(hi2c, tick_to, tick_start) != 0) {
|
|
+ goto bail;
|
|
+ }
|
|
+
|
|
+ mmio_write_32(hi2c->i2c_base_addr + I2C_ICR, I2C_FLAG_STOPF);
|
|
+
|
|
+ mmio_clrbits_32(hi2c->i2c_base_addr + I2C_CR2, I2C_RESET_CR2);
|
|
+
|
|
+ hi2c->i2c_state = I2C_STATE_READY;
|
|
+ hi2c->i2c_mode = I2C_MODE_NONE;
|
|
+
|
|
+ rc = 0;
|
|
+
|
|
+bail:
|
|
+ hi2c->lock = 0;
|
|
+ stm32mp_clk_disable(hi2c->clock);
|
|
+
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * @brief Read an amount of data in blocking mode from a specific memory
|
|
+ * address.
|
|
+ * @param hi2c: Pointer to a struct i2c_handle_s structure that contains
|
|
+ * the configuration information for the specified I2C.
|
|
+ * @param dev_addr: Target device address
|
|
+ * @param mem_addr: Internal memory address
|
|
+ * @param mem_add_size: Size of internal memory address
|
|
+ * @param p_data: Pointer to data buffer
|
|
+ * @param size: Amount of data to be sent
|
|
+ * @param timeout_ms: Timeout duration in milliseconds
|
|
+ * @retval 0 if OK, negative value else
|
|
+ */
|
|
+int stm32_i2c_mem_read(struct i2c_handle_s *hi2c, uint16_t dev_addr,
|
|
+ uint16_t mem_addr, uint16_t mem_add_size,
|
|
+ uint8_t *p_data, uint16_t size, uint32_t timeout_ms)
|
|
+{
|
|
+ return i2c_read(hi2c, dev_addr, mem_addr, mem_add_size,
|
|
+ p_data, size, timeout_ms, I2C_MODE_MEM);
|
|
+}
|
|
+
|
|
+/*
|
|
+ * @brief Receives in master mode an amount of data in blocking mode.
|
|
+ * @param hi2c: Pointer to a struct i2c_handle_s structure that contains
|
|
+ * the configuration information for the specified I2C.
|
|
+ * @param dev_addr: Target device address
|
|
+ * @param p_data: Pointer to data buffer
|
|
+ * @param size: Amount of data to be sent
|
|
+ * @param timeout_ms: Timeout duration in milliseconds
|
|
+ * @retval 0 if OK, negative value else
|
|
+ */
|
|
+int stm32_i2c_master_receive(struct i2c_handle_s *hi2c, uint16_t dev_addr,
|
|
+ uint8_t *p_data, uint16_t size,
|
|
+ uint32_t timeout_ms)
|
|
+{
|
|
+ return i2c_read(hi2c, dev_addr, 0, 0,
|
|
+ p_data, size, timeout_ms, I2C_MODE_MASTER);
|
|
+}
|
|
+
|
|
+/*
|
|
+ * @brief Checks if target device is ready for communication.
|
|
+ * @note This function is used with Memory devices
|
|
+ * @param hi2c: Pointer to a struct i2c_handle_s structure that contains
|
|
+ * the configuration information for the specified I2C.
|
|
+ * @param dev_addr: Target device address
|
|
+ * @param trials: Number of trials
|
|
+ * @param timeout_ms: Timeout duration in milliseconds
|
|
+ * @retval True if device is ready, false else
|
|
+ */
|
|
+bool stm32_i2c_is_device_ready(struct i2c_handle_s *hi2c,
|
|
+ uint16_t dev_addr, uint32_t trials,
|
|
+ uint32_t timeout_ms)
|
|
+{
|
|
+ uint32_t i2c_trials = 0U;
|
|
+ bool rc = false;
|
|
+ uint64_t tick_to = ms2tick(timeout_ms);
|
|
+
|
|
+ if ((hi2c->i2c_state != I2C_STATE_READY) || (hi2c->lock != 0U)) {
|
|
+ return rc;
|
|
+ }
|
|
+
|
|
+ stm32mp_clk_enable(hi2c->clock);
|
|
+
|
|
+ hi2c->lock = 1;
|
|
+ hi2c->i2c_mode = I2C_MODE_NONE;
|
|
+
|
|
+ if ((mmio_read_32(hi2c->i2c_base_addr + I2C_ISR) & I2C_FLAG_BUSY) !=
|
|
+ 0U) {
|
|
+ goto bail;
|
|
+ }
|
|
+
|
|
+ hi2c->i2c_state = I2C_STATE_BUSY;
|
|
+ hi2c->i2c_err = I2C_ERROR_NONE;
|
|
+
|
|
+ do {
|
|
+ uint64_t tick_start;
|
|
+
|
|
+ /* Generate Start */
|
|
+ if ((mmio_read_32(hi2c->i2c_base_addr + I2C_OAR1) &
|
|
+ I2C_OAR1_OA1MODE) == 0) {
|
|
+ mmio_write_32(hi2c->i2c_base_addr + I2C_CR2,
|
|
+ (((uint32_t)dev_addr & I2C_CR2_SADD) |
|
|
+ I2C_CR2_START | I2C_CR2_AUTOEND) &
|
|
+ ~I2C_CR2_RD_WRN);
|
|
+ } else {
|
|
+ mmio_write_32(hi2c->i2c_base_addr + I2C_CR2,
|
|
+ (((uint32_t)dev_addr & I2C_CR2_SADD) |
|
|
+ I2C_CR2_START | I2C_CR2_ADD10) &
|
|
+ ~I2C_CR2_RD_WRN);
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * No need to Check TC flag, with AUTOEND mode the stop
|
|
+ * is automatically generated.
|
|
+ * Wait until STOPF flag is set or a NACK flag is set.
|
|
+ */
|
|
+ tick_start = timeout_start();
|
|
+ do {
|
|
+ if ((mmio_read_32(hi2c->i2c_base_addr + I2C_ISR) &
|
|
+ (I2C_FLAG_STOPF | I2C_FLAG_AF)) != 0U) {
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ if (timeout_elapsed(tick_start, tick_to)) {
|
|
+ notif_i2c_timeout(hi2c);
|
|
+ goto bail;
|
|
+ }
|
|
+ } while (true);
|
|
+
|
|
+ if ((mmio_read_32(hi2c->i2c_base_addr + I2C_ISR) &
|
|
+ I2C_FLAG_AF) == 0U) {
|
|
+ if (i2c_wait_flag(hi2c, I2C_FLAG_STOPF, 0, tick_to,
|
|
+ tick_start) != 0) {
|
|
+ goto bail;
|
|
+ }
|
|
+
|
|
+ mmio_write_32(hi2c->i2c_base_addr + I2C_ICR,
|
|
+ I2C_FLAG_STOPF);
|
|
+
|
|
+ hi2c->i2c_state = I2C_STATE_READY;
|
|
+
|
|
+ rc = true;
|
|
+ goto bail;
|
|
+ }
|
|
+
|
|
+ if (i2c_wait_flag(hi2c, I2C_FLAG_STOPF, 0, tick_to,
|
|
+ tick_start) != 0) {
|
|
+ goto bail;
|
|
+ }
|
|
+
|
|
+ mmio_write_32(hi2c->i2c_base_addr + I2C_ICR, I2C_FLAG_AF);
|
|
+
|
|
+ mmio_write_32(hi2c->i2c_base_addr + I2C_ICR, I2C_FLAG_STOPF);
|
|
+
|
|
+ if (i2c_trials == trials) {
|
|
+ mmio_setbits_32(hi2c->i2c_base_addr + I2C_CR2,
|
|
+ I2C_CR2_STOP);
|
|
+
|
|
+ if (i2c_wait_flag(hi2c, I2C_FLAG_STOPF, 0, tick_to,
|
|
+ tick_start) != 0) {
|
|
+ goto bail;
|
|
+ }
|
|
+
|
|
+ mmio_write_32(hi2c->i2c_base_addr + I2C_ICR,
|
|
+ I2C_FLAG_STOPF);
|
|
+ }
|
|
+
|
|
+ i2c_trials++;
|
|
+ } while (i2c_trials < trials);
|
|
+
|
|
+ notif_i2c_timeout(hi2c);
|
|
+
|
|
+bail:
|
|
+ hi2c->lock = 0;
|
|
+ stm32mp_clk_disable(hi2c->clock);
|
|
+
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * @brief Master sends target device address followed by internal memory
|
|
+ * address for write request.
|
|
+ * @param hi2c: Pointer to a struct i2c_handle_s structure that contains
|
|
+ * the configuration information for the specified I2C.
|
|
+ * @param dev_addr: Target device address
|
|
+ * @param mem_addr: Internal memory address
|
|
+ * @param mem_add_size: Size of internal memory address
|
|
+ * @param tick_to: Tick timeout duration
|
|
+ * @param tick_start: Tick start value
|
|
+ * @retval 0 if OK, negative value else
|
|
+ */
|
|
+static int i2c_request_memory_write(struct i2c_handle_s *hi2c,
|
|
+ uint16_t dev_addr, uint16_t mem_addr,
|
|
+ uint16_t mem_add_size, uint64_t tick_to,
|
|
+ uint64_t tick_start)
|
|
+{
|
|
+ i2c_transfer_config(hi2c, dev_addr, mem_add_size, I2C_RELOAD_MODE,
|
|
+ I2C_GENERATE_START_WRITE);
|
|
+
|
|
+ if (i2c_wait_txis(hi2c, tick_to, tick_start) != 0) {
|
|
+ return -EIO;
|
|
+ }
|
|
+
|
|
+ if (mem_add_size == I2C_MEMADD_SIZE_8BIT) {
|
|
+ /* Send Memory Address */
|
|
+ mmio_write_8(hi2c->i2c_base_addr + I2C_TXDR,
|
|
+ (uint8_t)(mem_addr & 0x00FFU));
|
|
+ } else {
|
|
+ /* Send MSB of Memory Address */
|
|
+ mmio_write_8(hi2c->i2c_base_addr + I2C_TXDR,
|
|
+ (uint8_t)((mem_addr & 0xFF00U) >> 8));
|
|
+
|
|
+ if (i2c_wait_txis(hi2c, tick_to, tick_start) != 0) {
|
|
+ return -EIO;
|
|
+ }
|
|
+
|
|
+ /* Send LSB of Memory Address */
|
|
+ mmio_write_8(hi2c->i2c_base_addr + I2C_TXDR,
|
|
+ (uint8_t)(mem_addr & 0x00FFU));
|
|
+ }
|
|
+
|
|
+ if (i2c_wait_flag(hi2c, I2C_FLAG_TCR, 0, tick_to, tick_start) != 0) {
|
|
+ return -EIO;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * @brief Master sends target device address followed by internal memory
|
|
+ * address for read request.
|
|
+ * @param hi2c: Pointer to a struct i2c_handle_s structure that contains
|
|
+ * the configuration information for the specified I2C.
|
|
+ * @param dev_addr: Target device address
|
|
+ * @param mem_addr: Internal memory address
|
|
+ * @param mem_add_size: Size of internal memory address
|
|
+ * @param tick_to: Tick timeout duration
|
|
+ * @param tick_start: Tick start value
|
|
+ * @retval 0 if OK, negative value else
|
|
+ */
|
|
+static int i2c_request_memory_read(struct i2c_handle_s *hi2c, uint16_t dev_addr,
|
|
+ uint16_t mem_addr, uint16_t mem_add_size,
|
|
+ uint64_t tick_to, uint64_t tick_start)
|
|
+{
|
|
+ i2c_transfer_config(hi2c, dev_addr, mem_add_size, I2C_SOFTEND_MODE,
|
|
+ I2C_GENERATE_START_WRITE);
|
|
+
|
|
+ if (i2c_wait_txis(hi2c, tick_to, tick_start) != 0) {
|
|
+ return -EIO;
|
|
+ }
|
|
+
|
|
+ if (mem_add_size == I2C_MEMADD_SIZE_8BIT) {
|
|
+ /* Send Memory Address */
|
|
+ mmio_write_8(hi2c->i2c_base_addr + I2C_TXDR,
|
|
+ (uint8_t)(mem_addr & 0x00FFU));
|
|
+ } else {
|
|
+ /* Send MSB of Memory Address */
|
|
+ mmio_write_8(hi2c->i2c_base_addr + I2C_TXDR,
|
|
+ (uint8_t)((mem_addr & 0xFF00U) >> 8));
|
|
+
|
|
+ if (i2c_wait_txis(hi2c, tick_to, tick_start) != 0) {
|
|
+ return -EIO;
|
|
+ }
|
|
+
|
|
+ /* Send LSB of Memory Address */
|
|
+ mmio_write_8(hi2c->i2c_base_addr + I2C_TXDR,
|
|
+ (uint8_t)(mem_addr & 0x00FFU));
|
|
+ }
|
|
+
|
|
+ if (i2c_wait_flag(hi2c, I2C_FLAG_TC, 0, tick_to, tick_start) != 0) {
|
|
+ return -EIO;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * @brief I2C Tx data register flush process.
|
|
+ * @param hi2c: I2C handle
|
|
+ * @retval None
|
|
+ */
|
|
+static void i2c_flush_txdr(struct i2c_handle_s *hi2c)
|
|
+{
|
|
+ /*
|
|
+ * If a pending TXIS flag is set,
|
|
+ * write a dummy data in TXDR to clear it.
|
|
+ */
|
|
+ if ((mmio_read_32(hi2c->i2c_base_addr + I2C_ISR) & I2C_FLAG_TXIS) !=
|
|
+ 0U) {
|
|
+ mmio_write_32(hi2c->i2c_base_addr + I2C_TXDR, 0);
|
|
+ }
|
|
+
|
|
+ /* Flush TX register if not empty */
|
|
+ if ((mmio_read_32(hi2c->i2c_base_addr + I2C_ISR) & I2C_FLAG_TXE) ==
|
|
+ 0U) {
|
|
+ mmio_setbits_32(hi2c->i2c_base_addr + I2C_ISR,
|
|
+ I2C_FLAG_TXE);
|
|
+ }
|
|
+}
|
|
+
|
|
+/*
|
|
+ * @brief This function handles I2C Communication timeout.
|
|
+ * @param hi2c: Pointer to a struct i2c_handle_s structure that contains
|
|
+ * the configuration information for the specified I2C.
|
|
+ * @param flag: Specifies the I2C flag to check
|
|
+ * @param awaited_value: The awaited bit value for the flag (0 or 1)
|
|
+ * @param tick_to: Tick timeout duration
|
|
+ * @param tick_start: Tick start value
|
|
+ * @retval 0 if OK, negative value else
|
|
+ */
|
|
+static int i2c_wait_flag(struct i2c_handle_s *hi2c, uint32_t flag,
|
|
+ uint8_t awaited_value, uint64_t tick_to,
|
|
+ uint64_t tick_start)
|
|
+{
|
|
+ for ( ; ; ) {
|
|
+ uint32_t isr = mmio_read_32(hi2c->i2c_base_addr + I2C_ISR);
|
|
+
|
|
+ if (!!(isr & flag) != !!awaited_value) {
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ if (timeout_elapsed(tick_start, tick_to)) {
|
|
+ notif_i2c_timeout(hi2c);
|
|
+ hi2c->lock = 0;
|
|
+
|
|
+ return -EIO;
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
+/*
|
|
+ * @brief This function handles I2C Communication timeout for specific usage
|
|
+ * of TXIS flag.
|
|
+ * @param hi2c: Pointer to a struct i2c_handle_s structure that contains
|
|
+ * the configuration information for the specified I2C.
|
|
+ * @param tick_to: Tick timeout duration
|
|
+ * @param tick_start: Tick start value
|
|
+ * @retval 0 if OK, negative value else
|
|
+ */
|
|
+static int i2c_wait_txis(struct i2c_handle_s *hi2c, uint64_t tick_to,
|
|
+ uint64_t tick_start)
|
|
+{
|
|
+ while ((mmio_read_32(hi2c->i2c_base_addr + I2C_ISR) &
|
|
+ I2C_FLAG_TXIS) == 0U) {
|
|
+ if (i2c_ack_failed(hi2c, tick_to, tick_start) != 0) {
|
|
+ return -EIO;
|
|
+ }
|
|
+
|
|
+ if (timeout_elapsed(tick_start, tick_to)) {
|
|
+ notif_i2c_timeout(hi2c);
|
|
+ hi2c->lock = 0;
|
|
+
|
|
+ return -EIO;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * @brief This function handles I2C Communication timeout for specific
|
|
+ * usage of STOP flag.
|
|
+ * @param hi2c: Pointer to a struct i2c_handle_s structure that contains
|
|
+ * the configuration information for the specified I2C.
|
|
+ * @param tick_to: Tick timeout duration
|
|
+ * @param tick_start: Tick start value
|
|
+ * @retval 0 if OK, negative value else
|
|
+ */
|
|
+static int i2c_wait_stop(struct i2c_handle_s *hi2c, uint64_t tick_to,
|
|
+ uint64_t tick_start)
|
|
+{
|
|
+ while ((mmio_read_32(hi2c->i2c_base_addr + I2C_ISR) &
|
|
+ I2C_FLAG_STOPF) == 0U) {
|
|
+ if (i2c_ack_failed(hi2c, tick_to, tick_start) != 0) {
|
|
+ return -EIO;
|
|
+ }
|
|
+
|
|
+ if (timeout_elapsed(tick_start, tick_to)) {
|
|
+ notif_i2c_timeout(hi2c);
|
|
+ hi2c->lock = 0;
|
|
+
|
|
+ return -EIO;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * @brief This function handles Acknowledge failed detection during
|
|
+ * an I2C Communication.
|
|
+ * @param hi2c: Pointer to a struct i2c_handle_s structure that contains
|
|
+ * the configuration information for the specified I2C.
|
|
+ * @param tick_to: Tick timeout duration
|
|
+ * @param tick_start: Tick start value
|
|
+ * @retval 0 if OK, negative value else
|
|
+ */
|
|
+static int i2c_ack_failed(struct i2c_handle_s *hi2c, uint64_t tick_to,
|
|
+ uint64_t tick_start)
|
|
+{
|
|
+ if ((mmio_read_32(hi2c->i2c_base_addr + I2C_ISR) & I2C_FLAG_AF) == 0U) {
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * Wait until STOP Flag is reset.
|
|
+ * AutoEnd should be initiate after AF.
|
|
+ */
|
|
+ while ((mmio_read_32(hi2c->i2c_base_addr + I2C_ISR) &
|
|
+ I2C_FLAG_STOPF) == 0U) {
|
|
+ if (timeout_elapsed(tick_start, tick_to)) {
|
|
+ notif_i2c_timeout(hi2c);
|
|
+ hi2c->lock = 0;
|
|
+
|
|
+ return -EIO;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ mmio_write_32(hi2c->i2c_base_addr + I2C_ICR, I2C_FLAG_AF);
|
|
+
|
|
+ mmio_write_32(hi2c->i2c_base_addr + I2C_ICR, I2C_FLAG_STOPF);
|
|
+
|
|
+ i2c_flush_txdr(hi2c);
|
|
+
|
|
+ mmio_clrbits_32(hi2c->i2c_base_addr + I2C_CR2, I2C_RESET_CR2);
|
|
+
|
|
+ hi2c->i2c_err |= I2C_ERROR_AF;
|
|
+ hi2c->i2c_state = I2C_STATE_READY;
|
|
+ hi2c->i2c_mode = I2C_MODE_NONE;
|
|
+
|
|
+ hi2c->lock = 0;
|
|
+
|
|
+ return -EIO;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * @brief Handles I2Cx communication when starting transfer or during transfer
|
|
+ * (TC or TCR flag are set).
|
|
+ * @param hi2c: I2C handle
|
|
+ * @param dev_addr: Specifies the slave address to be programmed
|
|
+ * @param size: Specifies the number of bytes to be programmed.
|
|
+ * This parameter must be a value between 0 and 255.
|
|
+ * @param i2c_mode: New state of the I2C START condition generation.
|
|
+ * This parameter can be one of the following values:
|
|
+ * @arg @ref I2C_RELOAD_MODE: Enable Reload mode.
|
|
+ * @arg @ref I2C_AUTOEND_MODE: Enable Automatic end mode.
|
|
+ * @arg @ref I2C_SOFTEND_MODE: Enable Software end mode.
|
|
+ * @param request: New state of the I2C START condition generation.
|
|
+ * This parameter can be one of the following values:
|
|
+ * @arg @ref I2C_NO_STARTSTOP: Don't Generate stop and start condition.
|
|
+ * @arg @ref I2C_GENERATE_STOP: Generate stop condition
|
|
+ * (size should be set to 0).
|
|
+ * @arg @ref I2C_GENERATE_START_READ: Generate Restart for read request.
|
|
+ * @arg @ref I2C_GENERATE_START_WRITE: Generate Restart for write request.
|
|
+ * @retval None
|
|
+ */
|
|
+static void i2c_transfer_config(struct i2c_handle_s *hi2c, uint16_t dev_addr,
|
|
+ uint16_t size, uint32_t i2c_mode,
|
|
+ uint32_t request)
|
|
+{
|
|
+ uint32_t clr_value, set_value;
|
|
+
|
|
+ clr_value = (I2C_CR2_SADD | I2C_CR2_NBYTES | I2C_CR2_RELOAD |
|
|
+ I2C_CR2_AUTOEND | I2C_CR2_START | I2C_CR2_STOP) |
|
|
+ (I2C_CR2_RD_WRN & (request >> (31U - I2C_CR2_RD_WRN_OFFSET)));
|
|
+
|
|
+ set_value = ((uint32_t)dev_addr & I2C_CR2_SADD) |
|
|
+ (((uint32_t)size << I2C_CR2_NBYTES_OFFSET) & I2C_CR2_NBYTES) |
|
|
+ i2c_mode | request;
|
|
+
|
|
+ mmio_clrsetbits_32(hi2c->i2c_base_addr + I2C_CR2, clr_value, set_value);
|
|
+}
|
|
diff --git a/drivers/st/io/io_mmc.c b/drivers/st/io/io_mmc.c
|
|
new file mode 100644
|
|
index 0000000..bc9a91a
|
|
--- /dev/null
|
|
+++ b/drivers/st/io/io_mmc.c
|
|
@@ -0,0 +1,134 @@
|
|
+/*
|
|
+ * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
|
|
+ *
|
|
+ * SPDX-License-Identifier: BSD-3-Clause
|
|
+ */
|
|
+
|
|
+#include <assert.h>
|
|
+#include <debug.h>
|
|
+#include <errno.h>
|
|
+#include <io_driver.h>
|
|
+#include <io_mmc.h>
|
|
+#include <io_storage.h>
|
|
+#include <mmc.h>
|
|
+#include <stm32_sdmmc2.h>
|
|
+#include <string.h>
|
|
+
|
|
+/* SDMMC device functions */
|
|
+static int mmc_dev_open(const uintptr_t init_params, io_dev_info_t **dev_info);
|
|
+static int mmc_block_open(io_dev_info_t *dev_info, const uintptr_t spec,
|
|
+ io_entity_t *entity);
|
|
+static int mmc_dev_init(io_dev_info_t *dev_info, const uintptr_t init_params);
|
|
+static int mmc_block_seek(io_entity_t *entity, int mode,
|
|
+ signed long long offset);
|
|
+static int mmc_block_read(io_entity_t *entity, uintptr_t buffer, size_t length,
|
|
+ size_t *length_read);
|
|
+static int mmc_block_close(io_entity_t *entity);
|
|
+static int mmc_dev_close(io_dev_info_t *dev_info);
|
|
+static io_type_t device_type_mmc(void);
|
|
+
|
|
+static int64_t seek_offset;
|
|
+
|
|
+static const io_dev_connector_t mmc_dev_connector = {
|
|
+ .dev_open = mmc_dev_open
|
|
+};
|
|
+
|
|
+static const io_dev_funcs_t mmc_dev_funcs = {
|
|
+ .type = device_type_mmc,
|
|
+ .open = mmc_block_open,
|
|
+ .seek = mmc_block_seek,
|
|
+ .size = NULL,
|
|
+ .read = mmc_block_read,
|
|
+ .write = NULL,
|
|
+ .close = mmc_block_close,
|
|
+ .dev_init = mmc_dev_init,
|
|
+ .dev_close = mmc_dev_close,
|
|
+};
|
|
+
|
|
+static const io_dev_info_t mmc_dev_info = {
|
|
+ .funcs = &mmc_dev_funcs,
|
|
+ .info = 0,
|
|
+};
|
|
+
|
|
+/* Identify the device type as mmc device */
|
|
+static io_type_t device_type_mmc(void)
|
|
+{
|
|
+ return IO_TYPE_MMC;
|
|
+}
|
|
+
|
|
+/* Open a connection to the mmc device */
|
|
+static int mmc_dev_open(const uintptr_t init_params, io_dev_info_t **dev_info)
|
|
+{
|
|
+ assert(dev_info != NULL);
|
|
+ *dev_info = (io_dev_info_t *)&mmc_dev_info;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int mmc_dev_init(io_dev_info_t *dev_info, const uintptr_t init_params)
|
|
+{
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/* Close a connection to the mmc device */
|
|
+static int mmc_dev_close(io_dev_info_t *dev_info)
|
|
+{
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/* Open a file on the mmc device */
|
|
+static int mmc_block_open(io_dev_info_t *dev_info, const uintptr_t spec,
|
|
+ io_entity_t *entity)
|
|
+{
|
|
+ seek_offset = 0;
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/* Seek to a particular file offset on the mmc device */
|
|
+static int mmc_block_seek(io_entity_t *entity, int mode,
|
|
+ signed long long offset)
|
|
+{
|
|
+ seek_offset = offset;
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/* Read data from a file on the mmc device */
|
|
+static int mmc_block_read(io_entity_t *entity, uintptr_t buffer,
|
|
+ size_t length, size_t *length_read)
|
|
+{
|
|
+ uint8_t retries = 3U;
|
|
+
|
|
+ do {
|
|
+ retries--;
|
|
+ if (retries == 0U) {
|
|
+ return -EIO;
|
|
+ }
|
|
+
|
|
+ *length_read = mmc_read_blocks(seek_offset / MMC_BLOCK_SIZE,
|
|
+ buffer, length);
|
|
+
|
|
+ } while (*length_read != length);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/* Close a file on the mmc device */
|
|
+static int mmc_block_close(io_entity_t *entity)
|
|
+{
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/* Register the mmc driver with the IO abstraction */
|
|
+int register_io_dev_mmc(const io_dev_connector_t **dev_con)
|
|
+{
|
|
+ int result;
|
|
+
|
|
+ assert(dev_con != NULL);
|
|
+
|
|
+ result = io_register_device(&mmc_dev_info);
|
|
+ if (result == 0) {
|
|
+ *dev_con = &mmc_dev_connector;
|
|
+ }
|
|
+
|
|
+ return result;
|
|
+}
|
|
diff --git a/drivers/st/io/io_programmer_st_usb.c b/drivers/st/io/io_programmer_st_usb.c
|
|
new file mode 100644
|
|
index 0000000..a0871f6
|
|
--- /dev/null
|
|
+++ b/drivers/st/io/io_programmer_st_usb.c
|
|
@@ -0,0 +1,379 @@
|
|
+/*
|
|
+ * Copyright (c) 2017, STMicroelectronics - All Rights Reserved
|
|
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
|
|
+ *
|
|
+ * SPDX-License-Identifier: BSD-3-Clause
|
|
+ */
|
|
+
|
|
+#include <arch_helpers.h>
|
|
+#include <assert.h>
|
|
+#include <boot_api.h>
|
|
+#include <debug.h>
|
|
+#include <io_driver.h>
|
|
+#include <io_programmer.h>
|
|
+#include <io_programmer_st_usb.h>
|
|
+#include <io_stm32image.h>
|
|
+#include <io_storage.h>
|
|
+#include <platform_def.h>
|
|
+#include <stm32_iwdg.h>
|
|
+#include <stm32mp_auth.h>
|
|
+#include <stm32mp_dt.h>
|
|
+#include <string.h>
|
|
+#include <usb_ctx.h>
|
|
+#include <usb_st_dfu.h>
|
|
+
|
|
+static uint8_t first_usb_buffer[USB_DFU_MAX_XFER_SIZE + 1] __aligned(4);
|
|
+static usb_dfu_media_t usb_dfu_fops;
|
|
+static uint8_t checksum_is_wrong;
|
|
+static uint8_t usb_status;
|
|
+
|
|
+#define USB_STATE_READY 0
|
|
+#define USB_STATE_WRITTEN 1
|
|
+
|
|
+/* usb device functions */
|
|
+static int usb_dev_open(const uintptr_t init_params,
|
|
+ io_dev_info_t **dev_info);
|
|
+static int usb_block_open(io_dev_info_t *dev_info, const uintptr_t spec,
|
|
+ io_entity_t *entity);
|
|
+static int usb_dev_init(io_dev_info_t *dev_info,
|
|
+ const uintptr_t init_params);
|
|
+static int usb_partition_size(io_entity_t *entity, size_t *length);
|
|
+static int usb_block_seek(io_entity_t *entity, int mode,
|
|
+ signed long long offset);
|
|
+static int usb_block_read(io_entity_t *entity, uintptr_t buffer,
|
|
+ size_t length, size_t *length_read);
|
|
+static int usb_block_close(io_entity_t *entity);
|
|
+static int usb_dev_close(io_dev_info_t *dev_info);
|
|
+static io_type_t device_type_usb(void);
|
|
+
|
|
+static const io_dev_connector_t usb_dev_connector = {
|
|
+ .dev_open = usb_dev_open
|
|
+};
|
|
+
|
|
+static const io_dev_funcs_t usb_dev_funcs = {
|
|
+ .type = device_type_usb,
|
|
+ .open = usb_block_open,
|
|
+ .seek = usb_block_seek,
|
|
+ .size = usb_partition_size,
|
|
+ .read = usb_block_read,
|
|
+ .write = NULL,
|
|
+ .close = usb_block_close,
|
|
+ .dev_init = usb_dev_init,
|
|
+ .dev_close = usb_dev_close,
|
|
+};
|
|
+
|
|
+static io_dev_info_t usb_dev_info = {
|
|
+ .funcs = &usb_dev_funcs,
|
|
+ .info = (uintptr_t)0,
|
|
+};
|
|
+
|
|
+/* Identify the device type as usb */
|
|
+static io_type_t device_type_usb(void)
|
|
+{
|
|
+ return IO_TYPE_USB;
|
|
+}
|
|
+
|
|
+/* Callback to notify that data has been written in memory
|
|
+ * ( set by USBD_DFU_SetDownloadAddr)
|
|
+ */
|
|
+static uint16_t usb_callback_write_done(uint32_t *written_in, uint32_t len)
|
|
+{
|
|
+ VERBOSE("%s Written_in 0x%lx len %i\n", __func__, (uintptr_t)written_in,
|
|
+ len);
|
|
+
|
|
+ /* Update SRAM state machine when block writing is finished */
|
|
+ usb_status = USB_STATE_WRITTEN;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/* Call back to notify that a read memory is requested */
|
|
+static uint8_t *usb_callback_read(uint8_t *src, uint8_t *dest, uint32_t len)
|
|
+{
|
|
+ ERROR("%s read is not supported src 0x%lx dest 0x%lx len %i\n",
|
|
+ __func__, (uintptr_t)src, (uintptr_t)dest, len);
|
|
+
|
|
+ /* Return a valid address to avoid HardFault */
|
|
+ return (uint8_t *)(dest);
|
|
+}
|
|
+
|
|
+/* Get the status to know if written operation has been checked */
|
|
+static uint16_t usb_callback_get_status(void)
|
|
+{
|
|
+ uint16_t status;
|
|
+
|
|
+ /* According to SRAM state machine */
|
|
+ switch (usb_status) {
|
|
+ case USB_STATE_WRITTEN:
|
|
+ /* The SRAM bloc writing has been done, change state machine
|
|
+ * to set SRAM in SRAM_STATE_READY
|
|
+ */
|
|
+ usb_status = USB_STATE_READY;
|
|
+
|
|
+ /* Notice caller that SRAM block writing is finished */
|
|
+ status = DFU_MEDIA_STATE_WRITTEN;
|
|
+
|
|
+ /* Checks checksum calculation result */
|
|
+ if (checksum_is_wrong == 1) {
|
|
+ status = DFU_MEDIA_STATE_ERROR;
|
|
+ checksum_is_wrong = 0;
|
|
+ }
|
|
+ break;
|
|
+
|
|
+ case USB_STATE_READY:
|
|
+ /* Notice caller that SRAM is ready to be written */
|
|
+ status = DFU_MEDIA_STATE_READY;
|
|
+ break;
|
|
+
|
|
+ default:
|
|
+ status = DFU_MEDIA_STATE_ERROR;
|
|
+ ERROR("USB unknown state\n");
|
|
+ break;
|
|
+ }
|
|
+ VERBOSE("usb_callback_GetStatus status : %i\n", status);
|
|
+ return status;
|
|
+}
|
|
+
|
|
+/* Open a connection to the usb device */
|
|
+static int usb_dev_open(const uintptr_t init_params,
|
|
+ io_dev_info_t **dev_info)
|
|
+{
|
|
+ usb_handle_t *usb_core_handle = (usb_handle_t *)init_params;
|
|
+
|
|
+ assert(dev_info);
|
|
+ *dev_info = &usb_dev_info;
|
|
+
|
|
+ usb_dfu_fops.write_done = usb_callback_write_done;
|
|
+ usb_dfu_fops.read = usb_callback_read;
|
|
+ usb_dfu_fops.get_status = usb_callback_get_status;
|
|
+ usb_status = USB_STATE_READY;
|
|
+ checksum_is_wrong = 0;
|
|
+
|
|
+ usb_core_handle->user_data = &usb_dfu_fops;
|
|
+
|
|
+ usb_dev_info.info = (uintptr_t)usb_core_handle;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int usb_dev_init(io_dev_info_t *dev_info, const uintptr_t init_params)
|
|
+{
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/* Close a connection to the usb device */
|
|
+static int usb_dev_close(io_dev_info_t *dev_info)
|
|
+{
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/* Open a file on the usb device */
|
|
+static int usb_block_open(io_dev_info_t *dev_info, const uintptr_t spec,
|
|
+ io_entity_t *entity)
|
|
+{
|
|
+ int result;
|
|
+ uint32_t length = 0;
|
|
+ boot_api_image_header_t *header =
|
|
+ (boot_api_image_header_t *)first_usb_buffer;
|
|
+
|
|
+ const struct stm32image_part_info *partition_spec =
|
|
+ (struct stm32image_part_info *)spec;
|
|
+
|
|
+ /* Use PHASE_FSBL1 like init value*/
|
|
+ if (current_phase.phase_id == PHASE_FSBL1) {
|
|
+ assert(partition_spec);
|
|
+ assert(entity);
|
|
+
|
|
+ current_phase.current_packet = 0;
|
|
+
|
|
+ if (!strcmp(partition_spec->name, BL33_IMAGE_NAME)) {
|
|
+ /* read flash layout first for U-boot */
|
|
+ current_phase.phase_id = PHASE_FLASHLAYOUT;
|
|
+ current_phase.keep_header = 1;
|
|
+
|
|
+ usb_dfu_set_phase_id(PHASE_FLASHLAYOUT);
|
|
+ usb_dfu_set_download_addr((uintptr_t)
|
|
+ &first_usb_buffer[0]);
|
|
+
|
|
+ header->magic = 0;
|
|
+
|
|
+ while (((header->magic !=
|
|
+ BOOT_API_IMAGE_HEADER_MAGIC_NB) ||
|
|
+ usb_dfu_get_current_req() == DFU_DNLOAD)) {
|
|
+ usb_core_handle_it((usb_handle_t *)
|
|
+ usb_dev_info.info);
|
|
+ }
|
|
+ result = usb_block_read(NULL,
|
|
+ FLASHLAYOUT_BASE,
|
|
+ 0,
|
|
+ &length);
|
|
+ if (result != 0) {
|
|
+ return result;
|
|
+ }
|
|
+
|
|
+ flush_dcache_range((unsigned long)FLASHLAYOUT_BASE,
|
|
+ header->image_length +
|
|
+ sizeof(boot_api_image_header_t));
|
|
+
|
|
+ current_phase.current_packet = 0;
|
|
+ current_phase.keep_header = 0;
|
|
+ current_phase.phase_id = PHASE_SSBL;
|
|
+ current_phase.max_size = dt_get_ddr_size();
|
|
+ }
|
|
+ entity->info = (uintptr_t)¤t_phase;
|
|
+ result = 0;
|
|
+ } else {
|
|
+ WARN("A UART device is already active. Close first.\n");
|
|
+ result = -EIO;
|
|
+ }
|
|
+
|
|
+ return result;
|
|
+}
|
|
+
|
|
+/* Return the size of a partition */
|
|
+static int usb_partition_size(io_entity_t *entity, size_t *length)
|
|
+{
|
|
+ boot_api_image_header_t *header =
|
|
+ (boot_api_image_header_t *)first_usb_buffer;
|
|
+ int result = 0;
|
|
+
|
|
+ usb_dfu_set_phase_id(current_phase.phase_id);
|
|
+ usb_dfu_set_download_addr((uintptr_t)&first_usb_buffer[0]);
|
|
+
|
|
+ header->magic = 0;
|
|
+
|
|
+ while ((header->magic != BOOT_API_IMAGE_HEADER_MAGIC_NB) ||
|
|
+ (usb_dfu_get_current_req() == DFU_DNLOAD)) {
|
|
+ usb_core_handle_it((usb_handle_t *)usb_dev_info.info);
|
|
+ }
|
|
+
|
|
+ if (header->image_length > current_phase.max_size)
|
|
+ result = -EIO;
|
|
+ else
|
|
+ *length = header->image_length;
|
|
+
|
|
+ INFO("%s: partition size : 0x%x\n", __func__,
|
|
+ header->image_length);
|
|
+
|
|
+ return result;
|
|
+}
|
|
+
|
|
+/* Seek to a particular file offset on the usb device */
|
|
+static int usb_block_seek(io_entity_t *entity, int mode,
|
|
+ signed long long offset)
|
|
+{
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/* Read data from a file on the usb device */
|
|
+static int usb_block_read(io_entity_t *entity, uintptr_t buffer,
|
|
+ size_t length, size_t *length_read)
|
|
+{
|
|
+ uint8_t *local_ptr = (uint8_t *)buffer;
|
|
+ int result = 0;
|
|
+ boot_api_image_header_t *header =
|
|
+ (boot_api_image_header_t *)first_usb_buffer;
|
|
+
|
|
+ INFO("Start Download partition %i to address 0x%lx length %i\n",
|
|
+ current_phase.phase_id, buffer, length);
|
|
+
|
|
+ if (current_phase.keep_header) {
|
|
+ memcpy((uint8_t *)local_ptr,
|
|
+ (uint8_t *)&first_usb_buffer[0],
|
|
+ USB_DFU_MAX_XFER_SIZE);
|
|
+
|
|
+ usb_dfu_set_download_addr((uintptr_t)
|
|
+ &local_ptr[USB_DFU_MAX_XFER_SIZE]);
|
|
+ } else {
|
|
+ memcpy((uint8_t *)local_ptr,
|
|
+ (uint8_t *)
|
|
+ &first_usb_buffer[sizeof(boot_api_image_header_t)],
|
|
+ USB_DFU_MAX_XFER_SIZE -
|
|
+ sizeof(boot_api_image_header_t));
|
|
+
|
|
+ usb_dfu_set_download_addr((uintptr_t)
|
|
+ &local_ptr[USB_DFU_MAX_XFER_SIZE -
|
|
+ sizeof(boot_api_image_header_t)]);
|
|
+ }
|
|
+
|
|
+ while (!usb_dfu_download_is_completed()) {
|
|
+ /* Reload watchdog */
|
|
+ stm32_iwdg_refresh(IWDG2_INST);
|
|
+
|
|
+ usb_core_handle_it((usb_handle_t *)usb_dev_info.info);
|
|
+ }
|
|
+
|
|
+ usb_core_handle_it((usb_handle_t *)usb_dev_info.info);
|
|
+ usb_core_handle_it((usb_handle_t *)usb_dev_info.info);
|
|
+
|
|
+ if (current_phase.keep_header)
|
|
+ local_ptr += sizeof(boot_api_image_header_t);
|
|
+
|
|
+ /* Verify header and checksum payload */
|
|
+ result = check_header(header, (uintptr_t)local_ptr);
|
|
+ if (result) {
|
|
+ ERROR("Header check failed\n");
|
|
+ return result;
|
|
+ }
|
|
+
|
|
+#if defined(AUTHENTICATE_BL33)
|
|
+ if (current_phase.phase_id != PHASE_FLASHLAYOUT) {
|
|
+ result = check_authentication(header, (uintptr_t)local_ptr);
|
|
+ if (result != 0) {
|
|
+ ERROR("Authentication failed\n");
|
|
+ return result;
|
|
+ }
|
|
+ }
|
|
+#else
|
|
+ NOTICE("Authentication disabled: No signature check\n");
|
|
+#endif
|
|
+
|
|
+ /* Wait Detach in case of bl33 */
|
|
+ if (current_phase.phase_id == PHASE_SSBL) {
|
|
+ uint32_t timeout = IO_USB_TIMEOUT;
|
|
+ uint32_t detach_timeout = DETACH_TIMEOUT;
|
|
+
|
|
+ usb_dfu_set_phase_id(0x0);
|
|
+ usb_dfu_set_download_addr(UNDEFINE_DOWN_ADDR);
|
|
+ usb_dfu_request_detach();
|
|
+ while (timeout && detach_timeout) {
|
|
+ usb_core_handle_it((usb_handle_t *)
|
|
+ usb_dev_info.info);
|
|
+ if (!usb_dfu_detach_req())
|
|
+ detach_timeout--;
|
|
+ timeout--;
|
|
+ }
|
|
+ if (!timeout)
|
|
+ return -EIO;
|
|
+ /* STOP the USB Handler */
|
|
+ usb_core_stop((usb_handle_t *)usb_dev_info.info);
|
|
+ }
|
|
+
|
|
+ *length_read = length;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/* Close a file on the usb device */
|
|
+static int usb_block_close(io_entity_t *entity)
|
|
+{
|
|
+ current_phase.phase_id = PHASE_FSBL1;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/* Exported functions */
|
|
+
|
|
+/* Register the usb driver with the IO abstraction */
|
|
+int register_io_dev_usb(const io_dev_connector_t **dev_con)
|
|
+{
|
|
+ int result;
|
|
+
|
|
+ assert(dev_con);
|
|
+
|
|
+ result = io_register_device(&usb_dev_info);
|
|
+ if (!result)
|
|
+ *dev_con = &usb_dev_connector;
|
|
+
|
|
+ return result;
|
|
+}
|
|
diff --git a/drivers/st/io/io_stm32image.c b/drivers/st/io/io_stm32image.c
|
|
new file mode 100644
|
|
index 0000000..fde6269
|
|
--- /dev/null
|
|
+++ b/drivers/st/io/io_stm32image.c
|
|
@@ -0,0 +1,381 @@
|
|
+/*
|
|
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
|
|
+ *
|
|
+ * SPDX-License-Identifier: BSD-3-Clause
|
|
+ */
|
|
+
|
|
+#include <assert.h>
|
|
+#include <boot_api.h>
|
|
+#include <debug.h>
|
|
+#include <errno.h>
|
|
+#include <io_driver.h>
|
|
+#include <io_stm32image.h>
|
|
+#include <io_storage.h>
|
|
+#include <platform.h>
|
|
+#include <platform_def.h>
|
|
+#include <stm32mp_auth.h>
|
|
+#include <stdint.h>
|
|
+#include <string.h>
|
|
+#include <utils.h>
|
|
+
|
|
+static uintptr_t backend_dev_handle;
|
|
+static uintptr_t backend_image_spec;
|
|
+static uint32_t *stm32_img;
|
|
+static uint8_t first_lba_buffer[MAX_LBA_SIZE] __aligned(4);
|
|
+static struct stm32image_part_info *current_part;
|
|
+
|
|
+/* STM32 Image driver functions */
|
|
+static int stm32image_dev_open(const uintptr_t init_params,
|
|
+ io_dev_info_t **dev_info);
|
|
+static int stm32image_partition_open(io_dev_info_t *dev_info,
|
|
+ const uintptr_t spec, io_entity_t *entity);
|
|
+static int stm32image_partition_size(io_entity_t *entity, size_t *length);
|
|
+static int stm32image_partition_read(io_entity_t *entity, uintptr_t buffer,
|
|
+ size_t length, size_t *length_read);
|
|
+static int stm32image_partition_close(io_entity_t *entity);
|
|
+static int stm32image_dev_init(io_dev_info_t *dev_info,
|
|
+ const uintptr_t init_params);
|
|
+static int stm32image_dev_close(io_dev_info_t *dev_info);
|
|
+
|
|
+/* Identify the device type as a virtual driver */
|
|
+static io_type_t device_type_stm32image(void)
|
|
+{
|
|
+ return IO_TYPE_STM32IMAGE;
|
|
+}
|
|
+
|
|
+static const io_dev_connector_t stm32image_dev_connector = {
|
|
+ .dev_open = stm32image_dev_open
|
|
+};
|
|
+
|
|
+static const io_dev_funcs_t stm32image_dev_funcs = {
|
|
+ .type = device_type_stm32image,
|
|
+ .open = stm32image_partition_open,
|
|
+ .size = stm32image_partition_size,
|
|
+ .read = stm32image_partition_read,
|
|
+ .close = stm32image_partition_close,
|
|
+ .dev_init = stm32image_dev_init,
|
|
+ .dev_close = stm32image_dev_close,
|
|
+};
|
|
+
|
|
+static io_dev_info_t stm32image_dev_info = {
|
|
+ .funcs = &stm32image_dev_funcs,
|
|
+ .info = (uintptr_t)0,
|
|
+};
|
|
+
|
|
+static struct stm32image_device_info stm32image_dev;
|
|
+
|
|
+static int get_part_idx_by_binary_type(uint32_t binary_type)
|
|
+{
|
|
+ int i;
|
|
+
|
|
+ for (i = 0; i < STM32_PART_NUM; i++) {
|
|
+ if (stm32image_dev.part_info[i].binary_type == binary_type) {
|
|
+ return i;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return -EINVAL;
|
|
+}
|
|
+
|
|
+/* Open a connection to the STM32IMAGE device */
|
|
+static int stm32image_dev_open(const uintptr_t init_params,
|
|
+ io_dev_info_t **dev_info)
|
|
+{
|
|
+ int i;
|
|
+ struct stm32image_device_info *device_info =
|
|
+ (struct stm32image_device_info *)init_params;
|
|
+
|
|
+ assert(dev_info != NULL);
|
|
+ *dev_info = (io_dev_info_t *)&stm32image_dev_info;
|
|
+
|
|
+ stm32image_dev.device_size = device_info->device_size;
|
|
+ stm32image_dev.lba_size = device_info->lba_size;
|
|
+
|
|
+ for (i = 0; i < STM32_PART_NUM; i++) {
|
|
+ memcpy(stm32image_dev.part_info[i].name,
|
|
+ device_info->part_info[i].name, MAX_PART_NAME_SIZE);
|
|
+ stm32image_dev.part_info[i].binary_type =
|
|
+ device_info->part_info[i].binary_type;
|
|
+ stm32image_dev.part_info[i].part_offset =
|
|
+ device_info->part_info[i].part_offset;
|
|
+ stm32image_dev.part_info[i].bkp_offset =
|
|
+ device_info->part_info[i].bkp_offset;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/* Do some basic package checks */
|
|
+static int stm32image_dev_init(io_dev_info_t *dev_info,
|
|
+ const uintptr_t init_params)
|
|
+{
|
|
+ int result;
|
|
+
|
|
+ if ((backend_dev_handle != 0U) || (backend_image_spec != 0U)) {
|
|
+ ERROR("STM32 Image io supports only one session\n");
|
|
+ return -ENOMEM;
|
|
+ }
|
|
+
|
|
+ /* Obtain a reference to the image by querying the platform layer */
|
|
+ result = plat_get_image_source(STM32_IMAGE_ID, &backend_dev_handle,
|
|
+ &backend_image_spec);
|
|
+ if (result != 0) {
|
|
+ ERROR("STM32 image error (%i)\n", result);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ return result;
|
|
+}
|
|
+
|
|
+/* Close a connection to the STM32 Image device */
|
|
+static int stm32image_dev_close(io_dev_info_t *dev_info)
|
|
+{
|
|
+ backend_dev_handle = 0U;
|
|
+ backend_image_spec = 0U;
|
|
+ stm32_img = NULL;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/* Open a partition */
|
|
+static int stm32image_partition_open(io_dev_info_t *dev_info,
|
|
+ const uintptr_t spec, io_entity_t *entity)
|
|
+{
|
|
+ const struct stm32image_part_info *partition_spec;
|
|
+ int idx;
|
|
+
|
|
+ assert(entity != NULL);
|
|
+
|
|
+ partition_spec = (struct stm32image_part_info *)spec;
|
|
+ assert(partition_spec != NULL);
|
|
+
|
|
+ idx = get_part_idx_by_binary_type(partition_spec->binary_type);
|
|
+ if ((idx < 0) || (idx > STM32_PART_NUM)) {
|
|
+ ERROR("Wrong partition index (%d)\n", idx);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ current_part = &stm32image_dev.part_info[idx];
|
|
+ stm32_img = (uint32_t *)¤t_part->part_offset;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/* Return the size of a partition */
|
|
+static int stm32image_partition_size(io_entity_t *entity, size_t *length)
|
|
+{
|
|
+ int result;
|
|
+ uintptr_t backend_handle;
|
|
+ size_t bytes_read;
|
|
+ boot_api_image_header_t *header =
|
|
+ (boot_api_image_header_t *)first_lba_buffer;
|
|
+
|
|
+ assert(entity != NULL);
|
|
+ assert(length != NULL);
|
|
+
|
|
+ /* Attempt to access the image */
|
|
+ result = io_open(backend_dev_handle, backend_image_spec,
|
|
+ &backend_handle);
|
|
+
|
|
+ if (result < 0) {
|
|
+ ERROR("%s: io_open (%i)\n", __func__, result);
|
|
+ return result;
|
|
+ }
|
|
+
|
|
+ /* Reset magic header value */
|
|
+ header->magic = 0;
|
|
+
|
|
+ while (header->magic == 0U) {
|
|
+ result = io_seek(backend_handle, IO_SEEK_SET, *stm32_img);
|
|
+ if (result != 0) {
|
|
+ ERROR("%s: io_seek (%i)\n", __func__, result);
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ result = io_read(backend_handle, (uintptr_t)header,
|
|
+ MAX_LBA_SIZE, (size_t *)&bytes_read);
|
|
+ if (result != 0) {
|
|
+ if (current_part->bkp_offset == 0U) {
|
|
+ ERROR("%s: io_read (%i)\n", __func__, result);
|
|
+ }
|
|
+ header->magic = 0;
|
|
+ }
|
|
+
|
|
+ if ((header->magic != BOOT_API_IMAGE_HEADER_MAGIC_NB) ||
|
|
+ (header->binary_type != current_part->binary_type) ||
|
|
+ (header->image_length >= stm32image_dev.device_size)) {
|
|
+ VERBOSE("%s: partition %s not found at %x\n",
|
|
+ __func__, current_part->name, *stm32_img);
|
|
+
|
|
+ if (current_part->bkp_offset == 0U) {
|
|
+ result = -ENOMEM;
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ /* Header not correct, check next offset for backup */
|
|
+ *stm32_img += current_part->bkp_offset;
|
|
+ if (*stm32_img > stm32image_dev.device_size) {
|
|
+ /* No backup found, end of device reached */
|
|
+ WARN("%s : partition %s not found\n",
|
|
+ __func__, current_part->name);
|
|
+ result = -ENOMEM;
|
|
+ break;
|
|
+ }
|
|
+ header->magic = 0;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ io_close(backend_handle);
|
|
+
|
|
+ if (result != 0) {
|
|
+ return result;
|
|
+ }
|
|
+
|
|
+ if (header->image_length < stm32image_dev.lba_size) {
|
|
+ *length = stm32image_dev.lba_size;
|
|
+ } else {
|
|
+ *length = header->image_length;
|
|
+ }
|
|
+
|
|
+ INFO("STM32 Image size : %lu\n", (unsigned long)*length);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/* Read data from a partition */
|
|
+static int stm32image_partition_read(io_entity_t *entity, uintptr_t buffer,
|
|
+ size_t length, size_t *length_read)
|
|
+{
|
|
+ int result = 0;
|
|
+ uint8_t *local_buffer = (uint8_t *)buffer;
|
|
+ boot_api_image_header_t *header =
|
|
+ (boot_api_image_header_t *)first_lba_buffer;
|
|
+
|
|
+ assert(entity != NULL);
|
|
+ assert(buffer != 0U);
|
|
+ assert(length_read != NULL);
|
|
+
|
|
+ *length_read = 0U;
|
|
+
|
|
+ while (*length_read == 0U) {
|
|
+ int offset;
|
|
+ int local_length;
|
|
+ uintptr_t backend_handle;
|
|
+
|
|
+ if (header->magic != BOOT_API_IMAGE_HEADER_MAGIC_NB) {
|
|
+ /* Check for backup as image is corrupted */
|
|
+ if (current_part->bkp_offset == 0U) {
|
|
+ result = -ENOMEM;
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ *stm32_img += current_part->bkp_offset;
|
|
+ if (*stm32_img >= stm32image_dev.device_size) {
|
|
+ /* End of device reached */
|
|
+ result = -ENOMEM;
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ local_buffer = (uint8_t *)buffer;
|
|
+
|
|
+ result = stm32image_partition_size(entity, &length);
|
|
+ if (result != 0) {
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /* Part of image already loaded with the header */
|
|
+ memcpy(local_buffer, (uint8_t *)first_lba_buffer +
|
|
+ sizeof(boot_api_image_header_t),
|
|
+ MAX_LBA_SIZE - sizeof(boot_api_image_header_t));
|
|
+ local_buffer += MAX_LBA_SIZE - sizeof(boot_api_image_header_t);
|
|
+ offset = MAX_LBA_SIZE;
|
|
+
|
|
+ /* New image length to be read */
|
|
+ local_length = round_up(length -
|
|
+ ((MAX_LBA_SIZE) -
|
|
+ sizeof(boot_api_image_header_t)),
|
|
+ stm32image_dev.lba_size);
|
|
+
|
|
+ if ((header->load_address != 0U) &&
|
|
+ (header->load_address != buffer)) {
|
|
+ ERROR("Wrong load address\n");
|
|
+ panic();
|
|
+ }
|
|
+
|
|
+ result = io_open(backend_dev_handle, backend_image_spec,
|
|
+ &backend_handle);
|
|
+
|
|
+ if (result != 0) {
|
|
+ ERROR("%s: io_open (%i)\n", __func__, result);
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ result = io_seek(backend_handle, IO_SEEK_SET,
|
|
+ *stm32_img + offset);
|
|
+
|
|
+ if (result != 0) {
|
|
+ ERROR("%s: io_seek (%i)\n", __func__, result);
|
|
+ *length_read = 0;
|
|
+ io_close(backend_handle);
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ result = io_read(backend_handle, (uintptr_t)local_buffer,
|
|
+ local_length, length_read);
|
|
+
|
|
+ /* Adding part of size already read from header */
|
|
+ *length_read += MAX_LBA_SIZE - sizeof(boot_api_image_header_t);
|
|
+
|
|
+ if (result != 0) {
|
|
+ ERROR("%s: io_read (%i)\n", __func__, result);
|
|
+ *length_read = 0;
|
|
+ header->magic = 0;
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ result = check_header(header, buffer);
|
|
+ if (result != 0) {
|
|
+ ERROR("Header check failed\n");
|
|
+ *length_read = 0;
|
|
+ header->magic = 0;
|
|
+ }
|
|
+
|
|
+#ifdef AUTHENTICATE_BL33
|
|
+ result = check_authentication(header, buffer);
|
|
+ if (result != 0) {
|
|
+ ERROR("Authentication Failed\n");
|
|
+ return result;
|
|
+ }
|
|
+#else
|
|
+ NOTICE("Authentication disabled: No signature check\n");
|
|
+#endif
|
|
+
|
|
+ io_close(backend_handle);
|
|
+ }
|
|
+
|
|
+ return result;
|
|
+}
|
|
+
|
|
+/* Close a partition */
|
|
+static int stm32image_partition_close(io_entity_t *entity)
|
|
+{
|
|
+ current_part = NULL;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/* Register the stm32image driver with the IO abstraction */
|
|
+int register_io_dev_stm32image(const io_dev_connector_t **dev_con)
|
|
+{
|
|
+ int result;
|
|
+
|
|
+ assert(dev_con != NULL);
|
|
+
|
|
+ result = io_register_device(&stm32image_dev_info);
|
|
+ if (result == 0) {
|
|
+ *dev_con = &stm32image_dev_connector;
|
|
+ }
|
|
+
|
|
+ return result;
|
|
+}
|
|
diff --git a/drivers/st/iwdg/stm32_iwdg.c b/drivers/st/iwdg/stm32_iwdg.c
|
|
new file mode 100644
|
|
index 0000000..6d91a9f
|
|
--- /dev/null
|
|
+++ b/drivers/st/iwdg/stm32_iwdg.c
|
|
@@ -0,0 +1,289 @@
|
|
+/*
|
|
+ * Copyright (c) 2017-2018, STMicroelectronics - All Rights Reserved
|
|
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
|
|
+ *
|
|
+ * SPDX-License-Identifier: BSD-3-Clause
|
|
+ */
|
|
+
|
|
+#include <assert.h>
|
|
+#include <arch_helpers.h>
|
|
+#include <debug.h>
|
|
+#include <delay_timer.h>
|
|
+#include <errno.h>
|
|
+#include <gicv2.h>
|
|
+#include <libfdt.h>
|
|
+#include <mmio.h>
|
|
+#include <platform.h>
|
|
+#include <platform_def.h>
|
|
+#include <stm32_iwdg.h>
|
|
+#include <stm32mp_clkfunc.h>
|
|
+#include <stm32mp_common.h>
|
|
+#include <stm32mp_dt.h>
|
|
+#include <string.h>
|
|
+#include <utils.h>
|
|
+
|
|
+/* IWDG Compatibility */
|
|
+#define IWDG_COMPAT "st,stm32mp1-iwdg"
|
|
+#define IWDG_TIMEOUT_MS U(100)
|
|
+
|
|
+/* IWDG registers offsets */
|
|
+#define IWDG_KR_OFFSET 0x00U
|
|
+#define IWDG_PR_OFFSET 0x04U
|
|
+#define IWDG_RLR_OFFSET 0x08U
|
|
+#define IWDG_SR_OFFSET 0x0CU
|
|
+#define IWDG_EWCR_OFFSET 0x14U
|
|
+
|
|
+/* Registers values */
|
|
+#define IWDG_KR_ACCESS_KEY 0x5555
|
|
+#define IWDG_KR_RELOAD_KEY 0xAAAA
|
|
+#define IWDG_KR_START_KEY 0xCCCC
|
|
+
|
|
+#define IWDG_PR_DIV_4 0x00
|
|
+#define IWDG_PR_DIV_256 0x06
|
|
+
|
|
+#define IWDG_RLR_MAX_VAL 0xFFF
|
|
+
|
|
+#define IWDG_SR_EWU BIT(3)
|
|
+
|
|
+#define IWDG_EWCR_EWIE BIT(15)
|
|
+#define IWDG_EWCR_EWIC BIT(14)
|
|
+#define IWDG_EWCR_EWIT_MASK GENMASK(11, 0)
|
|
+
|
|
+struct stm32_iwdg_instance {
|
|
+ uintptr_t base;
|
|
+ unsigned long clock;
|
|
+ uint8_t flags;
|
|
+ int num_irq;
|
|
+};
|
|
+
|
|
+static struct stm32_iwdg_instance stm32_iwdg[IWDG_MAX_INSTANCE];
|
|
+
|
|
+static int stm32_iwdg_get_dt_node(struct dt_node_info *info, int offset)
|
|
+{
|
|
+ int node;
|
|
+
|
|
+ node = dt_get_node(info, offset, IWDG_COMPAT);
|
|
+ if (node < 0) {
|
|
+ if (offset == -1) {
|
|
+ VERBOSE("%s: No IDWG found\n", __func__);
|
|
+ }
|
|
+ return -FDT_ERR_NOTFOUND;
|
|
+ }
|
|
+
|
|
+ return node;
|
|
+}
|
|
+
|
|
+#if defined(IMAGE_BL32)
|
|
+void __dead2 stm32_iwdg_it_handler(int id)
|
|
+{
|
|
+ unsigned int cpu = plat_my_core_pos();
|
|
+ struct stm32_iwdg_instance *iwdg;
|
|
+ unsigned int instance;
|
|
+
|
|
+ for (instance = 0; instance < IWDG_MAX_INSTANCE; instance++) {
|
|
+ if (stm32_iwdg[instance].num_irq == id) {
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (instance == IWDG_MAX_INSTANCE) {
|
|
+ panic();
|
|
+ }
|
|
+
|
|
+ iwdg = &stm32_iwdg[instance];
|
|
+
|
|
+ VERBOSE("CPU %x IT Watchdog %d\n", cpu, instance + 1);
|
|
+
|
|
+ stm32_iwdg_refresh(instance);
|
|
+
|
|
+ stm32mp_clk_enable(iwdg->clock);
|
|
+
|
|
+ mmio_setbits_32(iwdg->base + IWDG_EWCR_OFFSET, IWDG_EWCR_EWIC);
|
|
+
|
|
+ stm32mp_clk_disable(iwdg->clock);
|
|
+
|
|
+ /* Ack interrupt as we do not return from next call */
|
|
+ gicv2_end_of_interrupt(id);
|
|
+
|
|
+ stm32mp_plat_reset(cpu);
|
|
+}
|
|
+
|
|
+static int stm32_iwdg_get_secure_timeout(int node)
|
|
+{
|
|
+ void *fdt;
|
|
+ const fdt32_t *cuint;
|
|
+
|
|
+ if (fdt_get_address(&fdt) == 0) {
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ cuint = fdt_getprop(fdt, node, "secure-timeout-sec", NULL);
|
|
+ if (cuint == NULL) {
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ return (int)fdt32_to_cpu(*cuint);
|
|
+}
|
|
+
|
|
+static int stm32_iwdg_conf_etimeout(int node, struct stm32_iwdg_instance *iwdg)
|
|
+{
|
|
+ int id_lsi;
|
|
+ int dt_secure_timeout = stm32_iwdg_get_secure_timeout(node);
|
|
+ uint32_t reload, status;
|
|
+ unsigned int timeout = IWDG_TIMEOUT_MS;
|
|
+ unsigned long long reload_ll;
|
|
+
|
|
+ if (dt_secure_timeout < 0) {
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ if (dt_secure_timeout == 0) {
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ id_lsi = fdt_get_clock_id_by_name(node, "lsi");
|
|
+ if (id_lsi < 0) {
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ /* Prescaler fix to 256 */
|
|
+ reload_ll = (unsigned long long)dt_secure_timeout *
|
|
+ stm32mp_clk_get_rate(id_lsi);
|
|
+ reload = ((uint32_t)(reload_ll >> 8) - 1U) & IWDG_EWCR_EWIT_MASK;
|
|
+
|
|
+ stm32mp_clk_enable(iwdg->clock);
|
|
+
|
|
+ mmio_write_32(iwdg->base + IWDG_KR_OFFSET, IWDG_KR_START_KEY);
|
|
+ mmio_write_32(iwdg->base + IWDG_KR_OFFSET, IWDG_KR_ACCESS_KEY);
|
|
+ mmio_write_32(iwdg->base + IWDG_PR_OFFSET, IWDG_PR_DIV_256);
|
|
+ mmio_write_32(iwdg->base + IWDG_EWCR_OFFSET, IWDG_EWCR_EWIE | reload);
|
|
+
|
|
+ do {
|
|
+ status = mmio_read_32(iwdg->base + IWDG_SR_OFFSET) &
|
|
+ IWDG_SR_EWU;
|
|
+ timeout--;
|
|
+ mdelay(1);
|
|
+ } while ((status != 0U) && (timeout != 0U));
|
|
+
|
|
+ iwdg->num_irq = stm32_gic_enable_spi(node, NULL);
|
|
+ if (iwdg->num_irq < 0) {
|
|
+ panic();
|
|
+ }
|
|
+
|
|
+ stm32mp_clk_disable(iwdg->clock);
|
|
+
|
|
+ return (timeout == 0U) ? -ETIMEDOUT : 0;
|
|
+}
|
|
+#endif
|
|
+
|
|
+void stm32_iwdg_refresh(uint32_t instance)
|
|
+{
|
|
+ struct stm32_iwdg_instance *iwdg = &stm32_iwdg[instance];
|
|
+
|
|
+ assert(iwdg);
|
|
+
|
|
+ stm32mp_clk_enable(iwdg->clock);
|
|
+
|
|
+ mmio_write_32(iwdg->base + IWDG_KR_OFFSET, IWDG_KR_RELOAD_KEY);
|
|
+
|
|
+ stm32mp_clk_disable(iwdg->clock);
|
|
+}
|
|
+
|
|
+int stm32_iwdg_init(void)
|
|
+{
|
|
+ int node = -1;
|
|
+ int __unused res;
|
|
+ struct dt_node_info dt_info;
|
|
+ void *fdt;
|
|
+ uint32_t __unused count = 0;
|
|
+ uint32_t idx;
|
|
+ uint32_t __unused otp_value;
|
|
+
|
|
+ if (fdt_get_address(&fdt) == 0) {
|
|
+ panic();
|
|
+ }
|
|
+
|
|
+ for (node = stm32_iwdg_get_dt_node(&dt_info, node);
|
|
+ node != -FDT_ERR_NOTFOUND;
|
|
+ node = stm32_iwdg_get_dt_node(&dt_info, node)) {
|
|
+ struct stm32_iwdg_instance *iwdg;
|
|
+ uint32_t hw_init;
|
|
+
|
|
+ idx = stm32_iwdg_get_instance(dt_info.base);
|
|
+ iwdg = &stm32_iwdg[idx];
|
|
+ iwdg->base = dt_info.base;
|
|
+ iwdg->clock = (unsigned long)dt_info.clock;
|
|
+
|
|
+ /* DT can specify low power cases */
|
|
+ if (fdt_getprop(fdt, node, "stm32,enable-on-stop", NULL) !=
|
|
+ NULL) {
|
|
+ iwdg->flags |= IWDG_ENABLE_ON_STOP;
|
|
+ }
|
|
+
|
|
+ if (fdt_getprop(fdt, node, "stm32,enable-on-standby", NULL) !=
|
|
+ NULL) {
|
|
+ iwdg->flags |= IWDG_ENABLE_ON_STANDBY;
|
|
+ }
|
|
+
|
|
+ /* Explicit list of supported bit flags */
|
|
+ hw_init = stm32_iwdg_get_otp_config(iwdg->base);
|
|
+
|
|
+ if ((hw_init & IWDG_HW_ENABLED) != 0) {
|
|
+ if (dt_info.status == DT_DISABLED) {
|
|
+ ERROR("OTP enabled but iwdg%d DT-disabled\n",
|
|
+ idx + 1);
|
|
+ panic();
|
|
+ }
|
|
+ iwdg->flags |= IWDG_HW_ENABLED;
|
|
+ }
|
|
+
|
|
+ if (dt_info.status == DT_DISABLED) {
|
|
+ zeromem((void *)iwdg,
|
|
+ sizeof(struct stm32_iwdg_instance));
|
|
+ goto next;
|
|
+ }
|
|
+
|
|
+ if ((hw_init & IWDG_ENABLE_ON_STOP) != 0) {
|
|
+ iwdg->flags |= IWDG_ENABLE_ON_STOP;
|
|
+ }
|
|
+
|
|
+ if ((hw_init & IWDG_ENABLE_ON_STANDBY) != 0) {
|
|
+ iwdg->flags |= IWDG_ENABLE_ON_STANDBY;
|
|
+ }
|
|
+
|
|
+ VERBOSE("IWDG%u found, %ssecure\n", idx + 1,
|
|
+ ((dt_info.status & DT_NON_SECURE) != 0) ?
|
|
+ "non " : "");
|
|
+
|
|
+ if ((dt_info.status & DT_NON_SECURE) != 0) {
|
|
+ stm32mp_register_non_secure_periph_iomem(iwdg->base);
|
|
+ } else {
|
|
+ stm32mp_register_secure_periph_iomem(iwdg->base);
|
|
+ }
|
|
+
|
|
+ stm32mp_clk_enable(iwdg->clock);
|
|
+ stm32mp_clk_disable(iwdg->clock);
|
|
+
|
|
+#if defined(IMAGE_BL32)
|
|
+ res = stm32_iwdg_conf_etimeout(node, iwdg);
|
|
+ if (res != 0) {
|
|
+ ERROR("IWDG%x early timeout config failed (%d)\n",
|
|
+ idx + 1, res);
|
|
+ return res;
|
|
+ }
|
|
+#endif
|
|
+#if defined(IMAGE_BL2)
|
|
+ if (stm32_iwdg_shadow_update(iwdg->base, iwdg->flags) !=
|
|
+ BSEC_OK) {
|
|
+ return -1;
|
|
+ }
|
|
+#endif
|
|
+
|
|
+next:
|
|
+ count++;
|
|
+ }
|
|
+
|
|
+ VERBOSE("%u IWDG instance%s found\n", count, count > 1 ? "s" : "");
|
|
+
|
|
+ return 0;
|
|
+}
|
|
diff --git a/drivers/st/mmc/stm32_sdmmc2.c b/drivers/st/mmc/stm32_sdmmc2.c
|
|
new file mode 100644
|
|
index 0000000..620087e
|
|
--- /dev/null
|
|
+++ b/drivers/st/mmc/stm32_sdmmc2.c
|
|
@@ -0,0 +1,752 @@
|
|
+/*
|
|
+ * Copyright (c) 2018-2019, STMicroelectronics - All Rights Reserved
|
|
+ *
|
|
+ * SPDX-License-Identifier: BSD-3-Clause
|
|
+ */
|
|
+
|
|
+#include <arch.h>
|
|
+#include <arch_helpers.h>
|
|
+#include <assert.h>
|
|
+#include <debug.h>
|
|
+#include <delay_timer.h>
|
|
+#include <errno.h>
|
|
+#include <libfdt.h>
|
|
+#include <mmc.h>
|
|
+#include <mmio.h>
|
|
+#include <platform.h>
|
|
+#include <platform_def.h>
|
|
+#include <stm32_gpio.h>
|
|
+#include <stm32_sdmmc2.h>
|
|
+#include <stm32mp_common.h>
|
|
+#include <stm32mp_dt.h>
|
|
+#include <stm32mp_reset.h>
|
|
+#include <string.h>
|
|
+#include <utils.h>
|
|
+
|
|
+/* Registers offsets */
|
|
+#define SDMMC_POWER 0x00U
|
|
+#define SDMMC_CLKCR 0x04U
|
|
+#define SDMMC_ARGR 0x08U
|
|
+#define SDMMC_CMDR 0x0CU
|
|
+#define SDMMC_RESPCMDR 0x10U
|
|
+#define SDMMC_RESP1R 0x14U
|
|
+#define SDMMC_RESP2R 0x18U
|
|
+#define SDMMC_RESP3R 0x1CU
|
|
+#define SDMMC_RESP4R 0x20U
|
|
+#define SDMMC_DTIMER 0x24U
|
|
+#define SDMMC_DLENR 0x28U
|
|
+#define SDMMC_DCTRLR 0x2CU
|
|
+#define SDMMC_DCNTR 0x30U
|
|
+#define SDMMC_STAR 0x34U
|
|
+#define SDMMC_ICR 0x38U
|
|
+#define SDMMC_MASKR 0x3CU
|
|
+#define SDMMC_ACKTIMER 0x40U
|
|
+#define SDMMC_IDMACTRLR 0x50U
|
|
+#define SDMMC_IDMABSIZER 0x54U
|
|
+#define SDMMC_IDMABASE0R 0x58U
|
|
+#define SDMMC_IDMABASE1R 0x5CU
|
|
+#define SDMMC_FIFOR 0x80U
|
|
+
|
|
+/* SDMMC power control register */
|
|
+#define SDMMC_POWER_PWRCTRL GENMASK(1, 0)
|
|
+#define SDMMC_POWER_DIRPOL BIT(4)
|
|
+
|
|
+/* SDMMC clock control register */
|
|
+#define SDMMC_CLKCR_WIDBUS_4 BIT(14)
|
|
+#define SDMMC_CLKCR_WIDBUS_8 BIT(15)
|
|
+#define SDMMC_CLKCR_NEGEDGE BIT(16)
|
|
+#define SDMMC_CLKCR_HWFC_EN BIT(17)
|
|
+#define SDMMC_CLKCR_SELCLKRX_0 BIT(20)
|
|
+
|
|
+/* SDMMC command register */
|
|
+#define SDMMC_CMDR_CMDTRANS BIT(6)
|
|
+#define SDMMC_CMDR_CMDSTOP BIT(7)
|
|
+#define SDMMC_CMDR_WAITRESP GENMASK(9, 8)
|
|
+#define SDMMC_CMDR_WAITRESP_SHORT BIT(8)
|
|
+#define SDMMC_CMDR_WAITRESP_SHORT_NOCRC BIT(9)
|
|
+#define SDMMC_CMDR_CPSMEN BIT(12)
|
|
+
|
|
+/* SDMMC data control register */
|
|
+#define SDMMC_DCTRLR_DTEN BIT(0)
|
|
+#define SDMMC_DCTRLR_DTDIR BIT(1)
|
|
+#define SDMMC_DCTRLR_DTMODE GENMASK(3, 2)
|
|
+#define SDMMC_DCTRLR_DBLOCKSIZE_0 BIT(4)
|
|
+#define SDMMC_DCTRLR_DBLOCKSIZE_1 BIT(5)
|
|
+#define SDMMC_DCTRLR_DBLOCKSIZE_3 BIT(7)
|
|
+#define SDMMC_DCTRLR_DBLOCKSIZE GENMASK(7, 4)
|
|
+#define SDMMC_DCTRLR_FIFORST BIT(13)
|
|
+
|
|
+#define SDMMC_DCTRLR_CLEAR_MASK (SDMMC_DCTRLR_DTEN | \
|
|
+ SDMMC_DCTRLR_DTDIR | \
|
|
+ SDMMC_DCTRLR_DTMODE | \
|
|
+ SDMMC_DCTRLR_DBLOCKSIZE)
|
|
+#define SDMMC_DBLOCKSIZE_8 (SDMMC_DCTRLR_DBLOCKSIZE_0 | \
|
|
+ SDMMC_DCTRLR_DBLOCKSIZE_1)
|
|
+#define SDMMC_DBLOCKSIZE_512 (SDMMC_DCTRLR_DBLOCKSIZE_0 | \
|
|
+ SDMMC_DCTRLR_DBLOCKSIZE_3)
|
|
+
|
|
+/* SDMMC status register */
|
|
+#define SDMMC_STAR_CCRCFAIL BIT(0)
|
|
+#define SDMMC_STAR_DCRCFAIL BIT(1)
|
|
+#define SDMMC_STAR_CTIMEOUT BIT(2)
|
|
+#define SDMMC_STAR_DTIMEOUT BIT(3)
|
|
+#define SDMMC_STAR_TXUNDERR BIT(4)
|
|
+#define SDMMC_STAR_RXOVERR BIT(5)
|
|
+#define SDMMC_STAR_CMDREND BIT(6)
|
|
+#define SDMMC_STAR_CMDSENT BIT(7)
|
|
+#define SDMMC_STAR_DATAEND BIT(8)
|
|
+#define SDMMC_STAR_DBCKEND BIT(10)
|
|
+#define SDMMC_STAR_DPSMACT BIT(12)
|
|
+#define SDMMC_STAR_RXFIFOHF BIT(15)
|
|
+#define SDMMC_STAR_RXFIFOE BIT(19)
|
|
+#define SDMMC_STAR_IDMATE BIT(27)
|
|
+#define SDMMC_STAR_IDMABTC BIT(28)
|
|
+
|
|
+/* SDMMC DMA control register */
|
|
+#define SDMMC_IDMACTRLR_IDMAEN BIT(0)
|
|
+
|
|
+#define SDMMC_STATIC_FLAGS (SDMMC_STAR_CCRCFAIL | \
|
|
+ SDMMC_STAR_DCRCFAIL | \
|
|
+ SDMMC_STAR_CTIMEOUT | \
|
|
+ SDMMC_STAR_DTIMEOUT | \
|
|
+ SDMMC_STAR_TXUNDERR | \
|
|
+ SDMMC_STAR_RXOVERR | \
|
|
+ SDMMC_STAR_CMDREND | \
|
|
+ SDMMC_STAR_CMDSENT | \
|
|
+ SDMMC_STAR_DATAEND | \
|
|
+ SDMMC_STAR_DBCKEND | \
|
|
+ SDMMC_STAR_IDMATE | \
|
|
+ SDMMC_STAR_IDMABTC)
|
|
+
|
|
+#define TIMEOUT_10_MS ms2tick(10)
|
|
+#define TIMEOUT_1_S s2tick(1)
|
|
+
|
|
+#define DT_SDMMC2_COMPAT "st,stm32-sdmmc2"
|
|
+
|
|
+static void stm32_sdmmc2_init(void);
|
|
+static int stm32_sdmmc2_send_cmd_req(struct mmc_cmd *cmd);
|
|
+static int stm32_sdmmc2_send_cmd(struct mmc_cmd *cmd);
|
|
+static int stm32_sdmmc2_set_ios(unsigned int clk, unsigned int width);
|
|
+static int stm32_sdmmc2_prepare(int lba, uintptr_t buf, size_t size);
|
|
+static int stm32_sdmmc2_read(int lba, uintptr_t buf, size_t size);
|
|
+static int stm32_sdmmc2_write(int lba, uintptr_t buf, size_t size);
|
|
+
|
|
+static const struct mmc_ops stm32_sdmmc2_ops = {
|
|
+ .init = stm32_sdmmc2_init,
|
|
+ .send_cmd = stm32_sdmmc2_send_cmd,
|
|
+ .set_ios = stm32_sdmmc2_set_ios,
|
|
+ .prepare = stm32_sdmmc2_prepare,
|
|
+ .read = stm32_sdmmc2_read,
|
|
+ .write = stm32_sdmmc2_write,
|
|
+};
|
|
+
|
|
+static struct stm32_sdmmc2_params sdmmc2_params;
|
|
+
|
|
+#pragma weak plat_sdmmc2_use_dma
|
|
+bool plat_sdmmc2_use_dma(unsigned int instance, unsigned int memory)
|
|
+{
|
|
+ return false;
|
|
+}
|
|
+
|
|
+static void dump_registers(void)
|
|
+{
|
|
+ uintptr_t base = sdmmc2_params.reg_base;
|
|
+
|
|
+ INFO("SDMMC_POWER = 0x%x\n", mmio_read_32(base + SDMMC_POWER));
|
|
+ INFO("SDMMC_CLKCR = 0x%x\n", mmio_read_32(base + SDMMC_CLKCR));
|
|
+ INFO("SDMMC_ARGR = 0x%x\n", mmio_read_32(base + SDMMC_ARGR));
|
|
+ INFO("SDMMC_CMDR = 0x%x\n", mmio_read_32(base + SDMMC_CMDR));
|
|
+ INFO("SDMMC_RESPCMDR = 0x%x\n", mmio_read_32(base + SDMMC_RESPCMDR));
|
|
+ INFO("SDMMC_RESP1R = 0x%x\n", mmio_read_32(base + SDMMC_RESP1R));
|
|
+ INFO("SDMMC_RESP2R = 0x%x\n", mmio_read_32(base + SDMMC_RESP2R));
|
|
+ INFO("SDMMC_RESP3R = 0x%x\n", mmio_read_32(base + SDMMC_RESP3R));
|
|
+ INFO("SDMMC_RESP4R = 0x%x\n", mmio_read_32(base + SDMMC_RESP4R));
|
|
+ INFO("SDMMC_DTIMER = 0x%x\n", mmio_read_32(base + SDMMC_DTIMER));
|
|
+ INFO("SDMMC_DLENR = 0x%x\n", mmio_read_32(base + SDMMC_DLENR));
|
|
+ INFO("SDMMC_DCTRLR = 0x%x\n", mmio_read_32(base + SDMMC_DCTRLR));
|
|
+ INFO("SDMMC_DCNTR = 0x%x\n", mmio_read_32(base + SDMMC_DCNTR));
|
|
+ INFO("SDMMC_MASKR = 0x%x\n", mmio_read_32(base + SDMMC_MASKR));
|
|
+ INFO("SDMMC_ACKTIMER = 0x%x\n", mmio_read_32(base + SDMMC_ACKTIMER));
|
|
+}
|
|
+
|
|
+static void stm32_sdmmc2_init(void)
|
|
+{
|
|
+ uint32_t clock_div;
|
|
+ uintptr_t base = sdmmc2_params.reg_base;
|
|
+
|
|
+ clock_div = div_round_up(sdmmc2_params.clk_rate,
|
|
+ STM32MP_MMC_INIT_FREQ * 2);
|
|
+
|
|
+ mmio_write_32(base + SDMMC_CLKCR, SDMMC_CLKCR_HWFC_EN | clock_div |
|
|
+ sdmmc2_params.negedge |
|
|
+ sdmmc2_params.pin_ckin);
|
|
+
|
|
+ mmio_write_32(base + SDMMC_POWER,
|
|
+ SDMMC_POWER_PWRCTRL | sdmmc2_params.dirpol);
|
|
+
|
|
+ mdelay(1);
|
|
+}
|
|
+
|
|
+static int stm32_sdmmc2_stop_transfer(void)
|
|
+{
|
|
+ struct mmc_cmd cmd_stop;
|
|
+
|
|
+ zeromem(&cmd_stop, sizeof(struct mmc_cmd));
|
|
+
|
|
+ cmd_stop.cmd_idx = MMC_CMD(12);
|
|
+ cmd_stop.resp_type = MMC_RESPONSE_R1B;
|
|
+
|
|
+ return stm32_sdmmc2_send_cmd(&cmd_stop);
|
|
+}
|
|
+
|
|
+static int stm32_sdmmc2_send_cmd_req(struct mmc_cmd *cmd)
|
|
+{
|
|
+ uint64_t start;
|
|
+ uint32_t flags_cmd, status;
|
|
+ uint32_t flags_data = 0;
|
|
+ int err = 0;
|
|
+ uintptr_t base = sdmmc2_params.reg_base;
|
|
+ unsigned int cmd_reg, arg_reg;
|
|
+
|
|
+ if (cmd == NULL) {
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ flags_cmd = SDMMC_STAR_CTIMEOUT;
|
|
+ arg_reg = cmd->cmd_arg;
|
|
+
|
|
+ if ((mmio_read_32(base + SDMMC_CMDR) & SDMMC_CMDR_CPSMEN) != 0U) {
|
|
+ mmio_write_32(base + SDMMC_CMDR, 0);
|
|
+ }
|
|
+
|
|
+ cmd_reg = cmd->cmd_idx | SDMMC_CMDR_CPSMEN;
|
|
+
|
|
+ if (cmd->resp_type == 0U) {
|
|
+ flags_cmd |= SDMMC_STAR_CMDSENT;
|
|
+ }
|
|
+
|
|
+ if ((cmd->resp_type & MMC_RSP_48) != 0U) {
|
|
+ if ((cmd->resp_type & MMC_RSP_136) != 0U) {
|
|
+ flags_cmd |= SDMMC_STAR_CMDREND;
|
|
+ cmd_reg |= SDMMC_CMDR_WAITRESP;
|
|
+ } else if ((cmd->resp_type & MMC_RSP_CRC) != 0U) {
|
|
+ flags_cmd |= SDMMC_STAR_CMDREND | SDMMC_STAR_CCRCFAIL;
|
|
+ cmd_reg |= SDMMC_CMDR_WAITRESP_SHORT;
|
|
+ } else {
|
|
+ flags_cmd |= SDMMC_STAR_CMDREND;
|
|
+ cmd_reg |= SDMMC_CMDR_WAITRESP_SHORT_NOCRC;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ switch (cmd->cmd_idx) {
|
|
+ case MMC_CMD(1):
|
|
+ arg_reg |= OCR_POWERUP;
|
|
+ break;
|
|
+ case MMC_CMD(8):
|
|
+ if (sdmmc2_params.device_info->mmc_dev_type == MMC_IS_EMMC) {
|
|
+ cmd_reg |= SDMMC_CMDR_CMDTRANS;
|
|
+ }
|
|
+ break;
|
|
+ case MMC_CMD(12):
|
|
+ cmd_reg |= SDMMC_CMDR_CMDSTOP;
|
|
+ break;
|
|
+ case MMC_CMD(17):
|
|
+ case MMC_CMD(18):
|
|
+ cmd_reg |= SDMMC_CMDR_CMDTRANS;
|
|
+ if (sdmmc2_params.use_dma) {
|
|
+ flags_data |= SDMMC_STAR_DCRCFAIL |
|
|
+ SDMMC_STAR_DTIMEOUT |
|
|
+ SDMMC_STAR_DATAEND |
|
|
+ SDMMC_STAR_RXOVERR |
|
|
+ SDMMC_STAR_IDMATE;
|
|
+ }
|
|
+ break;
|
|
+ case MMC_ACMD(41):
|
|
+ arg_reg |= OCR_3_2_3_3 | OCR_3_3_3_4;
|
|
+ break;
|
|
+ case MMC_ACMD(51):
|
|
+ cmd_reg |= SDMMC_CMDR_CMDTRANS;
|
|
+ if (sdmmc2_params.use_dma) {
|
|
+ flags_data |= SDMMC_STAR_DCRCFAIL |
|
|
+ SDMMC_STAR_DTIMEOUT |
|
|
+ SDMMC_STAR_DATAEND |
|
|
+ SDMMC_STAR_RXOVERR |
|
|
+ SDMMC_STAR_IDMATE |
|
|
+ SDMMC_STAR_DBCKEND;
|
|
+ }
|
|
+ break;
|
|
+ default:
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ if ((cmd->resp_type & MMC_RSP_BUSY) != 0U) {
|
|
+ mmio_write_32(base + SDMMC_DTIMER, UINT32_MAX);
|
|
+ }
|
|
+
|
|
+ mmio_write_32(base + SDMMC_ARGR, arg_reg);
|
|
+
|
|
+ mmio_write_32(base + SDMMC_CMDR, cmd_reg);
|
|
+
|
|
+ status = mmio_read_32(base + SDMMC_STAR);
|
|
+
|
|
+ start = timeout_start();
|
|
+
|
|
+ while ((status & flags_cmd) == 0U) {
|
|
+ if (timeout_elapsed(start, TIMEOUT_10_MS)) {
|
|
+ err = -ETIMEDOUT;
|
|
+ ERROR("%s: timeout 10ms (cmd = %d,status = %x)\n",
|
|
+ __func__, cmd->cmd_idx, status);
|
|
+ goto err_exit;
|
|
+ }
|
|
+
|
|
+ status = mmio_read_32(base + SDMMC_STAR);
|
|
+ }
|
|
+
|
|
+ if ((status & (SDMMC_STAR_CTIMEOUT | SDMMC_STAR_CCRCFAIL)) != 0U) {
|
|
+ if ((status & SDMMC_STAR_CTIMEOUT) != 0U) {
|
|
+ err = -ETIMEDOUT;
|
|
+ /*
|
|
+ * Those timeouts can occur, and framework will handle
|
|
+ * the retries. CMD8 is expected to return this timeout
|
|
+ * for eMMC
|
|
+ */
|
|
+ if (!((cmd->cmd_idx == MMC_CMD(1)) ||
|
|
+ (cmd->cmd_idx == MMC_CMD(13)) ||
|
|
+ ((cmd->cmd_idx == MMC_CMD(8)) &&
|
|
+ (cmd->resp_type == MMC_RESPONSE_R7)))) {
|
|
+ ERROR("%s: CTIMEOUT (cmd = %d,status = %x)\n",
|
|
+ __func__, cmd->cmd_idx, status);
|
|
+ }
|
|
+ } else {
|
|
+ err = -EIO;
|
|
+ ERROR("%s: CRCFAIL (cmd = %d,status = %x)\n",
|
|
+ __func__, cmd->cmd_idx, status);
|
|
+ }
|
|
+
|
|
+ goto err_exit;
|
|
+ }
|
|
+
|
|
+ if ((cmd_reg & SDMMC_CMDR_WAITRESP) != 0U) {
|
|
+ if ((cmd->cmd_idx == MMC_CMD(9)) &&
|
|
+ ((cmd_reg & SDMMC_CMDR_WAITRESP) == SDMMC_CMDR_WAITRESP)) {
|
|
+ /* Need to invert response to match CSD structure */
|
|
+ cmd->resp_data[0] = mmio_read_32(base + SDMMC_RESP4R);
|
|
+ cmd->resp_data[1] = mmio_read_32(base + SDMMC_RESP3R);
|
|
+ cmd->resp_data[2] = mmio_read_32(base + SDMMC_RESP2R);
|
|
+ cmd->resp_data[3] = mmio_read_32(base + SDMMC_RESP1R);
|
|
+ } else {
|
|
+ cmd->resp_data[0] = mmio_read_32(base + SDMMC_RESP1R);
|
|
+ if ((cmd_reg & SDMMC_CMDR_WAITRESP) ==
|
|
+ SDMMC_CMDR_WAITRESP) {
|
|
+ cmd->resp_data[1] = mmio_read_32(base +
|
|
+ SDMMC_RESP2R);
|
|
+ cmd->resp_data[2] = mmio_read_32(base +
|
|
+ SDMMC_RESP3R);
|
|
+ cmd->resp_data[3] = mmio_read_32(base +
|
|
+ SDMMC_RESP4R);
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (flags_data == 0U) {
|
|
+ mmio_write_32(base + SDMMC_ICR, SDMMC_STATIC_FLAGS);
|
|
+
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ status = mmio_read_32(base + SDMMC_STAR);
|
|
+
|
|
+ start = timeout_start();
|
|
+
|
|
+ while ((status & flags_data) == 0U) {
|
|
+ if (timeout_elapsed(start, TIMEOUT_10_MS)) {
|
|
+ ERROR("%s: timeout 10ms (cmd = %d,status = %x)\n",
|
|
+ __func__, cmd->cmd_idx, status);
|
|
+ err = -ETIMEDOUT;
|
|
+ goto err_exit;
|
|
+ }
|
|
+
|
|
+ status = mmio_read_32(base + SDMMC_STAR);
|
|
+ };
|
|
+
|
|
+ if ((status & (SDMMC_STAR_DTIMEOUT | SDMMC_STAR_DCRCFAIL |
|
|
+ SDMMC_STAR_TXUNDERR | SDMMC_STAR_RXOVERR |
|
|
+ SDMMC_STAR_IDMATE)) != 0U) {
|
|
+ ERROR("%s: Error flag (cmd = %d,status = %x)\n", __func__,
|
|
+ cmd->cmd_idx, status);
|
|
+ err = -EIO;
|
|
+ }
|
|
+
|
|
+err_exit:
|
|
+ mmio_write_32(base + SDMMC_ICR, SDMMC_STATIC_FLAGS);
|
|
+ mmio_clrbits_32(base + SDMMC_CMDR, SDMMC_CMDR_CMDTRANS);
|
|
+
|
|
+ if ((err != 0) && ((status & SDMMC_STAR_DPSMACT) != 0U)) {
|
|
+ int ret_stop = stm32_sdmmc2_stop_transfer();
|
|
+
|
|
+ if (ret_stop != 0) {
|
|
+ return ret_stop;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return err;
|
|
+}
|
|
+
|
|
+static int stm32_sdmmc2_send_cmd(struct mmc_cmd *cmd)
|
|
+{
|
|
+ int8_t retry;
|
|
+ int err = 0;
|
|
+
|
|
+ assert(cmd != NULL);
|
|
+
|
|
+ for (retry = 0; retry <= 3; retry++) {
|
|
+ err = stm32_sdmmc2_send_cmd_req(cmd);
|
|
+ if (err == 0) {
|
|
+ return err;
|
|
+ }
|
|
+
|
|
+ if ((cmd->cmd_idx == MMC_CMD(1)) ||
|
|
+ (cmd->cmd_idx == MMC_CMD(13))) {
|
|
+ return 0; /* Retry managed by framework */
|
|
+ }
|
|
+
|
|
+ /* Command 8 is expected to fail for eMMC */
|
|
+ if (!(cmd->cmd_idx == MMC_CMD(8))) {
|
|
+ WARN(" CMD%d, Retry: %d, Error: %d\n",
|
|
+ cmd->cmd_idx, retry, err);
|
|
+ }
|
|
+
|
|
+ udelay(10);
|
|
+ }
|
|
+
|
|
+ return err;
|
|
+}
|
|
+
|
|
+static int stm32_sdmmc2_set_ios(unsigned int clk, unsigned int width)
|
|
+{
|
|
+ uintptr_t base = sdmmc2_params.reg_base;
|
|
+ uint32_t bus_cfg = 0;
|
|
+ uint32_t clock_div, max_freq;
|
|
+ uint32_t clk_rate = sdmmc2_params.clk_rate;
|
|
+ uint32_t max_bus_freq = sdmmc2_params.device_info->max_bus_freq;
|
|
+
|
|
+ switch (width) {
|
|
+ case MMC_BUS_WIDTH_1:
|
|
+ break;
|
|
+ case MMC_BUS_WIDTH_4:
|
|
+ bus_cfg |= SDMMC_CLKCR_WIDBUS_4;
|
|
+ break;
|
|
+ case MMC_BUS_WIDTH_8:
|
|
+ bus_cfg |= SDMMC_CLKCR_WIDBUS_8;
|
|
+ break;
|
|
+ default:
|
|
+ panic();
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ if (sdmmc2_params.device_info->mmc_dev_type == MMC_IS_EMMC) {
|
|
+ if (max_bus_freq >= 52000000U) {
|
|
+ max_freq = STM32MP_EMMC_HIGH_SPEED_MAX_FREQ;
|
|
+ } else {
|
|
+ max_freq = STM32MP_EMMC_NORMAL_SPEED_MAX_FREQ;
|
|
+ }
|
|
+ } else {
|
|
+ if (max_bus_freq >= 50000000U) {
|
|
+ max_freq = STM32MP_SD_HIGH_SPEED_MAX_FREQ;
|
|
+ } else {
|
|
+ max_freq = STM32MP_SD_NORMAL_SPEED_MAX_FREQ;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ clock_div = div_round_up(clk_rate, max_freq * 2);
|
|
+
|
|
+ mmio_write_32(base + SDMMC_CLKCR,
|
|
+ SDMMC_CLKCR_HWFC_EN | clock_div | bus_cfg |
|
|
+ sdmmc2_params.negedge |
|
|
+ sdmmc2_params.pin_ckin);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int stm32_sdmmc2_prepare(int lba, uintptr_t buf, size_t size)
|
|
+{
|
|
+ struct mmc_cmd cmd;
|
|
+ int ret;
|
|
+ uintptr_t base = sdmmc2_params.reg_base;
|
|
+ uint32_t data_ctrl = SDMMC_DCTRLR_DTDIR;
|
|
+
|
|
+ if (size == 8U) {
|
|
+ data_ctrl |= SDMMC_DBLOCKSIZE_8;
|
|
+ } else {
|
|
+ data_ctrl |= SDMMC_DBLOCKSIZE_512;
|
|
+ }
|
|
+
|
|
+ sdmmc2_params.use_dma = plat_sdmmc2_use_dma(base, buf);
|
|
+
|
|
+ if (sdmmc2_params.use_dma) {
|
|
+ inv_dcache_range(buf, size);
|
|
+ }
|
|
+
|
|
+ /* Prepare CMD 16*/
|
|
+ mmio_write_32(base + SDMMC_DTIMER, 0);
|
|
+
|
|
+ mmio_write_32(base + SDMMC_DLENR, 0);
|
|
+
|
|
+ mmio_write_32(base + SDMMC_DCTRLR, 0);
|
|
+
|
|
+ zeromem(&cmd, sizeof(struct mmc_cmd));
|
|
+
|
|
+ cmd.cmd_idx = MMC_CMD(16);
|
|
+ if (size > MMC_BLOCK_SIZE) {
|
|
+ cmd.cmd_arg = MMC_BLOCK_SIZE;
|
|
+ } else {
|
|
+ cmd.cmd_arg = size;
|
|
+ }
|
|
+
|
|
+ cmd.resp_type = MMC_RESPONSE_R1;
|
|
+
|
|
+ ret = stm32_sdmmc2_send_cmd(&cmd);
|
|
+ if (ret != 0) {
|
|
+ ERROR("CMD16 failed\n");
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
+ /* Prepare data command */
|
|
+ mmio_write_32(base + SDMMC_DTIMER, UINT32_MAX);
|
|
+
|
|
+ mmio_write_32(base + SDMMC_DLENR, size);
|
|
+
|
|
+ if (sdmmc2_params.use_dma) {
|
|
+ mmio_write_32(base + SDMMC_IDMACTRLR,
|
|
+ SDMMC_IDMACTRLR_IDMAEN);
|
|
+ mmio_write_32(base + SDMMC_IDMABASE0R, buf);
|
|
+
|
|
+ flush_dcache_range(buf, size);
|
|
+ }
|
|
+
|
|
+ mmio_clrsetbits_32(base + SDMMC_DCTRLR,
|
|
+ SDMMC_DCTRLR_CLEAR_MASK,
|
|
+ data_ctrl);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int stm32_sdmmc2_read(int lba, uintptr_t buf, size_t size)
|
|
+{
|
|
+ uint32_t error_flags = SDMMC_STAR_RXOVERR | SDMMC_STAR_DCRCFAIL |
|
|
+ SDMMC_STAR_DTIMEOUT;
|
|
+ uint32_t flags = error_flags | SDMMC_STAR_DATAEND;
|
|
+ uint32_t status;
|
|
+ uint32_t *buffer;
|
|
+ uintptr_t base = sdmmc2_params.reg_base;
|
|
+ uintptr_t fifo_reg = base + SDMMC_FIFOR;
|
|
+ unsigned int start;
|
|
+ int ret;
|
|
+
|
|
+ /* Assert buf is 4 bytes aligned */
|
|
+ assert((buf & GENMASK(1, 0)) == 0U);
|
|
+
|
|
+ buffer = (uint32_t *)buf;
|
|
+
|
|
+ if (sdmmc2_params.use_dma) {
|
|
+ inv_dcache_range(buf, size);
|
|
+
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ if (size <= MMC_BLOCK_SIZE) {
|
|
+ flags |= SDMMC_STAR_DBCKEND;
|
|
+ }
|
|
+
|
|
+ start = timeout_start();
|
|
+
|
|
+ do {
|
|
+ status = mmio_read_32(base + SDMMC_STAR);
|
|
+
|
|
+ if ((status & error_flags) != 0U) {
|
|
+ ERROR("%s: Read error (status = %x)\n", __func__,
|
|
+ status);
|
|
+ dump_registers();
|
|
+ mmio_write_32(base + SDMMC_DCTRLR,
|
|
+ SDMMC_DCTRLR_FIFORST);
|
|
+
|
|
+ mmio_write_32(base + SDMMC_ICR,
|
|
+ SDMMC_STATIC_FLAGS);
|
|
+
|
|
+ ret = stm32_sdmmc2_stop_transfer();
|
|
+ if (ret != 0) {
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
+ return -EIO;
|
|
+ }
|
|
+
|
|
+ if (timeout_elapsed(start, TIMEOUT_1_S)) {
|
|
+ ERROR("%s: timeout 1s (status = %x)\n",
|
|
+ __func__, status);
|
|
+ dump_registers();
|
|
+ mmio_write_32(base + SDMMC_ICR,
|
|
+ SDMMC_STATIC_FLAGS);
|
|
+
|
|
+ ret = stm32_sdmmc2_stop_transfer();
|
|
+ if (ret != 0) {
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
+ return -ETIMEDOUT;
|
|
+ }
|
|
+
|
|
+ if (size < (8U * sizeof(uint32_t))) {
|
|
+ if ((mmio_read_32(base + SDMMC_DCNTR) > 0U) &&
|
|
+ ((status & SDMMC_STAR_RXFIFOE) == 0U)) {
|
|
+ *buffer = mmio_read_32(fifo_reg);
|
|
+ buffer++;
|
|
+ }
|
|
+ } else if ((status & SDMMC_STAR_RXFIFOHF) != 0U) {
|
|
+ uint32_t count;
|
|
+
|
|
+ /* Read data from SDMMC Rx FIFO */
|
|
+ for (count = 0; count < 8U; count++) {
|
|
+ *buffer = mmio_read_32(fifo_reg);
|
|
+ buffer++;
|
|
+ }
|
|
+ }
|
|
+ } while ((status & flags) == 0U);
|
|
+
|
|
+ mmio_write_32(base + SDMMC_ICR, SDMMC_STATIC_FLAGS);
|
|
+
|
|
+ if ((status & SDMMC_STAR_DPSMACT) != 0U) {
|
|
+ WARN("%s: DPSMACT=1, send stop\n", __func__);
|
|
+ return stm32_sdmmc2_stop_transfer();
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int stm32_sdmmc2_write(int lba, uintptr_t buf, size_t size)
|
|
+{
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int stm32_sdmmc2_dt_get_config(void)
|
|
+{
|
|
+ int sdmmc_node;
|
|
+ void *fdt = NULL;
|
|
+ const fdt32_t *cuint;
|
|
+
|
|
+ if (fdt_get_address(&fdt) == 0) {
|
|
+ return -FDT_ERR_NOTFOUND;
|
|
+ }
|
|
+
|
|
+ if (fdt == NULL) {
|
|
+ return -FDT_ERR_NOTFOUND;
|
|
+ }
|
|
+
|
|
+ sdmmc_node = fdt_node_offset_by_compatible(fdt, -1, DT_SDMMC2_COMPAT);
|
|
+
|
|
+ while (sdmmc_node != -FDT_ERR_NOTFOUND) {
|
|
+ cuint = fdt_getprop(fdt, sdmmc_node, "reg", NULL);
|
|
+ if (cuint == NULL) {
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ if (fdt32_to_cpu(*cuint) == sdmmc2_params.reg_base) {
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ sdmmc_node = fdt_node_offset_by_compatible(fdt, sdmmc_node,
|
|
+ DT_SDMMC2_COMPAT);
|
|
+ }
|
|
+
|
|
+ if (sdmmc_node == -FDT_ERR_NOTFOUND) {
|
|
+ return -FDT_ERR_NOTFOUND;
|
|
+ }
|
|
+
|
|
+ if (fdt_get_status(sdmmc_node) == DT_DISABLED) {
|
|
+ return -FDT_ERR_NOTFOUND;
|
|
+ }
|
|
+
|
|
+ if (dt_set_pinctrl_config(sdmmc_node) != 0) {
|
|
+ return -FDT_ERR_BADVALUE;
|
|
+ }
|
|
+
|
|
+ cuint = fdt_getprop(fdt, sdmmc_node, "clocks", NULL);
|
|
+ if (cuint == NULL) {
|
|
+ return -FDT_ERR_NOTFOUND;
|
|
+ }
|
|
+
|
|
+ cuint++;
|
|
+ sdmmc2_params.clock_id = fdt32_to_cpu(*cuint);
|
|
+
|
|
+ cuint = fdt_getprop(fdt, sdmmc_node, "resets", NULL);
|
|
+ if (cuint == NULL) {
|
|
+ return -FDT_ERR_NOTFOUND;
|
|
+ }
|
|
+
|
|
+ cuint++;
|
|
+ sdmmc2_params.reset_id = fdt32_to_cpu(*cuint);
|
|
+
|
|
+ if ((fdt_getprop(fdt, sdmmc_node, "st,use-ckin", NULL)) != NULL) {
|
|
+ sdmmc2_params.pin_ckin = SDMMC_CLKCR_SELCLKRX_0;
|
|
+ }
|
|
+
|
|
+ if ((fdt_getprop(fdt, sdmmc_node, "st,sig-dir", NULL)) != NULL) {
|
|
+ sdmmc2_params.dirpol = SDMMC_POWER_DIRPOL;
|
|
+ }
|
|
+
|
|
+ if ((fdt_getprop(fdt, sdmmc_node, "st,neg-edge", NULL)) != NULL) {
|
|
+ sdmmc2_params.negedge = SDMMC_CLKCR_NEGEDGE;
|
|
+ }
|
|
+
|
|
+ cuint = fdt_getprop(fdt, sdmmc_node, "bus-width", NULL);
|
|
+ if (cuint != NULL) {
|
|
+ switch (fdt32_to_cpu(*cuint)) {
|
|
+ case 4:
|
|
+ sdmmc2_params.bus_width = MMC_BUS_WIDTH_4;
|
|
+ break;
|
|
+
|
|
+ case 8:
|
|
+ sdmmc2_params.bus_width = MMC_BUS_WIDTH_8;
|
|
+ break;
|
|
+
|
|
+ default:
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+unsigned long long stm32_sdmmc2_mmc_get_device_size(void)
|
|
+{
|
|
+ return sdmmc2_params.device_info->device_size;
|
|
+}
|
|
+
|
|
+int stm32_sdmmc2_mmc_init(struct stm32_sdmmc2_params *params)
|
|
+{
|
|
+ assert((params != NULL) &&
|
|
+ ((params->reg_base & MMC_BLOCK_MASK) == 0U) &&
|
|
+ ((params->bus_width == MMC_BUS_WIDTH_1) ||
|
|
+ (params->bus_width == MMC_BUS_WIDTH_4) ||
|
|
+ (params->bus_width == MMC_BUS_WIDTH_8)));
|
|
+
|
|
+ memcpy(&sdmmc2_params, params, sizeof(struct stm32_sdmmc2_params));
|
|
+
|
|
+ if (stm32_sdmmc2_dt_get_config() != 0) {
|
|
+ ERROR("%s: DT error\n", __func__);
|
|
+ return -ENOMEM;
|
|
+ }
|
|
+
|
|
+ stm32mp_clk_enable(sdmmc2_params.clock_id);
|
|
+
|
|
+ stm32mp_reset_assert(sdmmc2_params.reset_id);
|
|
+ udelay(2);
|
|
+ stm32mp_reset_deassert(sdmmc2_params.reset_id);
|
|
+ mdelay(1);
|
|
+
|
|
+ sdmmc2_params.clk_rate = stm32mp_clk_get_rate(sdmmc2_params.clock_id);
|
|
+
|
|
+ return mmc_init(&stm32_sdmmc2_ops, sdmmc2_params.clk_rate,
|
|
+ sdmmc2_params.bus_width, sdmmc2_params.flags,
|
|
+ sdmmc2_params.device_info);
|
|
+}
|
|
diff --git a/drivers/st/nand/io_nand.c b/drivers/st/nand/io_nand.c
|
|
new file mode 100644
|
|
index 0000000..54ac8fb
|
|
--- /dev/null
|
|
+++ b/drivers/st/nand/io_nand.c
|
|
@@ -0,0 +1,228 @@
|
|
+/*
|
|
+ * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved.
|
|
+ *
|
|
+ * SPDX-License-Identifier: BSD-3-Clause
|
|
+ */
|
|
+
|
|
+#include <assert.h>
|
|
+#include <debug.h>
|
|
+#include <io_driver.h>
|
|
+#include <io_nand.h>
|
|
+#include <io_storage.h>
|
|
+#include <nand.h>
|
|
+#include <string.h>
|
|
+#include <utils_def.h>
|
|
+
|
|
+/* NAND device functions */
|
|
+static int nand_dev_open(const uintptr_t init_params, io_dev_info_t **dev_info);
|
|
+static int nand_block_open(io_dev_info_t *dev_info, const uintptr_t spec,
|
|
+ io_entity_t *entity);
|
|
+static int nand_dev_init(io_dev_info_t *dev_info, const uintptr_t init_params);
|
|
+static int nand_block_seek(io_entity_t *entity, int mode,
|
|
+ signed long long offset);
|
|
+static int nand_block_read(io_entity_t *entity, uintptr_t buffer,
|
|
+ size_t length, size_t *length_read);
|
|
+static int nand_block_close(io_entity_t *entity);
|
|
+static int nand_dev_close(io_dev_info_t *dev_info);
|
|
+static io_type_t device_type_nand(void);
|
|
+
|
|
+static NAND_HandleTypeDef *hnand;
|
|
+static uint64_t seek_offset;
|
|
+
|
|
+static const io_dev_connector_t nand_dev_connector = {
|
|
+ .dev_open = nand_dev_open
|
|
+};
|
|
+
|
|
+static const io_dev_funcs_t nand_dev_funcs = {
|
|
+ .type = device_type_nand,
|
|
+ .open = nand_block_open,
|
|
+ .seek = nand_block_seek,
|
|
+ .size = NULL,
|
|
+ .read = nand_block_read,
|
|
+ .write = NULL,
|
|
+ .close = nand_block_close,
|
|
+ .dev_init = nand_dev_init,
|
|
+ .dev_close = nand_dev_close,
|
|
+};
|
|
+
|
|
+static const io_dev_info_t nand_dev_info = {
|
|
+ .funcs = &nand_dev_funcs,
|
|
+ .info = (uintptr_t)0,
|
|
+};
|
|
+
|
|
+/* Identify the device type as memmap */
|
|
+static io_type_t device_type_nand(void)
|
|
+{
|
|
+ return IO_TYPE_NAND;
|
|
+}
|
|
+
|
|
+/* Open a connection to the nand device */
|
|
+static int nand_dev_open(const uintptr_t init_params, io_dev_info_t **dev_info)
|
|
+{
|
|
+ uint32_t nb_page_per_block, page_size;
|
|
+
|
|
+ assert(dev_info);
|
|
+ *dev_info = (io_dev_info_t *)&nand_dev_info;
|
|
+
|
|
+ hnand = (NAND_HandleTypeDef *)init_params;
|
|
+
|
|
+ if (nand_initialize(hnand) != STD_OK)
|
|
+ return -EIO;
|
|
+
|
|
+ hnand->Info.page_size_shift = 0;
|
|
+
|
|
+ page_size = hnand->Info.PageSize;
|
|
+ if (!IS_POWER_OF_TWO(page_size))
|
|
+ return -EINVAL;
|
|
+
|
|
+ while (page_size >>= 1)
|
|
+ hnand->Info.page_size_shift++;
|
|
+
|
|
+ nb_page_per_block = hnand->Info.BlockSize;
|
|
+ if (!IS_POWER_OF_TWO(nb_page_per_block))
|
|
+ return -EINVAL;
|
|
+
|
|
+ /* Block size is (page_size * number of pages per blocks) */
|
|
+ hnand->Info.block_size_shift = hnand->Info.page_size_shift;
|
|
+ while (nb_page_per_block >>= 1)
|
|
+ hnand->Info.block_size_shift++;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int nand_dev_init(io_dev_info_t *dev_info, const uintptr_t init_params)
|
|
+{
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/* Close a connection to the nand device */
|
|
+static int nand_dev_close(io_dev_info_t *dev_info)
|
|
+{
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/* Open a file on the nand device */
|
|
+static int nand_block_open(io_dev_info_t *dev_info, const uintptr_t spec,
|
|
+ io_entity_t *entity)
|
|
+{
|
|
+ seek_offset = 0;
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/* Seek to a particular file offset on the nand device */
|
|
+static int nand_block_seek(io_entity_t *entity, int mode,
|
|
+ signed long long offset)
|
|
+{
|
|
+ seek_offset = offset;
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/* Read data from a file on the nand device */
|
|
+static int nand_block_read(io_entity_t *entity, uintptr_t buffer,
|
|
+ size_t length, size_t *length_read)
|
|
+{
|
|
+ uint32_t block_size_shift = hnand->Info.block_size_shift;
|
|
+ uint32_t page_size_shift = hnand->Info.page_size_shift;
|
|
+ uint32_t buffer_index = 0;
|
|
+ uint32_t num_sectors_read = seek_offset / BCH_PAGE_SECTOR;
|
|
+ uint64_t number_sectors_to_read = length / BCH_PAGE_SECTOR;
|
|
+ uint64_t nand_address_block, nand_address_page;
|
|
+ NAND_AddressTypeDef nand_address;
|
|
+
|
|
+ *length_read = 0;
|
|
+
|
|
+ nand_address_block = seek_offset;
|
|
+ while (block_size_shift) {
|
|
+ nand_address_block >>= 1;
|
|
+ if (!nand_address_block)
|
|
+ break;
|
|
+ block_size_shift--;
|
|
+ }
|
|
+
|
|
+ nand_address.Block = (uint16_t)nand_address_block;
|
|
+
|
|
+ nand_address_page = seek_offset & ((1 << hnand->Info.block_size_shift)
|
|
+ - 1);
|
|
+ while (page_size_shift) {
|
|
+ nand_address_page >>= 1;
|
|
+ if (!nand_address_page)
|
|
+ break;
|
|
+ page_size_shift--;
|
|
+ }
|
|
+
|
|
+ nand_address.Page = (uint16_t)nand_address_page;
|
|
+
|
|
+ while (NAND_Check_Bad_Block(hnand, &nand_address) == BAD_BLOCK) {
|
|
+ nand_address.Block++;
|
|
+ if (nand_address.Block >= hnand->Info.BlockNb) {
|
|
+ ERROR("Cannot find valid block\n");
|
|
+ return -EIO;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if ((length % BCH_PAGE_SECTOR) != 0) {
|
|
+ /*
|
|
+ * yes, remainder required,
|
|
+ * adjust total number of sectors required
|
|
+ * one more page needed to read,
|
|
+ * data will not fill all page
|
|
+ */
|
|
+ number_sectors_to_read += 1;
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * Proceed here with reading/copying of
|
|
+ * (number_of_pages_remaining_to_read * BCH_PAGE_SECTOR)
|
|
+ * from NAND memory to SYSRAM download area
|
|
+ */
|
|
+ while (number_sectors_to_read != 0) {
|
|
+ uint32_t bch_sector_nb = num_sectors_read %
|
|
+ (hnand->Info.PageSize / BCH_PAGE_SECTOR);
|
|
+
|
|
+ if (NAND_Read_Logical_Page(hnand, &nand_address,
|
|
+ (uint8_t *)(buffer +
|
|
+ (buffer_index *
|
|
+ BCH_PAGE_SECTOR)),
|
|
+ bch_sector_nb) != STD_OK) {
|
|
+ VERBOSE("Page read failed or end of NAND reached\n");
|
|
+ return -EIO;
|
|
+ }
|
|
+
|
|
+ /* Increment read sectors number */
|
|
+ num_sectors_read++;
|
|
+ buffer_index++;
|
|
+
|
|
+ /* Decrement sectors to read */
|
|
+ number_sectors_to_read--;
|
|
+
|
|
+ /* Increment the NAND address */
|
|
+ NAND_Address_Inc(hnand, &nand_address, num_sectors_read);
|
|
+ }
|
|
+
|
|
+ *length_read = ((num_sectors_read - (seek_offset / BCH_PAGE_SECTOR)) *
|
|
+ BCH_PAGE_SECTOR);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/* Close a file on the nand device */
|
|
+static int nand_block_close(io_entity_t *entity)
|
|
+{
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/* Exported functions */
|
|
+
|
|
+/* Register the nand driver with the IO abstraction */
|
|
+int register_io_dev_nand(const io_dev_connector_t **dev_con)
|
|
+{
|
|
+ int result;
|
|
+
|
|
+ assert(dev_con);
|
|
+
|
|
+ result = io_register_device(&nand_dev_info);
|
|
+ if (!result)
|
|
+ *dev_con = &nand_dev_connector;
|
|
+
|
|
+ return result;
|
|
+}
|
|
diff --git a/drivers/st/nand/nand.c b/drivers/st/nand/nand.c
|
|
new file mode 100644
|
|
index 0000000..7f435cc
|
|
--- /dev/null
|
|
+++ b/drivers/st/nand/nand.c
|
|
@@ -0,0 +1,1548 @@
|
|
+/*
|
|
+ ******************************************************************************
|
|
+ * @file nand.c
|
|
+ * @author mgentilini - MCD IntroPack team - MPU AP v1 bootROM project
|
|
+ * @version V0.1
|
|
+ * @date 28-April-2016
|
|
+ * @brief Nand FMC driver module for STM32MP1.
|
|
+ ******************************************************************************
|
|
+ * @attention
|
|
+ *
|
|
+ * <h2><center>© COPYRIGHT(c) STMicroelectronics</center></h2>
|
|
+ *
|
|
+ * SPDX-License-Identifier: BSD-3-Clause
|
|
+ *
|
|
+ ******************************************************************************
|
|
+ */
|
|
+
|
|
+#include <assert.h>
|
|
+#include <debug.h>
|
|
+#include <delay_timer.h>
|
|
+#include <limits.h>
|
|
+#include <nand.h>
|
|
+#include <platform.h>
|
|
+#include <platform_def.h>
|
|
+#include <stdint.h>
|
|
+#include <stm32mp_common.h>
|
|
+#include <utils_def.h>
|
|
+
|
|
+/* Other internal NAND driver definitions */
|
|
+#define CMD_SECTION ((uint32_t)(1 << 16)) /* A16 high */
|
|
+#define ADDR_SECTION ((uint32_t)(1 << 17)) /* A17 high */
|
|
+#define DATA_SECTION (0) /* A16 and A17 low */
|
|
+
|
|
+#define EIGHT_BIT_ACCESS 0x0
|
|
+#define SIXTEEN_BIT_ACCESS 0x1
|
|
+
|
|
+#define ONFI_SIG_VALUE 0x49464E4F /* "ONFI" */
|
|
+#define EXT_PAGE_SIG_VALUE 0x53505045 /* "EPPS" */
|
|
+
|
|
+/* NAND instance number */
|
|
+#define NAND_INSTANCE_NB 1
|
|
+/* Wait Time following NAND_RESET command sent (30us) */
|
|
+#define NAND_RST_TIMEOUT 30
|
|
+#define NAND_READY_WAIT_TIMEOUT_VAL_250MS_AT_64MHz 16000000
|
|
+
|
|
+/* NAND ECC Calculation wait timeout */
|
|
+#define NAND_ECC_CALCULATION_TIMEOUT_VAL_250MS ms2tick(250)
|
|
+
|
|
+#define NAND_ECC_PAGE_SECTOR 512
|
|
+#define NAND_ECC_HAMMING1 1
|
|
+#define NAND_ECC_BCH4 4
|
|
+#define NAND_ECC_BCH8 8
|
|
+#define NAND_ECC_HAMMING1_BYTES_NB_8b 3
|
|
+#define NAND_ECC_BCH4_BYTES_NB_8b 7
|
|
+#define NAND_ECC_BCH8_BYTES_NB_8b 13
|
|
+#define NAND_ECC_HAMMING1_BYTES_NB_16b 4
|
|
+#define NAND_ECC_BCH4_BYTES_NB_16b 8
|
|
+#define NAND_ECC_BCH8_BYTES_NB_16b 14
|
|
+#define PARAM_PAGE_SIZE 256
|
|
+
|
|
+/* NAND memory status */
|
|
+#define NAND_BUSY ((uint32_t)0x00000000U)
|
|
+#define NAND_ERROR ((uint32_t)0x00000001U)
|
|
+#define NAND_READY ((uint32_t)0x00000040U)
|
|
+
|
|
+/* NAND ONFI commands */
|
|
+#define NAND_CMD_RESET ((uint8_t)0xFFU)
|
|
+#define NAND_CMD_READID ((uint8_t)0x90U)
|
|
+#define NAND_CMD_READID_SIG_ADDR ((uint8_t)0x20U)
|
|
+#define NAND_CMD_READ_PARAM_PAGE ((uint8_t)0xECU)
|
|
+#define NAND_CMD_READ_1ST ((uint8_t)0x00U)
|
|
+#define NAND_CMD_READ_2ND ((uint8_t)0x30U)
|
|
+#define NAND_CMD_STATUS ((uint8_t)0x70U)
|
|
+#define NAND_CMD_CHANGE_1ST ((uint8_t)0x05U)
|
|
+#define NAND_CMD_CHANGE_2ND ((uint8_t)0xE0U)
|
|
+
|
|
+/* CRC calculation */
|
|
+#define CRC_POLYNOM 0x8005
|
|
+#define CRC_INIT_VALUE 0x4F4E
|
|
+
|
|
+static void nand_calc_timing(NAND_HandleTypeDef *hNand)
|
|
+{
|
|
+ nand_timings *tims = &hNand->Info.timings;
|
|
+ unsigned long hclk = stm32mp_clk_get_rate(FMC_K);
|
|
+ unsigned long hclkp = FMC_NSEC_PER_SEC / (hclk / 1000);
|
|
+ int tar, tclr, thiz, twait, tset_mem, tset_att, thold_mem, thold_att;
|
|
+
|
|
+ tar = hclkp;
|
|
+ if (tar < FMC_TAR_MIN)
|
|
+ tar = FMC_TAR_MIN;
|
|
+ tims->tar = div_round_up(tar, hclkp) - 1;
|
|
+ if (tims->tar > FMC_PCR_TIMING_MASK)
|
|
+ tims->tar = FMC_PCR_TIMING_MASK;
|
|
+
|
|
+ tclr = hclkp;
|
|
+ if (tclr < FMC_TCLR_MIN)
|
|
+ tclr = FMC_TCLR_MIN;
|
|
+ tims->tclr = div_round_up(tclr, hclkp) - 1;
|
|
+ if (tims->tclr > FMC_PCR_TIMING_MASK)
|
|
+ tims->tclr = FMC_PCR_TIMING_MASK;
|
|
+
|
|
+ tims->thiz = FMC_THIZ;
|
|
+ thiz = (tims->thiz + 1) * hclkp;
|
|
+
|
|
+ /*
|
|
+ * tWAIT > tRP
|
|
+ * tWAIT > tWP
|
|
+ * tWAIT > tREA + tIO
|
|
+ */
|
|
+ twait = hclkp;
|
|
+ if (twait < FMC_TRP_MIN)
|
|
+ twait = FMC_TRP_MIN;
|
|
+ if (twait < FMC_TWP_MIN)
|
|
+ twait = FMC_TWP_MIN;
|
|
+ if (twait < FMC_TREA_MAX + FMC_TIO)
|
|
+ twait = FMC_TREA_MAX + FMC_TIO;
|
|
+ tims->twait = div_round_up(twait, hclkp);
|
|
+ if (tims->twait == 0)
|
|
+ tims->twait = 1;
|
|
+
|
|
+ /*
|
|
+ * tSETUP_MEM > tCS - tWAIT
|
|
+ * tSETUP_MEM > tALS - tWAIT
|
|
+ * tSETUP_MEM > tDS - (tWAIT - tHIZ)
|
|
+ */
|
|
+ tset_mem = hclkp;
|
|
+ if (twait < FMC_TCS_MIN && (tset_mem < FMC_TCS_MIN - twait))
|
|
+ tset_mem = FMC_TCS_MIN - twait;
|
|
+ if (twait < FMC_TALS_MIN && (tset_mem < FMC_TALS_MIN - twait))
|
|
+ tset_mem = FMC_TALS_MIN - twait;
|
|
+ if (twait > thiz && (twait - thiz < FMC_TDS_MIN) &&
|
|
+ (tset_mem < FMC_TDS_MIN - (twait - thiz)))
|
|
+ tset_mem = FMC_TDS_MIN - (twait - thiz);
|
|
+ tims->tset_mem = div_round_up(tset_mem, hclkp);
|
|
+ if (tims->tset_mem == 0)
|
|
+ tims->tset_mem = 1;
|
|
+
|
|
+ /*
|
|
+ * tHOLD_MEM > tCH
|
|
+ * tHOLD_MEM > tREH - tSETUP_MEM
|
|
+ * tHOLD_MEM > max(tRC, tWC) - (tSETUP_MEM + tWAIT)
|
|
+ */
|
|
+ thold_mem = hclkp;
|
|
+ if (thold_mem < FMC_TCH_MIN)
|
|
+ thold_mem = FMC_TCH_MIN;
|
|
+ if (tset_mem < FMC_TREH_MIN &&
|
|
+ (thold_mem < FMC_TREH_MIN - tset_mem))
|
|
+ thold_mem = FMC_TREH_MIN - tset_mem;
|
|
+ if ((tset_mem + twait < FMC_TRC_MIN) &&
|
|
+ (thold_mem < FMC_TRC_MIN - (tset_mem + twait)))
|
|
+ thold_mem = FMC_TRC_MIN - (tset_mem + twait);
|
|
+ if ((tset_mem + twait < FMC_TWC_MIN) &&
|
|
+ (thold_mem < FMC_TWC_MIN - (tset_mem + twait)))
|
|
+ thold_mem = FMC_TWC_MIN - (tset_mem + twait);
|
|
+ tims->thold_mem = div_round_up(thold_mem, hclkp);
|
|
+ if (tims->thold_mem == 0)
|
|
+ tims->thold_mem = 1;
|
|
+
|
|
+ /*
|
|
+ * tSETUP_ATT > tCS - tWAIT
|
|
+ * tSETUP_ATT > tCLS - tWAIT
|
|
+ * tSETUP_ATT > tALS - tWAIT
|
|
+ * tSETUP_ATT > tRHW - tHOLD_MEM
|
|
+ * tSETUP_ATT > tDS - (tWAIT - tHIZ)
|
|
+ */
|
|
+ tset_att = hclkp;
|
|
+ if (twait < FMC_TCS_MIN && (tset_att < FMC_TCS_MIN - twait))
|
|
+ tset_att = FMC_TCS_MIN - twait;
|
|
+ if (twait < FMC_TCLS_MIN && (tset_att < FMC_TCLS_MIN - twait))
|
|
+ tset_att = FMC_TCLS_MIN - twait;
|
|
+ if (twait < FMC_TALS_MIN && (tset_att < FMC_TALS_MIN - twait))
|
|
+ tset_att = FMC_TALS_MIN - twait;
|
|
+ if (thold_mem < FMC_TRHW_MIN &&
|
|
+ (tset_att < FMC_TRHW_MIN - thold_mem))
|
|
+ tset_att = FMC_TRHW_MIN - thold_mem;
|
|
+ if (twait > thiz && (twait - thiz < FMC_TDS_MIN) &&
|
|
+ (tset_att < FMC_TDS_MIN - (twait - thiz)))
|
|
+ tset_att = FMC_TDS_MIN - (twait - thiz);
|
|
+ tims->tset_att = div_round_up(tset_att, hclkp);
|
|
+ if (tims->tset_att == 0)
|
|
+ tims->tset_att = 1;
|
|
+
|
|
+ /*
|
|
+ * tHOLD_ATT > tALH
|
|
+ * tHOLD_ATT > tCH
|
|
+ * tHOLD_ATT > tCLH
|
|
+ * tHOLD_ATT > tCOH
|
|
+ * tHOLD_ATT > tDH
|
|
+ * tHOLD_ATT > tWB + tIO + tSYNC - tSETUP_MEM
|
|
+ * tHOLD_ATT > tADL - tSETUP_MEM
|
|
+ * tHOLD_ATT > tWH - tSETUP_MEM
|
|
+ * tHOLD_ATT > tWHR - tSETUP_MEM
|
|
+ * tHOLD_ATT > tRC - (tSETUP_ATT + tWAIT)
|
|
+ * tHOLD_ATT > tWC - (tSETUP_ATT + tWAIT)
|
|
+ */
|
|
+ thold_att = hclkp;
|
|
+ if (thold_att < FMC_TALH_MIN)
|
|
+ thold_att = FMC_TALH_MIN;
|
|
+ if (thold_att < FMC_TCH_MIN)
|
|
+ thold_att = FMC_TCH_MIN;
|
|
+ if (thold_att < FMC_TCLH_MIN)
|
|
+ thold_att = FMC_TCLH_MIN;
|
|
+ if (thold_att < FMC_TCOH_MIN)
|
|
+ thold_att = FMC_TCOH_MIN;
|
|
+ if (thold_att < FMC_TDH_MIN)
|
|
+ thold_att = FMC_TDH_MIN;
|
|
+ if ((FMC_TWB_MAX + FMC_TIO + FMC_TSYNC > tset_mem) &&
|
|
+ (thold_att < FMC_TWB_MAX + FMC_TIO + FMC_TSYNC - tset_mem))
|
|
+ thold_att = FMC_TWB_MAX + FMC_TIO + FMC_TSYNC - tset_mem;
|
|
+ if (tset_mem < FMC_TADL_MIN &&
|
|
+ (thold_att < FMC_TADL_MIN - tset_mem))
|
|
+ thold_att = FMC_TADL_MIN - tset_mem;
|
|
+ if (tset_mem < FMC_TWH_MIN &&
|
|
+ (thold_att < FMC_TWH_MIN - tset_mem))
|
|
+ thold_att = FMC_TWH_MIN - tset_mem;
|
|
+ if (tset_mem < FMC_TWHR_MIN &&
|
|
+ (thold_att < FMC_TWHR_MIN - tset_mem))
|
|
+ thold_att = FMC_TWHR_MIN - tset_mem;
|
|
+ if (tset_att + twait < FMC_TRC_MIN &&
|
|
+ (thold_att < FMC_TRC_MIN - (tset_att + twait)))
|
|
+ thold_att = FMC_TRC_MIN - (tset_att + twait);
|
|
+ if (tset_att + twait < FMC_TWC_MIN &&
|
|
+ (thold_att < FMC_TWC_MIN - (tset_att + twait)))
|
|
+ thold_att = FMC_TWC_MIN - (tset_att + twait);
|
|
+ tims->thold_att = div_round_up(thold_att, hclkp);
|
|
+ if (tims->thold_att == 0)
|
|
+ tims->thold_att = 1;
|
|
+}
|
|
+
|
|
+/*****************************************************************************
|
|
+ *
|
|
+ * Function: Nand_Init
|
|
+ *
|
|
+ * Description: This function initializes the Nand FMC driver.
|
|
+ *
|
|
+ * Input parameters: NAND_HandleTypeDef * hNand
|
|
+ * uint32_t bus_width
|
|
+ *
|
|
+ * Output parameters: none
|
|
+ *
|
|
+ * Return: None
|
|
+ *
|
|
+ *****************************************************************************/
|
|
+static void Nand_Init(NAND_HandleTypeDef *hNand, uint32_t bus_width,
|
|
+ uint32_t bch_algo)
|
|
+{
|
|
+ assert(hNand);
|
|
+
|
|
+ /*
|
|
+ * Initialize NAND control Interface
|
|
+ * Wait feature disabled, memory bank disabled, ECC logic disabled,
|
|
+ * BCH is selected, TCLR and TAR to max values, ECC sector size to 512B,
|
|
+ * BCH 8-bit is selected, enabled read access
|
|
+ *
|
|
+ * Be careful to not set ECCEN bit before Read Parameter Page command
|
|
+ * ECC logic must be enabled just before Read Logical Page
|
|
+ * Note: with PWAITEN feature, NAND controller temporizes next accesses,
|
|
+ * so no need to wait for ready/not busy after each command
|
|
+ */
|
|
+
|
|
+ /*
|
|
+ * Parameters should be given by boot_context
|
|
+ * Try to retrieve them with Nand_DetectAndInit
|
|
+ */
|
|
+ if (!hNand->Info.PageSize) {
|
|
+ hNand->Instance->PCReg |= FMC_PCR_ECCALG | /* Select BCH */
|
|
+ FMC_PCR_ECCSS_0 | /* ECCSS: Sector Size=512 bytes */
|
|
+ FMC_PCR_BCHECC |
|
|
+ FMC_PCR_PWAITEN;
|
|
+
|
|
+ hNand->Instance->PCReg &= ~FMC_PCR_PBKEN &
|
|
+ ~FMC_PCR_WE &
|
|
+ ~FMC_PCR_ECCSS_1 & /* ECCSS: Sector Size=512 bytes */
|
|
+ ~FMC_PCR_ECCSS_2; /* ECCSS: Sector Size=512 bytes */
|
|
+
|
|
+ if (bus_width == SIXTEEN_BIT_ACCESS) {
|
|
+ hNand->Instance->PCReg |= FMC_PCR_PWID_0;
|
|
+ hNand->Instance->PCReg &= ~FMC_PCR_PWID_1;
|
|
+ } else {
|
|
+ hNand->Instance->PCReg &= ~FMC_PCR_PWID_0;
|
|
+ hNand->Instance->PCReg &= ~FMC_PCR_PWID_1;
|
|
+ }
|
|
+
|
|
+ if (bch_algo == NAND_ECC_BCH4) {
|
|
+ /* BCH selected */
|
|
+ hNand->Instance->PCReg |= FMC_PCR_ECCALG;
|
|
+ /* BCH4 selected */
|
|
+ hNand->Instance->PCReg &= ~FMC_PCR_BCHECC;
|
|
+ } else if (bch_algo == NAND_ECC_BCH8) {
|
|
+ /* BCH selected */
|
|
+ hNand->Instance->PCReg |= FMC_PCR_ECCALG;
|
|
+ /* BCH8 selected */
|
|
+ hNand->Instance->PCReg |= FMC_PCR_BCHECC;
|
|
+ } else {
|
|
+ /* Hamming code selected */
|
|
+ hNand->Instance->PCReg &= ~FMC_PCR_ECCALG;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ nand_calc_timing(hNand);
|
|
+
|
|
+ /* Set tclr/tar timings */
|
|
+ hNand->Instance->PCReg &=
|
|
+ ~FMC_PCR_TCLR_0 & /* tCLR: forced to value 0 */
|
|
+ ~FMC_PCR_TCLR_1 & /* tCLR: forced to value 0 */
|
|
+ ~FMC_PCR_TCLR_2 & /* tCLR: forced to value 0 */
|
|
+ ~FMC_PCR_TCLR_3 & /* tCLR: forced to value 0 */
|
|
+ ~FMC_PCR_TAR_0 & /* tAR: forced to value 0 */
|
|
+ ~FMC_PCR_TAR_1 & /* tAR: forced to value 0 */
|
|
+ ~FMC_PCR_TAR_2 & /* tAR: forced to value 0 */
|
|
+ ~FMC_PCR_TAR_3; /* tAR: forced to value 0 */
|
|
+
|
|
+ hNand->Instance->PCReg |= FMC_PCR_TCLR(hNand->Info.timings.tclr);
|
|
+ hNand->Instance->PCReg |= FMC_PCR_TAR(hNand->Info.timings.tar);
|
|
+
|
|
+ /* Set tset/twait/thold/thiz timings in common bank */
|
|
+ hNand->Instance->PMEM = FMC_PMEM_MEMSET(hNand->Info.timings.tset_mem);
|
|
+ hNand->Instance->PMEM |= FMC_PMEM_MEMWAIT(hNand->Info.timings.twait);
|
|
+ hNand->Instance->PMEM |=
|
|
+ FMC_PMEM_MEMHOLD(hNand->Info.timings.thold_mem);
|
|
+ hNand->Instance->PMEM |= FMC_PMEM_MEMHIZ(hNand->Info.timings.thiz);
|
|
+
|
|
+ /* Set tset/twait/thold/thiz timings in attribut bank */
|
|
+ hNand->Instance->PATT = FMC_PATT_ATTSET(hNand->Info.timings.tset_att);
|
|
+ hNand->Instance->PATT |= FMC_PATT_ATTWAIT(hNand->Info.timings.twait);
|
|
+ hNand->Instance->PATT |=
|
|
+ FMC_PATT_ATTHOLD(hNand->Info.timings.thold_att);
|
|
+ hNand->Instance->PATT |= FMC_PATT_ATTHIZ(hNand->Info.timings.thiz);
|
|
+
|
|
+ /* Enable the NAND device */
|
|
+ hNand->Instance->PCReg |= FMC_PCR_PBKEN;
|
|
+
|
|
+ /* Enable FMC Controller IP */
|
|
+ hNand->Instance->BCR1 |= FMC_BCR1_FMCEN;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * @brief NAND memory read status
|
|
+ * @param hNand: pointer to a NAND_HandleTypeDef structure that contains
|
|
+ * the configuration information for NAND module.
|
|
+ * @retval NAND status
|
|
+ */
|
|
+static uint32_t NAND_ReadStatus(NAND_HandleTypeDef *hNand)
|
|
+{
|
|
+ uint32_t data;
|
|
+ uintptr_t deviceComMemAddr;
|
|
+ uintptr_t deviceAttrMemAddr;
|
|
+
|
|
+ assert(hNand);
|
|
+
|
|
+ /* Identify the device address */
|
|
+ deviceComMemAddr = FLASH_COMMON_MEM_BASE;
|
|
+ deviceAttrMemAddr = FLASH_ATTRIB_MEM_BASE;
|
|
+
|
|
+ /* Send Read status operation command */
|
|
+ *(__IO uint8_t *)(deviceAttrMemAddr | CMD_SECTION) =
|
|
+ NAND_CMD_STATUS;
|
|
+
|
|
+ /* Read status register data */
|
|
+ data = *(__IO uint8_t *)deviceComMemAddr;
|
|
+
|
|
+ /* Return the status */
|
|
+ if ((data & NAND_ERROR) == NAND_ERROR)
|
|
+ return NAND_ERROR;
|
|
+ else if ((data & NAND_READY) == NAND_READY)
|
|
+ return NAND_READY;
|
|
+
|
|
+ return NAND_BUSY;
|
|
+}
|
|
+
|
|
+/*****************************************************************************
|
|
+ *
|
|
+ * Function: NAND_WaitReadyWithTimeout
|
|
+ *
|
|
+ * Description: This function wait with timeout of 250 ms until
|
|
+ * NAND Ready bit is set.
|
|
+ * Nand detection and initialization.
|
|
+ *
|
|
+ * Input parameters: NAND_HandleTypeDef * hNand
|
|
+ *
|
|
+ * Return: value 0 is no timeout occurred, value 1 if 250 ms
|
|
+ * wait timeout elapsed while waiting for NAND Ready
|
|
+ * flag to raise.
|
|
+ *
|
|
+ *****************************************************************************/
|
|
+static uint32_t NAND_WaitReadyWithTimeout(NAND_HandleTypeDef *hNand)
|
|
+{
|
|
+ uint32_t timerValInit = 0;
|
|
+ uint32_t timeoutDetected = 0;
|
|
+
|
|
+ /* Is Nand handle NULL ? */
|
|
+ assert(hNand);
|
|
+
|
|
+ /* Get timer current value at start of loop */
|
|
+ timerValInit = (uint32_t)read_cntpct_el0();
|
|
+
|
|
+ /* Wait NAND Ready by a read status command until response or */
|
|
+ /* NAND Ready timeout elapses */
|
|
+ /* timeout = 250ms @ 64 MHz of gentimer */
|
|
+ while ((NAND_ReadStatus(hNand) != NAND_READY) &&
|
|
+ (timeoutDetected == 0)) {
|
|
+ /* Check if timeout occurred */
|
|
+ if (((uint32_t)read_cntpct_el0() - timerValInit) >=
|
|
+ NAND_READY_WAIT_TIMEOUT_VAL_250MS_AT_64MHz)
|
|
+ timeoutDetected = 1;
|
|
+ }
|
|
+
|
|
+ return(timeoutDetected);
|
|
+}
|
|
+
|
|
+/*****************************************************************************
|
|
+ *
|
|
+ * Function: Nand_Reset
|
|
+ *
|
|
+ * Description: Resets NAND Flash memory.
|
|
+ *
|
|
+ * Input parameters: NAND_HandleTypeDef * hNand
|
|
+ *
|
|
+ * Output parameters: none
|
|
+ *
|
|
+ * Return: Std_ReturnType
|
|
+ *
|
|
+ *****************************************************************************/
|
|
+static Std_ReturnType Nand_Reset(NAND_HandleTypeDef *hNand)
|
|
+{
|
|
+ Std_ReturnType retVal = STD_NOT_OK;
|
|
+ uintptr_t deviceAddress;
|
|
+ uint32_t timeoutDetected = 0;
|
|
+
|
|
+ /* Is Nand handle NULL ? */
|
|
+ assert(hNand);
|
|
+
|
|
+ /* Identify the device address */
|
|
+ deviceAddress = FLASH_COMMON_MEM_BASE;
|
|
+
|
|
+ /* Send NAND reset command */
|
|
+ /* Writes the command value in command section */
|
|
+ *(uint8_t *)(deviceAddress | CMD_SECTION) = NAND_CMD_RESET;
|
|
+
|
|
+ /* Wait the fixed 30 us time : after the NAND Reset command sent */
|
|
+ /* 30us @ 64 MHz of gentimer */
|
|
+ udelay(NAND_RST_TIMEOUT);
|
|
+
|
|
+ /* Wait NANDReady with timeout 250 ms */
|
|
+ timeoutDetected = NAND_WaitReadyWithTimeout(hNand);
|
|
+
|
|
+ /* If no timeout occurred : the NAND Reset phase was successful */
|
|
+ if (timeoutDetected == 0)
|
|
+ /* Set good status on exit */
|
|
+ retVal = STD_OK;
|
|
+
|
|
+ return retVal;
|
|
+}
|
|
+
|
|
+/*****************************************************************************
|
|
+ *
|
|
+ * Function: Nand_ReadIDCode
|
|
+ *
|
|
+ * Description: This function reads the NAND ID code
|
|
+ *
|
|
+ * Input parameters: NAND_HandleTypeDef * hNand: NAND handle
|
|
+ * NAND_IDTypeDef * pNAND_ID: NAND ID structure
|
|
+ *
|
|
+ * Output parameters: none
|
|
+ *
|
|
+ * Return: None
|
|
+ *
|
|
+ *****************************************************************************/
|
|
+static void Nand_ReadIDCode(NAND_HandleTypeDef *hNand, NAND_IDTypeDef *pNAND_ID)
|
|
+{
|
|
+ uint32_t data;
|
|
+ uintptr_t deviceComMemAddr;
|
|
+ uintptr_t deviceAttrMemAddr;
|
|
+
|
|
+ assert(hNand);
|
|
+
|
|
+ /* Identify the device addresses */
|
|
+ deviceComMemAddr = FLASH_COMMON_MEM_BASE;
|
|
+ deviceAttrMemAddr = FLASH_ATTRIB_MEM_BASE;
|
|
+
|
|
+ /* Send Read ID command sequence */
|
|
+ *(__IO uint8_t *)(deviceComMemAddr | CMD_SECTION) = NAND_CMD_READID;
|
|
+ *(__IO uint8_t *)(deviceAttrMemAddr | ADDR_SECTION) = 0x00;
|
|
+
|
|
+ udelay(NAND_RST_TIMEOUT);
|
|
+
|
|
+ /* Read the electronic signature from NAND flash */
|
|
+ data = *(__IO uint16_t *)deviceComMemAddr;
|
|
+
|
|
+ /* Return the data read */
|
|
+ pNAND_ID->Maker_Id = (uint8_t)(data);
|
|
+ pNAND_ID->Device_Id = (uint8_t)(data >> 8);
|
|
+}
|
|
+
|
|
+/**
|
|
+ * @brief NAND check CRC16
|
|
+ * @param crc: initial CRC value
|
|
+ * @param data_in: pointer to buffer
|
|
+ * @param data_len: length of data
|
|
+ * @retval CRC 16 bits
|
|
+ */
|
|
+static uint16_t NAND_CheckCrc16(uint16_t crc, uint8_t *data_in,
|
|
+ uint32_t data_len)
|
|
+{
|
|
+ /* Algorithm from ONFI standard */
|
|
+
|
|
+ uint32_t i, j, bit;
|
|
+
|
|
+ for (i = 0; i < data_len; i++) {
|
|
+ uint8_t curParam = *data_in++;
|
|
+
|
|
+ for (j = 0x80; j != 0; j >>= 1) {
|
|
+ bit = crc & 0x8000;
|
|
+ crc <<= 1;
|
|
+
|
|
+ if (curParam & j)
|
|
+ bit ^= 0x8000;
|
|
+
|
|
+ if (bit)
|
|
+ crc ^= CRC_POLYNOM;
|
|
+ }
|
|
+ crc &= 0xFFFF;
|
|
+ }
|
|
+
|
|
+ return crc;
|
|
+}
|
|
+
|
|
+/*****************************************************************************
|
|
+ *
|
|
+ * Function: Nand_ReadParameterPage
|
|
+ *
|
|
+ * Description: This function reads the NAND parameter page
|
|
+ * (command 0xEC)
|
|
+ * The Read Parameter Page command retrieves
|
|
+ * the data structure that describes
|
|
+ * the targets organization, features, timings
|
|
+ * and other behavioral parameters.
|
|
+ * There may also be additional information
|
|
+ * provided in an extended parameter page.
|
|
+ *
|
|
+ * Input parameters: NAND_HandleTypeDef * hNand
|
|
+ *
|
|
+ * Output parameters: none
|
|
+ *
|
|
+ * Return: Std_ReturnType
|
|
+ *
|
|
+ *****************************************************************************/
|
|
+static Std_ReturnType Nand_ReadParameterPage(NAND_HandleTypeDef *hNand)
|
|
+{
|
|
+ uint32_t index;
|
|
+ uint8_t buffer[PARAM_PAGE_SIZE];
|
|
+ uintptr_t deviceComMemAddr;
|
|
+ uintptr_t deviceAttrMemAddr;
|
|
+ int i;
|
|
+ uint16_t crc16;
|
|
+
|
|
+ assert(hNand);
|
|
+
|
|
+ /* Identify the device address */
|
|
+ deviceComMemAddr = FLASH_COMMON_MEM_BASE;
|
|
+ deviceAttrMemAddr = FLASH_ATTRIB_MEM_BASE;
|
|
+
|
|
+ /* Send ONFI Parameter Page Read sequence */
|
|
+ *(uint8_t *)(deviceComMemAddr | CMD_SECTION) = NAND_CMD_READ_PARAM_PAGE;
|
|
+ *(uint8_t *)(deviceAttrMemAddr | ADDR_SECTION) = 0x00;
|
|
+
|
|
+ udelay(NAND_RST_TIMEOUT);
|
|
+
|
|
+ /*
|
|
+ * Read Parameter Page
|
|
+ * Note: There are three consecutive redondant copies
|
|
+ * of parameter page
|
|
+ */
|
|
+ for (i = 0; i < 3; i++) {
|
|
+ /* Read parameter page from NAND flash */
|
|
+ /* Get data */
|
|
+ for (index = 0; index < PARAM_PAGE_SIZE; index++)
|
|
+ buffer[index] = *(uint8_t *)deviceComMemAddr;
|
|
+
|
|
+ /*
|
|
+ * Bytes 0-4: Parameter page signature
|
|
+ * This field contains the parameter page signature.
|
|
+ * When two or more bytes of the signature are valid,
|
|
+ * then it denotes that a valid copy
|
|
+ * of the parameter page is present
|
|
+ */
|
|
+ hNand->Info.Signature = (buffer[3] << 24) | (buffer[2] << 16) |
|
|
+ (buffer[1] << 8) | buffer[0];
|
|
+ crc16 = (buffer[254] | buffer[255] << 8);
|
|
+
|
|
+ if ((hNand->Info.Signature == ONFI_SIG_VALUE) &&
|
|
+ (NAND_CheckCrc16(CRC_INIT_VALUE, buffer,
|
|
+ PARAM_PAGE_SIZE - 2) == crc16))
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ if (i == 3) {
|
|
+ /* Could not find ONFI parameter page */
|
|
+ INFO("%s: No Onfi Parameter Page\n", __func__);
|
|
+ return STD_NOT_OK;
|
|
+ }
|
|
+
|
|
+ /* Byte 6, bit 0: data bus width (8 or 16) */
|
|
+ hNand->Info.BusWidth = buffer[6] & 0x1;
|
|
+
|
|
+ /* Bytes 80-83: Page size */
|
|
+ hNand->Info.PageSize = (buffer[83] << 24) | (buffer[82] << 16) |
|
|
+ (buffer[81] << 8) | buffer[80];
|
|
+
|
|
+ /* Bytes 92-95 : Block size in number of pages */
|
|
+ hNand->Info.BlockSize = (buffer[95] << 24) | (buffer[94] << 16) |
|
|
+ (buffer[93] << 8) | buffer[92];
|
|
+
|
|
+ /* Byte 96-99: Number of blocks per logical unit */
|
|
+ hNand->Info.BlockNb = (buffer[99] << 24) | (buffer[98] << 16) |
|
|
+ (buffer[97] << 8) | buffer[96];
|
|
+
|
|
+ /*
|
|
+ * Byte 112: Number of bits ECC correctability
|
|
+ * This field indicates the number of bits that the host
|
|
+ * should be able to correct per 512 bytes of data
|
|
+ */
|
|
+ if (buffer[112] != 0xFF) {
|
|
+ hNand->Info.ECCcorrectability = buffer[112];
|
|
+ } else if ((buffer[4] != 1) && (buffer[4] != 2) &&
|
|
+ buffer[6] & (1 << 7)) {
|
|
+ /* NAND ONFI, version > 2.1, with extended parameter page */
|
|
+ uint32_t ext_page_size = ((buffer[13] << 8) | buffer[12]);
|
|
+ uint32_t ext_page_offset = buffer[14] * PARAM_PAGE_SIZE;
|
|
+ uint32_t ecc_block_offset = 32;
|
|
+
|
|
+ /* Send ONFI Parameter Page Read sequence */
|
|
+ *(uint8_t *)(deviceComMemAddr | CMD_SECTION) =
|
|
+ NAND_CMD_READ_PARAM_PAGE;
|
|
+ *(uint8_t *)(deviceAttrMemAddr | ADDR_SECTION) = 0x00;
|
|
+
|
|
+ /* Skip ONFI parameter pages to read Extended parameter page */
|
|
+ *(uint8_t *)(deviceComMemAddr | CMD_SECTION) =
|
|
+ NAND_CMD_CHANGE_1ST;
|
|
+
|
|
+ *(uint8_t *)(deviceComMemAddr | ADDR_SECTION) =
|
|
+ ADDR_1ST_CYCLE(ext_page_offset);
|
|
+
|
|
+ *(uint8_t *)(deviceAttrMemAddr | ADDR_SECTION) =
|
|
+ ADDR_2ND_CYCLE(ext_page_offset);
|
|
+
|
|
+ *(uint8_t *)(deviceAttrMemAddr | CMD_SECTION) =
|
|
+ NAND_CMD_CHANGE_2ND;
|
|
+
|
|
+ udelay(NAND_RST_TIMEOUT);
|
|
+
|
|
+ /* Copy Extended parameter page */
|
|
+ for (index = 0; index < PARAM_PAGE_SIZE; index++)
|
|
+ buffer[index] = *(uint8_t *)deviceComMemAddr;
|
|
+
|
|
+ if (((buffer[5] << 24) | (buffer[4] << 16) |
|
|
+ (buffer[3] << 8) | buffer[2]) != EXT_PAGE_SIG_VALUE) {
|
|
+ WARN("Extended parameter page signature is wrong\n");
|
|
+ return STD_NOT_OK;
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * Extended parameter page can fit in buffer
|
|
+ * we can try to calculate its CRC
|
|
+ */
|
|
+ if (ext_page_size <= PARAM_PAGE_SIZE) {
|
|
+ crc16 = (buffer[1] << 8) | buffer[0];
|
|
+
|
|
+ if (NAND_CheckCrc16(CRC_INIT_VALUE, buffer,
|
|
+ ext_page_size) != crc16) {
|
|
+ WARN("Extended page CRC failed\n");
|
|
+ return STD_NOT_OK;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * Check the 8 sections of extended parameter page
|
|
+ * for an extended ECC information block (type = 2)
|
|
+ */
|
|
+ for (i = 0; i < 8; i++) {
|
|
+ if (buffer[16 + 2 * i] == 2)
|
|
+ break;
|
|
+
|
|
+ ecc_block_offset += buffer[17 + 2 * i];
|
|
+ }
|
|
+
|
|
+ if (i == 8) {
|
|
+ WARN("ECC extended block could not be found\n");
|
|
+ return STD_NOT_OK;
|
|
+ }
|
|
+
|
|
+ if (ext_page_size <= PARAM_PAGE_SIZE) {
|
|
+ /*
|
|
+ * ECC correctcatbility is the first byte
|
|
+ * of the ECC block
|
|
+ */
|
|
+ hNand->Info.ECCcorrectability =
|
|
+ buffer[ecc_block_offset];
|
|
+ } else {
|
|
+ /* Send ONFI Parameter Page Read sequence */
|
|
+ *(uint8_t *)(deviceComMemAddr | CMD_SECTION) =
|
|
+ NAND_CMD_READ_PARAM_PAGE;
|
|
+ *(uint8_t *)(deviceAttrMemAddr | ADDR_SECTION) = 0x00;
|
|
+
|
|
+ /*
|
|
+ * Skip ONFI parameter pages to read
|
|
+ * Extended parameter page
|
|
+ */
|
|
+ *(uint8_t *)(deviceComMemAddr | CMD_SECTION) =
|
|
+ NAND_CMD_CHANGE_1ST;
|
|
+ *(uint8_t *)(deviceComMemAddr | ADDR_SECTION) =
|
|
+ ADDR_1ST_CYCLE(ext_page_offset +
|
|
+ ecc_block_offset);
|
|
+
|
|
+ *(uint8_t *)(deviceAttrMemAddr | ADDR_SECTION) =
|
|
+ ADDR_2ND_CYCLE(ext_page_offset +
|
|
+ ecc_block_offset);
|
|
+
|
|
+ *(uint8_t *)(deviceAttrMemAddr | CMD_SECTION) =
|
|
+ NAND_CMD_CHANGE_2ND;
|
|
+
|
|
+ udelay(NAND_RST_TIMEOUT);
|
|
+
|
|
+ hNand->Info.ECCcorrectability =
|
|
+ *(uint8_t *)deviceComMemAddr;
|
|
+ }
|
|
+ } else {
|
|
+ WARN("ECC correctability could not be found\n");
|
|
+ return STD_NOT_OK;
|
|
+ }
|
|
+
|
|
+ return STD_OK;
|
|
+}
|
|
+
|
|
+/*****************************************************************************
|
|
+ *
|
|
+ * Function: Nand_DetectAndInit
|
|
+ *
|
|
+ * Description: This function initializes the Nand FMC driver.
|
|
+ * Nand detection and initialization.
|
|
+ *
|
|
+ * Input parameters: NAND_HandleTypeDef * hNand
|
|
+ *
|
|
+ * Output parameters: none
|
|
+ *
|
|
+ * Return: Std_ReturnType
|
|
+ *
|
|
+ *****************************************************************************/
|
|
+static Std_ReturnType Nand_DetectAndInit(NAND_HandleTypeDef *hNand)
|
|
+{
|
|
+ NAND_IDTypeDef pNAND_ID;
|
|
+ uint32_t nand_param_in_otp, result;
|
|
+
|
|
+ assert(hNand);
|
|
+
|
|
+ /* Remark : ReadID and ReadParameterPage are commands on 8-bit */
|
|
+
|
|
+ /* ReadID code */
|
|
+ Nand_ReadIDCode(hNand, &pNAND_ID);
|
|
+
|
|
+ /* Check if NAND parameters are stored in OTP */
|
|
+ result = bsec_shadow_read_otp(&nand_param_in_otp, NAND_OTP);
|
|
+ if (result != BSEC_OK) {
|
|
+ ERROR("BSEC: NAND_OTP Error %i\n", result);
|
|
+ return STD_NOT_OK;
|
|
+ }
|
|
+
|
|
+ if (nand_param_in_otp & NAND_PARAM_STORED_IN_OTP) {
|
|
+ /*
|
|
+ * NAND parameter shall be read from OTP
|
|
+ */
|
|
+ hNand->Info.BusWidth = (nand_param_in_otp & NAND_WIDTH_MASK) >>
|
|
+ NAND_WIDTH_OFFSET;
|
|
+
|
|
+ switch ((nand_param_in_otp & NAND_PAGE_SIZE_MASK) >>
|
|
+ NAND_PAGE_SIZE_OFFSET) {
|
|
+ case NAND_PAGE_SIZE_2K:
|
|
+ hNand->Info.PageSize = 2048;
|
|
+ break;
|
|
+
|
|
+ case NAND_PAGE_SIZE_4K:
|
|
+ hNand->Info.PageSize = 4096;
|
|
+ break;
|
|
+
|
|
+ case NAND_PAGE_SIZE_8K:
|
|
+ hNand->Info.PageSize = 8192;
|
|
+ break;
|
|
+
|
|
+ default:
|
|
+ hNand->Info.PageSize = 0;
|
|
+ ERROR("Cannot read NAND page size\n");
|
|
+ return STD_NOT_OK;
|
|
+ }
|
|
+
|
|
+ switch ((nand_param_in_otp & NAND_BLOCK_SIZE_MASK) >>
|
|
+ NAND_BLOCK_SIZE_OFFSET) {
|
|
+ case NAND_BLOCK_SIZE_64_PAGES:
|
|
+ hNand->Info.BlockSize = 64;
|
|
+ break;
|
|
+
|
|
+ case NAND_BLOCK_SIZE_128_PAGES:
|
|
+ hNand->Info.BlockSize = 128;
|
|
+ break;
|
|
+
|
|
+ case NAND_BLOCK_SIZE_256_PAGES:
|
|
+ hNand->Info.BlockSize = 256;
|
|
+ break;
|
|
+
|
|
+ default:
|
|
+ hNand->Info.BlockSize = 0;
|
|
+ ERROR("Cannot read NAND block size\n");
|
|
+ return STD_NOT_OK;
|
|
+ }
|
|
+
|
|
+ hNand->Info.BlockNb = ((nand_param_in_otp &
|
|
+ NAND_BLOCK_NB_MASK) >>
|
|
+ NAND_BLOCK_NB_OFFSET) *
|
|
+ NAND_BLOCK_NB_UNIT;
|
|
+
|
|
+ switch ((nand_param_in_otp & NAND_ECC_BIT_NB_MASK) >>
|
|
+ NAND_ECC_BIT_NB_OFFSET) {
|
|
+ case NAND_ECC_BIT_NB_UNSET:
|
|
+ hNand->Info.ECCcorrectability = 0;
|
|
+ break;
|
|
+
|
|
+ case NAND_ECC_BIT_NB_1_BITS:
|
|
+ hNand->Info.ECCcorrectability = 1;
|
|
+ break;
|
|
+
|
|
+ case NAND_ECC_BIT_NB_4_BITS:
|
|
+ hNand->Info.ECCcorrectability = 4;
|
|
+ break;
|
|
+
|
|
+ case NAND_ECC_BIT_NB_8_BITS:
|
|
+ hNand->Info.ECCcorrectability = 8;
|
|
+ break;
|
|
+
|
|
+ default:
|
|
+ hNand->Info.ECCcorrectability = 0;
|
|
+ ERROR("Cannot read ECCbit number\n");
|
|
+ return STD_NOT_OK;
|
|
+ }
|
|
+ } else {
|
|
+ /*
|
|
+ * ONFI or 'ONFI compliant' NAND
|
|
+ * 'ONFI compliant' means that parameters used by bootrom are
|
|
+ * available in parameter table at same offsets as in a
|
|
+ * ONFI parameter table.
|
|
+ * NAND parameter shall be read from Parameter table.
|
|
+ */
|
|
+
|
|
+ uint32_t onfi_ecc;
|
|
+
|
|
+ /* Read Nand parameter page */
|
|
+ if (Nand_ReadParameterPage(hNand) != STD_OK) {
|
|
+ ERROR("%s: NAND not initialized\n", __func__);
|
|
+ return STD_NOT_OK;
|
|
+ }
|
|
+
|
|
+ onfi_ecc = hNand->Info.ECCcorrectability;
|
|
+
|
|
+ /*
|
|
+ * For ONFI nand, ECC number of bits may be overridden by a
|
|
+ * value from OTP configuration.
|
|
+ */
|
|
+ switch ((nand_param_in_otp & NAND_ECC_BIT_NB_MASK) >>
|
|
+ NAND_ECC_BIT_NB_OFFSET) {
|
|
+ case NAND_ECC_BIT_NB_UNSET:
|
|
+ hNand->Info.ECCcorrectability = 0;
|
|
+ break;
|
|
+
|
|
+ case NAND_ECC_BIT_NB_1_BITS:
|
|
+ hNand->Info.ECCcorrectability = 1;
|
|
+ break;
|
|
+
|
|
+ case NAND_ECC_BIT_NB_4_BITS:
|
|
+ hNand->Info.ECCcorrectability = 4;
|
|
+ break;
|
|
+
|
|
+ case NAND_ECC_BIT_NB_8_BITS:
|
|
+ hNand->Info.ECCcorrectability = 8;
|
|
+ break;
|
|
+
|
|
+ default:
|
|
+ hNand->Info.ECCcorrectability = 0;
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * if OTP info is wrong, fall back to parameter read in ONFI
|
|
+ * parameter page
|
|
+ */
|
|
+ if (hNand->Info.ECCcorrectability == 0)
|
|
+ hNand->Info.ECCcorrectability = onfi_ecc;
|
|
+ }
|
|
+
|
|
+ Nand_Init(hNand, hNand->Info.BusWidth, hNand->Info.ECCcorrectability);
|
|
+
|
|
+ /* Now NAND Flash is detected and initialized */
|
|
+ return STD_OK;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * @brief NAND read page command sequence
|
|
+ * @param hNand: pointer to a NAND_HandleTypeDef structure that contains
|
|
+ * the configuration information for NAND module.
|
|
+ * @param colAddr: column address
|
|
+ * @param rowAddr: row address
|
|
+ * @retval Std_ReturnType
|
|
+ */
|
|
+static void NAND_Read_Page_Cmd(NAND_HandleTypeDef *hNand, uint32_t colAddr,
|
|
+ uint32_t rowAddr)
|
|
+{
|
|
+ uintptr_t deviceComMemAddr;
|
|
+ uintptr_t deviceAttrMemAddr;
|
|
+
|
|
+ assert(hNand);
|
|
+
|
|
+ /* Identify the device address */
|
|
+ deviceComMemAddr = FLASH_COMMON_MEM_BASE;
|
|
+ deviceAttrMemAddr = FLASH_ATTRIB_MEM_BASE;
|
|
+
|
|
+ /* If NAND 8bit */
|
|
+ if (hNand->Info.BusWidth == EIGHT_BIT_ACCESS) {
|
|
+ *(__IO uint8_t *)(deviceComMemAddr | CMD_SECTION) =
|
|
+ NAND_CMD_READ_1ST;
|
|
+
|
|
+ /* C1 */
|
|
+ *(__IO uint8_t *)(deviceComMemAddr | ADDR_SECTION) =
|
|
+ ADDR_1ST_CYCLE(colAddr);
|
|
+ /* C2 */
|
|
+ *(__IO uint8_t *)(deviceComMemAddr | ADDR_SECTION) =
|
|
+ ADDR_2ND_CYCLE(colAddr);
|
|
+ /* R1 */
|
|
+ *(__IO uint8_t *)(deviceComMemAddr | ADDR_SECTION) =
|
|
+ ADDR_1ST_CYCLE(rowAddr);
|
|
+ /* R2 */
|
|
+ *(__IO uint8_t *)(deviceComMemAddr | ADDR_SECTION) =
|
|
+ ADDR_2ND_CYCLE(rowAddr);
|
|
+
|
|
+ /* R3 */
|
|
+ *(__IO uint8_t *)(deviceAttrMemAddr | ADDR_SECTION) =
|
|
+ ADDR_3RD_CYCLE(rowAddr);
|
|
+
|
|
+ *(__IO uint8_t *)(deviceAttrMemAddr | CMD_SECTION) =
|
|
+ NAND_CMD_READ_2ND;
|
|
+ } else {
|
|
+ /* NAND 16bit */
|
|
+ *(__IO uint16_t *)(deviceComMemAddr | CMD_SECTION) =
|
|
+ NAND_CMD_READ_1ST;
|
|
+
|
|
+ /* C1 */
|
|
+ *(__IO uint16_t *)(deviceComMemAddr | ADDR_SECTION) =
|
|
+ ADDR_1ST_CYCLE(colAddr);
|
|
+ /* C2 */
|
|
+ *(__IO uint16_t *)(deviceComMemAddr | ADDR_SECTION) =
|
|
+ ADDR_2ND_CYCLE(colAddr);
|
|
+ /* R1 */
|
|
+ *(__IO uint16_t *)(deviceComMemAddr | ADDR_SECTION) =
|
|
+ ADDR_1ST_CYCLE(rowAddr);
|
|
+ /* R2 */
|
|
+ *(__IO uint16_t *)(deviceComMemAddr | ADDR_SECTION) =
|
|
+ ADDR_2ND_CYCLE(rowAddr);
|
|
+
|
|
+ /* R3 */
|
|
+ *(__IO uint16_t *)(deviceAttrMemAddr | ADDR_SECTION) =
|
|
+ ADDR_3RD_CYCLE(rowAddr);
|
|
+
|
|
+ *(__IO uint16_t *)(deviceAttrMemAddr | CMD_SECTION) =
|
|
+ NAND_CMD_READ_2ND;
|
|
+ }
|
|
+}
|
|
+
|
|
+/*****************************************************************************
|
|
+ *
|
|
+ * Function: _bit_count
|
|
+ *
|
|
+ * Description: Return the number of bits set to one in a 32bit word
|
|
+ *
|
|
+ * Input parameters: v 32 bit word
|
|
+ *
|
|
+ * Return: number of bits set to one in v.
|
|
+ *
|
|
+ *****************************************************************************/
|
|
+static uint32_t _bit_count(uint32_t v)
|
|
+{
|
|
+ uint32_t c = 0;
|
|
+
|
|
+ for (uint32_t i = 0; i < CHAR_BIT * sizeof(typeof(v)); i++)
|
|
+ if (v & (BIT(i)))
|
|
+ c++;
|
|
+
|
|
+ return c;
|
|
+}
|
|
+
|
|
+/*****************************************************************************
|
|
+ *
|
|
+ * Function: NAND_Hamming_Correction
|
|
+ *
|
|
+ * Description: Consider Hamming correction code, and apply correction
|
|
+ * if needed and possible.
|
|
+ *
|
|
+ * Input parameters: Buffer : pointer to buffer containing data read.
|
|
+ * EccBuffer : pointer to buffer containing ecc code read
|
|
+ * from out of band area.
|
|
+ * EccCalculated : ECC calculated by FMC during reading of
|
|
+ * data.
|
|
+ *
|
|
+ * Return: 0 no error detected
|
|
+ * 1 one error detected and correted
|
|
+ * > 1 unrecoverable error
|
|
+ * -1 ecc error
|
|
+ *
|
|
+ *****************************************************************************/
|
|
+static int NAND_Hamming_Correction(uint8_t *Buffer, uint8_t *EccBuffer,
|
|
+ uint32_t EccCalculated)
|
|
+{
|
|
+ uint8_t xor_ecc_ones;
|
|
+ uint16_t xor_ecc_1b, xor_ecc_2b, xor_ecc_3b;
|
|
+ union {
|
|
+ uint32_t val;
|
|
+ uint8_t bytes[4];
|
|
+ } xor_ecc;
|
|
+
|
|
+ /* Page size--------ECC_Code Size
|
|
+ * 256---------------22 bits LSB (ECC_CODE & 0x003FFFFF)
|
|
+ * 512---------------24 bits (ECC_CODE & 0x00FFFFFF)
|
|
+ * 1024--------------26 bits (ECC_CODE & 0x03FFFFFF)
|
|
+ * 2048--------------28 bits (ECC_CODE & 0x0FFFFFFF)
|
|
+ * 4096--------------30 bits (ECC_CODE & 0x3FFFFFFF)
|
|
+ * 8192--------------32 bits (ECC_CODE & 0xFFFFFFFF)
|
|
+ */
|
|
+
|
|
+ /* For Page size 512, ECC_Code size 24 bits */
|
|
+ xor_ecc_1b = (EccCalculated & 0x000000FF) ^ EccBuffer[0];
|
|
+ xor_ecc_2b = ((EccCalculated & 0x0000FF00) >> 8) ^ EccBuffer[1];
|
|
+ xor_ecc_3b = ((EccCalculated & 0x00FF0000) >> 16) ^ EccBuffer[2];
|
|
+
|
|
+ xor_ecc.val = 0L;
|
|
+ xor_ecc.bytes[2] = xor_ecc_3b;
|
|
+ xor_ecc.bytes[1] = xor_ecc_2b;
|
|
+ xor_ecc.bytes[0] = xor_ecc_1b;
|
|
+
|
|
+ if (xor_ecc.val == 0)
|
|
+ return 0; /* No Error */
|
|
+
|
|
+ xor_ecc_ones = _bit_count(xor_ecc.val);
|
|
+ if (xor_ecc_ones < 23) {
|
|
+ if (xor_ecc_ones == 12) {
|
|
+ uint16_t bit_address, byte_address;
|
|
+
|
|
+ /* Correctable ERROR */
|
|
+ bit_address = ((xor_ecc_1b >> 1) & 0x01) |
|
|
+ ((xor_ecc_1b >> 2) & 0x02) |
|
|
+ ((xor_ecc_1b >> 3) & 0x04);
|
|
+
|
|
+ byte_address = ((xor_ecc_1b >> 7) & 0x01) |
|
|
+ ((xor_ecc_2b) & 0x02) |
|
|
+ ((xor_ecc_2b >> 1) & 0x04) |
|
|
+ ((xor_ecc_2b >> 2) & 0x08) |
|
|
+ ((xor_ecc_2b >> 3) & 0x10) |
|
|
+ ((xor_ecc_3b << 4) & 0x20) |
|
|
+ ((xor_ecc_3b << 3) & 0x40) |
|
|
+ ((xor_ecc_3b << 2) & 0x80) |
|
|
+ ((xor_ecc_3b << 1) & 0x100);
|
|
+
|
|
+ /* Correct bit error in the data */
|
|
+ Buffer[byte_address] = (Buffer[byte_address]) ^
|
|
+ ((uint8_t)(1 << bit_address));
|
|
+ INFO("Hamming: 1 ECC error corrected\n");
|
|
+ return 1;
|
|
+ }
|
|
+
|
|
+ /* Non Correctable ERROR */
|
|
+ ERROR("%s: Uncorrectable ECC Errors\n", __func__);
|
|
+ return 2;
|
|
+ }
|
|
+
|
|
+ /* ECC ERROR */
|
|
+ ERROR("%s: Hamming correction error\n", __func__);
|
|
+ return -1;
|
|
+}
|
|
+
|
|
+/*****************************************************************************
|
|
+ *
|
|
+ * Function: NAND_Read_Logical_Page
|
|
+ *
|
|
+ * Description: Read 512B sector from NAND memory page
|
|
+ *
|
|
+ * Input parameters: hNand: pointer to a NAND_HandleTypeDef structure
|
|
+ * that contains the configuration information
|
|
+ * for NAND module.
|
|
+ * Address : pointer to NAND address structure
|
|
+ * Buffer : pointer to destination read buffer
|
|
+ * bch_sector_nb : 512B sector number in the page
|
|
+ *
|
|
+ *
|
|
+ * Return: Std_ReturnType
|
|
+ *
|
|
+ *****************************************************************************/
|
|
+Std_ReturnType NAND_Read_Logical_Page(NAND_HandleTypeDef *hNand,
|
|
+ NAND_AddressTypeDef *Address,
|
|
+ uint8_t *Buffer, uint32_t bch_sector_nb)
|
|
+{
|
|
+ uintptr_t deviceComMemAddr;
|
|
+ uintptr_t deviceAttrMemAddr;
|
|
+ uint32_t size = 0;
|
|
+ uint32_t index, bloc_nb, nb_pages_per_block, offset;
|
|
+ uint32_t ecc_size = 0;
|
|
+ uint32_t rowAddr = 0, colAddr = 0;
|
|
+ uint8_t EccBuffer[NAND_ECC_BCH8_BYTES_NB_16b];
|
|
+ uint32_t heccr = 0;
|
|
+
|
|
+ assert(hNand);
|
|
+
|
|
+ /* Identify the device address */
|
|
+ deviceComMemAddr = FLASH_COMMON_MEM_BASE;
|
|
+ deviceAttrMemAddr = FLASH_ATTRIB_MEM_BASE;
|
|
+
|
|
+ bloc_nb = Address->Block;
|
|
+ nb_pages_per_block = hNand->Info.BlockSize;
|
|
+
|
|
+ /* Page and block to be read */
|
|
+ rowAddr = (bloc_nb * nb_pages_per_block) + Address->Page;
|
|
+
|
|
+ /* If NAND 8bit */
|
|
+ if (hNand->Info.BusWidth == EIGHT_BIT_ACCESS) {
|
|
+ /* Byte or word in page to be read */
|
|
+ colAddr = bch_sector_nb * NAND_ECC_PAGE_SECTOR;
|
|
+
|
|
+ size = NAND_ECC_PAGE_SECTOR;
|
|
+ } else {
|
|
+ /* If NAND 16bit */
|
|
+ /* Byte or word in page to be read */
|
|
+ colAddr = (bch_sector_nb * NAND_ECC_PAGE_SECTOR) / 2;
|
|
+
|
|
+ size = NAND_ECC_PAGE_SECTOR / 2;
|
|
+ }
|
|
+
|
|
+ /* Reset ECC enabling */
|
|
+ hNand->Instance->PCReg &= ~FMC_PCR_ECCEN;
|
|
+ hNand->Instance->PCReg &= ~FMC_PCR_WE;
|
|
+ hNand->Instance->PCReg |= FMC_PCR_ECCEN;
|
|
+
|
|
+ /* Clear status */
|
|
+ hNand->Instance->BCHICR = 0x1F;
|
|
+
|
|
+ /* Send read page command sequence */
|
|
+ NAND_Read_Page_Cmd(hNand, colAddr, rowAddr);
|
|
+
|
|
+ /* Get data into destination buffer */
|
|
+ /* If NAND 8bit */
|
|
+ if (hNand->Info.BusWidth == EIGHT_BIT_ACCESS) {
|
|
+ uint8_t *Buffer8b = (uint8_t *)Buffer;
|
|
+
|
|
+ for (index = 0; index < size; index++)
|
|
+ *Buffer8b++ = *(uint8_t *)deviceComMemAddr;
|
|
+ } else {
|
|
+ /* If NAND 16bit */
|
|
+ uint16_t *Buffer16b = (uint16_t *)Buffer;
|
|
+
|
|
+ for (index = 0; index < size; index++)
|
|
+ *Buffer16b++ = *(uint16_t *)deviceComMemAddr;
|
|
+ }
|
|
+
|
|
+ if (hNand->Info.ECCcorrectability == NAND_ECC_HAMMING1) {
|
|
+ /* During read of data , syndrome is calculated */
|
|
+ /* Wait until decoding error is ready */
|
|
+ uint32_t timerValInit = read_cntpct_el0();
|
|
+
|
|
+ while ((hNand->Instance->SR & FMC_SR_NWRF) != FMC_SR_NWRF) {
|
|
+ if ((read_cntpct_el0() - timerValInit) >
|
|
+ NAND_ECC_CALCULATION_TIMEOUT_VAL_250MS) {
|
|
+ ERROR("%s: syndrome calculation timeout\n",
|
|
+ __func__);
|
|
+ return STD_NOT_OK;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ heccr = hNand->Instance->HECCR;
|
|
+ }
|
|
+
|
|
+ /* Read now corresponding ECC bytes (7 or 13) in spare area */
|
|
+ /* Page and block to be read */
|
|
+
|
|
+ if (hNand->Info.ECCcorrectability == NAND_ECC_BCH4) {
|
|
+ if (hNand->Info.BusWidth == EIGHT_BIT_ACCESS)
|
|
+ ecc_size = NAND_ECC_BCH4_BYTES_NB_8b;
|
|
+ else
|
|
+ ecc_size = NAND_ECC_BCH4_BYTES_NB_16b;
|
|
+ } else if (hNand->Info.ECCcorrectability == NAND_ECC_BCH8) {
|
|
+ if (hNand->Info.BusWidth == EIGHT_BIT_ACCESS)
|
|
+ ecc_size = NAND_ECC_BCH8_BYTES_NB_8b;
|
|
+ else
|
|
+ ecc_size = NAND_ECC_BCH8_BYTES_NB_16b;
|
|
+ } else {
|
|
+ if (hNand->Info.BusWidth == EIGHT_BIT_ACCESS)
|
|
+ ecc_size = NAND_ECC_HAMMING1_BYTES_NB_8b;
|
|
+ else
|
|
+ ecc_size = NAND_ECC_HAMMING1_BYTES_NB_16b;
|
|
+ }
|
|
+
|
|
+ offset = 2;
|
|
+
|
|
+ /* If NAND 8bit */
|
|
+ if (hNand->Info.BusWidth == EIGHT_BIT_ACCESS) {
|
|
+ /* Byte or word in page to be read */
|
|
+ /* See SRS mapping */
|
|
+ colAddr = hNand->Info.PageSize + offset +
|
|
+ (bch_sector_nb * ecc_size);
|
|
+ } else {
|
|
+ /* If NAND 16bit */
|
|
+ /* Byte or word in page to be read */
|
|
+ /* See SRS mapping */
|
|
+ colAddr = (hNand->Info.PageSize + offset +
|
|
+ (bch_sector_nb * ecc_size)) / 2;
|
|
+ }
|
|
+
|
|
+ /* Send change read column command */
|
|
+ if (hNand->Info.BusWidth == EIGHT_BIT_ACCESS) {
|
|
+ *(__IO uint8_t *)(deviceComMemAddr | CMD_SECTION) =
|
|
+ NAND_CMD_CHANGE_1ST;
|
|
+
|
|
+ /* C1 */
|
|
+ *(__IO uint8_t *)(deviceComMemAddr | ADDR_SECTION) =
|
|
+ ADDR_1ST_CYCLE(colAddr);
|
|
+ /* C2 */
|
|
+ *(__IO uint8_t *)(deviceAttrMemAddr | ADDR_SECTION) =
|
|
+ ADDR_2ND_CYCLE(colAddr);
|
|
+
|
|
+ *(__IO uint8_t *)(deviceAttrMemAddr | CMD_SECTION) =
|
|
+ NAND_CMD_CHANGE_2ND;
|
|
+ } else {
|
|
+ *(__IO uint16_t *)(deviceComMemAddr | CMD_SECTION) =
|
|
+ NAND_CMD_CHANGE_1ST;
|
|
+
|
|
+ /* C1 */
|
|
+ *(__IO uint16_t *)(deviceComMemAddr | ADDR_SECTION) =
|
|
+ ADDR_1ST_CYCLE(colAddr);
|
|
+ /* C2 */
|
|
+ *(__IO uint16_t *)(deviceAttrMemAddr | ADDR_SECTION) =
|
|
+ ADDR_2ND_CYCLE(colAddr);
|
|
+
|
|
+ *(__IO uint16_t *)(deviceAttrMemAddr | CMD_SECTION) =
|
|
+ NAND_CMD_CHANGE_2ND;
|
|
+ }
|
|
+
|
|
+ /* Get data into destination EccBuffer */
|
|
+
|
|
+ /* If NAND 8bit */
|
|
+ if (hNand->Info.BusWidth == EIGHT_BIT_ACCESS) {
|
|
+ uint8_t *pEccBuffer = EccBuffer;
|
|
+
|
|
+ for (index = 0; index < ecc_size; index++)
|
|
+ *(uint8_t *)pEccBuffer++ = *(uint8_t *)deviceComMemAddr;
|
|
+ } else {
|
|
+ /* If NAND 16bit */
|
|
+ uint16_t *pEccBuffer16b = (uint16_t *)(EccBuffer);
|
|
+
|
|
+ for (index = 0; index < ecc_size / 2; index++) {
|
|
+ *(uint16_t *)pEccBuffer16b++ =
|
|
+ *(uint16_t *)deviceComMemAddr;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (hNand->Info.ECCcorrectability == NAND_ECC_HAMMING1) {
|
|
+ int nb_errors;
|
|
+
|
|
+ nb_errors = NAND_Hamming_Correction(Buffer, EccBuffer,
|
|
+ heccr);
|
|
+ if ((nb_errors != 0) && (nb_errors != 1))
|
|
+ return STD_NOT_OK;
|
|
+
|
|
+ } else /* BCH error correction */ {
|
|
+ uint32_t ecc_errors_nb;
|
|
+ uint32_t i;
|
|
+ uint32_t errorPosition[8];
|
|
+
|
|
+ /*
|
|
+ * During read of data and parity bits, syndrome is calculated,
|
|
+ * then error location is launched
|
|
+ * Wait until decoding error is ready
|
|
+ */
|
|
+ uint32_t timerValInit = (uint32_t)read_cntpct_el0();
|
|
+
|
|
+ while ((hNand->Instance->BCHISR & FMC_BCHISR_DERF) !=
|
|
+ FMC_BCHISR_DERF) {
|
|
+ if (((uint32_t)read_cntpct_el0() - timerValInit) >
|
|
+ NAND_ECC_CALCULATION_TIMEOUT_VAL_250MS)
|
|
+ return STD_NOT_OK;
|
|
+ }
|
|
+
|
|
+ /* Read decoding results */
|
|
+ /* Check if there were uncorrectable errors */
|
|
+ if (hNand->Instance->BCHISR & FMC_BCHISR_DUEF) {
|
|
+ VERBOSE("%s: Uncorrectable ECC Error\n", __func__);
|
|
+ return STD_NOT_OK;
|
|
+ }
|
|
+
|
|
+ /* Check if there were errors */
|
|
+ if (!(hNand->Instance->BCHISR & FMC_BCHISR_DEFF))
|
|
+ return STD_OK;
|
|
+
|
|
+ /* Read number of errors */
|
|
+ ecc_errors_nb = hNand->Instance->BCHSR & FMC_BCHSR_DEN;
|
|
+
|
|
+ VERBOSE("%s: ECC Errors detected: %d\n", __func__,
|
|
+ ecc_errors_nb);
|
|
+
|
|
+ /* Retrieve the error position corresponding to the error
|
|
+ * number
|
|
+ */
|
|
+ /* Error 1 position : FMC_BCHDSR1.EBP1 */
|
|
+ errorPosition[0] = hNand->Instance->BCHDSR1 & FMC_BCHDSR1_EBP1;
|
|
+ /* Error 2 position : FMC_BCHDSR1.EBP2 */
|
|
+ errorPosition[1] = (hNand->Instance->BCHDSR1 & FMC_BCHDSR1_EBP2)
|
|
+ >> FMC_EBP2_MASK;
|
|
+ /* Error 3 position : FMC_BCHDSR2.EBP1 */
|
|
+ errorPosition[2] = hNand->Instance->BCHDSR2 & FMC_BCHDSR2_EBP1;
|
|
+ /* Error 4 position : FMC_BCHDSR2.EBP2 */
|
|
+ errorPosition[3] = (hNand->Instance->BCHDSR2 & FMC_BCHDSR2_EBP2)
|
|
+ >> FMC_EBP2_MASK;
|
|
+ /* Error 5 position : FMC_BCHDSR3.EBP1 */
|
|
+ errorPosition[4] = hNand->Instance->BCHDSR3 & FMC_BCHDSR3_EBP1;
|
|
+ /* Error 6 position : FMC_BCHDSR3.EBP2 */
|
|
+ errorPosition[5] = (hNand->Instance->BCHDSR3 & FMC_BCHDSR3_EBP2)
|
|
+ >> FMC_EBP2_MASK;
|
|
+ /* Error 7 position : FMC_BCHDSR4.EBP1 */
|
|
+ errorPosition[6] = hNand->Instance->BCHDSR4 & FMC_BCHDSR4_EBP1;
|
|
+ /* Error 8 position : FMC_BCHDSR4.EBP2 */
|
|
+ errorPosition[7] = (hNand->Instance->BCHDSR4 & FMC_BCHDSR4_EBP2)
|
|
+ >> FMC_EBP2_MASK;
|
|
+
|
|
+ /* Error position indicates error bit number in binary */
|
|
+ /* Retrieve the mask of the wrong bit to correct */
|
|
+ for (i = 0; i < ecc_errors_nb; i++) {
|
|
+ VERBOSE("%s: ECC Error position: %d\n", __func__,
|
|
+ errorPosition[i]);
|
|
+ /* Correct only if error is in data area */
|
|
+ if (errorPosition[i] < 0x1000) {
|
|
+ /*
|
|
+ * Retrieve the mask of the wrong bit
|
|
+ * to correct
|
|
+ */
|
|
+ uint32_t bitMask = BIT(errorPosition[i] & 0x07);
|
|
+
|
|
+ /*
|
|
+ * Remove bit postion in the error position
|
|
+ * (to have byte to correct)
|
|
+ */
|
|
+ errorPosition[i] >>= 0x03;
|
|
+ VERBOSE("%s: ECC Error in data area\n",
|
|
+ __func__);
|
|
+
|
|
+ /* Fix the error : invert the wrong bit */
|
|
+ *(Buffer + errorPosition[i]) ^= bitMask;
|
|
+ } else {
|
|
+ VERBOSE("%s: ECC Error not in data area\n",
|
|
+ __func__);
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return STD_OK;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * @brief NAND check bad blck
|
|
+ * @param hNand: pointer to a NAND_HandleTypeDef structure that contains
|
|
+ * the configuration information for NAND module.
|
|
+ * Address: pointer to NAND address structure
|
|
+ * @retval BAD_BLOCK or GOOD_BLOCK
|
|
+ */
|
|
+uint32_t NAND_Check_Bad_Block(NAND_HandleTypeDef *hNand,
|
|
+ NAND_AddressTypeDef *Address)
|
|
+{
|
|
+ uintptr_t deviceComMemAddr = 0;
|
|
+ uint32_t bloc_nb = 0;
|
|
+ uint32_t nb_pages_per_block = 0;
|
|
+ uint32_t page_nb;
|
|
+ uint32_t block_status = BAD_BLOCK;
|
|
+ uint32_t rowAddr = 0, colAddr = 0;
|
|
+ uint8_t bbm_marker, bbm_marker_2;
|
|
+ uint16_t bbm_marker16b;
|
|
+
|
|
+ assert(hNand);
|
|
+
|
|
+ /* Identify the device address */
|
|
+ deviceComMemAddr = FLASH_COMMON_MEM_BASE;
|
|
+
|
|
+ /*
|
|
+ * Bad block indication is is the 2 first bytes of the 1st
|
|
+ * or 2nd page of the block (depends on manufacturer)
|
|
+ */
|
|
+
|
|
+ /*
|
|
+ * Read the 2 first bytes of the spare area
|
|
+ * of the 1st page of the block
|
|
+ */
|
|
+ bloc_nb = Address->Block;
|
|
+ nb_pages_per_block = hNand->Info.BlockSize;
|
|
+
|
|
+ /* Page and block to be read */
|
|
+ page_nb = 0;
|
|
+ rowAddr = (bloc_nb * nb_pages_per_block) + page_nb;
|
|
+
|
|
+ /* If NAND 8bit */
|
|
+ if (hNand->Info.BusWidth == EIGHT_BIT_ACCESS) {
|
|
+ /* Byte or word in page to be read */
|
|
+ colAddr = hNand->Info.PageSize;
|
|
+ } else {
|
|
+ /* If NAND 16bit */
|
|
+ /* Byte or word in page to be read */
|
|
+ colAddr = hNand->Info.PageSize / 2;
|
|
+ }
|
|
+
|
|
+ /* Send read page command sequence */
|
|
+ NAND_Read_Page_Cmd(hNand, colAddr, rowAddr);
|
|
+
|
|
+ udelay(NAND_RST_TIMEOUT);
|
|
+
|
|
+ /* Get data into destination buffer */
|
|
+ /* If NAND 8bit */
|
|
+ if (hNand->Info.BusWidth == EIGHT_BIT_ACCESS) {
|
|
+ bbm_marker = *(uint8_t *)deviceComMemAddr;
|
|
+ bbm_marker_2 = *(uint8_t *)deviceComMemAddr;
|
|
+
|
|
+ if ((bbm_marker != 0xFF) || (bbm_marker_2 != 0xFF))
|
|
+ block_status = BAD_BLOCK;
|
|
+ else
|
|
+ block_status = GOOD_BLOCK;
|
|
+
|
|
+ } else {
|
|
+ /* If NAND 16bit */
|
|
+ bbm_marker16b = *(uint16_t *)deviceComMemAddr;
|
|
+
|
|
+ if (bbm_marker16b != 0xFFFF)
|
|
+ block_status = BAD_BLOCK;
|
|
+ else
|
|
+ block_status = GOOD_BLOCK;
|
|
+ }
|
|
+
|
|
+ if (block_status == BAD_BLOCK)
|
|
+ return block_status;
|
|
+
|
|
+ /*
|
|
+ * Read the 2 first bytes of the spare area of the 2nd page
|
|
+ * of the block
|
|
+ * Page and block to be read
|
|
+ */
|
|
+ page_nb = 1;
|
|
+ rowAddr = (bloc_nb * nb_pages_per_block) + page_nb;
|
|
+
|
|
+ /* Send read page command sequence */
|
|
+ NAND_Read_Page_Cmd(hNand, colAddr, rowAddr);
|
|
+
|
|
+ udelay(NAND_RST_TIMEOUT);
|
|
+
|
|
+ /* Get data into destination buffer */
|
|
+ /* If NAND 8bit */
|
|
+ if (hNand->Info.BusWidth == EIGHT_BIT_ACCESS) {
|
|
+ bbm_marker = *(uint8_t *)deviceComMemAddr;
|
|
+ bbm_marker_2 = *(uint8_t *)deviceComMemAddr;
|
|
+
|
|
+ if ((bbm_marker == 0xFF) && (bbm_marker_2 == 0xFF))
|
|
+ block_status = GOOD_BLOCK;
|
|
+ else
|
|
+ block_status = BAD_BLOCK;
|
|
+ } else {
|
|
+ /* If NAND 16bit */
|
|
+ bbm_marker16b = *(uint16_t *)deviceComMemAddr;
|
|
+
|
|
+ if (bbm_marker16b == 0xFFFF)
|
|
+ block_status = GOOD_BLOCK;
|
|
+ else
|
|
+ block_status = BAD_BLOCK;
|
|
+ }
|
|
+
|
|
+ return block_status;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * @brief Increment the NAND memory address
|
|
+ * @param hNand: pointer to a NAND_HandleTypeDef structure that contains
|
|
+ * the configuration information for NAND module.
|
|
+ * @param Address: pointer to NAND address structure
|
|
+ * @retval Std_ReturnType
|
|
+ */
|
|
+Std_ReturnType NAND_Address_Inc(NAND_HandleTypeDef *hNand,
|
|
+ NAND_AddressTypeDef *Address,
|
|
+ uint32_t numPagesRead)
|
|
+{
|
|
+ assert(hNand);
|
|
+
|
|
+ /* Increment page address */
|
|
+ if ((numPagesRead % (hNand->Info.PageSize / BCH_PAGE_SECTOR)) == 0)
|
|
+ Address->Page++;
|
|
+
|
|
+ /* Check NAND address is valid */
|
|
+ if (Address->Page == hNand->Info.BlockSize) {
|
|
+ Address->Page = 0;
|
|
+ /* Search for next valid block */
|
|
+ Address->Block++;
|
|
+ while (Address->Block < hNand->Info.BlockNb &&
|
|
+ NAND_Check_Bad_Block(hNand, Address) == BAD_BLOCK)
|
|
+ Address->Block++;
|
|
+
|
|
+ if (Address->Block == hNand->Info.BlockNb)
|
|
+ return STD_NOT_OK;
|
|
+ }
|
|
+
|
|
+ return STD_OK;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * @brief Initialize driver only if needed:
|
|
+ * bootrom must have initialize NAND and bootcontext
|
|
+ * must contains correct value.
|
|
+ * @param hNand: pointer to a NAND_HandleTypeDef structure that contains
|
|
+ * the configuration information for NAND module.
|
|
+ * @retval Std_ReturnType
|
|
+ */
|
|
+Std_ReturnType nand_initialize(NAND_HandleTypeDef *hnand)
|
|
+{
|
|
+ if (!hnand->Info.PageSize) {
|
|
+ INFO("Reconfigure NAND\n");
|
|
+ /* Not properly initialized by bootrom */
|
|
+ Nand_Init(hnand, EIGHT_BIT_ACCESS, NAND_ECC_BCH8);
|
|
+
|
|
+ if (Nand_Reset(hnand) != STD_OK) {
|
|
+ ERROR("nand: Reset error (IP base::0x%lx)\n",
|
|
+ (uintptr_t)hnand->Instance);
|
|
+ return STD_NOT_OK;
|
|
+ }
|
|
+
|
|
+ if (Nand_DetectAndInit(hnand) != STD_OK) {
|
|
+ ERROR("nand: DetectAndInit error (IP base:0x%lx)\n",
|
|
+ (uintptr_t)hnand->Instance);
|
|
+ return STD_NOT_OK;
|
|
+ }
|
|
+ } else {
|
|
+ /* Initialization done, just need to set correct timing */
|
|
+ Nand_Init(hnand, hnand->Info.BusWidth,
|
|
+ hnand->Info.ECCcorrectability);
|
|
+ }
|
|
+ return STD_OK;
|
|
+}
|
|
+
|
|
diff --git a/drivers/st/pmic/stm32_i2c.c b/drivers/st/pmic/stm32_i2c.c
|
|
deleted file mode 100644
|
|
index 0980139..0000000
|
|
--- a/drivers/st/pmic/stm32_i2c.c
|
|
+++ /dev/null
|
|
@@ -1,851 +0,0 @@
|
|
-/*
|
|
- * Copyright (c) 2016-2018, STMicroelectronics - All Rights Reserved
|
|
- *
|
|
- * SPDX-License-Identifier: BSD-3-Clause
|
|
- */
|
|
-
|
|
-#include <arch_helpers.h>
|
|
-#include <delay_timer.h>
|
|
-#include <errno.h>
|
|
-#include <mmio.h>
|
|
-#include <stdbool.h>
|
|
-#include <stdlib.h>
|
|
-#include <stm32_i2c.h>
|
|
-
|
|
-/* STM32 I2C registers offsets */
|
|
-#define I2C_CR1 0x00U
|
|
-#define I2C_CR2 0x04U
|
|
-#define I2C_OAR1 0x08U
|
|
-#define I2C_OAR2 0x0CU
|
|
-#define I2C_TIMINGR 0x10U
|
|
-#define I2C_TIMEOUTR 0x14U
|
|
-#define I2C_ISR 0x18U
|
|
-#define I2C_ICR 0x1CU
|
|
-#define I2C_PECR 0x20U
|
|
-#define I2C_RXDR 0x24U
|
|
-#define I2C_TXDR 0x28U
|
|
-
|
|
-#define MAX_DELAY 0xFFFFFFFFU
|
|
-
|
|
-/* I2C TIMING clear register Mask */
|
|
-#define TIMING_CLEAR_MASK 0xF0FFFFFFU
|
|
-/* Timeout 25 ms */
|
|
-#define I2C_TIMEOUT_BUSY 25U
|
|
-
|
|
-#define MAX_NBYTE_SIZE 255U
|
|
-
|
|
-static int i2c_request_memory_write(struct i2c_handle_s *hi2c,
|
|
- uint16_t dev_addr, uint16_t mem_addr,
|
|
- uint16_t mem_add_size, uint32_t timeout,
|
|
- uint32_t tick_start);
|
|
-static int i2c_request_memory_read(struct i2c_handle_s *hi2c, uint16_t dev_addr,
|
|
- uint16_t mem_addr, uint16_t mem_add_size,
|
|
- uint32_t timeout, uint32_t tick_start);
|
|
-
|
|
-/* Private functions to handle flags during polling transfer */
|
|
-static int i2c_wait_flag(struct i2c_handle_s *hi2c, uint32_t flag,
|
|
- uint8_t awaited_value, uint32_t timeout,
|
|
- uint32_t tick_start);
|
|
-static int i2c_wait_txis(struct i2c_handle_s *hi2c, uint32_t timeout,
|
|
- uint32_t tick_start);
|
|
-static int i2c_wait_stop(struct i2c_handle_s *hi2c, uint32_t timeout,
|
|
- uint32_t tick_start);
|
|
-static int i2c_ack_failed(struct i2c_handle_s *hi2c, uint32_t timeout,
|
|
- uint32_t tick_start);
|
|
-
|
|
-/* Private function to flush TXDR register */
|
|
-static void i2c_flush_txdr(struct i2c_handle_s *hi2c);
|
|
-
|
|
-/* Private function to start, restart or stop a transfer */
|
|
-static void i2c_transfer_config(struct i2c_handle_s *hi2c, uint16_t dev_addr,
|
|
- uint16_t size, uint32_t i2c_mode,
|
|
- uint32_t request);
|
|
-
|
|
-/*
|
|
- * @brief Initialize the I2C device.
|
|
- * @param hi2c: Pointer to a struct i2c_handle_s structure that contains
|
|
- * the configuration information for the specified I2C.
|
|
- * @retval 0 if OK, negative value else
|
|
- */
|
|
-int stm32_i2c_init(struct i2c_handle_s *hi2c)
|
|
-{
|
|
- if (hi2c == NULL) {
|
|
- return -ENOENT;
|
|
- }
|
|
-
|
|
- if (hi2c->i2c_state == I2C_STATE_RESET) {
|
|
- hi2c->lock = 0;
|
|
- }
|
|
-
|
|
- hi2c->i2c_state = I2C_STATE_BUSY;
|
|
-
|
|
- /* Disable the selected I2C peripheral */
|
|
- mmio_clrbits_32(hi2c->i2c_base_addr + I2C_CR1, I2C_CR1_PE);
|
|
-
|
|
- /* Configure I2Cx: Frequency range */
|
|
- mmio_write_32(hi2c->i2c_base_addr + I2C_TIMINGR,
|
|
- hi2c->i2c_init.timing & TIMING_CLEAR_MASK);
|
|
-
|
|
- /* Disable Own Address1 before set the Own Address1 configuration */
|
|
- mmio_clrbits_32(hi2c->i2c_base_addr + I2C_OAR1, I2C_OAR1_OA1EN);
|
|
-
|
|
- /* Configure I2Cx: Own Address1 and ack own address1 mode */
|
|
- if (hi2c->i2c_init.addressing_mode == I2C_ADDRESSINGMODE_7BIT) {
|
|
- mmio_write_32(hi2c->i2c_base_addr + I2C_OAR1,
|
|
- I2C_OAR1_OA1EN | hi2c->i2c_init.own_address1);
|
|
- } else { /* I2C_ADDRESSINGMODE_10BIT */
|
|
- mmio_write_32(hi2c->i2c_base_addr + I2C_OAR1,
|
|
- I2C_OAR1_OA1EN | I2C_OAR1_OA1MODE |
|
|
- hi2c->i2c_init.own_address1);
|
|
- }
|
|
-
|
|
- /* Configure I2Cx: Addressing Master mode */
|
|
- if (hi2c->i2c_init.addressing_mode == I2C_ADDRESSINGMODE_10BIT) {
|
|
- mmio_write_32(hi2c->i2c_base_addr + I2C_CR2, I2C_CR2_ADD10);
|
|
- }
|
|
-
|
|
- /*
|
|
- * Enable the AUTOEND by default, and enable NACK
|
|
- * (should be disable only during Slave process)
|
|
- */
|
|
- mmio_setbits_32(hi2c->i2c_base_addr + I2C_CR2,
|
|
- I2C_CR2_AUTOEND | I2C_CR2_NACK);
|
|
-
|
|
- /* Disable Own Address2 before set the Own Address2 configuration */
|
|
- mmio_clrbits_32(hi2c->i2c_base_addr + I2C_OAR2, I2C_DUALADDRESS_ENABLE);
|
|
-
|
|
- /* Configure I2Cx: Dual mode and Own Address2 */
|
|
- mmio_write_32(hi2c->i2c_base_addr + I2C_OAR2,
|
|
- hi2c->i2c_init.dual_address_mode |
|
|
- hi2c->i2c_init.own_address2 |
|
|
- (hi2c->i2c_init.own_address2_masks << 8));
|
|
-
|
|
- /* Configure I2Cx: Generalcall and NoStretch mode */
|
|
- mmio_write_32(hi2c->i2c_base_addr + I2C_CR1,
|
|
- hi2c->i2c_init.general_call_mode |
|
|
- hi2c->i2c_init.no_stretch_mode);
|
|
-
|
|
- /* Enable the selected I2C peripheral */
|
|
- mmio_setbits_32(hi2c->i2c_base_addr + I2C_CR1, I2C_CR1_PE);
|
|
-
|
|
- hi2c->i2c_err = I2C_ERROR_NONE;
|
|
- hi2c->i2c_state = I2C_STATE_READY;
|
|
- hi2c->i2c_mode = I2C_MODE_NONE;
|
|
-
|
|
- return 0;
|
|
-}
|
|
-
|
|
-/*
|
|
- * @brief Write an amount of data in blocking mode to a specific memory address
|
|
- * @param hi2c: Pointer to a struct i2c_handle_s structure that contains
|
|
- * the configuration information for the specified I2C.
|
|
- * @param dev_addr: Target device address
|
|
- * @param mem_addr: Internal memory address
|
|
- * @param mem_add_size: size of internal memory address
|
|
- * @param p_data: Pointer to data buffer
|
|
- * @param size: Amount of data to be sent
|
|
- * @param timeout: timeout duration
|
|
- * @retval 0 if OK, negative value else
|
|
- */
|
|
-int stm32_i2c_mem_write(struct i2c_handle_s *hi2c, uint16_t dev_addr,
|
|
- uint16_t mem_addr, uint16_t mem_add_size,
|
|
- uint8_t *p_data, uint16_t size, uint32_t timeout)
|
|
-{
|
|
- uint32_t tickstart;
|
|
-
|
|
- if ((hi2c->i2c_state != I2C_STATE_READY) || (hi2c->lock != 0U)) {
|
|
- return -EBUSY;
|
|
- }
|
|
-
|
|
- if ((p_data == NULL) || (size == 0U)) {
|
|
- return -EINVAL;
|
|
- }
|
|
-
|
|
- hi2c->lock = 1;
|
|
-
|
|
- tickstart = (uint32_t)read_cntpct_el0();
|
|
-
|
|
- if (i2c_wait_flag(hi2c, I2C_FLAG_BUSY, 1, I2C_TIMEOUT_BUSY,
|
|
- tickstart) != 0) {
|
|
- return -EIO;
|
|
- }
|
|
-
|
|
- hi2c->i2c_state = I2C_STATE_BUSY_TX;
|
|
- hi2c->i2c_mode = I2C_MODE_MEM;
|
|
- hi2c->i2c_err = I2C_ERROR_NONE;
|
|
-
|
|
- hi2c->p_buff = p_data;
|
|
- hi2c->xfer_count = size;
|
|
-
|
|
- /* Send Slave Address and Memory Address */
|
|
- if (i2c_request_memory_write(hi2c, dev_addr, mem_addr, mem_add_size,
|
|
- timeout, tickstart) != 0) {
|
|
- hi2c->lock = 0;
|
|
- return -EIO;
|
|
- }
|
|
-
|
|
- /*
|
|
- * Set NBYTES to write and reload
|
|
- * if hi2c->xfer_count > MAX_NBYTE_SIZE
|
|
- */
|
|
- if (hi2c->xfer_count > MAX_NBYTE_SIZE) {
|
|
- hi2c->xfer_size = MAX_NBYTE_SIZE;
|
|
- i2c_transfer_config(hi2c, dev_addr, hi2c->xfer_size,
|
|
- I2C_RELOAD_MODE, I2C_NO_STARTSTOP);
|
|
- } else {
|
|
- hi2c->xfer_size = hi2c->xfer_count;
|
|
- i2c_transfer_config(hi2c, dev_addr, hi2c->xfer_size,
|
|
- I2C_AUTOEND_MODE, I2C_NO_STARTSTOP);
|
|
- }
|
|
-
|
|
- do {
|
|
- if (i2c_wait_txis(hi2c, timeout, tickstart) != 0) {
|
|
- return -EIO;
|
|
- }
|
|
-
|
|
- mmio_write_8(hi2c->i2c_base_addr + I2C_TXDR, *hi2c->p_buff);
|
|
- hi2c->p_buff++;
|
|
- hi2c->xfer_count--;
|
|
- hi2c->xfer_size--;
|
|
-
|
|
- if ((hi2c->xfer_count != 0U) && (hi2c->xfer_size == 0U)) {
|
|
- /* Wait until TCR flag is set */
|
|
- if (i2c_wait_flag(hi2c, I2C_FLAG_TCR, 0, timeout,
|
|
- tickstart) != 0) {
|
|
- return -EIO;
|
|
- }
|
|
-
|
|
- if (hi2c->xfer_count > MAX_NBYTE_SIZE) {
|
|
- hi2c->xfer_size = MAX_NBYTE_SIZE;
|
|
- i2c_transfer_config(hi2c, dev_addr,
|
|
- hi2c->xfer_size,
|
|
- I2C_RELOAD_MODE,
|
|
- I2C_NO_STARTSTOP);
|
|
- } else {
|
|
- hi2c->xfer_size = hi2c->xfer_count;
|
|
- i2c_transfer_config(hi2c, dev_addr,
|
|
- hi2c->xfer_size,
|
|
- I2C_AUTOEND_MODE,
|
|
- I2C_NO_STARTSTOP);
|
|
- }
|
|
- }
|
|
-
|
|
- } while (hi2c->xfer_count > 0U);
|
|
-
|
|
- /*
|
|
- * No need to Check TC flag, with AUTOEND mode the stop
|
|
- * is automatically generated.
|
|
- * Wait until STOPF flag is reset.
|
|
- */
|
|
- if (i2c_wait_stop(hi2c, timeout, tickstart) != 0) {
|
|
- return -EIO;
|
|
- }
|
|
-
|
|
- mmio_write_32(hi2c->i2c_base_addr + I2C_ICR, I2C_FLAG_STOPF);
|
|
-
|
|
- mmio_clrbits_32(hi2c->i2c_base_addr + I2C_CR2, I2C_RESET_CR2);
|
|
-
|
|
- hi2c->i2c_state = I2C_STATE_READY;
|
|
- hi2c->i2c_mode = I2C_MODE_NONE;
|
|
-
|
|
- hi2c->lock = 0;
|
|
-
|
|
- return 0;
|
|
-}
|
|
-
|
|
-/*
|
|
- * @brief Read an amount of data in blocking mode from a specific memory
|
|
- * address
|
|
- * @param hi2c: Pointer to a struct i2c_handle_s structure that contains
|
|
- * the configuration information for the specified I2C.
|
|
- * @param dev_addr: Target device address
|
|
- * @param mem_addr: Internal memory address
|
|
- * @param mem_add_size: size of internal memory address
|
|
- * @param p_data: Pointer to data buffer
|
|
- * @param size: Amount of data to be sent
|
|
- * @param timeout: timeout duration
|
|
- * @retval 0 if OK, negative value else
|
|
- */
|
|
-int stm32_i2c_mem_read(struct i2c_handle_s *hi2c, uint16_t dev_addr,
|
|
- uint16_t mem_addr, uint16_t mem_add_size,
|
|
- uint8_t *p_data, uint16_t size, uint32_t timeout)
|
|
-{
|
|
- uint32_t tickstart;
|
|
-
|
|
- if ((hi2c->i2c_state != I2C_STATE_READY) || (hi2c->lock != 0U)) {
|
|
- return -EBUSY;
|
|
- }
|
|
-
|
|
- if ((p_data == NULL) || (size == 0U)) {
|
|
- return -EINVAL;
|
|
- }
|
|
-
|
|
- hi2c->lock = 1;
|
|
-
|
|
- tickstart = (uint32_t)read_cntpct_el0();
|
|
-
|
|
- if (i2c_wait_flag(hi2c, I2C_FLAG_BUSY, 1, I2C_TIMEOUT_BUSY,
|
|
- tickstart) != 0) {
|
|
- return -EIO;
|
|
- }
|
|
-
|
|
- hi2c->i2c_state = I2C_STATE_BUSY_RX;
|
|
- hi2c->i2c_mode = I2C_MODE_MEM;
|
|
- hi2c->i2c_err = I2C_ERROR_NONE;
|
|
-
|
|
- hi2c->p_buff = p_data;
|
|
- hi2c->xfer_count = size;
|
|
-
|
|
- /* Send Slave Address and Memory Address */
|
|
- if (i2c_request_memory_read(hi2c, dev_addr, mem_addr, mem_add_size,
|
|
- timeout, tickstart) != 0) {
|
|
- hi2c->lock = 0;
|
|
- return -EIO;
|
|
- }
|
|
-
|
|
- /*
|
|
- * Send Slave Address.
|
|
- * Set NBYTES to write and reload if hi2c->xfer_count > MAX_NBYTE_SIZE
|
|
- * and generate RESTART.
|
|
- */
|
|
- if (hi2c->xfer_count > MAX_NBYTE_SIZE) {
|
|
- hi2c->xfer_size = MAX_NBYTE_SIZE;
|
|
- i2c_transfer_config(hi2c, dev_addr, hi2c->xfer_size,
|
|
- I2C_RELOAD_MODE, I2C_GENERATE_START_READ);
|
|
- } else {
|
|
- hi2c->xfer_size = hi2c->xfer_count;
|
|
- i2c_transfer_config(hi2c, dev_addr, hi2c->xfer_size,
|
|
- I2C_AUTOEND_MODE, I2C_GENERATE_START_READ);
|
|
- }
|
|
-
|
|
- do {
|
|
- if (i2c_wait_flag(hi2c, I2C_FLAG_RXNE, 0, timeout,
|
|
- tickstart) != 0) {
|
|
- return -EIO;
|
|
- }
|
|
-
|
|
- *hi2c->p_buff = mmio_read_8(hi2c->i2c_base_addr + I2C_RXDR);
|
|
- hi2c->p_buff++;
|
|
- hi2c->xfer_size--;
|
|
- hi2c->xfer_count--;
|
|
-
|
|
- if ((hi2c->xfer_count != 0U) && (hi2c->xfer_size == 0U)) {
|
|
- if (i2c_wait_flag(hi2c, I2C_FLAG_TCR, 0, timeout,
|
|
- tickstart) != 0) {
|
|
- return -EIO;
|
|
- }
|
|
-
|
|
- if (hi2c->xfer_count > MAX_NBYTE_SIZE) {
|
|
- hi2c->xfer_size = MAX_NBYTE_SIZE;
|
|
- i2c_transfer_config(hi2c, dev_addr,
|
|
- hi2c->xfer_size,
|
|
- I2C_RELOAD_MODE,
|
|
- I2C_NO_STARTSTOP);
|
|
- } else {
|
|
- hi2c->xfer_size = hi2c->xfer_count;
|
|
- i2c_transfer_config(hi2c, dev_addr,
|
|
- hi2c->xfer_size,
|
|
- I2C_AUTOEND_MODE,
|
|
- I2C_NO_STARTSTOP);
|
|
- }
|
|
- }
|
|
- } while (hi2c->xfer_count > 0U);
|
|
-
|
|
- /*
|
|
- * No need to Check TC flag, with AUTOEND mode the stop
|
|
- * is automatically generated
|
|
- * Wait until STOPF flag is reset
|
|
- */
|
|
- if (i2c_wait_stop(hi2c, timeout, tickstart) != 0) {
|
|
- return -EIO;
|
|
- }
|
|
-
|
|
- mmio_write_32(hi2c->i2c_base_addr + I2C_ICR, I2C_FLAG_STOPF);
|
|
-
|
|
- mmio_clrbits_32(hi2c->i2c_base_addr + I2C_CR2, I2C_RESET_CR2);
|
|
-
|
|
- hi2c->i2c_state = I2C_STATE_READY;
|
|
- hi2c->i2c_mode = I2C_MODE_NONE;
|
|
-
|
|
- hi2c->lock = 0;
|
|
-
|
|
- return 0;
|
|
-}
|
|
-
|
|
-/*
|
|
- * @brief Checks if target device is ready for communication.
|
|
- * @note This function is used with Memory devices
|
|
- * @param hi2c: Pointer to a struct i2c_handle_s structure that contains
|
|
- * the configuration information for the specified I2C.
|
|
- * @param dev_addr: Target device address
|
|
- * @param trials: Number of trials
|
|
- * @param timeout: timeout duration
|
|
- * @retval 0 if OK, negative value else
|
|
- */
|
|
-int stm32_i2c_is_device_ready(struct i2c_handle_s *hi2c,
|
|
- uint16_t dev_addr, uint32_t trials,
|
|
- uint32_t timeout)
|
|
-{
|
|
- uint32_t i2c_trials = 0U;
|
|
-
|
|
- if ((hi2c->i2c_state != I2C_STATE_READY) || (hi2c->lock != 0U)) {
|
|
- return -EBUSY;
|
|
- }
|
|
-
|
|
- if ((mmio_read_32(hi2c->i2c_base_addr + I2C_ISR) & I2C_FLAG_BUSY) !=
|
|
- 0U) {
|
|
- return -EBUSY;
|
|
- }
|
|
-
|
|
- hi2c->lock = 1;
|
|
-
|
|
- hi2c->i2c_state = I2C_STATE_BUSY;
|
|
- hi2c->i2c_err = I2C_ERROR_NONE;
|
|
-
|
|
- do {
|
|
- uint32_t tickstart;
|
|
-
|
|
- /* Generate Start */
|
|
- if (hi2c->i2c_init.addressing_mode == I2C_ADDRESSINGMODE_7BIT) {
|
|
- mmio_write_32(hi2c->i2c_base_addr + I2C_CR2,
|
|
- (((uint32_t)dev_addr & I2C_CR2_SADD) |
|
|
- I2C_CR2_START | I2C_CR2_AUTOEND) &
|
|
- ~I2C_CR2_RD_WRN);
|
|
- } else {
|
|
- mmio_write_32(hi2c->i2c_base_addr + I2C_CR2,
|
|
- (((uint32_t)dev_addr & I2C_CR2_SADD) |
|
|
- I2C_CR2_START | I2C_CR2_ADD10) &
|
|
- ~I2C_CR2_RD_WRN);
|
|
- }
|
|
-
|
|
- /*
|
|
- * No need to Check TC flag, with AUTOEND mode the stop
|
|
- * is automatically generated
|
|
- * Wait until STOPF flag is set or a NACK flag is set
|
|
- */
|
|
- tickstart = (uint32_t)read_cntpct_el0();
|
|
- while (((mmio_read_32(hi2c->i2c_base_addr + I2C_ISR) &
|
|
- (I2C_FLAG_STOPF | I2C_FLAG_AF)) == 0U) &&
|
|
- (hi2c->i2c_state != I2C_STATE_TIMEOUT)) {
|
|
- if (timeout != MAX_DELAY) {
|
|
- if ((((uint32_t)read_cntpct_el0() - tickstart) >
|
|
- timeout) || (timeout == 0U)) {
|
|
- hi2c->i2c_state = I2C_STATE_READY;
|
|
-
|
|
- hi2c->i2c_err |=
|
|
- I2C_ERROR_TIMEOUT;
|
|
-
|
|
- hi2c->lock = 0;
|
|
-
|
|
- return -EIO;
|
|
- }
|
|
- }
|
|
- }
|
|
-
|
|
- /* Check if the NACKF flag has not been set */
|
|
- if ((mmio_read_32(hi2c->i2c_base_addr + I2C_ISR) &
|
|
- I2C_FLAG_AF) == 0U) {
|
|
- if (i2c_wait_flag(hi2c, I2C_FLAG_STOPF, 0, timeout,
|
|
- tickstart) != 0) {
|
|
- return -EIO;
|
|
- }
|
|
-
|
|
- mmio_write_32(hi2c->i2c_base_addr + I2C_ICR,
|
|
- I2C_FLAG_STOPF);
|
|
-
|
|
- hi2c->i2c_state = I2C_STATE_READY;
|
|
-
|
|
- hi2c->lock = 0;
|
|
-
|
|
- return 0;
|
|
- }
|
|
-
|
|
- if (i2c_wait_flag(hi2c, I2C_FLAG_STOPF, 0, timeout,
|
|
- tickstart) != 0) {
|
|
- return -EIO;
|
|
- }
|
|
-
|
|
- mmio_write_32(hi2c->i2c_base_addr + I2C_ICR, I2C_FLAG_AF);
|
|
-
|
|
- mmio_write_32(hi2c->i2c_base_addr + I2C_ICR, I2C_FLAG_STOPF);
|
|
-
|
|
- if (i2c_trials == trials) {
|
|
- mmio_setbits_32(hi2c->i2c_base_addr + I2C_CR2,
|
|
- I2C_CR2_STOP);
|
|
-
|
|
- if (i2c_wait_flag(hi2c, I2C_FLAG_STOPF, 0, timeout,
|
|
- tickstart) != 0) {
|
|
- return -EIO;
|
|
- }
|
|
-
|
|
- mmio_write_32(hi2c->i2c_base_addr + I2C_ICR,
|
|
- I2C_FLAG_STOPF);
|
|
- }
|
|
-
|
|
- i2c_trials++;
|
|
- } while (i2c_trials < trials);
|
|
-
|
|
- hi2c->i2c_state = I2C_STATE_READY;
|
|
-
|
|
- hi2c->i2c_err |= I2C_ERROR_TIMEOUT;
|
|
-
|
|
- hi2c->lock = 0;
|
|
-
|
|
- return -EIO;
|
|
-}
|
|
-
|
|
-/*
|
|
- * @brief Master sends target device address followed by internal memory
|
|
- * address for write request.
|
|
- * @param hi2c: Pointer to a struct i2c_handle_s structure that contains
|
|
- * the configuration information for the specified I2C.
|
|
- * @param dev_addr: Target device address
|
|
- * @param mem_addr: Internal memory address
|
|
- * @param mem_add_size: size of internal memory address
|
|
- * @param timeout: timeout duration
|
|
- * @param tick_start Tick start value
|
|
- * @retval 0 if OK, negative value else
|
|
- */
|
|
-static int i2c_request_memory_write(struct i2c_handle_s *hi2c,
|
|
- uint16_t dev_addr, uint16_t mem_addr,
|
|
- uint16_t mem_add_size, uint32_t timeout,
|
|
- uint32_t tick_start)
|
|
-{
|
|
- i2c_transfer_config(hi2c, dev_addr, mem_add_size, I2C_RELOAD_MODE,
|
|
- I2C_GENERATE_START_WRITE);
|
|
-
|
|
- if (i2c_wait_txis(hi2c, timeout, tick_start) != 0) {
|
|
- return -EIO;
|
|
- }
|
|
-
|
|
- if (mem_add_size == I2C_MEMADD_SIZE_8BIT) {
|
|
- /* Send Memory Address */
|
|
- mmio_write_8(hi2c->i2c_base_addr + I2C_TXDR,
|
|
- (uint8_t)(mem_addr & 0x00FFU));
|
|
- } else {
|
|
- /* Send MSB of Memory Address */
|
|
- mmio_write_8(hi2c->i2c_base_addr + I2C_TXDR,
|
|
- (uint8_t)((mem_addr & 0xFF00U) >> 8));
|
|
-
|
|
- /* Wait until TXIS flag is set */
|
|
- if (i2c_wait_txis(hi2c, timeout, tick_start) != 0) {
|
|
- return -EIO;
|
|
- }
|
|
-
|
|
- /* Send LSB of Memory Address */
|
|
- mmio_write_8(hi2c->i2c_base_addr + I2C_TXDR,
|
|
- (uint8_t)(mem_addr & 0x00FFU));
|
|
- }
|
|
-
|
|
- if (i2c_wait_flag(hi2c, I2C_FLAG_TCR, 0, timeout, tick_start) !=
|
|
- 0) {
|
|
- return -EIO;
|
|
- }
|
|
-
|
|
- return 0;
|
|
-}
|
|
-
|
|
-/*
|
|
- * @brief Master sends target device address followed by internal memory
|
|
- * address for read request.
|
|
- * @param hi2c: Pointer to a struct i2c_handle_s structure that contains
|
|
- * the configuration information for the specified I2C.
|
|
- * @param dev_addr: Target device address
|
|
- * @param mem_addr: Internal memory address
|
|
- * @param mem_add_size: size of internal memory address
|
|
- * @param timeout: timeout duration
|
|
- * @param tick_start Tick start value
|
|
- * @retval 0 if OK, negative value else
|
|
- */
|
|
-static int i2c_request_memory_read(struct i2c_handle_s *hi2c, uint16_t dev_addr,
|
|
- uint16_t mem_addr, uint16_t mem_add_size,
|
|
- uint32_t timeout, uint32_t tick_start)
|
|
-{
|
|
- i2c_transfer_config(hi2c, dev_addr, mem_add_size, I2C_SOFTEND_MODE,
|
|
- I2C_GENERATE_START_WRITE);
|
|
-
|
|
- if (i2c_wait_txis(hi2c, timeout, tick_start) != 0) {
|
|
- return -EIO;
|
|
- }
|
|
-
|
|
- if (mem_add_size == I2C_MEMADD_SIZE_8BIT) {
|
|
- /* Send Memory Address */
|
|
- mmio_write_8(hi2c->i2c_base_addr + I2C_TXDR,
|
|
- (uint8_t)(mem_addr & 0x00FFU));
|
|
- } else {
|
|
- /* Send MSB of Memory Address */
|
|
- mmio_write_8(hi2c->i2c_base_addr + I2C_TXDR,
|
|
- (uint8_t)((mem_addr & 0xFF00U) >> 8));
|
|
-
|
|
- /* Wait until TXIS flag is set */
|
|
- if (i2c_wait_txis(hi2c, timeout, tick_start) != 0) {
|
|
- return -EIO;
|
|
- }
|
|
-
|
|
- /* Send LSB of Memory Address */
|
|
- mmio_write_8(hi2c->i2c_base_addr + I2C_TXDR,
|
|
- (uint8_t)(mem_addr & 0x00FFU));
|
|
- }
|
|
-
|
|
- if (i2c_wait_flag(hi2c, I2C_FLAG_TC, 0, timeout, tick_start) != 0) {
|
|
- return -EIO;
|
|
- }
|
|
-
|
|
- return 0;
|
|
-}
|
|
-
|
|
-/*
|
|
- * @brief I2C Tx data register flush process.
|
|
- * @param hi2c: I2C handle.
|
|
- * @retval None
|
|
- */
|
|
-static void i2c_flush_txdr(struct i2c_handle_s *hi2c)
|
|
-{
|
|
- /*
|
|
- * If a pending TXIS flag is set,
|
|
- * write a dummy data in TXDR to clear it.
|
|
- */
|
|
- if ((mmio_read_32(hi2c->i2c_base_addr + I2C_ISR) & I2C_FLAG_TXIS) !=
|
|
- 0U) {
|
|
- mmio_write_32(hi2c->i2c_base_addr + I2C_TXDR, 0);
|
|
- }
|
|
-
|
|
- /* Flush TX register if not empty */
|
|
- if ((mmio_read_32(hi2c->i2c_base_addr + I2C_ISR) & I2C_FLAG_TXE) ==
|
|
- 0U) {
|
|
- mmio_setbits_32(hi2c->i2c_base_addr + I2C_ISR,
|
|
- I2C_FLAG_TXE);
|
|
- }
|
|
-}
|
|
-
|
|
-/*
|
|
- * @brief This function handles I2C Communication timeout.
|
|
- * @param hi2c: Pointer to a struct i2c_handle_s structure that contains
|
|
- * the configuration information for the specified I2C.
|
|
- * @param flag: Specifies the I2C flag to check.
|
|
- * @param awaited_value: The awaited bit value for the flag (0 or 1).
|
|
- * @param timeout: timeout duration
|
|
- * @param tick_start: Tick start value
|
|
- * @retval 0 if OK, negative value else
|
|
- */
|
|
-static int i2c_wait_flag(struct i2c_handle_s *hi2c, uint32_t flag,
|
|
- uint8_t awaited_value, uint32_t timeout,
|
|
- uint32_t tick_start)
|
|
-{
|
|
- uint8_t flag_check;
|
|
-
|
|
- do {
|
|
- flag_check = ((mmio_read_32(hi2c->i2c_base_addr + I2C_ISR) &
|
|
- flag) == flag) ? 1U : 0U;
|
|
-
|
|
- if (timeout != MAX_DELAY) {
|
|
- if ((((uint32_t)read_cntpct_el0() - tick_start) >
|
|
- timeout) || (timeout == 0U)) {
|
|
- hi2c->i2c_err |= I2C_ERROR_TIMEOUT;
|
|
- hi2c->i2c_state = I2C_STATE_READY;
|
|
- hi2c->i2c_mode = I2C_MODE_NONE;
|
|
-
|
|
- hi2c->lock = 0;
|
|
- return -EIO;
|
|
- }
|
|
- }
|
|
- } while (flag_check == awaited_value);
|
|
-
|
|
- return 0;
|
|
-}
|
|
-
|
|
-/*
|
|
- * @brief This function handles I2C Communication timeout for specific usage
|
|
- * of TXIS flag.
|
|
- * @param hi2c: Pointer to a struct i2c_handle_s structure that contains
|
|
- * the configuration information for the specified I2C.
|
|
- * @param timeout: timeout duration
|
|
- * @param tick_start: Tick start value
|
|
- * @retval 0 if OK, negative value else
|
|
- */
|
|
-static int i2c_wait_txis(struct i2c_handle_s *hi2c, uint32_t timeout,
|
|
- uint32_t tick_start)
|
|
-{
|
|
- while ((mmio_read_32(hi2c->i2c_base_addr + I2C_ISR) &
|
|
- I2C_FLAG_TXIS) == 0U) {
|
|
- if (i2c_ack_failed(hi2c, timeout, tick_start) != 0) {
|
|
- return -EIO;
|
|
- }
|
|
-
|
|
- if (timeout != MAX_DELAY) {
|
|
- if ((((uint32_t)read_cntpct_el0() - tick_start) >
|
|
- timeout) || (timeout == 0U)) {
|
|
- hi2c->i2c_err |= I2C_ERROR_TIMEOUT;
|
|
- hi2c->i2c_state = I2C_STATE_READY;
|
|
- hi2c->i2c_mode = I2C_MODE_NONE;
|
|
-
|
|
- hi2c->lock = 0;
|
|
-
|
|
- return -EIO;
|
|
- }
|
|
- }
|
|
- }
|
|
-
|
|
- return 0;
|
|
-}
|
|
-
|
|
-/*
|
|
- * @brief This function handles I2C Communication timeout for specific
|
|
- * usage of STOP flag.
|
|
- * @param hi2c: Pointer to a struct i2c_handle_s structure that contains
|
|
- * the configuration information for the specified I2C.
|
|
- * @param timeout: timeout duration
|
|
- * @param tick_start: Tick start value
|
|
- * @retval 0 if OK, negative value else
|
|
- */
|
|
-static int i2c_wait_stop(struct i2c_handle_s *hi2c, uint32_t timeout,
|
|
- uint32_t tick_start)
|
|
-{
|
|
- while ((mmio_read_32(hi2c->i2c_base_addr + I2C_ISR) &
|
|
- I2C_FLAG_STOPF) == 0U) {
|
|
- if (i2c_ack_failed(hi2c, timeout, tick_start) != 0) {
|
|
- return -EIO;
|
|
- }
|
|
-
|
|
- if ((((uint32_t)read_cntpct_el0() - tick_start) > timeout) ||
|
|
- (timeout == 0U)) {
|
|
- hi2c->i2c_err |= I2C_ERROR_TIMEOUT;
|
|
- hi2c->i2c_state = I2C_STATE_READY;
|
|
- hi2c->i2c_mode = I2C_MODE_NONE;
|
|
-
|
|
- hi2c->lock = 0;
|
|
-
|
|
- return -EIO;
|
|
- }
|
|
- }
|
|
-
|
|
- return 0;
|
|
-}
|
|
-
|
|
-/*
|
|
- * @brief This function handles Acknowledge failed detection during
|
|
- * an I2C Communication.
|
|
- * @param hi2c: Pointer to a struct i2c_handle_s structure that contains
|
|
- * the configuration information for the specified I2C.
|
|
- * @param timeout: timeout duration
|
|
- * @param tick_start: Tick start value
|
|
- * @retval 0 if OK, negative value else
|
|
- */
|
|
-static int i2c_ack_failed(struct i2c_handle_s *hi2c, uint32_t timeout,
|
|
- uint32_t tick_start)
|
|
-{
|
|
- if ((mmio_read_32(hi2c->i2c_base_addr + I2C_ISR) & I2C_FLAG_AF) == 0U) {
|
|
- return 0;
|
|
- }
|
|
-
|
|
- /*
|
|
- * Wait until STOP Flag is reset.
|
|
- * AutoEnd should be initiate after AF.
|
|
- */
|
|
- while ((mmio_read_32(hi2c->i2c_base_addr + I2C_ISR) &
|
|
- I2C_FLAG_STOPF) == 0U) {
|
|
- if (timeout != MAX_DELAY) {
|
|
- if ((((uint32_t)read_cntpct_el0() - tick_start) >
|
|
- timeout) || (timeout == 0U)) {
|
|
- hi2c->i2c_err |= I2C_ERROR_TIMEOUT;
|
|
- hi2c->i2c_state = I2C_STATE_READY;
|
|
- hi2c->i2c_mode = I2C_MODE_NONE;
|
|
-
|
|
- hi2c->lock = 0;
|
|
-
|
|
- return -EIO;
|
|
- }
|
|
- }
|
|
- }
|
|
-
|
|
- mmio_write_32(hi2c->i2c_base_addr + I2C_ICR, I2C_FLAG_AF);
|
|
-
|
|
- mmio_write_32(hi2c->i2c_base_addr + I2C_ICR, I2C_FLAG_STOPF);
|
|
-
|
|
- i2c_flush_txdr(hi2c);
|
|
-
|
|
- mmio_clrbits_32(hi2c->i2c_base_addr + I2C_CR2, I2C_RESET_CR2);
|
|
-
|
|
- hi2c->i2c_err |= I2C_ERROR_AF;
|
|
- hi2c->i2c_state = I2C_STATE_READY;
|
|
- hi2c->i2c_mode = I2C_MODE_NONE;
|
|
-
|
|
- hi2c->lock = 0;
|
|
-
|
|
- return -EIO;
|
|
-}
|
|
-
|
|
-/*
|
|
- * @brief Handles I2Cx communication when starting transfer or during transfer
|
|
- * (TC or TCR flag are set).
|
|
- * @param hi2c: I2C handle.
|
|
- * @param dev_addr: Specifies the slave address to be programmed.
|
|
- * @param size: Specifies the number of bytes to be programmed.
|
|
- * This parameter must be a value between 0 and 255.
|
|
- * @param i2c_mode: New state of the I2C START condition generation.
|
|
- * This parameter can be one of the following values:
|
|
- * @arg @ref I2C_RELOAD_MODE: Enable Reload mode .
|
|
- * @arg @ref I2C_AUTOEND_MODE: Enable Automatic end mode.
|
|
- * @arg @ref I2C_SOFTEND_MODE: Enable Software end mode.
|
|
- * @param request: New state of the I2C START condition generation.
|
|
- * This parameter can be one of the following values:
|
|
- * @arg @ref I2C_NO_STARTSTOP: Don't Generate stop and start condition.
|
|
- * @arg @ref I2C_GENERATE_STOP: Generate stop condition
|
|
- * (size should be set to 0).
|
|
- * @arg @ref I2C_GENERATE_START_READ: Generate Restart for read request.
|
|
- * @arg @ref I2C_GENERATE_START_WRITE: Generate Restart for write request.
|
|
- * @retval None
|
|
- */
|
|
-static void i2c_transfer_config(struct i2c_handle_s *hi2c, uint16_t dev_addr,
|
|
- uint16_t size, uint32_t i2c_mode,
|
|
- uint32_t request)
|
|
-{
|
|
- uint32_t clr_value, set_value;
|
|
-
|
|
- clr_value = (I2C_CR2_SADD | I2C_CR2_NBYTES | I2C_CR2_RELOAD |
|
|
- I2C_CR2_AUTOEND | I2C_CR2_START | I2C_CR2_STOP) |
|
|
- (I2C_CR2_RD_WRN & (request >> (31U - I2C_CR2_RD_WRN_OFFSET)));
|
|
-
|
|
- set_value = ((uint32_t)dev_addr & I2C_CR2_SADD) |
|
|
- (((uint32_t)size << I2C_CR2_NBYTES_OFFSET) & I2C_CR2_NBYTES) |
|
|
- i2c_mode | request;
|
|
-
|
|
- mmio_clrsetbits_32(hi2c->i2c_base_addr + I2C_CR2, clr_value, set_value);
|
|
-}
|
|
-
|
|
-/*
|
|
- * @brief Configure I2C Analog noise filter.
|
|
- * @param hi2c: Pointer to a struct i2c_handle_s structure that contains
|
|
- * the configuration information for the specified I2Cx peripheral
|
|
- * @param analog_filter: New state of the Analog filter.
|
|
- * @retval 0 if OK, negative value else
|
|
- */
|
|
-int stm32_i2c_config_analog_filter(struct i2c_handle_s *hi2c,
|
|
- uint32_t analog_filter)
|
|
-{
|
|
- if ((hi2c->i2c_state != I2C_STATE_READY) || (hi2c->lock != 0U)) {
|
|
- return -EBUSY;
|
|
- }
|
|
-
|
|
- hi2c->lock = 1;
|
|
-
|
|
- hi2c->i2c_state = I2C_STATE_BUSY;
|
|
-
|
|
- /* Disable the selected I2C peripheral */
|
|
- mmio_clrbits_32(hi2c->i2c_base_addr + I2C_CR1, I2C_CR1_PE);
|
|
-
|
|
- /* Reset I2Cx ANOFF bit */
|
|
- mmio_clrbits_32(hi2c->i2c_base_addr + I2C_CR1, I2C_CR1_ANFOFF);
|
|
-
|
|
- /* Set analog filter bit*/
|
|
- mmio_setbits_32(hi2c->i2c_base_addr + I2C_CR1, analog_filter);
|
|
-
|
|
- /* Enable the selected I2C peripheral */
|
|
- mmio_setbits_32(hi2c->i2c_base_addr + I2C_CR1, I2C_CR1_PE);
|
|
-
|
|
- hi2c->i2c_state = I2C_STATE_READY;
|
|
-
|
|
- hi2c->lock = 0;
|
|
-
|
|
- return 0;
|
|
-}
|
|
diff --git a/drivers/st/pmic/stm32mp1_pmic.c b/drivers/st/pmic/stm32mp1_pmic.c
|
|
deleted file mode 100644
|
|
index 958de08..0000000
|
|
--- a/drivers/st/pmic/stm32mp1_pmic.c
|
|
+++ /dev/null
|
|
@@ -1,346 +0,0 @@
|
|
-/*
|
|
- * Copyright (c) 2017-2018, STMicroelectronics - All Rights Reserved
|
|
- *
|
|
- * SPDX-License-Identifier: BSD-3-Clause
|
|
- */
|
|
-
|
|
-#include <debug.h>
|
|
-#include <delay_timer.h>
|
|
-#include <errno.h>
|
|
-#include <libfdt.h>
|
|
-#include <mmio.h>
|
|
-#include <mmio.h>
|
|
-#include <platform_def.h>
|
|
-#include <stdbool.h>
|
|
-#include <stm32_gpio.h>
|
|
-#include <stm32mp1_clk.h>
|
|
-#include <stm32mp1_dt.h>
|
|
-#include <stm32mp1_pmic.h>
|
|
-#include <stpmu1.h>
|
|
-#include <utils_def.h>
|
|
-
|
|
-/* I2C Timing hard-coded value, for I2C clock source is HSI at 64MHz */
|
|
-#define I2C_TIMING 0x10D07DB5
|
|
-
|
|
-#define I2C_TIMEOUT 0xFFFFF
|
|
-
|
|
-#define MASK_RESET_BUCK3 BIT(2)
|
|
-
|
|
-#define STPMU1_LDO12356_OUTPUT_MASK (uint8_t)(GENMASK(6, 2))
|
|
-#define STPMU1_LDO12356_OUTPUT_SHIFT 2
|
|
-#define STPMU1_LDO3_MODE (uint8_t)(BIT(7))
|
|
-#define STPMU1_LDO3_DDR_SEL 31U
|
|
-#define STPMU1_LDO3_1800000 (9U << STPMU1_LDO12356_OUTPUT_SHIFT)
|
|
-
|
|
-#define STPMU1_BUCK_OUTPUT_SHIFT 2
|
|
-#define STPMU1_BUCK3_1V8 (39U << STPMU1_BUCK_OUTPUT_SHIFT)
|
|
-
|
|
-#define STPMU1_DEFAULT_START_UP_DELAY_MS 1
|
|
-
|
|
-static struct i2c_handle_s i2c_handle;
|
|
-static uint32_t pmic_i2c_addr;
|
|
-
|
|
-static int dt_get_pmic_node(void *fdt)
|
|
-{
|
|
- return fdt_node_offset_by_compatible(fdt, -1, "st,stpmu1");
|
|
-}
|
|
-
|
|
-bool dt_check_pmic(void)
|
|
-{
|
|
- int node;
|
|
- void *fdt;
|
|
-
|
|
- if (fdt_get_address(&fdt) == 0) {
|
|
- return false;
|
|
- }
|
|
-
|
|
- node = dt_get_pmic_node(fdt);
|
|
- if (node < 0) {
|
|
- VERBOSE("%s: No PMIC node found in DT\n", __func__);
|
|
- return false;
|
|
- }
|
|
-
|
|
- return fdt_check_status(node);
|
|
-}
|
|
-
|
|
-static int dt_pmic_i2c_config(struct dt_node_info *i2c_info)
|
|
-{
|
|
- int pmic_node, i2c_node;
|
|
- void *fdt;
|
|
- const fdt32_t *cuint;
|
|
-
|
|
- if (fdt_get_address(&fdt) == 0) {
|
|
- return -ENOENT;
|
|
- }
|
|
-
|
|
- pmic_node = dt_get_pmic_node(fdt);
|
|
- if (pmic_node < 0) {
|
|
- return -FDT_ERR_NOTFOUND;
|
|
- }
|
|
-
|
|
- cuint = fdt_getprop(fdt, pmic_node, "reg", NULL);
|
|
- if (cuint == NULL) {
|
|
- return -FDT_ERR_NOTFOUND;
|
|
- }
|
|
-
|
|
- pmic_i2c_addr = fdt32_to_cpu(*cuint) << 1;
|
|
- if (pmic_i2c_addr > UINT16_MAX) {
|
|
- return -EINVAL;
|
|
- }
|
|
-
|
|
- i2c_node = fdt_parent_offset(fdt, pmic_node);
|
|
- if (i2c_node < 0) {
|
|
- return -FDT_ERR_NOTFOUND;
|
|
- }
|
|
-
|
|
- dt_fill_device_info(i2c_info, i2c_node);
|
|
- if (i2c_info->base == 0U) {
|
|
- return -FDT_ERR_NOTFOUND;
|
|
- }
|
|
-
|
|
- return dt_set_pinctrl_config(i2c_node);
|
|
-}
|
|
-
|
|
-int dt_pmic_enable_boot_on_regulators(void)
|
|
-{
|
|
- int pmic_node, regulators_node, regulator_node;
|
|
- void *fdt;
|
|
-
|
|
- if (fdt_get_address(&fdt) == 0) {
|
|
- return -ENOENT;
|
|
- }
|
|
-
|
|
- pmic_node = dt_get_pmic_node(fdt);
|
|
- if (pmic_node < 0) {
|
|
- return -FDT_ERR_NOTFOUND;
|
|
- }
|
|
-
|
|
- regulators_node = fdt_subnode_offset(fdt, pmic_node, "regulators");
|
|
-
|
|
- fdt_for_each_subnode(regulator_node, fdt, regulators_node) {
|
|
- const fdt32_t *cuint;
|
|
- const char *node_name;
|
|
- uint16_t voltage;
|
|
-
|
|
- if (fdt_getprop(fdt, regulator_node, "regulator-boot-on",
|
|
- NULL) == NULL) {
|
|
- continue;
|
|
- }
|
|
-
|
|
- cuint = fdt_getprop(fdt, regulator_node,
|
|
- "regulator-min-microvolt", NULL);
|
|
- if (cuint == NULL) {
|
|
- continue;
|
|
- }
|
|
-
|
|
- /* DT uses microvolts, whereas driver awaits millivolts */
|
|
- voltage = (uint16_t)(fdt32_to_cpu(*cuint) / 1000U);
|
|
- node_name = fdt_get_name(fdt, regulator_node, NULL);
|
|
-
|
|
- if (stpmu1_is_regulator_enabled(node_name) == 0U) {
|
|
- int status;
|
|
-
|
|
- status = stpmu1_regulator_voltage_set(node_name,
|
|
- voltage);
|
|
- if (status != 0) {
|
|
- return status;
|
|
- }
|
|
-
|
|
- status = stpmu1_regulator_enable(node_name);
|
|
- if (status != 0) {
|
|
- return status;
|
|
- }
|
|
- }
|
|
- }
|
|
-
|
|
- return 0;
|
|
-}
|
|
-
|
|
-void initialize_pmic_i2c(void)
|
|
-{
|
|
- int ret;
|
|
- struct dt_node_info i2c_info;
|
|
-
|
|
- if (dt_pmic_i2c_config(&i2c_info) != 0) {
|
|
- ERROR("I2C configuration failed\n");
|
|
- panic();
|
|
- }
|
|
-
|
|
- if (stm32mp1_clk_enable((uint32_t)i2c_info.clock) < 0) {
|
|
- ERROR("I2C clock enable failed\n");
|
|
- panic();
|
|
- }
|
|
-
|
|
- /* Initialize PMIC I2C */
|
|
- i2c_handle.i2c_base_addr = i2c_info.base;
|
|
- i2c_handle.i2c_init.timing = I2C_TIMING;
|
|
- i2c_handle.i2c_init.own_address1 = pmic_i2c_addr;
|
|
- i2c_handle.i2c_init.addressing_mode = I2C_ADDRESSINGMODE_7BIT;
|
|
- i2c_handle.i2c_init.dual_address_mode = I2C_DUALADDRESS_DISABLE;
|
|
- i2c_handle.i2c_init.own_address2 = 0;
|
|
- i2c_handle.i2c_init.own_address2_masks = I2C_OAR2_OA2NOMASK;
|
|
- i2c_handle.i2c_init.general_call_mode = I2C_GENERALCALL_DISABLE;
|
|
- i2c_handle.i2c_init.no_stretch_mode = I2C_NOSTRETCH_DISABLE;
|
|
-
|
|
- ret = stm32_i2c_init(&i2c_handle);
|
|
- if (ret != 0) {
|
|
- ERROR("Cannot initialize I2C %x (%d)\n",
|
|
- i2c_handle.i2c_base_addr, ret);
|
|
- panic();
|
|
- }
|
|
-
|
|
- ret = stm32_i2c_config_analog_filter(&i2c_handle,
|
|
- I2C_ANALOGFILTER_ENABLE);
|
|
- if (ret != 0) {
|
|
- ERROR("Cannot initialize I2C analog filter (%d)\n", ret);
|
|
- panic();
|
|
- }
|
|
-
|
|
- ret = stm32_i2c_is_device_ready(&i2c_handle, (uint16_t)pmic_i2c_addr, 1,
|
|
- I2C_TIMEOUT);
|
|
- if (ret != 0) {
|
|
- ERROR("I2C device not ready (%d)\n", ret);
|
|
- panic();
|
|
- }
|
|
-
|
|
- stpmu1_bind_i2c(&i2c_handle, (uint16_t)pmic_i2c_addr);
|
|
-}
|
|
-
|
|
-void initialize_pmic(void)
|
|
-{
|
|
- int status;
|
|
- uint8_t read_val;
|
|
-
|
|
- initialize_pmic_i2c();
|
|
-
|
|
- status = stpmu1_register_read(VERSION_STATUS_REG, &read_val);
|
|
- if (status != 0) {
|
|
- panic();
|
|
- }
|
|
-
|
|
- INFO("PMIC version = 0x%x\n", read_val);
|
|
-
|
|
- /* Keep VDD on during the reset cycle */
|
|
- status = stpmu1_register_update(MASK_RESET_BUCK_REG,
|
|
- MASK_RESET_BUCK3,
|
|
- MASK_RESET_BUCK3);
|
|
- if (status != 0) {
|
|
- panic();
|
|
- }
|
|
-}
|
|
-
|
|
-int pmic_ddr_power_init(enum ddr_type ddr_type)
|
|
-{
|
|
- bool buck3_at_1v8 = false;
|
|
- uint8_t read_val;
|
|
- int status;
|
|
-
|
|
- switch (ddr_type) {
|
|
- case STM32MP_DDR3:
|
|
- /* Set LDO3 to sync mode */
|
|
- status = stpmu1_register_read(LDO3_CONTROL_REG, &read_val);
|
|
- if (status != 0) {
|
|
- return status;
|
|
- }
|
|
-
|
|
- read_val &= ~STPMU1_LDO3_MODE;
|
|
- read_val &= ~STPMU1_LDO12356_OUTPUT_MASK;
|
|
- read_val |= STPMU1_LDO3_DDR_SEL << STPMU1_LDO12356_OUTPUT_SHIFT;
|
|
-
|
|
- status = stpmu1_register_write(LDO3_CONTROL_REG, read_val);
|
|
- if (status != 0) {
|
|
- return status;
|
|
- }
|
|
-
|
|
- status = stpmu1_regulator_voltage_set("buck2", 1350);
|
|
- if (status != 0) {
|
|
- return status;
|
|
- }
|
|
-
|
|
- status = stpmu1_regulator_enable("buck2");
|
|
- if (status != 0) {
|
|
- return status;
|
|
- }
|
|
-
|
|
- mdelay(STPMU1_DEFAULT_START_UP_DELAY_MS);
|
|
-
|
|
- status = stpmu1_regulator_enable("vref_ddr");
|
|
- if (status != 0) {
|
|
- return status;
|
|
- }
|
|
-
|
|
- mdelay(STPMU1_DEFAULT_START_UP_DELAY_MS);
|
|
-
|
|
- status = stpmu1_regulator_enable("ldo3");
|
|
- if (status != 0) {
|
|
- return status;
|
|
- }
|
|
-
|
|
- mdelay(STPMU1_DEFAULT_START_UP_DELAY_MS);
|
|
- break;
|
|
-
|
|
- case STM32MP_LPDDR2:
|
|
- /*
|
|
- * Set LDO3 to 1.8V
|
|
- * Set LDO3 to bypass mode if BUCK3 = 1.8V
|
|
- * Set LDO3 to normal mode if BUCK3 != 1.8V
|
|
- */
|
|
- status = stpmu1_register_read(BUCK3_CONTROL_REG, &read_val);
|
|
- if (status != 0) {
|
|
- return status;
|
|
- }
|
|
-
|
|
- if ((read_val & STPMU1_BUCK3_1V8) == STPMU1_BUCK3_1V8) {
|
|
- buck3_at_1v8 = true;
|
|
- }
|
|
-
|
|
- status = stpmu1_register_read(LDO3_CONTROL_REG, &read_val);
|
|
- if (status != 0) {
|
|
- return status;
|
|
- }
|
|
-
|
|
- read_val &= ~STPMU1_LDO3_MODE;
|
|
- read_val &= ~STPMU1_LDO12356_OUTPUT_MASK;
|
|
- read_val |= STPMU1_LDO3_1800000;
|
|
- if (buck3_at_1v8) {
|
|
- read_val |= STPMU1_LDO3_MODE;
|
|
- }
|
|
-
|
|
- status = stpmu1_register_write(LDO3_CONTROL_REG, read_val);
|
|
- if (status != 0) {
|
|
- return status;
|
|
- }
|
|
-
|
|
- status = stpmu1_regulator_voltage_set("buck2", 1200);
|
|
- if (status != 0) {
|
|
- return status;
|
|
- }
|
|
-
|
|
- status = stpmu1_regulator_enable("ldo3");
|
|
- if (status != 0) {
|
|
- return status;
|
|
- }
|
|
-
|
|
- mdelay(STPMU1_DEFAULT_START_UP_DELAY_MS);
|
|
-
|
|
- status = stpmu1_regulator_enable("buck2");
|
|
- if (status != 0) {
|
|
- return status;
|
|
- }
|
|
-
|
|
- mdelay(STPMU1_DEFAULT_START_UP_DELAY_MS);
|
|
-
|
|
- status = stpmu1_regulator_enable("vref_ddr");
|
|
- if (status != 0) {
|
|
- return status;
|
|
- }
|
|
-
|
|
- mdelay(STPMU1_DEFAULT_START_UP_DELAY_MS);
|
|
- break;
|
|
-
|
|
- default:
|
|
- break;
|
|
- };
|
|
-
|
|
- return 0;
|
|
-}
|
|
diff --git a/drivers/st/pmic/stm32mp_pmic.c b/drivers/st/pmic/stm32mp_pmic.c
|
|
new file mode 100644
|
|
index 0000000..c8d70db
|
|
--- /dev/null
|
|
+++ b/drivers/st/pmic/stm32mp_pmic.c
|
|
@@ -0,0 +1,522 @@
|
|
+/*
|
|
+ * Copyright (c) 2017-2018, STMicroelectronics - All Rights Reserved
|
|
+ *
|
|
+ * SPDX-License-Identifier: BSD-3-Clause
|
|
+ */
|
|
+
|
|
+#include <debug.h>
|
|
+#include <delay_timer.h>
|
|
+#include <errno.h>
|
|
+#include <mmio.h>
|
|
+#include <platform_def.h>
|
|
+#include <stm32_i2c.h>
|
|
+#include <stm32mp_dt.h>
|
|
+#include <stm32mp_pmic.h>
|
|
+#include <stpmic1.h>
|
|
+#include <utils_def.h>
|
|
+
|
|
+#define STPMIC1_LDO12356_OUTPUT_MASK (uint8_t)(GENMASK(6, 2))
|
|
+#define STPMIC1_LDO12356_OUTPUT_SHIFT 2
|
|
+#define STPMIC1_LDO3_MODE (uint8_t)(BIT(7))
|
|
+#define STPMIC1_LDO3_DDR_SEL 31U
|
|
+#define STPMIC1_LDO3_1800000 (9U << STPMIC1_LDO12356_OUTPUT_SHIFT)
|
|
+
|
|
+#define STPMIC1_BUCK_OUTPUT_SHIFT 2
|
|
+#define STPMIC1_BUCK3_1V8 (39U << STPMIC1_BUCK_OUTPUT_SHIFT)
|
|
+
|
|
+#define REGULATOR_MODE_STANDBY 8U
|
|
+
|
|
+#define STPMIC1_DEFAULT_START_UP_DELAY_MS 1
|
|
+
|
|
+static struct i2c_handle_s i2c_handle;
|
|
+static uint32_t pmic_i2c_addr;
|
|
+
|
|
+static int dt_get_pmic_node(void *fdt)
|
|
+{
|
|
+ return fdt_node_offset_by_compatible(fdt, -1, "st,stpmic1");
|
|
+}
|
|
+
|
|
+int dt_pmic_status(void)
|
|
+{
|
|
+ int node;
|
|
+ void *fdt;
|
|
+
|
|
+ if (fdt_get_address(&fdt) == 0) {
|
|
+ return -ENOENT;
|
|
+ }
|
|
+
|
|
+ node = dt_get_pmic_node(fdt);
|
|
+ if (node <= 0) {
|
|
+ return -FDT_ERR_NOTFOUND;
|
|
+ }
|
|
+
|
|
+ return fdt_get_status(node);
|
|
+}
|
|
+
|
|
+static bool dt_pmic_is_secure(void)
|
|
+{
|
|
+ int status = dt_pmic_status();
|
|
+
|
|
+ return (status >= 0) &&
|
|
+ (status == DT_SECURE) &&
|
|
+ (i2c_handle.dt_status == DT_SECURE);
|
|
+}
|
|
+
|
|
+/*
|
|
+ * Get PMIC and its I2C bus configuration from the device tree.
|
|
+ * Return 0 on success, negative on error, 1 if no PMIC node is defined.
|
|
+ */
|
|
+static int dt_pmic_i2c_config(struct dt_node_info *i2c_info,
|
|
+ struct stm32_i2c_init_s *init)
|
|
+{
|
|
+ int pmic_node, i2c_node;
|
|
+ void *fdt;
|
|
+ const fdt32_t *cuint;
|
|
+
|
|
+ if (fdt_get_address(&fdt) == 0) {
|
|
+ return -ENOENT;
|
|
+ }
|
|
+
|
|
+ pmic_node = dt_get_pmic_node(fdt);
|
|
+ if (pmic_node < 0) {
|
|
+ return 1;
|
|
+ }
|
|
+
|
|
+ cuint = fdt_getprop(fdt, pmic_node, "reg", NULL);
|
|
+ if (cuint == NULL) {
|
|
+ return -FDT_ERR_NOTFOUND;
|
|
+ }
|
|
+
|
|
+ pmic_i2c_addr = fdt32_to_cpu(*cuint) << 1;
|
|
+ if (pmic_i2c_addr > UINT16_MAX) {
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ i2c_node = fdt_parent_offset(fdt, pmic_node);
|
|
+ if (i2c_node < 0) {
|
|
+ return -FDT_ERR_NOTFOUND;
|
|
+ }
|
|
+
|
|
+ dt_fill_device_info(i2c_info, i2c_node);
|
|
+ if (i2c_info->base == 0U) {
|
|
+ return -FDT_ERR_NOTFOUND;
|
|
+ }
|
|
+
|
|
+ return stm32_i2c_get_setup_from_fdt(fdt, i2c_node, init);
|
|
+}
|
|
+
|
|
+int dt_pmic_configure_boot_on_regulators(void)
|
|
+{
|
|
+ int pmic_node, regulators_node, regulator_node;
|
|
+ void *fdt;
|
|
+
|
|
+ if (fdt_get_address(&fdt) == 0) {
|
|
+ return -ENOENT;
|
|
+ }
|
|
+
|
|
+ pmic_node = dt_get_pmic_node(fdt);
|
|
+ if (pmic_node < 0) {
|
|
+ return -FDT_ERR_NOTFOUND;
|
|
+ }
|
|
+
|
|
+ regulators_node = fdt_subnode_offset(fdt, pmic_node, "regulators");
|
|
+
|
|
+ fdt_for_each_subnode(regulator_node, fdt, regulators_node) {
|
|
+ const fdt32_t *cuint;
|
|
+ const char *node_name = fdt_get_name(fdt, regulator_node, NULL);
|
|
+ uint16_t voltage;
|
|
+ int status;
|
|
+
|
|
+#if defined(IMAGE_BL2)
|
|
+ if ((fdt_getprop(fdt, regulator_node, "regulator-boot-on",
|
|
+ NULL) == NULL) &&
|
|
+ (fdt_getprop(fdt, regulator_node, "regulator-always-on",
|
|
+ NULL) == NULL)) {
|
|
+#else
|
|
+ if (fdt_getprop(fdt, regulator_node, "regulator-boot-on",
|
|
+ NULL) == NULL) {
|
|
+#endif
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ if (fdt_getprop(fdt, regulator_node, "regulator-pull-down",
|
|
+ NULL) != NULL) {
|
|
+ int status;
|
|
+
|
|
+ status = stpmic1_regulator_pull_down_set(node_name);
|
|
+ if (status != 0) {
|
|
+ return status;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (fdt_getprop(fdt, regulator_node, "st,mask-reset",
|
|
+ NULL) != NULL) {
|
|
+ int status;
|
|
+
|
|
+ status = stpmic1_regulator_mask_reset_set(node_name);
|
|
+ if (status != 0) {
|
|
+ return status;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ cuint = fdt_getprop(fdt, regulator_node,
|
|
+ "regulator-min-microvolt", NULL);
|
|
+ if (cuint == NULL) {
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ /* DT uses microvolts, whereas driver awaits millivolts */
|
|
+ voltage = (uint16_t)(fdt32_to_cpu(*cuint) / 1000U);
|
|
+
|
|
+ status = stpmic1_regulator_voltage_set(node_name, voltage);
|
|
+ if (status != 0) {
|
|
+ return status;
|
|
+ }
|
|
+
|
|
+ if (stpmic1_is_regulator_enabled(node_name) == 0U) {
|
|
+ status = stpmic1_regulator_enable(node_name);
|
|
+ if (status != 0) {
|
|
+ return status;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+int dt_pmic_set_lp_config(const char *node_name)
|
|
+{
|
|
+ int pmic_node, regulators_node, regulator_node;
|
|
+ int status;
|
|
+ void *fdt;
|
|
+
|
|
+ if (node_name == NULL) {
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ if (fdt_get_address(&fdt) == 0) {
|
|
+ return -ENOENT;
|
|
+ }
|
|
+
|
|
+ pmic_node = dt_get_pmic_node(fdt);
|
|
+ if (pmic_node < 0) {
|
|
+ return -FDT_ERR_NOTFOUND;
|
|
+ }
|
|
+
|
|
+ status = stpmic1_powerctrl_on();
|
|
+ if (status != 0) {
|
|
+ return status;
|
|
+ };
|
|
+
|
|
+ regulators_node = fdt_subnode_offset(fdt, pmic_node, "regulators");
|
|
+
|
|
+ fdt_for_each_subnode(regulator_node, fdt, regulators_node) {
|
|
+ const fdt32_t *cuint;
|
|
+ const char *reg_name;
|
|
+ int regulator_state_node;
|
|
+
|
|
+ /*
|
|
+ * First, copy active configuration (Control register) to
|
|
+ * PWRCTRL Control register, even if regulator_state_node
|
|
+ * does not exist.
|
|
+ */
|
|
+ reg_name = fdt_get_name(fdt, regulator_node, NULL);
|
|
+ status = stpmic1_lp_copy_reg(reg_name);
|
|
+ if (status != 0) {
|
|
+ return status;
|
|
+ }
|
|
+
|
|
+ /* Then apply configs from regulator_state_node */
|
|
+ regulator_state_node = fdt_subnode_offset(fdt,
|
|
+ regulator_node,
|
|
+ node_name);
|
|
+ if (regulator_state_node <= 0) {
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ if (fdt_getprop(fdt, regulator_state_node,
|
|
+ "regulator-on-in-suspend", NULL) != NULL) {
|
|
+ status = stpmic1_lp_reg_on_off(reg_name, 1);
|
|
+ if (status != 0) {
|
|
+ return status;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (fdt_getprop(fdt, regulator_state_node,
|
|
+ "regulator-off-in-suspend", NULL) != NULL) {
|
|
+ status = stpmic1_lp_reg_on_off(reg_name, 0);
|
|
+ if (status != 0) {
|
|
+ return status;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ cuint = fdt_getprop(fdt, regulator_state_node,
|
|
+ "regulator-suspend-microvolt", NULL);
|
|
+ if (cuint != NULL) {
|
|
+ uint16_t voltage = (uint16_t)(fdt32_to_cpu(*cuint) /
|
|
+ 1000U);
|
|
+
|
|
+ status = stpmic1_lp_set_voltage(reg_name, voltage);
|
|
+ if (status != 0) {
|
|
+ return status;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ cuint = fdt_getprop(fdt, regulator_state_node,
|
|
+ "regulator-mode", NULL);
|
|
+ if (cuint != NULL) {
|
|
+ if (fdt32_to_cpu(*cuint) == REGULATOR_MODE_STANDBY) {
|
|
+ status = stpmic1_lp_set_mode(reg_name, 1);
|
|
+ if (status != 0) {
|
|
+ return status;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * initialize_pmic_i2c - Initialize I2C for the PMIC control
|
|
+ *
|
|
+ * Return true if PMIC is available, false if not found, panics on errors
|
|
+ */
|
|
+bool initialize_pmic_i2c(void)
|
|
+{
|
|
+ int ret;
|
|
+ struct dt_node_info i2c_info;
|
|
+ struct i2c_handle_s *i2c = &i2c_handle;
|
|
+ struct stm32_i2c_init_s i2c_init;
|
|
+
|
|
+ ret = dt_pmic_i2c_config(&i2c_info, &i2c_init);
|
|
+ if (ret < 0) {
|
|
+ ERROR("I2C configuration failed %d\n", ret);
|
|
+ panic();
|
|
+ }
|
|
+ if (ret != 0) {
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ /* Initialize PMIC I2C */
|
|
+ i2c->i2c_base_addr = i2c_info.base;
|
|
+ i2c->dt_status = i2c_info.status;
|
|
+ i2c->clock = i2c_info.clock;
|
|
+ i2c_init.own_address1 = pmic_i2c_addr;
|
|
+ i2c_init.addressing_mode = I2C_ADDRESSINGMODE_7BIT;
|
|
+ i2c_init.dual_address_mode = I2C_DUALADDRESS_DISABLE;
|
|
+ i2c_init.own_address2 = 0;
|
|
+ i2c_init.own_address2_masks = I2C_OAR2_OA2NOMASK;
|
|
+ i2c_init.general_call_mode = I2C_GENERALCALL_DISABLE;
|
|
+ i2c_init.no_stretch_mode = I2C_NOSTRETCH_DISABLE;
|
|
+ i2c_init.analog_filter = 1;
|
|
+ i2c_init.digital_filter_coef = 0;
|
|
+
|
|
+ ret = stm32_i2c_init(i2c, &i2c_init);
|
|
+ if (ret != 0) {
|
|
+ ERROR("Cannot initialize I2C %x (%d)\n",
|
|
+ i2c->i2c_base_addr, ret);
|
|
+ panic();
|
|
+ }
|
|
+
|
|
+ if (!stm32_i2c_is_device_ready(i2c, pmic_i2c_addr, 1,
|
|
+ I2C_TIMEOUT_BUSY_MS)) {
|
|
+ ERROR("I2C device not ready\n");
|
|
+ panic();
|
|
+ }
|
|
+
|
|
+ stpmic1_bind_i2c(i2c, (uint16_t)pmic_i2c_addr);
|
|
+
|
|
+ return true;
|
|
+}
|
|
+
|
|
+#if STM32MP1_DEBUG_ENABLE
|
|
+int pmic_keep_debug_unit(void)
|
|
+{
|
|
+ unsigned int i;
|
|
+ static const char * const regus[] = {
|
|
+ "buck1",
|
|
+ "buck3",
|
|
+ };
|
|
+
|
|
+ for (i = 0; i < ARRAY_SIZE(regus); i++) {
|
|
+ int res;
|
|
+
|
|
+ WARN("Mask %s\n", regus[i]);
|
|
+ res = stpmic1_regulator_mask_reset_set(regus[i]);
|
|
+ if (res != 0) {
|
|
+ return res;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+#endif
|
|
+
|
|
+static void register_non_secure_pmic(void)
|
|
+{
|
|
+ if (i2c_handle.i2c_base_addr == 0U) {
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ stm32mp_register_non_secure_periph_iomem(i2c_handle.i2c_base_addr);
|
|
+
|
|
+ if (stm32mp1_rcc_is_secure()) {
|
|
+ stm32mp1_register_clock_parents_secure(i2c_handle.clock);
|
|
+ }
|
|
+}
|
|
+
|
|
+static void register_secure_pmic(void)
|
|
+{
|
|
+ stm32mp_register_secure_periph_iomem(i2c_handle.i2c_base_addr);
|
|
+}
|
|
+
|
|
+void initialize_pmic(void)
|
|
+{
|
|
+ unsigned long pmic_version;
|
|
+
|
|
+ if (!initialize_pmic_i2c()) {
|
|
+ VERBOSE("No PMIC\n");
|
|
+ register_non_secure_pmic();
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ if (stpmic1_get_version(&pmic_version) != 0) {
|
|
+ ERROR("Failed to access PMIC\n");
|
|
+ panic();
|
|
+ }
|
|
+
|
|
+ INFO("PMIC version = 0x%02lx\n", pmic_version);
|
|
+ stpmic1_dump_regulators();
|
|
+
|
|
+ if (dt_pmic_is_secure()) {
|
|
+ register_secure_pmic();
|
|
+ } else {
|
|
+ VERBOSE("PMIC is not secure-only hence assumed non secure\n");
|
|
+ register_non_secure_pmic();
|
|
+ }
|
|
+
|
|
+#if defined(IMAGE_BL2)
|
|
+ if (dt_pmic_configure_boot_on_regulators() != 0) {
|
|
+ panic();
|
|
+ };
|
|
+#endif
|
|
+}
|
|
+
|
|
+int pmic_ddr_power_init(enum ddr_type ddr_type)
|
|
+{
|
|
+ bool buck3_at_1v8 = false;
|
|
+ uint8_t read_val;
|
|
+ int status;
|
|
+
|
|
+ switch (ddr_type) {
|
|
+ case STM32MP_DDR3:
|
|
+ /* Set LDO3 to sync mode */
|
|
+ status = stpmic1_register_read(LDO3_CONTROL_REG, &read_val);
|
|
+ if (status != 0) {
|
|
+ return status;
|
|
+ }
|
|
+
|
|
+ read_val &= ~STPMIC1_LDO3_MODE;
|
|
+ read_val &= ~STPMIC1_LDO12356_OUTPUT_MASK;
|
|
+ read_val |= STPMIC1_LDO3_DDR_SEL <<
|
|
+ STPMIC1_LDO12356_OUTPUT_SHIFT;
|
|
+
|
|
+ status = stpmic1_register_write(LDO3_CONTROL_REG, read_val);
|
|
+ if (status != 0) {
|
|
+ return status;
|
|
+ }
|
|
+
|
|
+ status = stpmic1_regulator_voltage_set("buck2", 1350);
|
|
+ if (status != 0) {
|
|
+ return status;
|
|
+ }
|
|
+
|
|
+ status = stpmic1_regulator_enable("buck2");
|
|
+ if (status != 0) {
|
|
+ return status;
|
|
+ }
|
|
+
|
|
+ mdelay(STPMIC1_DEFAULT_START_UP_DELAY_MS);
|
|
+
|
|
+ status = stpmic1_regulator_enable("vref_ddr");
|
|
+ if (status != 0) {
|
|
+ return status;
|
|
+ }
|
|
+
|
|
+ mdelay(STPMIC1_DEFAULT_START_UP_DELAY_MS);
|
|
+
|
|
+ status = stpmic1_regulator_enable("ldo3");
|
|
+ if (status != 0) {
|
|
+ return status;
|
|
+ }
|
|
+
|
|
+ mdelay(STPMIC1_DEFAULT_START_UP_DELAY_MS);
|
|
+ break;
|
|
+
|
|
+ case STM32MP_LPDDR2:
|
|
+ case STM32MP_LPDDR3:
|
|
+ /*
|
|
+ * Set LDO3 to 1.8V
|
|
+ * Set LDO3 to bypass mode if BUCK3 = 1.8V
|
|
+ * Set LDO3 to normal mode if BUCK3 != 1.8V
|
|
+ */
|
|
+ status = stpmic1_register_read(BUCK3_CONTROL_REG, &read_val);
|
|
+ if (status != 0) {
|
|
+ return status;
|
|
+ }
|
|
+
|
|
+ if ((read_val & STPMIC1_BUCK3_1V8) == STPMIC1_BUCK3_1V8) {
|
|
+ buck3_at_1v8 = true;
|
|
+ }
|
|
+
|
|
+ status = stpmic1_register_read(LDO3_CONTROL_REG, &read_val);
|
|
+ if (status != 0) {
|
|
+ return status;
|
|
+ }
|
|
+
|
|
+ read_val &= ~STPMIC1_LDO3_MODE;
|
|
+ read_val &= ~STPMIC1_LDO12356_OUTPUT_MASK;
|
|
+ read_val |= STPMIC1_LDO3_1800000;
|
|
+ if (buck3_at_1v8) {
|
|
+ read_val |= STPMIC1_LDO3_MODE;
|
|
+ }
|
|
+
|
|
+ status = stpmic1_register_write(LDO3_CONTROL_REG, read_val);
|
|
+ if (status != 0) {
|
|
+ return status;
|
|
+ }
|
|
+
|
|
+ status = stpmic1_regulator_voltage_set("buck2", 1200);
|
|
+ if (status != 0) {
|
|
+ return status;
|
|
+ }
|
|
+
|
|
+ status = stpmic1_regulator_enable("ldo3");
|
|
+ if (status != 0) {
|
|
+ return status;
|
|
+ }
|
|
+
|
|
+ mdelay(STPMIC1_DEFAULT_START_UP_DELAY_MS);
|
|
+
|
|
+ status = stpmic1_regulator_enable("buck2");
|
|
+ if (status != 0) {
|
|
+ return status;
|
|
+ }
|
|
+
|
|
+ mdelay(STPMIC1_DEFAULT_START_UP_DELAY_MS);
|
|
+
|
|
+ status = stpmic1_regulator_enable("vref_ddr");
|
|
+ if (status != 0) {
|
|
+ return status;
|
|
+ }
|
|
+
|
|
+ mdelay(STPMIC1_DEFAULT_START_UP_DELAY_MS);
|
|
+ break;
|
|
+
|
|
+ default:
|
|
+ break;
|
|
+ };
|
|
+
|
|
+ return 0;
|
|
+}
|
|
diff --git a/drivers/st/pmic/stpmic1.c b/drivers/st/pmic/stpmic1.c
|
|
new file mode 100644
|
|
index 0000000..2bd2b60
|
|
--- /dev/null
|
|
+++ b/drivers/st/pmic/stpmic1.c
|
|
@@ -0,0 +1,817 @@
|
|
+/*
|
|
+ * Copyright (c) 2016-2018, STMicroelectronics - All Rights Reserved
|
|
+ *
|
|
+ * SPDX-License-Identifier: BSD-3-Clause
|
|
+ */
|
|
+
|
|
+#include <debug.h>
|
|
+#include <platform.h>
|
|
+#include <stpmic1.h>
|
|
+#include <string.h>
|
|
+
|
|
+#define I2C_TIMEOUT_MS 25
|
|
+
|
|
+struct regul_struct {
|
|
+ const char *dt_node_name;
|
|
+ const uint16_t *voltage_table;
|
|
+ uint8_t voltage_table_size;
|
|
+ uint8_t control_reg;
|
|
+ uint8_t low_power_reg;
|
|
+ uint8_t pull_down_reg;
|
|
+ uint8_t pull_down;
|
|
+ uint8_t mask_reset_reg;
|
|
+ uint8_t mask_reset;
|
|
+};
|
|
+
|
|
+static struct i2c_handle_s *pmic_i2c_handle;
|
|
+static uint16_t pmic_i2c_addr;
|
|
+
|
|
+/* Voltage tables in mV */
|
|
+static const uint16_t buck1_voltage_table[] = {
|
|
+ 725,
|
|
+ 725,
|
|
+ 725,
|
|
+ 725,
|
|
+ 725,
|
|
+ 725,
|
|
+ 750,
|
|
+ 775,
|
|
+ 800,
|
|
+ 825,
|
|
+ 850,
|
|
+ 875,
|
|
+ 900,
|
|
+ 925,
|
|
+ 950,
|
|
+ 975,
|
|
+ 1000,
|
|
+ 1025,
|
|
+ 1050,
|
|
+ 1075,
|
|
+ 1100,
|
|
+ 1125,
|
|
+ 1150,
|
|
+ 1175,
|
|
+ 1200,
|
|
+ 1225,
|
|
+ 1250,
|
|
+ 1275,
|
|
+ 1300,
|
|
+ 1325,
|
|
+ 1350,
|
|
+ 1375,
|
|
+ 1400,
|
|
+ 1425,
|
|
+ 1450,
|
|
+ 1475,
|
|
+ 1500,
|
|
+ 1500,
|
|
+ 1500,
|
|
+ 1500,
|
|
+ 1500,
|
|
+ 1500,
|
|
+ 1500,
|
|
+ 1500,
|
|
+ 1500,
|
|
+ 1500,
|
|
+ 1500,
|
|
+ 1500,
|
|
+ 1500,
|
|
+ 1500,
|
|
+ 1500,
|
|
+ 1500,
|
|
+ 1500,
|
|
+ 1500,
|
|
+ 1500,
|
|
+ 1500,
|
|
+ 1500,
|
|
+ 1500,
|
|
+ 1500,
|
|
+ 1500,
|
|
+ 1500,
|
|
+ 1500,
|
|
+ 1500,
|
|
+ 1500,
|
|
+};
|
|
+
|
|
+static const uint16_t buck2_voltage_table[] = {
|
|
+ 1000,
|
|
+ 1000,
|
|
+ 1000,
|
|
+ 1000,
|
|
+ 1000,
|
|
+ 1000,
|
|
+ 1000,
|
|
+ 1000,
|
|
+ 1000,
|
|
+ 1000,
|
|
+ 1000,
|
|
+ 1000,
|
|
+ 1000,
|
|
+ 1000,
|
|
+ 1000,
|
|
+ 1000,
|
|
+ 1000,
|
|
+ 1000,
|
|
+ 1050,
|
|
+ 1050,
|
|
+ 1100,
|
|
+ 1100,
|
|
+ 1150,
|
|
+ 1150,
|
|
+ 1200,
|
|
+ 1200,
|
|
+ 1250,
|
|
+ 1250,
|
|
+ 1300,
|
|
+ 1300,
|
|
+ 1350,
|
|
+ 1350,
|
|
+ 1400,
|
|
+ 1400,
|
|
+ 1450,
|
|
+ 1450,
|
|
+ 1500,
|
|
+};
|
|
+
|
|
+static const uint16_t buck3_voltage_table[] = {
|
|
+ 1000,
|
|
+ 1000,
|
|
+ 1000,
|
|
+ 1000,
|
|
+ 1000,
|
|
+ 1000,
|
|
+ 1000,
|
|
+ 1000,
|
|
+ 1000,
|
|
+ 1000,
|
|
+ 1000,
|
|
+ 1000,
|
|
+ 1000,
|
|
+ 1000,
|
|
+ 1000,
|
|
+ 1000,
|
|
+ 1000,
|
|
+ 1000,
|
|
+ 1000,
|
|
+ 1000,
|
|
+ 1100,
|
|
+ 1100,
|
|
+ 1100,
|
|
+ 1100,
|
|
+ 1200,
|
|
+ 1200,
|
|
+ 1200,
|
|
+ 1200,
|
|
+ 1300,
|
|
+ 1300,
|
|
+ 1300,
|
|
+ 1300,
|
|
+ 1400,
|
|
+ 1400,
|
|
+ 1400,
|
|
+ 1400,
|
|
+ 1500,
|
|
+ 1600,
|
|
+ 1700,
|
|
+ 1800,
|
|
+ 1900,
|
|
+ 2000,
|
|
+ 2100,
|
|
+ 2200,
|
|
+ 2300,
|
|
+ 2400,
|
|
+ 2500,
|
|
+ 2600,
|
|
+ 2700,
|
|
+ 2800,
|
|
+ 2900,
|
|
+ 3000,
|
|
+ 3100,
|
|
+ 3200,
|
|
+ 3300,
|
|
+ 3400,
|
|
+};
|
|
+
|
|
+static const uint16_t buck4_voltage_table[] = {
|
|
+ 600,
|
|
+ 625,
|
|
+ 650,
|
|
+ 675,
|
|
+ 700,
|
|
+ 725,
|
|
+ 750,
|
|
+ 775,
|
|
+ 800,
|
|
+ 825,
|
|
+ 850,
|
|
+ 875,
|
|
+ 900,
|
|
+ 925,
|
|
+ 950,
|
|
+ 975,
|
|
+ 1000,
|
|
+ 1025,
|
|
+ 1050,
|
|
+ 1075,
|
|
+ 1100,
|
|
+ 1125,
|
|
+ 1150,
|
|
+ 1175,
|
|
+ 1200,
|
|
+ 1225,
|
|
+ 1250,
|
|
+ 1275,
|
|
+ 1300,
|
|
+ 1300,
|
|
+ 1350,
|
|
+ 1350,
|
|
+ 1400,
|
|
+ 1400,
|
|
+ 1450,
|
|
+ 1450,
|
|
+ 1500,
|
|
+ 1600,
|
|
+ 1700,
|
|
+ 1800,
|
|
+ 1900,
|
|
+ 2000,
|
|
+ 2100,
|
|
+ 2200,
|
|
+ 2300,
|
|
+ 2400,
|
|
+ 2500,
|
|
+ 2600,
|
|
+ 2700,
|
|
+ 2800,
|
|
+ 2900,
|
|
+ 3000,
|
|
+ 3100,
|
|
+ 3200,
|
|
+ 3300,
|
|
+ 3400,
|
|
+ 3500,
|
|
+ 3600,
|
|
+ 3700,
|
|
+ 3800,
|
|
+ 3900,
|
|
+};
|
|
+
|
|
+static const uint16_t ldo1_voltage_table[] = {
|
|
+ 1700,
|
|
+ 1700,
|
|
+ 1700,
|
|
+ 1700,
|
|
+ 1700,
|
|
+ 1700,
|
|
+ 1700,
|
|
+ 1700,
|
|
+ 1700,
|
|
+ 1800,
|
|
+ 1900,
|
|
+ 2000,
|
|
+ 2100,
|
|
+ 2200,
|
|
+ 2300,
|
|
+ 2400,
|
|
+ 2500,
|
|
+ 2600,
|
|
+ 2700,
|
|
+ 2800,
|
|
+ 2900,
|
|
+ 3000,
|
|
+ 3100,
|
|
+ 3200,
|
|
+ 3300,
|
|
+};
|
|
+
|
|
+static const uint16_t ldo2_voltage_table[] = {
|
|
+ 1700,
|
|
+ 1700,
|
|
+ 1700,
|
|
+ 1700,
|
|
+ 1700,
|
|
+ 1700,
|
|
+ 1700,
|
|
+ 1700,
|
|
+ 1700,
|
|
+ 1800,
|
|
+ 1900,
|
|
+ 2000,
|
|
+ 2100,
|
|
+ 2200,
|
|
+ 2300,
|
|
+ 2400,
|
|
+ 2500,
|
|
+ 2600,
|
|
+ 2700,
|
|
+ 2800,
|
|
+ 2900,
|
|
+ 3000,
|
|
+ 3100,
|
|
+ 3200,
|
|
+ 3300,
|
|
+};
|
|
+
|
|
+static const uint16_t ldo3_voltage_table[] = {
|
|
+ 1700,
|
|
+ 1700,
|
|
+ 1700,
|
|
+ 1700,
|
|
+ 1700,
|
|
+ 1700,
|
|
+ 1700,
|
|
+ 1700,
|
|
+ 1700,
|
|
+ 1800,
|
|
+ 1900,
|
|
+ 2000,
|
|
+ 2100,
|
|
+ 2200,
|
|
+ 2300,
|
|
+ 2400,
|
|
+ 2500,
|
|
+ 2600,
|
|
+ 2700,
|
|
+ 2800,
|
|
+ 2900,
|
|
+ 3000,
|
|
+ 3100,
|
|
+ 3200,
|
|
+ 3300,
|
|
+ 3300,
|
|
+ 3300,
|
|
+ 3300,
|
|
+ 3300,
|
|
+ 3300,
|
|
+ 3300,
|
|
+ 500,
|
|
+ 0xFFFF, /* VREFDDR */
|
|
+};
|
|
+
|
|
+static const uint16_t ldo5_voltage_table[] = {
|
|
+ 1700,
|
|
+ 1700,
|
|
+ 1700,
|
|
+ 1700,
|
|
+ 1700,
|
|
+ 1700,
|
|
+ 1700,
|
|
+ 1700,
|
|
+ 1700,
|
|
+ 1800,
|
|
+ 1900,
|
|
+ 2000,
|
|
+ 2100,
|
|
+ 2200,
|
|
+ 2300,
|
|
+ 2400,
|
|
+ 2500,
|
|
+ 2600,
|
|
+ 2700,
|
|
+ 2800,
|
|
+ 2900,
|
|
+ 3000,
|
|
+ 3100,
|
|
+ 3200,
|
|
+ 3300,
|
|
+ 3400,
|
|
+ 3500,
|
|
+ 3600,
|
|
+ 3700,
|
|
+ 3800,
|
|
+ 3900,
|
|
+};
|
|
+
|
|
+static const uint16_t ldo6_voltage_table[] = {
|
|
+ 900,
|
|
+ 1000,
|
|
+ 1100,
|
|
+ 1200,
|
|
+ 1300,
|
|
+ 1400,
|
|
+ 1500,
|
|
+ 1600,
|
|
+ 1700,
|
|
+ 1800,
|
|
+ 1900,
|
|
+ 2000,
|
|
+ 2100,
|
|
+ 2200,
|
|
+ 2300,
|
|
+ 2400,
|
|
+ 2500,
|
|
+ 2600,
|
|
+ 2700,
|
|
+ 2800,
|
|
+ 2900,
|
|
+ 3000,
|
|
+ 3100,
|
|
+ 3200,
|
|
+ 3300,
|
|
+};
|
|
+
|
|
+static const uint16_t ldo4_voltage_table[] = {
|
|
+ 3300,
|
|
+};
|
|
+
|
|
+static const uint16_t vref_ddr_voltage_table[] = {
|
|
+ 3300,
|
|
+};
|
|
+
|
|
+/* Table of Regulators in PMIC SoC */
|
|
+static const struct regul_struct regulators_table[] = {
|
|
+ {
|
|
+ .dt_node_name = "buck1",
|
|
+ .voltage_table = buck1_voltage_table,
|
|
+ .voltage_table_size = ARRAY_SIZE(buck1_voltage_table),
|
|
+ .control_reg = BUCK1_CONTROL_REG,
|
|
+ .low_power_reg = BUCK1_PWRCTRL_REG,
|
|
+ .pull_down_reg = BUCK_PULL_DOWN_REG,
|
|
+ .pull_down = BUCK1_PULL_DOWN_SHIFT,
|
|
+ .mask_reset_reg = MASK_RESET_BUCK_REG,
|
|
+ .mask_reset = BUCK1_MASK_RESET,
|
|
+ },
|
|
+ {
|
|
+ .dt_node_name = "buck2",
|
|
+ .voltage_table = buck2_voltage_table,
|
|
+ .voltage_table_size = ARRAY_SIZE(buck2_voltage_table),
|
|
+ .control_reg = BUCK2_CONTROL_REG,
|
|
+ .low_power_reg = BUCK2_PWRCTRL_REG,
|
|
+ .pull_down_reg = BUCK_PULL_DOWN_REG,
|
|
+ .pull_down = BUCK2_PULL_DOWN_SHIFT,
|
|
+ .mask_reset_reg = MASK_RESET_BUCK_REG,
|
|
+ .mask_reset = BUCK2_MASK_RESET,
|
|
+ },
|
|
+ {
|
|
+ .dt_node_name = "buck3",
|
|
+ .voltage_table = buck3_voltage_table,
|
|
+ .voltage_table_size = ARRAY_SIZE(buck3_voltage_table),
|
|
+ .control_reg = BUCK3_CONTROL_REG,
|
|
+ .low_power_reg = BUCK3_PWRCTRL_REG,
|
|
+ .pull_down_reg = BUCK_PULL_DOWN_REG,
|
|
+ .pull_down = BUCK3_PULL_DOWN_SHIFT,
|
|
+ .mask_reset_reg = MASK_RESET_BUCK_REG,
|
|
+ .mask_reset = BUCK3_MASK_RESET,
|
|
+ },
|
|
+ {
|
|
+ .dt_node_name = "buck4",
|
|
+ .voltage_table = buck4_voltage_table,
|
|
+ .voltage_table_size = ARRAY_SIZE(buck4_voltage_table),
|
|
+ .control_reg = BUCK4_CONTROL_REG,
|
|
+ .low_power_reg = BUCK4_PWRCTRL_REG,
|
|
+ .pull_down_reg = BUCK_PULL_DOWN_REG,
|
|
+ .pull_down = BUCK4_PULL_DOWN_SHIFT,
|
|
+ .mask_reset_reg = MASK_RESET_BUCK_REG,
|
|
+ .mask_reset = BUCK4_MASK_RESET,
|
|
+ },
|
|
+ {
|
|
+ .dt_node_name = "ldo1",
|
|
+ .voltage_table = ldo1_voltage_table,
|
|
+ .voltage_table_size = ARRAY_SIZE(ldo1_voltage_table),
|
|
+ .control_reg = LDO1_CONTROL_REG,
|
|
+ .low_power_reg = LDO1_PWRCTRL_REG,
|
|
+ .mask_reset_reg = MASK_RESET_LDO_REG,
|
|
+ .mask_reset = LDO1_MASK_RESET,
|
|
+ },
|
|
+ {
|
|
+ .dt_node_name = "ldo2",
|
|
+ .voltage_table = ldo2_voltage_table,
|
|
+ .voltage_table_size = ARRAY_SIZE(ldo2_voltage_table),
|
|
+ .control_reg = LDO2_CONTROL_REG,
|
|
+ .low_power_reg = LDO2_PWRCTRL_REG,
|
|
+ .mask_reset_reg = MASK_RESET_LDO_REG,
|
|
+ .mask_reset = LDO2_MASK_RESET,
|
|
+ },
|
|
+ {
|
|
+ .dt_node_name = "ldo3",
|
|
+ .voltage_table = ldo3_voltage_table,
|
|
+ .voltage_table_size = ARRAY_SIZE(ldo3_voltage_table),
|
|
+ .control_reg = LDO3_CONTROL_REG,
|
|
+ .low_power_reg = LDO3_PWRCTRL_REG,
|
|
+ .mask_reset_reg = MASK_RESET_LDO_REG,
|
|
+ .mask_reset = LDO3_MASK_RESET,
|
|
+ },
|
|
+ {
|
|
+ .dt_node_name = "ldo4",
|
|
+ .voltage_table = ldo4_voltage_table,
|
|
+ .voltage_table_size = ARRAY_SIZE(ldo4_voltage_table),
|
|
+ .control_reg = LDO4_CONTROL_REG,
|
|
+ .low_power_reg = LDO4_PWRCTRL_REG,
|
|
+ .mask_reset_reg = MASK_RESET_LDO_REG,
|
|
+ .mask_reset = LDO4_MASK_RESET,
|
|
+ },
|
|
+ {
|
|
+ .dt_node_name = "ldo5",
|
|
+ .voltage_table = ldo5_voltage_table,
|
|
+ .voltage_table_size = ARRAY_SIZE(ldo5_voltage_table),
|
|
+ .control_reg = LDO5_CONTROL_REG,
|
|
+ .low_power_reg = LDO5_PWRCTRL_REG,
|
|
+ .mask_reset_reg = MASK_RESET_LDO_REG,
|
|
+ .mask_reset = LDO5_MASK_RESET,
|
|
+ },
|
|
+ {
|
|
+ .dt_node_name = "ldo6",
|
|
+ .voltage_table = ldo6_voltage_table,
|
|
+ .voltage_table_size = ARRAY_SIZE(ldo6_voltage_table),
|
|
+ .control_reg = LDO6_CONTROL_REG,
|
|
+ .low_power_reg = LDO6_PWRCTRL_REG,
|
|
+ .mask_reset_reg = MASK_RESET_LDO_REG,
|
|
+ .mask_reset = LDO6_MASK_RESET,
|
|
+ },
|
|
+ {
|
|
+ .dt_node_name = "vref_ddr",
|
|
+ .voltage_table = vref_ddr_voltage_table,
|
|
+ .voltage_table_size = ARRAY_SIZE(vref_ddr_voltage_table),
|
|
+ .control_reg = VREF_DDR_CONTROL_REG,
|
|
+ .low_power_reg = VREF_DDR_PWRCTRL_REG,
|
|
+ .mask_reset_reg = MASK_RESET_LDO_REG,
|
|
+ .mask_reset = VREF_DDR_MASK_RESET,
|
|
+ },
|
|
+};
|
|
+
|
|
+#define MAX_REGUL ARRAY_SIZE(regulators_table)
|
|
+
|
|
+static const struct regul_struct *get_regulator_data(const char *name)
|
|
+{
|
|
+ uint8_t i;
|
|
+
|
|
+ for (i = 0 ; i < MAX_REGUL ; i++) {
|
|
+ if (strncmp(name, regulators_table[i].dt_node_name,
|
|
+ strlen(regulators_table[i].dt_node_name)) == 0) {
|
|
+ return ®ulators_table[i];
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /* Regulator not found */
|
|
+ panic();
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
+static uint8_t voltage_to_index(const char *name, uint16_t millivolts)
|
|
+{
|
|
+ const struct regul_struct *regul = get_regulator_data(name);
|
|
+ uint8_t i;
|
|
+
|
|
+ for (i = 0 ; i < regul->voltage_table_size ; i++) {
|
|
+ if (regul->voltage_table[i] == millivolts) {
|
|
+ return i;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /* Voltage not found */
|
|
+ panic();
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+int stpmic1_powerctrl_on(void)
|
|
+{
|
|
+ return stpmic1_register_update(MAIN_CONTROL_REG, PWRCTRL_PIN_VALID,
|
|
+ PWRCTRL_PIN_VALID);
|
|
+}
|
|
+
|
|
+int stpmic1_switch_off(void)
|
|
+{
|
|
+ return stpmic1_register_update(MAIN_CONTROL_REG, 1,
|
|
+ SOFTWARE_SWITCH_OFF_ENABLED);
|
|
+}
|
|
+
|
|
+int stpmic1_regulator_enable(const char *name)
|
|
+{
|
|
+ const struct regul_struct *regul = get_regulator_data(name);
|
|
+
|
|
+ return stpmic1_register_update(regul->control_reg, BIT(0), BIT(0));
|
|
+}
|
|
+
|
|
+int stpmic1_regulator_disable(const char *name)
|
|
+{
|
|
+ const struct regul_struct *regul = get_regulator_data(name);
|
|
+
|
|
+ return stpmic1_register_update(regul->control_reg, 0, BIT(0));
|
|
+}
|
|
+
|
|
+uint8_t stpmic1_is_regulator_enabled(const char *name)
|
|
+{
|
|
+ uint8_t val;
|
|
+ const struct regul_struct *regul = get_regulator_data(name);
|
|
+
|
|
+ if (stpmic1_register_read(regul->control_reg, &val) != 0) {
|
|
+ panic();
|
|
+ }
|
|
+
|
|
+ return (val & 0x1U);
|
|
+}
|
|
+
|
|
+int stpmic1_regulator_voltage_set(const char *name, uint16_t millivolts)
|
|
+{
|
|
+ uint8_t voltage_index = voltage_to_index(name, millivolts);
|
|
+ const struct regul_struct *regul = get_regulator_data(name);
|
|
+ uint8_t mask;
|
|
+
|
|
+ /* Voltage can be set for buck<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->control_reg,
|
|
+ voltage_index << LDO_BUCK_VOLTAGE_SHIFT,
|
|
+ mask);
|
|
+}
|
|
+
|
|
+int stpmic1_regulator_pull_down_set(const char *name)
|
|
+{
|
|
+ const struct regul_struct *regul = get_regulator_data(name);
|
|
+
|
|
+ if (regul->pull_down_reg != 0) {
|
|
+ return stpmic1_register_update(regul->pull_down_reg,
|
|
+ BIT(regul->pull_down),
|
|
+ LDO_BUCK_PULL_DOWN_MASK <<
|
|
+ regul->pull_down);
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+int stpmic1_regulator_mask_reset_set(const char *name)
|
|
+{
|
|
+ const struct regul_struct *regul = get_regulator_data(name);
|
|
+
|
|
+ return stpmic1_register_update(regul->mask_reset_reg,
|
|
+ BIT(regul->mask_reset),
|
|
+ LDO_BUCK_RESET_MASK <<
|
|
+ regul->mask_reset);
|
|
+}
|
|
+
|
|
+/* Low-power functions */
|
|
+int stpmic1_lp_copy_reg(const char *name)
|
|
+{
|
|
+ uint8_t val;
|
|
+ int status;
|
|
+ const struct regul_struct *regul = get_regulator_data(name);
|
|
+
|
|
+ status = stpmic1_register_read(regul->control_reg, &val);
|
|
+ if (status != 0) {
|
|
+ return status;
|
|
+ }
|
|
+
|
|
+ return stpmic1_register_write(regul->low_power_reg, val);
|
|
+}
|
|
+
|
|
+int stpmic1_lp_reg_on_off(const char *name, uint8_t enable)
|
|
+{
|
|
+ const struct regul_struct *regul = get_regulator_data(name);
|
|
+
|
|
+ return stpmic1_register_update(regul->low_power_reg, enable,
|
|
+ LDO_BUCK_ENABLE_MASK);
|
|
+}
|
|
+
|
|
+int stpmic1_lp_set_mode(const char *name, uint8_t hplp)
|
|
+{
|
|
+ const struct regul_struct *regul = get_regulator_data(name);
|
|
+
|
|
+ return stpmic1_register_update(regul->low_power_reg,
|
|
+ hplp << LDO_BUCK_HPLP_SHIFT,
|
|
+ LDO_BUCK_HPLP_ENABLE_MASK);
|
|
+}
|
|
+
|
|
+int stpmic1_lp_set_voltage(const char *name, uint16_t millivolts)
|
|
+{
|
|
+ uint8_t voltage_index = voltage_to_index(name, millivolts);
|
|
+ const struct regul_struct *regul = get_regulator_data(name);
|
|
+ uint8_t mask;
|
|
+
|
|
+ /* Voltage can be set for buck<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;
|
|
+
|
|
+ /* 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;
|
|
+ }
|
|
+
|
|
+ if (stpmic1_register_read(regul->control_reg, &value))
|
|
+ return -1;
|
|
+
|
|
+ value = (value & mask) >> LDO_BUCK_VOLTAGE_SHIFT;
|
|
+
|
|
+ if (value > regul->voltage_table_size)
|
|
+ return -1;
|
|
+
|
|
+ return (int)regul->voltage_table[value];
|
|
+}
|
|
+
|
|
+int stpmic1_register_read(uint8_t register_id, uint8_t *value)
|
|
+{
|
|
+ return stm32_i2c_mem_read(pmic_i2c_handle, pmic_i2c_addr,
|
|
+ (uint16_t)register_id,
|
|
+ I2C_MEMADD_SIZE_8BIT, value,
|
|
+ 1, I2C_TIMEOUT_MS);
|
|
+}
|
|
+
|
|
+int stpmic1_register_write(uint8_t register_id, uint8_t value)
|
|
+{
|
|
+ int status;
|
|
+
|
|
+ status = stm32_i2c_mem_write(pmic_i2c_handle, pmic_i2c_addr,
|
|
+ (uint16_t)register_id,
|
|
+ I2C_MEMADD_SIZE_8BIT, &value,
|
|
+ 1, I2C_TIMEOUT_MS);
|
|
+
|
|
+#if ENABLE_ASSERTIONS
|
|
+ if (status != 0) {
|
|
+ return status;
|
|
+ }
|
|
+
|
|
+ if ((register_id != WATCHDOG_CONTROL_REG) && (register_id <= 0x40U)) {
|
|
+ uint8_t readval;
|
|
+
|
|
+ status = stpmic1_register_read(register_id, &readval);
|
|
+ if (status != 0) {
|
|
+ return status;
|
|
+ }
|
|
+
|
|
+ if (readval != value) {
|
|
+ return -1;
|
|
+ }
|
|
+ }
|
|
+#endif
|
|
+
|
|
+ return status;
|
|
+}
|
|
+
|
|
+int stpmic1_register_update(uint8_t register_id, uint8_t value, uint8_t mask)
|
|
+{
|
|
+ int status;
|
|
+ uint8_t val;
|
|
+
|
|
+ status = stpmic1_register_read(register_id, &val);
|
|
+ if (status != 0) {
|
|
+ return status;
|
|
+ }
|
|
+
|
|
+ val = (val & ~mask) | (value & mask);
|
|
+
|
|
+ return stpmic1_register_write(register_id, val);
|
|
+}
|
|
+
|
|
+void stpmic1_bind_i2c(struct i2c_handle_s *i2c_handle, uint16_t i2c_addr)
|
|
+{
|
|
+ pmic_i2c_handle = i2c_handle;
|
|
+ pmic_i2c_addr = i2c_addr;
|
|
+}
|
|
+
|
|
+void stpmic1_dump_regulators(void)
|
|
+{
|
|
+ uint32_t i;
|
|
+
|
|
+ for (i = 0U; i < MAX_REGUL; i++) {
|
|
+ const char *name __unused = regulators_table[i].dt_node_name;
|
|
+
|
|
+ VERBOSE("PMIC regul %s: %sable, %dmV",
|
|
+ name,
|
|
+ stpmic1_is_regulator_enabled(name) ? "en" : "dis",
|
|
+ stpmic1_regulator_voltage_get(name));
|
|
+ }
|
|
+}
|
|
+
|
|
+int stpmic1_get_version(unsigned long *version)
|
|
+{
|
|
+ int rc;
|
|
+ uint8_t read_val;
|
|
+
|
|
+ rc = stpmic1_register_read(VERSION_STATUS_REG, &read_val);
|
|
+ if (rc) {
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ *version = (unsigned long)read_val;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
diff --git a/drivers/st/pmic/stpmu1.c b/drivers/st/pmic/stpmu1.c
|
|
deleted file mode 100644
|
|
index 5951899..0000000
|
|
--- a/drivers/st/pmic/stpmu1.c
|
|
+++ /dev/null
|
|
@@ -1,600 +0,0 @@
|
|
-/*
|
|
- * Copyright (c) 2016-2018, STMicroelectronics - All Rights Reserved
|
|
- *
|
|
- * SPDX-License-Identifier: BSD-3-Clause
|
|
- */
|
|
-
|
|
-#include <debug.h>
|
|
-#include <platform.h>
|
|
-#include <stpmu1.h>
|
|
-#include <string.h>
|
|
-
|
|
-struct regul_struct {
|
|
- const char *dt_node_name;
|
|
- const uint16_t *voltage_table;
|
|
- uint8_t voltage_table_size;
|
|
- uint8_t control_reg;
|
|
- uint8_t low_power_reg;
|
|
-};
|
|
-
|
|
-static struct i2c_handle_s *stpmu_i2c_handle;
|
|
-static uint16_t stpmu_i2c_addr;
|
|
-
|
|
-/* Voltage tables in mV */
|
|
-static const uint16_t buck1_voltage_table[] = {
|
|
- 600,
|
|
- 625,
|
|
- 650,
|
|
- 675,
|
|
- 700,
|
|
- 725,
|
|
- 750,
|
|
- 775,
|
|
- 800,
|
|
- 825,
|
|
- 850,
|
|
- 875,
|
|
- 900,
|
|
- 925,
|
|
- 950,
|
|
- 975,
|
|
- 1000,
|
|
- 1025,
|
|
- 1050,
|
|
- 1075,
|
|
- 1100,
|
|
- 1125,
|
|
- 1150,
|
|
- 1175,
|
|
- 1200,
|
|
- 1225,
|
|
- 1250,
|
|
- 1275,
|
|
- 1300,
|
|
- 1325,
|
|
- 1350,
|
|
- 1350,
|
|
-};
|
|
-
|
|
-static const uint16_t buck2_voltage_table[] = {
|
|
- 1000,
|
|
- 1000,
|
|
- 1000,
|
|
- 1000,
|
|
- 1000,
|
|
- 1000,
|
|
- 1000,
|
|
- 1000,
|
|
- 1000,
|
|
- 1000,
|
|
- 1000,
|
|
- 1000,
|
|
- 1000,
|
|
- 1000,
|
|
- 1000,
|
|
- 1000,
|
|
- 1000,
|
|
- 1000,
|
|
- 1050,
|
|
- 1050,
|
|
- 1100,
|
|
- 1100,
|
|
- 1150,
|
|
- 1150,
|
|
- 1200,
|
|
- 1200,
|
|
- 1250,
|
|
- 1250,
|
|
- 1300,
|
|
- 1300,
|
|
- 1350,
|
|
- 1350,
|
|
- 1400,
|
|
- 1400,
|
|
- 1450,
|
|
- 1450,
|
|
- 1500,
|
|
-};
|
|
-
|
|
-static const uint16_t buck3_voltage_table[] = {
|
|
- 1000,
|
|
- 1000,
|
|
- 1000,
|
|
- 1000,
|
|
- 1000,
|
|
- 1000,
|
|
- 1000,
|
|
- 1000,
|
|
- 1000,
|
|
- 1000,
|
|
- 1000,
|
|
- 1000,
|
|
- 1000,
|
|
- 1000,
|
|
- 1000,
|
|
- 1000,
|
|
- 1000,
|
|
- 1000,
|
|
- 1000,
|
|
- 1000,
|
|
- 1100,
|
|
- 1100,
|
|
- 1100,
|
|
- 1100,
|
|
- 1200,
|
|
- 1200,
|
|
- 1200,
|
|
- 1200,
|
|
- 1300,
|
|
- 1300,
|
|
- 1300,
|
|
- 1300,
|
|
- 1400,
|
|
- 1400,
|
|
- 1400,
|
|
- 1400,
|
|
- 1500,
|
|
- 1600,
|
|
- 1700,
|
|
- 1800,
|
|
- 1900,
|
|
- 2000,
|
|
- 2100,
|
|
- 2200,
|
|
- 2300,
|
|
- 2400,
|
|
- 2500,
|
|
- 2600,
|
|
- 2700,
|
|
- 2800,
|
|
- 2900,
|
|
- 3000,
|
|
- 3100,
|
|
- 3200,
|
|
- 3300,
|
|
- 3400,
|
|
-};
|
|
-
|
|
-static const uint16_t buck4_voltage_table[] = {
|
|
- 600,
|
|
- 625,
|
|
- 650,
|
|
- 675,
|
|
- 700,
|
|
- 725,
|
|
- 750,
|
|
- 775,
|
|
- 800,
|
|
- 825,
|
|
- 850,
|
|
- 875,
|
|
- 900,
|
|
- 925,
|
|
- 950,
|
|
- 975,
|
|
- 1000,
|
|
- 1025,
|
|
- 1050,
|
|
- 1075,
|
|
- 1100,
|
|
- 1125,
|
|
- 1150,
|
|
- 1175,
|
|
- 1200,
|
|
- 1225,
|
|
- 1250,
|
|
- 1275,
|
|
- 1300,
|
|
- 1300,
|
|
- 1350,
|
|
- 1350,
|
|
- 1400,
|
|
- 1400,
|
|
- 1450,
|
|
- 1450,
|
|
- 1500,
|
|
- 1600,
|
|
- 1700,
|
|
- 1800,
|
|
- 1900,
|
|
- 2000,
|
|
- 2100,
|
|
- 2200,
|
|
- 2300,
|
|
- 2400,
|
|
- 2500,
|
|
- 2600,
|
|
- 2700,
|
|
- 2800,
|
|
- 2900,
|
|
- 3000,
|
|
- 3100,
|
|
- 3200,
|
|
- 3300,
|
|
- 3400,
|
|
- 3500,
|
|
- 3600,
|
|
- 3700,
|
|
- 3800,
|
|
- 3900,
|
|
-};
|
|
-
|
|
-static const uint16_t ldo1_voltage_table[] = {
|
|
- 1700,
|
|
- 1700,
|
|
- 1700,
|
|
- 1700,
|
|
- 1700,
|
|
- 1700,
|
|
- 1700,
|
|
- 1700,
|
|
- 1700,
|
|
- 1800,
|
|
- 1900,
|
|
- 2000,
|
|
- 2100,
|
|
- 2200,
|
|
- 2300,
|
|
- 2400,
|
|
- 2500,
|
|
- 2600,
|
|
- 2700,
|
|
- 2800,
|
|
- 2900,
|
|
- 3000,
|
|
- 3100,
|
|
- 3200,
|
|
- 3300,
|
|
-};
|
|
-
|
|
-static const uint16_t ldo2_voltage_table[] = {
|
|
- 1700,
|
|
- 1700,
|
|
- 1700,
|
|
- 1700,
|
|
- 1700,
|
|
- 1700,
|
|
- 1700,
|
|
- 1700,
|
|
- 1700,
|
|
- 1800,
|
|
- 1900,
|
|
- 2000,
|
|
- 2100,
|
|
- 2200,
|
|
- 2300,
|
|
- 2400,
|
|
- 2500,
|
|
- 2600,
|
|
- 2700,
|
|
- 2800,
|
|
- 2900,
|
|
- 3000,
|
|
- 3100,
|
|
- 3200,
|
|
- 3300,
|
|
-};
|
|
-
|
|
-static const uint16_t ldo3_voltage_table[] = {
|
|
- 1700,
|
|
- 1700,
|
|
- 1700,
|
|
- 1700,
|
|
- 1700,
|
|
- 1700,
|
|
- 1700,
|
|
- 1700,
|
|
- 1700,
|
|
- 1800,
|
|
- 1900,
|
|
- 2000,
|
|
- 2100,
|
|
- 2200,
|
|
- 2300,
|
|
- 2400,
|
|
- 2500,
|
|
- 2600,
|
|
- 2700,
|
|
- 2800,
|
|
- 2900,
|
|
- 3000,
|
|
- 3100,
|
|
- 3200,
|
|
- 3300,
|
|
- 3300,
|
|
- 3300,
|
|
- 3300,
|
|
- 3300,
|
|
- 3300,
|
|
- 3300,
|
|
- 0xFFFF, /* VREFDDR */
|
|
-};
|
|
-
|
|
-static const uint16_t ldo5_voltage_table[] = {
|
|
- 1700,
|
|
- 1700,
|
|
- 1700,
|
|
- 1700,
|
|
- 1700,
|
|
- 1700,
|
|
- 1700,
|
|
- 1700,
|
|
- 1700,
|
|
- 1800,
|
|
- 1900,
|
|
- 2000,
|
|
- 2100,
|
|
- 2200,
|
|
- 2300,
|
|
- 2400,
|
|
- 2500,
|
|
- 2600,
|
|
- 2700,
|
|
- 2800,
|
|
- 2900,
|
|
- 3000,
|
|
- 3100,
|
|
- 3200,
|
|
- 3300,
|
|
- 3400,
|
|
- 3500,
|
|
- 3600,
|
|
- 3700,
|
|
- 3800,
|
|
- 3900,
|
|
-};
|
|
-
|
|
-static const uint16_t ldo6_voltage_table[] = {
|
|
- 900,
|
|
- 1000,
|
|
- 1100,
|
|
- 1200,
|
|
- 1300,
|
|
- 1400,
|
|
- 1500,
|
|
- 1600,
|
|
- 1700,
|
|
- 1800,
|
|
- 1900,
|
|
- 2000,
|
|
- 2100,
|
|
- 2200,
|
|
- 2300,
|
|
- 2400,
|
|
- 2500,
|
|
- 2600,
|
|
- 2700,
|
|
- 2800,
|
|
- 2900,
|
|
- 3000,
|
|
- 3100,
|
|
- 3200,
|
|
- 3300,
|
|
-};
|
|
-
|
|
-static const uint16_t ldo4_voltage_table[] = {
|
|
- 3300,
|
|
-};
|
|
-
|
|
-static const uint16_t vref_ddr_voltage_table[] = {
|
|
- 3300,
|
|
-};
|
|
-
|
|
-/* Table of Regulators in PMIC SoC */
|
|
-static const struct regul_struct regulators_table[] = {
|
|
- {
|
|
- .dt_node_name = "buck1",
|
|
- .voltage_table = buck1_voltage_table,
|
|
- .voltage_table_size = ARRAY_SIZE(buck1_voltage_table),
|
|
- .control_reg = BUCK1_CONTROL_REG,
|
|
- .low_power_reg = BUCK1_PWRCTRL_REG,
|
|
- },
|
|
- {
|
|
- .dt_node_name = "buck2",
|
|
- .voltage_table = buck2_voltage_table,
|
|
- .voltage_table_size = ARRAY_SIZE(buck2_voltage_table),
|
|
- .control_reg = BUCK2_CONTROL_REG,
|
|
- .low_power_reg = BUCK2_PWRCTRL_REG,
|
|
- },
|
|
- {
|
|
- .dt_node_name = "buck3",
|
|
- .voltage_table = buck3_voltage_table,
|
|
- .voltage_table_size = ARRAY_SIZE(buck3_voltage_table),
|
|
- .control_reg = BUCK3_CONTROL_REG,
|
|
- .low_power_reg = BUCK3_PWRCTRL_REG,
|
|
- },
|
|
- {
|
|
- .dt_node_name = "buck4",
|
|
- .voltage_table = buck4_voltage_table,
|
|
- .voltage_table_size = ARRAY_SIZE(buck4_voltage_table),
|
|
- .control_reg = BUCK4_CONTROL_REG,
|
|
- .low_power_reg = BUCK4_PWRCTRL_REG,
|
|
- },
|
|
- {
|
|
- .dt_node_name = "ldo1",
|
|
- .voltage_table = ldo1_voltage_table,
|
|
- .voltage_table_size = ARRAY_SIZE(ldo1_voltage_table),
|
|
- .control_reg = LDO1_CONTROL_REG,
|
|
- .low_power_reg = LDO1_PWRCTRL_REG,
|
|
- },
|
|
- {
|
|
- .dt_node_name = "ldo2",
|
|
- .voltage_table = ldo2_voltage_table,
|
|
- .voltage_table_size = ARRAY_SIZE(ldo2_voltage_table),
|
|
- .control_reg = LDO2_CONTROL_REG,
|
|
- .low_power_reg = LDO2_PWRCTRL_REG,
|
|
- },
|
|
- {
|
|
- .dt_node_name = "ldo3",
|
|
- .voltage_table = ldo3_voltage_table,
|
|
- .voltage_table_size = ARRAY_SIZE(ldo3_voltage_table),
|
|
- .control_reg = LDO3_CONTROL_REG,
|
|
- .low_power_reg = LDO3_PWRCTRL_REG,
|
|
- },
|
|
- {
|
|
- .dt_node_name = "ldo4",
|
|
- .voltage_table = ldo4_voltage_table,
|
|
- .voltage_table_size = ARRAY_SIZE(ldo4_voltage_table),
|
|
- .control_reg = LDO4_CONTROL_REG,
|
|
- .low_power_reg = LDO4_PWRCTRL_REG,
|
|
- },
|
|
- {
|
|
- .dt_node_name = "ldo5",
|
|
- .voltage_table = ldo5_voltage_table,
|
|
- .voltage_table_size = ARRAY_SIZE(ldo5_voltage_table),
|
|
- .control_reg = LDO5_CONTROL_REG,
|
|
- .low_power_reg = LDO5_PWRCTRL_REG,
|
|
- },
|
|
- {
|
|
- .dt_node_name = "ldo6",
|
|
- .voltage_table = ldo6_voltage_table,
|
|
- .voltage_table_size = ARRAY_SIZE(ldo6_voltage_table),
|
|
- .control_reg = LDO6_CONTROL_REG,
|
|
- .low_power_reg = LDO6_PWRCTRL_REG,
|
|
- },
|
|
- {
|
|
- .dt_node_name = "vref_ddr",
|
|
- .voltage_table = vref_ddr_voltage_table,
|
|
- .voltage_table_size = ARRAY_SIZE(vref_ddr_voltage_table),
|
|
- .control_reg = VREF_DDR_CONTROL_REG,
|
|
- .low_power_reg = VREF_DDR_PWRCTRL_REG,
|
|
- },
|
|
-};
|
|
-
|
|
-#define MAX_REGUL ARRAY_SIZE(regulators_table)
|
|
-
|
|
-static const struct regul_struct *stpmu1_get_regulator_data(const char *name)
|
|
-{
|
|
- uint8_t i;
|
|
-
|
|
- for (i = 0 ; i < MAX_REGUL ; i++) {
|
|
- if (strncmp(name, regulators_table[i].dt_node_name,
|
|
- strlen(regulators_table[i].dt_node_name)) == 0) {
|
|
- return ®ulators_table[i];
|
|
- }
|
|
- }
|
|
-
|
|
- /* Regulator not found */
|
|
- panic();
|
|
- return NULL;
|
|
-}
|
|
-
|
|
-static uint8_t stpmu1_voltage_find_index(const char *name,
|
|
- uint16_t millivolts)
|
|
-{
|
|
- const struct regul_struct *regul = stpmu1_get_regulator_data(name);
|
|
- uint8_t i;
|
|
-
|
|
- for (i = 0 ; i < regul->voltage_table_size ; i++) {
|
|
- if (regul->voltage_table[i] == millivolts) {
|
|
- return i;
|
|
- }
|
|
- }
|
|
-
|
|
- /* Voltage not found */
|
|
- panic();
|
|
-
|
|
- return 0;
|
|
-}
|
|
-
|
|
-int stpmu1_switch_off(void)
|
|
-{
|
|
- return stpmu1_register_update(MAIN_CONTROL_REG, 1,
|
|
- SOFTWARE_SWITCH_OFF_ENABLED);
|
|
-}
|
|
-
|
|
-int stpmu1_regulator_enable(const char *name)
|
|
-{
|
|
- const struct regul_struct *regul = stpmu1_get_regulator_data(name);
|
|
-
|
|
- return stpmu1_register_update(regul->control_reg, BIT(0), BIT(0));
|
|
-}
|
|
-
|
|
-int stpmu1_regulator_disable(const char *name)
|
|
-{
|
|
- const struct regul_struct *regul = stpmu1_get_regulator_data(name);
|
|
-
|
|
- return stpmu1_register_update(regul->control_reg, 0, BIT(0));
|
|
-}
|
|
-
|
|
-uint8_t stpmu1_is_regulator_enabled(const char *name)
|
|
-{
|
|
- uint8_t val;
|
|
- const struct regul_struct *regul = stpmu1_get_regulator_data(name);
|
|
-
|
|
- if (stpmu1_register_read(regul->control_reg, &val) != 0) {
|
|
- panic();
|
|
- }
|
|
-
|
|
- return (val & 0x1U);
|
|
-}
|
|
-
|
|
-int stpmu1_regulator_voltage_set(const char *name, uint16_t millivolts)
|
|
-{
|
|
- uint8_t voltage_index = stpmu1_voltage_find_index(name, millivolts);
|
|
- const struct regul_struct *regul = stpmu1_get_regulator_data(name);
|
|
-
|
|
- return stpmu1_register_update(regul->control_reg, voltage_index << 2,
|
|
- 0xFC);
|
|
-}
|
|
-
|
|
-int stpmu1_register_read(uint8_t register_id, uint8_t *value)
|
|
-{
|
|
- return stm32_i2c_mem_read(stpmu_i2c_handle, stpmu_i2c_addr,
|
|
- (uint16_t)register_id, I2C_MEMADD_SIZE_8BIT,
|
|
- value, 1, 100000);
|
|
-}
|
|
-
|
|
-int stpmu1_register_write(uint8_t register_id, uint8_t value)
|
|
-{
|
|
- int status;
|
|
-
|
|
- status = stm32_i2c_mem_write(stpmu_i2c_handle, stpmu_i2c_addr,
|
|
- (uint16_t)register_id,
|
|
- I2C_MEMADD_SIZE_8BIT, &value, 1, 100000);
|
|
-
|
|
- if (status != 0) {
|
|
- return status;
|
|
- }
|
|
-
|
|
- if ((register_id != WATCHDOG_CONTROL_REG) && (register_id <= 0x40U)) {
|
|
- uint8_t readval;
|
|
-
|
|
- status = stpmu1_register_read(register_id, &readval);
|
|
- if (status != 0) {
|
|
- return status;
|
|
- }
|
|
-
|
|
- if (readval != value) {
|
|
- return -1;
|
|
- }
|
|
- }
|
|
-
|
|
- return 0;
|
|
-}
|
|
-
|
|
-int stpmu1_register_update(uint8_t register_id, uint8_t value, uint8_t mask)
|
|
-{
|
|
- int status;
|
|
- uint8_t val;
|
|
-
|
|
- status = stpmu1_register_read(register_id, &val);
|
|
- if (status != 0) {
|
|
- return status;
|
|
- }
|
|
-
|
|
- /* Clear bits to update */
|
|
- val &= ~mask;
|
|
-
|
|
- /* Update appropriate bits*/
|
|
- val |= (value & mask);
|
|
-
|
|
- /* Send new value on I2C Bus */
|
|
- return stpmu1_register_write(register_id, val);
|
|
-}
|
|
-
|
|
-void stpmu1_bind_i2c(struct i2c_handle_s *i2c_handle, uint16_t i2c_addr)
|
|
-{
|
|
- stpmu_i2c_handle = i2c_handle;
|
|
- stpmu_i2c_addr = i2c_addr;
|
|
-}
|
|
diff --git a/drivers/st/qspi/io_qspi.c b/drivers/st/qspi/io_qspi.c
|
|
new file mode 100644
|
|
index 0000000..b00b7d6
|
|
--- /dev/null
|
|
+++ b/drivers/st/qspi/io_qspi.c
|
|
@@ -0,0 +1,349 @@
|
|
+/*
|
|
+ * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved.
|
|
+ *
|
|
+ * SPDX-License-Identifier: BSD-3-Clause
|
|
+ */
|
|
+
|
|
+#include <assert.h>
|
|
+#include <debug.h>
|
|
+#include <io_driver.h>
|
|
+#include <io_qspi.h>
|
|
+#include <io_storage.h>
|
|
+#include <libfdt.h>
|
|
+#include <mmio.h>
|
|
+#include <platform.h>
|
|
+#include <platform_def.h>
|
|
+#include <stm32mp_common.h>
|
|
+#include <stm32mp_dt.h>
|
|
+#include <string.h>
|
|
+
|
|
+#define QSPI_COMPAT "st,stm32f469-qspi"
|
|
+
|
|
+#define TIMEOUT_100_US us2tick(100)
|
|
+
|
|
+/* QSPI device functions */
|
|
+static int qspi_dev_open(const uintptr_t init_params,
|
|
+ io_dev_info_t **dev_info);
|
|
+static int qspi_block_open(io_dev_info_t *dev_info, const uintptr_t spec,
|
|
+ io_entity_t *entity);
|
|
+static int qspi_dev_init(io_dev_info_t *dev_info, const uintptr_t init_params);
|
|
+static int qspi_block_seek(io_entity_t *entity, int mode,
|
|
+ signed long long offset);
|
|
+static int qspi_block_read(io_entity_t *entity, uintptr_t buffer,
|
|
+ size_t length, size_t *length_read);
|
|
+static int qspi_block_close(io_entity_t *entity);
|
|
+static int qspi_dev_close(io_dev_info_t *dev_info);
|
|
+static io_type_t device_type_qspi(void);
|
|
+
|
|
+static QSPI_HandleTypeDef *hsd;
|
|
+static uint64_t seek_offset;
|
|
+
|
|
+static struct dt_node_info qspi_node_info;
|
|
+static uintptr_t qspi_mm_base;
|
|
+static size_t qspi_mm_size;
|
|
+static bool qspi_memory_map;
|
|
+
|
|
+static const io_dev_connector_t qspi_dev_connector = {
|
|
+ .dev_open = qspi_dev_open
|
|
+};
|
|
+
|
|
+static const io_dev_funcs_t qspi_dev_funcs = {
|
|
+ .type = device_type_qspi,
|
|
+ .open = qspi_block_open,
|
|
+ .seek = qspi_block_seek,
|
|
+ .size = NULL,
|
|
+ .read = qspi_block_read,
|
|
+ .write = NULL,
|
|
+ .close = qspi_block_close,
|
|
+ .dev_init = qspi_dev_init,
|
|
+ .dev_close = qspi_dev_close,
|
|
+};
|
|
+
|
|
+static const io_dev_info_t qspi_dev_info = {
|
|
+ .funcs = &qspi_dev_funcs,
|
|
+ .info = (uintptr_t)0,
|
|
+};
|
|
+
|
|
+/* Identify the device type as memmap */
|
|
+static io_type_t device_type_qspi(void)
|
|
+{
|
|
+ return IO_TYPE_QSPI;
|
|
+}
|
|
+
|
|
+/* Open a connection to the qspi device */
|
|
+static int qspi_dev_open(const uintptr_t init_params, io_dev_info_t **dev_info)
|
|
+{
|
|
+ int qspi_node;
|
|
+ int qspi_subnode = 0;
|
|
+ int ret;
|
|
+ uint32_t fsize;
|
|
+ uint32_t flash_max_freq = 0;
|
|
+ uint32_t div = 8U; /* Default clock divider */
|
|
+ uint32_t presc;
|
|
+ void *fdt;
|
|
+ const fdt32_t *cuint = NULL;
|
|
+
|
|
+ assert(dev_info);
|
|
+
|
|
+ if (fdt_get_address(&fdt) == 0) {
|
|
+ panic();
|
|
+ }
|
|
+
|
|
+ hsd = (QSPI_HandleTypeDef *)init_params;
|
|
+
|
|
+ qspi_node = dt_get_node(&qspi_node_info, -1, QSPI_COMPAT);
|
|
+ assert(qspi_node_info.base == (uintptr_t)hsd->instance);
|
|
+
|
|
+ *dev_info = (io_dev_info_t *)&qspi_dev_info;
|
|
+
|
|
+ ret = fdt_get_reg_props_by_name(qspi_node, "qspi_mm", &qspi_mm_base,
|
|
+ &qspi_mm_size);
|
|
+ if (ret != 0) {
|
|
+ INFO("NOR: Indirect mode\n");
|
|
+ qspi_memory_map = false;
|
|
+
|
|
+ /*
|
|
+ * Indirect mode is already initialized by bootrom:
|
|
+ * no configuration to be done.
|
|
+ */
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ /* Size of NOR is 2^(fsise + 1) */
|
|
+ fsize = ((__builtin_ctz(qspi_mm_size) - 1) << QSPI_DCR_FSIZE_SHIFT) &
|
|
+ QSPI_DCR_FSIZE_MASK;
|
|
+
|
|
+ /* switch to memory mapped mode */
|
|
+ INFO("NOR: Memory mapped mode\n");
|
|
+ qspi_memory_map = true;
|
|
+
|
|
+ fdt_for_each_subnode(qspi_subnode, fdt, qspi_node) {
|
|
+ cuint = fdt_getprop(fdt, qspi_subnode, "reg", NULL);
|
|
+
|
|
+ if ((cuint != NULL) && (fdt32_to_cpu(*cuint) == 0U)) {
|
|
+ /* Flash node found */
|
|
+ cuint = fdt_getprop(fdt, qspi_subnode,
|
|
+ "spi-max-frequency", NULL);
|
|
+ if (cuint != NULL) {
|
|
+ flash_max_freq = fdt32_to_cpu(*cuint);
|
|
+ }
|
|
+
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (flash_max_freq != 0) {
|
|
+ div = div_round_up(stm32mp_clk_get_rate(qspi_node_info.clock),
|
|
+ flash_max_freq);
|
|
+ }
|
|
+
|
|
+ presc = div - 1U;
|
|
+
|
|
+ if (presc > UINT8_MAX) {
|
|
+ presc = UINT8_MAX;
|
|
+ }
|
|
+
|
|
+ presc <<= QSPI_CR_PRESCALER_SHIFT;
|
|
+
|
|
+ /* Check if QuadSPI was configured in dual flash mode */
|
|
+ if ((hsd->instance->CR & QSPI_CR_DFM) != 0U) {
|
|
+ hsd->instance->CR = QSPI_CR_EN | presc | QSPI_CR_DFM;
|
|
+ if (hsd->is_dual == 0U) {
|
|
+ WARN("Dual NOR configured in IP\n");
|
|
+ WARN(" but set as single in boot context\n");
|
|
+ WARN(" -> Try Dual NOR boot\n");
|
|
+ }
|
|
+ } else {
|
|
+ hsd->instance->CR = QSPI_CR_EN | presc;
|
|
+ if (hsd->is_dual != 0U) {
|
|
+ WARN("Single NOR configured in IP\n");
|
|
+ WARN(" but set as dual in boot context\n");
|
|
+ WARN(" -> Try Single NOR boot\n");
|
|
+ }
|
|
+ }
|
|
+
|
|
+ hsd->instance->DCR = fsize | QSPI_DCR_CSHT;
|
|
+ hsd->instance->CCR = QSPI_DFLT_READ_FLAGS | QSPI_CCR_FMODE_MM;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int qspi_dev_init(io_dev_info_t *dev_info, const uintptr_t init_params)
|
|
+{
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/* Close a connection to the qspi device */
|
|
+static int qspi_dev_close(io_dev_info_t *dev_info)
|
|
+{
|
|
+ uint64_t start;
|
|
+
|
|
+ /* Send Abort command to end all transfers */
|
|
+ hsd->instance->CR |= QSPI_CR_ABORT;
|
|
+
|
|
+ start = timeout_start();
|
|
+ while ((hsd->instance->CR & QSPI_CR_ABORT) != 0U) {
|
|
+ if (timeout_elapsed(start, TIMEOUT_100_US)) {
|
|
+ return -ETIMEDOUT;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/* Open a file on the qspi device */
|
|
+static int qspi_block_open(io_dev_info_t *dev_info, const uintptr_t spec,
|
|
+ io_entity_t *entity)
|
|
+{
|
|
+ seek_offset = 0;
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/* Seek to a particular file offset on the qspi device */
|
|
+static int qspi_block_seek(io_entity_t *entity, int mode,
|
|
+ signed long long offset)
|
|
+{
|
|
+ seek_offset = offset;
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/* Read blocks in indirect mode */
|
|
+static int qspi_block_read_indr(io_entity_t *entity, uintptr_t buffer,
|
|
+ size_t length, size_t *length_read)
|
|
+{
|
|
+ uint32_t local_length = (uint32_t)length;
|
|
+ uint8_t *data = (uint8_t *)buffer;
|
|
+ uint8_t *qspi_dr_u8;
|
|
+ uint64_t start;
|
|
+ int ret = 0;
|
|
+
|
|
+ assert(hsd);
|
|
+
|
|
+ qspi_dr_u8 = (uint8_t *)&hsd->instance->DR;
|
|
+
|
|
+ /* Clear all flags */
|
|
+ hsd->instance->FCR = QSPI_SR_TCF | QSPI_SR_FTF |
|
|
+ QSPI_FCR_CTOF | QSPI_FCR_CSMF;
|
|
+ hsd->instance->DLR = local_length - 1;
|
|
+ hsd->instance->CCR = QSPI_DFLT_READ_FLAGS | QSPI_CCR_FMODE;
|
|
+ hsd->instance->AR = seek_offset;
|
|
+
|
|
+ while (local_length != 0U) {
|
|
+ *data++ = *qspi_dr_u8;
|
|
+ local_length--;
|
|
+ }
|
|
+
|
|
+ *length_read = length;
|
|
+
|
|
+ start = timeout_start();
|
|
+ while ((hsd->instance->SR & QSPI_SR_BUSY) != 0U) {
|
|
+ if (timeout_elapsed(start, TIMEOUT_100_US)) {
|
|
+ ret = -ETIMEDOUT;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static int qspi_block_read_mm_part(io_entity_t *entity, uintptr_t buffer,
|
|
+ size_t length, size_t *length_read)
|
|
+{
|
|
+ uint64_t start;
|
|
+ int ret = 0;
|
|
+
|
|
+ assert(hsd);
|
|
+
|
|
+ memcpy((uint8_t *)buffer, (uint8_t *)qspi_mm_base + seek_offset,
|
|
+ length);
|
|
+
|
|
+ *length_read = length;
|
|
+
|
|
+ start = timeout_start();
|
|
+ while ((hsd->instance->SR & QSPI_SR_BUSY) != 0U) {
|
|
+ if (timeout_elapsed(start, TIMEOUT_100_US)) {
|
|
+ ret = -ETIMEDOUT;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /* Send abort to avoid prefetch issues */
|
|
+ hsd->instance->CR |= QSPI_CR_ABORT;
|
|
+
|
|
+ start = timeout_start();
|
|
+ while ((hsd->instance->CR & QSPI_CR_ABORT) != 0U) {
|
|
+ if (timeout_elapsed(start, TIMEOUT_100_US)) {
|
|
+ ret = -ETIMEDOUT;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return ret;
|
|
+
|
|
+}
|
|
+
|
|
+/* Read blocks in memory map mode */
|
|
+static int qspi_block_read_mm(io_entity_t *entity, uintptr_t buffer,
|
|
+ size_t length, size_t *length_read)
|
|
+{
|
|
+ if (seek_offset + length + 1 >= qspi_mm_size) {
|
|
+ if (length > QSPI_NOR_LBA_SIZE) {
|
|
+ size_t length_read_mm, length_read_indr;
|
|
+
|
|
+ qspi_block_read_mm_part(entity, buffer,
|
|
+ length - QSPI_NOR_LBA_SIZE,
|
|
+ &length_read_mm);
|
|
+
|
|
+ seek_offset += length - QSPI_NOR_LBA_SIZE;
|
|
+
|
|
+ qspi_block_read_indr(entity, buffer + length -
|
|
+ QSPI_NOR_LBA_SIZE,
|
|
+ QSPI_NOR_LBA_SIZE,
|
|
+ &length_read_indr);
|
|
+
|
|
+ *length_read = length_read_mm + length_read_indr;
|
|
+ } else {
|
|
+ qspi_block_read_indr(entity, buffer, length,
|
|
+ length_read);
|
|
+ }
|
|
+ } else {
|
|
+ qspi_block_read_mm_part(entity, buffer, length, length_read);
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+
|
|
+}
|
|
+
|
|
+/* Read data from a file on the qspi device */
|
|
+static int qspi_block_read(io_entity_t *entity, uintptr_t buffer,
|
|
+ size_t length, size_t *length_read)
|
|
+{
|
|
+ if (qspi_memory_map) {
|
|
+ return qspi_block_read_mm(entity, buffer, length, length_read);
|
|
+ }
|
|
+
|
|
+ return qspi_block_read_indr(entity, buffer, length, length_read);
|
|
+}
|
|
+
|
|
+/* Close a file on the qspi device */
|
|
+static int qspi_block_close(io_entity_t *entity)
|
|
+{
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/* Exported functions */
|
|
+
|
|
+/* Register the qspi driver with the IO abstraction */
|
|
+int register_io_dev_qspi(const io_dev_connector_t **dev_con)
|
|
+{
|
|
+ int result;
|
|
+
|
|
+ assert(dev_con);
|
|
+
|
|
+ result = io_register_device(&qspi_dev_info);
|
|
+ if (result == 0) {
|
|
+ *dev_con = &qspi_dev_connector;
|
|
+ }
|
|
+
|
|
+ return result;
|
|
+}
|
|
diff --git a/drivers/st/reset/stm32mp1_reset.c b/drivers/st/reset/stm32mp1_reset.c
|
|
index 106bbfe..2e19ef0 100644
|
|
--- a/drivers/st/reset/stm32mp1_reset.c
|
|
+++ b/drivers/st/reset/stm32mp1_reset.c
|
|
@@ -6,34 +6,66 @@
|
|
|
|
#include <bl_common.h>
|
|
#include <debug.h>
|
|
+#include <delay_timer.h>
|
|
#include <limits.h>
|
|
#include <mmio.h>
|
|
#include <platform_def.h>
|
|
-#include <stm32mp1_rcc.h>
|
|
-#include <stm32mp1_reset.h>
|
|
+#include <stm32mp_common.h>
|
|
+#include <stm32mp_reset.h>
|
|
#include <utils_def.h>
|
|
|
|
-#define RST_CLR_OFFSET 4U
|
|
+#define RST_CLR_OFFSET 4U
|
|
+#define RESET_TIMEOUT_1MS_IN_US 1000
|
|
+#define RESET_TIMEOUT_STEP_US 10
|
|
|
|
-void stm32mp1_reset_assert(uint32_t id)
|
|
+static uint32_t id2reg_offset(unsigned int reset_id)
|
|
{
|
|
- uint32_t offset = (id / (uint32_t)__LONG_BIT) * sizeof(uintptr_t);
|
|
- uint32_t bit = id % (uint32_t)__LONG_BIT;
|
|
+ return ((reset_id & GENMASK(31, 5)) >> 5) * sizeof(uint32_t);
|
|
+}
|
|
+
|
|
+static uint8_t id2reg_bit_pos(unsigned int reset_id)
|
|
+{
|
|
+ return (uint8_t)(reset_id & GENMASK(4, 0));
|
|
+}
|
|
+
|
|
+void stm32mp_reset_assert(uint32_t id)
|
|
+{
|
|
+ uint32_t offset = id2reg_offset(id);
|
|
+ uint32_t bitmsk = BIT(id2reg_bit_pos(id));
|
|
+ int nb_tries = RESET_TIMEOUT_1MS_IN_US / RESET_TIMEOUT_STEP_US;
|
|
+ uintptr_t rcc_base = stm32mp_rcc_base();
|
|
|
|
- mmio_write_32(RCC_BASE + offset, BIT(bit));
|
|
- while ((mmio_read_32(RCC_BASE + offset) & BIT(bit)) == 0U) {
|
|
- ;
|
|
+ mmio_write_32(rcc_base + offset, bitmsk);
|
|
+
|
|
+ while (((mmio_read_32(rcc_base + offset) & bitmsk) == 0U) &&
|
|
+ (nb_tries != 0)) {
|
|
+ udelay(RESET_TIMEOUT_STEP_US);
|
|
+ nb_tries--;
|
|
+ }
|
|
+
|
|
+ if (nb_tries == 0) {
|
|
+ ERROR("Reset timeout\n");
|
|
+ panic();
|
|
}
|
|
}
|
|
|
|
-void stm32mp1_reset_deassert(uint32_t id)
|
|
+void stm32mp_reset_deassert(uint32_t id)
|
|
{
|
|
- uint32_t offset = ((id / (uint32_t)__LONG_BIT) * sizeof(uintptr_t)) +
|
|
- RST_CLR_OFFSET;
|
|
- uint32_t bit = id % (uint32_t)__LONG_BIT;
|
|
+ uint32_t offset = id2reg_offset(id) + RST_CLR_OFFSET;
|
|
+ uint32_t bitmsk = BIT(id2reg_bit_pos(id));
|
|
+ int nb_tries = RESET_TIMEOUT_1MS_IN_US / RESET_TIMEOUT_STEP_US;
|
|
+ uintptr_t rcc_base = stm32mp_rcc_base();
|
|
+
|
|
+ mmio_write_32(rcc_base + offset, bitmsk);
|
|
+
|
|
+ while (((mmio_read_32(rcc_base + offset) & bitmsk) != 0U) &&
|
|
+ (nb_tries != 0)) {
|
|
+ udelay(RESET_TIMEOUT_STEP_US);
|
|
+ nb_tries--;
|
|
+ }
|
|
|
|
- mmio_write_32(RCC_BASE + offset, BIT(bit));
|
|
- while ((mmio_read_32(RCC_BASE + offset) & BIT(bit)) != 0U) {
|
|
- ;
|
|
+ if (nb_tries == 0) {
|
|
+ ERROR("Reset timeout\n");
|
|
+ panic();
|
|
}
|
|
}
|
|
diff --git a/drivers/st/rng/stm32_rng.c b/drivers/st/rng/stm32_rng.c
|
|
new file mode 100644
|
|
index 0000000..eec75b2
|
|
--- /dev/null
|
|
+++ b/drivers/st/rng/stm32_rng.c
|
|
@@ -0,0 +1,191 @@
|
|
+/*
|
|
+ * Copyright (c) 2018, STMicroelectronics - All Rights Reserved
|
|
+ *
|
|
+ * SPDX-License-Identifier: BSD-3-Clause
|
|
+ */
|
|
+
|
|
+#include <arch_helpers.h>
|
|
+#include <assert.h>
|
|
+#include <delay_timer.h>
|
|
+#include <errno.h>
|
|
+#include <libfdt.h>
|
|
+#include <mmio.h>
|
|
+#include <platform_def.h>
|
|
+#include <stdbool.h>
|
|
+#include <stm32_rng.h>
|
|
+#include <stm32mp_dt.h>
|
|
+#include <stm32mp_reset.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
|
|
+
|
|
+struct stm32_rng_instance {
|
|
+ uintptr_t base;
|
|
+ unsigned long clock;
|
|
+};
|
|
+
|
|
+static struct stm32_rng_instance stm32_rng;
|
|
+
|
|
+/*
|
|
+ * stm32_rng_read - Read a number of random bytes from RNG
|
|
+ * out: pointer to the output buffer
|
|
+ * size: number of bytes to be read
|
|
+ * Return 0 on success, non-0 on failure
|
|
+ */
|
|
+int stm32_rng_read(uint8_t *out, uint32_t size)
|
|
+{
|
|
+ uint8_t *buf = out;
|
|
+ uint32_t len = size;
|
|
+ int nb_tries;
|
|
+ uint32_t data32;
|
|
+ int rc = 0;
|
|
+ int count;
|
|
+
|
|
+ if (stm32_rng.base == 0U) {
|
|
+ return -EPERM;
|
|
+ }
|
|
+
|
|
+ stm32mp_clk_enable(stm32_rng.clock);
|
|
+
|
|
+ if ((mmio_read_32(stm32_rng.base + RNG_CR) & RNG_CR_RNGEN) == 0U) {
|
|
+ mmio_write_32(stm32_rng.base + RNG_CR,
|
|
+ RNG_CR_RNGEN | RNG_CR_CED);
|
|
+ }
|
|
+
|
|
+ while (len != 0U) {
|
|
+ nb_tries = RNG_TIMEOUT_US / RNG_TIMEOUT_STEP_US;
|
|
+ do {
|
|
+ uint32_t status = mmio_read_32(stm32_rng.base + RNG_SR);
|
|
+
|
|
+ if ((status & (RNG_SR_SECS | RNG_SR_SEIS)) != 0U) {
|
|
+ uint8_t i;
|
|
+
|
|
+ /* Recommended by the SoC reference manual */
|
|
+ mmio_clrbits_32(stm32_rng.base + RNG_SR,
|
|
+ RNG_SR_SEIS);
|
|
+ dmb();
|
|
+ for (i = 12; i != 0; i--) {
|
|
+ (void)mmio_read_32(stm32_rng.base +
|
|
+ RNG_DR);
|
|
+ }
|
|
+ dmb();
|
|
+
|
|
+ if ((mmio_read_32(stm32_rng.base + RNG_SR) &
|
|
+ RNG_SR_SEIS) != 0U) {
|
|
+ ERROR("RNG noise\n");
|
|
+ panic();
|
|
+ }
|
|
+ }
|
|
+
|
|
+ udelay(RNG_TIMEOUT_STEP_US);
|
|
+ nb_tries--;
|
|
+ if (nb_tries == 0) {
|
|
+ rc = -ETIMEDOUT;
|
|
+ goto bail;
|
|
+ }
|
|
+ } while ((mmio_read_32(stm32_rng.base + RNG_SR) &
|
|
+ RNG_SR_DRDY) == 0U);
|
|
+
|
|
+ count = 4;
|
|
+ while (len != 0U) {
|
|
+ data32 = mmio_read_32(stm32_rng.base + RNG_DR);
|
|
+ count--;
|
|
+
|
|
+ memcpy(buf, &data32, MIN(len, sizeof(uint32_t)));
|
|
+ buf += MIN(len, sizeof(uint32_t));
|
|
+ len -= MIN(len, sizeof(uint32_t));
|
|
+
|
|
+ if (count == 0) {
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+bail:
|
|
+ stm32mp_clk_disable(stm32_rng.clock);
|
|
+
|
|
+ if (rc != 0) {
|
|
+ memset(out, 0, buf - out);
|
|
+ }
|
|
+
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * stm32_rng_init: Initialize rng from DT
|
|
+ * return 0 on success, negative value on failure
|
|
+ */
|
|
+int stm32_rng_init(void)
|
|
+{
|
|
+ void *fdt;
|
|
+ struct dt_node_info dt_rng;
|
|
+ int node;
|
|
+ uint8_t __unused test[43];
|
|
+
|
|
+ if (fdt_get_address(&fdt) == 0) {
|
|
+ panic();
|
|
+ }
|
|
+
|
|
+ node = dt_get_node(&dt_rng, -1, DT_RNG_COMPAT);
|
|
+ if (node < 0) {
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ if ((dt_rng.status & DT_SECURE) == 0) {
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ assert(dt_rng.base == RNG1_BASE);
|
|
+
|
|
+ stm32_rng.base = dt_rng.base;
|
|
+
|
|
+ if ((dt_rng.status & DT_NON_SECURE) == DT_NON_SECURE) {
|
|
+ stm32mp_register_non_secure_periph_iomem(stm32_rng.base);
|
|
+ } else {
|
|
+ stm32mp_register_secure_periph_iomem(stm32_rng.base);
|
|
+ }
|
|
+
|
|
+ if (dt_rng.clock < 0) {
|
|
+ panic();
|
|
+ }
|
|
+ stm32_rng.clock = (unsigned long)dt_rng.clock;
|
|
+
|
|
+ stm32mp_clk_enable(stm32_rng.clock);
|
|
+ stm32mp_clk_disable(stm32_rng.clock);
|
|
+
|
|
+ if (dt_rng.reset >= 0) {
|
|
+ stm32mp_reset_assert((unsigned long)dt_rng.reset);
|
|
+ udelay(20);
|
|
+ stm32mp_reset_deassert((unsigned long)dt_rng.reset);
|
|
+ }
|
|
+
|
|
+ VERBOSE("Init RNG done\n");
|
|
+
|
|
+#if STM32MP1_DEBUG_ENABLE
|
|
+ memset(test, 0xa5, sizeof(test));
|
|
+ if (stm32_rng_read(test, sizeof(test))) {
|
|
+ ERROR("RNG test\n");
|
|
+ panic();
|
|
+ }
|
|
+
|
|
+ VERBOSE("RNG test:\n");
|
|
+ VERBOSE_HEXDUMP8(test, sizeof(test));
|
|
+#endif
|
|
+
|
|
+ return 0;
|
|
+}
|
|
diff --git a/drivers/st/rtc/stm32_rtc.c b/drivers/st/rtc/stm32_rtc.c
|
|
new file mode 100644
|
|
index 0000000..017c46d
|
|
--- /dev/null
|
|
+++ b/drivers/st/rtc/stm32_rtc.c
|
|
@@ -0,0 +1,499 @@
|
|
+/*
|
|
+ * Copyright (c) 2018, STMicroelectronics - All Rights Reserved
|
|
+ *
|
|
+ * SPDX-License-Identifier: BSD-3-Clause
|
|
+ */
|
|
+
|
|
+#include <arch_helpers.h>
|
|
+#include <assert.h>
|
|
+#include <debug.h>
|
|
+#include <mmio.h>
|
|
+#include <platform_def.h>
|
|
+#include <spinlock.h>
|
|
+#include <stm32_rtc.h>
|
|
+#include <stm32mp_clkfunc.h>
|
|
+#include <stm32mp_dt.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)
|
|
+{
|
|
+ const uint32_t mask = SCTLR_M_BIT | SCTLR_C_BIT;
|
|
+
|
|
+ /* Lock is currently required only when MMU and cache are enabled */
|
|
+ if ((read_sctlr() & mask) == mask) {
|
|
+ spin_lock(&lock);
|
|
+ }
|
|
+}
|
|
+
|
|
+void stm32_rtc_regs_unlock(void)
|
|
+{
|
|
+ const uint32_t mask = SCTLR_M_BIT | SCTLR_C_BIT;
|
|
+
|
|
+ /* Unlock is required only when MMU and cache are enabled */
|
|
+ if ((read_sctlr() & mask) == mask) {
|
|
+ spin_unlock(&lock);
|
|
+ }
|
|
+}
|
|
+
|
|
+static void stm32_rtc_write_unprotect(void)
|
|
+{
|
|
+ mmio_write_32(rtc_dev.base + RTC_WPR, RTC_WPR_KEY1);
|
|
+ mmio_write_32(rtc_dev.base + RTC_WPR, RTC_WPR_KEY2);
|
|
+}
|
|
+
|
|
+static void stm32_rtc_write_protect(void)
|
|
+{
|
|
+ mmio_write_32(rtc_dev.base + RTC_WPR, RTC_WPR_KEY_LOCK);
|
|
+}
|
|
+
|
|
+/*******************************************************************************
|
|
+ * This function gets the BYPSHAD bit value of the RTC_CR register.
|
|
+ * It will determine if we need to reset RTC_ISCR.RSF after each RTC calendar
|
|
+ * read, and also wait for RTC_ISCR.RSF=1 before next read.
|
|
+ * Returns true or false depending on the bit value.
|
|
+ ******************************************************************************/
|
|
+static bool stm32_rtc_get_bypshad(void)
|
|
+{
|
|
+ return ((mmio_read_32(rtc_dev.base + RTC_CR) & RTC_CR_BYPSHAD) >>
|
|
+ RTC_CR_BYPSHAD_SHIFT) != 0U;
|
|
+}
|
|
+
|
|
+/*******************************************************************************
|
|
+ * This function reads the RTC calendar register values.
|
|
+ * If shadow registers are not bypassed, then a reset/poll is done.
|
|
+ ******************************************************************************/
|
|
+static void stm32_rtc_read_calendar(struct stm32_rtc_calendar *calendar)
|
|
+{
|
|
+ bool bypshad = stm32_rtc_get_bypshad();
|
|
+
|
|
+ if (!bypshad) {
|
|
+ mmio_clrbits_32((uint32_t)(rtc_dev.base + RTC_ICSR),
|
|
+ RTC_ICSR_RSF);
|
|
+ while ((mmio_read_32(rtc_dev.base + RTC_ICSR) & RTC_ICSR_RSF) !=
|
|
+ RTC_ICSR_RSF) {
|
|
+ ;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ calendar->ssr = mmio_read_32(rtc_dev.base + RTC_SSR);
|
|
+ calendar->tr = mmio_read_32(rtc_dev.base + RTC_TR);
|
|
+ calendar->dr = mmio_read_32(rtc_dev.base + RTC_DR);
|
|
+}
|
|
+
|
|
+/*******************************************************************************
|
|
+ * This function fill the rtc_time structure based on rtc_calendar register.
|
|
+ ******************************************************************************/
|
|
+static void stm32_rtc_get_time(struct stm32_rtc_calendar *cal,
|
|
+ struct stm32_rtc_time *tm)
|
|
+{
|
|
+ assert(cal != NULL);
|
|
+ assert(tm != NULL);
|
|
+
|
|
+ tm->hour = (((cal->tr & RTC_TR_HT_MASK) >> RTC_TR_HT_SHIFT) * 10U) +
|
|
+ ((cal->tr & RTC_TR_HU_MASK) >> RTC_TR_HU_SHIFT);
|
|
+
|
|
+ if ((cal->tr & RTC_TR_PM) != 0U) {
|
|
+ tm->hour += 12U;
|
|
+ }
|
|
+
|
|
+ tm->min = (((cal->tr & RTC_TR_MNT_MASK) >> RTC_TR_MNT_SHIFT) * 10U) +
|
|
+ ((cal->tr & RTC_TR_MNU_MASK) >> RTC_TR_MNU_SHIFT);
|
|
+ tm->sec = (((cal->tr & RTC_TR_ST_MASK) >> RTC_TR_ST_SHIFT) * 10U) +
|
|
+ (cal->tr & RTC_TR_SU_MASK);
|
|
+}
|
|
+
|
|
+/*******************************************************************************
|
|
+ * This function fill the rtc_time structure with the given date register.
|
|
+ ******************************************************************************/
|
|
+static void stm32_rtc_get_date(struct stm32_rtc_calendar *cal,
|
|
+ struct stm32_rtc_time *tm)
|
|
+{
|
|
+ assert(cal != NULL);
|
|
+ assert(tm != NULL);
|
|
+
|
|
+ tm->wday = (((cal->dr & RTC_DR_WDU_MASK) >> RTC_DR_WDU_SHIFT));
|
|
+
|
|
+ tm->day = (((cal->dr & RTC_DR_DT_MASK) >> RTC_DR_DT_SHIFT) * 10U) +
|
|
+ (cal->dr & RTC_DR_DU_MASK);
|
|
+
|
|
+ tm->month = (((cal->dr & RTC_DR_MT) >> RTC_DR_MT_SHIFT) * 10U) +
|
|
+ ((cal->dr & RTC_DR_MU_MASK) >> RTC_DR_MU_SHIFT);
|
|
+
|
|
+ tm->year = (((cal->dr & RTC_DR_YT_MASK) >> RTC_DR_YT_SHIFT) * 10U) +
|
|
+ ((cal->dr & RTC_DR_YU_MASK) >> RTC_DR_YU_SHIFT) + 2000U;
|
|
+}
|
|
+
|
|
+/*******************************************************************************
|
|
+ * This function reads the RTC timestamp register values and update time
|
|
+ * structure with the corresponding value.
|
|
+ ******************************************************************************/
|
|
+static void stm32_rtc_read_timestamp(struct stm32_rtc_time *time)
|
|
+{
|
|
+ assert(time != NULL);
|
|
+
|
|
+ struct stm32_rtc_calendar cal_tamp;
|
|
+
|
|
+ cal_tamp.tr = mmio_read_32(rtc_dev.base + RTC_TSTR);
|
|
+ cal_tamp.dr = mmio_read_32(rtc_dev.base + RTC_TSDR);
|
|
+ stm32_rtc_get_time(&cal_tamp, time);
|
|
+ stm32_rtc_get_date(&cal_tamp, time);
|
|
+}
|
|
+
|
|
+/*******************************************************************************
|
|
+ * This function gets the RTC calendar register values.
|
|
+ * It takes into account the need of reading twice or not, depending on
|
|
+ * frequencies previously setted, and the bypass or not of the shadow
|
|
+ * registers. This service is exposed externally.
|
|
+ ******************************************************************************/
|
|
+void stm32_rtc_get_calendar(struct stm32_rtc_calendar *calendar)
|
|
+{
|
|
+ bool read_twice = stm32mp1_rtc_get_read_twice();
|
|
+
|
|
+ stm32_rtc_regs_lock();
|
|
+ stm32mp_clk_enable(rtc_dev.clock);
|
|
+
|
|
+ stm32_rtc_read_calendar(calendar);
|
|
+
|
|
+ if (read_twice) {
|
|
+ uint32_t tr_save = calendar->tr;
|
|
+
|
|
+ stm32_rtc_read_calendar(calendar);
|
|
+
|
|
+ if (calendar->tr != tr_save) {
|
|
+ stm32_rtc_read_calendar(calendar);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ stm32mp_clk_disable(rtc_dev.clock);
|
|
+ stm32_rtc_regs_unlock();
|
|
+}
|
|
+
|
|
+/*******************************************************************************
|
|
+ * This function computes the second fraction in milliseconds.
|
|
+ * The returned value is a uint32_t between 0 and 1000.
|
|
+ ******************************************************************************/
|
|
+static uint32_t stm32_rtc_get_second_fraction(struct stm32_rtc_calendar *cal)
|
|
+{
|
|
+ uint32_t prediv_s = mmio_read_32(rtc_dev.base + RTC_PRER) &
|
|
+ RTC_PRER_PREDIV_S_MASK;
|
|
+ uint32_t ss = cal->ssr & RTC_SSR_SS_MASK;
|
|
+
|
|
+ return ((prediv_s - ss) * 1000U) / (prediv_s + 1U);
|
|
+}
|
|
+
|
|
+/*******************************************************************************
|
|
+ * This function computes the fraction difference between two timestamps.
|
|
+ * Here again the returned value is in milliseconds.
|
|
+ ******************************************************************************/
|
|
+static unsigned long long stm32_rtc_diff_frac(struct stm32_rtc_calendar *cur,
|
|
+ struct stm32_rtc_calendar *ref)
|
|
+{
|
|
+ unsigned long long val_r;
|
|
+ unsigned long long val_c;
|
|
+
|
|
+ val_r = stm32_rtc_get_second_fraction(ref);
|
|
+ val_c = stm32_rtc_get_second_fraction(cur);
|
|
+
|
|
+ if (val_c >= val_r) {
|
|
+ return val_c - val_r;
|
|
+ } else {
|
|
+ return 1000U - val_r + val_c;
|
|
+ }
|
|
+}
|
|
+
|
|
+/*******************************************************************************
|
|
+ * This function computes the time difference between two timestamps.
|
|
+ * It includes seconds, minutes and hours.
|
|
+ * Here again the returned value is in milliseconds.
|
|
+ ******************************************************************************/
|
|
+static unsigned long long stm32_rtc_diff_time(struct stm32_rtc_time *current,
|
|
+ struct stm32_rtc_time *ref)
|
|
+{
|
|
+ signed long long diff_in_s;
|
|
+ signed long long curr_s;
|
|
+ signed long long ref_s;
|
|
+
|
|
+ curr_s = (signed long long)current->sec +
|
|
+ (((signed long long)current->min +
|
|
+ (((signed long long)current->hour * 60))) * 60);
|
|
+
|
|
+ ref_s = (signed long long)ref->sec +
|
|
+ (((signed long long)ref->min +
|
|
+ (((signed long long)ref->hour * 60))) * 60);
|
|
+
|
|
+ diff_in_s = curr_s - ref_s;
|
|
+ if (diff_in_s < 0) {
|
|
+ diff_in_s += 24 * 60 * 60;
|
|
+ }
|
|
+
|
|
+ return (unsigned long long)diff_in_s * 1000U;
|
|
+}
|
|
+
|
|
+/*******************************************************************************
|
|
+ * This function determines if the year is leap or not.
|
|
+ * Returned value is true or false.
|
|
+ ******************************************************************************/
|
|
+static bool stm32_is_a_leap_year(uint32_t year)
|
|
+{
|
|
+ return ((year % 4U) == 0U) &&
|
|
+ (((year % 100U) != 0U) || ((year % 400U) == 0U));
|
|
+}
|
|
+
|
|
+/*******************************************************************************
|
|
+ * This function computes the date difference between two timestamps.
|
|
+ * It includes days, months, years, with exceptions.
|
|
+ * Here again the returned value is in milliseconds.
|
|
+ ******************************************************************************/
|
|
+static unsigned long long stm32_rtc_diff_date(struct stm32_rtc_time *current,
|
|
+ struct stm32_rtc_time *ref)
|
|
+{
|
|
+ uint32_t diff_in_days = 0;
|
|
+ uint32_t m;
|
|
+ static const uint8_t month_len[NB_MONTHS] = {
|
|
+ 31, 28, 31, 30, 31, 30,
|
|
+ 31, 31, 30, 31, 30, 31
|
|
+ };
|
|
+
|
|
+ /* Get the number of non-entire month days */
|
|
+ if (current->day >= ref->day) {
|
|
+ diff_in_days += current->day - ref->day;
|
|
+ } else {
|
|
+ diff_in_days += (uint32_t)month_len[ref->month - 1U] -
|
|
+ ref->day + current->day;
|
|
+ }
|
|
+
|
|
+ /* Get the number of entire months, and compute the related days */
|
|
+ if (current->month > (ref->month + 1U)) {
|
|
+ for (m = (ref->month + 1U); (m < current->month) &&
|
|
+ (m < 12U); m++) {
|
|
+ diff_in_days += (uint32_t)month_len[m - 1U];
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (current->month < (ref->month - 1U)) {
|
|
+ for (m = 1U; (m < current->month) && (m < 12U); m++) {
|
|
+ diff_in_days += (uint32_t)month_len[m - 1U];
|
|
+ }
|
|
+
|
|
+ for (m = (ref->month + 1U); m < 12U; m++) {
|
|
+ diff_in_days += (uint32_t)month_len[m - 1U];
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /* Get complete years */
|
|
+ if (current->year > (ref->year + 1U)) {
|
|
+ diff_in_days += (current->year - ref->year - 1U) * 365U;
|
|
+ }
|
|
+
|
|
+ /* Particular cases: leap years (one day more) */
|
|
+ if (diff_in_days > 0U) {
|
|
+ if (current->year == ref->year) {
|
|
+ if (stm32_is_a_leap_year(current->year)) {
|
|
+ if ((ref->month <= 2U) &&
|
|
+ (current->month >= 3U) &&
|
|
+ (current->day <= 28U)) {
|
|
+ diff_in_days++;
|
|
+ }
|
|
+ }
|
|
+ } else {
|
|
+ uint32_t y;
|
|
+
|
|
+ /* Ref year is leap */
|
|
+ if ((stm32_is_a_leap_year(ref->year)) &&
|
|
+ (ref->month <= 2U) && (ref->day <= 28U)) {
|
|
+ diff_in_days++;
|
|
+ }
|
|
+
|
|
+ /* Current year is leap */
|
|
+ if ((stm32_is_a_leap_year(current->year)) &&
|
|
+ (current->month >= 3U)) {
|
|
+ diff_in_days++;
|
|
+ }
|
|
+
|
|
+ /* Interleaved years are leap */
|
|
+ for (y = ref->year + 1U; y < current->year; y++) {
|
|
+ if (stm32_is_a_leap_year(y)) {
|
|
+ diff_in_days++;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return (24ULL * 60U * 60U * 1000U) * (unsigned long long)diff_in_days;
|
|
+}
|
|
+
|
|
+/*******************************************************************************
|
|
+ * This function computes the date difference between two rtc value.
|
|
+ * Here again the returned value is in milliseconds.
|
|
+ ******************************************************************************/
|
|
+unsigned long long stm32_rtc_diff_calendar(struct stm32_rtc_calendar *cur,
|
|
+ struct stm32_rtc_calendar *ref)
|
|
+{
|
|
+ unsigned long long diff_in_ms = 0;
|
|
+ struct stm32_rtc_time curr_t;
|
|
+ struct stm32_rtc_time ref_t;
|
|
+
|
|
+ stm32mp_clk_enable(rtc_dev.clock);
|
|
+
|
|
+ stm32_rtc_get_date(cur, &curr_t);
|
|
+ stm32_rtc_get_date(ref, &ref_t);
|
|
+ stm32_rtc_get_time(cur, &curr_t);
|
|
+ stm32_rtc_get_time(ref, &ref_t);
|
|
+
|
|
+ diff_in_ms += stm32_rtc_diff_frac(cur, ref);
|
|
+ diff_in_ms += stm32_rtc_diff_time(&curr_t, &ref_t);
|
|
+ diff_in_ms += stm32_rtc_diff_date(&curr_t, &ref_t);
|
|
+
|
|
+ stm32mp_clk_disable(rtc_dev.clock);
|
|
+
|
|
+ return diff_in_ms;
|
|
+}
|
|
+
|
|
+/*******************************************************************************
|
|
+ * This function fill the RTC timestamp structure.
|
|
+ ******************************************************************************/
|
|
+void stm32_rtc_get_timestamp(struct stm32_rtc_time *tamp_ts)
|
|
+{
|
|
+ stm32_rtc_regs_lock();
|
|
+ stm32mp_clk_enable(rtc_dev.clock);
|
|
+
|
|
+ if ((mmio_read_32(rtc_dev.base + RTC_SR) & RTC_SR_TSF) != 0U) {
|
|
+ /* Print timestamp for tamper event */
|
|
+ stm32_rtc_read_timestamp(tamp_ts);
|
|
+ mmio_setbits_32(rtc_dev.base + RTC_SCR, RTC_SCR_CTSF);
|
|
+ if ((mmio_read_32(rtc_dev.base + RTC_SR) & RTC_SR_TSOVF) !=
|
|
+ 0U) {
|
|
+ /* Overflow detected */
|
|
+ mmio_setbits_32(rtc_dev.base + RTC_SCR, RTC_SCR_CTSOVF);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ stm32mp_clk_disable(rtc_dev.clock);
|
|
+ stm32_rtc_regs_unlock();
|
|
+}
|
|
+
|
|
+/*******************************************************************************
|
|
+ * This function enable the timestamp bit for tamper and secure timestamp
|
|
+ * access.
|
|
+ ******************************************************************************/
|
|
+void stm32_rtc_set_tamper_timestamp(void)
|
|
+{
|
|
+ stm32_rtc_regs_lock();
|
|
+ stm32mp_clk_enable(rtc_dev.clock);
|
|
+
|
|
+ stm32_rtc_write_unprotect();
|
|
+
|
|
+ /* Enable tamper timestamper */
|
|
+ mmio_setbits_32(rtc_dev.base + RTC_CR, RTC_CR_TAMPTS);
|
|
+
|
|
+ /* Secure Timestamp bit */
|
|
+ mmio_clrbits_32(rtc_dev.base + RTC_SMCR, RTC_SMCR_TS_DPROT);
|
|
+
|
|
+ stm32_rtc_write_protect();
|
|
+
|
|
+ stm32mp_clk_disable(rtc_dev.clock);
|
|
+ stm32_rtc_regs_unlock();
|
|
+}
|
|
+
|
|
+/*******************************************************************************
|
|
+ * This function return state of tamper timestamp.
|
|
+ ******************************************************************************/
|
|
+bool stm32_rtc_is_timestamp_enable(void)
|
|
+{
|
|
+ bool ret;
|
|
+
|
|
+ stm32mp_clk_enable(rtc_dev.clock);
|
|
+
|
|
+ ret = (mmio_read_32(rtc_dev.base + RTC_CR) & RTC_CR_TAMPTS) != 0U;
|
|
+
|
|
+ stm32mp_clk_disable(rtc_dev.clock);
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+/*******************************************************************************
|
|
+ * RTC initialisation function.
|
|
+ ******************************************************************************/
|
|
+int stm32_rtc_init(void)
|
|
+{
|
|
+ int node;
|
|
+
|
|
+ node = dt_get_node(&rtc_dev, -1, RTC_COMPAT);
|
|
+ if (node < 0) {
|
|
+ return node;
|
|
+ }
|
|
+
|
|
+ if (rtc_dev.status == DT_SECURE) {
|
|
+ stm32mp_register_secure_periph_iomem(rtc_dev.base);
|
|
+ } else {
|
|
+ stm32mp_register_non_secure_periph_iomem(rtc_dev.base);
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
diff --git a/drivers/st/tamper/stm32_tamp.c b/drivers/st/tamper/stm32_tamp.c
|
|
new file mode 100644
|
|
index 0000000..0bfa177
|
|
--- /dev/null
|
|
+++ b/drivers/st/tamper/stm32_tamp.c
|
|
@@ -0,0 +1,375 @@
|
|
+/*
|
|
+ * Copyright (c) 2018, STMicroelectronics - All Rights Reserved
|
|
+ *
|
|
+ * SPDX-License-Identifier: BSD-3-Clause
|
|
+ */
|
|
+
|
|
+#include <assert.h>
|
|
+#include <errno.h>
|
|
+#include <libfdt.h>
|
|
+#include <mmio.h>
|
|
+#include <platform_def.h>
|
|
+#include <stm32_rng.h>
|
|
+#include <stm32_rtc.h>
|
|
+#include <stm32_tamp.h>
|
|
+#include <stm32mp_common.h>
|
|
+#include <stm32mp_dt.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].it_handler != NULL) {
|
|
+ int_list[tamp].it_handler();
|
|
+ }
|
|
+
|
|
+ mmio_setbits_32(stm32_tamp.base + STM32_TAMP_SCR,
|
|
+ BIT(int_id + 16U));
|
|
+ it &= ~BIT(int_id + 16U);
|
|
+ }
|
|
+ tamp++;
|
|
+ }
|
|
+
|
|
+tamp_ext:
|
|
+ tamp = 0;
|
|
+ /* External tamper interrupt */
|
|
+ if ((it == 0U) || ((it & STM32_TAMP_IER_TAMPXIE_ALL) == 0U)) {
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ while ((it != 0U) && (tamp < stm32_tamp.ext_nbtamp)) {
|
|
+ uint32_t ext_id = (uint32_t)ext_list[tamp].id;
|
|
+
|
|
+ if ((it & BIT(ext_id)) != 0U) {
|
|
+ if (ext_list[tamp].it_handler != NULL) {
|
|
+ ext_list[tamp].it_handler();
|
|
+ }
|
|
+
|
|
+ mmio_setbits_32(stm32_tamp.base + STM32_TAMP_SCR,
|
|
+ BIT(ext_id));
|
|
+ it &= ~BIT(ext_id);
|
|
+ }
|
|
+ tamp++;
|
|
+ }
|
|
+}
|
|
+
|
|
+int stm32_tamp_init(void)
|
|
+{
|
|
+ int node;
|
|
+ struct dt_node_info dt_tamp;
|
|
+ void *fdt;
|
|
+ uint32_t rev __unused;
|
|
+
|
|
+ if (fdt_get_address(&fdt) == 0) {
|
|
+ return -EPERM;
|
|
+ }
|
|
+
|
|
+ node = dt_get_node(&dt_tamp, -1, DT_TAMP_COMPAT);
|
|
+ if (node < 0) {
|
|
+ return -FDT_ERR_NOTFOUND;
|
|
+ }
|
|
+
|
|
+ assert(dt_tamp.base != 0U);
|
|
+ assert(dt_tamp.clock != -1);
|
|
+
|
|
+ stm32_tamp.base = dt_tamp.base;
|
|
+ stm32_tamp.clock = (uint32_t)dt_tamp.clock;
|
|
+
|
|
+ /* Init Tamp clock */
|
|
+ stm32mp_clk_enable(stm32_tamp.clock);
|
|
+
|
|
+ /* Reset Tamp register without modifying backup registers conf */
|
|
+ stm32_tamp_reset_register(stm32_tamp.base);
|
|
+
|
|
+ /* Check if tamper are secured */
|
|
+ if (dt_tamp.status != DT_SECURE) {
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ stm32_tamp.hwconf1 = mmio_read_32(stm32_tamp.base + STM32_TAMP_HWCFGR1);
|
|
+ stm32_tamp.hwconf2 = mmio_read_32(stm32_tamp.base + STM32_TAMP_HWCFGR2);
|
|
+
|
|
+ rev = mmio_read_32(stm32_tamp.base + STM32_TAMP_VERR);
|
|
+ VERBOSE("STM32 TAMPER V%u.%u\n", (rev & STM32_TAMP_VERR_MAJREV) >> 4,
|
|
+ rev & STM32_TAMP_VERR_MINREV);
|
|
+
|
|
+ if ((stm32_tamp.hwconf2 & STM32_TAMP_HWCFGR2_TZ) == 0U) {
|
|
+ ERROR("Tamper IP doesn't support trustzone");
|
|
+ return -EPERM;
|
|
+ }
|
|
+
|
|
+ stm32_tamp_set_secured(stm32_tamp.base);
|
|
+
|
|
+ if (fdt_getprop(fdt, node, "st,out3-pc13", NULL) != NULL) {
|
|
+ stm32_tamp_configure_or(stm32_tamp.base, 1);
|
|
+ }
|
|
+
|
|
+ if (stm32_gic_enable_spi(node, NULL) != 0) {
|
|
+ panic();
|
|
+ }
|
|
+
|
|
+ if (fdt_getprop(fdt, node, "wakeup-source", NULL) != NULL) {
|
|
+ mmio_setbits_32(EXTI_BASE + EXTI_TZENR1, EXTI_TZENR1_TZEN18);
|
|
+ mmio_setbits_32(EXTI_BASE + EXTI_C1IMR1, EXTI_IMR1_IM18);
|
|
+ }
|
|
+
|
|
+ return 1;
|
|
+}
|
|
diff --git a/drivers/st/timer/stm32_timer.c b/drivers/st/timer/stm32_timer.c
|
|
new file mode 100644
|
|
index 0000000..6d36e31
|
|
--- /dev/null
|
|
+++ b/drivers/st/timer/stm32_timer.c
|
|
@@ -0,0 +1,297 @@
|
|
+/*
|
|
+ * Copyright (c) 2018, STMicroelectronics - All Rights Reserved
|
|
+ *
|
|
+ * SPDX-License-Identifier: BSD-3-Clause
|
|
+ */
|
|
+
|
|
+#include <assert.h>
|
|
+#include <delay_timer.h>
|
|
+#include <errno.h>
|
|
+#include <libfdt.h>
|
|
+#include <mmio.h>
|
|
+#include <platform_def.h>
|
|
+#include <stdbool.h>
|
|
+#include <stm32_timer.h>
|
|
+#include <stm32mp_dt.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
|
|
+
|
|
+struct stm32_timer_instance {
|
|
+ uintptr_t base;
|
|
+ unsigned long clk;
|
|
+ unsigned long freq;
|
|
+ uint8_t cal_input;
|
|
+};
|
|
+
|
|
+static struct stm32_timer_instance stm32_timer[TIM_MAX_INSTANCE];
|
|
+
|
|
+static int stm32_timer_get_dt_node(struct dt_node_info *info, int offset)
|
|
+{
|
|
+ int node;
|
|
+
|
|
+ node = dt_get_node(info, offset, TIM_COMPAT);
|
|
+ if (node < 0) {
|
|
+ if (offset == -1) {
|
|
+ WARN("%s: No TIMER found\n", __func__);
|
|
+ }
|
|
+ return -FDT_ERR_NOTFOUND;
|
|
+ }
|
|
+
|
|
+ return node;
|
|
+}
|
|
+
|
|
+static void stm32_timer_config(struct stm32_timer_instance *timer)
|
|
+{
|
|
+ stm32mp_clk_enable(timer->clk);
|
|
+
|
|
+ timer->freq = stm32mp_clk_timer_get_rate(timer->clk);
|
|
+
|
|
+ if ((mmio_read_32(timer->base + TIM_TISEL) & TIM_TISEL_TI1SEL_MASK) !=
|
|
+ timer->cal_input) {
|
|
+ mmio_clrsetbits_32(timer->base + TIM_CCMR1,
|
|
+ TIM_CCMR_CC1S_TI1 | TIM_CCMR_CC1S_TI2,
|
|
+ TIM_CCMR_CC1S_TI1);
|
|
+
|
|
+ mmio_clrbits_32(timer->base + TIM_CCER,
|
|
+ TIM_CCER_CC1P | TIM_CCER_CC1NP);
|
|
+
|
|
+ mmio_clrsetbits_32(timer->base + TIM_SMCR,
|
|
+ TIM_SMCR_TS | TIM_SMCR_SMS,
|
|
+ (TIM_SMCR_TS_TI1FP1 << TIM_SMCR_TS_SHIFT) |
|
|
+ TIM_SMCR_SMS_RESET);
|
|
+
|
|
+ mmio_write_32(timer->base + TIM_TISEL, timer->cal_input);
|
|
+ mmio_setbits_32(timer->base + TIM_CR1, TIM_CR1_CEN);
|
|
+ mmio_setbits_32(timer->base + TIM_CCER, TIM_CCER_CC1E);
|
|
+ }
|
|
+
|
|
+ stm32mp_clk_disable(timer->clk);
|
|
+}
|
|
+
|
|
+static uint32_t stm32_timer_start_capture(struct stm32_timer_instance *timer)
|
|
+{
|
|
+ uint32_t timeout = TIM_TIMEOUT_US / TIM_TIMEOUT_STEP_US;
|
|
+ uint32_t counter = 0U;
|
|
+ uint32_t old_counter = 0U;
|
|
+ int twice = 0;
|
|
+
|
|
+ stm32_timer_config(timer);
|
|
+
|
|
+ stm32mp_clk_enable(timer->clk);
|
|
+
|
|
+ mmio_write_32(timer->base + TIM_SR, 0U);
|
|
+ while (((mmio_read_32(timer->base + TIM_SR) &
|
|
+ TIM_SR_UIF) == 0U) && (timeout != 0U)) {
|
|
+ udelay(TIM_TIMEOUT_STEP_US);
|
|
+ timeout--;
|
|
+ }
|
|
+
|
|
+ if (timeout == 0U) {
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
+ mmio_write_32(timer->base + TIM_SR, 0U);
|
|
+
|
|
+ while ((twice < 2) || (old_counter != counter)) {
|
|
+ timeout = TIM_TIMEOUT_US / TIM_TIMEOUT_STEP_US;
|
|
+
|
|
+ while (((mmio_read_32(timer->base + TIM_SR) &
|
|
+ TIM_SR_CC1IF) == 0U) && (timeout != 0U)) {
|
|
+ udelay(TIM_TIMEOUT_STEP_US);
|
|
+ timeout--;
|
|
+ }
|
|
+ if (timeout == 0U) {
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
+ old_counter = counter;
|
|
+ counter = mmio_read_32(timer->base + TIM_CCR1);
|
|
+ twice++;
|
|
+ }
|
|
+
|
|
+out:
|
|
+ stm32mp_clk_disable(timer->clk);
|
|
+
|
|
+ if (timeout == 0U) {
|
|
+ return 0U;
|
|
+ }
|
|
+
|
|
+ return counter;
|
|
+}
|
|
+
|
|
+unsigned long stm32_timer_hsi_freq(void)
|
|
+{
|
|
+ struct stm32_timer_instance *timer = &stm32_timer[HSI_CAL];
|
|
+ unsigned long hsi_freq;
|
|
+ uint32_t counter;
|
|
+
|
|
+ if (timer->base == 0) {
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ counter = stm32_timer_start_capture(timer);
|
|
+ VERBOSE("Counter value %i\n", counter);
|
|
+
|
|
+ if (counter == 0U) {
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ hsi_freq = (timer->freq / counter) << TIM_PRESCAL_HSI;
|
|
+
|
|
+ return hsi_freq;
|
|
+}
|
|
+
|
|
+unsigned long stm32_timer_csi_freq(void)
|
|
+{
|
|
+ struct stm32_timer_instance *timer = &stm32_timer[CSI_CAL];
|
|
+ unsigned long csi_freq;
|
|
+ uint32_t counter;
|
|
+
|
|
+ if (timer->base == 0) {
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ counter = stm32_timer_start_capture(timer);
|
|
+ VERBOSE("Counter value %i\n", counter);
|
|
+
|
|
+ if (counter == 0U) {
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ csi_freq = (timer->freq / counter) << TIM_PRESCAL_CSI;
|
|
+
|
|
+ return csi_freq;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * Get the timer frequence callback function for a target clock calibration
|
|
+ * @timer_freq_cb - Output callback function
|
|
+ * @type - Target clock calibration ID
|
|
+ */
|
|
+void stm32_timer_freq_func(unsigned long (**timer_freq_cb)(void),
|
|
+ enum timer_cal type)
|
|
+{
|
|
+ switch (type) {
|
|
+ case HSI_CAL:
|
|
+ if (stm32_timer[HSI_CAL].base != 0) {
|
|
+ *timer_freq_cb = stm32_timer_hsi_freq;
|
|
+ }
|
|
+ break;
|
|
+
|
|
+ case CSI_CAL:
|
|
+ if (stm32_timer[CSI_CAL].base != 0) {
|
|
+ *timer_freq_cb = stm32_timer_csi_freq;
|
|
+ }
|
|
+ break;
|
|
+
|
|
+ default:
|
|
+ panic();
|
|
+ }
|
|
+}
|
|
+
|
|
+/*
|
|
+ * Initialize timer from DT
|
|
+ * return 0 if disabled, 1 if enabled, else < 0
|
|
+ */
|
|
+int stm32_timer_init(void)
|
|
+{
|
|
+ void *fdt;
|
|
+ struct dt_node_info dt_timer;
|
|
+ int node = -1;
|
|
+ uint8_t nb_timer = 0;
|
|
+
|
|
+ if (fdt_get_address(&fdt) == 0) {
|
|
+ return -EPERM;
|
|
+ }
|
|
+
|
|
+ for (node = stm32_timer_get_dt_node(&dt_timer, node);
|
|
+ node != -FDT_ERR_NOTFOUND;
|
|
+ node = stm32_timer_get_dt_node(&dt_timer, node)) {
|
|
+
|
|
+ if (dt_timer.status == DT_SECURE) {
|
|
+ struct stm32_timer_instance *timer;
|
|
+ const fdt32_t *cuint;
|
|
+
|
|
+ nb_timer++;
|
|
+
|
|
+ cuint = fdt_getprop(fdt, node, "st,hsi-cal-input",
|
|
+ NULL);
|
|
+ if (cuint != NULL) {
|
|
+ timer = &stm32_timer[HSI_CAL];
|
|
+ timer->base = dt_timer.base;
|
|
+ timer->clk = dt_timer.clock;
|
|
+ timer->freq =
|
|
+ stm32mp_clk_timer_get_rate(timer->clk);
|
|
+ timer->cal_input =
|
|
+ (uint8_t)fdt32_to_cpu(*cuint);
|
|
+ stm32_timer_config(timer);
|
|
+ }
|
|
+
|
|
+ cuint = fdt_getprop(fdt, node, "st,csi_cal-input",
|
|
+ NULL);
|
|
+ if (cuint != NULL) {
|
|
+ timer = &stm32_timer[CSI_CAL];
|
|
+ timer->base = dt_timer.base;
|
|
+ timer->clk = dt_timer.clock;
|
|
+ timer->freq =
|
|
+ stm32mp_clk_timer_get_rate(timer->clk);
|
|
+ timer->cal_input =
|
|
+ (uint8_t)fdt32_to_cpu(*cuint);
|
|
+ stm32_timer_config(timer);
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ VERBOSE("%u TIMER instance%s found\n", nb_timer,
|
|
+ nb_timer > 1 ? "s" : "");
|
|
+
|
|
+ if (nb_timer == 0U) {
|
|
+ return -FDT_ERR_NOTFOUND;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
diff --git a/drivers/st/uart/aarch32/stm32_console.S b/drivers/st/uart/aarch32/stm32_console.S
|
|
index 792703a..823e38b 100644
|
|
--- a/drivers/st/uart/aarch32/stm32_console.S
|
|
+++ b/drivers/st/uart/aarch32/stm32_console.S
|
|
@@ -4,30 +4,27 @@
|
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
*/
|
|
#include <asm_macros.S>
|
|
+#include <assert_macros.S>
|
|
+#define USE_FINISH_CONSOLE_REG_2
|
|
+#include <console_macros.S>
|
|
+#include <stm32_console.h>
|
|
+#include <stm32_uart_regs.h>
|
|
|
|
#define USART_TIMEOUT 0x1000
|
|
|
|
-#define USART_CR1 0x00
|
|
-#define USART_CR1_UE 0x00000001
|
|
-#define USART_CR1_TE 0x00000008
|
|
-#define USART_CR1_FIFOEN 0x20000000
|
|
-
|
|
-#define USART_CR2 0x04
|
|
-#define USART_CR2_STOP 0x00003000
|
|
-
|
|
-#define USART_BRR 0x0C
|
|
+ /*
|
|
+ * "core" functions are low-level implementations that don't require
|
|
+ * writeable memory and are thus safe to call in BL1 crash context.
|
|
+ */
|
|
+ .globl console_stm32_core_init
|
|
+ .globl console_stm32_core_putc
|
|
+ .globl console_stm32_core_getc
|
|
+ .globl console_stm32_core_flush
|
|
|
|
-#define USART_ISR 0x1C
|
|
-#define USART_ISR_TC 0x00000040
|
|
-#define USART_ISR_TXE 0x00000080
|
|
-#define USART_ISR_TEACK 0x00200000
|
|
+ .globl console_stm32_putc
|
|
+ .globl console_stm32_flush
|
|
|
|
-#define USART_TDR 0x28
|
|
|
|
- .globl console_core_init
|
|
- .globl console_core_putc
|
|
- .globl console_core_getc
|
|
- .globl console_core_flush
|
|
|
|
/* -----------------------------------------------------------------
|
|
* int console_core_init(uintptr_t base_addr,
|
|
@@ -45,7 +42,7 @@
|
|
* Clobber list : r1, r2, r3
|
|
* -----------------------------------------------------------------
|
|
*/
|
|
-func console_core_init
|
|
+func console_stm32_core_init
|
|
/* Check the input base address */
|
|
cmp r0, #0
|
|
beq core_init_fail
|
|
@@ -88,21 +85,55 @@ teack_loop:
|
|
core_init_fail:
|
|
mov r0, #0
|
|
bx lr
|
|
-endfunc console_core_init
|
|
+endfunc console_stm32_core_init
|
|
|
|
- /* ---------------------------------------------------------------
|
|
+ .globl console_stm32_register
|
|
+
|
|
+ /* -------------------------------------------------------
|
|
+ * int console_stm32_register(uintptr_t baseaddr,
|
|
+ * uint32_t clock, uint32_t baud,
|
|
+ * struct console_stm32 *console);
|
|
+ * Function to initialize and register a new STM32
|
|
+ * console. Storage passed in for the console struct
|
|
+ * *must* be persistent (i.e. not from the stack).
|
|
+ * In: r0 - UART register base address
|
|
+ * r1 - UART clock in Hz
|
|
+ * r2 - Baud rate
|
|
+ * r3 - pointer to empty console_stm32 struct
|
|
+ * Out: return 1 on success, 0 on error
|
|
+ * Clobber list : r0, r1, r2
|
|
+ * -------------------------------------------------------
|
|
+ */
|
|
+func console_stm32_register
|
|
+ push {r4, lr}
|
|
+ mov r4, r3
|
|
+ cmp r4, #0
|
|
+ beq register_fail
|
|
+ str r0, [r4, #CONSOLE_T_STM32_BASE]
|
|
+
|
|
+ bl console_stm32_core_init
|
|
+ cmp r0, #0
|
|
+ beq register_fail
|
|
+
|
|
+ mov r0, r4
|
|
+ pop {r4, lr}
|
|
+ finish_console_register stm32 putc=1, getc=0, flush=1
|
|
+
|
|
+register_fail:
|
|
+ pop {r4, pc}
|
|
+endfunc console_stm32_register
|
|
+
|
|
+ /* --------------------------------------------------------
|
|
* int console_core_putc(int c, uintptr_t base_addr)
|
|
- *
|
|
- * Function to output a character over the console. It returns the
|
|
- * character printed on success or -1 on error.
|
|
- *
|
|
+ * Function to output a character over the console. It
|
|
+ * returns the character printed on success or -1 on error.
|
|
* In : r0 - character to be printed
|
|
* r1 - console base address
|
|
* Out : return -1 on error else return character.
|
|
- * Clobber list : r2
|
|
- * ---------------------------------------------------------------
|
|
+ * Clobber list : r2, r3
|
|
+ * --------------------------------------------------------
|
|
*/
|
|
-func console_core_putc
|
|
+func console_stm32_core_putc
|
|
/* Check the input parameter */
|
|
cmp r1, #0
|
|
beq putc_error
|
|
@@ -111,26 +142,38 @@ func console_core_putc
|
|
bne 2f
|
|
1:
|
|
/* Check Transmit Data Register Empty */
|
|
+ mov r3, #USART_TIMEOUT
|
|
txe_loop_1:
|
|
+ subs r3, r3, #1
|
|
+ beq putc_error
|
|
ldr r2, [r1, #USART_ISR]
|
|
tst r2, #USART_ISR_TXE
|
|
beq txe_loop_1
|
|
mov r2, #0xD
|
|
str r2, [r1, #USART_TDR]
|
|
/* Check transmit complete flag */
|
|
+ mov r3, #USART_TIMEOUT
|
|
tc_loop_1:
|
|
+ subs r3, r3, #1
|
|
+ beq putc_error
|
|
ldr r2, [r1, #USART_ISR]
|
|
tst r2, #USART_ISR_TC
|
|
beq tc_loop_1
|
|
2:
|
|
/* Check Transmit Data Register Empty */
|
|
+ mov r3, #USART_TIMEOUT
|
|
txe_loop_2:
|
|
+ subs r3, r3, #1
|
|
+ beq putc_error
|
|
ldr r2, [r1, #USART_ISR]
|
|
tst r2, #USART_ISR_TXE
|
|
beq txe_loop_2
|
|
str r0, [r1, #USART_TDR]
|
|
/* Check transmit complete flag */
|
|
+ mov r3, #USART_TIMEOUT
|
|
tc_loop_2:
|
|
+ subs r3, r3, #1
|
|
+ beq putc_error
|
|
ldr r2, [r1, #USART_ISR]
|
|
tst r2, #USART_ISR_TC
|
|
beq tc_loop_2
|
|
@@ -138,7 +181,26 @@ tc_loop_2:
|
|
putc_error:
|
|
mov r0, #-1
|
|
bx lr
|
|
-endfunc console_core_putc
|
|
+endfunc console_stm32_core_putc
|
|
+
|
|
+ /* ------------------------------------------------------------
|
|
+ * int console_stm32_putc(int c, struct console_stm32 *console)
|
|
+ * Function to output a character over the console. It
|
|
+ * returns the character printed on success or -1 on error.
|
|
+ * In: r0 - character to be printed
|
|
+ * r1 - pointer to console_t structure
|
|
+ * Out : return -1 on error else return character.
|
|
+ * Clobber list: r2
|
|
+ * ------------------------------------------------------------
|
|
+ */
|
|
+func console_stm32_putc
|
|
+#if ENABLE_ASSERTIONS
|
|
+ cmp r1, #0
|
|
+ ASM_ASSERT(ne)
|
|
+#endif /* ENABLE_ASSERTIONS */
|
|
+ ldr r1, [r1, #CONSOLE_T_STM32_BASE]
|
|
+ b console_stm32_core_putc
|
|
+endfunc console_stm32_putc
|
|
|
|
/* -----------------------------------------------------------
|
|
* int console_core_getc(uintptr_t base_addr)
|
|
@@ -151,11 +213,11 @@ endfunc console_core_putc
|
|
* Clobber list : r0, r1
|
|
* -----------------------------------------------------------
|
|
*/
|
|
-func console_core_getc
|
|
+func console_stm32_core_getc
|
|
/* Not supported */
|
|
mov r0, #-1
|
|
bx lr
|
|
-endfunc console_core_getc
|
|
+endfunc console_stm32_core_getc
|
|
|
|
/* ---------------------------------------------------------------
|
|
* int console_core_flush(uintptr_t base_addr)
|
|
@@ -165,14 +227,17 @@ endfunc console_core_getc
|
|
*
|
|
* In : r0 - console base address
|
|
* Out : return -1 on error else return 0.
|
|
- * Clobber list : r0, r1
|
|
+ * Clobber list : r0, r1, r2
|
|
* ---------------------------------------------------------------
|
|
*/
|
|
-func console_core_flush
|
|
+func console_stm32_core_flush
|
|
cmp r0, #0
|
|
beq flush_error
|
|
/* Check Transmit Data Register Empty */
|
|
+ mov r2, #USART_TIMEOUT
|
|
txe_loop_3:
|
|
+ subs r2, r2, #1
|
|
+ beq flush_error
|
|
ldr r1, [r0, #USART_ISR]
|
|
tst r1, #USART_ISR_TXE
|
|
beq txe_loop_3
|
|
@@ -181,4 +246,22 @@ txe_loop_3:
|
|
flush_error:
|
|
mov r0, #-1
|
|
bx lr
|
|
-endfunc console_core_flush
|
|
+endfunc console_stm32_core_flush
|
|
+
|
|
+ /* ------------------------------------------------------
|
|
+ * int console_stm32_flush(struct console_stm32 *console)
|
|
+ * Function to force a write of all buffered
|
|
+ * data that hasn't been output.
|
|
+ * In : r0 - pointer to console_t structure
|
|
+ * Out : return -1 on error else return 0.
|
|
+ * Clobber list: r0, r1
|
|
+ * ------------------------------------------------------
|
|
+ */
|
|
+func console_stm32_flush
|
|
+#if ENABLE_ASSERTIONS
|
|
+ cmp r0, #0
|
|
+ ASM_ASSERT(ne)
|
|
+#endif /* ENABLE_ASSERTIONS */
|
|
+ ldr r0, [r0, #CONSOLE_T_STM32_BASE]
|
|
+ b console_stm32_core_flush
|
|
+endfunc console_stm32_flush
|
|
diff --git a/drivers/st/uart/io_programmer_uart.c b/drivers/st/uart/io_programmer_uart.c
|
|
new file mode 100644
|
|
index 0000000..34a7cbb
|
|
--- /dev/null
|
|
+++ b/drivers/st/uart/io_programmer_uart.c
|
|
@@ -0,0 +1,597 @@
|
|
+/*
|
|
+ * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved.
|
|
+ *
|
|
+ * SPDX-License-Identifier: BSD-3-Clause
|
|
+ */
|
|
+
|
|
+#include <arch_helpers.h>
|
|
+#include <assert.h>
|
|
+#include <boot_api.h>
|
|
+#include <debug.h>
|
|
+#include <errno.h>
|
|
+#include <io_driver.h>
|
|
+#include <io_programmer.h>
|
|
+#include <io_stm32image.h>
|
|
+#include <io_storage.h>
|
|
+#include <io_uart.h>
|
|
+#include <platform_def.h>
|
|
+#include <stm32_iwdg.h>
|
|
+#include <stm32mp_auth.h>
|
|
+#include <stm32mp_dt.h>
|
|
+#include <string.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)¤t_phase;
|
|
+ result = 0;
|
|
+ } else {
|
|
+ WARN("A UART device is already active. Close first.\n");
|
|
+ result = -EIO;
|
|
+ }
|
|
+ return result;
|
|
+}
|
|
+
|
|
+static int uart_receive_command(uint8_t *command)
|
|
+{
|
|
+ uint8_t byte = 0;
|
|
+ uint8_t xor = 0;
|
|
+ uint8_t counter = 0, found = 0;
|
|
+ int ret;
|
|
+
|
|
+ /* check command */
|
|
+ ret = uart_read_byte(&byte);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ for (counter = 0; counter < sizeof(command_tab); counter++) {
|
|
+ if (command_tab[counter] == byte) {
|
|
+ found = 1;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (found) {
|
|
+ ret = uart_read_byte(&xor);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+ if ((byte ^ xor) != 0xFF) {
|
|
+ WARN("UART: Command XOR check fail (byte=0x%x, xor=0x%x)\n",
|
|
+ byte, xor);
|
|
+ return -EPROTO;
|
|
+ }
|
|
+ } else {
|
|
+ if (byte != INIT_BYTE) {
|
|
+ WARN("UART: Command unknown (byte=0x%x)\n", byte);
|
|
+ return -EPROTO;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ *command = byte;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int get_cmd_command(void)
|
|
+{
|
|
+ uint8_t counter = 0x0;
|
|
+
|
|
+ uart_write_byte(sizeof(command_tab));
|
|
+ uart_write_byte(USART_BL_VERSION);
|
|
+
|
|
+ for (counter = 0; counter < sizeof(command_tab); counter++)
|
|
+ uart_write_byte(command_tab[counter]);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int get_version_command(void)
|
|
+{
|
|
+ uart_write_byte(STM32_TF_VERSION);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int get_id_command(void)
|
|
+{
|
|
+ /* Send Device IDCode */
|
|
+ uart_write_byte(0x1);
|
|
+ uart_write_byte(DEVICE_ID_BYTE1);
|
|
+ uart_write_byte(DEVICE_ID_BYTE2);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int uart_send_phase(uint32_t address)
|
|
+{
|
|
+ uart_write_byte(0x05); /* length of data - 1 */
|
|
+ /* Send the ID of next partition */
|
|
+ uart_write_byte(current_phase.phase_id); /* partition ID */
|
|
+
|
|
+ uart_write_uint32(address); /* destination address */
|
|
+ uart_write_byte(0x00); /* length of extra data */
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int uart_download_part(uint8_t *buffer, uint32_t *length_read)
|
|
+{
|
|
+ uint8_t byte = 0;
|
|
+ uint8_t xor = 0;
|
|
+ uint8_t operation = 0;
|
|
+ uint32_t packet_number = 0;
|
|
+ uint8_t packet_size = 0;
|
|
+ int i = 0;
|
|
+ volatile uint8_t *ptr = (uint8_t *)buffer;
|
|
+
|
|
+ /* get operation number */
|
|
+ if (uart_read_byte(&operation))
|
|
+ return -EIO;
|
|
+ xor = operation;
|
|
+
|
|
+ /* get packet Number */
|
|
+ for (i = 3, byte = 0; i > 0; i--) {
|
|
+ if (uart_read_byte(&byte))
|
|
+ return -EIO;
|
|
+ xor ^= byte;
|
|
+ packet_number = (packet_number << 8) | byte;
|
|
+ }
|
|
+
|
|
+ if (packet_number != current_phase.current_packet) {
|
|
+ WARN("UART: Bad packet number receive: %i\n", packet_number);
|
|
+ return -EPROTO;
|
|
+ }
|
|
+
|
|
+ /* checksum */
|
|
+ if (uart_read_byte(&byte))
|
|
+ return -EIO;
|
|
+
|
|
+ if (xor != byte) {
|
|
+ WARN("UART: Download Command header checksum fail: calculated xor: %i, received xor:%i\n",
|
|
+ xor, byte);
|
|
+ return -EPROTO;
|
|
+ }
|
|
+
|
|
+ uart_write_byte(ACK_BYTE);
|
|
+
|
|
+ if (uart_read_byte(&packet_size))
|
|
+ return -EIO;
|
|
+
|
|
+ xor = packet_size;
|
|
+
|
|
+ for (i = packet_size; i >= 0; i--) {
|
|
+ /* Reload watchdog, once every 8 loops */
|
|
+ if (i % 8)
|
|
+ stm32_iwdg_refresh(IWDG2_INST);
|
|
+
|
|
+ if (uart_read_byte(&byte))
|
|
+ return -EIO;
|
|
+ *(volatile uint8_t *)ptr = byte;
|
|
+ xor ^= byte;
|
|
+ ptr++;
|
|
+ }
|
|
+
|
|
+ /* checksum */
|
|
+ if (uart_read_byte(&byte))
|
|
+ return -EIO;
|
|
+
|
|
+ if (xor != byte) {
|
|
+ WARN("UART: Download Command data checksum fail: calculated xor: 0x%x, received xor:0x%x\n",
|
|
+ xor, byte);
|
|
+ return -EPROTO;
|
|
+ }
|
|
+
|
|
+ current_phase.current_packet++;
|
|
+ *length_read = (uint32_t)packet_size + 1;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int uart_start_cmd(boot_api_image_header_t *header, uintptr_t buffer)
|
|
+{
|
|
+ uint8_t byte = 0;
|
|
+ uint8_t xor = 0;
|
|
+ int i = 0;
|
|
+ uint32_t start_address = 0;
|
|
+ int result = 0;
|
|
+
|
|
+ /* get address */
|
|
+ for (i = 4; i > 0; i--) {
|
|
+ if (uart_read_byte(&byte))
|
|
+ return -EIO;
|
|
+ xor ^= byte;
|
|
+ start_address = (start_address << 8) | byte;
|
|
+ }
|
|
+
|
|
+ /* checksum */
|
|
+ if (uart_read_byte(&byte))
|
|
+ return -EIO;
|
|
+
|
|
+ if (xor != byte) {
|
|
+ WARN("UART: Start command checksum fail: calculated xor: %i, received xor:%i\n",
|
|
+ xor, byte);
|
|
+ return -EPROTO;
|
|
+ }
|
|
+
|
|
+ switch (current_phase.phase_id) {
|
|
+ case PHASE_FLASHLAYOUT:
|
|
+ result = check_header(header, buffer +
|
|
+ sizeof(boot_api_image_header_t));
|
|
+ if (result)
|
|
+ return result;
|
|
+ break;
|
|
+
|
|
+ case PHASE_SSBL:
|
|
+ if (start_address != BL33_BASE) {
|
|
+ VERBOSE("BL33 address provided: 0x%x, using: 0x%x\n",
|
|
+ start_address, BL33_BASE);
|
|
+ }
|
|
+
|
|
+ result = check_header(header, buffer);
|
|
+ if (result)
|
|
+ return result;
|
|
+
|
|
+#ifdef AUTHENTICATE_BL33
|
|
+ result = check_authentication(header, buffer);
|
|
+ if (result != 0) {
|
|
+ return result;
|
|
+ }
|
|
+#else
|
|
+ NOTICE("Authentication disabled: No signature check\n");
|
|
+#endif
|
|
+ break;
|
|
+
|
|
+ default:
|
|
+ ERROR("Invalid phase ID : %i\n", current_phase.phase_id);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/* Read data from the uart device */
|
|
+static int uart_block_read(io_entity_t *entity, uintptr_t buffer,
|
|
+ size_t length, size_t *length_read)
|
|
+{
|
|
+ uint32_t read_length = 0;
|
|
+ uint32_t total_length = 0;
|
|
+ uint32_t ptr_offset = 0;
|
|
+ uint8_t command = 0;
|
|
+ uint8_t all_commands_done = 0;
|
|
+ boot_api_image_header_t *header =
|
|
+ (boot_api_image_header_t *)&header_buffer[0];
|
|
+
|
|
+ if (header_length_read && current_phase.keep_header) {
|
|
+ memcpy((uint8_t *)buffer, (uint8_t *)&header_buffer[0],
|
|
+ header_length_read);
|
|
+ ptr_offset += header_length_read;
|
|
+ } else if (header_length_read &&
|
|
+ ((header_length_read -
|
|
+ sizeof(boot_api_image_header_t)) > 0)) {
|
|
+ memcpy((uint8_t *)buffer,
|
|
+ (uint8_t *)
|
|
+ &header_buffer[sizeof(boot_api_image_header_t)],
|
|
+ header_length_read -
|
|
+ sizeof(boot_api_image_header_t));
|
|
+ ptr_offset += header_length_read -
|
|
+ sizeof(boot_api_image_header_t);
|
|
+ }
|
|
+
|
|
+ while (!all_commands_done) {
|
|
+ int result;
|
|
+
|
|
+ /* Reload watchdog */
|
|
+ stm32_iwdg_refresh(IWDG2_INST);
|
|
+
|
|
+ result = uart_receive_command(&command);
|
|
+ if (result) {
|
|
+ if (result == -EIO) {
|
|
+ WARN("UART: device error on command receive\n");
|
|
+ }
|
|
+
|
|
+ mdelay(2);
|
|
+
|
|
+ uart_flush_rx_fifo(PROGRAMMER_TIMEOUT);
|
|
+ uart_write_byte(NACK_BYTE);
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ /* Send ack */
|
|
+ uart_write_byte(ACK_BYTE);
|
|
+
|
|
+ switch (command) {
|
|
+ case INIT_BYTE:
|
|
+ /* Nothing to do */
|
|
+ continue;
|
|
+ case GET_CMD_COMMAND:
|
|
+ result = get_cmd_command();
|
|
+ break;
|
|
+
|
|
+ case GET_VER_COMMAND:
|
|
+ result = get_version_command();
|
|
+ break;
|
|
+
|
|
+ case GET_ID_COMMAND:
|
|
+ result = get_id_command();
|
|
+ break;
|
|
+
|
|
+ case PHASE_COMMAND:
|
|
+ result = uart_send_phase((uint32_t)buffer);
|
|
+ break;
|
|
+
|
|
+ case DOWNLOAD_COMMAND:
|
|
+ result = uart_download_part((uint8_t *)(buffer +
|
|
+ ptr_offset),
|
|
+ &read_length);
|
|
+ if (!result) {
|
|
+ ptr_offset += read_length;
|
|
+ total_length += read_length;
|
|
+ if ((total_length >= length) &&
|
|
+ !header_length_read) {
|
|
+ /* read header only go out*/
|
|
+ all_commands_done = 1;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ break;
|
|
+
|
|
+ case START_COMMAND:
|
|
+ result = uart_start_cmd(header, buffer);
|
|
+ if (!result)
|
|
+ all_commands_done = 1;
|
|
+
|
|
+ break;
|
|
+
|
|
+ default:
|
|
+ /* Not supported command */
|
|
+ WARN("UART: Unknown command\n");
|
|
+ uart_flush_rx_fifo(PROGRAMMER_TIMEOUT);
|
|
+ uart_write_byte(NACK_BYTE);
|
|
+ continue;
|
|
+ }
|
|
+ if (!result) {
|
|
+ /* Send ack */
|
|
+ uart_write_byte(ACK_BYTE);
|
|
+ } else if (result == -EPROTO) {
|
|
+ uart_flush_rx_fifo(0xFFFF);
|
|
+ uart_write_byte(NACK_BYTE);
|
|
+ } else {
|
|
+ uart_flush_rx_fifo(PROGRAMMER_TIMEOUT);
|
|
+ uart_write_byte(NACK_BYTE);
|
|
+ continue;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ *length_read = total_length;
|
|
+
|
|
+ INFO("Read block in buffer 0x%lx size 0x%x phase ID %i\n",
|
|
+ buffer, length, current_phase.phase_id);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/* Close a file on the uart device */
|
|
+static int uart_block_close(io_entity_t *entity)
|
|
+{
|
|
+ current_phase.phase_id = PHASE_FSBL1;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/* Exported functions */
|
|
+
|
|
+/* Register the uart driver with the IO abstraction */
|
|
+int register_io_dev_uart(const io_dev_connector_t **dev_con)
|
|
+{
|
|
+ int result;
|
|
+
|
|
+ assert(dev_con);
|
|
+
|
|
+ result = io_register_device(&uart_dev_info);
|
|
+ if (!result)
|
|
+ *dev_con = &uart_dev_connector;
|
|
+
|
|
+ return result;
|
|
+}
|
|
diff --git a/drivers/st/uart/stm32mp1xx_hal_uart.c b/drivers/st/uart/stm32mp1xx_hal_uart.c
|
|
new file mode 100644
|
|
index 0000000..c8e5860
|
|
--- /dev/null
|
|
+++ b/drivers/st/uart/stm32mp1xx_hal_uart.c
|
|
@@ -0,0 +1,799 @@
|
|
+/**
|
|
+ ******************************************************************************
|
|
+ * @file stm32mp1xx_hal_uart.c
|
|
+ * @author MCD Application Team
|
|
+ * @version $VERSION$
|
|
+ * @date $DATE$
|
|
+ * @brief UART HAL module driver.
|
|
+ * This file provides firmware functions to manage the following
|
|
+ * functionalities of the Universal Asynchronous Receiver Transmitter Peripheral (UART).
|
|
+ * + Initialization and de-initialization functions
|
|
+ * + IO operation functions
|
|
+ * + Peripheral Control functions
|
|
+ *
|
|
+ *
|
|
+ * @verbatim
|
|
+ * ===============================================================================
|
|
+ * ##### How to use this driver #####
|
|
+ * ===============================================================================
|
|
+ * [..]
|
|
+ * The UART HAL driver can be used as follows:
|
|
+ *
|
|
+ * (#) Declare a UART_HandleTypeDef handle structure (eg. UART_HandleTypeDef huart).
|
|
+ * (#) Initialize the UART low level resources by implementing the HAL_UART_MspInit() API:
|
|
+ * (++) Enable the USARTx interface clock.
|
|
+ * (++) UART pins configuration:
|
|
+ * (+++) Enable the clock for the UART GPIOs.
|
|
+ * (+++) Configure these UART pins as alternate function pull-up.
|
|
+ * (++) NVIC configuration if you need to use interrupt process (HAL_UART_Transmit_IT()
|
|
+ * and HAL_UART_Receive_IT() APIs):
|
|
+ * (+++) Configure the USARTx interrupt priority.
|
|
+ * (+++) Enable the NVIC USART IRQ handle.
|
|
+ * (++) UART interrupts handling:
|
|
+ * -@@- The specific UART interrupts (Transmission complete interrupt,
|
|
+ * RXNE interrupt and Error Interrupts) are managed using the macros
|
|
+ * __HAL_UART_ENABLE_IT() and __HAL_UART_DISABLE_IT() inside the transmit and receive processes.
|
|
+ * (++) DMA Configuration if you need to use DMA process (HAL_UART_Transmit_DMA()
|
|
+ * and HAL_UART_Receive_DMA() APIs):
|
|
+ * (+++) Declare a DMA handle structure for the Tx/Rx channel.
|
|
+ * (+++) Enable the DMAx interface clock.
|
|
+ * (+++) Configure the declared DMA handle structure with the required Tx/Rx parameters.
|
|
+ * (+++) Configure the DMA Tx/Rx channel.
|
|
+ * (+++) Associate the initialized DMA handle to the UART DMA Tx/Rx handle.
|
|
+ * (+++) Configure the priority and enable the NVIC for the transfer complete interrupt on the DMA Tx/Rx channel.
|
|
+ *
|
|
+ * (#) Program the Baud Rate, Word Length, Stop Bit, Parity, Hardware
|
|
+ * flow control and Mode (Receiver/Transmitter) in the huart handle Init structure.
|
|
+ *
|
|
+ * (#) If required, program UART advanced features (TX/RX pins swap, auto Baud rate detection,...)
|
|
+ * in the huart handle AdvancedInit structure.
|
|
+ *
|
|
+ * (#) For the UART asynchronous mode, initialize the UART registers by calling
|
|
+ * the HAL_UART_Init() API.
|
|
+ *
|
|
+ * (#) For the UART Half duplex mode, initialize the UART registers by calling
|
|
+ * the HAL_HalfDuplex_Init() API.
|
|
+ *
|
|
+ * (#) For the UART LIN (Local Interconnection Network) mode, initialize the UART registers
|
|
+ * by calling the HAL_LIN_Init() API.
|
|
+ *
|
|
+ * (#) For the UART Multiprocessor mode, initialize the UART registers
|
|
+ * by calling the HAL_MultiProcessor_Init() API.
|
|
+ *
|
|
+ * (#) For the UART RS485 Driver Enabled mode, initialize the UART registers
|
|
+ * by calling the HAL_RS485Ex_Init() API.
|
|
+ *
|
|
+ * [..]
|
|
+ * (@) These API's (HAL_UART_Init(), HAL_HalfDuplex_Init(), HAL_LIN_Init(), HAL_MultiProcessor_Init(),
|
|
+ * also configure the low level Hardware GPIO, CLOCK, CORTEX...etc) by
|
|
+ * calling the customized HAL_UART_MspInit() API.
|
|
+ *
|
|
+ * @endverbatim
|
|
+ ******************************************************************************
|
|
+ * @attention
|
|
+ *
|
|
+ * <h2><center>© COPYRIGHT(c) 2015-2017 STMicroelectronics</center></h2>
|
|
+ *
|
|
+ * SPDX-License-Identifier: BSD-3-Clause
|
|
+ *
|
|
+ ******************************************************************************
|
|
+ */
|
|
+
|
|
+/* Includes ------------------------------------------------------------------*/
|
|
+#include <assert.h>
|
|
+#include <bl_common.h>
|
|
+#include <platform_def.h>
|
|
+#include <stm32mp_clkfunc.h>
|
|
+#include <stm32mp1xx_hal_uart.h>
|
|
+#include <string.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 0000000..a920553
|
|
--- /dev/null
|
|
+++ b/drivers/st/usb_dwc2/usb_dwc2.c
|
|
@@ -0,0 +1,858 @@
|
|
+/*
|
|
+ * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved.
|
|
+ *
|
|
+ * SPDX-License-Identifier: BSD-3-Clause
|
|
+ */
|
|
+
|
|
+#include <arch_helpers.h>
|
|
+#include <debug.h>
|
|
+#include <stdint.h>
|
|
+#include <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/drivers/ti/uart/aarch64/16550_console.S b/drivers/ti/uart/aarch64/16550_console.S
|
|
index d46fa61..34cce95 100644
|
|
--- a/drivers/ti/uart/aarch64/16550_console.S
|
|
+++ b/drivers/ti/uart/aarch64/16550_console.S
|
|
@@ -7,6 +7,7 @@
|
|
#include <arch.h>
|
|
#include <asm_macros.S>
|
|
#include <assert_macros.S>
|
|
+#define USE_FINISH_CONSOLE_REG_2
|
|
#include <console_macros.S>
|
|
#include <uart_16550.h>
|
|
|
|
@@ -111,7 +112,7 @@ func console_16550_register
|
|
|
|
mov x0, x6
|
|
mov x30, x7
|
|
- finish_console_register 16550
|
|
+ finish_console_register 16550 putc=1, getc=1, flush=1
|
|
|
|
register_fail:
|
|
ret x7
|
|
diff --git a/fdts/stm32mp15-ddr.dtsi b/fdts/stm32mp15-ddr.dtsi
|
|
index be4e2c3..1a5c51c 100644
|
|
--- a/fdts/stm32mp15-ddr.dtsi
|
|
+++ b/fdts/stm32mp15-ddr.dtsi
|
|
@@ -5,7 +5,7 @@
|
|
|
|
/ {
|
|
soc {
|
|
- ddr: ddr@0x5A003000{
|
|
+ ddr: ddr@5A003000{
|
|
|
|
compatible = "st,stm32mp1-ddr";
|
|
|
|
diff --git a/fdts/stm32mp15-ddr3-1x4Gb-1066-binG.dtsi b/fdts/stm32mp15-ddr3-1x4Gb-1066-binG.dtsi
|
|
new file mode 100644
|
|
index 0000000..16b8cf6
|
|
--- /dev/null
|
|
+++ b/fdts/stm32mp15-ddr3-1x4Gb-1066-binG.dtsi
|
|
@@ -0,0 +1,121 @@
|
|
+// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
|
|
+/*
|
|
+ * Copyright (C) 2018, STMicroelectronics - All Rights Reserved
|
|
+ */
|
|
+/* STM32MP157C DK1/DK2 BOARD configuration
|
|
+ * 1x DDR3L 4Gb, 16-bit, 533MHz.
|
|
+ * Reference used NT5CC256M16DP-DI from NANYA
|
|
+ *
|
|
+ * DDR type / Platform DDR3/3L
|
|
+ * freq 533MHz
|
|
+ * width 16
|
|
+ * datasheet 0 = MT41J256M16-187 / DDR3-1066 bin G
|
|
+ * DDR density 4
|
|
+ * timing mode optimized
|
|
+ * Scheduling/QoS options : type = 2
|
|
+ * address mapping : RBC
|
|
+ * Tc > + 85C : N
|
|
+ */
|
|
+
|
|
+#define DDR_MEM_NAME "DDR3-1066/888 bin G 1x4Gb 533MHz v1.41"
|
|
+#define DDR_MEM_SPEED 533000
|
|
+#define DDR_MEM_SIZE 0x20000000
|
|
+
|
|
+#define DDR_MSTR 0x00041401
|
|
+#define DDR_MRCTRL0 0x00000010
|
|
+#define DDR_MRCTRL1 0x00000000
|
|
+#define DDR_DERATEEN 0x00000000
|
|
+#define DDR_DERATEINT 0x00800000
|
|
+#define DDR_PWRCTL 0x00000000
|
|
+#define DDR_PWRTMG 0x00400010
|
|
+#define DDR_HWLPCTL 0x00000000
|
|
+#define DDR_RFSHCTL0 0x00210000
|
|
+#define DDR_RFSHCTL3 0x00000000
|
|
+#define DDR_RFSHTMG 0x0081008B
|
|
+#define DDR_CRCPARCTL0 0x00000000
|
|
+#define DDR_DRAMTMG0 0x121B2414
|
|
+#define DDR_DRAMTMG1 0x000A041C
|
|
+#define DDR_DRAMTMG2 0x0608090F
|
|
+#define DDR_DRAMTMG3 0x0050400C
|
|
+#define DDR_DRAMTMG4 0x08040608
|
|
+#define DDR_DRAMTMG5 0x06060403
|
|
+#define DDR_DRAMTMG6 0x02020002
|
|
+#define DDR_DRAMTMG7 0x00000202
|
|
+#define DDR_DRAMTMG8 0x00001005
|
|
+#define DDR_DRAMTMG14 0x000000A0
|
|
+#define DDR_ZQCTL0 0xC2000040
|
|
+#define DDR_DFITMG0 0x02060105
|
|
+#define DDR_DFITMG1 0x00000202
|
|
+#define DDR_DFILPCFG0 0x07000000
|
|
+#define DDR_DFIUPD0 0xC0400003
|
|
+#define DDR_DFIUPD1 0x00000000
|
|
+#define DDR_DFIUPD2 0x00000000
|
|
+#define DDR_DFIPHYMSTR 0x00000000
|
|
+#define DDR_ADDRMAP1 0x00070707
|
|
+#define DDR_ADDRMAP2 0x00000000
|
|
+#define DDR_ADDRMAP3 0x1F000000
|
|
+#define DDR_ADDRMAP4 0x00001F1F
|
|
+#define DDR_ADDRMAP5 0x06060606
|
|
+#define DDR_ADDRMAP6 0x0F060606
|
|
+#define DDR_ADDRMAP9 0x00000000
|
|
+#define DDR_ADDRMAP10 0x00000000
|
|
+#define DDR_ADDRMAP11 0x00000000
|
|
+#define DDR_ODTCFG 0x06000600
|
|
+#define DDR_ODTMAP 0x00000001
|
|
+#define DDR_SCHED 0x00000C01
|
|
+#define DDR_SCHED1 0x00000000
|
|
+#define DDR_PERFHPR1 0x01000001
|
|
+#define DDR_PERFLPR1 0x08000200
|
|
+#define DDR_PERFWR1 0x08000400
|
|
+#define DDR_DBG0 0x00000000
|
|
+#define DDR_DBG1 0x00000000
|
|
+#define DDR_DBGCMD 0x00000000
|
|
+#define DDR_POISONCFG 0x00000000
|
|
+#define DDR_PCCFG 0x00000010
|
|
+#define DDR_PCFGR_0 0x00010000
|
|
+#define DDR_PCFGW_0 0x00000000
|
|
+#define DDR_PCFGQOS0_0 0x02100C03
|
|
+#define DDR_PCFGQOS1_0 0x00800100
|
|
+#define DDR_PCFGWQOS0_0 0x01100C03
|
|
+#define DDR_PCFGWQOS1_0 0x01000200
|
|
+#define DDR_PCFGR_1 0x00010000
|
|
+#define DDR_PCFGW_1 0x00000000
|
|
+#define DDR_PCFGQOS0_1 0x02100C03
|
|
+#define DDR_PCFGQOS1_1 0x00800040
|
|
+#define DDR_PCFGWQOS0_1 0x01100C03
|
|
+#define DDR_PCFGWQOS1_1 0x01000200
|
|
+#define DDR_PGCR 0x01442E02
|
|
+#define DDR_PTR0 0x0022AA5B
|
|
+#define DDR_PTR1 0x04841104
|
|
+#define DDR_PTR2 0x042DA068
|
|
+#define DDR_ACIOCR 0x10400812
|
|
+#define DDR_DXCCR 0x00000C40
|
|
+#define DDR_DSGCR 0xF200001F
|
|
+#define DDR_DCR 0x0000000B
|
|
+#define DDR_DTPR0 0x38D488D0
|
|
+#define DDR_DTPR1 0x098B00D8
|
|
+#define DDR_DTPR2 0x10023600
|
|
+#define DDR_MR0 0x00000840
|
|
+#define DDR_MR1 0x00000000
|
|
+#define DDR_MR2 0x00000208
|
|
+#define DDR_MR3 0x00000000
|
|
+#define DDR_ODTCR 0x00010000
|
|
+#define DDR_ZQ0CR1 0x00000038
|
|
+#define DDR_DX0GCR 0x0000CE81
|
|
+#define DDR_DX0DLLCR 0x40000000
|
|
+#define DDR_DX0DQTR 0xFFFFFFFF
|
|
+#define DDR_DX0DQSTR 0x3DB02000
|
|
+#define DDR_DX1GCR 0x0000CE81
|
|
+#define DDR_DX1DLLCR 0x40000000
|
|
+#define DDR_DX1DQTR 0xFFFFFFFF
|
|
+#define DDR_DX1DQSTR 0x3DB02000
|
|
+#define DDR_DX2GCR 0x0000CE81
|
|
+#define DDR_DX2DLLCR 0x40000000
|
|
+#define DDR_DX2DQTR 0xFFFFFFFF
|
|
+#define DDR_DX2DQSTR 0x3DB02000
|
|
+#define DDR_DX3GCR 0x0000CE81
|
|
+#define DDR_DX3DLLCR 0x40000000
|
|
+#define DDR_DX3DQTR 0xFFFFFFFF
|
|
+#define DDR_DX3DQSTR 0x3DB02000
|
|
+
|
|
+#include "stm32mp15-ddr.dtsi"
|
|
diff --git a/fdts/stm32mp15-ddr3-2x4Gb-1066-binG.dtsi b/fdts/stm32mp15-ddr3-2x4Gb-1066-binG.dtsi
|
|
index 58a4cdc..82e7104 100644
|
|
--- a/fdts/stm32mp15-ddr3-2x4Gb-1066-binG.dtsi
|
|
+++ b/fdts/stm32mp15-ddr3-2x4Gb-1066-binG.dtsi
|
|
@@ -3,7 +3,7 @@
|
|
* Copyright (C) 2018, STMicroelectronics - All Rights Reserved
|
|
*/
|
|
|
|
-/* STM32MP157C ED1 and ED2 BOARD configuration
|
|
+/* STM32MP157C ED1 BOARD configuration
|
|
* 2x DDR3L 4Gb each, 16-bit, 533MHz, Single Die Package in flyby topology.
|
|
* Reference used NT5CC256M16DP-DI from NANYA
|
|
*
|
|
@@ -15,10 +15,11 @@
|
|
* timing mode optimized
|
|
* Scheduling/QoS options : type = 2
|
|
* address mapping : RBC
|
|
+ * Tc > + 85C : N
|
|
*/
|
|
|
|
-#define DDR_MEM_NAME "DDR3-1066 bin G 2x4Gb 533MHz v1.39"
|
|
-#define DDR_MEM_SPEED 533
|
|
+#define DDR_MEM_NAME "DDR3-1066/888 bin G 2x4Gb 533MHz v1.41"
|
|
+#define DDR_MEM_SPEED 533000
|
|
#define DDR_MEM_SIZE 0x40000000
|
|
|
|
#define DDR_MSTR 0x00040401
|
|
@@ -62,7 +63,7 @@
|
|
#define DDR_ADDRMAP11 0x00000000
|
|
#define DDR_ODTCFG 0x06000600
|
|
#define DDR_ODTMAP 0x00000001
|
|
-#define DDR_SCHED 0x00001201
|
|
+#define DDR_SCHED 0x00000C01
|
|
#define DDR_SCHED1 0x00000000
|
|
#define DDR_PERFHPR1 0x01000001
|
|
#define DDR_PERFLPR1 0x08000200
|
|
@@ -74,15 +75,15 @@
|
|
#define DDR_PCCFG 0x00000010
|
|
#define DDR_PCFGR_0 0x00010000
|
|
#define DDR_PCFGW_0 0x00000000
|
|
-#define DDR_PCFGQOS0_0 0x02100B03
|
|
+#define DDR_PCFGQOS0_0 0x02100C03
|
|
#define DDR_PCFGQOS1_0 0x00800100
|
|
-#define DDR_PCFGWQOS0_0 0x01100B03
|
|
+#define DDR_PCFGWQOS0_0 0x01100C03
|
|
#define DDR_PCFGWQOS1_0 0x01000200
|
|
#define DDR_PCFGR_1 0x00010000
|
|
#define DDR_PCFGW_1 0x00000000
|
|
-#define DDR_PCFGQOS0_1 0x02100B03
|
|
-#define DDR_PCFGQOS1_1 0x00800000
|
|
-#define DDR_PCFGWQOS0_1 0x01100B03
|
|
+#define DDR_PCFGQOS0_1 0x02100C03
|
|
+#define DDR_PCFGQOS1_1 0x00800040
|
|
+#define DDR_PCFGWQOS0_1 0x01100C03
|
|
#define DDR_PCFGWQOS1_1 0x01000200
|
|
#define DDR_PGCR 0x01442E02
|
|
#define DDR_PTR0 0x0022AA5B
|
|
diff --git a/fdts/stm32mp157-pinctrl.dtsi b/fdts/stm32mp157-pinctrl.dtsi
|
|
index 21bd34e..8037e4f 100644
|
|
--- a/fdts/stm32mp157-pinctrl.dtsi
|
|
+++ b/fdts/stm32mp157-pinctrl.dtsi
|
|
@@ -3,13 +3,14 @@
|
|
* Copyright (C) STMicroelectronics 2017 - All Rights Reserved
|
|
* Author: Ludovic Barre <ludovic.barre@st.com> for STMicroelectronics.
|
|
*/
|
|
-
|
|
#include <dt-bindings/pinctrl/stm32-pinfunc.h>
|
|
+
|
|
/ {
|
|
soc {
|
|
- pinctrl: pin-controller {
|
|
+ pinctrl: pin-controller@50002000 {
|
|
#address-cells = <1>;
|
|
#size-cells = <1>;
|
|
+ compatible = "st,stm32mp157-pinctrl";
|
|
ranges = <0 0x50002000 0xa400>;
|
|
pins-are-numbered;
|
|
|
|
@@ -134,54 +135,76 @@
|
|
status = "disabled";
|
|
};
|
|
|
|
- uart4_pins_a: uart4@0 {
|
|
+ qspi_bk1_pins_a: qspi-bk1-0 {
|
|
pins1 {
|
|
- pinmux = <STM32_PINMUX('G', 11, AF6)>; /* UART4_TX */
|
|
+ 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 = <0>;
|
|
+ slew-rate = <1>;
|
|
};
|
|
pins2 {
|
|
- pinmux = <STM32_PINMUX('B', 2, AF8)>; /* UART4_RX */
|
|
- bias-disable;
|
|
+ pinmux = <STM32_PINMUX('B', 6, AF10)>; /* QSPI_BK1_NCS */
|
|
+ bias-pull-up;
|
|
+ drive-push-pull;
|
|
+ slew-rate = <1>;
|
|
};
|
|
};
|
|
|
|
- usart3_pins_a: usart3@0 {
|
|
+ qspi_bk2_pins_a: qspi-bk2-0 {
|
|
pins1 {
|
|
- pinmux = <STM32_PINMUX('B', 10, AF7)>, /* USART3_TX */
|
|
- <STM32_PINMUX('G', 8, AF8)>; /* USART3_RTS */
|
|
+ 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 = <0>;
|
|
+ slew-rate = <1>;
|
|
};
|
|
pins2 {
|
|
- pinmux = <STM32_PINMUX('B', 12, AF8)>, /* USART3_RX */
|
|
- <STM32_PINMUX('I', 10, AF8)>; /* USART3_CTS_NSS */
|
|
- bias-disable;
|
|
+ pinmux = <STM32_PINMUX('C', 0, AF10)>; /* QSPI_BK2_NCS */
|
|
+ bias-pull-up;
|
|
+ drive-push-pull;
|
|
+ slew-rate = <1>;
|
|
};
|
|
};
|
|
|
|
- sdmmc1_b4_pins_a: sdmmc1-b4@0 {
|
|
+ qspi_clk_pins_a: qspi-clk-0 {
|
|
pins {
|
|
+ pinmux = <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('C', 12, AF12)>, /* SDMMC1_CK */
|
|
<STM32_PINMUX('D', 2, AF12)>; /* SDMMC1_CMD */
|
|
- slew-rate = <3>;
|
|
+ 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 {
|
|
+ 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 = <3>;
|
|
+ slew-rate = <1>;
|
|
drive-push-pull;
|
|
bias-pull-up;
|
|
};
|
|
@@ -191,36 +214,113 @@
|
|
};
|
|
};
|
|
|
|
- sdmmc2_b4_pins_a: sdmmc2-b4@0 {
|
|
- pins {
|
|
+ sdmmc1_dir_pins_b: sdmmc1-dir-1 {
|
|
+ pins1 {
|
|
+ pinmux = <STM32_PINMUX('E', 12, AF8)>, /* SDMMC1_D0DIR */
|
|
+ <STM32_PINMUX('E', 14, AF11)>, /* SDMMC1_D123DIR */
|
|
+ <STM32_PINMUX('B', 9, AF11)>; /* SDMMC1_CDIR */
|
|
+ slew-rate = <3>;
|
|
+ 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('E', 3, AF9)>, /* SDMMC2_CK */
|
|
<STM32_PINMUX('G', 6, AF10)>; /* SDMMC2_CMD */
|
|
- slew-rate = <3>;
|
|
+ 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 {
|
|
+ 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 = <3>;
|
|
+ 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;
|
|
+ };
|
|
+ };
|
|
+
|
|
+ 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 {
|
|
+ pinctrl_z: pin-controller-z@54004000 {
|
|
#address-cells = <1>;
|
|
#size-cells = <1>;
|
|
+ compatible = "st,stm32mp157-z-pinctrl";
|
|
ranges = <0 0x54004000 0x400>;
|
|
pins-are-numbered;
|
|
|
|
@@ -236,7 +336,7 @@
|
|
status = "disabled";
|
|
};
|
|
|
|
- i2c4_pins_a: i2c4@0 {
|
|
+ i2c4_pins_a: i2c4-0 {
|
|
pins {
|
|
pinmux = <STM32_PINMUX('Z', 4, AF6)>, /* I2C4_SCL */
|
|
<STM32_PINMUX('Z', 5, AF6)>; /* I2C4_SDA */
|
|
diff --git a/fdts/stm32mp157a-dk1.dts b/fdts/stm32mp157a-dk1.dts
|
|
new file mode 100644
|
|
index 0000000..fadb442
|
|
--- /dev/null
|
|
+++ b/fdts/stm32mp157a-dk1.dts
|
|
@@ -0,0 +1,464 @@
|
|
+// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
|
|
+/*
|
|
+ * Copyright (C) STMicroelectronics 2018-2019 - All Rights Reserved
|
|
+ * Author: Alexandre Torgue <alexandre.torgue@st.com>.
|
|
+ */
|
|
+
|
|
+/dts-v1/;
|
|
+
|
|
+#include "stm32mp157c.dtsi"
|
|
+#include "stm32mp157cac-pinctrl.dtsi"
|
|
+
|
|
+/ {
|
|
+ model = "STMicroelectronics STM32MP157A-DK1 Discovery Board";
|
|
+ compatible = "st,stm32mp157a-dk1", "st,stm32mp157";
|
|
+
|
|
+ aliases {
|
|
+ serial0 = &uart4;
|
|
+ serial1 = &usart3;
|
|
+ serial2 = &uart7;
|
|
+ };
|
|
+
|
|
+ chosen {
|
|
+ stdout-path = "serial0:115200n8";
|
|
+ };
|
|
+
|
|
+};
|
|
+
|
|
+&clk_hse {
|
|
+ st,digbypass;
|
|
+};
|
|
+
|
|
+&i2c4 {
|
|
+ pinctrl-names = "default";
|
|
+ pinctrl-0 = <&i2c4_pins_a>;
|
|
+ i2c-scl-rising-time-ns = <185>;
|
|
+ i2c-scl-falling-time-ns = <20>;
|
|
+ status = "okay";
|
|
+
|
|
+ pmic: stpmic@33 {
|
|
+ compatible = "st,stpmic1";
|
|
+ reg = <0x33>;
|
|
+ interrupts-extended = <&exti_pwr 55 IRQ_TYPE_EDGE_FALLING>;
|
|
+ interrupt-controller;
|
|
+ #interrupt-cells = <2>;
|
|
+ status = "okay";
|
|
+
|
|
+ st,main-control-register = <0x04>;
|
|
+ st,vin-control-register = <0xc0>;
|
|
+ st,usb-control-register = <0x20>;
|
|
+
|
|
+ regulators {
|
|
+ compatible = "st,stpmic1-regulators";
|
|
+
|
|
+ ldo1-supply = <&v3v3>;
|
|
+ ldo3-supply = <&vdd_ddr>;
|
|
+ ldo6-supply = <&v3v3>;
|
|
+
|
|
+ vddcore: buck1 {
|
|
+ regulator-name = "vddcore";
|
|
+ regulator-min-microvolt = <1200000>;
|
|
+ regulator-max-microvolt = <1350000>;
|
|
+ regulator-always-on;
|
|
+ regulator-initial-mode = <0>;
|
|
+ regulator-over-current-protection;
|
|
+ };
|
|
+
|
|
+ vdd_ddr: buck2 {
|
|
+ regulator-name = "vdd_ddr";
|
|
+ regulator-min-microvolt = <1350000>;
|
|
+ regulator-max-microvolt = <1350000>;
|
|
+ regulator-always-on;
|
|
+ regulator-initial-mode = <0>;
|
|
+ regulator-over-current-protection;
|
|
+ };
|
|
+
|
|
+ vdd: buck3 {
|
|
+ regulator-name = "vdd";
|
|
+ regulator-min-microvolt = <3300000>;
|
|
+ regulator-max-microvolt = <3300000>;
|
|
+ regulator-always-on;
|
|
+ st,mask-reset;
|
|
+ regulator-initial-mode = <0>;
|
|
+ regulator-over-current-protection;
|
|
+ };
|
|
+
|
|
+ v3v3: buck4 {
|
|
+ regulator-name = "v3v3";
|
|
+ regulator-min-microvolt = <3300000>;
|
|
+ regulator-max-microvolt = <3300000>;
|
|
+ regulator-always-on;
|
|
+ regulator-over-current-protection;
|
|
+ regulator-initial-mode = <0>;
|
|
+ };
|
|
+
|
|
+ v1v8_audio: ldo1 {
|
|
+ regulator-name = "v1v8_audio";
|
|
+ regulator-min-microvolt = <1800000>;
|
|
+ regulator-max-microvolt = <1800000>;
|
|
+ regulator-always-on;
|
|
+ };
|
|
+
|
|
+ v3v3_hdmi: ldo2 {
|
|
+ regulator-name = "v3v3_hdmi";
|
|
+ regulator-min-microvolt = <3300000>;
|
|
+ regulator-max-microvolt = <3300000>;
|
|
+ regulator-always-on;
|
|
+ };
|
|
+
|
|
+ vtt_ddr: ldo3 {
|
|
+ regulator-name = "vtt_ddr";
|
|
+ regulator-min-microvolt = <500000>;
|
|
+ regulator-max-microvolt = <750000>;
|
|
+ regulator-always-on;
|
|
+ regulator-over-current-protection;
|
|
+ };
|
|
+
|
|
+ vdd_usb: ldo4 {
|
|
+ regulator-name = "vdd_usb";
|
|
+ regulator-min-microvolt = <3300000>;
|
|
+ regulator-max-microvolt = <3300000>;
|
|
+ };
|
|
+
|
|
+ vdda: ldo5 {
|
|
+ regulator-name = "vdda";
|
|
+ regulator-min-microvolt = <2900000>;
|
|
+ regulator-max-microvolt = <2900000>;
|
|
+ regulator-boot-on;
|
|
+ };
|
|
+
|
|
+ v1v2_hdmi: ldo6 {
|
|
+ regulator-name = "v1v2_hdmi";
|
|
+ regulator-min-microvolt = <1200000>;
|
|
+ regulator-max-microvolt = <1200000>;
|
|
+ regulator-always-on;
|
|
+ };
|
|
+
|
|
+ vref_ddr: vref_ddr {
|
|
+ regulator-name = "vref_ddr";
|
|
+ regulator-always-on;
|
|
+ regulator-over-current-protection;
|
|
+ };
|
|
+ };
|
|
+ };
|
|
+};
|
|
+
|
|
+&iwdg2 {
|
|
+ timeout-sec = <32>;
|
|
+ status = "okay";
|
|
+};
|
|
+
|
|
+&pwr {
|
|
+ pwr-supply = <&vdd>;
|
|
+};
|
|
+
|
|
+&rng1 {
|
|
+ status = "okay";
|
|
+};
|
|
+
|
|
+&rtc {
|
|
+ status = "okay";
|
|
+};
|
|
+
|
|
+&sdmmc1 {
|
|
+ pinctrl-names = "default";
|
|
+ pinctrl-0 = <&sdmmc1_b4_pins_a>;
|
|
+ broken-cd;
|
|
+ st,neg-edge;
|
|
+ bus-width = <4>;
|
|
+ vmmc-supply = <&v3v3>;
|
|
+ status = "okay";
|
|
+};
|
|
+
|
|
+&uart4 {
|
|
+ pinctrl-names = "default";
|
|
+ pinctrl-0 = <&uart4_pins_a>;
|
|
+ status = "okay";
|
|
+};
|
|
+
|
|
+&uart7 {
|
|
+ pinctrl-names = "default";
|
|
+ pinctrl-0 = <&uart7_pins_a>;
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+&usart3 {
|
|
+ pinctrl-names = "default";
|
|
+ pinctrl-0 = <&usart3_pins_b>;
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+
|
|
+/* ATF Specific */
|
|
+#include <dt-bindings/clock/stm32mp1-clksrc.h>
|
|
+#include <dt-bindings/power/stm32mp1-power.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 = "okay";
|
|
+ st,hsi-cal;
|
|
+ st,csi-cal;
|
|
+ st,cal-sec = <60>;
|
|
+ st,clksrc = <
|
|
+ CLK_MPU_PLL1P
|
|
+ CLK_AXI_PLL2P
|
|
+ CLK_MCU_PLL3P
|
|
+ CLK_PLL12_HSE
|
|
+ CLK_PLL3_HSE
|
|
+ CLK_PLL4_HSE
|
|
+ CLK_RTC_LSE
|
|
+ CLK_MCO1_DISABLED
|
|
+ CLK_MCO2_DISABLED
|
|
+ >;
|
|
+
|
|
+ st,clkdiv = <
|
|
+ 1 /*MPU*/
|
|
+ 0 /*AXI*/
|
|
+ 0 /*MCU*/
|
|
+ 1 /*APB1*/
|
|
+ 1 /*APB2*/
|
|
+ 1 /*APB3*/
|
|
+ 1 /*APB4*/
|
|
+ 2 /*APB5*/
|
|
+ 23 /*RTC*/
|
|
+ 0 /*MCO1*/
|
|
+ 0 /*MCO2*/
|
|
+ >;
|
|
+
|
|
+ st,pkcs = <
|
|
+ CLK_CKPER_HSE
|
|
+ CLK_FMC_ACLK
|
|
+ CLK_QSPI_ACLK
|
|
+ CLK_ETH_DISABLED
|
|
+ CLK_SDMMC12_PLL4P
|
|
+ CLK_DSI_DSIPLL
|
|
+ CLK_STGEN_HSE
|
|
+ CLK_USBPHY_HSE
|
|
+ CLK_SPI2S1_PLL3Q
|
|
+ CLK_SPI2S23_PLL3Q
|
|
+ CLK_SPI45_HSI
|
|
+ CLK_SPI6_HSI
|
|
+ CLK_I2C46_HSI
|
|
+ CLK_SDMMC3_PLL4P
|
|
+ CLK_USBO_USBPHY
|
|
+ CLK_ADC_CKPER
|
|
+ CLK_CEC_LSE
|
|
+ CLK_I2C12_HSI
|
|
+ CLK_I2C35_HSI
|
|
+ CLK_UART1_HSI
|
|
+ CLK_UART24_HSI
|
|
+ CLK_UART35_HSI
|
|
+ CLK_UART6_HSI
|
|
+ CLK_UART78_HSI
|
|
+ CLK_SPDIF_PLL4P
|
|
+ CLK_FDCAN_PLL4Q
|
|
+ CLK_SAI1_PLL3Q
|
|
+ CLK_SAI2_PLL3Q
|
|
+ CLK_SAI3_PLL3Q
|
|
+ CLK_SAI4_PLL3Q
|
|
+ CLK_RNG1_LSI
|
|
+ CLK_RNG2_LSI
|
|
+ CLK_LPTIM1_PCLK1
|
|
+ CLK_LPTIM23_PCLK3
|
|
+ CLK_LPTIM45_LSE
|
|
+ >;
|
|
+
|
|
+ /* VCO = 1300.0 MHz => P = 650 (CPU) */
|
|
+ pll1: st,pll@0 {
|
|
+ cfg = < 2 80 0 0 0 PQR(1,0,0) >;
|
|
+ frac = < 0x800 >;
|
|
+ };
|
|
+
|
|
+ /* VCO = 1066.0 MHz => P = 266 (AXI), Q = 533 (GPU), R = 533 (DDR) */
|
|
+ pll2: st,pll@1 {
|
|
+ cfg = < 2 65 1 0 0 PQR(1,1,1) >;
|
|
+ frac = < 0x1400 >;
|
|
+ };
|
|
+
|
|
+ /* VCO = 417.8 MHz => P = 209, Q = 24, R = 11 */
|
|
+ pll3: st,pll@2 {
|
|
+ cfg = < 1 33 1 16 36 PQR(1,1,1) >;
|
|
+ frac = < 0x1a04 >;
|
|
+ };
|
|
+
|
|
+ /* VCO = 594.0 MHz => P = 99, Q = 74, R = 74 */
|
|
+ pll4: st,pll@3 {
|
|
+ cfg = < 3 98 5 7 7 PQR(1,1,1) >;
|
|
+ };
|
|
+};
|
|
+
|
|
+/* Security specific */
|
|
+&etzpc {
|
|
+ st,decprot = <
|
|
+ DECPROT(STM32MP1_ETZPC_USART1_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
|
|
+ DECPROT(STM32MP1_ETZPC_SPI6_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
|
|
+ DECPROT(STM32MP1_ETZPC_I2C4_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
|
|
+ DECPROT(STM32MP1_ETZPC_I2C6_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
|
|
+ DECPROT(STM32MP1_ETZPC_RNG1_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
|
|
+ DECPROT(STM32MP1_ETZPC_HASH1_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
|
|
+ DECPROT(STM32MP1_ETZPC_CRYP1_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
|
|
+ >;
|
|
+};
|
|
+
|
|
+&iwdg2 {
|
|
+ secure-status = "okay";
|
|
+};
|
|
+
|
|
+&pwr {
|
|
+ system_suspend_supported_soc_modes = <
|
|
+ STM32_PM_CSLEEP_RUN
|
|
+ STM32_PM_CSTOP_ALLOW_LP_STOP
|
|
+ STM32_PM_CSTOP_ALLOW_STANDBY_DDR_SR
|
|
+ >;
|
|
+
|
|
+ system_off_soc_mode = <STM32_PM_CSTOP_ALLOW_STANDBY_DDR_OFF>;
|
|
+};
|
|
+
|
|
+&timers15 {
|
|
+ secure-status = "okay";
|
|
+ st,hsi-cal-input = <7>;
|
|
+ st,csi_cal-input = <8>;
|
|
+};
|
|
+
|
|
+/* Low-power states of regulators */
|
|
+&vddcore {
|
|
+ lp-stop {
|
|
+ regulator-on-in-suspend;
|
|
+ regulator-suspend-microvolt = <1200000>;
|
|
+ };
|
|
+ standby-ddr-sr {
|
|
+ regulator-off-in-suspend;
|
|
+ };
|
|
+ standby-ddr-off {
|
|
+ regulator-off-in-suspend;
|
|
+ };
|
|
+};
|
|
+
|
|
+&vdd_ddr {
|
|
+ lp-stop {
|
|
+ regulator-suspend-microvolt = <1350000>;
|
|
+ regulator-on-in-suspend;
|
|
+ };
|
|
+ standby-ddr-sr {
|
|
+ regulator-suspend-microvolt = <1350000>;
|
|
+ regulator-on-in-suspend;
|
|
+ };
|
|
+ standby-ddr-off {
|
|
+ regulator-off-in-suspend;
|
|
+ };
|
|
+};
|
|
+
|
|
+&vdd {
|
|
+ lp-stop {
|
|
+ regulator-suspend-microvolt = <3300000>;
|
|
+ regulator-on-in-suspend;
|
|
+ };
|
|
+ standby-ddr-sr {
|
|
+ regulator-suspend-microvolt = <3300000>;
|
|
+ regulator-on-in-suspend;
|
|
+ };
|
|
+ standby-ddr-off {
|
|
+ regulator-suspend-microvolt = <3300000>;
|
|
+ regulator-on-in-suspend;
|
|
+ };
|
|
+};
|
|
+
|
|
+&v3v3 {
|
|
+ lp-stop {
|
|
+ regulator-suspend-microvolt = <3300000>;
|
|
+ regulator-on-in-suspend;
|
|
+ };
|
|
+ standby-ddr-sr {
|
|
+ regulator-off-in-suspend;
|
|
+ };
|
|
+ standby-ddr-off {
|
|
+ regulator-off-in-suspend;
|
|
+ };
|
|
+};
|
|
+
|
|
+&v1v8_audio {
|
|
+ standby-ddr-sr {
|
|
+ regulator-off-in-suspend;
|
|
+ };
|
|
+ standby-ddr-off {
|
|
+ regulator-off-in-suspend;
|
|
+ };
|
|
+};
|
|
+
|
|
+&v3v3_hdmi {
|
|
+ standby-ddr-sr {
|
|
+ regulator-off-in-suspend;
|
|
+ };
|
|
+ standby-ddr-off {
|
|
+ regulator-off-in-suspend;
|
|
+ };
|
|
+};
|
|
+
|
|
+&vtt_ddr {
|
|
+ lp-stop {
|
|
+ regulator-off-in-suspend;
|
|
+ };
|
|
+ standby-ddr-sr {
|
|
+ regulator-off-in-suspend;
|
|
+ };
|
|
+ standby-ddr-off {
|
|
+ regulator-off-in-suspend;
|
|
+ };
|
|
+};
|
|
+
|
|
+&vdd_usb {
|
|
+ standby-ddr-sr {
|
|
+ regulator-off-in-suspend;
|
|
+ };
|
|
+ standby-ddr-off {
|
|
+ regulator-off-in-suspend;
|
|
+ };
|
|
+};
|
|
+
|
|
+&vdda {
|
|
+ standby-ddr-sr {
|
|
+ regulator-off-in-suspend;
|
|
+ };
|
|
+ standby-ddr-off {
|
|
+ regulator-off-in-suspend;
|
|
+ };
|
|
+};
|
|
+
|
|
+&v1v2_hdmi {
|
|
+ standby-ddr-sr {
|
|
+ regulator-off-in-suspend;
|
|
+ };
|
|
+ standby-ddr-off {
|
|
+ regulator-off-in-suspend;
|
|
+ };
|
|
+};
|
|
+
|
|
+&vref_ddr {
|
|
+ lp-stop {
|
|
+ regulator-on-in-suspend;
|
|
+ };
|
|
+ standby-ddr-sr {
|
|
+ regulator-on-in-suspend;
|
|
+ };
|
|
+ standby-ddr-off {
|
|
+ regulator-off-in-suspend;
|
|
+ };
|
|
+};
|
|
diff --git a/fdts/stm32mp157c-dk2.dts b/fdts/stm32mp157c-dk2.dts
|
|
new file mode 100644
|
|
index 0000000..fdcf4c8
|
|
--- /dev/null
|
|
+++ b/fdts/stm32mp157c-dk2.dts
|
|
@@ -0,0 +1,16 @@
|
|
+// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
|
|
+/*
|
|
+ * Copyright (C) STMicroelectronics 2018 - All Rights Reserved
|
|
+ * Author: Alexandre Torgue <alexandre.torgue@st.com>.
|
|
+ */
|
|
+
|
|
+/dts-v1/;
|
|
+
|
|
+#include "stm32mp157a-dk1.dts"
|
|
+
|
|
+/ {
|
|
+ model = "STMicroelectronics STM32MP157C-DK2 Discovery Board";
|
|
+ compatible = "st,stm32mp157c-dk2", "st,stm32mp157";
|
|
+
|
|
+};
|
|
+
|
|
diff --git a/fdts/stm32mp157c-ed1.dts b/fdts/stm32mp157c-ed1.dts
|
|
index e3dabe8..0daf4be 100644
|
|
--- a/fdts/stm32mp157c-ed1.dts
|
|
+++ b/fdts/stm32mp157c-ed1.dts
|
|
@@ -1,24 +1,30 @@
|
|
// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
|
|
/*
|
|
- * Copyright (C) STMicroelectronics 2017 - All Rights Reserved
|
|
+ * Copyright (C) STMicroelectronics 2017-2019 - All Rights Reserved
|
|
* Author: Ludovic Barre <ludovic.barre@st.com> for STMicroelectronics.
|
|
*/
|
|
-
|
|
/dts-v1/;
|
|
|
|
#include "stm32mp157c.dtsi"
|
|
#include "stm32mp157caa-pinctrl.dtsi"
|
|
|
|
/ {
|
|
- model = "STMicroelectronics STM32MP157C-ED1 pmic eval daughter";
|
|
+ model = "STMicroelectronics STM32MP157C eval daughter";
|
|
compatible = "st,stm32mp157c-ed1", "st,stm32mp157";
|
|
|
|
chosen {
|
|
- bootargs = "earlyprintk console=ttyS3,115200 root=/dev/ram";
|
|
- stdout-path = "serial3:115200n8";
|
|
+ stdout-path = "serial0:115200n8";
|
|
+ };
|
|
+
|
|
+ aliases {
|
|
+ serial0 = &uart4;
|
|
};
|
|
};
|
|
|
|
+&clk_hse {
|
|
+ st,digbypass;
|
|
+};
|
|
+
|
|
&i2c4 {
|
|
pinctrl-names = "default";
|
|
pinctrl-0 = <&i2c4_pins_a>;
|
|
@@ -26,37 +32,88 @@
|
|
i2c-scl-falling-time-ns = <20>;
|
|
status = "okay";
|
|
|
|
- pmic: stpmu1@33 {
|
|
- compatible = "st,stpmu1";
|
|
+ pmic: stpmic@33 {
|
|
+ compatible = "st,stpmic1";
|
|
reg = <0x33>;
|
|
+ interrupts-extended = <&exti_pwr 55 IRQ_TYPE_EDGE_FALLING>;
|
|
+ interrupt-controller;
|
|
+ #interrupt-cells = <2>;
|
|
status = "okay";
|
|
|
|
- st,main_control_register = <0x04>;
|
|
- st,vin_control_register = <0xc0>;
|
|
- st,usb_control_register = <0x30>;
|
|
+ st,main-control-register = <0x04>;
|
|
+ st,vin-control-register = <0xc0>;
|
|
+ st,usb-control-register = <0x20>;
|
|
|
|
regulators {
|
|
- compatible = "st,stpmu1-regulators";
|
|
+ compatible = "st,stpmic1-regulators";
|
|
+
|
|
+ ldo1-supply = <&v3v3>;
|
|
+ ldo2-supply = <&v3v3>;
|
|
+ ldo3-supply = <&vdd_ddr>;
|
|
+ ldo5-supply = <&v3v3>;
|
|
+ ldo6-supply = <&v3v3>;
|
|
+
|
|
+ vddcore: buck1 {
|
|
+ regulator-name = "vddcore";
|
|
+ regulator-min-microvolt = <1200000>;
|
|
+ regulator-max-microvolt = <1350000>;
|
|
+ regulator-always-on;
|
|
+ regulator-initial-mode = <0>;
|
|
+ regulator-over-current-protection;
|
|
+ };
|
|
+
|
|
+ vdd_ddr: buck2 {
|
|
+ regulator-name = "vdd_ddr";
|
|
+ regulator-min-microvolt = <1350000>;
|
|
+ regulator-max-microvolt = <1350000>;
|
|
+ regulator-always-on;
|
|
+ regulator-initial-mode = <0>;
|
|
+ regulator-over-current-protection;
|
|
+ };
|
|
+
|
|
+ vdd: buck3 {
|
|
+ regulator-name = "vdd";
|
|
+ regulator-min-microvolt = <3300000>;
|
|
+ regulator-max-microvolt = <3300000>;
|
|
+ regulator-always-on;
|
|
+ st,mask-reset;
|
|
+ regulator-initial-mode = <0>;
|
|
+ regulator-over-current-protection;
|
|
+ };
|
|
|
|
v3v3: buck4 {
|
|
regulator-name = "v3v3";
|
|
regulator-min-microvolt = <3300000>;
|
|
regulator-max-microvolt = <3300000>;
|
|
- regulator-boot-on;
|
|
+ regulator-always-on;
|
|
+ regulator-over-current-protection;
|
|
+ regulator-initial-mode = <0>;
|
|
+ };
|
|
+
|
|
+ vdda: ldo1 {
|
|
+ regulator-name = "vdda";
|
|
+ regulator-min-microvolt = <2900000>;
|
|
+ regulator-max-microvolt = <2900000>;
|
|
+ };
|
|
+
|
|
+ v2v8: ldo2 {
|
|
+ regulator-name = "v2v8";
|
|
+ regulator-min-microvolt = <2800000>;
|
|
+ regulator-max-microvolt = <2800000>;
|
|
+ };
|
|
+
|
|
+ vtt_ddr: ldo3 {
|
|
+ regulator-name = "vtt_ddr";
|
|
+ regulator-min-microvolt = <500000>;
|
|
+ regulator-max-microvolt = <750000>;
|
|
+ regulator-always-on;
|
|
regulator-over-current-protection;
|
|
- regulator-initial-mode = <8>;
|
|
-
|
|
- regulator-state-standby {
|
|
- regulator-suspend-microvolt = <3300000>;
|
|
- regulator-unchanged-in-suspend;
|
|
- regulator-mode = <8>;
|
|
- };
|
|
- regulator-state-mem {
|
|
- regulator-off-in-suspend;
|
|
- };
|
|
- regulator-state-disk {
|
|
- regulator-off-in-suspend;
|
|
- };
|
|
+ };
|
|
+
|
|
+ vdd_usb: ldo4 {
|
|
+ regulator-name = "vdd_usb";
|
|
+ regulator-min-microvolt = <3300000>;
|
|
+ regulator-max-microvolt = <3300000>;
|
|
};
|
|
|
|
vdd_sd: ldo5 {
|
|
@@ -64,40 +121,49 @@
|
|
regulator-min-microvolt = <2900000>;
|
|
regulator-max-microvolt = <2900000>;
|
|
regulator-boot-on;
|
|
+ };
|
|
|
|
- regulator-state-standby {
|
|
- regulator-suspend-microvolt = <2900000>;
|
|
- regulator-unchanged-in-suspend;
|
|
- };
|
|
- regulator-state-mem {
|
|
- regulator-off-in-suspend;
|
|
- };
|
|
- regulator-state-disk {
|
|
- regulator-off-in-suspend;
|
|
- };
|
|
+ v1v8: ldo6 {
|
|
+ regulator-name = "v1v8";
|
|
+ regulator-min-microvolt = <1800000>;
|
|
+ regulator-max-microvolt = <1800000>;
|
|
+ };
|
|
+
|
|
+ vref_ddr: vref_ddr {
|
|
+ regulator-name = "vref_ddr";
|
|
+ regulator-always-on;
|
|
+ regulator-over-current-protection;
|
|
};
|
|
};
|
|
};
|
|
};
|
|
|
|
&iwdg2 {
|
|
- instance = <2>;
|
|
timeout-sec = <32>;
|
|
status = "okay";
|
|
};
|
|
|
|
+&pwr {
|
|
+ pwr-supply = <&vdd>;
|
|
+};
|
|
+
|
|
&rng1 {
|
|
status = "okay";
|
|
};
|
|
|
|
+&rtc {
|
|
+ status = "okay";
|
|
+};
|
|
+
|
|
&sdmmc1 {
|
|
pinctrl-names = "default";
|
|
pinctrl-0 = <&sdmmc1_b4_pins_a &sdmmc1_dir_pins_a>;
|
|
broken-cd;
|
|
- st,dirpol;
|
|
- st,negedge;
|
|
- st,pin-ckin;
|
|
+ st,sig-dir;
|
|
+ st,neg-edge;
|
|
+ st,use-ckin;
|
|
bus-width = <4>;
|
|
+ vmmc-supply = <&vdd_sd>;
|
|
sd-uhs-sdr12;
|
|
sd-uhs-sdr25;
|
|
sd-uhs-sdr50;
|
|
@@ -112,22 +178,25 @@
|
|
non-removable;
|
|
no-sd;
|
|
no-sdio;
|
|
- st,dirpol;
|
|
- st,negedge;
|
|
+ st,neg-edge;
|
|
bus-width = <8>;
|
|
+ vmmc-supply = <&v3v3>;
|
|
+ vqmmc-supply = <&v3v3>;
|
|
+ mmc-ddr-3_3v;
|
|
status = "okay";
|
|
};
|
|
|
|
&uart4 {
|
|
pinctrl-names = "default";
|
|
pinctrl-0 = <&uart4_pins_a>;
|
|
- resets = <&rcc UART4_R>;
|
|
status = "okay";
|
|
};
|
|
|
|
/* ATF Specific */
|
|
#include <dt-bindings/clock/stm32mp1-clksrc.h>
|
|
+#include <dt-bindings/power/stm32mp1-power.h>
|
|
#include "stm32mp15-ddr3-2x4Gb-1066-binG.dtsi"
|
|
+#include "stm32mp157c-security.dtsi"
|
|
|
|
/ {
|
|
aliases {
|
|
@@ -145,21 +214,18 @@
|
|
gpio25 = &gpioz;
|
|
i2c3 = &i2c4;
|
|
};
|
|
-
|
|
- soc {
|
|
- stgen: stgen@5C008000 {
|
|
- compatible = "st,stm32-stgen";
|
|
- reg = <0x5C008000 0x1000>;
|
|
- status = "okay";
|
|
- };
|
|
- };
|
|
};
|
|
|
|
/* CLOCK init */
|
|
&rcc {
|
|
+ secure-status = "okay";
|
|
+ st,hsi-cal;
|
|
+ st,csi-cal;
|
|
+ st,cal-sec = <60>;
|
|
st,clksrc = <
|
|
CLK_MPU_PLL1P
|
|
CLK_AXI_PLL2P
|
|
+ CLK_MCU_PLL3P
|
|
CLK_PLL12_HSE
|
|
CLK_PLL3_HSE
|
|
CLK_PLL4_HSE
|
|
@@ -171,6 +237,7 @@
|
|
st,clkdiv = <
|
|
1 /*MPU*/
|
|
0 /*AXI*/
|
|
+ 0 /*MCU*/
|
|
1 /*APB1*/
|
|
1 /*APB2*/
|
|
1 /*APB3*/
|
|
@@ -186,7 +253,7 @@
|
|
CLK_FMC_ACLK
|
|
CLK_QSPI_ACLK
|
|
CLK_ETH_DISABLED
|
|
- CLK_SDMMC12_PLL3R
|
|
+ CLK_SDMMC12_PLL4P
|
|
CLK_DSI_DSIPLL
|
|
CLK_STGEN_HSE
|
|
CLK_USBPHY_HSE
|
|
@@ -195,7 +262,7 @@
|
|
CLK_SPI45_HSI
|
|
CLK_SPI6_HSI
|
|
CLK_I2C46_HSI
|
|
- CLK_SDMMC3_PLL3R
|
|
+ CLK_SDMMC3_PLL4P
|
|
CLK_USBO_USBPHY
|
|
CLK_ADC_CKPER
|
|
CLK_CEC_LSE
|
|
@@ -206,17 +273,17 @@
|
|
CLK_UART35_HSI
|
|
CLK_UART6_HSI
|
|
CLK_UART78_HSI
|
|
- CLK_SPDIF_PLL3Q
|
|
+ CLK_SPDIF_PLL4P
|
|
CLK_FDCAN_PLL4Q
|
|
CLK_SAI1_PLL3Q
|
|
CLK_SAI2_PLL3Q
|
|
CLK_SAI3_PLL3Q
|
|
CLK_SAI4_PLL3Q
|
|
- CLK_RNG1_CSI
|
|
- CLK_RNG2_CSI
|
|
+ CLK_RNG1_LSI
|
|
+ CLK_RNG2_LSI
|
|
CLK_LPTIM1_PCLK1
|
|
CLK_LPTIM23_PCLK3
|
|
- CLK_LPTIM45_PCLK3
|
|
+ CLK_LPTIM45_LSE
|
|
>;
|
|
|
|
/* VCO = 1300.0 MHz => P = 650 (CPU) */
|
|
@@ -231,16 +298,167 @@
|
|
frac = < 0x1400 >;
|
|
};
|
|
|
|
- /* VCO = 786.4 MHz => P = 197, Q = 49, R = 98 */
|
|
+ /* VCO = 417.8 MHz => P = 209, Q = 24, R = 11 */
|
|
pll3: st,pll@2 {
|
|
- cfg = < 2 97 3 15 7 PQR(1,1,1) >;
|
|
- frac = < 0x9ba >;
|
|
+ cfg = < 1 33 1 16 36 PQR(1,1,1) >;
|
|
+ frac = < 0x1a04 >;
|
|
};
|
|
|
|
- /* VCO = 508.0 MHz => P = 56, Q = 56, R = 56 */
|
|
+ /* VCO = 594.0 MHz => P = 99, Q = 74, R = 74 */
|
|
pll4: st,pll@3 {
|
|
- cfg = < 5 126 8 8 8 PQR(1,1,1) >;
|
|
+ cfg = < 3 98 5 7 7 PQR(1,1,1) >;
|
|
};
|
|
};
|
|
|
|
-/delete-node/ &clk_csi;
|
|
+/* Security specific */
|
|
+&etzpc {
|
|
+ st,decprot = <
|
|
+ DECPROT(STM32MP1_ETZPC_USART1_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
|
|
+ DECPROT(STM32MP1_ETZPC_SPI6_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
|
|
+ DECPROT(STM32MP1_ETZPC_I2C4_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
|
|
+ DECPROT(STM32MP1_ETZPC_I2C6_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
|
|
+ DECPROT(STM32MP1_ETZPC_RNG1_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
|
|
+ DECPROT(STM32MP1_ETZPC_HASH1_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
|
|
+ DECPROT(STM32MP1_ETZPC_CRYP1_ID, DECPROT_NS_RW, DECPROT_UNLOCK)
|
|
+ >;
|
|
+};
|
|
+
|
|
+&iwdg2 {
|
|
+ secure-status = "okay";
|
|
+};
|
|
+
|
|
+&pwr {
|
|
+ system_suspend_supported_soc_modes = <
|
|
+ STM32_PM_CSLEEP_RUN
|
|
+ STM32_PM_CSTOP_ALLOW_LP_STOP
|
|
+ STM32_PM_CSTOP_ALLOW_STANDBY_DDR_SR
|
|
+ >;
|
|
+ system_off_soc_mode = <STM32_PM_CSTOP_ALLOW_STANDBY_DDR_OFF>;
|
|
+};
|
|
+
|
|
+&timers15 {
|
|
+ secure-status = "okay";
|
|
+ st,hsi-cal-input = <7>;
|
|
+ st,csi_cal-input = <8>;
|
|
+};
|
|
+
|
|
+/* Low-power states of regulators */
|
|
+&vddcore {
|
|
+ lp-stop {
|
|
+ regulator-on-in-suspend;
|
|
+ regulator-suspend-microvolt = <1200000>;
|
|
+ };
|
|
+ standby-ddr-sr {
|
|
+ regulator-off-in-suspend;
|
|
+ };
|
|
+ standby-ddr-off {
|
|
+ regulator-off-in-suspend;
|
|
+ };
|
|
+};
|
|
+
|
|
+&vdd_ddr {
|
|
+ lp-stop {
|
|
+ regulator-suspend-microvolt = <1350000>;
|
|
+ regulator-on-in-suspend;
|
|
+ };
|
|
+ standby-ddr-sr {
|
|
+ regulator-suspend-microvolt = <1350000>;
|
|
+ regulator-on-in-suspend;
|
|
+ };
|
|
+ standby-ddr-off {
|
|
+ regulator-off-in-suspend;
|
|
+ };
|
|
+};
|
|
+
|
|
+&vdd {
|
|
+ lp-stop {
|
|
+ regulator-suspend-microvolt = <3300000>;
|
|
+ regulator-on-in-suspend;
|
|
+ };
|
|
+ standby-ddr-sr {
|
|
+ regulator-suspend-microvolt = <3300000>;
|
|
+ regulator-on-in-suspend;
|
|
+ };
|
|
+ standby-ddr-off {
|
|
+ regulator-suspend-microvolt = <3300000>;
|
|
+ regulator-on-in-suspend;
|
|
+ };
|
|
+};
|
|
+
|
|
+&v3v3 {
|
|
+ standby-ddr-sr {
|
|
+ regulator-off-in-suspend;
|
|
+ };
|
|
+ standby-ddr-off {
|
|
+ regulator-off-in-suspend;
|
|
+ };
|
|
+};
|
|
+
|
|
+&vdda {
|
|
+ standby-ddr-sr {
|
|
+ regulator-off-in-suspend;
|
|
+ };
|
|
+ standby-ddr-off {
|
|
+ regulator-off-in-suspend;
|
|
+ };
|
|
+};
|
|
+
|
|
+&v2v8 {
|
|
+ standby-ddr-sr {
|
|
+ regulator-off-in-suspend;
|
|
+ };
|
|
+ standby-ddr-off {
|
|
+ regulator-off-in-suspend;
|
|
+ };
|
|
+};
|
|
+
|
|
+&vtt_ddr {
|
|
+ lp-stop {
|
|
+ regulator-off-in-suspend;
|
|
+ };
|
|
+ standby-ddr-sr {
|
|
+ regulator-off-in-suspend;
|
|
+ };
|
|
+ standby-ddr-off {
|
|
+ regulator-off-in-suspend;
|
|
+ };
|
|
+};
|
|
+
|
|
+&vdd_usb {
|
|
+ standby-ddr-sr {
|
|
+ regulator-off-in-suspend;
|
|
+ };
|
|
+ standby-ddr-off {
|
|
+ regulator-off-in-suspend;
|
|
+ };
|
|
+};
|
|
+
|
|
+&vdd_sd {
|
|
+ standby-ddr-sr {
|
|
+ regulator-off-in-suspend;
|
|
+ };
|
|
+ standby-ddr-off {
|
|
+ regulator-off-in-suspend;
|
|
+ };
|
|
+};
|
|
+
|
|
+&v1v8 {
|
|
+ standby-ddr-sr {
|
|
+ regulator-off-in-suspend;
|
|
+ };
|
|
+ standby-ddr-off {
|
|
+ regulator-off-in-suspend;
|
|
+ };
|
|
+};
|
|
+
|
|
+&vref_ddr {
|
|
+ lp-stop {
|
|
+ regulator-on-in-suspend;
|
|
+ };
|
|
+ standby-ddr-sr {
|
|
+ regulator-on-in-suspend;
|
|
+ };
|
|
+ standby-ddr-off {
|
|
+ regulator-off-in-suspend;
|
|
+ };
|
|
+};
|
|
diff --git a/fdts/stm32mp157c-ev1.dts b/fdts/stm32mp157c-ev1.dts
|
|
index 98a9d35..cfde8ed 100644
|
|
--- a/fdts/stm32mp157c-ev1.dts
|
|
+++ b/fdts/stm32mp157c-ev1.dts
|
|
@@ -3,23 +3,65 @@
|
|
* Copyright (C) STMicroelectronics 2017 - All Rights Reserved
|
|
* Author: Ludovic Barre <ludovic.barre@st.com> for STMicroelectronics.
|
|
*/
|
|
-
|
|
/dts-v1/;
|
|
+
|
|
#include "stm32mp157c-ed1.dts"
|
|
|
|
/ {
|
|
- model = "STMicroelectronics STM32MP157C-EV1 pmic eval daughter on eval mother";
|
|
+ model = "STMicroelectronics STM32MP157C eval daughter on eval mother";
|
|
compatible = "st,stm32mp157c-ev1", "st,stm32mp157c-ed1", "st,stm32mp157";
|
|
|
|
chosen {
|
|
- bootargs = "earlyprintk console=ttyS3,115200 root=/dev/ram";
|
|
- stdout-path = "serial3:115200n8";
|
|
+ stdout-path = "serial0:115200n8";
|
|
+ };
|
|
+
|
|
+ aliases {
|
|
+ serial1 = &usart3;
|
|
+ };
|
|
+};
|
|
+
|
|
+&fmc {
|
|
+ status = "okay";
|
|
+ #address-cells = <1>;
|
|
+ #size-cells = <0>;
|
|
+
|
|
+ nand: nand@0 {
|
|
+ reg = <0>;
|
|
+ nand-on-flash-bbt;
|
|
+ #address-cells = <1>;
|
|
+ #size-cells = <1>;
|
|
+ };
|
|
+};
|
|
+
|
|
+&qspi {
|
|
+ pinctrl-names = "default";
|
|
+ pinctrl-0 = <&qspi_clk_pins_a &qspi_bk1_pins_a &qspi_bk2_pins_a>;
|
|
+ reg = <0x58003000 0x1000>, <0x70000000 0x4000000>;
|
|
+ #address-cells = <1>;
|
|
+ #size-cells = <0>;
|
|
+ status = "okay";
|
|
+
|
|
+ flash0: mx66l51235l@0 {
|
|
+ compatible = "jedec,spi-nor";
|
|
+ reg = <0>;
|
|
+ spi-rx-bus-width = <4>;
|
|
+ spi-max-frequency = <108000000>;
|
|
+ #address-cells = <1>;
|
|
+ #size-cells = <1>;
|
|
+ };
|
|
+
|
|
+ flash1: mx66l51235l@1 {
|
|
+ compatible = "jedec,spi-nor";
|
|
+ reg = <1>;
|
|
+ spi-rx-bus-width = <4>;
|
|
+ spi-max-frequency = <108000000>;
|
|
+ #address-cells = <1>;
|
|
+ #size-cells = <1>;
|
|
};
|
|
};
|
|
|
|
&usart3 {
|
|
pinctrl-names = "default";
|
|
pinctrl-0 = <&usart3_pins_a>;
|
|
- resets = <&rcc USART3_R>;
|
|
status = "disabled";
|
|
};
|
|
diff --git a/fdts/stm32mp157c-security.dtsi b/fdts/stm32mp157c-security.dtsi
|
|
new file mode 100644
|
|
index 0000000..8d45a33
|
|
--- /dev/null
|
|
+++ b/fdts/stm32mp157c-security.dtsi
|
|
@@ -0,0 +1,71 @@
|
|
+/*
|
|
+ * Copyright : STMicroelectronics 2017
|
|
+ *
|
|
+ * SPDX-License-Identifier: GPL-2.0+ BSD-3-Clause
|
|
+ */
|
|
+
|
|
+#include <dt-bindings/soc/st,stm32-etzpc.h>
|
|
+
|
|
+/ {
|
|
+ soc {
|
|
+ iwdg1: iwdg@5C003000 {
|
|
+ compatible = "st,stm32mp1-iwdg";
|
|
+ reg = <0x5C003000 0x400>;
|
|
+ clocks = <&rcc IWDG1>, <&rcc CK_LSI>;
|
|
+ clock-names = "pclk", "lsi";
|
|
+ interrupts = <GIC_SPI 150 IRQ_TYPE_LEVEL_HIGH>;
|
|
+ status = "disabled";
|
|
+ secure-status = "disabled";
|
|
+ };
|
|
+
|
|
+ etzpc: etzpc@5C007000 {
|
|
+ compatible = "st,stm32-etzpc";
|
|
+ reg = <0x5C007000 0x400>;
|
|
+ clocks = <&rcc TZPC>;
|
|
+ status = "disabled";
|
|
+ secure-status = "okay";
|
|
+ };
|
|
+
|
|
+ stgen: stgen@5C008000 {
|
|
+ compatible = "st,stm32-stgen";
|
|
+ reg = <0x5C008000 0x1000>;
|
|
+ };
|
|
+ };
|
|
+};
|
|
+
|
|
+&bsec {
|
|
+ mac_addr: mac_addr@e4 {
|
|
+ reg = <0xe4 0x6>;
|
|
+ };
|
|
+ /* Spare field to align on 32-bit OTP granularity */
|
|
+ spare_ns_ea: spare_ns_ea@ea {
|
|
+ reg = <0xea 0x2>;
|
|
+ };
|
|
+ board_id: board_id@ec {
|
|
+ reg = <0xec 0x4>;
|
|
+ };
|
|
+};
|
|
+
|
|
+&iwdg2 {
|
|
+ secure-interrupts = <GIC_SPI 151 IRQ_TYPE_LEVEL_HIGH>;
|
|
+};
|
|
+
|
|
+&rcc {
|
|
+ secure-interrupts = <GIC_SPI 145 IRQ_TYPE_LEVEL_HIGH>;
|
|
+ interrupt-names = "wakeup";
|
|
+};
|
|
+
|
|
+&sdmmc1 {
|
|
+ compatible = "st,stm32-sdmmc2";
|
|
+};
|
|
+
|
|
+&sdmmc2 {
|
|
+ compatible = "st,stm32-sdmmc2";
|
|
+};
|
|
+
|
|
+&tamp {
|
|
+ compatible = "st,stm32-tamp";
|
|
+ clocks = <&rcc RTCAPB>;
|
|
+ interrupts = <GIC_SPI 197 IRQ_TYPE_LEVEL_HIGH>;
|
|
+ secure-status= "disabled";
|
|
+};
|
|
diff --git a/fdts/stm32mp157c.dtsi b/fdts/stm32mp157c.dtsi
|
|
index 8b13c0e..06c2cf1 100644
|
|
--- a/fdts/stm32mp157c.dtsi
|
|
+++ b/fdts/stm32mp157c.dtsi
|
|
@@ -1,9 +1,9 @@
|
|
// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
|
|
/*
|
|
- * Copyright (C) STMicroelectronics 2017 - All Rights Reserved
|
|
+ * Copyright (C) STMicroelectronics 2017-2019 - All Rights Reserved
|
|
* Author: Ludovic Barre <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>
|
|
|
|
@@ -11,15 +11,12 @@
|
|
#address-cells = <1>;
|
|
#size-cells = <1>;
|
|
|
|
- aliases {
|
|
- serial0 = &usart1;
|
|
- serial1 = &usart2;
|
|
- serial2 = &usart3;
|
|
- serial3 = &uart4;
|
|
- serial4 = &uart5;
|
|
- serial5 = &usart6;
|
|
- serial6 = &uart7;
|
|
- serial7 = &uart8;
|
|
+ intc: interrupt-controller@a0021000 {
|
|
+ compatible = "arm,cortex-a7-gic";
|
|
+ #interrupt-cells = <3>;
|
|
+ interrupt-controller;
|
|
+ reg = <0xa0021000 0x1000>,
|
|
+ <0xa0022000 0x2000>;
|
|
};
|
|
|
|
clocks {
|
|
@@ -56,7 +53,7 @@
|
|
clk_i2s_ckin: i2s_ckin {
|
|
#clock-cells = <0>;
|
|
compatible = "fixed-clock";
|
|
- clock-frequency = <64000000>;
|
|
+ clock-frequency = <0>;
|
|
};
|
|
|
|
clk_dsi_phy: ck_dsi_phy {
|
|
@@ -64,31 +61,38 @@
|
|
compatible = "fixed-clock";
|
|
clock-frequency = <0>;
|
|
};
|
|
-
|
|
- clk_usbo_48m: ck_usbo_48m {
|
|
- #clock-cells = <0>;
|
|
- compatible = "fixed-clock";
|
|
- clock-frequency = <48000000>;
|
|
- };
|
|
};
|
|
|
|
soc {
|
|
compatible = "simple-bus";
|
|
#address-cells = <1>;
|
|
#size-cells = <1>;
|
|
+ interrupt-parent = <&intc>;
|
|
ranges;
|
|
|
|
+ timers12: timer@40006000 {
|
|
+ #address-cells = <1>;
|
|
+ #size-cells = <0>;
|
|
+ compatible = "st,stm32-timers";
|
|
+ reg = <0x40006000 0x400>;
|
|
+ clocks = <&rcc TIM12_K>;
|
|
+ clock-names = "int";
|
|
+ status = "disabled";
|
|
+ };
|
|
+
|
|
usart2: serial@4000e000 {
|
|
- compatible = "st,stm32h7-usart";
|
|
+ compatible = "st,stm32h7-uart";
|
|
reg = <0x4000e000 0x400>;
|
|
clocks = <&rcc USART2_K>;
|
|
+ resets = <&rcc USART2_R>;
|
|
status = "disabled";
|
|
};
|
|
|
|
usart3: serial@4000f000 {
|
|
- compatible = "st,stm32h7-usart";
|
|
+ compatible = "st,stm32h7-uart";
|
|
reg = <0x4000f000 0x400>;
|
|
clocks = <&rcc USART3_K>;
|
|
+ resets = <&rcc USART3_R>;
|
|
status = "disabled";
|
|
};
|
|
|
|
@@ -96,6 +100,7 @@
|
|
compatible = "st,stm32h7-uart";
|
|
reg = <0x40010000 0x400>;
|
|
clocks = <&rcc UART4_K>;
|
|
+ resets = <&rcc UART4_R>;
|
|
status = "disabled";
|
|
};
|
|
|
|
@@ -103,6 +108,7 @@
|
|
compatible = "st,stm32h7-uart";
|
|
reg = <0x40011000 0x400>;
|
|
clocks = <&rcc UART5_K>;
|
|
+ resets = <&rcc UART5_R>;
|
|
status = "disabled";
|
|
};
|
|
|
|
@@ -111,6 +117,7 @@
|
|
compatible = "st,stm32h7-uart";
|
|
reg = <0x40018000 0x400>;
|
|
clocks = <&rcc UART7_K>;
|
|
+ resets = <&rcc UART7_R>;
|
|
status = "disabled";
|
|
};
|
|
|
|
@@ -118,21 +125,34 @@
|
|
compatible = "st,stm32h7-uart";
|
|
reg = <0x40019000 0x400>;
|
|
clocks = <&rcc UART8_K>;
|
|
+ resets = <&rcc UART8_R>;
|
|
status = "disabled";
|
|
};
|
|
|
|
usart6: serial@44003000 {
|
|
- compatible = "st,stm32h7-usart";
|
|
+ compatible = "st,stm32h7-uart";
|
|
reg = <0x44003000 0x400>;
|
|
clocks = <&rcc USART6_K>;
|
|
+ resets = <&rcc USART6_R>;
|
|
+ status = "disabled";
|
|
+ };
|
|
+
|
|
+ timers15: timer@44006000 {
|
|
+ #address-cells = <1>;
|
|
+ #size-cells = <0>;
|
|
+ compatible = "st,stm32-timers";
|
|
+ reg = <0x44006000 0x400>;
|
|
+ clocks = <&rcc TIM15_K>;
|
|
+ clock-names = "int";
|
|
status = "disabled";
|
|
};
|
|
|
|
sdmmc3: sdmmc@48004000 {
|
|
- compatible = "st,stm32-sdmmc2";
|
|
+ compatible = "arm,pl18x", "arm,primecell";
|
|
+ arm,primecell-periphid = <0x00253180>;
|
|
reg = <0x48004000 0x400>, <0x48005000 0x400>;
|
|
- reg-names = "sdmmc", "delay";
|
|
clocks = <&rcc SDMMC3_K>;
|
|
+ clock-names = "apb_pclk";
|
|
resets = <&rcc SDMMC3_R>;
|
|
cap-sd-highspeed;
|
|
cap-mmc-highspeed;
|
|
@@ -140,18 +160,69 @@
|
|
status = "disabled";
|
|
};
|
|
|
|
+ usbotg_hs: usb-otg@49000000 {
|
|
+ compatible = "st,stm32mp1-hsotg", "snps,dwc2";
|
|
+ reg = <0x49000000 0x10000>;
|
|
+ clocks = <&rcc USBO_K>;
|
|
+ clock-names = "otg";
|
|
+ resets = <&rcc USBO_R>;
|
|
+ reset-names = "dwc2";
|
|
+ status = "disabled";
|
|
+ };
|
|
+
|
|
rcc: rcc@50000000 {
|
|
- compatible = "syscon", "st,stm32mp1-rcc";
|
|
+ compatible = "st,stm32mp1-rcc", "syscon";
|
|
+ reg = <0x50000000 0x1000>;
|
|
#clock-cells = <1>;
|
|
#reset-cells = <1>;
|
|
- reg = <0x50000000 0x1000>;
|
|
+ interrupts = <GIC_SPI 5 IRQ_TYPE_LEVEL_HIGH>;
|
|
+ };
|
|
+
|
|
+ pwr: pwr@50001000 {
|
|
+ compatible = "st,stm32mp1-pwr", "syscon", "simple-mfd";
|
|
+ reg = <0x50001000 0x400>;
|
|
};
|
|
|
|
- rcc_reboot: rcc-reboot@50000000 {
|
|
- compatible = "syscon-reboot";
|
|
- regmap = <&rcc>;
|
|
- offset = <0x404>;
|
|
- mask = <0x1>;
|
|
+ exti: interrupt-controller@5000d000 {
|
|
+ compatible = "st,stm32mp1-exti", "syscon";
|
|
+ interrupt-controller;
|
|
+ #interrupt-cells = <2>;
|
|
+ reg = <0x5000d000 0x400>;
|
|
+
|
|
+ /* exti_pwr is an extra interrupt controller used for
|
|
+ * EXTI 55 to 60. It's mapped on pwr interrupt
|
|
+ * controller.
|
|
+ */
|
|
+ exti_pwr: exti-pwr {
|
|
+ interrupt-controller;
|
|
+ #interrupt-cells = <2>;
|
|
+ interrupt-parent = <&pwr>;
|
|
+ st,irq-number = <6>;
|
|
+ };
|
|
+ };
|
|
+
|
|
+ syscfg: syscon@50020000 {
|
|
+ compatible = "st,stm32mp157-syscfg", "syscon";
|
|
+ reg = <0x50020000 0x400>;
|
|
+ clocks = <&rcc SYSCFG>;
|
|
+ };
|
|
+
|
|
+ cryp1: cryp@54001000 {
|
|
+ compatible = "st,stm32mp1-cryp";
|
|
+ reg = <0x54001000 0x400>;
|
|
+ interrupts = <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 {
|
|
@@ -162,13 +233,15 @@
|
|
status = "disabled";
|
|
};
|
|
|
|
- fmc_nand: fmc_nand@58002000 {
|
|
- compatible = "st,stm32mp1-fmc";
|
|
+ fmc: nand-controller@58002000 {
|
|
+ compatible = "st,stm32mp15-fmc2";
|
|
reg = <0x58002000 0x1000>,
|
|
- <0x80000000 0x40000>,
|
|
- <0x81000000 0x40000>,
|
|
- <0x88000000 0x40000>,
|
|
- <0x89000000 0x40000>;
|
|
+ <0x80000000 0x1000>,
|
|
+ <0x88010000 0x1000>,
|
|
+ <0x88020000 0x1000>,
|
|
+ <0x81000000 0x1000>,
|
|
+ <0x89010000 0x1000>,
|
|
+ <0x89020000 0x1000>;
|
|
clocks = <&rcc FMC_K>;
|
|
resets = <&rcc FMC_R>;
|
|
status = "disabled";
|
|
@@ -177,15 +250,18 @@
|
|
qspi: qspi@58003000 {
|
|
compatible = "st,stm32f469-qspi";
|
|
reg = <0x58003000 0x1000>, <0x70000000 0x10000000>;
|
|
+ reg-names = "qspi", "qspi_mm";
|
|
clocks = <&rcc QSPI_K>;
|
|
+ resets = <&rcc QSPI_R>;
|
|
status = "disabled";
|
|
};
|
|
|
|
sdmmc1: sdmmc@58005000 {
|
|
- compatible = "st,stm32-sdmmc2";
|
|
+ compatible = "arm,pl18x", "arm,primecell";
|
|
+ arm,primecell-periphid = <0x00253180>;
|
|
reg = <0x58005000 0x1000>, <0x58006000 0x1000>;
|
|
- reg-names = "sdmmc", "delay";
|
|
clocks = <&rcc SDMMC1_K>;
|
|
+ clock-names = "apb_pclk";
|
|
resets = <&rcc SDMMC1_R>;
|
|
cap-sd-highspeed;
|
|
cap-mmc-highspeed;
|
|
@@ -194,10 +270,11 @@
|
|
};
|
|
|
|
sdmmc2: sdmmc@58007000 {
|
|
- compatible = "st,stm32-sdmmc2";
|
|
+ compatible = "arm,pl18x", "arm,primecell";
|
|
+ arm,primecell-periphid = <0x00253180>;
|
|
reg = <0x58007000 0x1000>, <0x58008000 0x1000>;
|
|
- reg-names = "sdmmc", "delay";
|
|
clocks = <&rcc SDMMC2_K>;
|
|
+ clock-names = "apb_pclk";
|
|
resets = <&rcc SDMMC2_R>;
|
|
cap-sd-highspeed;
|
|
cap-mmc-highspeed;
|
|
@@ -205,7 +282,7 @@
|
|
status = "disabled";
|
|
};
|
|
|
|
- iwdg2: iwdg@5a002000 {
|
|
+ iwdg2: watchdog@5a002000 {
|
|
compatible = "st,stm32mp1-iwdg";
|
|
reg = <0x5a002000 0x400>;
|
|
clocks = <&rcc IWDG2>, <&rcc CK_LSI>;
|
|
@@ -214,15 +291,34 @@
|
|
};
|
|
|
|
usart1: serial@5c000000 {
|
|
- compatible = "st,stm32h7-usart";
|
|
+ compatible = "st,stm32h7-uart";
|
|
reg = <0x5c000000 0x400>;
|
|
+ interrupt-names = "event", "wakeup";
|
|
+ interrupts-extended = <&intc GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH>,
|
|
+ <&exti 26 1>;
|
|
clocks = <&rcc USART1_K>;
|
|
+ resets = <&rcc USART1_R>;
|
|
+ status = "disabled";
|
|
+ };
|
|
+
|
|
+ spi6: spi@5c001000 {
|
|
+ #address-cells = <1>;
|
|
+ #size-cells = <0>;
|
|
+ compatible = "st,stm32h7-spi";
|
|
+ reg = <0x5c001000 0x400>;
|
|
+ interrupts = <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>;
|
|
@@ -235,6 +331,41 @@
|
|
reg = <0x5c004000 0x400>;
|
|
clocks = <&rcc RTCAPB>, <&rcc RTC>;
|
|
clock-names = "pclk", "rtc_ck";
|
|
+ interrupts-extended = <&intc GIC_SPI 3 IRQ_TYPE_LEVEL_HIGH>,
|
|
+ <&exti 19 1>;
|
|
+ status = "disabled";
|
|
+ };
|
|
+
|
|
+ bsec: nvmem@5c005000 {
|
|
+ compatible = "st,stm32mp15-bsec";
|
|
+ reg = <0x5c005000 0x400>;
|
|
+ #address-cells = <1>;
|
|
+ #size-cells = <1>;
|
|
+ ts_cal1: calib@5c {
|
|
+ reg = <0x5c 0x2>;
|
|
+ };
|
|
+ ts_cal2: calib@5e {
|
|
+ reg = <0x5e 0x2>;
|
|
+ };
|
|
+ };
|
|
+
|
|
+ i2c6: i2c@5c009000 {
|
|
+ compatible = "st,stm32f7-i2c";
|
|
+ reg = <0x5c009000 0x400>;
|
|
+ interrupt-names = "event", "error", "wakeup";
|
|
+ interrupts-extended = <&intc GIC_SPI 135 IRQ_TYPE_LEVEL_HIGH>,
|
|
+ <&intc GIC_SPI 136 IRQ_TYPE_LEVEL_HIGH>,
|
|
+ <&exti 54 1>;
|
|
+ clocks = <&rcc I2C6_K>;
|
|
+ resets = <&rcc I2C6_R>;
|
|
+ #address-cells = <1>;
|
|
+ #size-cells = <0>;
|
|
+ status = "disabled";
|
|
+ };
|
|
+
|
|
+ tamp: tamp@5c00a000 {
|
|
+ compatible = "simple-bus", "syscon", "simple-mfd";
|
|
+ reg = <0x5c00a000 0x400>;
|
|
};
|
|
};
|
|
};
|
|
diff --git a/fdts/stm32mp157caa-pinctrl.dtsi b/fdts/stm32mp157caa-pinctrl.dtsi
|
|
index 774561a..9b9cd08 100644
|
|
--- a/fdts/stm32mp157caa-pinctrl.dtsi
|
|
+++ b/fdts/stm32mp157caa-pinctrl.dtsi
|
|
@@ -7,8 +7,8 @@
|
|
#include "stm32mp157-pinctrl.dtsi"
|
|
/ {
|
|
soc {
|
|
- pinctrl: pin-controller {
|
|
- compatible = "st,stm32mp157caa-pinctrl";
|
|
+ pinctrl: pin-controller@50002000 {
|
|
+ st,package = <STM32MP157CAA>;
|
|
|
|
gpioa: gpio@50002000 {
|
|
status = "okay";
|
|
@@ -77,8 +77,8 @@
|
|
};
|
|
};
|
|
|
|
- pinctrl_z: pin-controller-z {
|
|
- compatible = "st,stm32mp157caa-z-pinctrl";
|
|
+ pinctrl_z: pin-controller-z@54004000 {
|
|
+ st,package = <STM32MP157CAA>;
|
|
|
|
gpioz: gpio@54004000 {
|
|
status = "okay";
|
|
diff --git a/fdts/stm32mp157cab-pinctrl.dtsi b/fdts/stm32mp157cab-pinctrl.dtsi
|
|
new file mode 100644
|
|
index 0000000..c570cf9
|
|
--- /dev/null
|
|
+++ b/fdts/stm32mp157cab-pinctrl.dtsi
|
|
@@ -0,0 +1,62 @@
|
|
+// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
|
|
+/*
|
|
+ * Copyright (C) STMicroelectronics 2018 - All Rights Reserved
|
|
+ * Author: Alexandre Torgue <alexandre.torgue@st.com>
|
|
+ */
|
|
+
|
|
+#include "stm32mp157-pinctrl.dtsi"
|
|
+/ {
|
|
+ soc {
|
|
+ pinctrl: pin-controller@50002000 {
|
|
+ st,package = <STM32MP157CAB>;
|
|
+
|
|
+ gpioa: gpio@50002000 {
|
|
+ status = "okay";
|
|
+ ngpios = <16>;
|
|
+ gpio-ranges = <&pinctrl 0 0 16>;
|
|
+ };
|
|
+
|
|
+ gpiob: gpio@50003000 {
|
|
+ status = "okay";
|
|
+ ngpios = <16>;
|
|
+ gpio-ranges = <&pinctrl 0 16 16>;
|
|
+ };
|
|
+
|
|
+ gpioc: gpio@50004000 {
|
|
+ status = "okay";
|
|
+ ngpios = <16>;
|
|
+ gpio-ranges = <&pinctrl 0 32 16>;
|
|
+ };
|
|
+
|
|
+ gpiod: gpio@50005000 {
|
|
+ status = "okay";
|
|
+ ngpios = <16>;
|
|
+ gpio-ranges = <&pinctrl 0 48 16>;
|
|
+ };
|
|
+
|
|
+ gpioe: gpio@50006000 {
|
|
+ status = "okay";
|
|
+ ngpios = <16>;
|
|
+ gpio-ranges = <&pinctrl 0 64 16>;
|
|
+ };
|
|
+
|
|
+ gpiof: gpio@50007000 {
|
|
+ status = "okay";
|
|
+ ngpios = <6>;
|
|
+ gpio-ranges = <&pinctrl 6 86 6>;
|
|
+ };
|
|
+
|
|
+ gpiog: gpio@50008000 {
|
|
+ status = "okay";
|
|
+ ngpios = <10>;
|
|
+ gpio-ranges = <&pinctrl 6 102 10>;
|
|
+ };
|
|
+
|
|
+ gpioh: gpio@50009000 {
|
|
+ status = "okay";
|
|
+ ngpios = <2>;
|
|
+ gpio-ranges = <&pinctrl 0 112 2>;
|
|
+ };
|
|
+ };
|
|
+ };
|
|
+};
|
|
diff --git a/fdts/stm32mp157cac-pinctrl.dtsi b/fdts/stm32mp157cac-pinctrl.dtsi
|
|
new file mode 100644
|
|
index 0000000..777f991
|
|
--- /dev/null
|
|
+++ b/fdts/stm32mp157cac-pinctrl.dtsi
|
|
@@ -0,0 +1,78 @@
|
|
+// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
|
|
+/*
|
|
+ * Copyright (C) STMicroelectronics 2018 - All Rights Reserved
|
|
+ * Author: Alexandre Torgue <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/stm32mp157cad-pinctrl.dtsi b/fdts/stm32mp157cad-pinctrl.dtsi
|
|
new file mode 100644
|
|
index 0000000..c4c303a
|
|
--- /dev/null
|
|
+++ b/fdts/stm32mp157cad-pinctrl.dtsi
|
|
@@ -0,0 +1,62 @@
|
|
+// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
|
|
+/*
|
|
+ * Copyright (C) STMicroelectronics 2018 - All Rights Reserved
|
|
+ * Author: Alexandre Torgue <alexandre.torgue@st.com>
|
|
+ */
|
|
+
|
|
+#include "stm32mp157-pinctrl.dtsi"
|
|
+/ {
|
|
+ soc {
|
|
+ pinctrl: pin-controller@50002000 {
|
|
+ st,package = <STM32MP157CAD>;
|
|
+
|
|
+ gpioa: gpio@50002000 {
|
|
+ status = "okay";
|
|
+ ngpios = <16>;
|
|
+ gpio-ranges = <&pinctrl 0 0 16>;
|
|
+ };
|
|
+
|
|
+ gpiob: gpio@50003000 {
|
|
+ status = "okay";
|
|
+ ngpios = <16>;
|
|
+ gpio-ranges = <&pinctrl 0 16 16>;
|
|
+ };
|
|
+
|
|
+ gpioc: gpio@50004000 {
|
|
+ status = "okay";
|
|
+ ngpios = <16>;
|
|
+ gpio-ranges = <&pinctrl 0 32 16>;
|
|
+ };
|
|
+
|
|
+ gpiod: gpio@50005000 {
|
|
+ status = "okay";
|
|
+ ngpios = <16>;
|
|
+ gpio-ranges = <&pinctrl 0 48 16>;
|
|
+ };
|
|
+
|
|
+ gpioe: gpio@50006000 {
|
|
+ status = "okay";
|
|
+ ngpios = <16>;
|
|
+ gpio-ranges = <&pinctrl 0 64 16>;
|
|
+ };
|
|
+
|
|
+ gpiof: gpio@50007000 {
|
|
+ status = "okay";
|
|
+ ngpios = <6>;
|
|
+ gpio-ranges = <&pinctrl 6 86 6>;
|
|
+ };
|
|
+
|
|
+ gpiog: gpio@50008000 {
|
|
+ status = "okay";
|
|
+ ngpios = <10>;
|
|
+ gpio-ranges = <&pinctrl 6 102 10>;
|
|
+ };
|
|
+
|
|
+ gpioh: gpio@50009000 {
|
|
+ status = "okay";
|
|
+ ngpios = <2>;
|
|
+ gpio-ranges = <&pinctrl 0 112 2>;
|
|
+ };
|
|
+ };
|
|
+ };
|
|
+};
|
|
diff --git a/include/common/aarch32/console_macros.S b/include/common/aarch32/console_macros.S
|
|
new file mode 100644
|
|
index 0000000..7c30688
|
|
--- /dev/null
|
|
+++ b/include/common/aarch32/console_macros.S
|
|
@@ -0,0 +1,84 @@
|
|
+/*
|
|
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
|
|
+ *
|
|
+ * SPDX-License-Identifier: BSD-3-Clause
|
|
+ */
|
|
+#ifndef __CONSOLE_MACROS_S__
|
|
+#define __CONSOLE_MACROS_S__
|
|
+
|
|
+#include <console.h>
|
|
+
|
|
+/*
|
|
+ * This macro encapsulates the common setup that has to be done at the end of
|
|
+ * a console driver's register function. It will register all of the driver's
|
|
+ * callbacks in the console_t structure and initialize the flags field (by
|
|
+ * default consoles are enabled for the "boot" and "crash" states, this can be
|
|
+ * changed after registration with the console_set_scope() function). It ends
|
|
+ * with a tail call that will include return to the caller.
|
|
+ * REQUIRES console_t pointer in x0 and a valid return address in x30.
|
|
+ */
|
|
+/*
|
|
+ * The USE_FINISH_CONSOLE_REG_2 guard is introduced to allow selection between
|
|
+ * the 2 variants of the finish_console_register macro and will be removed
|
|
+ * once the deprecated variant is removed.
|
|
+ */
|
|
+#ifndef USE_FINISH_CONSOLE_REG_2
|
|
+#if !ERROR_DEPRECATED
|
|
+ /* This version of the macro is deprecated. Use the new version */
|
|
+ .macro finish_console_register _driver
|
|
+ /*
|
|
+ * Add these weak definitions so we will automatically write a 0 if the
|
|
+ * function doesn't exist. I'd rather use .ifdef but that only works if
|
|
+ * the function was defined (not just declared .global) above this point
|
|
+ * in the file, which we can't guarantee.
|
|
+ */
|
|
+ .weak console_\_driver\()_putc
|
|
+ .weak console_\_driver\()_getc
|
|
+ .weak console_\_driver\()_flush
|
|
+
|
|
+ /* Don't use adrp on weak funcs! See GNU ld bugzilla issue 22589. */
|
|
+ ldr r1, =console_\_driver\()_putc
|
|
+ str r1, [r0, #CONSOLE_T_PUTC]
|
|
+ ldr r1, =console_\_driver\()_getc
|
|
+ str r1, [r0, #CONSOLE_T_GETC]
|
|
+ ldr r1, =console_\_driver\()_flush
|
|
+ str r1, [r0, #CONSOLE_T_FLUSH]
|
|
+ mov r1, #(CONSOLE_FLAG_BOOT | CONSOLE_FLAG_CRASH)
|
|
+ str r1, [r0, #CONSOLE_T_FLAGS]
|
|
+ b console_register
|
|
+ .endm
|
|
+#endif /* ERROR_DEPRECATED */
|
|
+#else /* USE_FINISH_CONSOLE_REG_2 */
|
|
+ /* The new version of the macro not using weak references */
|
|
+ .macro finish_console_register _driver, putc=0, getc=0, flush=0
|
|
+ /*
|
|
+ * If any of the callback is not specified or set as 0, then the
|
|
+ * corresponding callback entry in console_t is set to 0.
|
|
+ */
|
|
+ .ifne \putc
|
|
+ ldr r1, =console_\_driver\()_putc
|
|
+ .else
|
|
+ mov r1, #0
|
|
+ .endif
|
|
+ str r1, [r0, #CONSOLE_T_PUTC]
|
|
+
|
|
+ .ifne \getc
|
|
+ ldr r1, =console_\_driver\()_getc
|
|
+ .else
|
|
+ mov r1, #0
|
|
+ .endif
|
|
+ str r1, [r0, #CONSOLE_T_GETC]
|
|
+
|
|
+ .ifne \flush
|
|
+ ldr r1, =console_\_driver\()_flush
|
|
+ .else
|
|
+ mov r1, #0
|
|
+ .endif
|
|
+ str r1, [r0, #CONSOLE_T_FLUSH]
|
|
+
|
|
+ mov r1, #(CONSOLE_FLAG_BOOT | CONSOLE_FLAG_CRASH)
|
|
+ str r1, [r0, #CONSOLE_T_FLAGS]
|
|
+ b console_register
|
|
+ .endm
|
|
+#endif /* USE_FINISH_CONSOLE_REG_2 */
|
|
+#endif /* __CONSOLE_MACROS_S__ */
|
|
diff --git a/include/common/aarch64/console_macros.S b/include/common/aarch64/console_macros.S
|
|
index 0ebea2c..b285ecc 100644
|
|
--- a/include/common/aarch64/console_macros.S
|
|
+++ b/include/common/aarch64/console_macros.S
|
|
@@ -1,5 +1,5 @@
|
|
/*
|
|
- * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
|
|
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
|
|
*
|
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
*/
|
|
@@ -17,6 +17,14 @@
|
|
* with a tail call that will include return to the caller.
|
|
* REQUIRES console_t pointer in x0 and a valid return address in x30.
|
|
*/
|
|
+/*
|
|
+ * The USE_FINISH_CONSOLE_REG_2 guard is introduced to allow selection between
|
|
+ * the 2 variants of the finish_console_register macro and will be removed
|
|
+ * once the deprecated variant is removed.
|
|
+ */
|
|
+#ifndef USE_FINISH_CONSOLE_REG_2
|
|
+#if !ERROR_DEPRECATED
|
|
+ /* This version of the macro is deprecated. Use the new version */
|
|
.macro finish_console_register _driver
|
|
/*
|
|
* Add these weak definitions so we will automatically write a 0 if the
|
|
@@ -39,5 +47,41 @@
|
|
str x1, [x0, #CONSOLE_T_FLAGS]
|
|
b console_register
|
|
.endm
|
|
+#endif /* ERROR_DEPRECATED */
|
|
+#else /* USE_FINISH_CONSOLE_REG_2 */
|
|
+ /* The new version of the macro not using weak references */
|
|
+ .macro finish_console_register _driver, putc=0, getc=0, flush=0
|
|
+ /*
|
|
+ * If any of the callback is not specified or set as 0, then the
|
|
+ * corresponding callback entry in console_t is set to 0.
|
|
+ */
|
|
+ .ifne \putc
|
|
+ adrp x1, console_\_driver\()_putc
|
|
+ add x1, x1, :lo12:console_\_driver\()_putc
|
|
+ str x1, [x0, #CONSOLE_T_PUTC]
|
|
+ .else
|
|
+ str xzr, [x0, #CONSOLE_T_PUTC]
|
|
+ .endif
|
|
+
|
|
+ .ifne \getc
|
|
+ adrp x1, console_\_driver\()_getc
|
|
+ add x1, x1, :lo12:console_\_driver\()_getc
|
|
+ str x1, [x0, #CONSOLE_T_GETC]
|
|
+ .else
|
|
+ str xzr, [x0, #CONSOLE_T_GETC]
|
|
+ .endif
|
|
|
|
+ .ifne \flush
|
|
+ adrp x1, console_\_driver\()_flush
|
|
+ add x1, x1, :lo12:console_\_driver\()_flush
|
|
+ str x1, [x0, #CONSOLE_T_FLUSH]
|
|
+ .else
|
|
+ str xzr, [x0, #CONSOLE_T_FLUSH]
|
|
+ .endif
|
|
+
|
|
+ mov x1, #(CONSOLE_FLAG_BOOT | CONSOLE_FLAG_CRASH)
|
|
+ str x1, [x0, #CONSOLE_T_FLAGS]
|
|
+ b console_register
|
|
+ .endm
|
|
+#endif /* USE_FINISH_CONSOLE_REG_2 */
|
|
#endif /* __CONSOLE_MACROS_S__ */
|
|
diff --git a/include/common/tbbr/tbbr_img_def.h b/include/common/tbbr/tbbr_img_def.h
|
|
index a97914d..96bfb53 100644
|
|
--- a/include/common/tbbr/tbbr_img_def.h
|
|
+++ b/include/common/tbbr/tbbr_img_def.h
|
|
@@ -77,7 +77,13 @@
|
|
/* NT_FW_CONFIG */
|
|
#define NT_FW_CONFIG_ID U(27)
|
|
|
|
+/* GPT Partition */
|
|
+#define GPT_IMAGE_ID U(28)
|
|
+
|
|
+/* Binary with STM32 header */
|
|
+#define STM32_IMAGE_ID U(29)
|
|
+
|
|
/* Define size of the array */
|
|
-#define MAX_NUMBER_IDS U(28)
|
|
+#define MAX_NUMBER_IDS U(30)
|
|
|
|
#endif /* __TBBR_IMG_DEF_H__ */
|
|
diff --git a/include/drivers/arm/tzc400.h b/include/drivers/arm/tzc400.h
|
|
index 095099c..a0c7542 100644
|
|
--- a/include/drivers/arm/tzc400.h
|
|
+++ b/include/drivers/arm/tzc400.h
|
|
@@ -32,6 +32,7 @@
|
|
#define BUILD_CONFIG_NR_SHIFT 0
|
|
#define BUILD_CONFIG_NR_MASK 0x1f
|
|
|
|
+#define FILTER_OFFSET 0x10
|
|
/*
|
|
* Number of gate keepers is implementation defined. But we know the max for
|
|
* this device is 4. Get implementation details from BUILD_CONFIG.
|
|
@@ -112,6 +113,9 @@ void tzc400_configure_region(unsigned int filters,
|
|
void tzc400_set_action(tzc_action_t action);
|
|
void tzc400_enable_filters(void);
|
|
void tzc400_disable_filters(void);
|
|
+void tzc400_clear_all_interrupts(void);
|
|
+int tzc400_is_pending_interrupt(void);
|
|
+void tzc400_it_handler(void);
|
|
|
|
static inline void tzc_init(uintptr_t base)
|
|
{
|
|
diff --git a/include/drivers/io/io_driver.h b/include/drivers/io/io_driver.h
|
|
index 8306407..3d2c3ab 100644
|
|
--- a/include/drivers/io/io_driver.h
|
|
+++ b/include/drivers/io/io_driver.h
|
|
@@ -39,7 +39,7 @@ typedef struct io_dev_funcs {
|
|
io_type_t (*type)(void);
|
|
int (*open)(io_dev_info_t *dev_info, const uintptr_t spec,
|
|
io_entity_t *entity);
|
|
- int (*seek)(io_entity_t *entity, int mode, ssize_t offset);
|
|
+ int (*seek)(io_entity_t *entity, int mode, signed long long offset);
|
|
int (*size)(io_entity_t *entity, size_t *length);
|
|
int (*read)(io_entity_t *entity, uintptr_t buffer, size_t length,
|
|
size_t *length_read);
|
|
diff --git a/include/drivers/io/io_storage.h b/include/drivers/io/io_storage.h
|
|
index 485ed8c..2bf7721 100644
|
|
--- a/include/drivers/io/io_storage.h
|
|
+++ b/include/drivers/io/io_storage.h
|
|
@@ -22,6 +22,12 @@ typedef enum {
|
|
IO_TYPE_DUMMY,
|
|
IO_TYPE_FIRMWARE_IMAGE_PACKAGE,
|
|
IO_TYPE_BLOCK,
|
|
+ IO_TYPE_MMC,
|
|
+ IO_TYPE_STM32IMAGE,
|
|
+ IO_TYPE_UART,
|
|
+ IO_TYPE_QSPI,
|
|
+ IO_TYPE_NAND,
|
|
+ IO_TYPE_USB,
|
|
IO_TYPE_MAX
|
|
} io_type_t;
|
|
|
|
@@ -86,7 +92,7 @@ int io_dev_close(uintptr_t dev_handle);
|
|
/* Synchronous operations */
|
|
int io_open(uintptr_t dev_handle, const uintptr_t spec, uintptr_t *handle);
|
|
|
|
-int io_seek(uintptr_t handle, io_seek_mode_t mode, ssize_t offset);
|
|
+int io_seek(uintptr_t handle, io_seek_mode_t mode, signed long long offset);
|
|
|
|
int io_size(uintptr_t handle, size_t *length);
|
|
|
|
diff --git a/include/drivers/st/bsec.h b/include/drivers/st/bsec.h
|
|
new file mode 100644
|
|
index 0000000..b21bde8
|
|
--- /dev/null
|
|
+++ b/include/drivers/st/bsec.h
|
|
@@ -0,0 +1,205 @@
|
|
+/*
|
|
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
|
|
+ *
|
|
+ * SPDX-License-Identifier: BSD-3-Clause
|
|
+ */
|
|
+
|
|
+#ifndef __BSEC_H__
|
|
+#define __BSEC_H__
|
|
+
|
|
+#include <stdbool.h>
|
|
+#include <stdint.h>
|
|
+#include <utils_def.h>
|
|
+
|
|
+/*
|
|
+ * IP configuration
|
|
+ */
|
|
+#define BSEC_OTP_MASK GENMASK(4, 0)
|
|
+#define BSEC_OTP_BANK_SHIFT 5
|
|
+#define BSEC_TIMEOUT_VALUE 0xFFFF
|
|
+
|
|
+#define ADDR_LOWER_OTP_PERLOCK_SHIFT 0x03
|
|
+#define DATA_LOWER_OTP_PERLOCK_BIT 0x03U /* 2 significants bits are used */
|
|
+#define DATA_LOWER_OTP_PERLOCK_MASK GENMASK(2, 0)
|
|
+#define ADDR_UPPER_OTP_PERLOCK_SHIFT 0x04
|
|
+#define DATA_UPPER_OTP_PERLOCK_BIT 0x01U /* 1 significants bits are used */
|
|
+#define DATA_UPPER_OTP_PERLOCK_MASK GENMASK(3, 0)
|
|
+
|
|
+/*
|
|
+ * Return status
|
|
+ */
|
|
+#define BSEC_OK 0U
|
|
+#define BSEC_ERROR 0xFFFFFFFFU
|
|
+#define BSEC_DISTURBED 0xFFFFFFFEU
|
|
+#define BSEC_INVALID_PARAM 0xFFFFFFFCU
|
|
+#define BSEC_PROG_FAIL 0xFFFFFFFBU
|
|
+#define BSEC_LOCK_FAIL 0xFFFFFFFAU
|
|
+#define BSEC_WRITE_FAIL 0xFFFFFFF9U
|
|
+#define BSEC_SHADOW_FAIL 0xFFFFFFF8U
|
|
+#define BSEC_TIMEOUT 0xFFFFFFF7U
|
|
+
|
|
+/*
|
|
+ * BSEC REGISTER OFFSET (base relative)
|
|
+ */
|
|
+#define BSEC_OTP_CONF_OFF 0x000U
|
|
+#define BSEC_OTP_CTRL_OFF 0x004U
|
|
+#define BSEC_OTP_WRDATA_OFF 0x008U
|
|
+#define BSEC_OTP_STATUS_OFF 0x00CU
|
|
+#define BSEC_OTP_LOCK_OFF 0x010U
|
|
+#define BSEC_DEN_OFF 0x014U
|
|
+#define BSEC_DISTURBED_OFF 0x01CU
|
|
+#define BSEC_DISTURBED1_OFF 0x020U
|
|
+#define BSEC_DISTURBED2_OFF 0x024U
|
|
+#define BSEC_ERROR_OFF 0x034U
|
|
+#define BSEC_ERROR1_OFF 0x038U
|
|
+#define BSEC_ERROR2_OFF 0x03CU
|
|
+#define BSEC_WRLOCK_OFF 0x04CU /* Safmem permanent lock */
|
|
+#define BSEC_WRLOCK1_OFF 0x050U
|
|
+#define BSEC_WRLOCK2_OFF 0x054U
|
|
+#define BSEC_SPLOCK_OFF 0x064U /* Program safmem sticky lock */
|
|
+#define BSEC_SPLOCK1_OFF 0x068U
|
|
+#define BSEC_SPLOCK2_OFF 0x06CU
|
|
+#define BSEC_SWLOCK_OFF 0x07CU /* Write in OTP sticky lock */
|
|
+#define BSEC_SWLOCK1_OFF 0x080U
|
|
+#define BSEC_SWLOCK2_OFF 0x084U
|
|
+#define BSEC_SRLOCK_OFF 0x094U /* Shadowing sticky lock */
|
|
+#define BSEC_SRLOCK1_OFF 0x098U
|
|
+#define BSEC_SRLOCK2_OFF 0x09CU
|
|
+#define BSEC_JTAG_IN_OFF 0x0ACU
|
|
+#define BSEC_JTAG_OUT_OFF 0x0B0U
|
|
+#define BSEC_SCRATCH_OFF 0x0B4U
|
|
+#define BSEC_OTP_DATA_OFF 0x200U
|
|
+#define BSEC_IPHW_CFG_OFF 0xFF0U
|
|
+#define BSEC_IPVR_OFF 0xFF4U
|
|
+#define BSEC_IP_ID_OFF 0xFF8U
|
|
+#define BSEC_IP_MAGIC_ID_OFF 0xFFCU
|
|
+
|
|
+/*
|
|
+ * BSEC_CONFIGURATION Register
|
|
+ */
|
|
+#define BSEC_CONF_POWER_UP_MASK BIT(0)
|
|
+#define BSEC_CONF_POWER_UP_SHIFT 0
|
|
+#define BSEC_CONF_FRQ_MASK GENMASK(2, 1)
|
|
+#define BSEC_CONF_FRQ_SHIFT 1
|
|
+#define BSEC_CONF_PRG_WIDTH_MASK GENMASK(6, 3)
|
|
+#define BSEC_CONF_PRG_WIDTH_SHIFT 3
|
|
+#define BSEC_CONF_TREAD_MASK GENMASK(8, 7)
|
|
+#define BSEC_CONF_TREAD_SHIFT 7
|
|
+
|
|
+/*
|
|
+ * BSEC_CONTROL Register
|
|
+ */
|
|
+#define BSEC_READ 0x000U
|
|
+#define BSEC_WRITE 0x100U
|
|
+#define BSEC_LOCK 0x200U
|
|
+
|
|
+/*
|
|
+ * BSEC_OTP_LOCK register
|
|
+ */
|
|
+#define UPPER_OTP_LOCK_MASK BIT(0)
|
|
+#define UPPER_OTP_LOCK_SHIFT 0
|
|
+#define DENREG_LOCK_MASK BIT(2)
|
|
+#define DENREG_LOCK_SHIFT 2
|
|
+#define GPLOCK_LOCK_MASK BIT(4)
|
|
+#define GPLOCK_LOCK_SHIFT 4
|
|
+
|
|
+/*
|
|
+ * BSEC_OTP_STATUS Register
|
|
+ */
|
|
+#define BSEC_MODE_STATUS_MASK GENMASK(2, 0)
|
|
+#define BSEC_MODE_BUSY_MASK BIT(3)
|
|
+#define BSEC_MODE_PROGFAIL_MASK BIT(4)
|
|
+#define BSEC_MODE_PWR_MASK BIT(5)
|
|
+#define BSEC_MODE_BIST1_LOCK_MASK BIT(6)
|
|
+#define BSEC_MODE_BIST2_LOCK_MASK BIT(7)
|
|
+
|
|
+/* OTP MODE*/
|
|
+#define BSEC_MODE_OPEN1 0x00
|
|
+#define BSEC_MODE_SECURED 0x01
|
|
+#define BSEC_MODE_OPEN2 0x02
|
|
+#define BSEC_MODE_INVALID 0x04
|
|
+
|
|
+/* BSEC_DENABLE Register */
|
|
+#define BSEC_HDPEN BIT(4)
|
|
+#define BSEC_SPIDEN BIT(5)
|
|
+#define BSEC_SPINDEN BIT(6)
|
|
+#define BSEC_DBGSWGEN BIT(10)
|
|
+#define BSEC_DEN_ALL_MSK GENMASK(10, 0)
|
|
+
|
|
+/* BSEC_FENABLE Register */
|
|
+#define BSEC_FEN_ALL_MSK GENMASK(14, 0)
|
|
+
|
|
+/*
|
|
+ * OTP Lock services definition
|
|
+ * Value must corresponding to the bit number in the register
|
|
+ */
|
|
+#define BSEC_LOCK_UPPER_OTP 0x00
|
|
+#define BSEC_LOCK_DEBUG 0x02
|
|
+#define BSEC_LOCK_PROGRAM 0x03
|
|
+
|
|
+/* Values for struct bsec_config::freq */
|
|
+#define FREQ_10_20_MHZ 0x0
|
|
+#define FREQ_20_30_MHZ 0x1
|
|
+#define FREQ_30_45_MHZ 0x2
|
|
+#define FREQ_45_67_MHZ 0x3
|
|
+
|
|
+/*
|
|
+ * Device info structure, providing device-specific functions and a means of
|
|
+ * adding driver-specific state
|
|
+ */
|
|
+struct bsec_config {
|
|
+ uint8_t tread; /* SAFMEM Reading current level default 0 */
|
|
+ uint8_t pulse_width; /* SAFMEM Programming pulse width default 1 */
|
|
+ uint8_t freq; /* SAFMEM CLOCK see freq value define
|
|
+ * default FREQ_45_67_MHZ
|
|
+ */
|
|
+ uint8_t power; /* Power up SAFMEM. 1 power up, 0 power off */
|
|
+ uint8_t prog_lock; /* Programming Sticky lock
|
|
+ * 1 programming is locked until next reset
|
|
+ */
|
|
+ uint8_t den_lock; /* Debug enable is sticky lock
|
|
+ * 1 debug enable is locked until next reset
|
|
+ */
|
|
+ uint8_t upper_otp_lock; /* Shadowing of upper OTP is sticky lock
|
|
+ * 1 shadowing of upper OTP is locked
|
|
+ * until next reset
|
|
+ */
|
|
+};
|
|
+
|
|
+uint32_t bsec_probe(void);
|
|
+uint32_t bsec_get_base(void);
|
|
+
|
|
+uint32_t bsec_set_config(struct bsec_config *cfg);
|
|
+uint32_t bsec_get_config(struct bsec_config *cfg);
|
|
+
|
|
+uint32_t bsec_shadow_register(uint32_t otp);
|
|
+uint32_t bsec_read_otp(uint32_t *val, uint32_t otp);
|
|
+uint32_t bsec_write_otp(uint32_t val, uint32_t otp);
|
|
+uint32_t bsec_program_otp(uint32_t val, uint32_t otp);
|
|
+uint32_t bsec_permanent_lock_otp(uint32_t otp);
|
|
+
|
|
+uint32_t bsec_write_debug_conf(uint32_t val);
|
|
+uint32_t bsec_read_debug_conf(void);
|
|
+uint32_t bsec_write_feature_conf(uint32_t val);
|
|
+uint32_t bsec_read_feature_conf(uint32_t *val);
|
|
+
|
|
+uint32_t bsec_get_status(void);
|
|
+uint32_t bsec_get_hw_conf(void);
|
|
+uint32_t bsec_get_version(void);
|
|
+uint32_t bsec_get_id(void);
|
|
+uint32_t bsec_get_magic_id(void);
|
|
+
|
|
+bool bsec_write_sr_lock(uint32_t otp, uint32_t value);
|
|
+bool bsec_read_sr_lock(uint32_t otp);
|
|
+bool bsec_write_sw_lock(uint32_t otp, uint32_t value);
|
|
+bool bsec_read_sw_lock(uint32_t otp);
|
|
+bool bsec_write_sp_lock(uint32_t otp, uint32_t value);
|
|
+bool bsec_read_sp_lock(uint32_t otp);
|
|
+bool bsec_wr_lock(uint32_t otp);
|
|
+uint32_t bsec_otp_lock(uint32_t service, uint32_t value);
|
|
+
|
|
+bool bsec_mode_is_closed_device(void);
|
|
+uint32_t bsec_shadow_read_otp(uint32_t *otp_value, uint32_t word);
|
|
+uint32_t bsec_check_nsec_access_rights(uint32_t otp);
|
|
+
|
|
+#endif /*__BSEC_H__*/
|
|
diff --git a/include/drivers/st/etzpc.h b/include/drivers/st/etzpc.h
|
|
new file mode 100644
|
|
index 0000000..c31d996
|
|
--- /dev/null
|
|
+++ b/include/drivers/st/etzpc.h
|
|
@@ -0,0 +1,32 @@
|
|
+/*
|
|
+ * Copyright (c) 2017-2018, STMicroelectronics
|
|
+ *
|
|
+ * SPDX-License-Identifier: BSD-3-Clause
|
|
+ */
|
|
+
|
|
+#ifndef __ETZPC_H__
|
|
+#define __ETZPC_H__
|
|
+
|
|
+/* Define security level for each peripheral (DECPROT) */
|
|
+enum etzpc_decprot_attributes {
|
|
+ TZPC_DECPROT_S_RW = 0,
|
|
+ TZPC_DECPROT_NS_R_S_W = 1,
|
|
+ TZPC_DECPROT_MCU_ISOLATION = 2,
|
|
+ TZPC_DECPROT_NS_RW = 3,
|
|
+ TZPC_DECPROT_MAX = 4,
|
|
+};
|
|
+
|
|
+void etzpc_configure_decprot(uint32_t decprot_id,
|
|
+ enum etzpc_decprot_attributes decprot_attr);
|
|
+enum etzpc_decprot_attributes etzpc_get_decprot(uint32_t decprot_id);
|
|
+void etzpc_lock_decprot(uint32_t decprot_id);
|
|
+void etzpc_configure_tzma(uint32_t tzma_id, uint16_t tzma_value);
|
|
+uint16_t etzpc_get_tzma(uint32_t tzma_id);
|
|
+void etzpc_lock_tzma(uint32_t tzma_id);
|
|
+bool etzpc_get_lock_tzma(uint32_t tzma_id);
|
|
+uint8_t etzpc_get_num_per_sec(void);
|
|
+uint8_t etzpc_get_revision(void);
|
|
+uintptr_t etzpc_get_base_address(void);
|
|
+int etzpc_init(void);
|
|
+
|
|
+#endif /* __ETZPC_H__ */
|
|
diff --git a/include/drivers/st/hash_sec.h b/include/drivers/st/hash_sec.h
|
|
new file mode 100644
|
|
index 0000000..a8d8b9b
|
|
--- /dev/null
|
|
+++ b/include/drivers/st/hash_sec.h
|
|
@@ -0,0 +1,113 @@
|
|
+/**
|
|
+ ******************************************************************************
|
|
+ * @file hash_sec.h
|
|
+ * @author mgentilini - MCD IntroPack team - MPU AP v1 bootROM project
|
|
+ * @version V0.1
|
|
+ * @date 22-Sept-2015
|
|
+ * @brief Header file for STM32MP1 HASH driver module.
|
|
+ ******************************************************************************
|
|
+ * @attention
|
|
+ *
|
|
+ * <h2><center>© COPYRIGHT(c) 2015 STMicroelectronics</center></h2>
|
|
+ *
|
|
+ * SPDX-License-Identifier: BSD-3-Clause
|
|
+ *
|
|
+ ******************************************************************************
|
|
+ */
|
|
+
|
|
+/* Define to prevent recursive inclusion -------------------------------------*/
|
|
+#ifndef __HASH_SEC_H
|
|
+#define __HASH_SEC_H
|
|
+
|
|
+#ifdef __cplusplus
|
|
+extern "C" {
|
|
+#endif
|
|
+
|
|
+#include <stm32mp1xx_hal.h>
|
|
+#include <stm32_hal_hash_reg.h>
|
|
+
|
|
+/* Definitions----------------------------------------------------------------*/
|
|
+#define HASH ((HASH_TypeDef *)HASH_BASE)
|
|
+#define HASH_DIGEST ((HASH_DIGEST_TypeDef *)(HASH_BASE + 0x310))
|
|
+
|
|
+#define HASH_TIMEOUT_VALUE 0x500000
|
|
+
|
|
+/*
|
|
+ * HASH IP uses 512 bits : ie 64 bytes block in order to start computation of
|
|
+ * Hash intermediate Digest
|
|
+ * The digest intermediate computation starts only after 64 bytes are entered
|
|
+ */
|
|
+#define HASH_BLOCK_SIZE_NB_BYTES 64
|
|
+
|
|
+/**
|
|
+ * @brief Set the number of valid bits in last word 32 bits written in Data
|
|
+ * register
|
|
+ * @param SIZE: size in byte of last data written in Data register.
|
|
+ * @retval None
|
|
+ */
|
|
+
|
|
+#define __HAL_HASH_SET_NBVALIDBITSINLAST32BITSWORD(SIZE) \
|
|
+ do { \
|
|
+ HASH->STR &= ~(HASH_STR_NBW); \
|
|
+ HASH->STR |= 8 * ((SIZE) % 4); \
|
|
+ } while (0)
|
|
+
|
|
+/**
|
|
+ * @brief HASH Handle Structure definition
|
|
+ */
|
|
+typedef struct {
|
|
+ HASH_TypeDef *Instance; /*!< HASH Registers base address */
|
|
+ uint32_t State;
|
|
+ uint32_t Error;
|
|
+ const uint8_t *pHashInBuffPtr; /*!< Pointer to input buffer */
|
|
+ const uint8_t *pHashOutBuffPtr; /*!< Pointer to output buffer */
|
|
+} HASH_HandleTypeDef;
|
|
+
|
|
+#define HASH_DIGEST_DONE 0x0
|
|
+#define HASH_TIMEOUT 0x1
|
|
+#define HASH_INIT_DONE 0x2
|
|
+#define HASH_ACCU_DONE 0x3
|
|
+#define HASH_FINISHED 0x4
|
|
+#define HASH_INIT_NOT_DONE 0x5
|
|
+
|
|
+/** @defgroup HASH_Algo_Selection
|
|
+ * @{
|
|
+ */
|
|
+#define HASH_AlgoSelection_SHA256 HASH_CR_ALGO /*!< HASH function is SHA256 */
|
|
+
|
|
+/**
|
|
+ * @}
|
|
+ */
|
|
+
|
|
+/** @defgroup HASH_Data_Type
|
|
+ * @{
|
|
+ */
|
|
+#define HASH_DATATYPE_8B HASH_CR_DATATYPE_1 /*!< 8-bit data. All bytes are
|
|
+ * swapped
|
|
+ */
|
|
+
|
|
+/* Exported functions --------------------------------------------------------*/
|
|
+
|
|
+/* HASH processing using polling *********************************************/
|
|
+Std_ReturnType HASH_SHA256_Init(HASH_HandleTypeDef *hHash);
|
|
+
|
|
+Std_ReturnType HASH_SHA256_Start(HASH_HandleTypeDef *hHash,
|
|
+ const uint8_t *pInBuffer,
|
|
+ uint32_t sizeInBytes,
|
|
+ uint8_t *pOutBuffer, uint32_t Timeout);
|
|
+
|
|
+Std_ReturnType HASH_SHA256_Accumulate(HASH_HandleTypeDef *hHash,
|
|
+ const uint8_t *pInBuffer,
|
|
+ uint32_t sizeInBytes);
|
|
+
|
|
+Std_ReturnType HASH_SHA256_Finish(HASH_HandleTypeDef *hHash,
|
|
+ uint8_t *pOutBuffer, uint32_t Timeout);
|
|
+
|
|
+#ifdef __cplusplus
|
|
+}
|
|
+#endif
|
|
+
|
|
+#endif /* __HASH_SEC_H */
|
|
+
|
|
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
|
|
+
|
|
diff --git a/include/drivers/st/io_mmc.h b/include/drivers/st/io_mmc.h
|
|
new file mode 100644
|
|
index 0000000..de71e7d
|
|
--- /dev/null
|
|
+++ b/include/drivers/st/io_mmc.h
|
|
@@ -0,0 +1,14 @@
|
|
+/*
|
|
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
|
|
+ *
|
|
+ * SPDX-License-Identifier: BSD-3-Clause
|
|
+ */
|
|
+
|
|
+#ifndef IO_MMC_H
|
|
+#define IO_MMC_H
|
|
+
|
|
+#include <io_driver.h>
|
|
+
|
|
+int register_io_dev_mmc(const io_dev_connector_t **dev_con);
|
|
+
|
|
+#endif /* IO_MMC_H */
|
|
diff --git a/include/drivers/st/io_nand.h b/include/drivers/st/io_nand.h
|
|
new file mode 100644
|
|
index 0000000..13c8fbf
|
|
--- /dev/null
|
|
+++ b/include/drivers/st/io_nand.h
|
|
@@ -0,0 +1,19 @@
|
|
+/*
|
|
+ * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved.
|
|
+ *
|
|
+ * SPDX-License-Identifier: BSD-3-Clause
|
|
+ */
|
|
+
|
|
+#ifndef __IO_NAND_H__
|
|
+#define __IO_NAND_H__
|
|
+
|
|
+#define STM32_NAND_MAX_BLOCK_SIZE 512
|
|
+
|
|
+typedef struct nand_device_info {
|
|
+ uint64_t device_size; /* Size of device in bytes */
|
|
+ uint32_t block_size; /* block size in bytes */
|
|
+} nand_device_info_t;
|
|
+
|
|
+int register_io_dev_nand(const io_dev_connector_t **dev_con);
|
|
+
|
|
+#endif /* __IO_NAND_H__ */
|
|
diff --git a/include/drivers/st/io_programmer.h b/include/drivers/st/io_programmer.h
|
|
new file mode 100644
|
|
index 0000000..454aa68
|
|
--- /dev/null
|
|
+++ b/include/drivers/st/io_programmer.h
|
|
@@ -0,0 +1,51 @@
|
|
+/*
|
|
+ * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved.
|
|
+ *
|
|
+ * SPDX-License-Identifier: BSD-3-Clause
|
|
+ */
|
|
+
|
|
+#ifndef __IO_PROGRAMMER_H__
|
|
+#define __IO_PROGRAMMER_H__
|
|
+
|
|
+/* Phase definition */
|
|
+#define PHASE_FLASHLAYOUT 0
|
|
+#define PHASE_FSBL1 1
|
|
+#define PHASE_FSBL2 2
|
|
+#define PHASE_SSBL 3
|
|
+
|
|
+/* Command definition */
|
|
+#define GET_CMD_COMMAND 0x00
|
|
+#define GET_VER_COMMAND 0x01
|
|
+#define GET_ID_COMMAND 0x02
|
|
+#define PHASE_COMMAND 0x03
|
|
+#define START_COMMAND 0x21
|
|
+#define DOWNLOAD_COMMAND 0x31
|
|
+
|
|
+/* Answer defines */
|
|
+#define INIT_BYTE 0x7F
|
|
+#define ACK_BYTE 0x79
|
|
+#define NACK_BYTE 0x1F
|
|
+#define ABORT 0x5F
|
|
+
|
|
+#define PROGRAMMER_TIMEOUT 0xFFFFFFFE
|
|
+
|
|
+#define DEVICE_ID_BYTE1 0x05
|
|
+#define DEVICE_ID_BYTE2 0x00
|
|
+
|
|
+/* phase structure */
|
|
+struct phase_struct {
|
|
+ uint32_t keep_header;
|
|
+ uint32_t current_packet;
|
|
+ size_t max_size;
|
|
+ uint8_t phase_id;
|
|
+};
|
|
+
|
|
+/* current phase struct variable */
|
|
+static struct phase_struct current_phase = {
|
|
+ .phase_id = PHASE_FSBL1,
|
|
+ .max_size = 0,
|
|
+ .keep_header = 0,
|
|
+ .current_packet = 0,
|
|
+};
|
|
+
|
|
+#endif /* __IO_PROGRAMMER_H__ */
|
|
diff --git a/include/drivers/st/io_programmer_st_usb.h b/include/drivers/st/io_programmer_st_usb.h
|
|
new file mode 100644
|
|
index 0000000..f6ad9c7
|
|
--- /dev/null
|
|
+++ b/include/drivers/st/io_programmer_st_usb.h
|
|
@@ -0,0 +1,20 @@
|
|
+/*
|
|
+ * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved.
|
|
+ *
|
|
+ * SPDX-License-Identifier: BSD-3-Clause
|
|
+ */
|
|
+
|
|
+#ifndef __IO_USB_H__
|
|
+#define __IO_USB_H__
|
|
+
|
|
+#define IO_USB_TIMEOUT 0xFFFFF
|
|
+/* need to call the USB Handler 4 times after to have
|
|
+ * received the detach request
|
|
+ */
|
|
+#define DETACH_TIMEOUT 0x100
|
|
+
|
|
+#define USB_DFU_MAX_XFER_SIZE 1024
|
|
+
|
|
+int register_io_dev_usb(const io_dev_connector_t **dev_con);
|
|
+
|
|
+#endif /* __IO_USB_H__ */
|
|
diff --git a/include/drivers/st/io_qspi.h b/include/drivers/st/io_qspi.h
|
|
new file mode 100644
|
|
index 0000000..fc03faf
|
|
--- /dev/null
|
|
+++ b/include/drivers/st/io_qspi.h
|
|
@@ -0,0 +1,92 @@
|
|
+/*
|
|
+ * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved.
|
|
+ *
|
|
+ * SPDX-License-Identifier: BSD-3-Clause
|
|
+ */
|
|
+
|
|
+#ifndef __IO_QSPI_H__
|
|
+#define __IO_QSPI_H__
|
|
+
|
|
+#define QSPI_FMODE_MASK 0x0C000000
|
|
+#define QSPI_FMODE_MEMORY_MAPPED 0x0C000000
|
|
+
|
|
+#define QSPI_NOR_MAX_SIZE 0x10000000 /* 256 MB*/
|
|
+#define QSPI_NOR_LBA_SIZE 0x00000200 /* 512 B*/
|
|
+#define QSPI_NOR_BLK_SIZE 0x00040000 /* 256 KB*/
|
|
+
|
|
+#define QSPI_CR_EN 0x00000001
|
|
+#define QSPI_CR_ABORT 0x00000002
|
|
+#define QSPI_CR_TCEN 0x00000008
|
|
+#define QSPI_CR_SSHIFT 0x00000010
|
|
+#define QSPI_CR_DFM 0x00000040
|
|
+#define QSPI_CR_PRESCALER_SHIFT 24
|
|
+
|
|
+#define QSPI_DCR_CSHT 0x00000100
|
|
+#define QSPI_DCR_FSIZE_MASK 0x001F0000
|
|
+#define QSPI_DCR_FSIZE_SHIFT 16
|
|
+
|
|
+#define QSPI_CCR_INST 0x0000000B
|
|
+#define QSPI_CCR_IMODE 0x00000100
|
|
+#define QSPI_CCR_ADMODE 0x00000400
|
|
+#define QSPI_CCR_ADSIZE 0x00002000
|
|
+#define QSPI_CCR_ABMODE 0x00000000
|
|
+#define QSPI_CCR_ABSIZE 0x00000000
|
|
+#define QSPI_CCR_DCYC 0x00200000
|
|
+#define QSPI_CCR_DMODE 0x01000000
|
|
+#define QSPI_CCR_FMODE_MM 0x0C000000
|
|
+#define QSPI_CCR_FMODE 0x04000000
|
|
+#define QSPI_CCR_SIOO 0x00000000
|
|
+#define QSPI_CCR_DDRM 0x00000000
|
|
+#define QSPI_CCR_DHHC 0x00000000
|
|
+
|
|
+#define QSPI_SR_FLEVEL 0x1F00
|
|
+#define QSPI_SR_BUSY 0x0020
|
|
+#define QSPI_SR_TOF 0x0010
|
|
+#define QSPI_SR_SMF 0x0008
|
|
+#define QSPI_SR_FTF 0x0004
|
|
+#define QSPI_SR_TCF 0x0002
|
|
+#define QSPI_SR_TEF 0x0001
|
|
+
|
|
+#define QSPI_FCR_CTOF 0x0008
|
|
+#define QSPI_FCR_CSMF 0x0004
|
|
+#define QSPI_FCR_CTCF 0x0002
|
|
+#define QSPI_FCR_CTEF 0x0001
|
|
+
|
|
+#define QSPI_DFLT_READ_FLAGS (QSPI_CCR_INST | QSPI_CCR_IMODE | \
|
|
+ QSPI_CCR_ADMODE | QSPI_CCR_ADSIZE | \
|
|
+ QSPI_CCR_ABMODE | QSPI_CCR_ABSIZE | \
|
|
+ QSPI_CCR_DCYC | QSPI_CCR_DMODE | \
|
|
+ QSPI_CCR_SIOO | QSPI_CCR_DDRM | \
|
|
+ QSPI_CCR_DHHC)
|
|
+
|
|
+/*
|
|
+ * QUAD Serial Peripheral Interface
|
|
+ */
|
|
+
|
|
+typedef struct {
|
|
+ volatile uint32_t CR; /* Control register */
|
|
+ volatile uint32_t DCR; /* Device Configuration register */
|
|
+ volatile uint32_t SR; /* Status register */
|
|
+ volatile uint32_t FCR; /* Flag Clear register */
|
|
+ volatile uint32_t DLR; /* Data Length register */
|
|
+ volatile uint32_t CCR; /* Communication Configuration register */
|
|
+ volatile uint32_t AR; /* Address register */
|
|
+ volatile uint32_t ABR; /* Alternate Bytes register */
|
|
+ volatile uint32_t DR; /* Data register */
|
|
+ volatile uint32_t PSMKR; /* Polling Status Mask register */
|
|
+ volatile uint32_t PSMAR; /* Polling Status Match register */
|
|
+ volatile uint32_t PIR; /* Polling Interval register */
|
|
+ volatile uint32_t LPTR; /* Low Power Timeout register */
|
|
+} QUADSPI_TypeDef;
|
|
+
|
|
+/*
|
|
+ * QSPI Handle Structure definition
|
|
+ */
|
|
+typedef struct {
|
|
+ QUADSPI_TypeDef *instance; /* QSPI registers base address */
|
|
+ uint32_t is_dual;
|
|
+} QSPI_HandleTypeDef;
|
|
+
|
|
+int register_io_dev_qspi(const io_dev_connector_t **dev_con);
|
|
+
|
|
+#endif /* __IO_QSPI_H__ */
|
|
diff --git a/include/drivers/st/io_stm32image.h b/include/drivers/st/io_stm32image.h
|
|
new file mode 100644
|
|
index 0000000..b668219
|
|
--- /dev/null
|
|
+++ b/include/drivers/st/io_stm32image.h
|
|
@@ -0,0 +1,32 @@
|
|
+/*
|
|
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
|
|
+ *
|
|
+ * SPDX-License-Identifier: BSD-3-Clause
|
|
+ */
|
|
+
|
|
+#ifndef IO_STM32IMAGE_H
|
|
+#define IO_STM32IMAGE_H
|
|
+
|
|
+#include <io_driver.h>
|
|
+#include <partition.h>
|
|
+
|
|
+#define MAX_LBA_SIZE 512
|
|
+#define MAX_PART_NAME_SIZE (EFI_NAMELEN + 1)
|
|
+#define STM32_PART_NUM (PLAT_PARTITION_MAX_ENTRIES - STM32_TF_A_COPIES)
|
|
+
|
|
+struct stm32image_part_info {
|
|
+ char name[MAX_PART_NAME_SIZE];
|
|
+ uint32_t binary_type;
|
|
+ uintptr_t part_offset;
|
|
+ uint32_t bkp_offset;
|
|
+};
|
|
+
|
|
+struct stm32image_device_info {
|
|
+ struct stm32image_part_info part_info[STM32_PART_NUM];
|
|
+ uint32_t device_size;
|
|
+ uint32_t lba_size;
|
|
+};
|
|
+
|
|
+int register_io_dev_stm32image(const io_dev_connector_t **dev_con);
|
|
+
|
|
+#endif /* IO_STM32IMAGE_H */
|
|
diff --git a/include/drivers/st/io_uart.h b/include/drivers/st/io_uart.h
|
|
new file mode 100644
|
|
index 0000000..2f9ecb3
|
|
--- /dev/null
|
|
+++ b/include/drivers/st/io_uart.h
|
|
@@ -0,0 +1,12 @@
|
|
+/*
|
|
+ * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved.
|
|
+ *
|
|
+ * SPDX-License-Identifier: BSD-3-Clause
|
|
+ */
|
|
+
|
|
+#ifndef __IO_UART_H__
|
|
+#define __IO_UART_H__
|
|
+
|
|
+int register_io_dev_uart(const io_dev_connector_t **dev_con);
|
|
+
|
|
+#endif /* __IO_UART_H__ */
|
|
diff --git a/include/drivers/st/nand.h b/include/drivers/st/nand.h
|
|
new file mode 100644
|
|
index 0000000..f92511d
|
|
--- /dev/null
|
|
+++ b/include/drivers/st/nand.h
|
|
@@ -0,0 +1,252 @@
|
|
+/*
|
|
+ ******************************************************************************
|
|
+ * @file nand.h
|
|
+ * @author mgentilini - MCD IntroPack team - MPU AP v1 bootROM project
|
|
+ * @version V0.1
|
|
+ * @date 28-April-2016
|
|
+ * @brief Header file for STM32MP1 Nand driver module.
|
|
+ ******************************************************************************
|
|
+ * @attention
|
|
+ *
|
|
+ * <h2><center>© COPYRIGHT(c) STMicroelectronics</center></h2>
|
|
+ *
|
|
+ * SPDX-License-Identifier: BSD-3-Clause
|
|
+ *
|
|
+ ******************************************************************************
|
|
+ */
|
|
+
|
|
+#ifndef __NAND_H
|
|
+#define __NAND_H
|
|
+
|
|
+#include <stm32mp1xx_hal.h>
|
|
+
|
|
+/* FMC NAND Flash 'common memory' data area */
|
|
+#define FLASH_COMMON_MEM_BASE 0x80000000
|
|
+/* FMC NAND Flash 'attribute memory' data area */
|
|
+#define FLASH_ATTRIB_MEM_BASE 0x88000000
|
|
+
|
|
+#define BCH_PAGE_SECTOR 512
|
|
+
|
|
+/* BBM */
|
|
+#define GOOD_BLOCK 0
|
|
+#define BAD_BLOCK 1
|
|
+
|
|
+/**************** Bit definition for FMC_PCR register *******************/
|
|
+/* Wait feature enable bit */
|
|
+#define FMC_PCR_PWAITEN ((uint32_t)0x00000002)
|
|
+/* PC Card/NAND Flash memory bank enable bit */
|
|
+#define FMC_PCR_PBKEN ((uint32_t)0x00000004)
|
|
+
|
|
+/* PWID[1:0] bits (NAND Flash databus width) */
|
|
+#define FMC_PCR_PWID ((uint32_t)0x00000030)
|
|
+#define FMC_PCR_PWID_0 ((uint32_t)0x00000010) /* Bit 0 */
|
|
+#define FMC_PCR_PWID_1 ((uint32_t)0x00000020) /* Bit 1 */
|
|
+
|
|
+/* ECC computation logic enable bit */
|
|
+#define FMC_PCR_ECCEN ((uint32_t)0x00000040)
|
|
+
|
|
+/* ECC algorithm */
|
|
+#define FMC_PCR_ECCALG ((uint32_t)0x00000100)
|
|
+
|
|
+/* TCLR[3:0] bits (CLE to RE delay) */
|
|
+#define FMC_PCR_TCLR_0 ((uint32_t)0x00000200) /* Bit 0 */
|
|
+#define FMC_PCR_TCLR_1 ((uint32_t)0x00000400) /* Bit 1 */
|
|
+#define FMC_PCR_TCLR_2 ((uint32_t)0x00000800) /* Bit 2 */
|
|
+#define FMC_PCR_TCLR_3 ((uint32_t)0x00001000) /* Bit 3 */
|
|
+
|
|
+/* TAR[3:0] bits (ALE to RE delay) */
|
|
+#define FMC_PCR_TAR_0 ((uint32_t)0x00002000) /* Bit 0 */
|
|
+#define FMC_PCR_TAR_1 ((uint32_t)0x00004000) /* Bit 1 */
|
|
+#define FMC_PCR_TAR_2 ((uint32_t)0x00008000) /* Bit 2 */
|
|
+#define FMC_PCR_TAR_3 ((uint32_t)0x00010000) /* Bit 3 */
|
|
+
|
|
+/* ECCSS[1:0] bits (ECC sector size) */
|
|
+#define FMC_PCR_ECCSS ((uint32_t)0x000E0000)
|
|
+#define FMC_PCR_ECCSS_0 ((uint32_t)0x00020000) /* Bit 0 */
|
|
+#define FMC_PCR_ECCSS_1 ((uint32_t)0x00040000) /* Bit 1 */
|
|
+#define FMC_PCR_ECCSS_2 ((uint32_t)0x00080000) /* Bit 2 */
|
|
+
|
|
+/* BCH Error correction capability */
|
|
+#define FMC_PCR_BCHECC ((uint32_t)0x01000000)
|
|
+
|
|
+/* Write enable */
|
|
+#define FMC_PCR_WE ((uint32_t)0x02000000)
|
|
+
|
|
+/**************** Bit definition for FMC_BCR1 register *******************/
|
|
+/* FMC controller enable */
|
|
+#define FMC_BCR1_FMCEN ((uint32_t)0x80000000)
|
|
+
|
|
+/**************** Bit definition for FMC_BCHISR register *******************/
|
|
+/* Decoder Error Ready Flag */
|
|
+#define FMC_BCHISR_DERF ((uint32_t)0x00000002)
|
|
+/* Decoder Uncorrectable Error Flag */
|
|
+#define FMC_BCHISR_DUEF ((uint32_t)0x00000001)
|
|
+/* Decoder Error Found Flag */
|
|
+#define FMC_BCHISR_DEFF ((uint32_t)0x00000004)
|
|
+
|
|
+/**************** Bit definition for FMC_BCHSR register *******************/
|
|
+/* Decoder Error Number */
|
|
+#define FMC_BCHSR_DEN ((uint32_t)0x0000000F)
|
|
+
|
|
+/**************** Bit definition for FMC_BCHDSR0 register *******************/
|
|
+/* Decoder Uncorrectable Error */
|
|
+#define FMC_BCHDSR0_DUE ((uint32_t)0x00000001)
|
|
+/* Decoder Error Number */
|
|
+#define FMC_BCHDSR0_DEN ((uint32_t)0x000000F0)
|
|
+
|
|
+/**************** Bit definition for FMC_BCHDSR1 register *******************/
|
|
+#define FMC_BCHDSR1_EBP1 ((uint32_t)0x00001FFF)
|
|
+#define FMC_BCHDSR1_EBP2 ((uint32_t)0x1FFF0000)
|
|
+
|
|
+/**************** Bit definition for FMC_BCHDSR2 register *******************/
|
|
+#define FMC_BCHDSR2_EBP1 ((uint32_t)0x00001FFF)
|
|
+#define FMC_BCHDSR2_EBP2 ((uint32_t)0x1FFF0000)
|
|
+
|
|
+/**************** Bit definition for FMC_BCHDSR3 register *******************/
|
|
+#define FMC_BCHDSR3_EBP1 ((uint32_t)0x00001FFF)
|
|
+#define FMC_BCHDSR3_EBP2 ((uint32_t)0x1FFF0000)
|
|
+
|
|
+/**************** Bit definition for FMC_BCHDSR4 register *******************/
|
|
+#define FMC_BCHDSR4_EBP1 ((uint32_t)0x00001FFF)
|
|
+#define FMC_BCHDSR4_EBP2 ((uint32_t)0x1FFF0000)
|
|
+
|
|
+/**************** Bit definition for FMC_SR register **********************/
|
|
+#define FMC_SR_NWRF ((uint32_t)0x00000040)
|
|
+#define FMC_SR_PF ((uint32_t)0x00000010)
|
|
+
|
|
+#define FMC_NSEC_PER_SEC 1000000000L
|
|
+
|
|
+/* Timings */
|
|
+#define FMC_THIZ 1
|
|
+#define FMC_TIO 8000
|
|
+#define FMC_TSYNC 3000
|
|
+#define FMC_PCR_TIMING_MASK 0xf
|
|
+#define FMC_PMEM_PATT_TIMING_MASK 0xff
|
|
+
|
|
+/* Register: FMC_PCR */
|
|
+#define FMC_PCR_TCLR(x) (((x) & 0xf) << 9)
|
|
+#define FMC_PCR_TAR(x) (((x) & 0xf) << 13)
|
|
+
|
|
+/* Register: FMC_PMEM */
|
|
+#define FMC_PMEM_MEMSET(x) (((x) & 0xff) << 0)
|
|
+#define FMC_PMEM_MEMWAIT(x) (((x) & 0xff) << 8)
|
|
+#define FMC_PMEM_MEMHOLD(x) (((x) & 0xff) << 16)
|
|
+#define FMC_PMEM_MEMHIZ(x) (((x) & 0xff) << 24)
|
|
+
|
|
+/* Register: FMC_PATT */
|
|
+#define FMC_PATT_ATTSET(x) (((x) & 0xff) << 0)
|
|
+#define FMC_PATT_ATTWAIT(x) (((x) & 0xff) << 8)
|
|
+#define FMC_PATT_ATTHOLD(x) (((x) & 0xff) << 16)
|
|
+#define FMC_PATT_ATTHIZ(x) (((x) & 0xff) << 24)
|
|
+
|
|
+/* NAND ONFI Default Value Mode 0 */
|
|
+#define FMC_TADL_MIN 200000
|
|
+#define FMC_TALH_MIN 20000
|
|
+#define FMC_TALS_MIN 50000
|
|
+#define FMC_TAR_MIN 25000
|
|
+#define FMC_TCH_MIN 20000
|
|
+#define FMC_TCLH_MIN 20000
|
|
+#define FMC_TCLR_MIN 20000
|
|
+#define FMC_TCLS_MIN 50000
|
|
+#define FMC_TCOH_MIN 0
|
|
+#define FMC_TCS_MIN 70000
|
|
+#define FMC_TDH_MIN 20000
|
|
+#define FMC_TDS_MIN 40000
|
|
+#define FMC_TRC_MIN 100000
|
|
+#define FMC_TREA_MAX 40000
|
|
+#define FMC_TREH_MIN 30000
|
|
+#define FMC_TRHW_MIN 200000
|
|
+#define FMC_TRP_MIN 50000
|
|
+#define FMC_TWB_MAX 200000
|
|
+#define FMC_TWC_MIN 100000
|
|
+#define FMC_TWH_MIN 30000
|
|
+#define FMC_TWHR_MIN 120000
|
|
+#define FMC_TWP_MIN 50000
|
|
+
|
|
+
|
|
+#define FMC_EBP2_MASK 16
|
|
+
|
|
+/* 1st addressing cycle */
|
|
+#define ADDR_1ST_CYCLE(__ADDRESS__) (uint8_t)(__ADDRESS__)
|
|
+/* 2nd addressing cycle */
|
|
+#define ADDR_2ND_CYCLE(__ADDRESS__) (uint8_t)((__ADDRESS__) >> 8)
|
|
+/* 3rd addressing cycle */
|
|
+#define ADDR_3RD_CYCLE(__ADDRESS__) (uint8_t)((__ADDRESS__) >> 16)
|
|
+/* 4th addressing cycle */
|
|
+#define ADDR_4TH_CYCLE(__ADDRESS__) (uint8_t)((__ADDRESS__) >> 24)
|
|
+
|
|
+typedef struct {
|
|
+ uint8_t tclr;
|
|
+ uint8_t tar;
|
|
+ uint8_t thiz;
|
|
+ uint8_t twait;
|
|
+ uint8_t thold_mem;
|
|
+ uint8_t tset_mem;
|
|
+ uint8_t thold_att;
|
|
+ uint8_t tset_att;
|
|
+} nand_timings;
|
|
+
|
|
+typedef struct {
|
|
+ uint32_t Signature; /* NAND Parameter page signature */
|
|
+
|
|
+ uint32_t PageSize; /* NAND memory page (without spare area) size
|
|
+ * measured in B
|
|
+ */
|
|
+
|
|
+ uint32_t BlockSize; /* NAND memory block size in number
|
|
+ * of pages
|
|
+ */
|
|
+
|
|
+ uint32_t BlockNb; /* NAND memory number of blocks */
|
|
+
|
|
+ uint32_t ZoneSize; /* NAND memory zone size measured in number
|
|
+ * of blocks
|
|
+ */
|
|
+
|
|
+ uint32_t BusWidth; /* NAND memory bus width in bytes */
|
|
+
|
|
+ uint32_t ECCcorrectability; /* NAND number of bits ECC correctability */
|
|
+
|
|
+ uint32_t page_size_shift;
|
|
+ uint32_t block_size_shift;
|
|
+
|
|
+ nand_timings timings;
|
|
+
|
|
+} NAND_InfoTypeDef;
|
|
+
|
|
+/* NAND Memory address Structure definition */
|
|
+typedef struct {
|
|
+ uint16_t Page; /* NAND memory Page address */
|
|
+
|
|
+ uint16_t Zone; /* NAND memory Zone address */
|
|
+
|
|
+ uint16_t Block; /* NAND memory Block address */
|
|
+} NAND_AddressTypeDef;
|
|
+
|
|
+/* NAND Memory electronic signature Structure definition */
|
|
+typedef struct {
|
|
+ uint8_t Maker_Id;
|
|
+
|
|
+ uint8_t Device_Id;
|
|
+} NAND_IDTypeDef;
|
|
+
|
|
+/* NAND handle Structure definition */
|
|
+typedef struct {
|
|
+ FMC_TypeDef *Instance; /* Register base address */
|
|
+
|
|
+ NAND_InfoTypeDef Info; /* NAND characteristic information structure */
|
|
+} NAND_HandleTypeDef;
|
|
+
|
|
+/* Exported functions */
|
|
+Std_ReturnType nand_initialize(NAND_HandleTypeDef *hnand);
|
|
+Std_ReturnType NAND_Read_Logical_Page(NAND_HandleTypeDef *hNand,
|
|
+ NAND_AddressTypeDef *Address,
|
|
+ uint8_t *Buffer, uint32_t bch_sector_nb);
|
|
+uint32_t NAND_Check_Bad_Block(NAND_HandleTypeDef *hNand,
|
|
+ NAND_AddressTypeDef *Address);
|
|
+Std_ReturnType NAND_Address_Inc(NAND_HandleTypeDef *hNand,
|
|
+ NAND_AddressTypeDef *Address,
|
|
+ uint32_t numPagesRead);
|
|
+
|
|
+#endif /* __NAND_H */
|
|
+
|
|
diff --git a/include/drivers/st/stm32_console.h b/include/drivers/st/stm32_console.h
|
|
new file mode 100644
|
|
index 0000000..57e6d74
|
|
--- /dev/null
|
|
+++ b/include/drivers/st/stm32_console.h
|
|
@@ -0,0 +1,34 @@
|
|
+/*
|
|
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
|
|
+ *
|
|
+ * SPDX-License-Identifier: BSD-3-Clause
|
|
+ */
|
|
+
|
|
+#ifndef STM32_CONSOLE_H
|
|
+#define STM32_CONSOLE_H
|
|
+
|
|
+#include <console.h>
|
|
+
|
|
+#define CONSOLE_T_STM32_BASE CONSOLE_T_DRVDATA
|
|
+
|
|
+#ifndef __ASSEMBLY__
|
|
+
|
|
+#include <stdint.h>
|
|
+
|
|
+struct console_stm32 {
|
|
+ console_t console;
|
|
+ uintptr_t base;
|
|
+};
|
|
+
|
|
+/*
|
|
+ * Initialize a new STM32 console instance and register it with the console
|
|
+ * framework. The |console| pointer must point to storage that will be valid
|
|
+ * for the lifetime of the console, such as a global or static local variable.
|
|
+ * Its contents will be reinitialized from scratch.
|
|
+ */
|
|
+int console_stm32_register(uintptr_t baseaddr, uint32_t clock, uint32_t baud,
|
|
+ struct console_stm32 *console);
|
|
+
|
|
+#endif /*__ASSEMBLY__*/
|
|
+
|
|
+#endif /* STM32_CONSOLE_H */
|
|
diff --git a/include/drivers/st/stm32_gpio.h b/include/drivers/st/stm32_gpio.h
|
|
index 7a5ccd3..33cef04 100644
|
|
--- a/include/drivers/st/stm32_gpio.h
|
|
+++ b/include/drivers/st/stm32_gpio.h
|
|
@@ -4,15 +4,11 @@
|
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
*/
|
|
|
|
-#ifndef __PLAT_GPIO_H__
|
|
-#define __PLAT_GPIO_H__
|
|
+#ifndef STM32_GPIO_H
|
|
+#define STM32_GPIO_H
|
|
|
|
#include <utils_def.h>
|
|
|
|
-#define STM32_GPIOA_BANK U(0x50002000)
|
|
-#define STM32_GPIOZ_BANK U(0x54004000)
|
|
-#define STM32_GPIO_BANK_OFFSET U(0x1000)
|
|
-
|
|
#define GPIO_MODE_OFFSET U(0x00)
|
|
#define GPIO_TYPE_OFFSET U(0x04)
|
|
#define GPIO_SPEED_OFFSET U(0x08)
|
|
@@ -20,56 +16,14 @@
|
|
#define GPIO_BSRR_OFFSET U(0x18)
|
|
#define GPIO_AFRL_OFFSET U(0x20)
|
|
#define GPIO_AFRH_OFFSET U(0x24)
|
|
+#define GPIO_SECR_OFFSET U(0x30)
|
|
|
|
#define GPIO_ALT_LOWER_LIMIT U(0x08)
|
|
|
|
-#define GPIO_BANK_A U(0x00)
|
|
-#define GPIO_BANK_B U(0x01)
|
|
-#define GPIO_BANK_C U(0x02)
|
|
-#define GPIO_BANK_D U(0x03)
|
|
-#define GPIO_BANK_E U(0x04)
|
|
-#define GPIO_BANK_F U(0x05)
|
|
-#define GPIO_BANK_G U(0x06)
|
|
-#define GPIO_BANK_H U(0x07)
|
|
-#define GPIO_BANK_I U(0x08)
|
|
-#define GPIO_BANK_J U(0x09)
|
|
-#define GPIO_BANK_K U(0x0A)
|
|
-#define GPIO_BANK_Z U(0x19)
|
|
-
|
|
-#define GPIO_PIN_0 U(0x00)
|
|
-#define GPIO_PIN_1 U(0x01)
|
|
-#define GPIO_PIN_2 U(0x02)
|
|
-#define GPIO_PIN_3 U(0x03)
|
|
-#define GPIO_PIN_4 U(0x04)
|
|
-#define GPIO_PIN_5 U(0x05)
|
|
-#define GPIO_PIN_6 U(0x06)
|
|
-#define GPIO_PIN_7 U(0x07)
|
|
-#define GPIO_PIN_8 U(0x08)
|
|
-#define GPIO_PIN_9 U(0x09)
|
|
-#define GPIO_PIN_10 U(0x0A)
|
|
-#define GPIO_PIN_11 U(0x0B)
|
|
-#define GPIO_PIN_12 U(0x0C)
|
|
-#define GPIO_PIN_13 U(0x0D)
|
|
-#define GPIO_PIN_14 U(0x0E)
|
|
-#define GPIO_PIN_15 U(0x0F)
|
|
-#define GPIO_PIN_MAX GPIO_PIN_15
|
|
+#define GPIO_PIN_(_x) U(_x)
|
|
+#define GPIO_PIN_MAX GPIO_PIN_(15)
|
|
|
|
-#define GPIO_ALTERNATE_0 0x00
|
|
-#define GPIO_ALTERNATE_1 0x01
|
|
-#define GPIO_ALTERNATE_2 0x02
|
|
-#define GPIO_ALTERNATE_3 0x03
|
|
-#define GPIO_ALTERNATE_4 0x04
|
|
-#define GPIO_ALTERNATE_5 0x05
|
|
-#define GPIO_ALTERNATE_6 0x06
|
|
-#define GPIO_ALTERNATE_7 0x07
|
|
-#define GPIO_ALTERNATE_8 0x08
|
|
-#define GPIO_ALTERNATE_9 0x09
|
|
-#define GPIO_ALTERNATE_10 0x0A
|
|
-#define GPIO_ALTERNATE_11 0x0B
|
|
-#define GPIO_ALTERNATE_12 0x0C
|
|
-#define GPIO_ALTERNATE_13 0x0D
|
|
-#define GPIO_ALTERNATE_14 0x0E
|
|
-#define GPIO_ALTERNATE_15 0x0F
|
|
+#define GPIO_ALTERNATE_(_x) U(_x)
|
|
#define GPIO_ALTERNATE_MASK U(0x0F)
|
|
|
|
#define GPIO_MODE_INPUT 0x00
|
|
@@ -82,8 +36,8 @@
|
|
|
|
#define GPIO_SPEED_LOW 0x00
|
|
#define GPIO_SPEED_MEDIUM 0x01
|
|
-#define GPIO_SPEED_FAST 0x02
|
|
-#define GPIO_SPEED_HIGH 0x03
|
|
+#define GPIO_SPEED_HIGH 0x02
|
|
+#define GPIO_SPEED_VERY_HIGH 0x03
|
|
#define GPIO_SPEED_MASK U(0x03)
|
|
|
|
#define GPIO_NO_PULL 0x00
|
|
@@ -94,8 +48,10 @@
|
|
#ifndef __ASSEMBLY__
|
|
#include <stdint.h>
|
|
|
|
+int dt_set_pinctrl_config(int node);
|
|
void set_gpio(uint32_t bank, uint32_t pin, uint32_t mode, uint32_t speed,
|
|
- uint32_t pull, uint32_t alternate);
|
|
+ uint32_t pull, uint32_t alternate, uint8_t status);
|
|
+void set_gpio_secure_cfg(uint32_t bank, uint32_t pin, bool secure);
|
|
#endif /*__ASSEMBLY__*/
|
|
|
|
-#endif /*__PLAT_GPIO_H__*/
|
|
+#endif /* STM32_GPIO_H */
|
|
diff --git a/include/drivers/st/stm32_hal_hash_reg.h b/include/drivers/st/stm32_hal_hash_reg.h
|
|
new file mode 100644
|
|
index 0000000..e7a589b
|
|
--- /dev/null
|
|
+++ b/include/drivers/st/stm32_hal_hash_reg.h
|
|
@@ -0,0 +1,136 @@
|
|
+/**
|
|
+ ******************************************************************************
|
|
+ * @file stm32_hal_hash_reg.h
|
|
+ * @author MCD Intropack Team - MPU AP v1 bootROM project
|
|
+ * @date 22 September 2015
|
|
+ * @brief STM32 Device Peripheral Access Layer Header File.
|
|
+ *
|
|
+ * This file contains:
|
|
+ * - Data structures and the address mapping for all peripherals
|
|
+ * - Peripheral's registers declarations and bits definition
|
|
+ * - Macros to access peripherals registers hardware
|
|
+ *
|
|
+ ******************************************************************************
|
|
+ * @attention
|
|
+ *
|
|
+ * <h2><center>© COPYRIGHT(c) 2015 STMicroelectronics</center></h2>
|
|
+ *
|
|
+ * SPDX-License-Identifier: BSD-3-Clause
|
|
+ *
|
|
+ ******************************************************************************
|
|
+ */
|
|
+
|
|
+#ifndef _STM32_HAL_HASH_REG_H_
|
|
+#define _STM32_HAL_HASH_REG_H_
|
|
+
|
|
+#ifdef __cplusplus
|
|
+ extern "C" {
|
|
+#endif /* __cplusplus */
|
|
+
|
|
+
|
|
+/** @addtogroup Peripheral_registers_structures
|
|
+ * @{
|
|
+ */
|
|
+
|
|
+/**
|
|
+ * @brief Secure digital input/output Interface
|
|
+ */
|
|
+#ifndef __ASM_INCLUDE__
|
|
+/**
|
|
+ * @brief HASH
|
|
+ */
|
|
+
|
|
+typedef struct
|
|
+{
|
|
+ __IO uint32_t CR; /*!< HASH control register, Address offset: 0x00 */
|
|
+ __IO uint32_t DIN; /*!< HASH data input register, Address offset: 0x04 */
|
|
+ __IO uint32_t STR; /*!< HASH start register, Address offset: 0x08 */
|
|
+ __IO uint32_t HR[5]; /*!< HASH digest registers, Address offset: 0x0C-0x1C */
|
|
+ __IO uint32_t IMR; /*!< HASH interrupt enable register, Address offset: 0x20 */
|
|
+ __IO uint32_t SR; /*!< HASH status register, Address offset: 0x24 */
|
|
+ uint32_t RESERVED[52]; /*!< Reserved, 0x28-0xF4 */
|
|
+ __IO uint32_t CSR[54]; /*!< HASH context swap registers, Address offset: 0x0F8-0x1CC */
|
|
+} HASH_TypeDef;
|
|
+#endif /* __ASM_INCLUDE__ */
|
|
+
|
|
+#ifndef __ASM_INCLUDE__
|
|
+/**
|
|
+ * @brief HASH_DIGEST
|
|
+ */
|
|
+
|
|
+typedef struct
|
|
+{
|
|
+ __IO uint32_t HR[8]; /*!< HASH digest registers, Address offset: 0x310-0x32C */
|
|
+} HASH_DIGEST_TypeDef;
|
|
+#endif /* __ASM_INCLUDE__ */
|
|
+
|
|
+
|
|
+
|
|
+
|
|
+
|
|
+/** @addtogroup Exported_constants
|
|
+ * @{
|
|
+ */
|
|
+
|
|
+ /** @addtogroup Peripheral_Registers_Bits_Definition
|
|
+ * @{
|
|
+ */
|
|
+
|
|
+/****************** Bits definition for HASH_CR register ********************/
|
|
+#define HASH_CR_INIT ((uint32_t)0x00000004)
|
|
+#define HASH_CR_DMAE ((uint32_t)0x00000008)
|
|
+#define HASH_CR_DATATYPE ((uint32_t)0x00000030)
|
|
+#define HASH_CR_DATATYPE_0 ((uint32_t)0x00000010)
|
|
+#define HASH_CR_DATATYPE_1 ((uint32_t)0x00000020)
|
|
+#define HASH_CR_MODE ((uint32_t)0x00000040)
|
|
+#define HASH_CR_ALGO ((uint32_t)0x00040080)
|
|
+#define HASH_CR_ALGO_0 ((uint32_t)0x00000080)
|
|
+#define HASH_CR_ALGO_1 ((uint32_t)0x00040000)
|
|
+#define HASH_CR_NBW ((uint32_t)0x00000F00)
|
|
+#define HASH_CR_NBW_0 ((uint32_t)0x00000100)
|
|
+#define HASH_CR_NBW_1 ((uint32_t)0x00000200)
|
|
+#define HASH_CR_NBW_2 ((uint32_t)0x00000400)
|
|
+#define HASH_CR_NBW_3 ((uint32_t)0x00000800)
|
|
+#define HASH_CR_DINNE ((uint32_t)0x00001000)
|
|
+#define HASH_CR_MDMAT ((uint32_t)0x00002000)
|
|
+#define HASH_CR_LKEY ((uint32_t)0x00010000)
|
|
+
|
|
+/****************** Bits definition for HASH_STR register *******************/
|
|
+#define HASH_STR_NBW ((uint32_t)0x0000001F)
|
|
+#define HASH_STR_NBW_0 ((uint32_t)0x00000001)
|
|
+#define HASH_STR_NBW_1 ((uint32_t)0x00000002)
|
|
+#define HASH_STR_NBW_2 ((uint32_t)0x00000004)
|
|
+#define HASH_STR_NBW_3 ((uint32_t)0x00000008)
|
|
+#define HASH_STR_NBW_4 ((uint32_t)0x00000010)
|
|
+#define HASH_STR_DCAL ((uint32_t)0x00000100)
|
|
+
|
|
+/****************** Bits definition for HASH_IMR register *******************/
|
|
+#define HASH_IMR_DINIM ((uint32_t)0x00000001)
|
|
+#define HASH_IMR_DCIM ((uint32_t)0x00000002)
|
|
+
|
|
+/****************** Bits definition for HASH_SR register ********************/
|
|
+#define HASH_SR_DINIS ((uint32_t)0x00000001)
|
|
+#define HASH_SR_DCIS ((uint32_t)0x00000002)
|
|
+#define HASH_SR_DMAS ((uint32_t)0x00000004)
|
|
+#define HASH_SR_BUSY ((uint32_t)0x00000008)
|
|
+
|
|
+/**
|
|
+ * @}
|
|
+ */
|
|
+
|
|
+/**
|
|
+ * @}
|
|
+ */
|
|
+
|
|
+
|
|
+/**
|
|
+ * @}
|
|
+ */
|
|
+
|
|
+#ifdef __cplusplus
|
|
+}
|
|
+#endif /* __cplusplus */
|
|
+
|
|
+#endif /* _STM32_HAL_HASH_REG_H_ */
|
|
+
|
|
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
|
|
diff --git a/include/drivers/st/stm32_i2c.h b/include/drivers/st/stm32_i2c.h
|
|
index 29b9d34..4d5e302 100644
|
|
--- a/include/drivers/st/stm32_i2c.h
|
|
+++ b/include/drivers/st/stm32_i2c.h
|
|
@@ -1,11 +1,11 @@
|
|
/*
|
|
* Copyright (c) 2016-2018, STMicroelectronics - All Rights Reserved
|
|
*
|
|
- * SPDX-License-Identifier: BSD-3-Clause
|
|
+ * SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
|
|
*/
|
|
|
|
-#ifndef __STM32MP1_I2C_H
|
|
-#define __STM32MP1_I2C_H
|
|
+#ifndef STM32_I2C_H
|
|
+#define STM32_I2C_H
|
|
|
|
#include <stdint.h>
|
|
#include <utils_def.h>
|
|
@@ -72,6 +72,21 @@
|
|
#define I2C_TIMINGR_SDADEL GENMASK(19, 16)
|
|
#define I2C_TIMINGR_SCLDEL GENMASK(23, 20)
|
|
#define I2C_TIMINGR_PRESC GENMASK(31, 28)
|
|
+#define I2C_TIMINGR_SCLL_MAX (I2C_TIMINGR_SCLL + 1)
|
|
+#define I2C_TIMINGR_SCLH_MAX ((I2C_TIMINGR_SCLH >> 8) + 1)
|
|
+#define I2C_TIMINGR_SDADEL_MAX ((I2C_TIMINGR_SDADEL >> 16) + 1)
|
|
+#define I2C_TIMINGR_SCLDEL_MAX ((I2C_TIMINGR_SCLDEL >> 20) + 1)
|
|
+#define I2C_TIMINGR_PRESC_MAX ((I2C_TIMINGR_PRESC >> 28) + 1)
|
|
+#define I2C_SET_TIMINGR_SCLL(n) ((n) & \
|
|
+ (I2C_TIMINGR_SCLL_MAX - 1))
|
|
+#define I2C_SET_TIMINGR_SCLH(n) (((n) & \
|
|
+ (I2C_TIMINGR_SCLH_MAX - 1)) << 8)
|
|
+#define I2C_SET_TIMINGR_SDADEL(n) (((n) & \
|
|
+ (I2C_TIMINGR_SDADEL_MAX - 1)) << 16)
|
|
+#define I2C_SET_TIMINGR_SCLDEL(n) (((n) & \
|
|
+ (I2C_TIMINGR_SCLDEL_MAX - 1)) << 20)
|
|
+#define I2C_SET_TIMINGR_PRESC(n) (((n) & \
|
|
+ (I2C_TIMINGR_PRESC_MAX - 1)) << 28)
|
|
|
|
/* Bit definition for I2C_TIMEOUTR register */
|
|
#define I2C_TIMEOUTR_TIMEOUTA GENMASK(11, 0)
|
|
@@ -110,94 +125,113 @@
|
|
#define I2C_ICR_TIMOUTCF BIT(12)
|
|
#define I2C_ICR_ALERTCF BIT(13)
|
|
|
|
-struct stm32_i2c_init_s {
|
|
- uint32_t timing; /* Specifies the I2C_TIMINGR_register value
|
|
- * This parameter is calculated by referring
|
|
- * to I2C initialization section in Reference
|
|
- * manual.
|
|
- */
|
|
-
|
|
- uint32_t own_address1; /* Specifies the first device own address.
|
|
- * This parameter can be a 7-bit or 10-bit
|
|
- * address.
|
|
- */
|
|
-
|
|
- uint32_t addressing_mode; /* Specifies if 7-bit or 10-bit addressing
|
|
- * mode is selected.
|
|
- * This parameter can be a value of @ref
|
|
- * I2C_ADDRESSING_MODE.
|
|
- */
|
|
-
|
|
- uint32_t dual_address_mode; /* Specifies if dual addressing mode is
|
|
- * selected.
|
|
- * This parameter can be a value of @ref
|
|
- * I2C_DUAL_ADDRESSING_MODE.
|
|
- */
|
|
-
|
|
- uint32_t own_address2; /* Specifies the second device own address
|
|
- * if dual addressing mode is selected.
|
|
- * This parameter can be a 7-bit address.
|
|
- */
|
|
-
|
|
- uint32_t own_address2_masks; /* Specifies the acknowledge mask address
|
|
- * second device own address if dual
|
|
- * addressing mode is selected.
|
|
- * This parameter can be a value of @ref
|
|
- * I2C_OWN_ADDRESS2_MASKS.
|
|
- */
|
|
-
|
|
- uint32_t general_call_mode; /* Specifies if general call mode is
|
|
- * selected.
|
|
- * This parameter can be a value of @ref
|
|
- * I2C_GENERAL_CALL_ADDRESSING_MODE.
|
|
- */
|
|
-
|
|
- uint32_t no_stretch_mode; /* Specifies if nostretch mode is
|
|
- * selected.
|
|
- * This parameter can be a value of @ref
|
|
- * I2C_NOSTRETCH_MODE.
|
|
- */
|
|
+enum i2c_speed_e {
|
|
+ I2C_SPEED_STANDARD, /* 100 kHz */
|
|
+ I2C_SPEED_FAST, /* 400 kHz */
|
|
+ I2C_SPEED_FAST_PLUS, /* 1 MHz */
|
|
+};
|
|
+
|
|
+#define STANDARD_RATE 100000
|
|
+#define FAST_RATE 400000
|
|
+#define FAST_PLUS_RATE 1000000
|
|
|
|
+struct stm32_i2c_init_s {
|
|
+ uint32_t own_address1; /*
|
|
+ * Specifies the first device own
|
|
+ * address. This parameter can be a
|
|
+ * 7-bit or 10-bit address.
|
|
+ */
|
|
+
|
|
+ uint32_t addressing_mode; /*
|
|
+ * Specifies if 7-bit or 10-bit
|
|
+ * addressing mode is selected.
|
|
+ * This parameter can be a value of
|
|
+ * @ref I2C_ADDRESSING_MODE.
|
|
+ */
|
|
+
|
|
+ uint32_t dual_address_mode; /*
|
|
+ * Specifies if dual addressing mode is
|
|
+ * selected.
|
|
+ * This parameter can be a value of @ref
|
|
+ * I2C_DUAL_ADDRESSING_MODE.
|
|
+ */
|
|
+
|
|
+ uint32_t own_address2; /*
|
|
+ * Specifies the second device own
|
|
+ * address if dual addressing mode is
|
|
+ * selected. This parameter can be a
|
|
+ * 7-bit address.
|
|
+ */
|
|
+
|
|
+ uint32_t own_address2_masks; /*
|
|
+ * Specifies the acknowledge mask
|
|
+ * address second device own address
|
|
+ * if dual addressing mode is selected
|
|
+ * This parameter can be a value of @ref
|
|
+ * I2C_OWN_ADDRESS2_MASKS.
|
|
+ */
|
|
+
|
|
+ uint32_t general_call_mode; /*
|
|
+ * Specifies if general call mode is
|
|
+ * selected.
|
|
+ * This parameter can be a value of @ref
|
|
+ * I2C_GENERAL_CALL_ADDRESSING_MODE.
|
|
+ */
|
|
+
|
|
+ uint32_t no_stretch_mode; /*
|
|
+ * Specifies if nostretch mode is
|
|
+ * selected.
|
|
+ * This parameter can be a value of @ref
|
|
+ * I2C_NOSTRETCH_MODE.
|
|
+ */
|
|
+
|
|
+ uint32_t rise_time; /*
|
|
+ * Specifies the SCL clock pin rising
|
|
+ * time in nanoseconds.
|
|
+ */
|
|
+
|
|
+ uint32_t fall_time; /*
|
|
+ * Specifies the SCL clock pin falling
|
|
+ * time in nanoseconds.
|
|
+ */
|
|
+
|
|
+ enum i2c_speed_e speed_mode; /*
|
|
+ * Specifies the I2C clock source
|
|
+ * frequency mode.
|
|
+ * This parameter can be a value of @ref
|
|
+ * i2c_speed_mode_e.
|
|
+ */
|
|
+
|
|
+ int analog_filter; /*
|
|
+ * Specifies if the I2C analog noise
|
|
+ * filter is selected.
|
|
+ * This parameter can be 0 (filter
|
|
+ * off), all other values mean filter
|
|
+ * on.
|
|
+ */
|
|
+
|
|
+ uint8_t digital_filter_coef; /*
|
|
+ * Specifies the I2C digital noise
|
|
+ * filter coefficient.
|
|
+ * This parameter can be a value
|
|
+ * between 0 and
|
|
+ * STM32_I2C_DIGITAL_FILTER_MAX.
|
|
+ */
|
|
};
|
|
|
|
enum i2c_state_e {
|
|
- I2C_STATE_RESET = 0x00U, /* Peripheral is not yet
|
|
- * initialized.
|
|
- */
|
|
- I2C_STATE_READY = 0x20U, /* Peripheral Initialized
|
|
- * and ready for use.
|
|
- */
|
|
- I2C_STATE_BUSY = 0x24U, /* An internal process is
|
|
- * ongoing.
|
|
- */
|
|
- I2C_STATE_BUSY_TX = 0x21U, /* Data Transmission process
|
|
- * is ongoing.
|
|
- */
|
|
- I2C_STATE_BUSY_RX = 0x22U, /* Data Reception process
|
|
- * is ongoing.
|
|
- */
|
|
- I2C_STATE_LISTEN = 0x28U, /* Address Listen Mode is
|
|
- * ongoing.
|
|
- */
|
|
- I2C_STATE_BUSY_TX_LISTEN = 0x29U, /* Address Listen Mode
|
|
- * and Data Transmission
|
|
- * process is ongoing.
|
|
- */
|
|
- I2C_STATE_BUSY_RX_LISTEN = 0x2AU, /* Address Listen Mode
|
|
- * and Data Reception
|
|
- * process is ongoing.
|
|
- */
|
|
- I2C_STATE_ABORT = 0x60U, /* Abort user request ongoing. */
|
|
- I2C_STATE_TIMEOUT = 0xA0U, /* Timeout state. */
|
|
- I2C_STATE_ERROR = 0xE0U /* Error. */
|
|
-
|
|
+ I2C_STATE_RESET = 0x00U, /* Not yet initialized */
|
|
+ I2C_STATE_READY = 0x20U, /* Ready for use */
|
|
+ I2C_STATE_BUSY = 0x24U, /* Internal process ongoing */
|
|
+ I2C_STATE_BUSY_TX = 0x21U, /* Data Transmission ongoing */
|
|
+ I2C_STATE_BUSY_RX = 0x22U, /* Data Reception ongoing */
|
|
};
|
|
|
|
enum i2c_mode_e {
|
|
- I2C_MODE_NONE = 0x00U, /* No I2C communication on going. */
|
|
- I2C_MODE_MASTER = 0x10U, /* I2C communication is in Master Mode. */
|
|
- I2C_MODE_SLAVE = 0x20U, /* I2C communication is in Slave Mode. */
|
|
- I2C_MODE_MEM = 0x40U /* I2C communication is in Memory Mode. */
|
|
+ I2C_MODE_NONE = 0x00U, /* No active communication */
|
|
+ I2C_MODE_MASTER = 0x10U, /* Communication in Master Mode */
|
|
+ I2C_MODE_SLAVE = 0x20U, /* Communication in Slave Mode */
|
|
+ I2C_MODE_MEM = 0x40U /* Communication in Memory Mode */
|
|
|
|
};
|
|
|
|
@@ -212,52 +246,38 @@ enum i2c_mode_e {
|
|
|
|
struct i2c_handle_s {
|
|
uint32_t i2c_base_addr; /* Registers base address */
|
|
-
|
|
- struct stm32_i2c_init_s i2c_init; /* Communication parameters */
|
|
-
|
|
- uint8_t *p_buff; /* Pointer to transfer buffer */
|
|
-
|
|
- uint16_t xfer_size; /* Transfer size */
|
|
-
|
|
- uint16_t xfer_count; /* Transfer counter */
|
|
-
|
|
- uint32_t prev_state; /* Communication previous
|
|
- * state
|
|
- */
|
|
-
|
|
- uint8_t lock; /* Locking object */
|
|
-
|
|
- enum i2c_state_e i2c_state; /* Communication state */
|
|
-
|
|
- enum i2c_mode_e i2c_mode; /* Communication mode */
|
|
-
|
|
- uint32_t i2c_err; /* Error code */
|
|
+ unsigned int dt_status; /* DT nsec/sec status */
|
|
+ unsigned int clock; /* Clock reference */
|
|
+ uint8_t lock; /* Locking object */
|
|
+ enum i2c_state_e i2c_state; /* Communication state */
|
|
+ enum i2c_mode_e i2c_mode; /* Communication mode */
|
|
+ uint32_t i2c_err; /* Error code */
|
|
};
|
|
|
|
-#define I2C_ADDRESSINGMODE_7BIT 0x00000001U
|
|
-#define I2C_ADDRESSINGMODE_10BIT 0x00000002U
|
|
+#define I2C_ADDRESSINGMODE_7BIT 0x00000001U
|
|
+#define I2C_ADDRESSINGMODE_10BIT 0x00000002U
|
|
|
|
-#define I2C_DUALADDRESS_DISABLE 0x00000000U
|
|
-#define I2C_DUALADDRESS_ENABLE I2C_OAR2_OA2EN
|
|
+#define I2C_DUALADDRESS_DISABLE 0x00000000U
|
|
+#define I2C_DUALADDRESS_ENABLE I2C_OAR2_OA2EN
|
|
|
|
-#define I2C_GENERALCALL_DISABLE 0x00000000U
|
|
-#define I2C_GENERALCALL_ENABLE I2C_CR1_GCEN
|
|
+#define I2C_GENERALCALL_DISABLE 0x00000000U
|
|
+#define I2C_GENERALCALL_ENABLE I2C_CR1_GCEN
|
|
|
|
-#define I2C_NOSTRETCH_DISABLE 0x00000000U
|
|
-#define I2C_NOSTRETCH_ENABLE I2C_CR1_NOSTRETCH
|
|
+#define I2C_NOSTRETCH_DISABLE 0x00000000U
|
|
+#define I2C_NOSTRETCH_ENABLE I2C_CR1_NOSTRETCH
|
|
|
|
-#define I2C_MEMADD_SIZE_8BIT 0x00000001U
|
|
-#define I2C_MEMADD_SIZE_16BIT 0x00000002U
|
|
+#define I2C_MEMADD_SIZE_8BIT 0x00000001U
|
|
+#define I2C_MEMADD_SIZE_16BIT 0x00000002U
|
|
|
|
-#define I2C_RELOAD_MODE I2C_CR2_RELOAD
|
|
-#define I2C_AUTOEND_MODE I2C_CR2_AUTOEND
|
|
-#define I2C_SOFTEND_MODE 0x00000000U
|
|
+#define I2C_RELOAD_MODE I2C_CR2_RELOAD
|
|
+#define I2C_AUTOEND_MODE I2C_CR2_AUTOEND
|
|
+#define I2C_SOFTEND_MODE 0x00000000U
|
|
|
|
-#define I2C_NO_STARTSTOP 0x00000000U
|
|
-#define I2C_GENERATE_STOP (BIT(31) | I2C_CR2_STOP)
|
|
-#define I2C_GENERATE_START_READ (BIT(31) | I2C_CR2_START | \
|
|
- I2C_CR2_RD_WRN)
|
|
-#define I2C_GENERATE_START_WRITE (BIT(31) | I2C_CR2_START)
|
|
+#define I2C_NO_STARTSTOP 0x00000000U
|
|
+#define I2C_GENERATE_STOP (BIT(31) | I2C_CR2_STOP)
|
|
+#define I2C_GENERATE_START_READ (BIT(31) | I2C_CR2_START | \
|
|
+ I2C_CR2_RD_WRN)
|
|
+#define I2C_GENERATE_START_WRITE (BIT(31) | I2C_CR2_START)
|
|
|
|
#define I2C_FLAG_TXE I2C_ISR_TXE
|
|
#define I2C_FLAG_TXIS I2C_ISR_TXIS
|
|
@@ -280,21 +300,36 @@ struct i2c_handle_s {
|
|
I2C_CR2_NBYTES | I2C_CR2_RELOAD | \
|
|
I2C_CR2_RD_WRN)
|
|
|
|
-#define I2C_ANALOGFILTER_ENABLE ((uint32_t)0x00000000U)
|
|
-#define I2C_ANALOGFILTER_DISABLE I2C_CR1_ANFOFF
|
|
+#define I2C_TIMEOUT_BUSY_MS 25U
|
|
|
|
-int stm32_i2c_init(struct i2c_handle_s *hi2c);
|
|
+#define I2C_ANALOGFILTER_ENABLE 0x00000000U
|
|
+#define I2C_ANALOGFILTER_DISABLE I2C_CR1_ANFOFF
|
|
|
|
+/* STM32 specific defines */
|
|
+#define STM32_I2C_RISE_TIME_DEFAULT 25 /* ns */
|
|
+#define STM32_I2C_FALL_TIME_DEFAULT 10 /* ns */
|
|
+#define STM32_I2C_SPEED_DEFAULT I2C_SPEED_STANDARD
|
|
+#define STM32_I2C_ANALOG_FILTER_DELAY_MIN 50 /* ns */
|
|
+#define STM32_I2C_ANALOG_FILTER_DELAY_MAX 260 /* ns */
|
|
+#define STM32_I2C_DIGITAL_FILTER_MAX 16
|
|
+
|
|
+int stm32_i2c_get_setup_from_fdt(void *fdt, int node,
|
|
+ struct stm32_i2c_init_s *init);
|
|
+int stm32_i2c_init(struct i2c_handle_s *hi2c,
|
|
+ struct stm32_i2c_init_s *init_data);
|
|
int stm32_i2c_mem_write(struct i2c_handle_s *hi2c, uint16_t dev_addr,
|
|
uint16_t mem_addr, uint16_t mem_add_size,
|
|
- uint8_t *p_data, uint16_t size, uint32_t timeout);
|
|
+ uint8_t *p_data, uint16_t size, uint32_t timeout_ms);
|
|
int stm32_i2c_mem_read(struct i2c_handle_s *hi2c, uint16_t dev_addr,
|
|
uint16_t mem_addr, uint16_t mem_add_size,
|
|
- uint8_t *p_data, uint16_t size, uint32_t timeout);
|
|
-int stm32_i2c_is_device_ready(struct i2c_handle_s *hi2c, uint16_t dev_addr,
|
|
- uint32_t trials, uint32_t timeout);
|
|
-
|
|
-int stm32_i2c_config_analog_filter(struct i2c_handle_s *hi2c,
|
|
- uint32_t analog_filter);
|
|
-
|
|
-#endif /* __STM32MP1_I2C_H */
|
|
+ uint8_t *p_data, uint16_t size, uint32_t timeout_ms);
|
|
+int stm32_i2c_master_transmit(struct i2c_handle_s *hi2c, uint16_t dev_addr,
|
|
+ uint8_t *p_data, uint16_t size,
|
|
+ uint32_t timeout_ms);
|
|
+int stm32_i2c_master_receive(struct i2c_handle_s *hi2c, uint16_t dev_addr,
|
|
+ uint8_t *p_data, uint16_t size,
|
|
+ uint32_t timeout_ms);
|
|
+bool stm32_i2c_is_device_ready(struct i2c_handle_s *hi2c, uint16_t dev_addr,
|
|
+ uint32_t trials, uint32_t timeout_ms);
|
|
+
|
|
+#endif /* STM32_I2C_H */
|
|
diff --git a/include/drivers/st/stm32_iwdg.h b/include/drivers/st/stm32_iwdg.h
|
|
new file mode 100644
|
|
index 0000000..b6d4769
|
|
--- /dev/null
|
|
+++ b/include/drivers/st/stm32_iwdg.h
|
|
@@ -0,0 +1,20 @@
|
|
+/*
|
|
+ * Copyright (c) 2018, STMicroelectronics - All Rights Reserved
|
|
+ *
|
|
+ * SPDX-License-Identifier: BSD-3-Clause
|
|
+ */
|
|
+
|
|
+#ifndef __STM32_IWDG_H__
|
|
+#define __STM32_IWDG_H__
|
|
+
|
|
+#include <stdint.h>
|
|
+
|
|
+#define IWDG_HW_ENABLED BIT(0)
|
|
+#define IWDG_ENABLE_ON_STOP BIT(1)
|
|
+#define IWDG_ENABLE_ON_STANDBY BIT(2)
|
|
+
|
|
+int stm32_iwdg_init(void);
|
|
+void stm32_iwdg_refresh(uint32_t instance);
|
|
+void __dead2 stm32_iwdg_it_handler(int id);
|
|
+
|
|
+#endif /* __STM32_IWDG_H__ */
|
|
diff --git a/include/drivers/st/stm32_rng.h b/include/drivers/st/stm32_rng.h
|
|
new file mode 100644
|
|
index 0000000..a644118
|
|
--- /dev/null
|
|
+++ b/include/drivers/st/stm32_rng.h
|
|
@@ -0,0 +1,13 @@
|
|
+/*
|
|
+ * Copyright (c) 2018, STMicroelectronics - All Rights Reserved
|
|
+ *
|
|
+ * SPDX-License-Identifier: BSD-3-Clause
|
|
+ */
|
|
+
|
|
+#ifndef STM32_RNG_H
|
|
+#define STM32_RNG_H
|
|
+
|
|
+int stm32_rng_read(uint8_t *out, uint32_t size);
|
|
+int stm32_rng_init(void);
|
|
+
|
|
+#endif /* STM32_RNG_H */
|
|
diff --git a/include/drivers/st/stm32_rtc.h b/include/drivers/st/stm32_rtc.h
|
|
new file mode 100644
|
|
index 0000000..bc9e61e
|
|
--- /dev/null
|
|
+++ b/include/drivers/st/stm32_rtc.h
|
|
@@ -0,0 +1,79 @@
|
|
+/*
|
|
+ * Copyright (c) 2017-2018, STMicroelectronics - All Rights Reserved
|
|
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
|
|
+ *
|
|
+ * SPDX-License-Identifier: BSD-3-Clause
|
|
+ */
|
|
+
|
|
+#ifndef __PLAT_RTC_H__
|
|
+#define __PLAT_RTC_H__
|
|
+
|
|
+#include <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 /* __PLAT_RTC_H__ */
|
|
diff --git a/include/drivers/st/stm32_sdmmc2.h b/include/drivers/st/stm32_sdmmc2.h
|
|
new file mode 100644
|
|
index 0000000..b172659
|
|
--- /dev/null
|
|
+++ b/include/drivers/st/stm32_sdmmc2.h
|
|
@@ -0,0 +1,31 @@
|
|
+/*
|
|
+ * Copyright (c) 2017-2018, STMicroelectronics - All Rights Reserved
|
|
+ *
|
|
+ * SPDX-License-Identifier: BSD-3-Clause
|
|
+ */
|
|
+
|
|
+#ifndef STM32_SDMMC2_H
|
|
+#define STM32_SDMMC2_H
|
|
+
|
|
+#include <mmc.h>
|
|
+#include <stdbool.h>
|
|
+
|
|
+struct stm32_sdmmc2_params {
|
|
+ uintptr_t reg_base;
|
|
+ unsigned int clk_rate;
|
|
+ unsigned int bus_width;
|
|
+ unsigned int flags;
|
|
+ struct mmc_device_info *device_info;
|
|
+ unsigned int pin_ckin;
|
|
+ unsigned int negedge;
|
|
+ unsigned int dirpol;
|
|
+ unsigned int clock_id;
|
|
+ unsigned int reset_id;
|
|
+ bool use_dma;
|
|
+};
|
|
+
|
|
+unsigned long long stm32_sdmmc2_mmc_get_device_size(void);
|
|
+int stm32_sdmmc2_mmc_init(struct stm32_sdmmc2_params *params);
|
|
+bool plat_sdmmc2_use_dma(unsigned int instance, unsigned int memory);
|
|
+
|
|
+#endif /* STM32_SDMMC2_H */
|
|
diff --git a/include/drivers/st/stm32_tamp.h b/include/drivers/st/stm32_tamp.h
|
|
new file mode 100644
|
|
index 0000000..3933c26
|
|
--- /dev/null
|
|
+++ b/include/drivers/st/stm32_tamp.h
|
|
@@ -0,0 +1,163 @@
|
|
+/*
|
|
+ * Copyright (c) 2014, ARM Limited and Contributors. All rights reserved.
|
|
+ *
|
|
+ * SPDX-License-Identifier: BSD-3-Clause
|
|
+ */
|
|
+
|
|
+#ifndef __TAMPER_H__
|
|
+#define __TAMPER_H__
|
|
+
|
|
+/* Internal Tamper */
|
|
+enum stm32_tamp_int_id {
|
|
+ ITAMP1 = 0,
|
|
+ ITAMP2,
|
|
+ ITAMP3,
|
|
+ ITAMP4,
|
|
+ ITAMP5,
|
|
+ ITAMP6,
|
|
+ ITAMP7,
|
|
+ ITAMP8,
|
|
+ ITAMP9,
|
|
+ ITAMP10,
|
|
+ ITAMP11,
|
|
+ ITAMP12,
|
|
+ ITAMP13,
|
|
+ ITAMP14,
|
|
+ ITAMP15,
|
|
+ ITAMP16
|
|
+};
|
|
+
|
|
+/* External Tamper */
|
|
+enum stm32_tamp_ext_id {
|
|
+ EXT_TAMP1 = 0,
|
|
+ EXT_TAMP2,
|
|
+ EXT_TAMP3,
|
|
+ EXT_TAMP4,
|
|
+ EXT_TAMP5,
|
|
+ EXT_TAMP6,
|
|
+ EXT_TAMP7,
|
|
+ EXT_TAMP8
|
|
+};
|
|
+
|
|
+enum stm32_tamp_state {
|
|
+ TAMP_DISABLE = 0,
|
|
+ TAMP_ENABLE
|
|
+};
|
|
+
|
|
+#define TAMP_UNUSED {.id = -1}
|
|
+
|
|
+/* define TAMPER modes */
|
|
+#define TAMP_TRIG_OFF 0x0U
|
|
+#define TAMP_TRIG_ON 0x1U
|
|
+#define TAMP_ACTIVE 0x2U
|
|
+#define TAMP_ERASE 0x0U
|
|
+#define TAMP_NOERASE 0x1U
|
|
+#define TAMP_NO_EVT_MASK 0x0U
|
|
+#define TAMP_EVT_MASK 0x1U
|
|
+
|
|
+/* define Passive FILTER mode */
|
|
+#define TAMP_FILTER_PRECHARGE 0x0U
|
|
+#define TAMP_FILTER_PULL_UP_DISABLE 0x1U
|
|
+#define TAMP_FILTER_DURATION_1_CYCLE 0x0U
|
|
+#define TAMP_FILTER_DURATION_2_CYCLES 0x1U
|
|
+#define TAMP_FILTER_DURATION_3_CYCLES 0x2U
|
|
+#define TAMP_FILTER_DURATION_4_CYCLES 0x3U
|
|
+#define TAMP_FILTER_COUNT_1 0x0U
|
|
+#define TAMP_FILTER_COUNT_2 0x1U
|
|
+#define TAMP_FILTER_COUNT_4 0x2U
|
|
+#define TAMP_FILTER_COUNT_8 0x3U
|
|
+#define TAMP_FILTER_SAMPLING_32768 0x0U
|
|
+#define TAMP_FILTER_SAMPLING_16384 0x1U
|
|
+#define TAMP_FILTER_SAMPLING_8192 0x2U
|
|
+#define TAMP_FILTER_SAMPLING_4096 0x3U
|
|
+#define TAMP_FILTER_SAMPLING_2048 0x4U
|
|
+#define TAMP_FILTER_SAMPLING_1024 0x5U
|
|
+#define TAMP_FILTER_SAMPLING_512 0x6U
|
|
+#define TAMP_FILTER_SAMPLING_256 0x7U
|
|
+
|
|
+/* define active filter */
|
|
+#define TAMP_ACTIVE_FILTER_OFF 0x0U
|
|
+#define TAMP_ACTIVE_FILTER_ON 0x1U
|
|
+#define TAMP_ACTIVE_ATO_DEDICTED 0x0U
|
|
+#define TAMP_ACTIVE_ATO_TAMPOUTSEL 0x1U
|
|
+#define TAMP_ACTIVE_APER_1_OUTPUT 0x0U
|
|
+#define TAMP_ACTIVE_APER_2_OUTPUTS 0x1U
|
|
+#define TAMP_ACTIVE_APER_3_4_OUTPUTS 0x2U
|
|
+#define TAMP_ACTIVE_APER_5_OUTPUTS 0x3U
|
|
+#define TAMP_ACTIVE_CKSEL_DIV_0 0x0U
|
|
+#define TAMP_ACTIVE_CKSEL_DIV_2 0x1U
|
|
+#define TAMP_ACTIVE_CKSEL_DIV_4 0x2U
|
|
+#define TAMP_ACTIVE_CKSEL_DIV_8 0x3U
|
|
+#define TAMP_ACTIVE_CKSEL_DIV_16 0x4U
|
|
+#define TAMP_ACTIVE_CKSEL_DIV_32 0x5U
|
|
+#define TAMP_ACTIVE_CKSEL_DIV_64 0x6U
|
|
+#define TAMP_ACTIVE_CKSEL_DIV_128 0x7U
|
|
+#define TAMP_ACTIVE_ATOSEL_OUT1_(X) (0x0U << (X * 2))
|
|
+#define TAMP_ACTIVE_ATOSEL_OUT2_(X) (0x1U << (X * 2))
|
|
+#define TAMP_ACTIVE_ATOSEL_OUT3_(X) (0x2U << (X * 2))
|
|
+#define TAMP_ACTIVE_ATOSEL_OUT4_(X) (0x3U << (X * 2))
|
|
+
|
|
+#define TAMP_EXT(tamp_id, trig, erase, mask) (((tamp_id) << 3) | ((trig) << 2)\
|
|
+ | ((erase) << 1) | (mask))
|
|
+
|
|
+#define TAMP_FLTCR(precharge, duration, count, sample) (((precharge) << 7) |\
|
|
+ ((duration) << 5) |\
|
|
+ ((count) << 3) |\
|
|
+ (sample))
|
|
+
|
|
+#define TAMP_ACT(filter, ato, aper, atcksel, atosel) (((filter) << 31) |\
|
|
+ ((ato) << 30) |\
|
|
+ ((aper) << 24) |\
|
|
+ ((atcksel) << 16) |\
|
|
+ (atosel) << 8)
|
|
+
|
|
+struct stm32_tamp_int {
|
|
+ int id;
|
|
+ void (*it_handler)(void);
|
|
+};
|
|
+
|
|
+struct stm32_tamp_ext {
|
|
+ int id;
|
|
+ uint8_t mode;
|
|
+ uint8_t erase;
|
|
+ uint8_t evt_mask;
|
|
+ void (*it_handler)(void);
|
|
+};
|
|
+
|
|
+/*
|
|
+ * stm32_tamp_write_mcounter : Increase monotonic counter
|
|
+ */
|
|
+void stm32_tamp_write_mcounter(void);
|
|
+
|
|
+/*
|
|
+ * stm32_tamp_it_handler : Interrupt handler
|
|
+ */
|
|
+void stm32_tamp_it_handler(void);
|
|
+
|
|
+/*
|
|
+ * stm32_tamp_configure_internal: Configure internal tamper
|
|
+ * tamper_list: List of tamper to enable
|
|
+ * nb_tamper: Number of tamper in list
|
|
+ */
|
|
+void stm32_tamp_configure_internal(struct stm32_tamp_int *tamper_list,
|
|
+ uint16_t nb_tamper);
|
|
+
|
|
+/*
|
|
+ * stm32_tamp_configure_external: Configure external tamper and associated
|
|
+ * configuration for filtering
|
|
+ * ext_tamp_list: List of external tamper to configure
|
|
+ * nb_tamper: Number of tamper in list
|
|
+ * passive_conf: Filter configuration
|
|
+ * active_conf: Configuration for active tamper
|
|
+ */
|
|
+void stm32_tamp_configure_external(struct stm32_tamp_ext *ext_tamper_list,
|
|
+ uint8_t nb_tamper, uint32_t passive_conf,
|
|
+ uint32_t active_conf);
|
|
+
|
|
+/*
|
|
+ * stm32_tamp_init: Initialize tamper from DT
|
|
+ * return 0 if disabled, 1 if enabled, else < 0
|
|
+ */
|
|
+int stm32_tamp_init(void);
|
|
+
|
|
+#endif /* __TAMPER__ */
|
|
diff --git a/include/drivers/st/stm32_timer.h b/include/drivers/st/stm32_timer.h
|
|
new file mode 100644
|
|
index 0000000..e62f3df
|
|
--- /dev/null
|
|
+++ b/include/drivers/st/stm32_timer.h
|
|
@@ -0,0 +1,21 @@
|
|
+/*
|
|
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
|
|
+ *
|
|
+ * SPDX-License-Identifier: BSD-3-Clause
|
|
+ */
|
|
+
|
|
+#ifndef STM32_TIMER_H
|
|
+#define STM32_TIMER_H
|
|
+
|
|
+enum timer_cal {
|
|
+ HSI_CAL = 0,
|
|
+ CSI_CAL
|
|
+};
|
|
+
|
|
+unsigned long stm32_timer_hsi_freq(void);
|
|
+unsigned long stm32_timer_csi_freq(void);
|
|
+void stm32_timer_freq_func(unsigned long (**timer_freq_cb)(void),
|
|
+ enum timer_cal type);
|
|
+int stm32_timer_init(void);
|
|
+
|
|
+#endif /* STM32_TIMER_H */
|
|
diff --git a/include/drivers/st/stm32_uart_regs.h b/include/drivers/st/stm32_uart_regs.h
|
|
new file mode 100644
|
|
index 0000000..e78d3d4
|
|
--- /dev/null
|
|
+++ b/include/drivers/st/stm32_uart_regs.h
|
|
@@ -0,0 +1,199 @@
|
|
+/*
|
|
+ * Copyright (C) 2018, STMicroelectronics - All Rights Reserved
|
|
+ *
|
|
+ * SPDX-License-Identifier: BSD-3-Clause
|
|
+ */
|
|
+
|
|
+#ifndef STM32_UART_REGS_H
|
|
+#define STM32_UART_REGS_H
|
|
+
|
|
+#include <utils_def.h>
|
|
+
|
|
+#define USART_CR1 U(0x00)
|
|
+#define USART_CR2 U(0x04)
|
|
+#define USART_CR3 U(0x08)
|
|
+#define USART_BRR U(0x0C)
|
|
+#define USART_GTPR U(0x10)
|
|
+#define USART_RTOR U(0x14)
|
|
+#define USART_RQR U(0x18)
|
|
+#define USART_ISR U(0x1C)
|
|
+#define USART_ICR U(0x20)
|
|
+#define USART_RDR U(0x24)
|
|
+#define USART_TDR U(0x28)
|
|
+#define USART_PRESC U(0x2C)
|
|
+
|
|
+/* USART_CR1 register fields */
|
|
+#define USART_CR1_UE BIT(0)
|
|
+#define USART_CR1_UESM BIT(1)
|
|
+#define USART_CR1_RE BIT(2)
|
|
+#define USART_CR1_TE BIT(3)
|
|
+#define USART_CR1_IDLEIE BIT(4)
|
|
+#define USART_CR1_RXNEIE BIT(5)
|
|
+#define USART_CR1_TCIE BIT(6)
|
|
+#define USART_CR1_TXEIE BIT(7)
|
|
+#define USART_CR1_PEIE BIT(8)
|
|
+#define USART_CR1_PS BIT(9)
|
|
+#define USART_CR1_PCE BIT(10)
|
|
+#define USART_CR1_WAKE BIT(11)
|
|
+#define USART_CR1_M (BIT(28) | BIT(12))
|
|
+#define USART_CR1_M0 BIT(12)
|
|
+#define USART_CR1_MME BIT(13)
|
|
+#define USART_CR1_CMIE BIT(14)
|
|
+#define USART_CR1_OVER8 BIT(15)
|
|
+#define USART_CR1_DEDT GENMASK(20, 16)
|
|
+#define USART_CR1_DEDT_0 BIT(16)
|
|
+#define USART_CR1_DEDT_1 BIT(17)
|
|
+#define USART_CR1_DEDT_2 BIT(18)
|
|
+#define USART_CR1_DEDT_3 BIT(19)
|
|
+#define USART_CR1_DEDT_4 BIT(20)
|
|
+#define USART_CR1_DEAT GENMASK(25, 21)
|
|
+#define USART_CR1_DEAT_0 BIT(21)
|
|
+#define USART_CR1_DEAT_1 BIT(22)
|
|
+#define USART_CR1_DEAT_2 BIT(23)
|
|
+#define USART_CR1_DEAT_3 BIT(24)
|
|
+#define USART_CR1_DEAT_4 BIT(25)
|
|
+#define USART_CR1_RTOIE BIT(26)
|
|
+#define USART_CR1_EOBIE BIT(27)
|
|
+#define USART_CR1_M1 BIT(28)
|
|
+#define USART_CR1_FIFOEN BIT(29)
|
|
+#define USART_CR1_TXFEIE BIT(30)
|
|
+#define USART_CR1_RXFFIE BIT(31)
|
|
+
|
|
+/* USART_CR2 register fields */
|
|
+#define USART_CR2_SLVEN BIT(0)
|
|
+#define USART_CR2_DIS_NSS BIT(3)
|
|
+#define USART_CR2_ADDM7 BIT(4)
|
|
+#define USART_CR2_LBDL BIT(5)
|
|
+#define USART_CR2_LBDIE BIT(6)
|
|
+#define USART_CR2_LBCL BIT(8)
|
|
+#define USART_CR2_CPHA BIT(9)
|
|
+#define USART_CR2_CPOL BIT(10)
|
|
+#define USART_CR2_CLKEN BIT(11)
|
|
+#define USART_CR2_STOP GENMASK(13, 12)
|
|
+#define USART_CR2_STOP_0 BIT(12)
|
|
+#define USART_CR2_STOP_1 BIT(13)
|
|
+#define USART_CR2_LINEN BIT(14)
|
|
+#define USART_CR2_SWAP BIT(15)
|
|
+#define USART_CR2_RXINV BIT(16)
|
|
+#define USART_CR2_TXINV BIT(17)
|
|
+#define USART_CR2_DATAINV BIT(18)
|
|
+#define USART_CR2_MSBFIRST BIT(19)
|
|
+#define USART_CR2_ABREN BIT(20)
|
|
+#define USART_CR2_ABRMODE GENMASK(22, 21)
|
|
+#define USART_CR2_ABRMODE_0 BIT(21)
|
|
+#define USART_CR2_ABRMODE_1 BIT(22)
|
|
+#define USART_CR2_RTOEN BIT(23)
|
|
+#define USART_CR2_ADD GENMASK(31, 24)
|
|
+
|
|
+/* USART_CR3 register fields */
|
|
+#define USART_CR3_EIE BIT(0)
|
|
+#define USART_CR3_IREN BIT(1)
|
|
+#define USART_CR3_IRLP BIT(2)
|
|
+#define USART_CR3_HDSEL BIT(3)
|
|
+#define USART_CR3_NACK BIT(4)
|
|
+#define USART_CR3_SCEN BIT(5)
|
|
+#define USART_CR3_DMAR BIT(6)
|
|
+#define USART_CR3_DMAT BIT(7)
|
|
+#define USART_CR3_RTSE BIT(8)
|
|
+#define USART_CR3_CTSE BIT(9)
|
|
+#define USART_CR3_CTSIE BIT(10)
|
|
+#define USART_CR3_ONEBIT BIT(11)
|
|
+#define USART_CR3_OVRDIS BIT(12)
|
|
+#define USART_CR3_DDRE BIT(13)
|
|
+#define USART_CR3_DEM BIT(14)
|
|
+#define USART_CR3_DEP BIT(15)
|
|
+#define USART_CR3_SCARCNT GENMASK(19, 17)
|
|
+#define USART_CR3_SCARCNT_0 BIT(17)
|
|
+#define USART_CR3_SCARCNT_1 BIT(18)
|
|
+#define USART_CR3_SCARCNT_2 BIT(19)
|
|
+#define USART_CR3_WUS GENMASK(21, 20)
|
|
+#define USART_CR3_WUS_0 BIT(20)
|
|
+#define USART_CR3_WUS_1 BIT(21)
|
|
+#define USART_CR3_WUFIE BIT(22)
|
|
+#define USART_CR3_TXFTIE BIT(23)
|
|
+#define USART_CR3_TCBGTIE BIT(24)
|
|
+#define USART_CR3_RXFTCFG GENMASK(27, 25)
|
|
+#define USART_CR3_RXFTCFG_0 BIT(25)
|
|
+#define USART_CR3_RXFTCFG_1 BIT(26)
|
|
+#define USART_CR3_RXFTCFG_2 BIT(27)
|
|
+#define USART_CR3_RXFTIE BIT(28)
|
|
+#define USART_CR3_TXFTCFG GENMASK(31, 29)
|
|
+#define USART_CR3_TXFTCFG_0 BIT(29)
|
|
+#define USART_CR3_TXFTCFG_1 BIT(30)
|
|
+#define USART_CR3_TXFTCFG_2 BIT(31)
|
|
+
|
|
+/* USART_BRR register fields */
|
|
+#define USART_BRR_DIV_FRACTION GENMASK(3, 0)
|
|
+#define USART_BRR_DIV_MANTISSA GENMASK(15, 4)
|
|
+
|
|
+/* USART_GTPR register fields */
|
|
+#define USART_GTPR_PSC GENMASK(7, 0)
|
|
+#define USART_GTPR_GT GENMASK(15, 8)
|
|
+
|
|
+/* USART_RTOR register fields */
|
|
+#define USART_RTOR_RTO GENMASK(23, 0)
|
|
+#define USART_RTOR_BLEN GENMASK(31, 24)
|
|
+
|
|
+/* USART_RQR register fields */
|
|
+#define USART_RQR_ABRRQ BIT(0)
|
|
+#define USART_RQR_SBKRQ BIT(1)
|
|
+#define USART_RQR_MMRQ BIT(2)
|
|
+#define USART_RQR_RXFRQ BIT(3)
|
|
+#define USART_RQR_TXFRQ BIT(4)
|
|
+
|
|
+/* USART_ISR register fields */
|
|
+#define USART_ISR_PE BIT(0)
|
|
+#define USART_ISR_FE BIT(1)
|
|
+#define USART_ISR_NE BIT(2)
|
|
+#define USART_ISR_ORE BIT(3)
|
|
+#define USART_ISR_IDLE BIT(4)
|
|
+#define USART_ISR_RXNE BIT(5)
|
|
+#define USART_ISR_TC BIT(6)
|
|
+#define USART_ISR_TXE BIT(7)
|
|
+#define USART_ISR_LBDF BIT(8)
|
|
+#define USART_ISR_CTSIF BIT(9)
|
|
+#define USART_ISR_CTS BIT(10)
|
|
+#define USART_ISR_RTOF BIT(11)
|
|
+#define USART_ISR_EOBF BIT(12)
|
|
+#define USART_ISR_UDR BIT(13)
|
|
+#define USART_ISR_ABRE BIT(14)
|
|
+#define USART_ISR_ABRF BIT(15)
|
|
+#define USART_ISR_BUSY BIT(16)
|
|
+#define USART_ISR_CMF BIT(17)
|
|
+#define USART_ISR_SBKF BIT(18)
|
|
+#define USART_ISR_RWU BIT(19)
|
|
+#define USART_ISR_WUF BIT(20)
|
|
+#define USART_ISR_TEACK BIT(21)
|
|
+#define USART_ISR_REACK BIT(22)
|
|
+#define USART_ISR_TXFE BIT(23)
|
|
+#define USART_ISR_RXFF BIT(24)
|
|
+#define USART_ISR_TCBGT BIT(25)
|
|
+#define USART_ISR_RXFT BIT(26)
|
|
+#define USART_ISR_TXFT BIT(27)
|
|
+
|
|
+/* USART_ICR register fields */
|
|
+#define USART_ICR_PECF BIT(0)
|
|
+#define USART_ICR_FECF BIT(1)
|
|
+#define USART_ICR_NCF BIT(2)
|
|
+#define USART_ICR_ORECF BIT(3)
|
|
+#define USART_ICR_IDLECF BIT(4)
|
|
+#define USART_ICR_TCCF BIT(6)
|
|
+#define USART_ICR_TCBGT BIT(7)
|
|
+#define USART_ICR_LBDCF BIT(8)
|
|
+#define USART_ICR_CTSCF BIT(9)
|
|
+#define USART_ICR_RTOCF BIT(11)
|
|
+#define USART_ICR_EOBCF BIT(12)
|
|
+#define USART_ICR_UDRCF BIT(13)
|
|
+#define USART_ICR_CMCF BIT(17)
|
|
+#define USART_ICR_WUCF BIT(20)
|
|
+
|
|
+/* USART_RDR register fields */
|
|
+#define USART_RDR_RDR GENMASK(8, 0)
|
|
+
|
|
+/* USART_TDR register fields */
|
|
+#define USART_TDR_TDR GENMASK(8, 0)
|
|
+
|
|
+/* USART_PRESC register fields */
|
|
+#define USART_PRESC_PRESCALER GENMASK(3, 0)
|
|
+
|
|
+#endif /* STM32_UART_REGS_H */
|
|
diff --git a/include/drivers/st/stm32mp1_clk.h b/include/drivers/st/stm32mp1_clk.h
|
|
index 85a1eb8..0c8583a 100644
|
|
--- a/include/drivers/st/stm32mp1_clk.h
|
|
+++ b/include/drivers/st/stm32mp1_clk.h
|
|
@@ -4,27 +4,72 @@
|
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
*/
|
|
|
|
-#ifndef __STM32MP1_CLK_H__
|
|
-#define __STM32MP1_CLK_H__
|
|
+#ifndef STM32MP1_CLK_H
|
|
+#define STM32MP1_CLK_H
|
|
|
|
-#include <arch_helpers.h>
|
|
#include <stdbool.h>
|
|
+#include <stdint.h>
|
|
+
|
|
+#include <dt-bindings/clock/stm32mp1-clks.h>
|
|
|
|
int stm32mp1_clk_probe(void);
|
|
int stm32mp1_clk_init(void);
|
|
+
|
|
+bool stm32mp1_rcc_is_secure(void);
|
|
+bool stm32mp1_rcc_is_mckprot(void);
|
|
+
|
|
+void __stm32mp1_clk_enable(unsigned long id, bool caller_is_secure);
|
|
+void __stm32mp1_clk_disable(unsigned long id, bool caller_is_secure);
|
|
bool stm32mp1_clk_is_enabled(unsigned long id);
|
|
-int stm32mp1_clk_enable(unsigned long id);
|
|
-int stm32mp1_clk_disable(unsigned long id);
|
|
-unsigned long stm32mp1_clk_get_rate(unsigned long id);
|
|
-void stm32mp1_stgen_increment(unsigned long long offset_in_ms);
|
|
|
|
-static inline uint32_t get_timer(uint32_t base)
|
|
+static inline void stm32mp1_clk_enable_non_secure(unsigned long id)
|
|
+{
|
|
+ __stm32mp1_clk_enable(id, false);
|
|
+}
|
|
+
|
|
+static inline void stm32mp1_clk_enable_secure(unsigned long id)
|
|
+{
|
|
+ __stm32mp1_clk_enable(id, true);
|
|
+}
|
|
+
|
|
+static inline void stm32mp1_clk_disable_non_secure(unsigned long id)
|
|
{
|
|
- if (base == 0U) {
|
|
- return (uint32_t)(~read_cntpct_el0());
|
|
- }
|
|
+ __stm32mp1_clk_disable(id, false);
|
|
+}
|
|
|
|
- return base - (uint32_t)(~read_cntpct_el0());
|
|
+static inline void stm32mp1_clk_disable_secure(unsigned long id)
|
|
+{
|
|
+ __stm32mp1_clk_disable(id, true);
|
|
}
|
|
|
|
-#endif /* __STM32MP1_CLK_H__ */
|
|
+unsigned int stm32mp1_clk_get_refcount(unsigned long id);
|
|
+
|
|
+unsigned long stm32mp_clk_get_rate(unsigned long id);
|
|
+unsigned long stm32mp_clk_timer_get_rate(unsigned long id);
|
|
+
|
|
+void stm32mp1_stgen_increment(unsigned long long offset_in_ms);
|
|
+
|
|
+bool stm32mp1_rtc_get_read_twice(void);
|
|
+
|
|
+/* SMP protection on RCC registers access */
|
|
+void stm32mp1_clk_rcc_regs_lock(void);
|
|
+void stm32mp1_clk_rcc_regs_unlock(void);
|
|
+
|
|
+unsigned long stm32mp1_clk_rcc2id(unsigned int offset, unsigned int bit);
|
|
+
|
|
+#if defined(IMAGE_BL32)
|
|
+bool stm32mp1_rcc_get_wakeup(void);
|
|
+void stm32mp1_rcc_set_wakeup(bool state);
|
|
+void stm32mp1_rcc_it_handler(uint32_t id);
|
|
+int stm32mp1_rcc_start_hsi_cal(void);
|
|
+int stm32mp1_rcc_start_csi_cal(void);
|
|
+void stm32mp1_cal_init(void);
|
|
+#endif
|
|
+
|
|
+void stm32mp1_rcc_init_late(void);
|
|
+
|
|
+void stm32mp1_register_clock_parents_secure(unsigned long id);
|
|
+
|
|
+void stm32mp1_update_earlyboot_clocks_state(void);
|
|
+
|
|
+#endif /* STM32MP1_CLK_H */
|
|
diff --git a/include/drivers/st/stm32mp1_clkfunc.h b/include/drivers/st/stm32mp1_clkfunc.h
|
|
index 635a9cd..b488478 100644
|
|
--- a/include/drivers/st/stm32mp1_clkfunc.h
|
|
+++ b/include/drivers/st/stm32mp1_clkfunc.h
|
|
@@ -4,9 +4,10 @@
|
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
*/
|
|
|
|
-#ifndef __STM32MP1_CLKFUNC_H__
|
|
-#define __STM32MP1_CLKFUNC_H__
|
|
+#ifndef STM32MP1_CLKFUNC_H
|
|
+#define STM32MP1_CLKFUNC_H
|
|
|
|
+#include <libfdt.h>
|
|
#include <stdbool.h>
|
|
|
|
enum stm32mp_osc_id {
|
|
@@ -16,7 +17,6 @@ enum stm32mp_osc_id {
|
|
_LSI,
|
|
_LSE,
|
|
_I2S_CKIN,
|
|
- _USB_PHY_48,
|
|
NB_OSC,
|
|
_UNKNOWN_OSC_ID = 0xFF
|
|
};
|
|
@@ -29,14 +29,6 @@ uint32_t fdt_osc_read_uint32_default(enum stm32mp_osc_id osc_id,
|
|
const char *prop_name,
|
|
uint32_t dflt_value);
|
|
|
|
-uint32_t fdt_rcc_read_addr(void);
|
|
-int fdt_rcc_read_uint32_array(const char *prop_name,
|
|
- uint32_t *array, uint32_t count);
|
|
-int fdt_rcc_subnode_offset(const char *name);
|
|
-const uint32_t *fdt_rcc_read_prop(const char *prop_name, int *lenp);
|
|
-bool fdt_get_rcc_secure_status(void);
|
|
+int fdt_rcc_enable_it(const char *name);
|
|
|
|
-uintptr_t fdt_get_stgen_base(void);
|
|
-int fdt_get_clock_id(int node);
|
|
-
|
|
-#endif /* __STM32MP1_CLKFUNC_H__ */
|
|
+#endif /* STM32MP1_CLKFUNC_H */
|
|
diff --git a/include/drivers/st/stm32mp1_ddr.h b/include/drivers/st/stm32mp1_ddr.h
|
|
index 0765664..b2773b0 100644
|
|
--- a/include/drivers/st/stm32mp1_ddr.h
|
|
+++ b/include/drivers/st/stm32mp1_ddr.h
|
|
@@ -4,8 +4,8 @@
|
|
* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
|
|
*/
|
|
|
|
-#ifndef _STM32MP1_DDR_H
|
|
-#define _STM32MP1_DDR_H
|
|
+#ifndef STM32MP1_DDR_H
|
|
+#define STM32MP1_DDR_H
|
|
|
|
#include <stdbool.h>
|
|
|
|
@@ -152,7 +152,7 @@ struct stm32mp1_ddrphy_cal {
|
|
|
|
struct stm32mp1_ddr_info {
|
|
const char *name;
|
|
- uint16_t speed; /* in MHZ */
|
|
+ uint32_t speed; /* in kHZ */
|
|
uint32_t size; /* Memory size in byte = col * row * width */
|
|
};
|
|
|
|
@@ -165,9 +165,12 @@ struct stm32mp1_ddr_config {
|
|
struct stm32mp1_ddrphy_reg p_reg;
|
|
struct stm32mp1_ddrphy_timing p_timing;
|
|
struct stm32mp1_ddrphy_cal p_cal;
|
|
+ bool self_refresh;
|
|
+ uint32_t zdata;
|
|
};
|
|
|
|
-int stm32mp1_ddr_clk_enable(struct ddr_info *priv, uint16_t mem_speed);
|
|
+int stm32mp1_ddr_clk_enable(struct ddr_info *priv, uint32_t mem_speed);
|
|
void stm32mp1_ddr_init(struct ddr_info *priv,
|
|
struct stm32mp1_ddr_config *config);
|
|
-#endif /* _STM32MP1_DDR_H */
|
|
+
|
|
+#endif /* STM32MP1_DDR_H */
|
|
diff --git a/include/drivers/st/stm32mp1_ddr_helpers.h b/include/drivers/st/stm32mp1_ddr_helpers.h
|
|
index 298a080..ecc14d2 100644
|
|
--- a/include/drivers/st/stm32mp1_ddr_helpers.h
|
|
+++ b/include/drivers/st/stm32mp1_ddr_helpers.h
|
|
@@ -4,9 +4,17 @@
|
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
*/
|
|
|
|
-#ifndef __STM32MP1_DDR_HELPERS_H__
|
|
-#define __STM32MP1_DDR_HELPERS_H__
|
|
+#ifndef STM32MP1_DDR_HELPERS_H
|
|
+#define STM32MP1_DDR_HELPERS_H
|
|
+
|
|
+#include <stdbool.h>
|
|
|
|
void ddr_enable_clock(void);
|
|
+int ddr_sw_self_refresh_exit(void);
|
|
+int ddr_standby_sr_entry(uint32_t *zq0cr0_zdata);
|
|
+void ddr_sr_mode_ssr(void);
|
|
+void ddr_sr_mode_asr(void);
|
|
+void ddr_sr_mode_hsr(void);
|
|
+bool ddr_is_nonsecured_area(uintptr_t address, uint32_t length);
|
|
|
|
-#endif /* __STM32MP1_DDR_HELPERS_H__ */
|
|
+#endif /* STM32MP1_DDR_HELPERS_H */
|
|
diff --git a/include/drivers/st/stm32mp1_ddr_regs.h b/include/drivers/st/stm32mp1_ddr_regs.h
|
|
index 64ad965..e928688 100644
|
|
--- a/include/drivers/st/stm32mp1_ddr_regs.h
|
|
+++ b/include/drivers/st/stm32mp1_ddr_regs.h
|
|
@@ -4,9 +4,10 @@
|
|
* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
|
|
*/
|
|
|
|
-#ifndef _RAM_STM32MP1_DDR_REGS_H
|
|
-#define _RAM_STM32MP1_DDR_REGS_H
|
|
+#ifndef STM32MP1_DDR_REGS_H
|
|
+#define STM32MP1_DDR_REGS_H
|
|
|
|
+#include <stdio.h>
|
|
#include <utils_def.h>
|
|
|
|
/* DDR3/LPDDR2/LPDDR3 Controller (DDRCTRL) registers */
|
|
@@ -247,11 +248,14 @@ struct stm32mp1_ddrphy {
|
|
#define DDRCTRL_DBGSTAT 0x310
|
|
#define DDRCTRL_SWCTL 0x320
|
|
#define DDRCTRL_SWSTAT 0x324
|
|
+#define DDRCTRL_PSTAT 0x3FC
|
|
#define DDRCTRL_PCTRL_0 0x490
|
|
#define DDRCTRL_PCTRL_1 0x540
|
|
|
|
/* DDR Controller Register fields */
|
|
#define DDRCTRL_MSTR_DDR3 BIT(0)
|
|
+#define DDRCTRL_MSTR_LPDDR2 BIT(2)
|
|
+#define DDRCTRL_MSTR_LPDDR3 BIT(3)
|
|
#define DDRCTRL_MSTR_DATA_BUS_WIDTH_MASK GENMASK(13, 12)
|
|
#define DDRCTRL_MSTR_DATA_BUS_WIDTH_FULL 0
|
|
#define DDRCTRL_MSTR_DATA_BUS_WIDTH_HALF BIT(12)
|
|
@@ -269,7 +273,7 @@ struct stm32mp1_ddrphy {
|
|
/* Only one rank supported */
|
|
#define DDRCTRL_MRCTRL0_MR_RANK_SHIFT 4
|
|
#define DDRCTRL_MRCTRL0_MR_RANK_ALL \
|
|
- (0x1U << DDRCTRL_MRCTRL0_MR_RANK_SHIFT)
|
|
+ BIT(DDRCTRL_MRCTRL0_MR_RANK_SHIFT)
|
|
#define DDRCTRL_MRCTRL0_MR_ADDR_SHIFT 12
|
|
#define DDRCTRL_MRCTRL0_MR_ADDR_MASK GENMASK(15, 12)
|
|
#define DDRCTRL_MRCTRL0_MR_WR BIT(31)
|
|
@@ -367,6 +371,7 @@ struct stm32mp1_ddrphy {
|
|
|
|
#define DDRPHYC_DLLGCR_BPS200 BIT(23)
|
|
|
|
+#define DDRPHYC_ACDLLCR_DLLSRST BIT(30)
|
|
#define DDRPHYC_ACDLLCR_DLLDIS BIT(31)
|
|
|
|
#define DDRPHYC_PTR0_TDLLSRST_OFFSET 0
|
|
@@ -408,6 +413,4 @@ struct stm32mp1_ddrphy {
|
|
#define DDRPHYC_DXNDLLCR_SDPHASE_MASK GENMASK(17, 14)
|
|
#define DDRPHYC_DXNDLLCR_SDPHASE_SHIFT 14
|
|
|
|
-void ddr_enable_clock(void);
|
|
-
|
|
-#endif /* _RAM_STM32MP1_DDR_REGS_H */
|
|
+#endif /* STM32MP1_DDR_REGS_H */
|
|
diff --git a/include/drivers/st/stm32mp1_pmic.h b/include/drivers/st/stm32mp1_pmic.h
|
|
deleted file mode 100644
|
|
index 5d94b40..0000000
|
|
--- a/include/drivers/st/stm32mp1_pmic.h
|
|
+++ /dev/null
|
|
@@ -1,18 +0,0 @@
|
|
-/*
|
|
- * Copyright (c) 2017-2018, STMicroelectronics - All Rights Reserved
|
|
- *
|
|
- * SPDX-License-Identifier: BSD-3-Clause
|
|
- */
|
|
-
|
|
-#ifndef __STM32MP1_PMIC_H__
|
|
-#define __STM32MP1_PMIC_H__
|
|
-
|
|
-#include <stdbool.h>
|
|
-
|
|
-bool dt_check_pmic(void);
|
|
-int dt_pmic_enable_boot_on_regulators(void);
|
|
-void initialize_pmic_i2c(void);
|
|
-void initialize_pmic(void);
|
|
-int pmic_ddr_power_init(enum ddr_type ddr_type);
|
|
-
|
|
-#endif /* __STM32MP1_PMIC_H__ */
|
|
diff --git a/include/drivers/st/stm32mp1_pwr.h b/include/drivers/st/stm32mp1_pwr.h
|
|
index e567042..1a22824 100644
|
|
--- a/include/drivers/st/stm32mp1_pwr.h
|
|
+++ b/include/drivers/st/stm32mp1_pwr.h
|
|
@@ -1,11 +1,11 @@
|
|
/*
|
|
- * Copyright (c) 2017-2018, STMicroelectronics - All Rights Reserved
|
|
+ * Copyright (c) 2017-2019, STMicroelectronics - All Rights Reserved
|
|
*
|
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
*/
|
|
|
|
-#ifndef __STM32MP1_PWR_H__
|
|
-#define __STM32MP1_PWR_H__
|
|
+#ifndef STM32MP1_PWR_H
|
|
+#define STM32MP1_PWR_H
|
|
|
|
#include <utils_def.h>
|
|
|
|
@@ -13,20 +13,43 @@
|
|
#define PWR_CR2 U(0x08)
|
|
#define PWR_CR3 U(0x0C)
|
|
#define PWR_MPUCR U(0x10)
|
|
+#define PWR_MCUCR U(0x14)
|
|
#define PWR_WKUPCR U(0x20)
|
|
#define PWR_MPUWKUPENR U(0x28)
|
|
|
|
+#define PWR_OFFSET_MASK GENMASK(9, 0)
|
|
+
|
|
#define PWR_CR1_LPDS BIT(0)
|
|
#define PWR_CR1_LPCFG BIT(1)
|
|
#define PWR_CR1_LVDS BIT(2)
|
|
#define PWR_CR1_DBP BIT(8)
|
|
|
|
+#define PWR_CR2_BREN BIT(0)
|
|
+#define PWR_CR2_RREN BIT(1)
|
|
+
|
|
+#define PWR_CR3_VBE BIT(8)
|
|
+#define PWR_CR3_VBRS BIT(9)
|
|
#define PWR_CR3_DDRSREN BIT(10)
|
|
#define PWR_CR3_DDRSRDIS BIT(11)
|
|
#define PWR_CR3_DDRRETEN BIT(12)
|
|
+#define PWR_CR3_USB33DEN BIT(24)
|
|
+#define PWR_CR3_REG18EN BIT(28)
|
|
+#define PWR_CR3_REG11EN BIT(30)
|
|
|
|
#define PWR_MPUCR_PDDS BIT(0)
|
|
#define PWR_MPUCR_CSTDBYDIS BIT(3)
|
|
#define PWR_MPUCR_CSSF BIT(9)
|
|
|
|
-#endif /* __STM32MP1_PWR_H__ */
|
|
+#define PWR_MCUCR_PDDS BIT(0)
|
|
+
|
|
+#define PWR_WKUPCR_MASK GENMASK(27, 16) | GENMASK(13, 8) | GENMASK(5, 0)
|
|
+
|
|
+#define PWR_MPUWKUPENR_MASK GENMASK(5, 0)
|
|
+
|
|
+#ifndef __ASSEMBLY__
|
|
+/* SMP protection on PWR registers access */
|
|
+void pwr_regs_lock(void);
|
|
+void pwr_regs_unlock(void);
|
|
+#endif /* __ASSEMBLY__ */
|
|
+
|
|
+#endif /* STM32MP1_PWR_H */
|
|
diff --git a/include/drivers/st/stm32mp1_ram.h b/include/drivers/st/stm32mp1_ram.h
|
|
index af96177..38360e7 100644
|
|
--- a/include/drivers/st/stm32mp1_ram.h
|
|
+++ b/include/drivers/st/stm32mp1_ram.h
|
|
@@ -4,9 +4,9 @@
|
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
*/
|
|
|
|
-#ifndef _STM32MP1_RAM_H
|
|
-#define _STM32MP1_RAM_H
|
|
+#ifndef STM32MP1_RAM_H
|
|
+#define STM32MP1_RAM_H
|
|
|
|
int stm32mp1_ddr_probe(void);
|
|
|
|
-#endif /* _STM32MP1_RAM_H */
|
|
+#endif /* STM32MP1_RAM_H */
|
|
diff --git a/include/drivers/st/stm32mp1_rcc.h b/include/drivers/st/stm32mp1_rcc.h
|
|
index e28ca97..7e1b337 100644
|
|
--- a/include/drivers/st/stm32mp1_rcc.h
|
|
+++ b/include/drivers/st/stm32mp1_rcc.h
|
|
@@ -4,8 +4,8 @@
|
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
*/
|
|
|
|
-#ifndef __STM32MP1_RCC_H__
|
|
-#define __STM32MP1_RCC_H__
|
|
+#ifndef STM32MP1_RCC_H
|
|
+#define STM32MP1_RCC_H
|
|
|
|
#include <utils_def.h>
|
|
|
|
@@ -68,6 +68,14 @@
|
|
#define RCC_MP_AHB6ENCLRR U(0x21C)
|
|
#define RCC_MP_TZAHB6ENSETR U(0x220)
|
|
#define RCC_MP_TZAHB6ENCLRR U(0x224)
|
|
+#define RCC_MC_APB4ENSETR U(0x280)
|
|
+#define RCC_MC_APB4ENCLRR U(0x284)
|
|
+#define RCC_MC_APB5ENSETR U(0x288)
|
|
+#define RCC_MC_APB5ENCLRR U(0x28C)
|
|
+#define RCC_MC_AHB5ENSETR U(0x290)
|
|
+#define RCC_MC_AHB5ENCLRR U(0x294)
|
|
+#define RCC_MC_AHB6ENSETR U(0x298)
|
|
+#define RCC_MC_AHB6ENCLRR U(0x29C)
|
|
#define RCC_MP_APB4LPENSETR U(0x300)
|
|
#define RCC_MP_APB4LPENCLRR U(0x304)
|
|
#define RCC_MP_APB5LPENSETR U(0x308)
|
|
@@ -78,6 +86,14 @@
|
|
#define RCC_MP_AHB6LPENCLRR U(0x31C)
|
|
#define RCC_MP_TZAHB6LPENSETR U(0x320)
|
|
#define RCC_MP_TZAHB6LPENCLRR U(0x324)
|
|
+#define RCC_MC_APB4LPENSETR U(0x380)
|
|
+#define RCC_MC_APB4LPENCLRR U(0x384)
|
|
+#define RCC_MC_APB5LPENSETR U(0x388)
|
|
+#define RCC_MC_APB5LPENCLRR U(0x38C)
|
|
+#define RCC_MC_AHB5LPENSETR U(0x390)
|
|
+#define RCC_MC_AHB5LPENCLRR U(0x394)
|
|
+#define RCC_MC_AHB6LPENSETR U(0x398)
|
|
+#define RCC_MC_AHB6LPENCLRR U(0x39C)
|
|
#define RCC_BR_RSTSCLRR U(0x400)
|
|
#define RCC_MP_GRSTCSETR U(0x404)
|
|
#define RCC_MP_RSTSCLRR U(0x408)
|
|
@@ -95,6 +111,7 @@
|
|
#define RCC_RCK4SELR U(0x824)
|
|
#define RCC_TIMG1PRER U(0x828)
|
|
#define RCC_TIMG2PRER U(0x82C)
|
|
+#define RCC_MCUDIVR U(0x830)
|
|
#define RCC_APB1DIVR U(0x834)
|
|
#define RCC_APB2DIVR U(0x838)
|
|
#define RCC_APB3DIVR U(0x83C)
|
|
@@ -162,6 +179,22 @@
|
|
#define RCC_MP_AHB4ENCLRR U(0xA2C)
|
|
#define RCC_MP_MLAHBENSETR U(0xA38)
|
|
#define RCC_MP_MLAHBENCLRR U(0xA3C)
|
|
+#define RCC_MC_APB1ENSETR U(0xA80)
|
|
+#define RCC_MC_APB1ENCLRR U(0xA84)
|
|
+#define RCC_MC_APB2ENSETR U(0xA88)
|
|
+#define RCC_MC_APB2ENCLRR U(0xA8C)
|
|
+#define RCC_MC_APB3ENSETR U(0xA90)
|
|
+#define RCC_MC_APB3ENCLRR U(0xA94)
|
|
+#define RCC_MC_AHB2ENSETR U(0xA98)
|
|
+#define RCC_MC_AHB2ENCLRR U(0xA9C)
|
|
+#define RCC_MC_AHB3ENSETR U(0xAA0)
|
|
+#define RCC_MC_AHB3ENCLRR U(0xAA4)
|
|
+#define RCC_MC_AHB4ENSETR U(0xAA8)
|
|
+#define RCC_MC_AHB4ENCLRR U(0xAAC)
|
|
+#define RCC_MC_AXIMENSETR U(0xAB0)
|
|
+#define RCC_MC_AXIMENCLRR U(0xAB4)
|
|
+#define RCC_MC_MLAHBENSETR U(0xAB8)
|
|
+#define RCC_MC_MLAHBENCLRR U(0xABC)
|
|
#define RCC_MP_APB1LPENSETR U(0xB00)
|
|
#define RCC_MP_APB1LPENCLRR U(0xB04)
|
|
#define RCC_MP_APB2LPENSETR U(0xB08)
|
|
@@ -178,12 +211,34 @@
|
|
#define RCC_MP_AXIMLPENCLRR U(0xB34)
|
|
#define RCC_MP_MLAHBLPENSETR U(0xB38)
|
|
#define RCC_MP_MLAHBLPENCLRR U(0xB3C)
|
|
+#define RCC_MC_APB1LPENSETR U(0xB80)
|
|
+#define RCC_MC_APB1LPENCLRR U(0xB84)
|
|
+#define RCC_MC_APB2LPENSETR U(0xB88)
|
|
+#define RCC_MC_APB2LPENCLRR U(0xB8C)
|
|
+#define RCC_MC_APB3LPENSETR U(0xB90)
|
|
+#define RCC_MC_APB3LPENCLRR U(0xB94)
|
|
+#define RCC_MC_AHB2LPENSETR U(0xB98)
|
|
+#define RCC_MC_AHB2LPENCLRR U(0xB9C)
|
|
+#define RCC_MC_AHB3LPENSETR U(0xBA0)
|
|
+#define RCC_MC_AHB3LPENCLRR U(0xBA4)
|
|
+#define RCC_MC_AHB4LPENSETR U(0xBA8)
|
|
+#define RCC_MC_AHB4LPENCLRR U(0xBAC)
|
|
+#define RCC_MC_AXIMLPENSETR U(0xBB0)
|
|
+#define RCC_MC_AXIMLPENCLRR U(0xBB4)
|
|
+#define RCC_MC_MLAHBLPENSETR U(0xBB8)
|
|
+#define RCC_MC_MLAHBLPENCLRR U(0xBBC)
|
|
+#define RCC_MC_RSTSCLRR U(0xC00)
|
|
+#define RCC_MC_CIER U(0xC14)
|
|
+#define RCC_MC_CIFR U(0xC18)
|
|
#define RCC_VERR U(0xFF4)
|
|
#define RCC_IDR U(0xFF8)
|
|
#define RCC_SIDR U(0xFFC)
|
|
|
|
+#define RCC_OFFSET_MASK GENMASK(11, 0)
|
|
+
|
|
/* Values for RCC_TZCR register */
|
|
#define RCC_TZCR_TZEN BIT(0)
|
|
+#define RCC_TZCR_MCKPROT BIT(1)
|
|
|
|
/* Used for most of RCC_<x>SELR registers */
|
|
#define RCC_SELR_SRC_MASK GENMASK(2, 0)
|
|
@@ -220,6 +275,10 @@
|
|
#define RCC_APBXDIV_MASK GENMASK(2, 0)
|
|
#define RCC_MPUDIV_MASK GENMASK(2, 0)
|
|
#define RCC_AXIDIV_MASK GENMASK(2, 0)
|
|
+#define RCC_MCUDIV_MASK GENMASK(3, 0)
|
|
+
|
|
+/* Used for TIMER Prescaler */
|
|
+#define RCC_TIMGXPRER_TIMGXPRE BIT(0)
|
|
|
|
/* Offset between RCC_MP_xxxENSETR and RCC_MP_xxxENCLRR registers */
|
|
#define RCC_MP_ENCLRR_OFFSET U(4)
|
|
@@ -228,6 +287,7 @@
|
|
#define RCC_BDCR_LSEON BIT(0)
|
|
#define RCC_BDCR_LSEBYP BIT(1)
|
|
#define RCC_BDCR_LSERDY BIT(2)
|
|
+#define RCC_BDCR_DIGBYP BIT(3)
|
|
#define RCC_BDCR_LSEDRV_MASK GENMASK(5, 4)
|
|
#define RCC_BDCR_LSEDRV_SHIFT 4
|
|
#define RCC_BDCR_LSECSSON BIT(8)
|
|
@@ -243,6 +303,7 @@
|
|
/* Used for all RCC_PLL<n>CR registers */
|
|
#define RCC_PLLNCR_PLLON BIT(0)
|
|
#define RCC_PLLNCR_PLLRDY BIT(1)
|
|
+#define RCC_PLLNCR_SSCG_CTRL BIT(2)
|
|
#define RCC_PLLNCR_DIVPEN BIT(4)
|
|
#define RCC_PLLNCR_DIVQEN BIT(5)
|
|
#define RCC_PLLNCR_DIVREN BIT(6)
|
|
@@ -281,8 +342,12 @@
|
|
|
|
/* Used for RCC_OCENSETR and RCC_OCENCLRR registers */
|
|
#define RCC_OCENR_HSION BIT(0)
|
|
+#define RCC_OCENR_HSIKERON BIT(1)
|
|
#define RCC_OCENR_CSION BIT(4)
|
|
+#define RCC_OCENR_CSIKERON BIT(5)
|
|
+#define RCC_OCENR_DIGBYP BIT(7)
|
|
#define RCC_OCENR_HSEON BIT(8)
|
|
+#define RCC_OCENR_HSEKERON BIT(9)
|
|
#define RCC_OCENR_HSEBYP BIT(10)
|
|
#define RCC_OCENR_HSECSSON BIT(11)
|
|
|
|
@@ -319,6 +384,16 @@
|
|
|
|
/* Fields of RCC_HSICFGR register */
|
|
#define RCC_HSICFGR_HSIDIV_MASK GENMASK(1, 0)
|
|
+#define RCC_HSICFGR_HSITRIM_SHIFT 8
|
|
+#define RCC_HSICFGR_HSITRIM_MASK GENMASK(14, 8)
|
|
+#define RCC_HSICFGR_HSICAL_SHIFT 16
|
|
+#define RCC_HSICFGR_HSICAL_MASK GENMASK(27, 16)
|
|
+
|
|
+/* Fields of RCC_CSICFGR register */
|
|
+#define RCC_CSICFGR_CSITRIM_SHIFT 8
|
|
+#define RCC_CSICFGR_CSITRIM_MASK GENMASK(12, 8)
|
|
+#define RCC_CSICFGR_CSICAL_SHIFT 16
|
|
+#define RCC_CSICFGR_CSICAL_MASK GENMASK(23, 16)
|
|
|
|
/* Used for RCC_MCO related operations */
|
|
#define RCC_MCOCFG_MCOON BIT(12)
|
|
@@ -330,22 +405,37 @@
|
|
#define RCC_DBGCFGR_DBGCKEN BIT(8)
|
|
|
|
/* RCC register fields for reset reasons */
|
|
-#define RCC_MP_RSTSCLRR_PORRSTF BIT(0)
|
|
-#define RCC_MP_RSTSCLRR_BORRSTF BIT(1)
|
|
-#define RCC_MP_RSTSCLRR_PADRSTF BIT(2)
|
|
-#define RCC_MP_RSTSCLRR_HCSSRSTF BIT(3)
|
|
-#define RCC_MP_RSTSCLRR_VCORERSTF BIT(4)
|
|
-#define RCC_MP_RSTSCLRR_MPSYSRSTF BIT(6)
|
|
-#define RCC_MP_RSTSCLRR_IWDG1RSTF BIT(8)
|
|
-#define RCC_MP_RSTSCLRR_IWDG2RSTF BIT(9)
|
|
-#define RCC_MP_RSTSCLRR_STDBYRSTF BIT(11)
|
|
-#define RCC_MP_RSTSCLRR_CSTDBYRSTF BIT(12)
|
|
+#define RCC_MP_RSTSCLRR_PORRSTF BIT(0)
|
|
+#define RCC_MP_RSTSCLRR_BORRSTF BIT(1)
|
|
+#define RCC_MP_RSTSCLRR_PADRSTF BIT(2)
|
|
+#define RCC_MP_RSTSCLRR_HCSSRSTF BIT(3)
|
|
+#define RCC_MP_RSTSCLRR_VCORERSTF BIT(4)
|
|
+#define RCC_MP_RSTSCLRR_MPSYSRSTF BIT(6)
|
|
+#define RCC_MP_RSTSCLRR_MCSYSRSTF BIT(7)
|
|
+#define RCC_MP_RSTSCLRR_IWDG1RSTF BIT(8)
|
|
+#define RCC_MP_RSTSCLRR_IWDG2RSTF BIT(9)
|
|
+#define RCC_MP_RSTSCLRR_STDBYRSTF BIT(11)
|
|
+#define RCC_MP_RSTSCLRR_CSTDBYRSTF BIT(12)
|
|
+#define RCC_MP_RSTSCLRR_MPUP0RSTF BIT(13)
|
|
+#define RCC_MP_RSTSCLRR_MPUP1RSTF BIT(14)
|
|
|
|
/* Global Reset Register */
|
|
#define RCC_MP_GRSTCSETR_MPSYSRST BIT(0)
|
|
+#define RCC_MP_GRSTCSETR_MCURST BIT(1)
|
|
+#define RCC_MP_GRSTCSETR_MPUP0RST BIT(4)
|
|
+#define RCC_MP_GRSTCSETR_MPUP1RST BIT(5)
|
|
|
|
/* Clock Source Interrupt Flag Register */
|
|
#define RCC_MP_CIFR_MASK U(0x110F1F)
|
|
+#define RCC_MP_CIFR_LSIRDYF BIT(0)
|
|
+#define RCC_MP_CIFR_LSERDYF BIT(1)
|
|
+#define RCC_MP_CIFR_HSIRDYF BIT(2)
|
|
+#define RCC_MP_CIFR_HSERDYF BIT(3)
|
|
+#define RCC_MP_CIFR_CSIRDYF BIT(4)
|
|
+#define RCC_MP_CIFR_PLL1DYF BIT(8)
|
|
+#define RCC_MP_CIFR_PLL2DYF BIT(9)
|
|
+#define RCC_MP_CIFR_PLL3DYF BIT(10)
|
|
+#define RCC_MP_CIFR_PLL4DYF BIT(11)
|
|
#define RCC_MP_CIFR_WKUPF BIT(20)
|
|
|
|
/* Stop Request Set Register */
|
|
@@ -362,7 +452,29 @@
|
|
/* Values of RCC_MP_APB1ENSETR register */
|
|
#define RCC_MP_APB1ENSETR_UART4EN BIT(16)
|
|
|
|
+/* Values of RCC_MP_APB5ENSETR register */
|
|
+#define RCC_MP_APB5ENSETR_SPI6EN BIT(0)
|
|
+#define RCC_MP_APB5ENSETR_I2C4EN BIT(2)
|
|
+#define RCC_MP_APB5ENSETR_I2C6EN BIT(3)
|
|
+#define RCC_MP_APB5ENSETR_USART1EN BIT(4)
|
|
+#define RCC_MP_APB5ENSETR_RTCAPBEN BIT(8)
|
|
+#define RCC_MP_APB5ENSETR_IWDG1APBEN BIT(15)
|
|
+
|
|
/* Values of RCC_MP_AHB4ENSETR register */
|
|
#define RCC_MP_AHB4ENSETR_GPIOGEN BIT(6)
|
|
+#define RCC_MP_AHB4ENSETR_GPIOHEN BIT(7)
|
|
+
|
|
+/* Values of RCC_MP_AHB5ENSETR register */
|
|
+#define RCC_MP_AHB5ENSETR_GPIOZEN BIT(0)
|
|
+#define RCC_MP_AHB5ENSETR_CRYP1EN BIT(4)
|
|
+#define RCC_MP_AHB5ENSETR_HASH1EN BIT(5)
|
|
+#define RCC_MP_AHB5ENSETR_RNG1EN BIT(6)
|
|
+
|
|
+/* Values of RCC_MP_IWDGFZSETR register */
|
|
+#define RCC_MP_IWDGFZSETR_IWDG1 BIT(0)
|
|
+#define RCC_MP_IWDGFZSETR_IWDG2 BIT(1)
|
|
+
|
|
+/* Values of RCC_PWRLPDLYCR register */
|
|
+#define RCC_PWRLPDLYCR_PWRLP_DLY_MASK GENMASK(21, 0)
|
|
|
|
-#endif /* __STM32MP1_RCC_H__ */
|
|
+#endif /* STM32MP1_RCC_H */
|
|
diff --git a/include/drivers/st/stm32mp1_reset.h b/include/drivers/st/stm32mp1_reset.h
|
|
deleted file mode 100644
|
|
index 76ee09d..0000000
|
|
--- a/include/drivers/st/stm32mp1_reset.h
|
|
+++ /dev/null
|
|
@@ -1,15 +0,0 @@
|
|
-/*
|
|
- * Copyright (c) 2018, STMicroelectronics - All Rights Reserved
|
|
- *
|
|
- * SPDX-License-Identifier: BSD-3-Clause
|
|
- */
|
|
-
|
|
-#ifndef __STM32MP1_RESET_H__
|
|
-#define __STM32MP1_RESET_H__
|
|
-
|
|
-#include <stdint.h>
|
|
-
|
|
-void stm32mp1_reset_assert(uint32_t reset_id);
|
|
-void stm32mp1_reset_deassert(uint32_t reset_id);
|
|
-
|
|
-#endif /* __STM32MP1_RESET_H__ */
|
|
diff --git a/include/drivers/st/stm32mp1xx_hal.h b/include/drivers/st/stm32mp1xx_hal.h
|
|
new file mode 100644
|
|
index 0000000..5e4f9e7
|
|
--- /dev/null
|
|
+++ b/include/drivers/st/stm32mp1xx_hal.h
|
|
@@ -0,0 +1,203 @@
|
|
+/*
|
|
+ * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved.
|
|
+ *
|
|
+ * SPDX-License-Identifier: BSD-3-Clause
|
|
+ */
|
|
+
|
|
+#ifndef __STM32_HAL_H
|
|
+#define __STM32_HAL_H
|
|
+
|
|
+#include <arch_helpers.h>
|
|
+#include <mmio.h>
|
|
+#include <stdint.h>
|
|
+#include <stddef.h>
|
|
+#include <delay_timer.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 0000000..b6af232
|
|
--- /dev/null
|
|
+++ b/include/drivers/st/stm32mp1xx_hal_uart.h
|
|
@@ -0,0 +1,1586 @@
|
|
+/**
|
|
+ ******************************************************************************
|
|
+ * @file stm32mp1xx_hal_uart.h
|
|
+ * @author MCD Application Team
|
|
+ * @version V0.3.0
|
|
+ * @date 14-January-2015
|
|
+ * @brief Header file of UART HAL module.
|
|
+ ******************************************************************************
|
|
+ * @attention
|
|
+ *
|
|
+ * <h2><center>© 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 <stm32mp1xx_hal.h>
|
|
+#include <stm32_uart_regs.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 0000000..193f870
|
|
--- /dev/null
|
|
+++ b/include/drivers/st/stm32mp1xx_hal_uart_ex.h
|
|
@@ -0,0 +1,87 @@
|
|
+/**
|
|
+ ******************************************************************************
|
|
+ * @file stm32mp1xx_hal_uart_ex.h
|
|
+ * @author MCD Application Team
|
|
+ * @version $VERSION$
|
|
+ * @date $DATE$
|
|
+ * @brief Header file of UART HAL Extended module.
|
|
+ ******************************************************************************
|
|
+ * @attention
|
|
+ *
|
|
+ * <h2><center>© 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
|
|
new file mode 100644
|
|
index 0000000..c77c0b5
|
|
--- /dev/null
|
|
+++ b/include/drivers/st/stm32mp_clkfunc.h
|
|
@@ -0,0 +1,28 @@
|
|
+/*
|
|
+ * Copyright (c) 2017-2018, STMicroelectronics - All Rights Reserved
|
|
+ *
|
|
+ * SPDX-License-Identifier: BSD-3-Clause
|
|
+ */
|
|
+
|
|
+#ifndef STM32MP_CLKFUNC_H
|
|
+#define STM32MP_CLKFUNC_H
|
|
+
|
|
+#include <libfdt.h>
|
|
+#include <stdbool.h>
|
|
+
|
|
+int fdt_get_rcc_node(void *fdt);
|
|
+uint32_t fdt_rcc_read_addr(void);
|
|
+int fdt_rcc_read_uint32_array(const char *prop_name,
|
|
+ uint32_t *array, uint32_t count);
|
|
+uint32_t fdt_rcc_read_uint32_default(const char *prop_name,
|
|
+ uint32_t dflt_value);
|
|
+int fdt_rcc_subnode_offset(const char *name);
|
|
+const fdt32_t *fdt_rcc_read_prop(const char *prop_name, int *lenp);
|
|
+bool fdt_get_rcc_secure_status(void);
|
|
+
|
|
+uintptr_t fdt_get_stgen_base(void);
|
|
+int fdt_get_clock_id(int node);
|
|
+int fdt_get_clock_id_by_name(int node, const char *name);
|
|
+unsigned long fdt_get_uart_clock_freq(uintptr_t instance);
|
|
+
|
|
+#endif /* STM32MP_CLKFUNC_H */
|
|
diff --git a/include/drivers/st/stm32mp_pmic.h b/include/drivers/st/stm32mp_pmic.h
|
|
new file mode 100644
|
|
index 0000000..39c80e4
|
|
--- /dev/null
|
|
+++ b/include/drivers/st/stm32mp_pmic.h
|
|
@@ -0,0 +1,24 @@
|
|
+/*
|
|
+ * Copyright (c) 2017-2018, STMicroelectronics - All Rights Reserved
|
|
+ *
|
|
+ * SPDX-License-Identifier: BSD-3-Clause
|
|
+ */
|
|
+
|
|
+#ifndef STM32MP_PMIC_H
|
|
+#define STM32MP_PMIC_H
|
|
+
|
|
+#include <platform_def.h>
|
|
+#include <stdbool.h>
|
|
+#include <stdint.h>
|
|
+
|
|
+int dt_pmic_status(void);
|
|
+int dt_pmic_configure_boot_on_regulators(void);
|
|
+int dt_pmic_set_lp_config(const char *node_name);
|
|
+bool initialize_pmic_i2c(void);
|
|
+void initialize_pmic(void);
|
|
+#if STM32MP1_DEBUG_ENABLE
|
|
+int pmic_keep_debug_unit(void);
|
|
+#endif
|
|
+int pmic_ddr_power_init(enum ddr_type ddr_type);
|
|
+
|
|
+#endif /* STM32MP_PMIC_H */
|
|
diff --git a/include/drivers/st/stm32mp_reset.h b/include/drivers/st/stm32mp_reset.h
|
|
new file mode 100644
|
|
index 0000000..5bd159f
|
|
--- /dev/null
|
|
+++ b/include/drivers/st/stm32mp_reset.h
|
|
@@ -0,0 +1,15 @@
|
|
+/*
|
|
+ * Copyright (c) 2018, STMicroelectronics - All Rights Reserved
|
|
+ *
|
|
+ * SPDX-License-Identifier: BSD-3-Clause
|
|
+ */
|
|
+
|
|
+#ifndef STM32MP_RESET_H
|
|
+#define STM32MP_RESET_H
|
|
+
|
|
+#include <stdint.h>
|
|
+
|
|
+void stm32mp_reset_assert(uint32_t reset_id);
|
|
+void stm32mp_reset_deassert(uint32_t reset_id);
|
|
+
|
|
+#endif /* STM32MP_RESET_H */
|
|
diff --git a/include/drivers/st/stpmic1.h b/include/drivers/st/stpmic1.h
|
|
new file mode 100644
|
|
index 0000000..803a69e
|
|
--- /dev/null
|
|
+++ b/include/drivers/st/stpmic1.h
|
|
@@ -0,0 +1,173 @@
|
|
+/*
|
|
+ * Copyright (c) 2016-2018, STMicroelectronics - All Rights Reserved
|
|
+ *
|
|
+ * SPDX-License-Identifier: BSD-3-Clause
|
|
+ */
|
|
+
|
|
+#ifndef STPMIC1_H
|
|
+#define STPMIC1_H
|
|
+
|
|
+#include <stm32_i2c.h>
|
|
+#include <utils_def.h>
|
|
+
|
|
+#define TURN_ON_REG 0x1U
|
|
+#define TURN_OFF_REG 0x2U
|
|
+#define ICC_LDO_TURN_OFF_REG 0x3U
|
|
+#define ICC_BUCK_TURN_OFF_REG 0x4U
|
|
+#define RESET_STATUS_REG 0x5U
|
|
+#define VERSION_STATUS_REG 0x6U
|
|
+#define MAIN_CONTROL_REG 0x10U
|
|
+#define PADS_PULL_REG 0x11U
|
|
+#define BUCK_PULL_DOWN_REG 0x12U
|
|
+#define LDO14_PULL_DOWN_REG 0x13U
|
|
+#define LDO56_PULL_DOWN_REG 0x14U
|
|
+#define VIN_CONTROL_REG 0x15U
|
|
+#define PONKEY_TIMER_REG 0x16U
|
|
+#define MASK_RANK_BUCK_REG 0x17U
|
|
+#define MASK_RESET_BUCK_REG 0x18U
|
|
+#define MASK_RANK_LDO_REG 0x19U
|
|
+#define MASK_RESET_LDO_REG 0x1AU
|
|
+#define WATCHDOG_CONTROL_REG 0x1BU
|
|
+#define WATCHDOG_TIMER_REG 0x1CU
|
|
+#define BUCK_ICC_TURNOFF_REG 0x1DU
|
|
+#define LDO_ICC_TURNOFF_REG 0x1EU
|
|
+#define BUCK_APM_CONTROL_REG 0x1FU
|
|
+#define BUCK1_CONTROL_REG 0x20U
|
|
+#define BUCK2_CONTROL_REG 0x21U
|
|
+#define BUCK3_CONTROL_REG 0x22U
|
|
+#define BUCK4_CONTROL_REG 0x23U
|
|
+#define VREF_DDR_CONTROL_REG 0x24U
|
|
+#define LDO1_CONTROL_REG 0x25U
|
|
+#define LDO2_CONTROL_REG 0x26U
|
|
+#define LDO3_CONTROL_REG 0x27U
|
|
+#define LDO4_CONTROL_REG 0x28U
|
|
+#define LDO5_CONTROL_REG 0x29U
|
|
+#define LDO6_CONTROL_REG 0x2AU
|
|
+#define BUCK1_PWRCTRL_REG 0x30U
|
|
+#define BUCK2_PWRCTRL_REG 0x31U
|
|
+#define BUCK3_PWRCTRL_REG 0x32U
|
|
+#define BUCK4_PWRCTRL_REG 0x33U
|
|
+#define VREF_DDR_PWRCTRL_REG 0x34U
|
|
+#define LDO1_PWRCTRL_REG 0x35U
|
|
+#define LDO2_PWRCTRL_REG 0x36U
|
|
+#define LDO3_PWRCTRL_REG 0x37U
|
|
+#define LDO4_PWRCTRL_REG 0x38U
|
|
+#define LDO5_PWRCTRL_REG 0x39U
|
|
+#define LDO6_PWRCTRL_REG 0x3AU
|
|
+#define FREQUENCY_SPREADING_REG 0x3BU
|
|
+#define USB_CONTROL_REG 0x40U
|
|
+#define ITLATCH1_REG 0x50U
|
|
+#define ITLATCH2_REG 0x51U
|
|
+#define ITLATCH3_REG 0x52U
|
|
+#define ITLATCH4_REG 0x53U
|
|
+#define ITSETLATCH1_REG 0x60U
|
|
+#define ITSETLATCH2_REG 0x61U
|
|
+#define ITSETLATCH3_REG 0x62U
|
|
+#define ITSETLATCH4_REG 0x63U
|
|
+#define ITCLEARLATCH1_REG 0x70U
|
|
+#define ITCLEARLATCH2_REG 0x71U
|
|
+#define ITCLEARLATCH3_REG 0x72U
|
|
+#define ITCLEARLATCH4_REG 0x73U
|
|
+#define ITMASK1_REG 0x80U
|
|
+#define ITMASK2_REG 0x81U
|
|
+#define ITMASK3_REG 0x82U
|
|
+#define ITMASK4_REG 0x83U
|
|
+#define ITSETMASK1_REG 0x90U
|
|
+#define ITSETMASK2_REG 0x91U
|
|
+#define ITSETMASK3_REG 0x92U
|
|
+#define ITSETMASK4_REG 0x93U
|
|
+#define ITCLEARMASK1_REG 0xA0U
|
|
+#define ITCLEARMASK2_REG 0xA1U
|
|
+#define ITCLEARMASK3_REG 0xA2U
|
|
+#define ITCLEARMASK4_REG 0xA3U
|
|
+#define ITSOURCE1_REG 0xB0U
|
|
+#define ITSOURCE2_REG 0xB1U
|
|
+#define ITSOURCE3_REG 0xB2U
|
|
+#define ITSOURCE4_REG 0xB3U
|
|
+
|
|
+/* Registers masks */
|
|
+#define LDO_VOLTAGE_MASK 0x7CU
|
|
+#define BUCK_VOLTAGE_MASK 0xFCU
|
|
+#define LDO_BUCK_VOLTAGE_SHIFT 2
|
|
+#define LDO_BUCK_ENABLE_MASK 0x01U
|
|
+#define LDO_BUCK_HPLP_ENABLE_MASK 0x02U
|
|
+#define LDO_BUCK_HPLP_SHIFT 1
|
|
+#define LDO_BUCK_RANK_MASK 0x01U
|
|
+#define LDO_BUCK_RESET_MASK 0x01U
|
|
+#define LDO_BUCK_PULL_DOWN_MASK 0x03U
|
|
+
|
|
+/* Pull down register */
|
|
+#define BUCK1_PULL_DOWN_SHIFT 0
|
|
+#define BUCK2_PULL_DOWN_SHIFT 2
|
|
+#define BUCK3_PULL_DOWN_SHIFT 4
|
|
+#define BUCK4_PULL_DOWN_SHIFT 6
|
|
+#define VREF_DDR_PULL_DOWN_SHIFT 4
|
|
+
|
|
+/* Buck Mask reset register */
|
|
+#define BUCK1_MASK_RESET 0
|
|
+#define BUCK2_MASK_RESET 1
|
|
+#define BUCK3_MASK_RESET 2
|
|
+#define BUCK4_MASK_RESET 3
|
|
+
|
|
+/* LDO Mask reset register */
|
|
+#define LDO1_MASK_RESET 0
|
|
+#define LDO2_MASK_RESET 1
|
|
+#define LDO3_MASK_RESET 2
|
|
+#define LDO4_MASK_RESET 3
|
|
+#define LDO5_MASK_RESET 4
|
|
+#define LDO6_MASK_RESET 5
|
|
+#define VREF_DDR_MASK_RESET 6
|
|
+
|
|
+/* Main PMIC Control Register (MAIN_CONTROL_REG) */
|
|
+#define ICC_EVENT_ENABLED BIT(4)
|
|
+#define PWRCTRL_POLARITY_HIGH BIT(3)
|
|
+#define PWRCTRL_PIN_VALID BIT(2)
|
|
+#define RESTART_REQUEST_ENABLED BIT(1)
|
|
+#define SOFTWARE_SWITCH_OFF_ENABLED BIT(0)
|
|
+
|
|
+/* Main PMIC PADS Control Register (PADS_PULL_REG) */
|
|
+#define WAKEUP_DETECTOR_DISABLED BIT(4)
|
|
+#define PWRCTRL_PD_ACTIVE BIT(3)
|
|
+#define PWRCTRL_PU_ACTIVE BIT(2)
|
|
+#define WAKEUP_PD_ACTIVE BIT(1)
|
|
+#define PONKEY_PU_ACTIVE BIT(0)
|
|
+
|
|
+/* Main PMIC VINLOW Control Register (VIN_CONTROL_REGC DMSC) */
|
|
+#define SWIN_DETECTOR_ENABLED BIT(7)
|
|
+#define SWOUT_DETECTOR_ENABLED BIT(6)
|
|
+#define VINLOW_HYST_MASK 0x3
|
|
+#define VINLOW_HYST_SHIFT 4
|
|
+#define VINLOW_THRESHOLD_MASK 0x7
|
|
+#define VINLOW_THRESHOLD_SHIFT 1
|
|
+#define VINLOW_ENABLED 0x01
|
|
+#define VINLOW_CTRL_REG_MASK 0xFF
|
|
+
|
|
+/* USB Control Register */
|
|
+#define BOOST_OVP_DISABLED BIT(7)
|
|
+#define VBUS_OTG_DETECTION_DISABLED BIT(6)
|
|
+#define OCP_LIMIT_HIGH BIT(3)
|
|
+#define SWIN_SWOUT_ENABLED BIT(2)
|
|
+#define USBSW_OTG_SWITCH_ENABLED BIT(1)
|
|
+
|
|
+int stpmic1_powerctrl_on(void);
|
|
+int stpmic1_switch_off(void);
|
|
+int stpmic1_register_read(uint8_t register_id, uint8_t *value);
|
|
+int stpmic1_register_write(uint8_t register_id, uint8_t value);
|
|
+int stpmic1_register_update(uint8_t register_id, uint8_t value, uint8_t mask);
|
|
+int stpmic1_regulator_enable(const char *name);
|
|
+int stpmic1_regulator_disable(const char *name);
|
|
+uint8_t stpmic1_is_regulator_enabled(const char *name);
|
|
+int stpmic1_regulator_voltage_set(const char *name, uint16_t millivolts);
|
|
+int stpmic1_regulator_voltage_get(const char *name);
|
|
+int stpmic1_regulator_pull_down_set(const char *name);
|
|
+int stpmic1_regulator_mask_reset_set(const char *name);
|
|
+int stpmic1_lp_copy_reg(const char *name);
|
|
+int stpmic1_lp_reg_on_off(const char *name, uint8_t enable);
|
|
+int stpmic1_lp_set_mode(const char *name, uint8_t hplp);
|
|
+int stpmic1_lp_set_voltage(const char *name, uint16_t millivolts);
|
|
+void stpmic1_bind_i2c(struct i2c_handle_s *i2c_handle, uint16_t i2c_addr);
|
|
+
|
|
+int stpmic1_get_version(unsigned long *version);
|
|
+void stpmic1_dump_regulators(void);
|
|
+
|
|
+#endif /* STPMIC1_H */
|
|
diff --git a/include/drivers/st/stpmu1.h b/include/drivers/st/stpmu1.h
|
|
deleted file mode 100644
|
|
index 1b93ab2..0000000
|
|
--- a/include/drivers/st/stpmu1.h
|
|
+++ /dev/null
|
|
@@ -1,141 +0,0 @@
|
|
-/*
|
|
- * Copyright (c) 2016-2018, STMicroelectronics - All Rights Reserved
|
|
- *
|
|
- * SPDX-License-Identifier: BSD-3-Clause
|
|
- */
|
|
-
|
|
-
|
|
-#ifndef __STPMU1_H__
|
|
-#define __STPMU1_H__
|
|
-
|
|
-#include <stm32_i2c.h>
|
|
-#include <utils_def.h>
|
|
-
|
|
-#define TURN_ON_REG 0x1U
|
|
-#define TURN_OFF_REG 0x2U
|
|
-#define ICC_LDO_TURN_OFF_REG 0x3U
|
|
-#define ICC_BUCK_TURN_OFF_REG 0x4U
|
|
-#define RESET_STATUS_REG 0x5U
|
|
-#define VERSION_STATUS_REG 0x6U
|
|
-#define MAIN_CONTROL_REG 0x10U
|
|
-#define PADS_PULL_REG 0x11U
|
|
-#define BUCK_PULL_DOWN_REG 0x12U
|
|
-#define LDO14_PULL_DOWN_REG 0x13U
|
|
-#define LDO56_PULL_DOWN_REG 0x14U
|
|
-#define VIN_CONTROL_REG 0x15U
|
|
-#define PONKEY_TIMER_REG 0x16U
|
|
-#define MASK_RANK_BUCK_REG 0x17U
|
|
-#define MASK_RESET_BUCK_REG 0x18U
|
|
-#define MASK_RANK_LDO_REG 0x19U
|
|
-#define MASK_RESET_LDO_REG 0x1AU
|
|
-#define WATCHDOG_CONTROL_REG 0x1BU
|
|
-#define WATCHDOG_TIMER_REG 0x1CU
|
|
-#define BUCK_ICC_TURNOFF_REG 0x1DU
|
|
-#define LDO_ICC_TURNOFF_REG 0x1EU
|
|
-#define BUCK_APM_CONTROL_REG 0x1FU
|
|
-#define BUCK1_CONTROL_REG 0x20U
|
|
-#define BUCK2_CONTROL_REG 0x21U
|
|
-#define BUCK3_CONTROL_REG 0x22U
|
|
-#define BUCK4_CONTROL_REG 0x23U
|
|
-#define VREF_DDR_CONTROL_REG 0x24U
|
|
-#define LDO1_CONTROL_REG 0x25U
|
|
-#define LDO2_CONTROL_REG 0x26U
|
|
-#define LDO3_CONTROL_REG 0x27U
|
|
-#define LDO4_CONTROL_REG 0x28U
|
|
-#define LDO5_CONTROL_REG 0x29U
|
|
-#define LDO6_CONTROL_REG 0x2AU
|
|
-#define BUCK1_PWRCTRL_REG 0x30U
|
|
-#define BUCK2_PWRCTRL_REG 0x31U
|
|
-#define BUCK3_PWRCTRL_REG 0x32U
|
|
-#define BUCK4_PWRCTRL_REG 0x33U
|
|
-#define VREF_DDR_PWRCTRL_REG 0x34U
|
|
-#define LDO1_PWRCTRL_REG 0x35U
|
|
-#define LDO2_PWRCTRL_REG 0x36U
|
|
-#define LDO3_PWRCTRL_REG 0x37U
|
|
-#define LDO4_PWRCTRL_REG 0x38U
|
|
-#define LDO5_PWRCTRL_REG 0x39U
|
|
-#define LDO6_PWRCTRL_REG 0x3AU
|
|
-#define FREQUENCY_SPREADING_REG 0x3BU
|
|
-#define USB_CONTROL_REG 0x40U
|
|
-#define ITLATCH1_REG 0x50U
|
|
-#define ITLATCH2_REG 0x51U
|
|
-#define ITLATCH3_REG 0x52U
|
|
-#define ITLATCH4_REG 0x53U
|
|
-#define ITSETLATCH1_REG 0x60U
|
|
-#define ITSETLATCH2_REG 0x61U
|
|
-#define ITSETLATCH3_REG 0x62U
|
|
-#define ITSETLATCH4_REG 0x63U
|
|
-#define ITCLEARLATCH1_REG 0x70U
|
|
-#define ITCLEARLATCH2_REG 0x71U
|
|
-#define ITCLEARLATCH3_REG 0x72U
|
|
-#define ITCLEARLATCH4_REG 0x73U
|
|
-#define ITMASK1_REG 0x80U
|
|
-#define ITMASK2_REG 0x81U
|
|
-#define ITMASK3_REG 0x82U
|
|
-#define ITMASK4_REG 0x83U
|
|
-#define ITSETMASK1_REG 0x90U
|
|
-#define ITSETMASK2_REG 0x91U
|
|
-#define ITSETMASK3_REG 0x92U
|
|
-#define ITSETMASK4_REG 0x93U
|
|
-#define ITCLEARMASK1_REG 0xA0U
|
|
-#define ITCLEARMASK2_REG 0xA1U
|
|
-#define ITCLEARMASK3_REG 0xA2U
|
|
-#define ITCLEARMASK4_REG 0xA3U
|
|
-#define ITSOURCE1_REG 0xB0U
|
|
-#define ITSOURCE2_REG 0xB1U
|
|
-#define ITSOURCE3_REG 0xB2U
|
|
-#define ITSOURCE4_REG 0xB3U
|
|
-#define LDO_VOLTAGE_MASK 0x7CU
|
|
-#define BUCK_VOLTAGE_MASK 0xFCU
|
|
-#define LDO_BUCK_VOLTAGE_SHIFT 2
|
|
-#define LDO_ENABLE_MASK 0x01U
|
|
-#define BUCK_ENABLE_MASK 0x01U
|
|
-#define BUCK_HPLP_ENABLE_MASK 0x02U
|
|
-#define LDO_HPLP_ENABLE_MASK 0x02U
|
|
-#define LDO_BUCK_HPLP_SHIFT 1
|
|
-#define LDO_BUCK_RANK_MASK 0x01U
|
|
-#define LDO_BUCK_RESET_MASK 0x01U
|
|
-#define LDO_BUCK_PULL_DOWN_MASK 0x03U
|
|
-
|
|
-/* Main PMIC Control Register (MAIN_CONTROL_REG) */
|
|
-#define ICC_EVENT_ENABLED BIT(4)
|
|
-#define PWRCTRL_POLARITY_HIGH BIT(3)
|
|
-#define PWRCTRL_PIN_VALID BIT(2)
|
|
-#define RESTART_REQUEST_ENABLED BIT(1)
|
|
-#define SOFTWARE_SWITCH_OFF_ENABLED BIT(0)
|
|
-
|
|
-/* Main PMIC PADS Control Register (PADS_PULL_REG) */
|
|
-#define WAKEUP_DETECTOR_DISABLED BIT(4)
|
|
-#define PWRCTRL_PD_ACTIVE BIT(3)
|
|
-#define PWRCTRL_PU_ACTIVE BIT(2)
|
|
-#define WAKEUP_PD_ACTIVE BIT(1)
|
|
-#define PONKEY_PU_ACTIVE BIT(0)
|
|
-
|
|
-/* Main PMIC VINLOW Control Register (VIN_CONTROL_REGC DMSC) */
|
|
-#define SWIN_DETECTOR_ENABLED BIT(7)
|
|
-#define SWOUT_DETECTOR_ENABLED BIT(6)
|
|
-#define VINLOW_HYST_MASK 0x3
|
|
-#define VINLOW_HYST_SHIFT 4
|
|
-#define VINLOW_THRESHOLD_MASK 0x7
|
|
-#define VINLOW_THRESHOLD_SHIFT 1
|
|
-#define VINLOW_ENABLED 0x01
|
|
-#define VINLOW_CTRL_REG_MASK 0xFF
|
|
-
|
|
-/* USB Control Register */
|
|
-#define BOOST_OVP_DISABLED BIT(7)
|
|
-#define VBUS_OTG_DETECTION_DISABLED BIT(6)
|
|
-#define OCP_LIMIT_HIGH BIT(3)
|
|
-#define SWIN_SWOUT_ENABLED BIT(2)
|
|
-#define USBSW_OTG_SWITCH_ENABLED BIT(1)
|
|
-
|
|
-int stpmu1_switch_off(void);
|
|
-int stpmu1_register_read(uint8_t register_id, uint8_t *value);
|
|
-int stpmu1_register_write(uint8_t register_id, uint8_t value);
|
|
-int stpmu1_register_update(uint8_t register_id, uint8_t value, uint8_t mask);
|
|
-int stpmu1_regulator_enable(const char *name);
|
|
-int stpmu1_regulator_disable(const char *name);
|
|
-uint8_t stpmu1_is_regulator_enabled(const char *name);
|
|
-int stpmu1_regulator_voltage_set(const char *name, uint16_t millivolts);
|
|
-void stpmu1_bind_i2c(struct i2c_handle_s *i2c_handle, uint16_t i2c_addr);
|
|
-
|
|
-#endif /* __STPMU1_H__ */
|
|
diff --git a/include/drivers/st/usb_dwc2.h b/include/drivers/st/usb_dwc2.h
|
|
new file mode 100644
|
|
index 0000000..85628f1
|
|
--- /dev/null
|
|
+++ b/include/drivers/st/usb_dwc2.h
|
|
@@ -0,0 +1,443 @@
|
|
+/*
|
|
+ * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved.
|
|
+ *
|
|
+ * SPDX-License-Identifier: BSD-3-Clause
|
|
+ */
|
|
+
|
|
+#ifndef __USB_DWC2_H
|
|
+#define __USB_DWC2_H
|
|
+
|
|
+#include <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/interrupt-controller/arm-gic.h b/include/dt-bindings/interrupt-controller/arm-gic.h
|
|
new file mode 100644
|
|
index 0000000..aa9158c
|
|
--- /dev/null
|
|
+++ b/include/dt-bindings/interrupt-controller/arm-gic.h
|
|
@@ -0,0 +1,21 @@
|
|
+/* SPDX-License-Identifier: GPL-2.0 or BSD-3-Clause */
|
|
+/*
|
|
+ * This header provides constants for the ARM GIC.
|
|
+ */
|
|
+
|
|
+#ifndef _DT_BINDINGS_INTERRUPT_CONTROLLER_ARM_GIC_H
|
|
+#define _DT_BINDINGS_INTERRUPT_CONTROLLER_ARM_GIC_H
|
|
+
|
|
+/* interrupt specifier cell 0 */
|
|
+
|
|
+#define GIC_SPI 0
|
|
+#define GIC_PPI 1
|
|
+
|
|
+#define IRQ_TYPE_NONE 0
|
|
+#define IRQ_TYPE_EDGE_RISING 1
|
|
+#define IRQ_TYPE_EDGE_FALLING 2
|
|
+#define IRQ_TYPE_EDGE_BOTH (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING)
|
|
+#define IRQ_TYPE_LEVEL_HIGH 4
|
|
+#define IRQ_TYPE_LEVEL_LOW 8
|
|
+
|
|
+#endif
|
|
diff --git a/include/dt-bindings/pinctrl/stm32-pinfunc.h b/include/dt-bindings/pinctrl/stm32-pinfunc.h
|
|
index e2f1f1b..7f6e4b9 100644
|
|
--- a/include/dt-bindings/pinctrl/stm32-pinfunc.h
|
|
+++ b/include/dt-bindings/pinctrl/stm32-pinfunc.h
|
|
@@ -32,4 +32,10 @@
|
|
|
|
#define STM32_PINMUX(port, line, mode) (((PIN_NO(port, line)) << 8) | (mode))
|
|
|
|
+/* package information */
|
|
+#define STM32MP157CAA 0x1
|
|
+#define STM32MP157CAB 0x2
|
|
+#define STM32MP157CAC 0x4
|
|
+#define STM32MP157CAD 0x8
|
|
+
|
|
#endif /* _DT_BINDINGS_STM32_PINFUNC_H */
|
|
diff --git a/include/dt-bindings/power/stm32mp1-power.h b/include/dt-bindings/power/stm32mp1-power.h
|
|
new file mode 100644
|
|
index 0000000..bfb7f78
|
|
--- /dev/null
|
|
+++ b/include/dt-bindings/power/stm32mp1-power.h
|
|
@@ -0,0 +1,19 @@
|
|
+/* SPDX-License-Identifier: GPL-2.0 or BSD-3-Clause */
|
|
+/*
|
|
+ * Copyright (C) STMicroelectronics 2018 - All Rights Reserved
|
|
+ * Author: Yann Gautier <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/soc/st,stm32-etzpc.h b/include/dt-bindings/soc/st,stm32-etzpc.h
|
|
new file mode 100644
|
|
index 0000000..6678b8e
|
|
--- /dev/null
|
|
+++ b/include/dt-bindings/soc/st,stm32-etzpc.h
|
|
@@ -0,0 +1,107 @@
|
|
+/*
|
|
+ * Copyright (C) 2017, STMicroelectronics - All Rights Reserved
|
|
+ *
|
|
+ * SPDX-License-Identifier: GPL-2.0+ BSD-3-Clause
|
|
+ */
|
|
+
|
|
+#ifndef _DT_BINDINGS_STM32_ETZPC_H
|
|
+#define _DT_BINDINGS_STM32_ETZPC_H
|
|
+
|
|
+/* define DECPROT modes */
|
|
+#define DECPROT_S_RW 0x0
|
|
+#define DECPROT_NS_R_S_W 0x1
|
|
+#define DECPROT_MCU_ISOLATION 0x2
|
|
+#define DECPROT_NS_RW 0x3
|
|
+
|
|
+/* define DECPROT lock */
|
|
+#define DECPROT_UNLOCK 0x0
|
|
+#define DECPROT_LOCK 0x1
|
|
+
|
|
+/* define ETZPC ID */
|
|
+#define STM32MP1_ETZPC_STGENC_ID 0
|
|
+#define STM32MP1_ETZPC_BKPSRAM_ID 1
|
|
+#define STM32MP1_ETZPC_IWDG1_ID 2
|
|
+#define STM32MP1_ETZPC_USART1_ID 3
|
|
+#define STM32MP1_ETZPC_SPI6_ID 4
|
|
+#define STM32MP1_ETZPC_I2C4_ID 5
|
|
+#define STM32MP1_ETZPC_RNG1_ID 7
|
|
+#define STM32MP1_ETZPC_HASH1_ID 8
|
|
+#define STM32MP1_ETZPC_CRYP1_ID 9
|
|
+#define STM32MP1_ETZPC_DDRCTRL_ID 10
|
|
+#define STM32MP1_ETZPC_DDRPHYC_ID 11
|
|
+#define STM32MP1_ETZPC_I2C6_ID 12
|
|
+#define STM32MP1_ETZPC_TIM2_ID 16
|
|
+#define STM32MP1_ETZPC_TIM3_ID 17
|
|
+#define STM32MP1_ETZPC_TIM4_ID 18
|
|
+#define STM32MP1_ETZPC_TIM5_ID 19
|
|
+#define STM32MP1_ETZPC_TIM6_ID 20
|
|
+#define STM32MP1_ETZPC_TIM7_ID 21
|
|
+#define STM32MP1_ETZPC_TIM12_ID 22
|
|
+#define STM32MP1_ETZPC_TIM13_ID 23
|
|
+#define STM32MP1_ETZPC_TIM14_ID 24
|
|
+#define STM32MP1_ETZPC_LPTIM1_ID 25
|
|
+#define STM32MP1_ETZPC_WWDG1_ID 26
|
|
+#define STM32MP1_ETZPC_SPI2_ID 27
|
|
+#define STM32MP1_ETZPC_SPI3_ID 28
|
|
+#define STM32MP1_ETZPC_SPDIFRX_ID 29
|
|
+#define STM32MP1_ETZPC_USART2_ID 30
|
|
+#define STM32MP1_ETZPC_USART3_ID 31
|
|
+#define STM32MP1_ETZPC_UART4_ID 32
|
|
+#define STM32MP1_ETZPC_UART5_ID 33
|
|
+#define STM32MP1_ETZPC_I2C1_ID 34
|
|
+#define STM32MP1_ETZPC_I2C2_ID 35
|
|
+#define STM32MP1_ETZPC_I2C3_ID 36
|
|
+#define STM32MP1_ETZPC_I2C5_ID 37
|
|
+#define STM32MP1_ETZPC_CEC_ID 38
|
|
+#define STM32MP1_ETZPC_DAC_ID 39
|
|
+#define STM32MP1_ETZPC_UART7_ID 40
|
|
+#define STM32MP1_ETZPC_UART8_ID 41
|
|
+#define STM32MP1_ETZPC_MDIOS_ID 44
|
|
+#define STM32MP1_ETZPC_TIM1_ID 48
|
|
+#define STM32MP1_ETZPC_TIM8_ID 49
|
|
+#define STM32MP1_ETZPC_USART6_ID 51
|
|
+#define STM32MP1_ETZPC_SPI1_ID 52
|
|
+#define STM32MP1_ETZPC_SPI4_ID 53
|
|
+#define STM32MP1_ETZPC_TIM15_ID 54
|
|
+#define STM32MP1_ETZPC_TIM16_ID 55
|
|
+#define STM32MP1_ETZPC_TIM17_ID 56
|
|
+#define STM32MP1_ETZPC_SPI5_ID 57
|
|
+#define STM32MP1_ETZPC_SAI1_ID 58
|
|
+#define STM32MP1_ETZPC_SAI2_ID 59
|
|
+#define STM32MP1_ETZPC_SAI3_ID 60
|
|
+#define STM32MP1_ETZPC_DFSDM_ID 61
|
|
+#define STM32MP1_ETZPC_TT_FDCAN_ID 62
|
|
+#define STM32MP1_ETZPC_LPTIM2_ID 64
|
|
+#define STM32MP1_ETZPC_LPTIM3_ID 65
|
|
+#define STM32MP1_ETZPC_LPTIM4_ID 66
|
|
+#define STM32MP1_ETZPC_LPTIM5_ID 67
|
|
+#define STM32MP1_ETZPC_SAI4_ID 68
|
|
+#define STM32MP1_ETZPC_VREFBUF_ID 69
|
|
+#define STM32MP1_ETZPC_DCMI_ID 70
|
|
+#define STM32MP1_ETZPC_CRC2_ID 71
|
|
+#define STM32MP1_ETZPC_ADC_ID 72
|
|
+#define STM32MP1_ETZPC_HASH2_ID 73
|
|
+#define STM32MP1_ETZPC_RNG2_ID 74
|
|
+#define STM32MP1_ETZPC_CRYP2_ID 75
|
|
+#define STM32MP1_ETZPC_SRAM1_ID 80
|
|
+#define STM32MP1_ETZPC_SRAM2_ID 81
|
|
+#define STM32MP1_ETZPC_SRAM3_ID 82
|
|
+#define STM32MP1_ETZPC_SRAM4_ID 83
|
|
+#define STM32MP1_ETZPC_RETRAM_ID 84
|
|
+#define STM32MP1_ETZPC_OTG_ID 85
|
|
+#define STM32MP1_ETZPC_SDMMC3_ID 86
|
|
+#define STM32MP1_ETZPC_DLYBSD3_ID 87
|
|
+#define STM32MP1_ETZPC_DMA1_ID 88
|
|
+#define STM32MP1_ETZPC_DMA2_ID 89
|
|
+#define STM32MP1_ETZPC_DMAMUX_ID 90
|
|
+#define STM32MP1_ETZPC_FMC_ID 91
|
|
+#define STM32MP1_ETZPC_QSPI_ID 92
|
|
+#define STM32MP1_ETZPC_DLYBQ_ID 93
|
|
+#define STM32MP1_ETZPC_ETH_ID 94
|
|
+
|
|
+#define STM32MP1_ETZPC_MAX_ID 96
|
|
+
|
|
+#define DECPROT(id, mode, lock) (((id) << 16) | ((mode) << 8) | (lock))
|
|
+
|
|
+#endif /* _DT_BINDINGS_STM32_ETZPC_H */
|
|
+
|
|
diff --git a/include/lib/aarch32/arch.h b/include/lib/aarch32/arch.h
|
|
index 3536d20..aa34b9c 100644
|
|
--- a/include/lib/aarch32/arch.h
|
|
+++ b/include/lib/aarch32/arch.h
|
|
@@ -61,6 +61,9 @@
|
|
* Generic timer memory mapped registers & offsets
|
|
******************************************************************************/
|
|
#define CNTCR_OFF U(0x000)
|
|
+#define CNTSR_OFF U(0x004)
|
|
+#define CNTCVL_OFF U(0x008)
|
|
+#define CNTCVU_OFF U(0x00C)
|
|
#define CNTFID_OFF U(0x020)
|
|
|
|
#define CNTCR_EN (U(1) << 0)
|
|
@@ -457,6 +460,8 @@
|
|
#define HSTR p15, 4, c1, c1, 3
|
|
#define CNTHCTL p15, 4, c14, c1, 0
|
|
#define CNTKCTL p15, 0, c14, c1, 0
|
|
+#define CNTPTVAL p15, 0, c14, c2, 0
|
|
+#define CNTPCTL p15, 0, c14, c2, 1
|
|
#define VPIDR p15, 4, c0, c0, 0
|
|
#define VMPIDR p15, 4, c0, c0, 5
|
|
#define ISR p15, 0, c12, c1, 0
|
|
@@ -466,6 +471,7 @@
|
|
#define HTCR p15, 4, c2, c0, 2
|
|
#define HMAIR0 p15, 4, c10, c2, 0
|
|
#define ATS1CPR p15, 0, c7, c8, 0
|
|
+#define ATS1CPW p15, 0, c7, c8, 1
|
|
#define ATS1HR p15, 4, c7, c8, 0
|
|
#define DBGOSDLR p14, 0, c1, c3, 4
|
|
|
|
@@ -514,6 +520,12 @@
|
|
#define ICC_ASGI1R_EL1_64 p15, 1, c12
|
|
#define ICC_SGI0R_EL1_64 p15, 2, c12
|
|
|
|
+/* Fault registers. The format is: coproc, opt1, CRn, CRm, opt2 */
|
|
+#define DFSR p15, 0, c5, c0, 0
|
|
+#define IFSR p15, 0, c5, c0, 1
|
|
+#define DFAR p15, 0, c6, c0, 0
|
|
+#define IFAR p15, 0, c6, c0, 2
|
|
+
|
|
/*******************************************************************************
|
|
* Definitions of MAIR encodings for device and normal memory
|
|
******************************************************************************/
|
|
@@ -567,6 +579,8 @@
|
|
/* PAR fields */
|
|
#define PAR_F_SHIFT U(0)
|
|
#define PAR_F_MASK ULL(0x1)
|
|
+#define PAR_NS_SHIFT U(9)
|
|
+#define PAR_NS_MASK U(0x1)
|
|
#define PAR_ADDR_SHIFT U(12)
|
|
#define PAR_ADDR_MASK (BIT_64(40) - ULL(1)) /* 40-bits-wide page address */
|
|
|
|
diff --git a/include/lib/aarch32/arch_helpers.h b/include/lib/aarch32/arch_helpers.h
|
|
index 5d9c1c1..e48123c 100644
|
|
--- a/include/lib/aarch32/arch_helpers.h
|
|
+++ b/include/lib/aarch32/arch_helpers.h
|
|
@@ -261,6 +261,8 @@ DEFINE_COPROCR_RW_FUNCS_64(ttbr1, TTBR1_64)
|
|
DEFINE_COPROCR_RW_FUNCS_64(cntvoff, CNTVOFF_64)
|
|
DEFINE_COPROCR_RW_FUNCS(csselr, CSSELR)
|
|
DEFINE_COPROCR_RW_FUNCS(hstr, HSTR)
|
|
+DEFINE_COPROCR_RW_FUNCS(cntptval, CNTPTVAL)
|
|
+DEFINE_COPROCR_RW_FUNCS(cntpctl, CNTPCTL)
|
|
|
|
DEFINE_COPROCR_RW_FUNCS(icc_sre_el1, ICC_SRE)
|
|
DEFINE_COPROCR_RW_FUNCS(icc_sre_el2, ICC_HSRE)
|
|
@@ -282,6 +284,7 @@ DEFINE_COPROCR_RW_FUNCS(cnthp_ctl, CNTHP_CTL)
|
|
DEFINE_COPROCR_READ_FUNC(pmcr, PMCR)
|
|
|
|
DEFINE_COPROCR_RW_FUNCS(ats1cpr, ATS1CPR)
|
|
+DEFINE_COPROCR_RW_FUNCS(ats1cpw, ATS1CPW)
|
|
DEFINE_COPROCR_RW_FUNCS(ats1hr, ATS1HR)
|
|
DEFINE_COPROCR_RW_FUNCS_64(par, PAR_64)
|
|
|
|
diff --git a/include/lib/cpus/aarch32/cortex_a9.h b/include/lib/cpus/aarch32/cortex_a9.h
|
|
index be85f9b..ea8412f 100644
|
|
--- a/include/lib/cpus/aarch32/cortex_a9.h
|
|
+++ b/include/lib/cpus/aarch32/cortex_a9.h
|
|
@@ -18,6 +18,11 @@
|
|
#define CORTEX_A9_ACTLR_SMP_BIT (1 << 6)
|
|
#define CORTEX_A9_ACTLR_FLZW_BIT (1 << 3)
|
|
|
|
+#if defined(ARMV7_CORTEX_A_ACTLR_FLZW_BIT) && \
|
|
+ ARMV7_CORTEX_A_ACTLR_FLZW_BIT != CORTEX_A9_ACTLR_FLZW_BIT
|
|
+#error Cortex-A9 ACTLR field FLZW does not match
|
|
+#endif
|
|
+
|
|
/*******************************************************************************
|
|
* CPU Power Control Register
|
|
******************************************************************************/
|
|
diff --git a/include/lib/optee_utils.h b/include/lib/optee_utils.h
|
|
index 3d35b19..96c90bd 100644
|
|
--- a/include/lib/optee_utils.h
|
|
+++ b/include/lib/optee_utils.h
|
|
@@ -8,6 +8,7 @@
|
|
|
|
#include <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/psci/psci.h b/include/lib/psci/psci.h
|
|
index b27e481..b7febc3 100644
|
|
--- a/include/lib/psci/psci.h
|
|
+++ b/include/lib/psci/psci.h
|
|
@@ -302,10 +302,10 @@ typedef struct plat_psci_ops {
|
|
void (*pwr_domain_on_finish)(const psci_power_state_t *target_state);
|
|
void (*pwr_domain_suspend_finish)(
|
|
const psci_power_state_t *target_state);
|
|
- void (*pwr_domain_pwr_down_wfi)(
|
|
- const psci_power_state_t *target_state) __dead2;
|
|
- void (*system_off)(void) __dead2;
|
|
- void (*system_reset)(void) __dead2;
|
|
+ void __dead2 (*pwr_domain_pwr_down_wfi)(
|
|
+ const psci_power_state_t *target_state);
|
|
+ void __dead2 (*system_off)(void);
|
|
+ void __dead2 (*system_reset)(void);
|
|
int (*validate_power_state)(unsigned int power_state,
|
|
psci_power_state_t *req_state);
|
|
int (*validate_ns_entrypoint)(uintptr_t ns_entrypoint);
|
|
diff --git a/include/lib/usb/usb_core.h b/include/lib/usb/usb_core.h
|
|
new file mode 100644
|
|
index 0000000..eb0e87a
|
|
--- /dev/null
|
|
+++ b/include/lib/usb/usb_core.h
|
|
@@ -0,0 +1,352 @@
|
|
+/*
|
|
+ * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved.
|
|
+ *
|
|
+ * SPDX-License-Identifier: BSD-3-Clause
|
|
+ */
|
|
+
|
|
+#ifndef __USBD_CORE_H
|
|
+#define __USBD_CORE_H
|
|
+
|
|
+#include <stdint.h>
|
|
+#include <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 /* __USBD_CORE_H */
|
|
diff --git a/include/lib/usb/usb_st_dfu.h b/include/lib/usb/usb_st_dfu.h
|
|
new file mode 100644
|
|
index 0000000..3709683
|
|
--- /dev/null
|
|
+++ b/include/lib/usb/usb_st_dfu.h
|
|
@@ -0,0 +1,115 @@
|
|
+/*
|
|
+ * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved.
|
|
+ *
|
|
+ * SPDX-License-Identifier: BSD-3-Clause
|
|
+ */
|
|
+
|
|
+#ifndef __USB_DFU_H
|
|
+#define __USB_DFU_H
|
|
+
|
|
+#include <stdint.h>
|
|
+#include <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_DFU_H */
|
|
diff --git a/include/lib/utils.h b/include/lib/utils.h
|
|
index d46d846..b6ab26e 100644
|
|
--- a/include/lib/utils.h
|
|
+++ b/include/lib/utils.h
|
|
@@ -4,8 +4,8 @@
|
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
*/
|
|
|
|
-#ifndef __UTILS_H__
|
|
-#define __UTILS_H__
|
|
+#ifndef UTILS_H
|
|
+#define UTILS_H
|
|
|
|
/*
|
|
* C code should be put in this part of the header to avoid breaking ASM files
|
|
@@ -67,6 +67,29 @@ void zero_normalmem(void *mem, u_register_t length);
|
|
* zeroing.
|
|
*/
|
|
void zeromem(void *mem, u_register_t length);
|
|
+
|
|
+/*
|
|
+ * Utility function to return the address of a symbol. By default, the
|
|
+ * compiler generates adr/adrp instruction pair to return the reference
|
|
+ * to the symbol and this utility is used to override this compiler
|
|
+ * generated to code to use `ldr` instruction.
|
|
+ *
|
|
+ * This helps when Position Independent Executable needs to reference a symbol
|
|
+ * which is constant and does not depend on the execute address of the binary.
|
|
+ */
|
|
+#define DEFINE_LOAD_SYM_ADDR(_name) \
|
|
+static inline u_register_t load_addr_## _name(void) \
|
|
+{ \
|
|
+ u_register_t v; \
|
|
+ /* Create a void reference to silence compiler */ \
|
|
+ (void) _name; \
|
|
+ __asm__ volatile ("ldr %0, =" #_name : "=r" (v)); \
|
|
+ return v; \
|
|
+}
|
|
+
|
|
+/* Helper to invoke the function defined by DEFINE_LOAD_SYM_ADDR() */
|
|
+#define LOAD_ADDR_OF(_name) (typeof(_name) *) load_addr_## _name()
|
|
+
|
|
#endif /* !(defined(__LINKER__) || defined(__ASSEMBLY__)) */
|
|
|
|
-#endif /* __UTILS_H__ */
|
|
+#endif /* UTILS_H */
|
|
diff --git a/include/lib/utils_def.h b/include/lib/utils_def.h
|
|
index 5b4fd78..51863d8 100644
|
|
--- a/include/lib/utils_def.h
|
|
+++ b/include/lib/utils_def.h
|
|
@@ -30,11 +30,19 @@
|
|
* position @h. For example
|
|
* GENMASK_64(39, 21) gives us the 64bit vector 0x000000ffffe00000.
|
|
*/
|
|
+#if defined(__LINKER__) || defined(__ASSEMBLY__)
|
|
+#define GENMASK_32(h, l) \
|
|
+ (((0xFFFFFFFF) << (l)) & (0xFFFFFFFF >> (32 - 1 - (h))))
|
|
+
|
|
+#define GENMASK_64(h, l) \
|
|
+ ((~0 << (l)) & (~0 >> (64 - 1 - (h))))
|
|
+#else
|
|
#define GENMASK_32(h, l) \
|
|
(((~UINT32_C(0)) << (l)) & (~UINT32_C(0) >> (32 - 1 - (h))))
|
|
|
|
#define GENMASK_64(h, l) \
|
|
(((~UINT64_C(0)) << (l)) & (~UINT64_C(0) >> (64 - 1 - (h))))
|
|
+#endif
|
|
|
|
#ifdef AARCH32
|
|
#define GENMASK GENMASK_32
|
|
@@ -50,7 +58,17 @@
|
|
|
|
#define div_round_up(val, div) __extension__ ({ \
|
|
__typeof__(div) _div = (div); \
|
|
- ((val) + _div - 1) / _div; \
|
|
+ ((val) + _div - (__typeof__(div)) 1) / _div; \
|
|
+})
|
|
+
|
|
+/*
|
|
+ * Macro for unsigned integer division with nearest rounding variant.
|
|
+ * Default integer division rounds down.
|
|
+ */
|
|
+#define udiv_round_nearest(x, y) __extension__ ({ \
|
|
+ __typeof__(x) _x = (x); \
|
|
+ __typeof__(y) _y = (y); \
|
|
+ (_x + (_y / 2)) / _y; \
|
|
})
|
|
|
|
#define MIN(x, y) __extension__ ({ \
|
|
diff --git a/include/lib/xlat_tables/xlat_tables_v2_helpers.h b/include/lib/xlat_tables/xlat_tables_v2_helpers.h
|
|
index fa89958..c9504b3 100644
|
|
--- a/include/lib/xlat_tables/xlat_tables_v2_helpers.h
|
|
+++ b/include/lib/xlat_tables/xlat_tables_v2_helpers.h
|
|
@@ -120,6 +120,37 @@ struct xlat_ctx {
|
|
/* do nothing */
|
|
#endif /* PLAT_XLAT_TABLES_DYNAMIC */
|
|
|
|
+#ifdef PLAT_XLAT_BASE
|
|
+#define tf_xlat_tables (void *)PLAT_XLAT_BASE
|
|
+
|
|
+#define XLAT_TABLES(_ctx_name, _xlat_tables_count, _section_name) \
|
|
+ CASSERT(!(PLAT_XLAT_BASE & (XLAT_TABLE_SIZE - 1)), \
|
|
+ invalid_plat_xlat_base); \
|
|
+ CASSERT(PLAT_XLAT_SIZE >= (sizeof(uint64_t) * \
|
|
+ XLAT_TABLE_ENTRIES * _xlat_tables_count), \
|
|
+ invalid_plat_xlat_size);
|
|
+
|
|
+#else
|
|
+#define XLAT_TABLES(_ctx_name, _xlat_tables_count, _section_name) \
|
|
+ static uint64_t _ctx_name##_xlat_tables[_xlat_tables_count][XLAT_TABLE_ENTRIES] \
|
|
+ __aligned(XLAT_TABLE_SIZE) __section(_section_name);
|
|
+#endif
|
|
+
|
|
+#ifdef PLAT_BASE_XLAT_BASE
|
|
+#define tf_base_xlat_table (void *)PLAT_BASE_XLAT_BASE
|
|
+
|
|
+#define BASE_XLAT_TABLE(_ctx_name, _virt_addr_space_size) \
|
|
+ CASSERT(!(PLAT_BASE_XLAT_BASE & \
|
|
+ ((GET_NUM_BASE_LEVEL_ENTRIES(_virt_addr_space_size) * \
|
|
+ sizeof(uint64_t)) - 1)), invalid_plat_base_xlat_cfg);
|
|
+#else
|
|
+#define BASE_XLAT_TABLE(_ctx_name, _virt_addr_space_size) \
|
|
+ static uint64_t _ctx_name##_base_xlat_table \
|
|
+ [GET_NUM_BASE_LEVEL_ENTRIES(_virt_addr_space_size)] \
|
|
+ __aligned(GET_NUM_BASE_LEVEL_ENTRIES(_virt_addr_space_size) * \
|
|
+ sizeof(uint64_t));
|
|
+#endif
|
|
+
|
|
#define REGISTER_XLAT_CONTEXT_FULL_SPEC(_ctx_name, _mmap_count, \
|
|
_xlat_tables_count, _virt_addr_space_size, \
|
|
_phy_addr_space_size, _xlat_regime, _section_name)\
|
|
@@ -131,14 +162,8 @@ struct xlat_ctx {
|
|
\
|
|
static mmap_region_t _ctx_name##_mmap[_mmap_count + 1]; \
|
|
\
|
|
- static uint64_t _ctx_name##_xlat_tables[_xlat_tables_count] \
|
|
- [XLAT_TABLE_ENTRIES] \
|
|
- __aligned(XLAT_TABLE_SIZE) __section(_section_name); \
|
|
- \
|
|
- static uint64_t _ctx_name##_base_xlat_table \
|
|
- [GET_NUM_BASE_LEVEL_ENTRIES(_virt_addr_space_size)] \
|
|
- __aligned(GET_NUM_BASE_LEVEL_ENTRIES(_virt_addr_space_size)\
|
|
- * sizeof(uint64_t)); \
|
|
+ XLAT_TABLES(_ctx_name, _xlat_tables_count, _section_name) \
|
|
+ BASE_XLAT_TABLE(_ctx_name, _virt_addr_space_size) \
|
|
\
|
|
XLAT_ALLOC_DYNMAP_STRUCT(_ctx_name, _xlat_tables_count) \
|
|
\
|
|
diff --git a/include/plat/common/platform.h b/include/plat/common/platform.h
|
|
index a30b579..1a6161e 100644
|
|
--- a/include/plat/common/platform.h
|
|
+++ b/include/plat/common/platform.h
|
|
@@ -93,6 +93,11 @@ unsigned int plat_ic_get_interrupt_id(unsigned int raw);
|
|
******************************************************************************/
|
|
uintptr_t plat_get_my_stack(void);
|
|
void plat_report_exception(unsigned int exception_type);
|
|
+#if AARCH32_EXCEPTION_DEBUG
|
|
+void plat_report_undef_inst(unsigned int fault_address);
|
|
+void plat_report_prefetch_abort(unsigned int fault_address);
|
|
+void plat_report_data_abort(unsigned int fault_address);
|
|
+#endif
|
|
int plat_crash_console_init(void);
|
|
int plat_crash_console_putc(int c);
|
|
int plat_crash_console_flush(void);
|
|
diff --git a/lib/compiler-rt/builtins/int_lib.h b/lib/compiler-rt/builtins/int_lib.h
|
|
index 787777a..80a7c41 100644
|
|
--- a/lib/compiler-rt/builtins/int_lib.h
|
|
+++ b/lib/compiler-rt/builtins/int_lib.h
|
|
@@ -27,27 +27,28 @@
|
|
|
|
#if defined(__ELF__)
|
|
#define FNALIAS(alias_name, original_name) \
|
|
- void alias_name() __attribute__((alias(#original_name)))
|
|
+ void alias_name() __attribute__((__alias__(#original_name)))
|
|
+#define COMPILER_RT_ALIAS(aliasee) __attribute__((__alias__(#aliasee)))
|
|
#else
|
|
#define FNALIAS(alias, name) _Pragma("GCC error(\"alias unsupported on this file format\")")
|
|
+#define COMPILER_RT_ALIAS(aliasee) _Pragma("GCC error(\"alias unsupported on this file format\")")
|
|
#endif
|
|
|
|
/* ABI macro definitions */
|
|
|
|
#if __ARM_EABI__
|
|
-# define ARM_EABI_FNALIAS(aeabi_name, name) \
|
|
- void __aeabi_##aeabi_name() __attribute__((alias("__" #name)));
|
|
# ifdef COMPILER_RT_ARMHF_TARGET
|
|
# define COMPILER_RT_ABI
|
|
# else
|
|
-# define COMPILER_RT_ABI __attribute__((pcs("aapcs")))
|
|
+# define COMPILER_RT_ABI __attribute__((__pcs__("aapcs")))
|
|
# endif
|
|
#else
|
|
-# define ARM_EABI_FNALIAS(aeabi_name, name)
|
|
# define COMPILER_RT_ABI
|
|
#endif
|
|
|
|
-#ifdef _MSC_VER
|
|
+#define AEABI_RTABI __attribute__((__pcs__("aapcs")))
|
|
+
|
|
+#if defined(_MSC_VER) && !defined(__clang__)
|
|
#define ALWAYS_INLINE __forceinline
|
|
#define NOINLINE __declspec(noinline)
|
|
#define NORETURN __declspec(noreturn)
|
|
diff --git a/lib/compiler-rt/builtins/lshrdi3.c b/lib/compiler-rt/builtins/lshrdi3.c
|
|
new file mode 100644
|
|
index 0000000..67b2a76
|
|
--- /dev/null
|
|
+++ b/lib/compiler-rt/builtins/lshrdi3.c
|
|
@@ -0,0 +1,45 @@
|
|
+/* ===-- lshrdi3.c - Implement __lshrdi3 -----------------------------------===
|
|
+ *
|
|
+ * The LLVM Compiler Infrastructure
|
|
+ *
|
|
+ * This file is dual licensed under the MIT and the University of Illinois Open
|
|
+ * Source Licenses. See LICENSE.TXT for details.
|
|
+ *
|
|
+ * ===----------------------------------------------------------------------===
|
|
+ *
|
|
+ * This file implements __lshrdi3 for the compiler_rt library.
|
|
+ *
|
|
+ * ===----------------------------------------------------------------------===
|
|
+ */
|
|
+
|
|
+#include "int_lib.h"
|
|
+
|
|
+/* Returns: logical a >> b */
|
|
+
|
|
+/* Precondition: 0 <= b < bits_in_dword */
|
|
+
|
|
+COMPILER_RT_ABI di_int
|
|
+__lshrdi3(di_int a, si_int b)
|
|
+{
|
|
+ const int bits_in_word = (int)(sizeof(si_int) * CHAR_BIT);
|
|
+ udwords input;
|
|
+ udwords result;
|
|
+ input.all = a;
|
|
+ if (b & bits_in_word) /* bits_in_word <= b < bits_in_dword */
|
|
+ {
|
|
+ result.s.high = 0;
|
|
+ result.s.low = input.s.high >> (b - bits_in_word);
|
|
+ }
|
|
+ else /* 0 <= b < bits_in_word */
|
|
+ {
|
|
+ if (b == 0)
|
|
+ return a;
|
|
+ result.s.high = input.s.high >> b;
|
|
+ result.s.low = (input.s.high << (bits_in_word - b)) | (input.s.low >> b);
|
|
+ }
|
|
+ return result.all;
|
|
+}
|
|
+
|
|
+#if defined(__ARM_EABI__)
|
|
+AEABI_RTABI di_int __aeabi_llsr(di_int a, si_int b) COMPILER_RT_ALIAS(__lshrdi3);
|
|
+#endif
|
|
diff --git a/lib/compiler-rt/compiler-rt.mk b/lib/compiler-rt/compiler-rt.mk
|
|
index cb5ab31..49e497e 100644
|
|
--- a/lib/compiler-rt/compiler-rt.mk
|
|
+++ b/lib/compiler-rt/compiler-rt.mk
|
|
@@ -31,5 +31,6 @@
|
|
ifeq (${ARCH},aarch32)
|
|
COMPILER_RT_SRCS := lib/compiler-rt/builtins/arm/aeabi_uldivmod.S \
|
|
lib/compiler-rt/builtins/udivmoddi4.c \
|
|
- lib/compiler-rt/builtins/ctzdi2.c
|
|
+ lib/compiler-rt/builtins/ctzdi2.c \
|
|
+ lib/compiler-rt/builtins/lshrdi3.c
|
|
endif
|
|
diff --git a/lib/libfdt/fdt_ro.c b/lib/libfdt/fdt_ro.c
|
|
index 0459098..88aeb59 100644
|
|
--- a/lib/libfdt/fdt_ro.c
|
|
+++ b/lib/libfdt/fdt_ro.c
|
|
@@ -597,7 +597,7 @@ int fdt_stringlist_search(const void *fdt, int nodeoffset, const char *property,
|
|
|
|
list = fdt_getprop(fdt, nodeoffset, property, &length);
|
|
if (!list)
|
|
- return -length;
|
|
+ return length;
|
|
|
|
len = strlen(string) + 1;
|
|
end = list + length;
|
|
diff --git a/lib/optee/optee_utils.c b/lib/optee/optee_utils.c
|
|
index 34d095b..0f1e560 100644
|
|
--- a/lib/optee/optee_utils.c
|
|
+++ b/lib/optee/optee_utils.c
|
|
@@ -132,6 +132,36 @@ static int parse_optee_image(image_info_t *image_info,
|
|
}
|
|
|
|
/*******************************************************************************
|
|
+ * Parse the OPTEE header for an executable entry point address.
|
|
+ * Return 1 on success, 0 on failure.
|
|
+ ******************************************************************************/
|
|
+int get_optee_header_ep(entry_point_info_t *header_ep, uintptr_t *pc)
|
|
+{
|
|
+ optee_header_t *optee_header;
|
|
+ int num;
|
|
+
|
|
+ assert(pc && header_ep && header_ep->pc);
|
|
+ optee_header = (optee_header_t *)header_ep->pc;
|
|
+
|
|
+ if (!tee_validate_header(optee_header))
|
|
+ return 0;
|
|
+
|
|
+ for (num = 0; num < optee_header->nb_images; num++) {
|
|
+ optee_image_t *optee_image =
|
|
+ &optee_header->optee_image_list[num];
|
|
+
|
|
+ if (optee_image->image_id != OPTEE_PAGER_IMAGE_ID)
|
|
+ continue;
|
|
+
|
|
+ *pc = ((uint64_t)optee_image->load_addr_hi << 32) |
|
|
+ optee_image->load_addr_lo;
|
|
+ return 1;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/*******************************************************************************
|
|
* Parse the OPTEE header
|
|
* Return 0 on success or a negative error code otherwise.
|
|
******************************************************************************/
|
|
diff --git a/lib/usb/usb_core.c b/lib/usb/usb_core.c
|
|
new file mode 100644
|
|
index 0000000..240c1c1
|
|
--- /dev/null
|
|
+++ b/lib/usb/usb_core.c
|
|
@@ -0,0 +1,732 @@
|
|
+/*
|
|
+ * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved.
|
|
+ *
|
|
+ * SPDX-License-Identifier: BSD-3-Clause
|
|
+ */
|
|
+
|
|
+#include <stdint.h>
|
|
+#include <debug.h>
|
|
+#include "usb_core.h"
|
|
+
|
|
+/*
|
|
+ * @brief Set a STALL condition over an endpoint
|
|
+ * @param hpcd: PCD handle
|
|
+ * @param ep_addr: endpoint address
|
|
+ * @retval HAL status
|
|
+ */
|
|
+static usb_status_t usb_core_set_stall(usb_handle_t *pdev, uint8_t ep_addr)
|
|
+{
|
|
+ usb_otg_ep_t *ep;
|
|
+ pcd_handle_t *hpcd = (pcd_handle_t *)pdev->data;
|
|
+
|
|
+ if ((0x80 & ep_addr) == 0x80)
|
|
+ ep = &hpcd->in_ep[ep_addr & 0x7F];
|
|
+ else
|
|
+ ep = &hpcd->out_ep[ep_addr];
|
|
+
|
|
+ ep->is_stall = 1;
|
|
+ ep->num = ep_addr & 0x7F;
|
|
+ ep->is_in = ((ep_addr & 0x80) == 0x80);
|
|
+
|
|
+ pdev->driver->ep_set_stall(hpcd->instance, ep);
|
|
+ if ((ep_addr & 0x7F) == 0)
|
|
+ pdev->driver->ep0_out_start(hpcd->instance);
|
|
+
|
|
+ return USBD_OK;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * usb_core_get_desc
|
|
+ * Handle Get Descriptor requests
|
|
+ * pdev : device instance
|
|
+ * req : usb request
|
|
+ * return : status
|
|
+ */
|
|
+static void usb_core_get_desc(usb_handle_t *pdev,
|
|
+ usb_setup_req_t *req)
|
|
+{
|
|
+ uint16_t len;
|
|
+ uint8_t *pbuf;
|
|
+
|
|
+ switch (req->value >> 8) {
|
|
+ case USB_DESC_TYPE_DEVICE:
|
|
+ pbuf = pdev->desc->get_device_desc(&len);
|
|
+ break;
|
|
+
|
|
+ case USB_DESC_TYPE_CONFIGURATION:
|
|
+ pbuf = (uint8_t *)pdev->desc->get_hs_config_desc(&len);
|
|
+ pbuf[1] = USB_DESC_TYPE_CONFIGURATION;
|
|
+ break;
|
|
+
|
|
+ case USB_DESC_TYPE_STRING:
|
|
+ switch ((uint8_t)(req->value)) {
|
|
+ case USBD_IDX_LANGID_STR:
|
|
+ pbuf = pdev->desc->get_lang_id_desc(&len);
|
|
+ break;
|
|
+
|
|
+ case USBD_IDX_MFC_STR:
|
|
+ pbuf = pdev->desc->get_manufacturer_desc(&len);
|
|
+ break;
|
|
+
|
|
+ case USBD_IDX_PRODUCT_STR:
|
|
+ pbuf = pdev->desc->get_product_desc(&len);
|
|
+ break;
|
|
+
|
|
+ case USBD_IDX_SERIAL_STR:
|
|
+ pbuf = pdev->desc->get_serial_desc(&len);
|
|
+ break;
|
|
+
|
|
+ case USBD_IDX_CONFIG_STR:
|
|
+ pbuf = pdev->desc->get_configuration_desc(&len);
|
|
+ break;
|
|
+
|
|
+ case USBD_IDX_INTERFACE_STR:
|
|
+ pbuf = pdev->desc->get_interface_desc(&len);
|
|
+ break;
|
|
+
|
|
+ default:
|
|
+ pbuf = pdev->desc->get_usr_desc(req->value, &len);
|
|
+ break;
|
|
+ }
|
|
+ break;
|
|
+
|
|
+ case USB_DESC_TYPE_DEVICE_QUALIFIER:
|
|
+ pbuf = (uint8_t *)pdev->desc->get_device_qualifier_desc(&len);
|
|
+ break;
|
|
+
|
|
+ case USB_DESC_TYPE_OTHER_SPEED_CONFIGURATION:
|
|
+ pbuf = (uint8_t *)pdev->desc->get_other_speed_config_desc(&len);
|
|
+ pbuf[1] = USB_DESC_TYPE_OTHER_SPEED_CONFIGURATION;
|
|
+ break;
|
|
+
|
|
+ default:
|
|
+ ERROR("Unknown request %i\n", req->value >> 8);
|
|
+ usb_core_ctl_error(pdev);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ if ((len != 0) && (req->length != 0)) {
|
|
+ len = MIN(len, req->length);
|
|
+
|
|
+ /* Set EP0 State */
|
|
+ pdev->ep0_state = USBD_EP0_DATA_IN;
|
|
+ pdev->ep_in[0].total_length = len;
|
|
+ pdev->ep_in[0].rem_length = len;
|
|
+ /* Start the transfer */
|
|
+ usb_core_transmit(pdev, 0x00, pbuf, len);
|
|
+ }
|
|
+}
|
|
+
|
|
+/*
|
|
+ * usb_core_set_config
|
|
+ * Handle Set device configuration request
|
|
+ * pdev : device instance
|
|
+ * req : usb request
|
|
+ * return : status
|
|
+ */
|
|
+static void usb_core_set_config(usb_handle_t *pdev, usb_setup_req_t *req)
|
|
+{
|
|
+ static uint8_t cfgidx;
|
|
+
|
|
+ cfgidx = (uint8_t)(req->value);
|
|
+
|
|
+ if (cfgidx > USBD_MAX_NUM_CONFIGURATION) {
|
|
+ usb_core_ctl_error(pdev);
|
|
+ } else {
|
|
+ switch (pdev->dev_state) {
|
|
+ case USBD_STATE_ADDRESSED:
|
|
+ if (cfgidx) {
|
|
+ pdev->dev_config = cfgidx;
|
|
+ pdev->dev_state = USBD_STATE_CONFIGURED;
|
|
+ if (!pdev->class) {
|
|
+ usb_core_ctl_error(pdev);
|
|
+ return;
|
|
+ }
|
|
+ /* Set configuration and Start the Class*/
|
|
+ if (pdev->class->init(pdev, cfgidx) != 0) {
|
|
+ usb_core_ctl_error(pdev);
|
|
+ return;
|
|
+ }
|
|
+ }
|
|
+ break;
|
|
+
|
|
+ case USBD_STATE_CONFIGURED:
|
|
+ if (cfgidx == 0) {
|
|
+ pdev->dev_state = USBD_STATE_ADDRESSED;
|
|
+ pdev->dev_config = cfgidx;
|
|
+ pdev->class->de_init(pdev, cfgidx);
|
|
+ } else if (cfgidx != pdev->dev_config) {
|
|
+ if (!pdev->class) {
|
|
+ usb_core_ctl_error(pdev);
|
|
+ return;
|
|
+ }
|
|
+ /* Clear old configuration */
|
|
+ pdev->class->de_init(pdev, pdev->dev_config);
|
|
+
|
|
+ /* set new configuration */
|
|
+ pdev->dev_config = cfgidx;
|
|
+ /* Set configuration and Start the Class*/
|
|
+ if (pdev->class->init(pdev, cfgidx) != 0) {
|
|
+ usb_core_ctl_error(pdev);
|
|
+ return;
|
|
+ }
|
|
+ }
|
|
+ break;
|
|
+
|
|
+ default:
|
|
+ usb_core_ctl_error(pdev);
|
|
+ return;
|
|
+ }
|
|
+ /* Set EP0 State */
|
|
+ pdev->ep0_state = USBD_EP0_STATUS_IN;
|
|
+
|
|
+ /* Send status */
|
|
+ usb_core_transmit(pdev, 0, NULL, 0);
|
|
+ }
|
|
+}
|
|
+
|
|
+/*
|
|
+ * usb_core_get_status
|
|
+ * Handle Get Status request
|
|
+ * pdev : device instance
|
|
+ * req : usb request
|
|
+ * return : status
|
|
+ */
|
|
+static void usb_core_get_status(usb_handle_t *pdev, usb_setup_req_t *req)
|
|
+{
|
|
+ if ((pdev->dev_state == USBD_STATE_ADDRESSED) ||
|
|
+ (pdev->dev_state == USBD_STATE_CONFIGURED)) {
|
|
+ pdev->dev_config_status = USB_CONFIG_SELF_POWERED;
|
|
+
|
|
+ if (pdev->dev_remote_wakeup)
|
|
+ pdev->dev_config_status |= USB_CONFIG_REMOTE_WAKEUP;
|
|
+
|
|
+ /* Set EP0 State */
|
|
+ pdev->ep0_state = USBD_EP0_DATA_IN;
|
|
+ pdev->ep_in[0].total_length = 2;
|
|
+ pdev->ep_in[0].rem_length = 2;
|
|
+ /* Start the transfer */
|
|
+ usb_core_transmit(pdev, 0x00,
|
|
+ (uint8_t *)&pdev->dev_config_status, 2);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ usb_core_ctl_error(pdev);
|
|
+}
|
|
+
|
|
+/*
|
|
+ * usb_core_set_address
|
|
+ * Set device address
|
|
+ * pdev : device instance
|
|
+ * req : usb request
|
|
+ * return : status
|
|
+ */
|
|
+static void usb_core_set_address(usb_handle_t *pdev, usb_setup_req_t *req)
|
|
+{
|
|
+ if ((req->index == 0) && (req->length == 0)) {
|
|
+ uint8_t dev_addr = (uint8_t)(req->value) & 0x7F;
|
|
+
|
|
+ if (pdev->dev_state == USBD_STATE_CONFIGURED) {
|
|
+ usb_core_ctl_error(pdev);
|
|
+ } else {
|
|
+ pdev->dev_address = dev_addr;
|
|
+ pdev->driver->set_address(((pcd_handle_t *)
|
|
+ (pdev->data))->instance,
|
|
+ dev_addr);
|
|
+ /* Set EP0 State */
|
|
+ pdev->ep0_state = USBD_EP0_STATUS_IN;
|
|
+
|
|
+ /* Send status */
|
|
+ usb_core_transmit(pdev, 0, NULL, 0);
|
|
+
|
|
+ if (dev_addr != 0)
|
|
+ pdev->dev_state = USBD_STATE_ADDRESSED;
|
|
+ else
|
|
+ pdev->dev_state = USBD_STATE_DEFAULT;
|
|
+ }
|
|
+ } else {
|
|
+ usb_core_ctl_error(pdev);
|
|
+ }
|
|
+}
|
|
+
|
|
+/*
|
|
+ * usb_core_dev_req
|
|
+ * Handle standard usb device requests
|
|
+ * pdev : device instance
|
|
+ * req : usb request
|
|
+ * return : status
|
|
+ */
|
|
+static usb_status_t usb_core_dev_req(usb_handle_t *pdev, usb_setup_req_t *req)
|
|
+{
|
|
+ INFO("receive request %i\n", req->b_request);
|
|
+ switch (req->b_request) {
|
|
+ case USB_REQ_GET_DESCRIPTOR:
|
|
+ usb_core_get_desc(pdev, req);
|
|
+ break;
|
|
+
|
|
+ case USB_REQ_SET_CONFIGURATION:
|
|
+ usb_core_set_config(pdev, req);
|
|
+ break;
|
|
+
|
|
+ case USB_REQ_GET_STATUS:
|
|
+ usb_core_get_status(pdev, req);
|
|
+ break;
|
|
+ case USB_REQ_SET_ADDRESS:
|
|
+ usb_core_set_address(pdev, req);
|
|
+ break;
|
|
+ case USB_REQ_GET_CONFIGURATION:
|
|
+ case USB_REQ_SET_FEATURE:
|
|
+ case USB_REQ_CLEAR_FEATURE:
|
|
+ default:
|
|
+ ERROR("NOT SUPPORTED %i\n", req->b_request);
|
|
+ usb_core_ctl_error(pdev);
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ return USBD_OK;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * usb_core_itf_req
|
|
+ * Handle standard usb interface requests
|
|
+ * pdev : device instance
|
|
+ * req : usb request
|
|
+ * return : status
|
|
+ */
|
|
+static usb_status_t usb_core_itf_req(usb_handle_t *pdev, usb_setup_req_t *req)
|
|
+{
|
|
+ switch (pdev->dev_state) {
|
|
+ case USBD_STATE_CONFIGURED:
|
|
+ if (LOBYTE(req->index) <= USBD_MAX_NUM_INTERFACES) {
|
|
+ pdev->class->setup(pdev, req);
|
|
+
|
|
+ if (req->length == 0) {
|
|
+ /* Set EP0 State */
|
|
+ pdev->ep0_state = USBD_EP0_STATUS_IN;
|
|
+
|
|
+ usb_core_transmit(pdev, 0, NULL, 0);
|
|
+ }
|
|
+ } else {
|
|
+ usb_core_ctl_error(pdev);
|
|
+ }
|
|
+ break;
|
|
+
|
|
+ default:
|
|
+ usb_core_ctl_error(pdev);
|
|
+ break;
|
|
+ }
|
|
+ return USBD_OK;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * @brief USBD_ParseSetupRequest
|
|
+ * Copy buffer into setup structure
|
|
+ * @param pdev: device instance
|
|
+ * @param req: usb request
|
|
+ * @retval None
|
|
+ */
|
|
+static void usb_core_parse_req(usb_setup_req_t *req, uint8_t *pdata)
|
|
+{
|
|
+ req->bm_request = *(uint8_t *)(pdata);
|
|
+ req->b_request = *(uint8_t *)(pdata + 1);
|
|
+ req->value = SWAPBYTE(pdata + 2);
|
|
+ req->index = SWAPBYTE(pdata + 4);
|
|
+ req->length = SWAPBYTE(pdata + 6);
|
|
+}
|
|
+
|
|
+/*
|
|
+ * usb_core_setup_stage
|
|
+ * Handle the setup stage
|
|
+ * pdev: device instance
|
|
+ * return : status
|
|
+ */
|
|
+static usb_status_t usb_core_setup_stage(usb_handle_t *pdev, uint8_t *psetup)
|
|
+{
|
|
+ usb_core_parse_req(&pdev->request, psetup);
|
|
+
|
|
+ pdev->ep0_state = USBD_EP0_SETUP;
|
|
+ pdev->ep0_data_len = pdev->request.length;
|
|
+
|
|
+ switch (pdev->request.bm_request & 0x1F) {
|
|
+ case USB_REQ_RECIPIENT_DEVICE:
|
|
+ usb_core_dev_req(pdev, &pdev->request);
|
|
+ break;
|
|
+
|
|
+ case USB_REQ_RECIPIENT_INTERFACE:
|
|
+ usb_core_itf_req(pdev, &pdev->request);
|
|
+ break;
|
|
+
|
|
+ case USB_REQ_RECIPIENT_ENDPOINT:
|
|
+ default:
|
|
+ ERROR("receive unsupported request %i",
|
|
+ pdev->request.bm_request & 0x1F);
|
|
+ usb_core_set_stall(pdev, pdev->request.bm_request & 0x80);
|
|
+ return USBD_FAIL;
|
|
+ }
|
|
+ return USBD_OK;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * usb_core_data_out
|
|
+ * Handle data OUT stage
|
|
+ * pdev: device instance
|
|
+ * epnum: endpoint index
|
|
+ * return : status
|
|
+ */
|
|
+static usb_status_t usb_core_data_out(usb_handle_t *pdev, uint8_t epnum,
|
|
+ uint8_t *pdata)
|
|
+{
|
|
+ usb_endpoint_t *pep;
|
|
+
|
|
+ if (epnum == 0) {
|
|
+ pep = &pdev->ep_out[0];
|
|
+ if (pdev->ep0_state == USBD_EP0_DATA_OUT) {
|
|
+ if (pep->rem_length > pep->maxpacket) {
|
|
+ pep->rem_length -= pep->maxpacket;
|
|
+
|
|
+ usb_core_receive(pdev, 0, pdata,
|
|
+ MIN(pep->rem_length,
|
|
+ pep->maxpacket));
|
|
+ } else {
|
|
+ if (pdev->class->ep0_rx_ready &&
|
|
+ (pdev->dev_state == USBD_STATE_CONFIGURED))
|
|
+ pdev->class->ep0_rx_ready(pdev);
|
|
+
|
|
+ pdev->ep0_state = USBD_EP0_STATUS_IN;
|
|
+ usb_core_transmit(pdev, 0x00, NULL, 0);
|
|
+ }
|
|
+ }
|
|
+ } else if (pdev->class->data_out &&
|
|
+ (pdev->dev_state == USBD_STATE_CONFIGURED))
|
|
+ pdev->class->data_out(pdev, epnum);
|
|
+
|
|
+ return USBD_OK;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * usb_core_data_in
|
|
+ * Handle data in stage
|
|
+ * pdev: device instance
|
|
+ * epnum: endpoint index
|
|
+ * return : status
|
|
+ */
|
|
+static usb_status_t usb_core_data_in(usb_handle_t *pdev, uint8_t epnum,
|
|
+ uint8_t *pdata)
|
|
+{
|
|
+ if (epnum == 0) {
|
|
+ usb_endpoint_t *pep = &pdev->ep_in[0];
|
|
+
|
|
+ if (pdev->ep0_state == USBD_EP0_DATA_IN) {
|
|
+ if (pep->rem_length > pep->maxpacket) {
|
|
+ pep->rem_length -= pep->maxpacket;
|
|
+
|
|
+ usb_core_transmit(pdev, 0, pdata,
|
|
+ pep->rem_length);
|
|
+
|
|
+ /* Prepare endpoint for premature
|
|
+ * end of transfer
|
|
+ */
|
|
+ usb_core_receive(pdev, 0, NULL, 0);
|
|
+ } else {
|
|
+ /* last packet is MPS multiple,
|
|
+ * so send ZLP packet
|
|
+ */
|
|
+ if ((pep->total_length % pep->maxpacket == 0) &&
|
|
+ (pep->total_length >= pep->maxpacket) &&
|
|
+ (pep->total_length < pdev->ep0_data_len)) {
|
|
+ usb_core_transmit(pdev, 0, NULL, 0);
|
|
+
|
|
+ pdev->ep0_data_len = 0;
|
|
+
|
|
+ /* Prepare endpoint for premature
|
|
+ * end of transfer
|
|
+ */
|
|
+ usb_core_receive(pdev, 0, NULL, 0);
|
|
+ } else {
|
|
+ if (pdev->class->ep0_tx_sent &&
|
|
+ (pdev->dev_state ==
|
|
+ USBD_STATE_CONFIGURED))
|
|
+ pdev->class->ep0_tx_sent(pdev);
|
|
+
|
|
+ /* Set EP0 State */
|
|
+ pdev->ep0_state = USBD_EP0_STATUS_OUT;
|
|
+
|
|
+ /* Start the transfer */
|
|
+ usb_core_receive(pdev, 0, NULL, 0);
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ if (pdev->dev_test_mode == 1) {
|
|
+ ERROR("Not supported");
|
|
+ pdev->dev_test_mode = 0;
|
|
+ return USBD_FAIL;
|
|
+ }
|
|
+ } else if (pdev->class->data_in &&
|
|
+ (pdev->dev_state == USBD_STATE_CONFIGURED)) {
|
|
+ pdev->class->data_in(pdev, epnum);
|
|
+ }
|
|
+ return USBD_OK;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * usb_core_Suspend
|
|
+ * Handle Suspend event
|
|
+ * pdev : device instance
|
|
+ * return : status
|
|
+ */
|
|
+
|
|
+static usb_status_t usb_core_suspend(usb_handle_t *pdev)
|
|
+{
|
|
+ INFO("USB Suspend mode\n");
|
|
+
|
|
+ pdev->dev_old_state = pdev->dev_state;
|
|
+ pdev->dev_state = USBD_STATE_SUSPENDED;
|
|
+
|
|
+ return USBD_OK;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * usb_core_resume
|
|
+ * Handle Resume event
|
|
+ * pdev : device instance
|
|
+ * return : status
|
|
+ */
|
|
+
|
|
+static usb_status_t usb_core_resume(usb_handle_t *pdev)
|
|
+{
|
|
+ INFO("USB Resume\n");
|
|
+ pdev->dev_state = pdev->dev_old_state;
|
|
+
|
|
+ return USBD_OK;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * usb_core_sof
|
|
+ * Handle SOF event
|
|
+ * pdev : device instance
|
|
+ * return : status
|
|
+ */
|
|
+
|
|
+static usb_status_t usb_core_sof(usb_handle_t *pdev)
|
|
+{
|
|
+ if (pdev->dev_state == USBD_STATE_CONFIGURED) {
|
|
+ if (pdev->class->sof)
|
|
+ pdev->class->sof(pdev);
|
|
+ }
|
|
+
|
|
+ return USBD_OK;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * usb_core_DevDisconnected
|
|
+ * Handle device disconnection event
|
|
+ * pdev : device instance
|
|
+ * return : status
|
|
+ */
|
|
+static usb_status_t usb_core_disconnect(usb_handle_t *pdev)
|
|
+{
|
|
+ /* Free Class Resources */
|
|
+ pdev->dev_state = USBD_STATE_DEFAULT;
|
|
+ pdev->class->de_init(pdev, pdev->dev_config);
|
|
+
|
|
+ return USBD_OK;
|
|
+}
|
|
+
|
|
+usb_status_t usb_core_handle_it(usb_handle_t *pdev)
|
|
+{
|
|
+ uint32_t param = 0;
|
|
+ uint32_t len = 0;
|
|
+ usb_otg_ep_t *ep;
|
|
+
|
|
+ switch (pdev->driver->it_handler(pdev->data->instance, ¶m)) {
|
|
+ case USB_DATA_OUT:
|
|
+ usb_core_data_out(pdev, param,
|
|
+ pdev->data->out_ep[param].xfer_buff);
|
|
+ break;
|
|
+ case USB_DATA_IN:
|
|
+ usb_core_data_in(pdev, param,
|
|
+ pdev->data->in_ep[param].xfer_buff);
|
|
+ break;
|
|
+ case USB_SETUP:
|
|
+ usb_core_setup_stage(pdev, (uint8_t *)pdev->data->setup);
|
|
+ break;
|
|
+ case USB_ENUM_DONE:
|
|
+ pdev->data->init.speed = USB_OTG_SPEED_HIGH;
|
|
+ pdev->data->init.ep0_mps = USB_OTG_HS_MAX_PACKET_SIZE;
|
|
+ break;
|
|
+ case USB_READ_DATA_PACKET:
|
|
+ ep = &pdev->data->out_ep[param & USB_OTG_OUT_EPNUM_MASK];
|
|
+ len = (param & USB_OTG_OUT_COUNT_MASK) >> 0x10;
|
|
+ pdev->driver->read_packet(pdev->data->instance,
|
|
+ ep->xfer_buff, len);
|
|
+ ep->xfer_buff += len;
|
|
+ ep->xfer_count += len;
|
|
+ break;
|
|
+ case USB_READ_SETUP_PACKET:
|
|
+ ep = &pdev->data->out_ep[param & USB_OTG_OUT_EPNUM_MASK];
|
|
+ len = (param & USB_OTG_OUT_COUNT_MASK) >> 0x10;
|
|
+ pdev->driver->read_packet(pdev->data->instance,
|
|
+ (uint8_t *)pdev->data->setup, 8);
|
|
+ ep->xfer_count += len;
|
|
+ break;
|
|
+ case USB_RESUME:
|
|
+ if (pdev->data->lpm_state == LPM_L1)
|
|
+ pdev->data->lpm_state = LPM_L0;
|
|
+ else
|
|
+ usb_core_resume(pdev);
|
|
+ break;
|
|
+ case USB_SUSPEND:
|
|
+ usb_core_suspend(pdev);
|
|
+ break;
|
|
+ case USB_LPM:
|
|
+ if (pdev->data->lpm_state == LPM_L0) {
|
|
+ pdev->data->lpm_state = LPM_L1;
|
|
+ pdev->data->besl = param;
|
|
+ } else {
|
|
+ usb_core_suspend(pdev);
|
|
+ }
|
|
+ break;
|
|
+ case USB_SOF:
|
|
+ usb_core_sof(pdev);
|
|
+ break;
|
|
+ case USB_DISCONNECT:
|
|
+ usb_core_disconnect(pdev);
|
|
+ break;
|
|
+ case USB_WRITE_EMPTY:
|
|
+ pdev->driver->write_empty_tx_fifo(pdev->data->instance, param,
|
|
+ pdev->data->in_ep[param].xfer_len,
|
|
+ (uint32_t *)
|
|
+ &pdev->data->in_ep[param].xfer_count,
|
|
+ pdev->data->in_ep[param].maxpacket,
|
|
+ &pdev->data->in_ep[param].xfer_buff);
|
|
+ break;
|
|
+ case USB_NOTHING:
|
|
+ default:
|
|
+ break;
|
|
+ }
|
|
+ return USBD_OK;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * @brief Receive an amount of data
|
|
+ * @param hpcd: PCD handle
|
|
+ * @param ep_addr: endpoint address
|
|
+ * @param pBuf: pointer to the reception buffer
|
|
+ * @param len: amount of data to be received
|
|
+ * @retval HAL status
|
|
+ */
|
|
+usb_status_t usb_core_receive(usb_handle_t *pdev, uint8_t ep_addr,
|
|
+ uint8_t *buf, uint32_t len)
|
|
+{
|
|
+ usb_otg_ep_t *ep;
|
|
+ pcd_handle_t *hpcd = (pcd_handle_t *)pdev->data;
|
|
+
|
|
+ ep = &hpcd->out_ep[ep_addr & 0x7F];
|
|
+
|
|
+ /*setup and start the Xfer */
|
|
+ ep->xfer_buff = buf;
|
|
+ ep->xfer_len = len;
|
|
+ ep->xfer_count = 0;
|
|
+ ep->is_in = 0;
|
|
+ ep->num = ep_addr & 0x7F;
|
|
+
|
|
+ if ((ep_addr & 0x7F) == 0)
|
|
+ pdev->driver->ep0_start_xfer(hpcd->instance, ep);
|
|
+ else
|
|
+ pdev->driver->ep_start_xfer(hpcd->instance, ep);
|
|
+
|
|
+ return USBD_OK;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * @brief Send an amount of data
|
|
+ * @param hpcd: PCD handle
|
|
+ * @param ep_addr: endpoint address
|
|
+ * @param pBuf: pointer to the transmission buffer
|
|
+ * @param len: amount of data to be sent
|
|
+ * @retval HAL status
|
|
+ */
|
|
+usb_status_t usb_core_transmit(usb_handle_t *pdev, uint8_t ep_addr,
|
|
+ uint8_t *buf, uint32_t len)
|
|
+{
|
|
+ usb_otg_ep_t *ep;
|
|
+ pcd_handle_t *hpcd = (pcd_handle_t *)pdev->data;
|
|
+
|
|
+ ep = &hpcd->in_ep[ep_addr & 0x7F];
|
|
+
|
|
+ /*setup and start the Xfer */
|
|
+ ep->xfer_buff = buf;
|
|
+ ep->xfer_len = len;
|
|
+ ep->xfer_count = 0;
|
|
+ ep->is_in = 1;
|
|
+ ep->num = ep_addr & 0x7F;
|
|
+
|
|
+ if ((ep_addr & 0x7F) == 0)
|
|
+ pdev->driver->ep0_start_xfer(hpcd->instance, ep);
|
|
+ else
|
|
+ pdev->driver->ep_start_xfer(hpcd->instance, ep);
|
|
+
|
|
+ return USBD_OK;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * @brief usb_core_ctl_error
|
|
+ * Handle USB low level Error
|
|
+ * @param pdev: device instance
|
|
+ * @param req: usb request
|
|
+ * @retval None
|
|
+ */
|
|
+
|
|
+void usb_core_ctl_error(usb_handle_t *pdev)
|
|
+{
|
|
+ ERROR("%s : Send an ERROR\n", __func__);
|
|
+ usb_core_set_stall(pdev, 0x80);
|
|
+ usb_core_set_stall(pdev, 0);
|
|
+}
|
|
+
|
|
+/*
|
|
+ * usb_core_stop
|
|
+ * Stop the USB Device Core.
|
|
+ * pdev: Device Handle
|
|
+ * return : USBD Status
|
|
+ */
|
|
+usb_status_t usb_core_stop(usb_handle_t *pdev)
|
|
+{
|
|
+ /* Free Class Resources */
|
|
+ pdev->class->de_init(pdev, pdev->dev_config);
|
|
+
|
|
+ /* Stop the low level driver */
|
|
+ pdev->driver->disable_int(pdev->data->instance);
|
|
+ pdev->driver->stop_device(pdev->data->instance);
|
|
+ pdev->driver->dev_disconnect(pdev->data->instance);
|
|
+ return USBD_OK;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * usb_core_stop
|
|
+ * Stop the USB Device Core.
|
|
+ * pdev: Device Handle
|
|
+ * return : USBD Status
|
|
+ */
|
|
+usb_status_t register_usb_driver(usb_handle_t *pdev, const usb_driver_t *driver,
|
|
+ void *driver_handle)
|
|
+{
|
|
+ /* Free Class Resources */
|
|
+ pdev->driver = driver;
|
|
+ pdev->data->instance = driver_handle;
|
|
+ return USBD_OK;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * usb_core_stop
|
|
+ * Stop the USB Device Core.
|
|
+ * pdev: Device Handle
|
|
+ * return : USBD Status
|
|
+ */
|
|
+usb_status_t register_platform(usb_handle_t *pdev,
|
|
+ const usb_desc_t *plat_call_back)
|
|
+{
|
|
+ /* Free Class Resources */
|
|
+ pdev->desc = plat_call_back;
|
|
+ return USBD_OK;
|
|
+}
|
|
diff --git a/lib/usb/usb_st_dfu.c b/lib/usb/usb_st_dfu.c
|
|
new file mode 100644
|
|
index 0000000..2cf01f6
|
|
--- /dev/null
|
|
+++ b/lib/usb/usb_st_dfu.c
|
|
@@ -0,0 +1,865 @@
|
|
+/*
|
|
+ * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved.
|
|
+ *
|
|
+ * SPDX-License-Identifier: BSD-3-Clause
|
|
+ */
|
|
+
|
|
+#include <debug.h>
|
|
+#include <stm32mp1_usb_desc.h>
|
|
+#include <string.h>
|
|
+#include <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:
|
|
+ INFO("Receive DFU detach\n");
|
|
+ break;
|
|
+
|
|
+ default:
|
|
+ ERROR("phase ID :%i\n", DFU_GET_PHASE);
|
|
+ usb_core_ctl_error(pdev);
|
|
+ ret = USBD_FAIL;
|
|
+ break;
|
|
+ }
|
|
+ } else {
|
|
+ ERROR("Unknown alternate : %i\n", hdfu->alt_setting);
|
|
+ ret = USBD_FAIL;
|
|
+ }
|
|
+ break;
|
|
+ case USB_REQ_TYPE_STANDARD:
|
|
+ switch (req->b_request) {
|
|
+ case USB_REQ_GET_DESCRIPTOR:
|
|
+ if ((req->value >> 8) == DFU_DESCRIPTOR_TYPE) {
|
|
+ pbuf = pdev->desc->get_dfu_desc(&len);
|
|
+ len = MIN(len, req->length);
|
|
+ }
|
|
+
|
|
+ pdev->ep0_state = USBD_EP0_DATA_IN;
|
|
+ pdev->ep_in[0].total_length = len;
|
|
+ pdev->ep_in[0].rem_length = len;
|
|
+ /* Start the transfer */
|
|
+ usb_core_transmit(pdev, 0x00, pbuf, len);
|
|
+
|
|
+ break;
|
|
+
|
|
+ case USB_REQ_GET_INTERFACE:
|
|
+ pdev->ep0_state = USBD_EP0_DATA_IN;
|
|
+ pdev->ep_in[0].total_length = 1;
|
|
+ pdev->ep_in[0].rem_length = 1;
|
|
+ /* Start the transfer */
|
|
+ usb_core_transmit(pdev, 0x00,
|
|
+ (uint8_t *)&hdfu->alt_setting, 1);
|
|
+ break;
|
|
+
|
|
+ case USB_REQ_SET_INTERFACE:
|
|
+ hdfu->alt_setting = (uint8_t)(req->value);
|
|
+ break;
|
|
+
|
|
+ default:
|
|
+ usb_core_ctl_error(pdev);
|
|
+ ret = USBD_FAIL;
|
|
+ break;
|
|
+ }
|
|
+ default:
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static const usb_class_t USBD_DFU_initvalue = {
|
|
+ usb_dfu_init,
|
|
+ usb_dfu_de_init,
|
|
+ usb_dfu_setup,
|
|
+ usb_dfu_ep0_tx_ready,
|
|
+ usb_dfu_ep0_rx_ready,
|
|
+ usb_dfu_data_in,
|
|
+ usb_dfu_data_out,
|
|
+ usb_dfu_sof,
|
|
+ usb_dfu_iso_in_incomplete,
|
|
+ usb_dfu_iso_out_incomplete,
|
|
+ 0
|
|
+};
|
|
+
|
|
+void usb_dfu_register_callback(usb_handle_t *pdev)
|
|
+{
|
|
+ pdev->class = (usb_class_t *)&USBD_DFU_initvalue;
|
|
+}
|
|
+
|
|
+void usb_dfu_set_phase_id(uint32_t phase_id)
|
|
+{
|
|
+ usbd_dfu_phase_id = phase_id;
|
|
+ usbd_dfu_operation_complete = 0;
|
|
+}
|
|
+
|
|
+void usb_dfu_set_download_addr(uintptr_t addr)
|
|
+{
|
|
+ usbd_dfu_download_address = addr;
|
|
+}
|
|
+
|
|
+uint32_t usb_dfu_download_is_completed(void)
|
|
+{
|
|
+ return usbd_dfu_operation_complete;
|
|
+}
|
|
+
|
|
+uint32_t usb_dfu_get_current_req(void)
|
|
+{
|
|
+ return usbd_dfu_current_req;
|
|
+}
|
|
+
|
|
+uint32_t usb_dfu_detach_req(void)
|
|
+{
|
|
+ return usbd_detach_req;
|
|
+}
|
|
+
|
|
+void usb_dfu_request_detach(void)
|
|
+{
|
|
+ usbd_detach_req = 1;
|
|
+}
|
|
diff --git a/lib/xlat_tables/aarch32/xlat_tables.c b/lib/xlat_tables/aarch32/xlat_tables.c
|
|
index 5595703..27e7207 100644
|
|
--- a/lib/xlat_tables/aarch32/xlat_tables.c
|
|
+++ b/lib/xlat_tables/aarch32/xlat_tables.c
|
|
@@ -23,8 +23,17 @@
|
|
#define NUM_BASE_LEVEL_ENTRIES \
|
|
GET_NUM_BASE_LEVEL_ENTRIES(PLAT_VIRT_ADDR_SPACE_SIZE)
|
|
|
|
+#ifdef PLAT_BASE_XLAT_BASE
|
|
+CASSERT(!(PLAT_BASE_XLAT_BASE &
|
|
+ (NUM_BASE_LEVEL_ENTRIES * sizeof(uint64_t) - 1)),
|
|
+ invalid_plat_base_xlat_base);
|
|
+CASSERT(PLAT_BASE_XLAT_SIZE == sizeof(uint64_t) * NUM_BASE_LEVEL_ENTRIES,
|
|
+ invalid_plat_base_xlat_size);
|
|
+static uint64_t *base_xlation_table = (uint64_t *)PLAT_BASE_XLAT_BASE;
|
|
+#else
|
|
static uint64_t base_xlation_table[NUM_BASE_LEVEL_ENTRIES]
|
|
__aligned(NUM_BASE_LEVEL_ENTRIES * sizeof(uint64_t));
|
|
+#endif
|
|
|
|
#if ENABLE_ASSERTIONS
|
|
static unsigned long long get_max_supported_pa(void)
|
|
diff --git a/lib/xlat_tables/aarch64/xlat_tables.c b/lib/xlat_tables/aarch64/xlat_tables.c
|
|
index 4afdeed..309fda1 100644
|
|
--- a/lib/xlat_tables/aarch64/xlat_tables.c
|
|
+++ b/lib/xlat_tables/aarch64/xlat_tables.c
|
|
@@ -22,6 +22,10 @@
|
|
#define NUM_BASE_LEVEL_ENTRIES \
|
|
GET_NUM_BASE_LEVEL_ENTRIES(PLAT_VIRT_ADDR_SPACE_SIZE)
|
|
|
|
+#ifdef PLAT_BASE_XLAT_BASE
|
|
+#error "PLAT_BASE_XLAT_BASE is not allowed on AArch64 capable architectures"
|
|
+#endif
|
|
+
|
|
static uint64_t base_xlation_table[NUM_BASE_LEVEL_ENTRIES]
|
|
__aligned(NUM_BASE_LEVEL_ENTRIES * sizeof(uint64_t));
|
|
|
|
diff --git a/lib/xlat_tables/xlat_tables_common.c b/lib/xlat_tables/xlat_tables_common.c
|
|
index ca67f2a..9c903f9 100644
|
|
--- a/lib/xlat_tables/xlat_tables_common.c
|
|
+++ b/lib/xlat_tables/xlat_tables_common.c
|
|
@@ -35,8 +35,17 @@
|
|
#define UNSET_DESC ~0ULL
|
|
#define MT_UNKNOWN ~0U
|
|
|
|
+#ifdef PLAT_XLAT_BASE
|
|
+#define XLAT_TABLE_REQUIRED_ENTRIES (XLAT_TABLE_ENTRIES * MAX_XLAT_TABLES)
|
|
+CASSERT(PLAT_XLAT_SIZE == sizeof(uint64_t) * XLAT_TABLE_REQUIRED_ENTRIES,
|
|
+ invalid_plat_xlat_size);
|
|
+CASSERT(!(PLAT_XLAT_BASE & (XLAT_TABLE_SIZE - 1)), invalid_plat_xlat_base);
|
|
+#define xlat_tables ((uint64_t (*)[XLAT_TABLE_ENTRIES]) \
|
|
+ (unsigned long *)PLAT_XLAT_BASE)
|
|
+#else
|
|
static uint64_t xlat_tables[MAX_XLAT_TABLES][XLAT_TABLE_ENTRIES]
|
|
__aligned(XLAT_TABLE_SIZE) __section("xlat_table");
|
|
+#endif
|
|
|
|
static unsigned int next_xlat;
|
|
static unsigned long long xlat_max_pa;
|
|
@@ -408,6 +417,15 @@ void init_xlation_table(uintptr_t base_va, uint64_t *table,
|
|
ap1_mask = 0ULL;
|
|
}
|
|
|
|
+#ifdef PLAT_BASE_XLAT_BASE
|
|
+ inv_dcache_range(PLAT_BASE_XLAT_BASE, PLAT_BASE_XLAT_SIZE);
|
|
+ zeromem((void *)PLAT_BASE_XLAT_BASE, PLAT_BASE_XLAT_SIZE);
|
|
+#endif
|
|
+#ifdef PLAT_XLAT_BASE
|
|
+ inv_dcache_range(PLAT_XLAT_BASE, PLAT_XLAT_SIZE);
|
|
+ zeromem((void *)PLAT_XLAT_BASE, PLAT_XLAT_SIZE);
|
|
+#endif
|
|
+
|
|
init_xlation_table_inner(mmap, base_va, table, level);
|
|
*max_va = xlat_max_va;
|
|
*max_pa = xlat_max_pa;
|
|
diff --git a/lib/xlat_tables_v2/xlat_tables_core.c b/lib/xlat_tables_v2/xlat_tables_core.c
|
|
index 003718e..a410ad6 100644
|
|
--- a/lib/xlat_tables_v2/xlat_tables_core.c
|
|
+++ b/lib/xlat_tables_v2/xlat_tables_core.c
|
|
@@ -1026,7 +1026,12 @@ void init_xlat_tables_ctx(xlat_ctx_t *ctx)
|
|
xlat_mmap_print(mm);
|
|
|
|
/* All tables must be zeroed before mapping any region. */
|
|
-
|
|
+#ifdef PLAT_BASE_XLAT_BASE
|
|
+ inv_dcache_range(PLAT_BASE_XLAT_BASE, PLAT_BASE_XLAT_SIZE);
|
|
+#endif
|
|
+#ifdef PLAT_XLAT_BASE
|
|
+ inv_dcache_range(PLAT_XLAT_BASE, PLAT_XLAT_SIZE);
|
|
+#endif
|
|
for (unsigned int i = 0U; i < ctx->base_table_entries; i++)
|
|
ctx->base_table[i] = INVALID_DESC;
|
|
|
|
diff --git a/make_helpers/build_macros.mk b/make_helpers/build_macros.mk
|
|
index 92a0f6e..44c537b 100644
|
|
--- a/make_helpers/build_macros.mk
|
|
+++ b/make_helpers/build_macros.mk
|
|
@@ -450,17 +450,24 @@ endef
|
|
# $(2) = input dts
|
|
define MAKE_DTB
|
|
|
|
+# List of DTB file(s) to generate, based on DTS file basename list
|
|
$(eval DOBJ := $(addprefix $(1)/,$(call SOURCES_TO_DTBS,$(2))))
|
|
+# List of the pre-compiled DTS file(s)
|
|
$(eval DPRE := $(addprefix $(1)/,$(patsubst %.dts,%.pre.dts,$(notdir $(2)))))
|
|
-$(eval DEP := $(patsubst %.dtb,%.d,$(DOBJ)))
|
|
+# Dependencies of the pre-compiled DTS file(s) on its source and included files
|
|
+$(eval DTSDEP := $(patsubst %.dtb,%.o.d,$(DOBJ)))
|
|
+# Dependencies of the DT compilation on its pre-compiled DTS
|
|
+$(eval DTBDEP := $(patsubst %.dtb,%.d,$(DOBJ)))
|
|
|
|
$(DOBJ): $(2) $(filter-out %.d,$(MAKEFILE_LIST)) | fdt_dirs
|
|
@echo " CPP $$<"
|
|
- $$(Q)$$(CPP) $$(CPPFLAGS) -x assembler-with-cpp -o $(DPRE) $$<
|
|
+ $(eval DTBS := $(addprefix $(1)/,$(call SOURCES_TO_DTBS,$(2))))
|
|
+ $$(Q)$$(CPP) $$(CPPFLAGS) -x assembler-with-cpp -MT $(DTBS) -MMD -MF $(DTSDEP) -o $(DPRE) $$<
|
|
@echo " DTC $$<"
|
|
- $$(Q)$$(DTC) $$(DTC_FLAGS) -i fdts -d $(DEP) -o $$@ $(DPRE)
|
|
+ $$(Q)$$(DTC) $$(DTC_FLAGS) -i fdts -d $(DTBDEP) -o $$@ $(DPRE)
|
|
|
|
--include $(DEP)
|
|
+-include $(DTBDEP)
|
|
+-include $(DTSDEP)
|
|
|
|
endef
|
|
|
|
diff --git a/make_helpers/defaults.mk b/make_helpers/defaults.mk
|
|
index 7df4cd2..0ade4e7 100644
|
|
--- a/make_helpers/defaults.mk
|
|
+++ b/make_helpers/defaults.mk
|
|
@@ -79,6 +79,9 @@ ENABLE_STACK_PROTECTOR := 0
|
|
# Flag to enable exception handling in EL3
|
|
EL3_EXCEPTION_HANDLING := 0
|
|
|
|
+# Flag to enable exception debug for AARCH32
|
|
+AARCH32_EXCEPTION_DEBUG := 0
|
|
+
|
|
# Build flag to treat usage of deprecated platform and framework APIs as error.
|
|
ERROR_DEPRECATED := 0
|
|
|
|
diff --git a/plat/arm/common/aarch32/arm_helpers.S b/plat/arm/common/aarch32/arm_helpers.S
|
|
index c4cfa8a..badddd3 100644
|
|
--- a/plat/arm/common/aarch32/arm_helpers.S
|
|
+++ b/plat/arm/common/aarch32/arm_helpers.S
|
|
@@ -48,7 +48,7 @@ func plat_crash_console_init
|
|
ldr r0, =PLAT_ARM_CRASH_UART_BASE
|
|
ldr r1, =PLAT_ARM_CRASH_UART_CLK_IN_HZ
|
|
ldr r2, =ARM_CONSOLE_BAUDRATE
|
|
- b console_core_init
|
|
+ b console_pl011_core_init
|
|
endfunc plat_crash_console_init
|
|
|
|
/* ---------------------------------------------
|
|
@@ -60,7 +60,7 @@ endfunc plat_crash_console_init
|
|
*/
|
|
func plat_crash_console_putc
|
|
ldr r1, =PLAT_ARM_CRASH_UART_BASE
|
|
- b console_core_putc
|
|
+ b console_pl011_core_putc
|
|
endfunc plat_crash_console_putc
|
|
|
|
/* ---------------------------------------------
|
|
@@ -73,5 +73,5 @@ endfunc plat_crash_console_putc
|
|
*/
|
|
func plat_crash_console_flush
|
|
ldr r0, =PLAT_ARM_CRASH_UART_BASE
|
|
- b console_core_flush
|
|
+ b console_pl011_core_flush
|
|
endfunc plat_crash_console_flush
|
|
diff --git a/plat/arm/common/arm_common.mk b/plat/arm/common/arm_common.mk
|
|
index a8df5ba..9d31f08 100644
|
|
--- a/plat/arm/common/arm_common.mk
|
|
+++ b/plat/arm/common/arm_common.mk
|
|
@@ -123,9 +123,7 @@ ENABLE_PMF := 1
|
|
SEPARATE_CODE_AND_RODATA := 1
|
|
|
|
# Use the multi console API, which is only available for AArch64 for now
|
|
-ifeq (${ARCH}, aarch64)
|
|
- MULTI_CONSOLE_API := 1
|
|
-endif
|
|
+MULTI_CONSOLE_API := 1
|
|
|
|
# Disable ARM Cryptocell by default
|
|
ARM_CRYPTOCELL_INTEG := 0
|
|
diff --git a/plat/arm/common/sp_min/arm_sp_min_setup.c b/plat/arm/common/sp_min/arm_sp_min_setup.c
|
|
index 10c1914..b8234c1 100644
|
|
--- a/plat/arm/common/sp_min/arm_sp_min_setup.c
|
|
+++ b/plat/arm/common/sp_min/arm_sp_min_setup.c
|
|
@@ -9,6 +9,7 @@
|
|
#include <console.h>
|
|
#include <debug.h>
|
|
#include <mmio.h>
|
|
+#include <pl011.h>
|
|
#include <plat_arm.h>
|
|
#include <platform.h>
|
|
#include <platform_def.h>
|
|
@@ -61,8 +62,7 @@ void arm_sp_min_early_platform_setup(void *from_bl2, uintptr_t tos_fw_config,
|
|
uintptr_t hw_config, void *plat_params_from_bl2)
|
|
{
|
|
/* Initialize the console to provide early debug support */
|
|
- console_init(PLAT_ARM_BOOT_UART_BASE, PLAT_ARM_BOOT_UART_CLK_IN_HZ,
|
|
- ARM_CONSOLE_BAUDRATE);
|
|
+ arm_console_boot_init();
|
|
|
|
#if RESET_TO_SP_MIN
|
|
/* There are no parameters from BL2 if SP_MIN is a reset vector */
|
|
@@ -152,8 +152,7 @@ void sp_min_early_platform_setup2(u_register_t arg0, u_register_t arg1,
|
|
void arm_sp_min_plat_runtime_setup(void)
|
|
{
|
|
/* Initialize the runtime console */
|
|
- console_init(PLAT_ARM_SP_MIN_RUN_UART_BASE,
|
|
- PLAT_ARM_SP_MIN_RUN_UART_CLK_IN_HZ, ARM_CONSOLE_BAUDRATE);
|
|
+ arm_console_runtime_init();
|
|
}
|
|
|
|
/*******************************************************************************
|
|
diff --git a/plat/common/aarch32/crash_console_helpers.S b/plat/common/aarch32/crash_console_helpers.S
|
|
new file mode 100644
|
|
index 0000000..fc37c08
|
|
--- /dev/null
|
|
+++ b/plat/common/aarch32/crash_console_helpers.S
|
|
@@ -0,0 +1,92 @@
|
|
+/*
|
|
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
|
|
+ *
|
|
+ * SPDX-License-Identifier: BSD-3-Clause
|
|
+ */
|
|
+
|
|
+/*
|
|
+ * If a platform wishes to use the functions in this file it has to be added to
|
|
+ * the Makefile of the platform. It is not included in the common Makefile.
|
|
+ */
|
|
+
|
|
+#include <asm_macros.S>
|
|
+#include <console.h>
|
|
+
|
|
+ .globl plat_crash_console_init
|
|
+ .globl plat_crash_console_putc
|
|
+ .globl plat_crash_console_flush
|
|
+
|
|
+#if MULTI_CONSOLE_API
|
|
+
|
|
+ /* -----------------------------------------------------
|
|
+ * int plat_crash_console_init(void)
|
|
+ * Use normal console by default. Switch it to crash
|
|
+ * mode so serial consoles become active again.
|
|
+ * NOTE: This default implementation will only work for
|
|
+ * crashes that occur after a normal console (marked
|
|
+ * valid for the crash state) has been registered with
|
|
+ * the console framework. To debug crashes that occur
|
|
+ * earlier, the platform has to override these functions
|
|
+ * with an implementation that initializes a console
|
|
+ * driver with hardcoded parameters. See
|
|
+ * docs/porting-guide.rst for more information.
|
|
+ * -----------------------------------------------------
|
|
+ */
|
|
+func plat_crash_console_init
|
|
+#if defined(IMAGE_BL1)
|
|
+ /*
|
|
+ * BL1 code can possibly crash so early that the data segment is not yet
|
|
+ * accessible. Don't risk undefined behavior by trying to run the normal
|
|
+ * console framework. Platforms that want to debug BL1 will need to
|
|
+ * override this with custom functions that can run from registers only.
|
|
+ */
|
|
+ mov r0, #0
|
|
+ bx lr
|
|
+#else /* IMAGE_BL1 */
|
|
+ mov r3, lr
|
|
+ mov r0, #CONSOLE_FLAG_CRASH
|
|
+ bl console_switch_state
|
|
+ mov r0, #1
|
|
+ bx r3
|
|
+#endif
|
|
+endfunc plat_crash_console_init
|
|
+
|
|
+ /* -----------------------------------------------------
|
|
+ * void plat_crash_console_putc(int character)
|
|
+ * Output through the normal console by default.
|
|
+ * -----------------------------------------------------
|
|
+ */
|
|
+func plat_crash_console_putc
|
|
+ b console_putc
|
|
+endfunc plat_crash_console_putc
|
|
+
|
|
+ /* -----------------------------------------------------
|
|
+ * void plat_crash_console_flush(void)
|
|
+ * Flush normal console by default.
|
|
+ * -----------------------------------------------------
|
|
+ */
|
|
+func plat_crash_console_flush
|
|
+ b console_flush
|
|
+endfunc plat_crash_console_flush
|
|
+
|
|
+#else /* MULTI_CONSOLE_API */
|
|
+
|
|
+ /* -----------------------------------------------------
|
|
+ * In the old API these are all no-op stubs that need to
|
|
+ * be overridden by the platform to be useful.
|
|
+ * -----------------------------------------------------
|
|
+ */
|
|
+func plat_crash_console_init
|
|
+ mov r0, #0
|
|
+ bx lr
|
|
+endfunc plat_crash_console_init
|
|
+
|
|
+func plat_crash_console_putc
|
|
+ bx lr
|
|
+endfunc plat_crash_console_putc
|
|
+
|
|
+func plat_crash_console_flush
|
|
+ bx lr
|
|
+endfunc plat_crash_console_flush
|
|
+
|
|
+#endif
|
|
diff --git a/plat/common/aarch32/plat_sp_min_common.c b/plat/common/aarch32/plat_sp_min_common.c
|
|
index a9a92c7..f1b1e9c 100644
|
|
--- a/plat/common/aarch32/plat_sp_min_common.c
|
|
+++ b/plat/common/aarch32/plat_sp_min_common.c
|
|
@@ -21,5 +21,9 @@ void sp_min_plat_runtime_setup(void)
|
|
* Finish the use of console driver in SP_MIN so that any runtime logs
|
|
* from SP_MIN will be suppressed.
|
|
*/
|
|
+#if MULTI_CONSOLE_API
|
|
+ console_switch_state(CONSOLE_FLAG_RUNTIME);
|
|
+#else
|
|
console_uninit();
|
|
+#endif
|
|
}
|
|
diff --git a/plat/common/aarch32/platform_helpers.S b/plat/common/aarch32/platform_helpers.S
|
|
index d618539..91ddc47 100644
|
|
--- a/plat/common/aarch32/platform_helpers.S
|
|
+++ b/plat/common/aarch32/platform_helpers.S
|
|
@@ -8,9 +8,16 @@
|
|
#include <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
|
|
+#if !ERROR_DEPRECATED
|
|
.weak plat_crash_console_init
|
|
.weak plat_crash_console_putc
|
|
.weak plat_crash_console_flush
|
|
+#endif
|
|
.weak plat_reset_handler
|
|
.weak plat_disable_acp
|
|
.weak bl1_plat_prepare_exit
|
|
@@ -26,6 +33,36 @@ func plat_report_exception
|
|
bx lr
|
|
endfunc plat_report_exception
|
|
|
|
+#if AARCH32_EXCEPTION_DEBUG
|
|
+ /* -----------------------------------------------------
|
|
+ * Placeholder function which should be redefined by
|
|
+ * each platform.
|
|
+ * -----------------------------------------------------
|
|
+ */
|
|
+func plat_report_undef_inst
|
|
+ bx lr
|
|
+endfunc plat_report_undef_inst
|
|
+
|
|
+ /* -----------------------------------------------------
|
|
+ * Placeholder function which should be redefined by
|
|
+ * each platform.
|
|
+ * -----------------------------------------------------
|
|
+ */
|
|
+func plat_report_prefetch_abort
|
|
+ bx lr
|
|
+endfunc plat_report_prefetch_abort
|
|
+
|
|
+ /* -----------------------------------------------------
|
|
+ * Placeholder function which should be redefined by
|
|
+ * each platform.
|
|
+ * -----------------------------------------------------
|
|
+ */
|
|
+func plat_report_data_abort
|
|
+ bx lr
|
|
+endfunc plat_report_data_abort
|
|
+#endif
|
|
+
|
|
+#if !ERROR_DEPRECATED
|
|
/* -----------------------------------------------------
|
|
* Placeholder function which should be redefined by
|
|
* each platform.
|
|
@@ -54,6 +91,7 @@ func plat_crash_console_flush
|
|
mov r0, #0
|
|
bx lr
|
|
endfunc plat_crash_console_flush
|
|
+#endif
|
|
|
|
/* -----------------------------------------------------
|
|
* Placeholder function which should be redefined by
|
|
diff --git a/plat/common/aarch64/crash_console_helpers.S b/plat/common/aarch64/crash_console_helpers.S
|
|
new file mode 100644
|
|
index 0000000..5af8db2
|
|
--- /dev/null
|
|
+++ b/plat/common/aarch64/crash_console_helpers.S
|
|
@@ -0,0 +1,92 @@
|
|
+/*
|
|
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
|
|
+ *
|
|
+ * SPDX-License-Identifier: BSD-3-Clause
|
|
+ */
|
|
+
|
|
+/*
|
|
+ * If a platform wishes to use the functions in this file it has to be added to
|
|
+ * the Makefile of the platform. It is not included in the common Makefile.
|
|
+ */
|
|
+
|
|
+#include <asm_macros.S>
|
|
+#include <console.h>
|
|
+
|
|
+ .globl plat_crash_console_init
|
|
+ .globl plat_crash_console_putc
|
|
+ .globl plat_crash_console_flush
|
|
+
|
|
+#if MULTI_CONSOLE_API
|
|
+
|
|
+ /* -----------------------------------------------------
|
|
+ * int plat_crash_console_init(void)
|
|
+ * Use normal console by default. Switch it to crash
|
|
+ * mode so serial consoles become active again.
|
|
+ * NOTE: This default implementation will only work for
|
|
+ * crashes that occur after a normal console (marked
|
|
+ * valid for the crash state) has been registered with
|
|
+ * the console framework. To debug crashes that occur
|
|
+ * earlier, the platform has to override these functions
|
|
+ * with an implementation that initializes a console
|
|
+ * driver with hardcoded parameters. See
|
|
+ * docs/porting-guide.rst for more information.
|
|
+ * -----------------------------------------------------
|
|
+ */
|
|
+func plat_crash_console_init
|
|
+#if defined(IMAGE_BL1)
|
|
+ /*
|
|
+ * BL1 code can possibly crash so early that the data segment is not yet
|
|
+ * accessible. Don't risk undefined behavior by trying to run the normal
|
|
+ * console framework. Platforms that want to debug BL1 will need to
|
|
+ * override this with custom functions that can run from registers only.
|
|
+ */
|
|
+ mov x0, #0
|
|
+ ret
|
|
+#else /* IMAGE_BL1 */
|
|
+ mov x3, x30
|
|
+ mov x0, #CONSOLE_FLAG_CRASH
|
|
+ bl console_switch_state
|
|
+ mov x0, #1
|
|
+ ret x3
|
|
+#endif
|
|
+endfunc plat_crash_console_init
|
|
+
|
|
+ /* -----------------------------------------------------
|
|
+ * void plat_crash_console_putc(int character)
|
|
+ * Output through the normal console by default.
|
|
+ * -----------------------------------------------------
|
|
+ */
|
|
+func plat_crash_console_putc
|
|
+ b console_putc
|
|
+endfunc plat_crash_console_putc
|
|
+
|
|
+ /* -----------------------------------------------------
|
|
+ * void plat_crash_console_flush(void)
|
|
+ * Flush normal console by default.
|
|
+ * -----------------------------------------------------
|
|
+ */
|
|
+func plat_crash_console_flush
|
|
+ b console_flush
|
|
+endfunc plat_crash_console_flush
|
|
+
|
|
+#else /* MULTI_CONSOLE_API */
|
|
+
|
|
+ /* -----------------------------------------------------
|
|
+ * In the old API these are all no-op stubs that need to
|
|
+ * be overridden by the platform to be useful.
|
|
+ * -----------------------------------------------------
|
|
+ */
|
|
+func plat_crash_console_init
|
|
+ mov x0, #0
|
|
+ ret
|
|
+endfunc plat_crash_console_init
|
|
+
|
|
+func plat_crash_console_putc
|
|
+ ret
|
|
+endfunc plat_crash_console_putc
|
|
+
|
|
+func plat_crash_console_flush
|
|
+ ret
|
|
+endfunc plat_crash_console_flush
|
|
+
|
|
+#endif
|
|
diff --git a/plat/common/aarch64/platform_helpers.S b/plat/common/aarch64/platform_helpers.S
|
|
index 7214588..d3ffcaf 100644
|
|
--- a/plat/common/aarch64/platform_helpers.S
|
|
+++ b/plat/common/aarch64/platform_helpers.S
|
|
@@ -10,9 +10,11 @@
|
|
#include <platform_def.h>
|
|
|
|
.weak plat_report_exception
|
|
+#if !ERROR_DEPRECATED
|
|
.weak plat_crash_console_init
|
|
.weak plat_crash_console_putc
|
|
.weak plat_crash_console_flush
|
|
+#endif
|
|
.weak plat_reset_handler
|
|
.weak plat_disable_acp
|
|
.weak bl1_plat_prepare_exit
|
|
@@ -37,6 +39,7 @@ func plat_report_exception
|
|
ret
|
|
endfunc plat_report_exception
|
|
|
|
+#if !ERROR_DEPRECATED
|
|
#if MULTI_CONSOLE_API
|
|
/* -----------------------------------------------------
|
|
* int plat_crash_console_init(void)
|
|
@@ -109,6 +112,7 @@ func plat_crash_console_flush
|
|
ret
|
|
endfunc plat_crash_console_flush
|
|
#endif
|
|
+#endif /* ERROR_DEPRECATED */
|
|
|
|
/* -----------------------------------------------------
|
|
* Placeholder function which should be redefined by
|
|
diff --git a/plat/common/plat_log_common.c b/plat/common/plat_log_common.c
|
|
index 49e1c15..c757c6b 100644
|
|
--- a/plat/common/plat_log_common.c
|
|
+++ b/plat/common/plat_log_common.c
|
|
@@ -5,6 +5,7 @@
|
|
*/
|
|
|
|
#include <debug.h>
|
|
+#include <platform.h>
|
|
|
|
/* Allow platforms to override the log prefix string */
|
|
#pragma weak plat_log_get_prefix
|
|
diff --git a/plat/imx/common/lpuart_console.S b/plat/imx/common/lpuart_console.S
|
|
index ad71b89..668fd62 100644
|
|
--- a/plat/imx/common/lpuart_console.S
|
|
+++ b/plat/imx/common/lpuart_console.S
|
|
@@ -6,6 +6,7 @@
|
|
|
|
#include <arch.h>
|
|
#include <asm_macros.S>
|
|
+#define USE_FINISH_CONSOLE_REG_2
|
|
#include <console_macros.S>
|
|
#include <assert_macros.S>
|
|
#include "imx8_lpuart.h"
|
|
@@ -26,7 +27,7 @@ func console_lpuart_register
|
|
|
|
mov x0, x6
|
|
mov x30, x7
|
|
- finish_console_register lpuart
|
|
+ finish_console_register lpuart putc=1, getc=1
|
|
|
|
register_fail:
|
|
ret x7
|
|
diff --git a/plat/layerscape/common/aarch64/ls_console.S b/plat/layerscape/common/aarch64/ls_console.S
|
|
index 5c87465..ec4390a 100644
|
|
--- a/plat/layerscape/common/aarch64/ls_console.S
|
|
+++ b/plat/layerscape/common/aarch64/ls_console.S
|
|
@@ -6,6 +6,7 @@
|
|
|
|
#include <arch.h>
|
|
#include <asm_macros.S>
|
|
+#define USE_FINISH_CONSOLE_REG_2
|
|
#include <console_macros.S>
|
|
#include <assert_macros.S>
|
|
#include "ls_16550.h"
|
|
@@ -106,7 +107,7 @@ func console_ls_16550_register
|
|
|
|
mov x0, x6
|
|
mov x30, x7
|
|
- finish_console_register ls_16550
|
|
+ finish_console_register ls_16550 putc=1, getc=1, flush=1
|
|
|
|
register_fail:
|
|
ret x7
|
|
diff --git a/plat/st/common/bl2_io_storage.c b/plat/st/common/bl2_io_storage.c
|
|
new file mode 100644
|
|
index 0000000..263c3ba
|
|
--- /dev/null
|
|
+++ b/plat/st/common/bl2_io_storage.c
|
|
@@ -0,0 +1,773 @@
|
|
+/*
|
|
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
|
|
+ *
|
|
+ * SPDX-License-Identifier: BSD-3-Clause
|
|
+ */
|
|
+
|
|
+#include <arch_helpers.h>
|
|
+#include <assert.h>
|
|
+#include <boot_api.h>
|
|
+#include <debug.h>
|
|
+#include <io_block.h>
|
|
+#include <io_driver.h>
|
|
+#include <io_dummy.h>
|
|
+#include <io_mmc.h>
|
|
+#if STM32MP_FMC_NAND
|
|
+#include <io_nand.h>
|
|
+#endif
|
|
+#include <io_programmer_st_usb.h>
|
|
+#if STM32MP1_QSPI_NOR
|
|
+#include <io_qspi.h>
|
|
+#endif
|
|
+#include <io_stm32image.h>
|
|
+#include <io_storage.h>
|
|
+#if STM32MP_UART_PROGRAMMER
|
|
+#include <io_uart.h>
|
|
+#endif
|
|
+#include <mmc.h>
|
|
+#include <mmio.h>
|
|
+#if STM32MP_FMC_NAND
|
|
+#include <nand.h>
|
|
+#endif
|
|
+#include <partition.h>
|
|
+#include <platform.h>
|
|
+#include <platform_def.h>
|
|
+#include <stm32_gpio.h>
|
|
+#include <stm32_sdmmc2.h>
|
|
+#include <stm32mp_common.h>
|
|
+#include <stm32mp_dt.h>
|
|
+#include <string.h>
|
|
+#ifdef STM32MP_USB
|
|
+#include <usb_core.h>
|
|
+#include <usb_ctx.h>
|
|
+#include <usb_dwc2.h>
|
|
+#include <usb_st_dfu.h>
|
|
+#endif
|
|
+#include <utils.h>
|
|
+
|
|
+/* IO devices */
|
|
+static const io_dev_connector_t *dummy_dev_con;
|
|
+static uintptr_t dummy_dev_handle;
|
|
+static uintptr_t dummy_dev_spec;
|
|
+
|
|
+static uintptr_t image_dev_handle;
|
|
+
|
|
+#if STM32MP_SDMMC || STM32MP_EMMC
|
|
+static io_block_spec_t gpt_block_spec = {
|
|
+ .offset = 0,
|
|
+ .length = 34 * MMC_BLOCK_SIZE, /* Size of GPT table */
|
|
+};
|
|
+
|
|
+static uint32_t block_buffer[MMC_BLOCK_SIZE] __aligned(MMC_BLOCK_SIZE);
|
|
+
|
|
+static const io_block_dev_spec_t mmc_block_dev_spec = {
|
|
+ /* It's used as temp buffer in block driver */
|
|
+ .buffer = {
|
|
+ .offset = (size_t)&block_buffer,
|
|
+ .length = MMC_BLOCK_SIZE,
|
|
+ },
|
|
+ .ops = {
|
|
+ .read = mmc_read_blocks,
|
|
+ .write = NULL,
|
|
+ },
|
|
+ .block_size = MMC_BLOCK_SIZE,
|
|
+};
|
|
+#endif
|
|
+
|
|
+static uintptr_t storage_dev_handle;
|
|
+#if STM32MP_SDMMC || STM32MP_EMMC
|
|
+static const io_dev_connector_t *mmc_dev_con;
|
|
+#endif
|
|
+
|
|
+#if STM32MP1_QSPI_NOR
|
|
+static const io_dev_connector_t *qspi_dev_con;
|
|
+
|
|
+static QSPI_HandleTypeDef qspi_dev_spec = {
|
|
+ .instance = (QUADSPI_TypeDef *)STM32MP1_QSPI1_BASE,
|
|
+ .is_dual = 0,
|
|
+};
|
|
+#endif
|
|
+
|
|
+#if STM32MP_UART_PROGRAMMER
|
|
+/* uart*/
|
|
+static const io_dev_connector_t *uart_dev_con;
|
|
+
|
|
+static UART_HandleTypeDef uart_programmer = {
|
|
+ .Init.BaudRate = STM32MP_UART_BAUDRATE,
|
|
+ .Init.StopBits = UART_STOPBITS_1,
|
|
+ .Init.HwFlowCtl = UART_HWCONTROL_NONE,
|
|
+ .Init.Mode = UART_MODE_TX_RX,
|
|
+ .Init.OverSampling = UART_OVERSAMPLING_16,
|
|
+ .Init.FIFOMode = UART_FIFOMODE_ENABLE,
|
|
+ .AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_AUTOBAUDRATE_INIT,
|
|
+ .AdvancedInit.AutoBaudRateEnable = UART_ADVFEATURE_AUTOBAUDRATE_DISABLE,
|
|
+};
|
|
+#endif /* STM32MP_UART_PROGRAMMER */
|
|
+
|
|
+#ifdef STM32MP_USB
|
|
+static usb_handle_t usb_core_handle;
|
|
+static usb_dfu_handle_t usb_dfu_handle;
|
|
+static pcd_handle_t pcd_handle;
|
|
+static const io_dev_connector_t *usb_dev_con;
|
|
+#endif /*STM32MP_USB*/
|
|
+
|
|
+#if STM32MP_FMC_NAND
|
|
+/* nand */
|
|
+static const io_dev_connector_t *nand_dev_con;
|
|
+static NAND_HandleTypeDef nand_dev_spec;
|
|
+#endif
|
|
+
|
|
+#ifdef AARCH32_SP_OPTEE
|
|
+static const struct stm32image_part_info optee_header_partition_spec = {
|
|
+ .name = OPTEE_HEADER_IMAGE_NAME,
|
|
+ .binary_type = OPTEE_HEADER_BINARY_TYPE,
|
|
+};
|
|
+
|
|
+static const struct stm32image_part_info optee_pager_partition_spec = {
|
|
+ .name = OPTEE_PAGER_IMAGE_NAME,
|
|
+ .binary_type = OPTEE_PAGER_BINARY_TYPE,
|
|
+};
|
|
+
|
|
+static const struct stm32image_part_info optee_paged_partition_spec = {
|
|
+ .name = OPTEE_PAGED_IMAGE_NAME,
|
|
+ .binary_type = OPTEE_PAGED_BINARY_TYPE,
|
|
+};
|
|
+#else
|
|
+static const io_block_spec_t bl32_block_spec = {
|
|
+ .offset = BL32_BASE,
|
|
+ .length = STM32MP_BL32_SIZE
|
|
+};
|
|
+#endif
|
|
+
|
|
+static const io_block_spec_t bl2_block_spec = {
|
|
+ .offset = BL2_BASE,
|
|
+ .length = STM32MP_BL2_SIZE,
|
|
+};
|
|
+
|
|
+static const struct stm32image_part_info bl33_partition_spec = {
|
|
+ .name = BL33_IMAGE_NAME,
|
|
+ .binary_type = BL33_BINARY_TYPE,
|
|
+};
|
|
+
|
|
+enum {
|
|
+ IMG_IDX_BL33,
|
|
+#ifdef AARCH32_SP_OPTEE
|
|
+ IMG_IDX_OPTEE_HEADER,
|
|
+ IMG_IDX_OPTEE_PAGER,
|
|
+ IMG_IDX_OPTEE_PAGED,
|
|
+#endif
|
|
+ IMG_IDX_NUM
|
|
+};
|
|
+
|
|
+static struct stm32image_device_info stm32image_dev_info_spec = {
|
|
+ .lba_size = MMC_BLOCK_SIZE,
|
|
+ .part_info[IMG_IDX_BL33] = {
|
|
+ .name = BL33_IMAGE_NAME,
|
|
+ .binary_type = BL33_BINARY_TYPE,
|
|
+ },
|
|
+#ifdef AARCH32_SP_OPTEE
|
|
+ .part_info[IMG_IDX_OPTEE_HEADER] = {
|
|
+ .name = OPTEE_HEADER_IMAGE_NAME,
|
|
+ .binary_type = OPTEE_HEADER_BINARY_TYPE,
|
|
+ },
|
|
+ .part_info[IMG_IDX_OPTEE_PAGER] = {
|
|
+ .name = OPTEE_PAGER_IMAGE_NAME,
|
|
+ .binary_type = OPTEE_PAGER_BINARY_TYPE,
|
|
+ },
|
|
+ .part_info[IMG_IDX_OPTEE_PAGED] = {
|
|
+ .name = OPTEE_PAGED_IMAGE_NAME,
|
|
+ .binary_type = OPTEE_PAGED_BINARY_TYPE,
|
|
+ },
|
|
+#endif
|
|
+};
|
|
+
|
|
+static io_block_spec_t stm32image_block_spec = {
|
|
+ .offset = 0,
|
|
+ .length = 0,
|
|
+};
|
|
+
|
|
+static const io_dev_connector_t *stm32image_dev_con;
|
|
+
|
|
+static int open_dummy(const uintptr_t spec);
|
|
+static int open_image(const uintptr_t spec);
|
|
+static int open_storage(const uintptr_t spec);
|
|
+
|
|
+struct plat_io_policy {
|
|
+ uintptr_t *dev_handle;
|
|
+ uintptr_t image_spec;
|
|
+ int (*check)(const uintptr_t spec);
|
|
+};
|
|
+
|
|
+static const struct plat_io_policy policies[] = {
|
|
+ [BL2_IMAGE_ID] = {
|
|
+ .dev_handle = &dummy_dev_handle,
|
|
+ .image_spec = (uintptr_t)&bl2_block_spec,
|
|
+ .check = open_dummy
|
|
+ },
|
|
+#ifdef AARCH32_SP_OPTEE
|
|
+ [BL32_IMAGE_ID] = {
|
|
+ .dev_handle = &image_dev_handle,
|
|
+ .image_spec = (uintptr_t)&optee_header_partition_spec,
|
|
+ .check = open_image
|
|
+ },
|
|
+ [BL32_EXTRA1_IMAGE_ID] = {
|
|
+ .dev_handle = &image_dev_handle,
|
|
+ .image_spec = (uintptr_t)&optee_pager_partition_spec,
|
|
+ .check = open_image
|
|
+ },
|
|
+ [BL32_EXTRA2_IMAGE_ID] = {
|
|
+ .dev_handle = &image_dev_handle,
|
|
+ .image_spec = (uintptr_t)&optee_paged_partition_spec,
|
|
+ .check = open_image
|
|
+ },
|
|
+#else
|
|
+ [BL32_IMAGE_ID] = {
|
|
+ .dev_handle = &dummy_dev_handle,
|
|
+ .image_spec = (uintptr_t)&bl32_block_spec,
|
|
+ .check = open_dummy
|
|
+ },
|
|
+#endif
|
|
+ [BL33_IMAGE_ID] = {
|
|
+ .dev_handle = &image_dev_handle,
|
|
+ .image_spec = (uintptr_t)&bl33_partition_spec,
|
|
+ .check = open_image
|
|
+ },
|
|
+#if STM32MP_SDMMC || STM32MP_EMMC
|
|
+ [GPT_IMAGE_ID] = {
|
|
+ .dev_handle = &storage_dev_handle,
|
|
+ .image_spec = (uintptr_t)&gpt_block_spec,
|
|
+ .check = open_storage
|
|
+ },
|
|
+#endif
|
|
+ [STM32_IMAGE_ID] = {
|
|
+ .dev_handle = &storage_dev_handle,
|
|
+ .image_spec = (uintptr_t)&stm32image_block_spec,
|
|
+ .check = open_storage
|
|
+ }
|
|
+};
|
|
+
|
|
+static int open_dummy(const uintptr_t spec)
|
|
+{
|
|
+ return io_dev_init(dummy_dev_handle, 0);
|
|
+}
|
|
+
|
|
+static int open_image(const uintptr_t spec)
|
|
+{
|
|
+ return io_dev_init(image_dev_handle, 0);
|
|
+}
|
|
+
|
|
+static int open_storage(const uintptr_t spec)
|
|
+{
|
|
+ return io_dev_init(storage_dev_handle, 0);
|
|
+}
|
|
+
|
|
+static void print_boot_device(boot_api_context_t *boot_context)
|
|
+{
|
|
+ switch (boot_context->boot_interface_selected) {
|
|
+ case BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_SD:
|
|
+ INFO("Using SDMMC\n");
|
|
+ break;
|
|
+ case BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_EMMC:
|
|
+ INFO("Using EMMC\n");
|
|
+ break;
|
|
+#if STM32MP_UART_PROGRAMMER
|
|
+ case BOOT_API_CTX_BOOT_INTERFACE_SEL_SERIAL_UART:
|
|
+ INFO("Using UART\n");
|
|
+ break;
|
|
+#endif
|
|
+ case BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_NOR_QSPI:
|
|
+ INFO("Using NOR\n");
|
|
+ if (boot_context->nor_isdual != 0U) {
|
|
+ INFO("NOR is configured in Dual Flash Mode\n");
|
|
+ }
|
|
+ break;
|
|
+ case BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_NAND_FMC:
|
|
+ INFO("Using NAND\n");
|
|
+ break;
|
|
+#ifdef STM32MP_USB
|
|
+ case BOOT_API_CTX_BOOT_INTERFACE_SEL_SERIAL_USB:
|
|
+ INFO("Using USB\n");
|
|
+ break;
|
|
+#endif
|
|
+#ifdef STM32MP1_QSPI_NAND
|
|
+ case BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_NAND_QSPI:
|
|
+ INFO("Using QSPI NAND\n");
|
|
+ break;
|
|
+#endif
|
|
+ default:
|
|
+ ERROR("Boot interface not found\n");
|
|
+ panic();
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ if (boot_context->boot_interface_instance != 0U) {
|
|
+ INFO(" Instance %d\n", boot_context->boot_interface_instance);
|
|
+ }
|
|
+}
|
|
+
|
|
+#if STM32MP_EMMC || STM32MP_SDMMC
|
|
+static void print_bootrom_sd_status(boot_api_context_t *boot_context)
|
|
+{
|
|
+ if (boot_context->sd_err_internal_timeout_cnt != 0U) {
|
|
+ WARN("BootROM: %d timeout issues\n",
|
|
+ boot_context->sd_err_internal_timeout_cnt);
|
|
+ }
|
|
+
|
|
+ if (boot_context->sd_err_dcrc_fail_cnt != 0U) {
|
|
+ WARN("BootROM: %d DCRCFAIL error\n",
|
|
+ boot_context->sd_err_dcrc_fail_cnt);
|
|
+ }
|
|
+
|
|
+ if (boot_context->sd_err_dtimeout_cnt != 0U) {
|
|
+ WARN("BootROM: %d DTIMEOUT error\n",
|
|
+ boot_context->sd_err_dtimeout_cnt);
|
|
+ }
|
|
+
|
|
+ if (boot_context->sd_err_ctimeout_cnt != 0U) {
|
|
+ WARN("BootROM: %d CTIMEOUT error\n",
|
|
+ boot_context->sd_err_ctimeout_cnt);
|
|
+ }
|
|
+
|
|
+ if (boot_context->sd_err_ccrc_fail_cnt != 0U) {
|
|
+ WARN("BootROM: %d CCRCFAIL error count\n",
|
|
+ boot_context->sd_err_ccrc_fail_cnt);
|
|
+ }
|
|
+
|
|
+ if (boot_context->sd_overall_retry_cnt != 0U) {
|
|
+ WARN("BootROM: %d command retries\n",
|
|
+ boot_context->sd_overall_retry_cnt);
|
|
+ }
|
|
+}
|
|
+
|
|
+static void print_bootrom_emmc_status(boot_api_context_t *boot_context)
|
|
+{
|
|
+ INFO("BootROM: %d (0x%x) bytes copied from eMMC\n",
|
|
+ boot_context->emmc_nbbytes_rxcopied_tosysram_download_area,
|
|
+ boot_context->emmc_nbbytes_rxcopied_tosysram_download_area);
|
|
+
|
|
+ if (boot_context->emmc_error_status !=
|
|
+ BOOT_API_CTX_EMMC_ERROR_STATUS_NONE) {
|
|
+ WARN("BootROM eMMC error:\n");
|
|
+ switch (boot_context->emmc_error_status) {
|
|
+ case BOOT_API_CTX_EMMC_ERROR_STATUS_CMD_TIMEOUT:
|
|
+ WARN(" CMD timeout\n");
|
|
+ break;
|
|
+ case BOOT_API_CTX_EMMC_ERROR_STATUS_ACK_TIMEOUT:
|
|
+ WARN(" ACK timeout\n");
|
|
+ break;
|
|
+ case BOOT_API_CTX_EMMC_ERROR_STATUS_DATA_CRC_FAIL:
|
|
+ WARN(" DATA CRC failed\n");
|
|
+ break;
|
|
+ case BOOT_API_CTX_EMMC_ERROR_STATUS_NOT_ENOUGH_BOOT_DATA_RX:
|
|
+ WARN(" Not enough data copied\n");
|
|
+ break;
|
|
+ case BOOT_API_CTX_EMMC_ERROR_STATUS_HEADER_NOT_FOUND:
|
|
+ WARN(" Header not found\n");
|
|
+ break;
|
|
+ case BOOT_API_CTX_EMMC_ERROR_STATUS_HEADER_SIZE_ZERO:
|
|
+ WARN(" Header size is zero\n");
|
|
+ break;
|
|
+ case BOOT_API_CTX_EMMC_ERROR_STATUS_IMAGE_NOT_COMPLETE:
|
|
+ WARN(" Image not complete\n");
|
|
+ break;
|
|
+ default:
|
|
+ WARN(" Error not listed\n");
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ switch (boot_context->emmc_xfer_status) {
|
|
+ case BOOT_API_CTX_EMMC_XFER_STATUS_NOT_STARTED:
|
|
+ WARN("BootROM: eMMC transfer status:\n");
|
|
+ WARN(" not started\n");
|
|
+ break;
|
|
+ case BOOT_API_CTX_EMMC_XFER_STATUS_DATAEND_DETECTED:
|
|
+ break;
|
|
+ case BOOT_API_CTX_EMMC_XFER_STATUS_XFER_OVERALL_TIMEOUT_DETECTED:
|
|
+ WARN("BootROM: eMMC transfer status:\n");
|
|
+ WARN(" timeout detected\n");
|
|
+ break;
|
|
+ case BOOT_API_CTX_EMMC_XFER_STATUS_XFER_DATA_TIMEOUT:
|
|
+ WARN("BootROM: eMMC transfer status:\n");
|
|
+ WARN(" data timeout detected\n");
|
|
+ break;
|
|
+ default:
|
|
+ WARN("BootROM: eMMC transfer status:\n");
|
|
+ WARN(" status not listed\n");
|
|
+ break;
|
|
+ }
|
|
+}
|
|
+#endif
|
|
+
|
|
+
|
|
+void stm32mp_io_setup(void)
|
|
+{
|
|
+ int io_result __unused;
|
|
+ uint8_t idx;
|
|
+ struct stm32image_part_info *part;
|
|
+#if STM32MP_UART_PROGRAMMER
|
|
+ uintptr_t uart_addr;
|
|
+#endif
|
|
+#if STM32MP_SDMMC || STM32MP_EMMC
|
|
+ struct stm32_sdmmc2_params params;
|
|
+ struct mmc_device_info device_info;
|
|
+ uintptr_t mmc_default_instance;
|
|
+ const partition_entry_t *entry;
|
|
+#endif
|
|
+#ifdef STM32MP_USB
|
|
+ struct usb_ctx *usb_context;
|
|
+#endif
|
|
+ boot_api_context_t *boot_context =
|
|
+ (boot_api_context_t *)stm32mp_get_boot_ctx_address();
|
|
+
|
|
+ print_boot_device(boot_context);
|
|
+
|
|
+ if ((boot_context->boot_partition_used_toboot == 1U) ||
|
|
+ (boot_context->boot_partition_used_toboot == 2U)) {
|
|
+ INFO("Boot used partition fsbl%d\n",
|
|
+ boot_context->boot_partition_used_toboot);
|
|
+ }
|
|
+
|
|
+ io_result = register_io_dev_dummy(&dummy_dev_con);
|
|
+ assert(io_result == 0);
|
|
+
|
|
+ io_result = io_dev_open(dummy_dev_con, dummy_dev_spec,
|
|
+ &dummy_dev_handle);
|
|
+ assert(io_result == 0);
|
|
+
|
|
+ switch (boot_context->boot_interface_selected) {
|
|
+ case BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_SD:
|
|
+ case BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_EMMC:
|
|
+ dmbsy();
|
|
+
|
|
+#if STM32MP_EMMC || STM32MP_SDMMC
|
|
+ memset(¶ms, 0, sizeof(struct stm32_sdmmc2_params));
|
|
+
|
|
+ if (boot_context->boot_interface_selected ==
|
|
+ BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_EMMC) {
|
|
+ device_info.mmc_dev_type = MMC_IS_EMMC;
|
|
+ print_bootrom_emmc_status(boot_context);
|
|
+#if STM32MP_EMMC
|
|
+ mmc_default_instance = STM32MP_SDMMC2_BASE;
|
|
+#else
|
|
+ ERROR("MMC driver is not enabled\n");
|
|
+ panic();
|
|
+#endif
|
|
+ } else {
|
|
+ device_info.mmc_dev_type = MMC_IS_SD;
|
|
+ print_bootrom_sd_status(boot_context);
|
|
+#if STM32MP_SDMMC
|
|
+ mmc_default_instance = STM32MP_SDMMC1_BASE;
|
|
+#else
|
|
+ ERROR("MMC driver is not enabled\n");
|
|
+ panic();
|
|
+#endif
|
|
+ }
|
|
+
|
|
+ switch (boot_context->boot_interface_instance) {
|
|
+ case 1:
|
|
+ params.reg_base = STM32MP_SDMMC1_BASE;
|
|
+ break;
|
|
+ case 2:
|
|
+ params.reg_base = STM32MP_SDMMC2_BASE;
|
|
+ break;
|
|
+ case 3:
|
|
+ params.reg_base = STM32MP_SDMMC3_BASE;
|
|
+ break;
|
|
+ default:
|
|
+ WARN("SDMMC instance not found, using default\n");
|
|
+ params.reg_base = mmc_default_instance;
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ params.device_info = &device_info;
|
|
+ if (stm32_sdmmc2_mmc_init(¶ms) != 0) {
|
|
+ ERROR("SDMMC%u init failed\n",
|
|
+ boot_context->boot_interface_instance);
|
|
+ panic();
|
|
+ }
|
|
+
|
|
+ /* Open MMC as a block device to read GPT table */
|
|
+ io_result = register_io_dev_block(&mmc_dev_con);
|
|
+ if (io_result != 0) {
|
|
+ panic();
|
|
+ }
|
|
+
|
|
+ io_result = io_dev_open(mmc_dev_con,
|
|
+ (uintptr_t)&mmc_block_dev_spec,
|
|
+ &storage_dev_handle);
|
|
+ assert(io_result == 0);
|
|
+
|
|
+ partition_init(GPT_IMAGE_ID);
|
|
+
|
|
+ io_result = io_dev_close(storage_dev_handle);
|
|
+ assert(io_result == 0);
|
|
+
|
|
+ stm32image_dev_info_spec.device_size =
|
|
+ stm32_sdmmc2_mmc_get_device_size();
|
|
+
|
|
+ for (idx = 0U; idx < IMG_IDX_NUM; idx++) {
|
|
+ part = &stm32image_dev_info_spec.part_info[idx];
|
|
+ entry = get_partition_entry(part->name);
|
|
+ if (entry == NULL) {
|
|
+ ERROR("Partition %s not found\n",
|
|
+ part->name);
|
|
+ panic();
|
|
+ }
|
|
+
|
|
+ part->part_offset = entry->start;
|
|
+ part->bkp_offset = 0U;
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * Re-open MMC with io_mmc, for better perfs compared to
|
|
+ * io_block.
|
|
+ */
|
|
+ io_result = register_io_dev_mmc(&mmc_dev_con);
|
|
+ assert(io_result == 0);
|
|
+
|
|
+ io_result = io_dev_open(mmc_dev_con, 0, &storage_dev_handle);
|
|
+ assert(io_result == 0);
|
|
+
|
|
+ io_result = register_io_dev_stm32image(&stm32image_dev_con);
|
|
+ assert(io_result == 0);
|
|
+
|
|
+ io_result = io_dev_open(stm32image_dev_con,
|
|
+ (uintptr_t)&stm32image_dev_info_spec,
|
|
+ &image_dev_handle);
|
|
+ assert(io_result == 0);
|
|
+#else /* STM32MP_EMMC || STM32MP_SDMMC */
|
|
+ ERROR("EMMC or SDMMC driver not enabled\n");
|
|
+ panic();
|
|
+#endif /* STM32MP_EMMC || STM32MP_SDMMC */
|
|
+ break;
|
|
+
|
|
+#if STM32MP1_QSPI_NOR
|
|
+ case BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_NOR_QSPI:
|
|
+ dmbsy();
|
|
+
|
|
+ io_result = register_io_dev_qspi(&qspi_dev_con);
|
|
+
|
|
+ assert(io_result == 0);
|
|
+ switch (boot_context->boot_interface_instance) {
|
|
+ case 1:
|
|
+ qspi_dev_spec.instance =
|
|
+ (QUADSPI_TypeDef *)STM32MP1_QSPI1_BASE;
|
|
+ break;
|
|
+ default:
|
|
+ WARN("NOR instance not found, using default\n");
|
|
+ qspi_dev_spec.instance =
|
|
+ (QUADSPI_TypeDef *)STM32MP1_QSPI1_BASE;
|
|
+ break;
|
|
+ }
|
|
+ qspi_dev_spec.is_dual = boot_context->nor_isdual;
|
|
+
|
|
+ /* Open connections to devices and cache the handles */
|
|
+ io_result = io_dev_open(qspi_dev_con,
|
|
+ (uintptr_t)&qspi_dev_spec,
|
|
+ &storage_dev_handle);
|
|
+ assert(io_result == 0);
|
|
+
|
|
+ stm32image_dev_info_spec.device_size = QSPI_NOR_MAX_SIZE;
|
|
+ stm32image_dev_info_spec.lba_size = QSPI_NOR_LBA_SIZE;
|
|
+
|
|
+ idx = IMG_IDX_BL33;
|
|
+ part = &stm32image_dev_info_spec.part_info[idx];
|
|
+ part->part_offset = STM32MP_NOR_BL33_OFFSET;
|
|
+ part->bkp_offset = QSPI_NOR_BLK_SIZE;
|
|
+
|
|
+#ifdef AARCH32_SP_OPTEE
|
|
+ idx = IMG_IDX_OPTEE_HEADER;
|
|
+ part = &stm32image_dev_info_spec.part_info[idx];
|
|
+ part->part_offset = STM32MP_NOR_TEEH_OFFSET;
|
|
+ part->bkp_offset = QSPI_NOR_BLK_SIZE;
|
|
+
|
|
+ idx = IMG_IDX_OPTEE_PAGED;
|
|
+ part = &stm32image_dev_info_spec.part_info[idx];
|
|
+ part->part_offset = STM32MP_NOR_TEED_OFFSET;
|
|
+ part->bkp_offset = QSPI_NOR_BLK_SIZE;
|
|
+
|
|
+ idx = IMG_IDX_OPTEE_PAGER;
|
|
+ part = &stm32image_dev_info_spec.part_info[idx];
|
|
+ part->part_offset = STM32MP_NOR_TEEX_OFFSET;
|
|
+ part->bkp_offset = QSPI_NOR_BLK_SIZE;
|
|
+#endif
|
|
+
|
|
+ io_result = register_io_dev_stm32image(&stm32image_dev_con);
|
|
+ assert(io_result == 0);
|
|
+
|
|
+ io_result = io_dev_open(stm32image_dev_con,
|
|
+ (uintptr_t)&stm32image_dev_info_spec,
|
|
+ &image_dev_handle);
|
|
+ assert(io_result == 0);
|
|
+ break;
|
|
+#endif
|
|
+
|
|
+ case BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_NAND_FMC:
|
|
+
|
|
+#if STM32MP_FMC_NAND
|
|
+ dmbsy();
|
|
+
|
|
+ /* Register the IO devices on this platform */
|
|
+ io_result = register_io_dev_nand(&nand_dev_con);
|
|
+ assert(io_result == 0);
|
|
+
|
|
+ nand_dev_spec.Instance = (FMC_TypeDef *)STM32MP_FMC_BASE;
|
|
+ nand_dev_spec.Info.PageSize = boot_context->nand_page_size;
|
|
+ nand_dev_spec.Info.BlockSize = boot_context->nand_block_size;
|
|
+ nand_dev_spec.Info.BlockNb = boot_context->nand_block_nb;
|
|
+ nand_dev_spec.Info.BusWidth = boot_context->nand_data_width;
|
|
+ nand_dev_spec.Info.ECCcorrectability =
|
|
+ boot_context->nand_ecc_bits;
|
|
+
|
|
+ /* Open connections to devices and cache the handles */
|
|
+ io_result = io_dev_open(nand_dev_con, (uintptr_t)&nand_dev_spec,
|
|
+ &storage_dev_handle);
|
|
+ assert(io_result == 0);
|
|
+
|
|
+ stm32image_dev_info_spec.device_size =
|
|
+ nand_dev_spec.Info.PageSize *
|
|
+ nand_dev_spec.Info.BlockSize *
|
|
+ nand_dev_spec.Info.BlockNb;
|
|
+ stm32image_dev_info_spec.lba_size = BCH_PAGE_SECTOR;
|
|
+
|
|
+ idx = IMG_IDX_BL33;
|
|
+ part = &stm32image_dev_info_spec.part_info[idx];
|
|
+ part->part_offset = STM32MP_NAND_BL33_OFFSET;
|
|
+ part->bkp_offset = nand_dev_spec.Info.PageSize *
|
|
+ nand_dev_spec.Info.BlockSize;
|
|
+
|
|
+#ifdef AARCH32_SP_OPTEE
|
|
+ idx = IMG_IDX_OPTEE_HEADER;
|
|
+ part = &stm32image_dev_info_spec.part_info[idx];
|
|
+ part->part_offset = STM32MP_NAND_TEEH_OFFSET;
|
|
+ part->bkp_offset = nand_dev_spec.Info.PageSize *
|
|
+ nand_dev_spec.Info.BlockSize;
|
|
+
|
|
+ idx = IMG_IDX_OPTEE_PAGED;
|
|
+ part = &stm32image_dev_info_spec.part_info[idx];
|
|
+ part->part_offset = STM32MP_NAND_TEED_OFFSET;
|
|
+ part->bkp_offset = nand_dev_spec.Info.PageSize *
|
|
+ nand_dev_spec.Info.BlockSize;
|
|
+
|
|
+ idx = IMG_IDX_OPTEE_PAGER;
|
|
+ part = &stm32image_dev_info_spec.part_info[idx];
|
|
+ part->part_offset = STM32MP_NAND_TEEX_OFFSET;
|
|
+ part->bkp_offset = nand_dev_spec.Info.PageSize *
|
|
+ nand_dev_spec.Info.BlockSize;
|
|
+#endif
|
|
+
|
|
+ io_result = register_io_dev_stm32image(&stm32image_dev_con);
|
|
+ assert(io_result == 0);
|
|
+
|
|
+ io_result = io_dev_open(stm32image_dev_con,
|
|
+ (uintptr_t)&stm32image_dev_info_spec,
|
|
+ &image_dev_handle);
|
|
+ assert(io_result == 0);
|
|
+#else
|
|
+ ERROR("FMC NAND driver is not enabled\n");
|
|
+ panic();
|
|
+#endif
|
|
+ break;
|
|
+
|
|
+#if STM32MP_UART_PROGRAMMER
|
|
+ case BOOT_API_CTX_BOOT_INTERFACE_SEL_SERIAL_UART:
|
|
+
|
|
+ /* Register the IO devices on this platform */
|
|
+ io_result = register_io_dev_uart(&uart_dev_con);
|
|
+ assert(io_result == 0);
|
|
+
|
|
+ uart_programmer.Init.WordLength = UART_WORDLENGTH_9B;
|
|
+ uart_programmer.Init.Parity = UART_PARITY_EVEN;
|
|
+ uart_addr =
|
|
+ get_uart_address(boot_context->boot_interface_instance);
|
|
+
|
|
+ if (uart_addr) {
|
|
+ uart_programmer.Instance = (USART_TypeDef *)uart_addr;
|
|
+ } else {
|
|
+ WARN("UART instance not found, using default\n");
|
|
+ uart_programmer.Instance = (USART_TypeDef *)USART2_BASE;
|
|
+ }
|
|
+
|
|
+ /* Open connections to devices and cache the handles */
|
|
+ io_result = io_dev_open(uart_dev_con,
|
|
+ (uintptr_t)&uart_programmer,
|
|
+ &image_dev_handle);
|
|
+ assert(!io_result);
|
|
+ break;
|
|
+#endif
|
|
+
|
|
+#ifdef STM32MP_USB
|
|
+ case BOOT_API_CTX_BOOT_INTERFACE_SEL_SERIAL_USB:
|
|
+ usb_context = (struct usb_ctx *)boot_context->usb_context;
|
|
+
|
|
+ pcd_handle.in_ep[0].maxpacket = 0x40;
|
|
+ pcd_handle.out_ep[0].maxpacket = 0x40;
|
|
+
|
|
+ pcd_handle.state = HAL_PCD_STATE_READY;
|
|
+
|
|
+ usb_core_handle.data = &pcd_handle;
|
|
+
|
|
+ usb_dwc2_init_driver(&usb_core_handle,
|
|
+ (uint32_t *)USB_OTG_BASE);
|
|
+
|
|
+ usb_dfu_register_callback(&usb_core_handle);
|
|
+
|
|
+ stm32mp_usb_init_desc(&usb_core_handle);
|
|
+
|
|
+ usb_core_handle.ep_in[0].maxpacket = 0x40;
|
|
+ usb_core_handle.ep_out[0].maxpacket = 0x40;
|
|
+
|
|
+ usb_core_handle.ep0_state =
|
|
+ usb_context->pusbd_device_ctx->ep0_state;
|
|
+ usb_core_handle.dev_state = USBD_STATE_CONFIGURED;
|
|
+
|
|
+ usb_core_handle.class_data = &usb_dfu_handle;
|
|
+ usb_dfu_handle.dev_state = DFU_STATE_IDLE;
|
|
+
|
|
+ /* Register the IO devices on this platform */
|
|
+ io_result = register_io_dev_usb(&usb_dev_con);
|
|
+ assert(io_result == 0);
|
|
+
|
|
+ /* Open connections to devices and cache the handles */
|
|
+ io_result = io_dev_open(usb_dev_con,
|
|
+ (uintptr_t)&usb_core_handle,
|
|
+ &image_dev_handle);
|
|
+
|
|
+ assert(io_result == 0);
|
|
+ break;
|
|
+#endif
|
|
+#ifdef STM32MP1_QSPI_NAND
|
|
+ case BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_NAND_QSPI:
|
|
+ ERROR("QSPI NAND not supported\n");
|
|
+ break;
|
|
+#endif
|
|
+
|
|
+ default:
|
|
+ ERROR("Boot interface %d not supported\n",
|
|
+ boot_context->boot_interface_selected);
|
|
+ break;
|
|
+ }
|
|
+}
|
|
+
|
|
+/*
|
|
+ * Return an IO device handle and specification which can be used to access
|
|
+ * an image. Use this to enforce platform load policy.
|
|
+ */
|
|
+int plat_get_image_source(unsigned int image_id, uintptr_t *dev_handle,
|
|
+ uintptr_t *image_spec)
|
|
+{
|
|
+ int rc;
|
|
+ const struct plat_io_policy *policy;
|
|
+
|
|
+ assert(image_id < ARRAY_SIZE(policies));
|
|
+
|
|
+ policy = &policies[image_id];
|
|
+ rc = policy->check(policy->image_spec);
|
|
+ if (rc == 0) {
|
|
+ *image_spec = policy->image_spec;
|
|
+ *dev_handle = *(policy->dev_handle);
|
|
+ }
|
|
+
|
|
+ return rc;
|
|
+}
|
|
diff --git a/plat/st/common/include/stm32mp_auth.h b/plat/st/common/include/stm32mp_auth.h
|
|
new file mode 100644
|
|
index 0000000..70f8202
|
|
--- /dev/null
|
|
+++ b/plat/st/common/include/stm32mp_auth.h
|
|
@@ -0,0 +1,15 @@
|
|
+/*
|
|
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
|
|
+ *
|
|
+ * SPDX-License-Identifier: BSD-3-Clause
|
|
+ */
|
|
+
|
|
+#ifndef STM32MP_AUTH_H
|
|
+#define STM32MP_AUTH_H
|
|
+
|
|
+#include <boot_api.h>
|
|
+
|
|
+int check_header(boot_api_image_header_t *header, uintptr_t buffer);
|
|
+int check_authentication(boot_api_image_header_t *header, uintptr_t buffer);
|
|
+
|
|
+#endif /* STM32MP_AUTH_H */
|
|
diff --git a/plat/st/common/include/stm32mp_common.h b/plat/st/common/include/stm32mp_common.h
|
|
new file mode 100644
|
|
index 0000000..dc2568b6
|
|
--- /dev/null
|
|
+++ b/plat/st/common/include/stm32mp_common.h
|
|
@@ -0,0 +1,49 @@
|
|
+/*
|
|
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
|
|
+ *
|
|
+ * SPDX-License-Identifier: BSD-3-Clause
|
|
+ */
|
|
+
|
|
+#ifndef STM32MP_COMMON_H
|
|
+#define STM32MP_COMMON_H
|
|
+
|
|
+#include <cdefs.h>
|
|
+#include <stdbool.h>
|
|
+
|
|
+void __dead2 stm32mp_plat_reset(int cpu);
|
|
+
|
|
+void stm32mp_save_boot_ctx_address(uintptr_t address);
|
|
+uintptr_t stm32mp_get_boot_ctx_address(void);
|
|
+
|
|
+int stm32mp_is_single_core(void);
|
|
+
|
|
+uintptr_t stm32mp_ddrctrl_base(void);
|
|
+uintptr_t stm32mp_ddrphyc_base(void);
|
|
+uintptr_t stm32mp_pwr_base(void);
|
|
+uintptr_t stm32mp_rcc_base(void);
|
|
+
|
|
+int stm32_gic_enable_spi(int node, const char *name);
|
|
+
|
|
+uint32_t stm32_read_otp_status(uint32_t *otp_value, uint32_t word);
|
|
+uint8_t stm32_iwdg_get_instance(uintptr_t base);
|
|
+uint32_t stm32_iwdg_get_otp_config(uintptr_t base);
|
|
+
|
|
+#if defined(IMAGE_BL2)
|
|
+uint32_t stm32_iwdg_shadow_update(uintptr_t base, uint32_t flags);
|
|
+#endif
|
|
+
|
|
+uintptr_t stm32_get_gpio_bank_base(unsigned int bank);
|
|
+int stm32_get_gpio_bank_clock(unsigned int bank);
|
|
+uint32_t stm32_get_gpio_bank_offset(unsigned int bank);
|
|
+void stm32mp_print_cpuinfo(void);
|
|
+void stm32mp_print_boardinfo(void);
|
|
+
|
|
+uint64_t s2tick(uint32_t timeout_s);
|
|
+uint64_t ms2tick(uint32_t timeout_ms);
|
|
+uint64_t us2tick(uint32_t timeout_us);
|
|
+uint64_t timeout_start(void);
|
|
+bool timeout_elapsed(uint64_t tick_start, uint64_t tick_to);
|
|
+
|
|
+void stm32mp_io_setup(void);
|
|
+
|
|
+#endif /* STM32MP1_COMMON_H */
|
|
diff --git a/plat/st/common/include/stm32mp_dt.h b/plat/st/common/include/stm32mp_dt.h
|
|
new file mode 100644
|
|
index 0000000..ee313d5
|
|
--- /dev/null
|
|
+++ b/plat/st/common/include/stm32mp_dt.h
|
|
@@ -0,0 +1,54 @@
|
|
+/*
|
|
+ * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
|
|
+ *
|
|
+ * SPDX-License-Identifier: BSD-3-Clause
|
|
+ */
|
|
+
|
|
+#ifndef STM32MP_DT_H
|
|
+#define STM32MP_DT_H
|
|
+
|
|
+#include <libfdt.h>
|
|
+#include <stdbool.h>
|
|
+
|
|
+#define DT_DISABLED U(0)
|
|
+#define DT_NON_SECURE U(1)
|
|
+#define DT_SECURE U(2)
|
|
+#define DT_SHARED (DT_NON_SECURE | DT_SECURE)
|
|
+
|
|
+struct dt_node_info {
|
|
+ uint32_t base;
|
|
+ int32_t clock;
|
|
+ int32_t reset;
|
|
+ uint8_t status;
|
|
+};
|
|
+
|
|
+/*******************************************************************************
|
|
+ * Function and variable prototypes
|
|
+ ******************************************************************************/
|
|
+int dt_open_and_check(void);
|
|
+int fdt_get_address(void **fdt_addr);
|
|
+bool fdt_check_node(int node);
|
|
+uint8_t fdt_get_status(int node);
|
|
+int fdt_get_interrupt(int node, const fdt32_t **array, int *len,
|
|
+ bool *extended);
|
|
+uint32_t fdt_read_uint32_default(int node, const char *prop_name,
|
|
+ uint32_t dflt_value);
|
|
+int fdt_read_uint32_array(int node, const char *prop_name,
|
|
+ uint32_t *array, uint32_t count);
|
|
+int fdt_get_reg_props_by_name(int node, const char *name, uintptr_t *base,
|
|
+ size_t *size);
|
|
+int dt_set_stdout_pinctrl(void);
|
|
+void dt_fill_device_info(struct dt_node_info *info, int node);
|
|
+int dt_get_node(struct dt_node_info *info, int offset, const char *compat);
|
|
+int dt_get_stdout_uart_info(struct dt_node_info *info);
|
|
+uint32_t dt_get_ddr_size(void);
|
|
+uintptr_t dt_get_ddrctrl_base(void);
|
|
+uintptr_t dt_get_ddrphyc_base(void);
|
|
+uintptr_t dt_get_pwr_base(void);
|
|
+uint32_t dt_get_pwr_vdd_voltage(void);
|
|
+uintptr_t dt_get_syscfg_base(void);
|
|
+const char *dt_get_board_model(void);
|
|
+int fdt_get_gpio_bank_pinctrl_node(unsigned int bank);
|
|
+int fdt_get_gpioz_nbpins_from_dt(void);
|
|
+
|
|
+#endif /* STM32MP_DT_H */
|
|
diff --git a/plat/st/common/include/stm32mp_shres_helpers.h b/plat/st/common/include/stm32mp_shres_helpers.h
|
|
new file mode 100644
|
|
index 0000000..565b3d4
|
|
--- /dev/null
|
|
+++ b/plat/st/common/include/stm32mp_shres_helpers.h
|
|
@@ -0,0 +1,86 @@
|
|
+/*
|
|
+ * Copyright (C) 2018, STMicroelectronics - All Rights Reserved
|
|
+ *
|
|
+ * SPDX-License-Identifier: BSD-3-Clause
|
|
+ */
|
|
+
|
|
+#ifndef STM32MP_SHRES_HELPERS_H
|
|
+#define STM32MP_SHRES_HELPERS_H
|
|
+
|
|
+#include <debug.h>
|
|
+#include <stdint.h>
|
|
+
|
|
+/*
|
|
+ * Lock/unlock access to shared registers
|
|
+ *
|
|
+ * @lock - NULL or pointer to spin lock
|
|
+ */
|
|
+
|
|
+void stm32mp_lock_shregs(void);
|
|
+void stm32mp_unlock_shregs(void);
|
|
+void stm32mp_mmio_clrsetbits_32_shregs(uintptr_t addr, uint32_t clear,
|
|
+ uint32_t set);
|
|
+void stm32mp_mmio_clrbits_32_shregs(uintptr_t addr, uint32_t clear);
|
|
+void stm32mp_mmio_setbits_32_shregs(uintptr_t addr, uint32_t set);
|
|
+
|
|
+/*
|
|
+ * Shared reference counter: increments by 2 on secure increment
|
|
+ * request, decrements by 2 on secure decrement request. Bit #0
|
|
+ * is set to 1 on non-secure increment request and reset to 0 on
|
|
+ * non-secure decrement request. The counter initializes to
|
|
+ * either 0, 1 or 2 upon their expect default state.
|
|
+ * Counters saturates once above UINT_MAX / 2.
|
|
+ */
|
|
+#define SHREFCNT_NONSECURE_FLAG 0x1UL
|
|
+#define SHREFCNT_SECURE_STEP 0x2UL
|
|
+#define SHREFCNT_MAX (UINT32_MAX / 2)
|
|
+
|
|
+/* Return 1 if refcnt increments from 0, else return 0 */
|
|
+static inline int stm32mp_incr_shrefcnt(unsigned int *refcnt, bool secure)
|
|
+{
|
|
+ int rc = !*refcnt;
|
|
+
|
|
+ if (secure) {
|
|
+ *refcnt += SHREFCNT_SECURE_STEP;
|
|
+ if (*refcnt >= SHREFCNT_MAX) {
|
|
+ panic();
|
|
+ }
|
|
+ } else {
|
|
+ *refcnt |= SHREFCNT_NONSECURE_FLAG;
|
|
+ }
|
|
+
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+/* Return 1 if refcnt decrements to 0, else return 0 */
|
|
+static inline int stm32mp_decr_shrefcnt(unsigned int *refcnt, bool secure)
|
|
+{
|
|
+ int rc = 0;
|
|
+
|
|
+ if (secure) {
|
|
+ if (*refcnt < SHREFCNT_MAX) {
|
|
+ if (*refcnt < SHREFCNT_SECURE_STEP) {
|
|
+ panic();
|
|
+ }
|
|
+ *refcnt -= SHREFCNT_SECURE_STEP;
|
|
+ rc = !*refcnt;
|
|
+ }
|
|
+ } else {
|
|
+ rc = (*refcnt == SHREFCNT_NONSECURE_FLAG);
|
|
+ *refcnt &= ~SHREFCNT_NONSECURE_FLAG;
|
|
+ }
|
|
+
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+static inline int stm32mp_incr_refcnt(unsigned int *refcnt)
|
|
+{
|
|
+ return stm32mp_incr_shrefcnt(refcnt, true);
|
|
+}
|
|
+
|
|
+static inline int stm32mp_decr_refcnt(unsigned int *refcnt)
|
|
+{
|
|
+ return stm32mp_decr_shrefcnt(refcnt, true);
|
|
+}
|
|
+
|
|
+#endif /* STM32MP_SHRES_HELPERS_H */
|
|
diff --git a/plat/st/common/stm32mp_auth.c b/plat/st/common/stm32mp_auth.c
|
|
new file mode 100644
|
|
index 0000000..773c95e
|
|
--- /dev/null
|
|
+++ b/plat/st/common/stm32mp_auth.c
|
|
@@ -0,0 +1,121 @@
|
|
+/*
|
|
+ * Copyright (c) 2016-2018, STMicroelectronics - All Rights Reserved
|
|
+ *
|
|
+ * SPDX-License-Identifier: BSD-3-Clause
|
|
+ */
|
|
+
|
|
+#include <debug.h>
|
|
+#include <errno.h>
|
|
+#include <hash_sec.h>
|
|
+#include <io_storage.h>
|
|
+#include <platform_def.h>
|
|
+#include <stm32mp_auth.h>
|
|
+#include <stm32mp_common.h>
|
|
+
|
|
+int check_header(boot_api_image_header_t *header, uintptr_t buffer)
|
|
+{
|
|
+ uint32_t i;
|
|
+ uint32_t img_checksum = 0;
|
|
+
|
|
+ /*
|
|
+ * Check header/payload validity:
|
|
+ * - Header magic
|
|
+ * - Header version
|
|
+ * - Payload checksum
|
|
+ */
|
|
+ if (header->magic != BOOT_API_IMAGE_HEADER_MAGIC_NB) {
|
|
+ ERROR("Header magic is not correct\n");
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ if (header->header_version != BOOT_API_HEADER_VERSION) {
|
|
+ ERROR("Header version is not correct\n");
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ for (i = 0; i < header->image_length; i++) {
|
|
+ img_checksum += *(uint8_t *)(buffer + i);
|
|
+ }
|
|
+
|
|
+ if (header->payload_checksum != img_checksum) {
|
|
+ ERROR("Payload checksum is not correct:\n");
|
|
+ ERROR(" Computed: 0x%x (awaited: 0x%x)\n", img_checksum,
|
|
+ header->payload_checksum);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+int check_authentication(boot_api_image_header_t *header, uintptr_t buffer)
|
|
+{
|
|
+ uint32_t sec_closed, uret;
|
|
+ HASH_HandleTypeDef hhash;
|
|
+ uint8_t image_hash[BOOT_API_SHA256_DIGEST_SIZE_IN_BYTES];
|
|
+ uint32_t header_skip_cksum = sizeof(header->magic) +
|
|
+ sizeof(header->image_signature) +
|
|
+ sizeof(header->payload_checksum);
|
|
+ boot_api_context_t *boot_context =
|
|
+ (boot_api_context_t *)stm32mp_get_boot_ctx_address();
|
|
+
|
|
+ uret = bsec_read_otp(&sec_closed, BOOT_API_OTP_MODE_WORD_NB);
|
|
+ if (uret != 0) {
|
|
+ ERROR("Error reading OTP configuration\n");
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ /* Check Security Status */
|
|
+ if ((sec_closed & BIT(BOOT_API_OTP_MODE_CLOSED_BIT_POS)) == 0U) {
|
|
+ if (header->option_flags != 0U) {
|
|
+ WARN("Skip signature check (header option)\n");
|
|
+ return 0;
|
|
+ }
|
|
+ INFO("Check signature on Non-Full-Secured platform\n");
|
|
+ }
|
|
+
|
|
+ /* Check Public Key */
|
|
+ if (boot_context->p_bootrom_ext_service_ecdsa_check_key
|
|
+ (header->ecc_pubk, NULL) != STD_OK) {
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ /* Compute end of header hash and payload hash */
|
|
+ uret = HASH_SHA256_Init(&hhash);
|
|
+ if (uret != STD_OK) {
|
|
+ ERROR("Hash init failed\n");
|
|
+ return -EBUSY;
|
|
+ }
|
|
+
|
|
+ uret = HASH_SHA256_Accumulate(&hhash,
|
|
+ (uint8_t *)&header->header_version,
|
|
+ sizeof(boot_api_image_header_t) -
|
|
+ header_skip_cksum);
|
|
+ if (uret != STD_OK) {
|
|
+ ERROR("Hash of header failed\n");
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ uret = HASH_SHA256_Start(&hhash, (uint8_t *)buffer,
|
|
+ header->image_length, image_hash,
|
|
+ HASH_TIMEOUT_VALUE);
|
|
+ if (uret != STD_OK) {
|
|
+ ERROR("Hash of payload failed\n");
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ uret = HASH_SHA256_Finish(&hhash, image_hash, HASH_TIMEOUT_VALUE);
|
|
+ if (uret != STD_OK) {
|
|
+ ERROR("Hash of payload failed\n");
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ /* Verify signature */
|
|
+ if (boot_context->p_bootrom_ext_service_ecdsa_verify_signature
|
|
+ (image_hash, header->ecc_pubk, header->image_signature,
|
|
+ header->ecc_algo_type) != STD_OK) {
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
diff --git a/plat/st/common/stm32mp_common.c b/plat/st/common/stm32mp_common.c
|
|
new file mode 100644
|
|
index 0000000..8efac68
|
|
--- /dev/null
|
|
+++ b/plat/st/common/stm32mp_common.c
|
|
@@ -0,0 +1,168 @@
|
|
+/*
|
|
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
|
|
+ *
|
|
+ * SPDX-License-Identifier: BSD-3-Clause
|
|
+ */
|
|
+
|
|
+#include <arch_helpers.h>
|
|
+#include <assert.h>
|
|
+#include <bl_common.h>
|
|
+#include <debug.h>
|
|
+#include <mmio.h>
|
|
+#include <platform.h>
|
|
+#include <platform_def.h>
|
|
+#include <stm32mp_clkfunc.h>
|
|
+#include <stm32mp_common.h>
|
|
+#include <stm32mp_dt.h>
|
|
+
|
|
+uintptr_t plat_get_ns_image_entrypoint(void)
|
|
+{
|
|
+ return BL33_BASE;
|
|
+}
|
|
+
|
|
+unsigned int plat_get_syscnt_freq2(void)
|
|
+{
|
|
+ return read_cntfrq_el0();
|
|
+}
|
|
+
|
|
+#pragma weak stm32mp_plat_reset
|
|
+void __dead2 stm32mp_plat_reset(int cpu)
|
|
+{
|
|
+ panic();
|
|
+}
|
|
+
|
|
+/* Functions to save and get boot context address given by ROM code */
|
|
+static uintptr_t boot_ctx_address;
|
|
+
|
|
+void stm32mp_save_boot_ctx_address(uintptr_t address)
|
|
+{
|
|
+ boot_ctx_address = address;
|
|
+}
|
|
+
|
|
+uintptr_t stm32mp_get_boot_ctx_address(void)
|
|
+{
|
|
+ return boot_ctx_address;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * This function determines if one single core is presently running. This is
|
|
+ * done by OTP read.
|
|
+ * Returns 1 if yes, 0 if more that one core is running, -1 if error.
|
|
+ */
|
|
+#pragma weak stm32mp_is_single_core
|
|
+
|
|
+int stm32mp_is_single_core(void)
|
|
+{
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+uintptr_t stm32mp_ddrctrl_base(void)
|
|
+{
|
|
+ static uintptr_t ddrctrl_base;
|
|
+
|
|
+ if (ddrctrl_base == 0) {
|
|
+ ddrctrl_base = dt_get_ddrctrl_base();
|
|
+
|
|
+ assert(ddrctrl_base == DDRCTRL_BASE);
|
|
+ }
|
|
+
|
|
+ return ddrctrl_base;
|
|
+}
|
|
+
|
|
+uintptr_t stm32mp_ddrphyc_base(void)
|
|
+{
|
|
+ static uintptr_t ddrphyc_base;
|
|
+
|
|
+ if (ddrphyc_base == 0) {
|
|
+ ddrphyc_base = dt_get_ddrphyc_base();
|
|
+
|
|
+ assert(ddrphyc_base == DDRPHYC_BASE);
|
|
+ }
|
|
+
|
|
+ return ddrphyc_base;
|
|
+}
|
|
+
|
|
+uintptr_t stm32mp_pwr_base(void)
|
|
+{
|
|
+ static uintptr_t pwr_base;
|
|
+
|
|
+ if (pwr_base == 0) {
|
|
+ pwr_base = dt_get_pwr_base();
|
|
+
|
|
+ assert(pwr_base == PWR_BASE);
|
|
+ }
|
|
+
|
|
+ return pwr_base;
|
|
+}
|
|
+
|
|
+uintptr_t stm32mp_rcc_base(void)
|
|
+{
|
|
+ static uintptr_t rcc_base;
|
|
+
|
|
+ if (rcc_base == 0) {
|
|
+ rcc_base = fdt_rcc_read_addr();
|
|
+
|
|
+ assert(rcc_base == RCC_BASE);
|
|
+ }
|
|
+
|
|
+ return rcc_base;
|
|
+}
|
|
+
|
|
+uintptr_t stm32_get_gpio_bank_base(unsigned int bank)
|
|
+{
|
|
+ switch (bank) {
|
|
+ case GPIO_BANK_A ... GPIO_BANK_K:
|
|
+ return GPIOA_BASE + (bank * GPIO_BANK_OFFSET);
|
|
+ case GPIO_BANK_Z:
|
|
+ return GPIOZ_BASE;
|
|
+ default:
|
|
+ panic();
|
|
+ }
|
|
+}
|
|
+
|
|
+/* Return clock ID on success, negative value on error */
|
|
+int stm32_get_gpio_bank_clock(unsigned int bank)
|
|
+{
|
|
+ switch (bank) {
|
|
+ case GPIO_BANK_A ... GPIO_BANK_K:
|
|
+ return (int)GPIOA + (bank - GPIO_BANK_A);
|
|
+ case GPIO_BANK_Z:
|
|
+ return (int)GPIOZ;
|
|
+ default:
|
|
+ panic();
|
|
+ }
|
|
+}
|
|
+
|
|
+uint32_t stm32_get_gpio_bank_offset(unsigned int bank)
|
|
+{
|
|
+ if (bank == GPIO_BANK_Z) {
|
|
+ return 0;
|
|
+ } else {
|
|
+ return bank * GPIO_BANK_OFFSET;
|
|
+ }
|
|
+}
|
|
+
|
|
+uint64_t s2tick(uint32_t timeout_s)
|
|
+{
|
|
+ return (uint64_t)timeout_s * read_cntfrq_el0();
|
|
+}
|
|
+
|
|
+uint64_t ms2tick(uint32_t timeout_ms)
|
|
+{
|
|
+ return s2tick(timeout_ms) / 1000U;
|
|
+}
|
|
+
|
|
+uint64_t us2tick(uint32_t timeout_us)
|
|
+{
|
|
+ return s2tick(timeout_us) / (1000U * 1000U);
|
|
+}
|
|
+
|
|
+uint64_t timeout_start(void)
|
|
+{
|
|
+ return read_cntpct_el0();
|
|
+}
|
|
+
|
|
+bool timeout_elapsed(uint64_t tick_start, uint64_t tick_to)
|
|
+{
|
|
+ return (tick_to != 0U) && ((read_cntpct_el0() - tick_start) > tick_to);
|
|
+}
|
|
diff --git a/plat/st/common/stm32mp_dt.c b/plat/st/common/stm32mp_dt.c
|
|
new file mode 100644
|
|
index 0000000..48529cb
|
|
--- /dev/null
|
|
+++ b/plat/st/common/stm32mp_dt.c
|
|
@@ -0,0 +1,559 @@
|
|
+/*
|
|
+ * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
|
|
+ *
|
|
+ * SPDX-License-Identifier: BSD-3-Clause
|
|
+ */
|
|
+
|
|
+#include <assert.h>
|
|
+#include <debug.h>
|
|
+#include <libfdt.h>
|
|
+#include <platform_def.h>
|
|
+#include <stm32_gpio.h>
|
|
+#include <stm32mp_clkfunc.h>
|
|
+#include <stm32mp_common.h>
|
|
+#include <stm32mp_dt.h>
|
|
+
|
|
+static int fdt_checked;
|
|
+
|
|
+static void *fdt = (void *)(uintptr_t)STM32MP_DTB_BASE;
|
|
+
|
|
+/*******************************************************************************
|
|
+ * This function checks device tree file with its header.
|
|
+ * Returns 0 on success and a negative FDT error code on failure.
|
|
+ ******************************************************************************/
|
|
+int dt_open_and_check(void)
|
|
+{
|
|
+ int ret = fdt_check_header(fdt);
|
|
+
|
|
+ if (ret == 0) {
|
|
+ fdt_checked = 1;
|
|
+ }
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+/*******************************************************************************
|
|
+ * This function gets the address of the DT.
|
|
+ * If DT is OK, fdt_addr is filled with DT address.
|
|
+ * Returns 1 if success, 0 otherwise.
|
|
+ ******************************************************************************/
|
|
+int fdt_get_address(void **fdt_addr)
|
|
+{
|
|
+ if (fdt_checked == 1) {
|
|
+ *fdt_addr = fdt;
|
|
+ }
|
|
+
|
|
+ return fdt_checked;
|
|
+}
|
|
+
|
|
+/*******************************************************************************
|
|
+ * This function check the presence of a node (generic use of fdt library).
|
|
+ * Returns true if present, else return false.
|
|
+ ******************************************************************************/
|
|
+bool fdt_check_node(int node)
|
|
+{
|
|
+ int len;
|
|
+ const char *cchar;
|
|
+
|
|
+ cchar = fdt_get_name(fdt, node, &len);
|
|
+
|
|
+ return (cchar != NULL) && (len >= 0);
|
|
+}
|
|
+
|
|
+/*******************************************************************************
|
|
+ * This function return global node status (generic use of fdt library).
|
|
+ ******************************************************************************/
|
|
+uint8_t fdt_get_status(int node)
|
|
+{
|
|
+ uint8_t status = DT_DISABLED;
|
|
+ int len;
|
|
+ const char *cchar;
|
|
+
|
|
+ cchar = fdt_getprop(fdt, node, "status", &len);
|
|
+ if ((cchar == NULL) ||
|
|
+ (strncmp(cchar, "okay", (size_t)len) == 0)) {
|
|
+ status |= DT_NON_SECURE;
|
|
+ }
|
|
+
|
|
+ cchar = fdt_getprop(fdt, node, "secure-status", &len);
|
|
+ if (cchar == NULL) {
|
|
+ if (status == DT_NON_SECURE) {
|
|
+ status |= DT_SECURE;
|
|
+ }
|
|
+ } else if (strncmp(cchar, "okay", (size_t)len) == 0) {
|
|
+ status |= DT_SECURE;
|
|
+ }
|
|
+
|
|
+ return status;
|
|
+}
|
|
+
|
|
+/*******************************************************************************
|
|
+ * This function return interrupts from node.
|
|
+ ******************************************************************************/
|
|
+int fdt_get_interrupt(int node, const fdt32_t **array, int *len, bool *extended)
|
|
+{
|
|
+ uint8_t status = fdt_get_status(node);
|
|
+
|
|
+ *extended = false;
|
|
+
|
|
+ switch (status) {
|
|
+ case DT_SECURE:
|
|
+ *array = fdt_getprop(fdt, node, "interrupts-extended", len);
|
|
+ if (*array == NULL) {
|
|
+ *array = fdt_getprop(fdt, node, "interrupts", len);
|
|
+ } else {
|
|
+ *extended = true;
|
|
+ }
|
|
+ break;
|
|
+
|
|
+ case DT_SHARED:
|
|
+ *array = fdt_getprop(fdt, node, "secure-interrupts", len);
|
|
+ break;
|
|
+
|
|
+ default:
|
|
+ return -FDT_ERR_NOTFOUND;
|
|
+ }
|
|
+
|
|
+ if (*array == NULL) {
|
|
+ return -FDT_ERR_NOTFOUND;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/*******************************************************************************
|
|
+ * This function reads a value of a node property (generic use of fdt
|
|
+ * library).
|
|
+ * Returns value if success, and a default value if property not found.
|
|
+ * Default value is passed as parameter.
|
|
+ ******************************************************************************/
|
|
+uint32_t fdt_read_uint32_default(int node, const char *prop_name,
|
|
+ uint32_t dflt_value)
|
|
+{
|
|
+ const fdt32_t *cuint;
|
|
+ int lenp;
|
|
+
|
|
+ cuint = fdt_getprop(fdt, node, prop_name, &lenp);
|
|
+ if (cuint == NULL) {
|
|
+ return dflt_value;
|
|
+ }
|
|
+
|
|
+ return fdt32_to_cpu(*cuint);
|
|
+}
|
|
+
|
|
+/*******************************************************************************
|
|
+ * This function reads a series of parameters in a node property
|
|
+ * (generic use of fdt library).
|
|
+ * It reads the values inside the device tree, from property name and node.
|
|
+ * The number of parameters is also indicated as entry parameter.
|
|
+ * Returns 0 on success and a negative FDT error code on failure.
|
|
+ * If success, values are stored at the third parameter address.
|
|
+ ******************************************************************************/
|
|
+int fdt_read_uint32_array(int node, const char *prop_name, uint32_t *array,
|
|
+ uint32_t count)
|
|
+{
|
|
+ const fdt32_t *cuint;
|
|
+ int len;
|
|
+ uint32_t i;
|
|
+
|
|
+ cuint = fdt_getprop(fdt, node, prop_name, &len);
|
|
+ if (cuint == NULL) {
|
|
+ return -FDT_ERR_NOTFOUND;
|
|
+ }
|
|
+
|
|
+ if ((uint32_t)len != (count * sizeof(uint32_t))) {
|
|
+ return -FDT_ERR_BADLAYOUT;
|
|
+ }
|
|
+
|
|
+ for (i = 0; i < ((uint32_t)len / sizeof(uint32_t)); i++) {
|
|
+ *array = fdt32_to_cpu(*cuint);
|
|
+ array++;
|
|
+ cuint++;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/*******************************************************************************
|
|
+ * This function fills reg node info (base & size) with an index found by
|
|
+ * checking the reg-names node.
|
|
+ * Returns 0 on success and a negative FDT error code on failure.
|
|
+ ******************************************************************************/
|
|
+int fdt_get_reg_props_by_name(int node, const char *name, uintptr_t *base,
|
|
+ size_t *size)
|
|
+{
|
|
+ const fdt32_t *cuint;
|
|
+ int index, len;
|
|
+
|
|
+ index = fdt_stringlist_search(fdt, node, "reg-names", name);
|
|
+ if (index < 0) {
|
|
+ return index;
|
|
+ }
|
|
+
|
|
+ cuint = fdt_getprop(fdt, node, "reg", &len);
|
|
+ if (cuint == NULL) {
|
|
+ return -FDT_ERR_NOTFOUND;
|
|
+ }
|
|
+
|
|
+ if ((index * (int)sizeof(uint32_t)) > len) {
|
|
+ return -FDT_ERR_BADVALUE;
|
|
+ }
|
|
+
|
|
+ cuint += index << 1;
|
|
+ *base = fdt32_to_cpu(*cuint);
|
|
+ cuint++;
|
|
+ *size = fdt32_to_cpu(*cuint);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/*******************************************************************************
|
|
+ * This function gets the stdout path node.
|
|
+ * It reads the value indicated inside the device tree.
|
|
+ * Returns node on success and a negative FDT error code on failure.
|
|
+ ******************************************************************************/
|
|
+static int dt_get_stdout_node_offset(void)
|
|
+{
|
|
+ int node;
|
|
+ const char *cchar;
|
|
+
|
|
+ node = fdt_path_offset(fdt, "/secure-chosen");
|
|
+ if (node < 0) {
|
|
+ node = fdt_path_offset(fdt, "/chosen");
|
|
+ if (node < 0) {
|
|
+ return -FDT_ERR_NOTFOUND;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ cchar = fdt_getprop(fdt, node, "stdout-path", NULL);
|
|
+ if (cchar == NULL) {
|
|
+ return -FDT_ERR_NOTFOUND;
|
|
+ }
|
|
+
|
|
+ node = -FDT_ERR_NOTFOUND;
|
|
+ if (strchr(cchar, (int)':') != NULL) {
|
|
+ const char *name;
|
|
+ char *str = (char *)cchar;
|
|
+ int len = 0;
|
|
+
|
|
+ while (strncmp(":", str, 1)) {
|
|
+ len++;
|
|
+ str++;
|
|
+ }
|
|
+
|
|
+ name = fdt_get_alias_namelen(fdt, cchar, len);
|
|
+
|
|
+ if (name != NULL) {
|
|
+ node = fdt_path_offset(fdt, name);
|
|
+ }
|
|
+ } else {
|
|
+ node = fdt_path_offset(fdt, cchar);
|
|
+ }
|
|
+
|
|
+ return node;
|
|
+}
|
|
+
|
|
+/*******************************************************************************
|
|
+ * This function gets the stdout pin configuration information from the DT.
|
|
+ * And then calls the sub-function to treat it and set GPIO registers.
|
|
+ * Returns 0 on success and a negative FDT error code on failure.
|
|
+ ******************************************************************************/
|
|
+int dt_set_stdout_pinctrl(void)
|
|
+{
|
|
+ int node;
|
|
+
|
|
+ node = dt_get_stdout_node_offset();
|
|
+ if (node < 0) {
|
|
+ return -FDT_ERR_NOTFOUND;
|
|
+ }
|
|
+
|
|
+ return dt_set_pinctrl_config(node);
|
|
+}
|
|
+
|
|
+/*******************************************************************************
|
|
+ * This function fills the generic information from a given node.
|
|
+ ******************************************************************************/
|
|
+void dt_fill_device_info(struct dt_node_info *info, int node)
|
|
+{
|
|
+ const fdt32_t *cuint;
|
|
+
|
|
+ cuint = fdt_getprop(fdt, node, "reg", NULL);
|
|
+ if (cuint != NULL) {
|
|
+ info->base = fdt32_to_cpu(*cuint);
|
|
+ } else {
|
|
+ info->base = 0;
|
|
+ }
|
|
+
|
|
+ cuint = fdt_getprop(fdt, node, "clocks", NULL);
|
|
+ if (cuint != NULL) {
|
|
+ cuint++;
|
|
+ info->clock = (int)fdt32_to_cpu(*cuint);
|
|
+ } else {
|
|
+ info->clock = -1;
|
|
+ }
|
|
+
|
|
+ cuint = fdt_getprop(fdt, node, "resets", NULL);
|
|
+ if (cuint != NULL) {
|
|
+ cuint++;
|
|
+ info->reset = (int)fdt32_to_cpu(*cuint);
|
|
+ } else {
|
|
+ info->reset = -1;
|
|
+ }
|
|
+
|
|
+ info->status = fdt_get_status(node);
|
|
+}
|
|
+
|
|
+/*******************************************************************************
|
|
+ * This function retrieve the generic information from DT.
|
|
+ * Returns node on success and a negative FDT error code on failure.
|
|
+ ******************************************************************************/
|
|
+int dt_get_node(struct dt_node_info *info, int offset, const char *compat)
|
|
+{
|
|
+ int node;
|
|
+
|
|
+ node = fdt_node_offset_by_compatible(fdt, offset, compat);
|
|
+ if (node < 0) {
|
|
+ return -FDT_ERR_NOTFOUND;
|
|
+ }
|
|
+
|
|
+ dt_fill_device_info(info, node);
|
|
+
|
|
+ return node;
|
|
+}
|
|
+
|
|
+/*******************************************************************************
|
|
+ * This function gets the UART instance info of stdout from the DT.
|
|
+ * Returns node on success and a negative FDT error code on failure.
|
|
+ ******************************************************************************/
|
|
+int dt_get_stdout_uart_info(struct dt_node_info *info)
|
|
+{
|
|
+ int node;
|
|
+
|
|
+ node = dt_get_stdout_node_offset();
|
|
+ if (node < 0) {
|
|
+ return -FDT_ERR_NOTFOUND;
|
|
+ }
|
|
+
|
|
+ dt_fill_device_info(info, node);
|
|
+
|
|
+ return node;
|
|
+}
|
|
+
|
|
+/*******************************************************************************
|
|
+ * This function gets DDR size information from the DT.
|
|
+ * Returns value in bytes on success, and 0 on failure.
|
|
+ ******************************************************************************/
|
|
+uint32_t dt_get_ddr_size(void)
|
|
+{
|
|
+ int node;
|
|
+
|
|
+ node = fdt_node_offset_by_compatible(fdt, -1, DT_DDR_COMPAT);
|
|
+ if (node < 0) {
|
|
+ INFO("%s: Cannot read DDR node in DT\n", __func__);
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ return fdt_read_uint32_default(node, "st,mem-size", 0);
|
|
+}
|
|
+
|
|
+/*******************************************************************************
|
|
+ * This function gets DDRCTRL base address information from the DT.
|
|
+ * Returns value on success, and 0 on failure.
|
|
+ ******************************************************************************/
|
|
+uintptr_t dt_get_ddrctrl_base(void)
|
|
+{
|
|
+ int node;
|
|
+ uint32_t array[4];
|
|
+
|
|
+ node = fdt_node_offset_by_compatible(fdt, -1, DT_DDR_COMPAT);
|
|
+ if (node < 0) {
|
|
+ INFO("%s: Cannot read DDR node in DT\n", __func__);
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ if (fdt_read_uint32_array(node, "reg", array, 4) < 0) {
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ return array[0];
|
|
+}
|
|
+
|
|
+/*******************************************************************************
|
|
+ * This function gets DDRPHYC base address information from the DT.
|
|
+ * Returns value on success, and 0 on failure.
|
|
+ ******************************************************************************/
|
|
+uintptr_t dt_get_ddrphyc_base(void)
|
|
+{
|
|
+ int node;
|
|
+ uint32_t array[4];
|
|
+
|
|
+ node = fdt_node_offset_by_compatible(fdt, -1, DT_DDR_COMPAT);
|
|
+ if (node < 0) {
|
|
+ INFO("%s: Cannot read DDR node in DT\n", __func__);
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ if (fdt_read_uint32_array(node, "reg", array, 4) < 0) {
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ return array[2];
|
|
+}
|
|
+
|
|
+/*******************************************************************************
|
|
+ * This function gets PWR base address information from the DT.
|
|
+ * Returns value on success, and 0 on failure.
|
|
+ ******************************************************************************/
|
|
+uintptr_t dt_get_pwr_base(void)
|
|
+{
|
|
+ int node;
|
|
+ const fdt32_t *cuint;
|
|
+
|
|
+ node = fdt_node_offset_by_compatible(fdt, -1, DT_PWR_COMPAT);
|
|
+ if (node < 0) {
|
|
+ INFO("%s: Cannot read PWR node in DT\n", __func__);
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ cuint = fdt_getprop(fdt, node, "reg", NULL);
|
|
+ if (cuint == NULL) {
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ return fdt32_to_cpu(*cuint);
|
|
+}
|
|
+
|
|
+/*******************************************************************************
|
|
+ * This function gets PWR VDD regulator voltage information from the DT.
|
|
+ * Returns value in microvolts on success, and 0 on failure.
|
|
+ ******************************************************************************/
|
|
+uint32_t dt_get_pwr_vdd_voltage(void)
|
|
+{
|
|
+ int node;
|
|
+ const fdt32_t *cuint;
|
|
+
|
|
+ node = fdt_node_offset_by_compatible(fdt, -1, DT_PWR_COMPAT);
|
|
+ if (node < 0) {
|
|
+ INFO("%s: Cannot read PWR node in DT\n", __func__);
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ cuint = fdt_getprop(fdt, node, "pwr-supply", NULL);
|
|
+ if (cuint == NULL) {
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ node = fdt_node_offset_by_phandle(fdt, fdt32_to_cpu(*cuint));
|
|
+ if (node < 0) {
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ cuint = fdt_getprop(fdt, node, "regulator-min-microvolt", NULL);
|
|
+ if (cuint == NULL) {
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ return fdt32_to_cpu(*cuint);
|
|
+}
|
|
+
|
|
+/*******************************************************************************
|
|
+ * This function gets SYSCFG base address information from the DT.
|
|
+ * Returns value on success, and 0 on failure.
|
|
+ ******************************************************************************/
|
|
+uintptr_t dt_get_syscfg_base(void)
|
|
+{
|
|
+ int node;
|
|
+ const fdt32_t *cuint;
|
|
+
|
|
+ node = fdt_node_offset_by_compatible(fdt, -1, DT_SYSCFG_COMPAT);
|
|
+ if (node < 0) {
|
|
+ INFO("%s: Cannot read SYSCFG node in DT\n", __func__);
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ cuint = fdt_getprop(fdt, node, "reg", NULL);
|
|
+ if (cuint == NULL) {
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ return fdt32_to_cpu(*cuint);
|
|
+}
|
|
+
|
|
+/*******************************************************************************
|
|
+ * This function retrieves board model from DT
|
|
+ * Returns string taken from model node, NULL otherwise
|
|
+ ******************************************************************************/
|
|
+const char *dt_get_board_model(void)
|
|
+{
|
|
+ int node = fdt_path_offset(fdt, "/");
|
|
+
|
|
+ if (node < 0) {
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ return (const char *)fdt_getprop(fdt, node, "model", NULL);
|
|
+}
|
|
+
|
|
+/*******************************************************************************
|
|
+ * This function gets GPIO bank PINCTRL node information from the DT.
|
|
+ * Returns node value.
|
|
+ ******************************************************************************/
|
|
+int fdt_get_gpio_bank_pinctrl_node(unsigned int bank)
|
|
+{
|
|
+ switch (bank) {
|
|
+ case GPIO_BANK_A ... GPIO_BANK_K:
|
|
+ return fdt_path_offset(fdt, "/soc/pin-controller");
|
|
+ case GPIO_BANK_Z:
|
|
+ return fdt_path_offset(fdt, "/soc/pin-controller-z");
|
|
+ default:
|
|
+ panic();
|
|
+ }
|
|
+}
|
|
+
|
|
+/*******************************************************************************
|
|
+ * This function gets GPIOZ pin number information from the DT.
|
|
+ * It also checks node consistency.
|
|
+ ******************************************************************************/
|
|
+int fdt_get_gpioz_nbpins_from_dt(void)
|
|
+{
|
|
+ int pinctrl_node;
|
|
+ int pinctrl_subnode;
|
|
+
|
|
+ pinctrl_node = fdt_get_gpio_bank_pinctrl_node(GPIO_BANK_Z);
|
|
+ if (pinctrl_node < 0) {
|
|
+ return -FDT_ERR_NOTFOUND;
|
|
+ }
|
|
+
|
|
+ fdt_for_each_subnode(pinctrl_subnode, fdt, pinctrl_node) {
|
|
+ uint32_t bank_offset;
|
|
+ const fdt32_t *cuint;
|
|
+
|
|
+ if (fdt_getprop(fdt, pinctrl_subnode,
|
|
+ "gpio-controller", NULL) == NULL) {
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ cuint = fdt_getprop(fdt, pinctrl_subnode, "reg", NULL);
|
|
+ if (cuint == NULL) {
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ bank_offset = stm32_get_gpio_bank_offset(GPIO_BANK_Z);
|
|
+ if (fdt32_to_cpu(*cuint) != bank_offset) {
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ if (fdt_get_status(pinctrl_subnode) == DT_DISABLED) {
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ cuint = fdt_getprop(fdt, pinctrl_subnode, "ngpios", NULL);
|
|
+ if (cuint == NULL) {
|
|
+ return -FDT_ERR_NOTFOUND;
|
|
+ }
|
|
+
|
|
+ return (int)fdt32_to_cpu(*cuint);
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
diff --git a/plat/st/common/stm32mp_shres_helpers.c b/plat/st/common/stm32mp_shres_helpers.c
|
|
new file mode 100644
|
|
index 0000000..b8bc2ec
|
|
--- /dev/null
|
|
+++ b/plat/st/common/stm32mp_shres_helpers.c
|
|
@@ -0,0 +1,71 @@
|
|
+/*
|
|
+ * Copyright (C) 2018, STMicroelectronics - All Rights Reserved
|
|
+ *
|
|
+ * SPDX-License-Identifier: BSD-3-Clause
|
|
+ */
|
|
+
|
|
+#include <arch_helpers.h>
|
|
+#include <mmio.h>
|
|
+#include <spinlock.h>
|
|
+#include <stm32mp_shres_helpers.h>
|
|
+
|
|
+static struct spinlock shregs_lock;
|
|
+
|
|
+static int stm32mp_lock_available(void)
|
|
+{
|
|
+ /* The spinlocks are used only when MMU is enabled */
|
|
+#ifdef AARCH32
|
|
+ return (read_sctlr() & SCTLR_M_BIT) && (read_sctlr() & SCTLR_C_BIT);
|
|
+#else
|
|
+ return (read_sctlr_el3() & SCTLR_M_BIT) &&
|
|
+ (read_sctlr_el3() & SCTLR_C_BIT);
|
|
+#endif
|
|
+}
|
|
+
|
|
+void stm32mp_lock_shregs(void)
|
|
+{
|
|
+ if (stm32mp_lock_available() == 0U) {
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ /* Assume interrupts are masked */
|
|
+ spin_lock(&shregs_lock);
|
|
+}
|
|
+
|
|
+void stm32mp_unlock_shregs(void)
|
|
+{
|
|
+ if (stm32mp_lock_available() == 0U) {
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ spin_unlock(&shregs_lock);
|
|
+}
|
|
+
|
|
+/* Shared register access: upon shared resource lock */
|
|
+void stm32mp_mmio_clrsetbits_32_shregs(uintptr_t addr, uint32_t clear,
|
|
+ uint32_t set)
|
|
+{
|
|
+ stm32mp_lock_shregs();
|
|
+
|
|
+ mmio_clrsetbits_32(addr, clear, set);
|
|
+
|
|
+ stm32mp_unlock_shregs();
|
|
+}
|
|
+
|
|
+void stm32mp_mmio_clrbits_32_shregs(uintptr_t addr, uint32_t clear)
|
|
+{
|
|
+ stm32mp_lock_shregs();
|
|
+
|
|
+ mmio_clrbits_32(addr, clear);
|
|
+
|
|
+ stm32mp_unlock_shregs();
|
|
+}
|
|
+
|
|
+void stm32mp_mmio_setbits_32_shregs(uintptr_t addr, uint32_t set)
|
|
+{
|
|
+ stm32mp_lock_shregs();
|
|
+
|
|
+ mmio_setbits_32(addr, set);
|
|
+
|
|
+ stm32mp_unlock_shregs();
|
|
+}
|
|
diff --git a/plat/st/stm32mp1/bl2_io_storage.c b/plat/st/stm32mp1/bl2_io_storage.c
|
|
deleted file mode 100644
|
|
index 7346c0c..0000000
|
|
--- a/plat/st/stm32mp1/bl2_io_storage.c
|
|
+++ /dev/null
|
|
@@ -1,193 +0,0 @@
|
|
-/*
|
|
- * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
|
|
- *
|
|
- * SPDX-License-Identifier: BSD-3-Clause
|
|
- */
|
|
-
|
|
-#include <arch_helpers.h>
|
|
-#include <assert.h>
|
|
-#include <boot_api.h>
|
|
-#include <debug.h>
|
|
-#include <io_driver.h>
|
|
-#include <io_dummy.h>
|
|
-#include <io_storage.h>
|
|
-#include <mmio.h>
|
|
-#include <platform.h>
|
|
-#include <platform_def.h>
|
|
-#include <stm32mp1_private.h>
|
|
-#include <stm32mp1_rcc.h>
|
|
-#include <string.h>
|
|
-#include <utils.h>
|
|
-
|
|
-/* IO devices */
|
|
-static const io_dev_connector_t *dummy_dev_con;
|
|
-static uintptr_t dummy_dev_handle;
|
|
-static uintptr_t dummy_dev_spec;
|
|
-
|
|
-static const io_block_spec_t bl32_block_spec = {
|
|
- .offset = BL32_BASE,
|
|
- .length = STM32MP1_BL32_SIZE
|
|
-};
|
|
-
|
|
-static const io_block_spec_t bl2_block_spec = {
|
|
- .offset = BL2_BASE,
|
|
- .length = STM32MP1_BL2_SIZE,
|
|
-};
|
|
-
|
|
-static int open_dummy(const uintptr_t spec);
|
|
-
|
|
-struct plat_io_policy {
|
|
- uintptr_t *dev_handle;
|
|
- uintptr_t image_spec;
|
|
- int (*check)(const uintptr_t spec);
|
|
-};
|
|
-
|
|
-static const struct plat_io_policy policies[] = {
|
|
- [BL2_IMAGE_ID] = {
|
|
- .dev_handle = &dummy_dev_handle,
|
|
- .image_spec = (uintptr_t)&bl2_block_spec,
|
|
- .check = open_dummy
|
|
- },
|
|
- [BL32_IMAGE_ID] = {
|
|
- .dev_handle = &dummy_dev_handle,
|
|
- .image_spec = (uintptr_t)&bl32_block_spec,
|
|
- .check = open_dummy
|
|
- },
|
|
-};
|
|
-
|
|
-static int open_dummy(const uintptr_t spec)
|
|
-{
|
|
- return io_dev_init(dummy_dev_handle, 0);
|
|
-}
|
|
-
|
|
-static void print_boot_device(boot_api_context_t *boot_context)
|
|
-{
|
|
- switch (boot_context->boot_interface_selected) {
|
|
- case BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_SD:
|
|
- INFO("Using SDMMC\n");
|
|
- break;
|
|
- case BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_EMMC:
|
|
- INFO("Using EMMC\n");
|
|
- break;
|
|
- default:
|
|
- ERROR("Boot interface not found\n");
|
|
- panic();
|
|
- break;
|
|
- }
|
|
-
|
|
- if (boot_context->boot_interface_instance != 0U) {
|
|
- INFO(" Instance %d\n", boot_context->boot_interface_instance);
|
|
- }
|
|
-}
|
|
-
|
|
-static void print_reset_reason(void)
|
|
-{
|
|
- uint32_t rstsr = mmio_read_32(RCC_BASE + RCC_MP_RSTSCLRR);
|
|
-
|
|
- if (rstsr == 0U) {
|
|
- WARN("Reset reason unknown\n");
|
|
- return;
|
|
- }
|
|
-
|
|
- INFO("Reset reason (0x%x):\n", rstsr);
|
|
-
|
|
- if ((rstsr & RCC_MP_RSTSCLRR_PADRSTF) == 0U) {
|
|
- if ((rstsr & RCC_MP_RSTSCLRR_STDBYRSTF) != 0U) {
|
|
- INFO("System exits from STANDBY\n");
|
|
- return;
|
|
- }
|
|
-
|
|
- if ((rstsr & RCC_MP_RSTSCLRR_CSTDBYRSTF) != 0U) {
|
|
- INFO("MPU exits from CSTANDBY\n");
|
|
- return;
|
|
- }
|
|
- }
|
|
-
|
|
- if ((rstsr & RCC_MP_RSTSCLRR_PORRSTF) != 0U) {
|
|
- INFO(" Power-on Reset (rst_por)\n");
|
|
- return;
|
|
- }
|
|
-
|
|
- if ((rstsr & RCC_MP_RSTSCLRR_BORRSTF) != 0U) {
|
|
- INFO(" Brownout Reset (rst_bor)\n");
|
|
- return;
|
|
- }
|
|
-
|
|
- if ((rstsr & RCC_MP_RSTSCLRR_MPSYSRSTF) != 0U) {
|
|
- INFO(" System reset generated by MPU (MPSYSRST)\n");
|
|
- return;
|
|
- }
|
|
-
|
|
- if ((rstsr & RCC_MP_RSTSCLRR_HCSSRSTF) != 0U) {
|
|
- INFO(" Reset due to a clock failure on HSE\n");
|
|
- return;
|
|
- }
|
|
-
|
|
- if ((rstsr & RCC_MP_RSTSCLRR_IWDG1RSTF) != 0U) {
|
|
- INFO(" IWDG1 Reset (rst_iwdg1)\n");
|
|
- return;
|
|
- }
|
|
-
|
|
- if ((rstsr & RCC_MP_RSTSCLRR_IWDG2RSTF) != 0U) {
|
|
- INFO(" IWDG2 Reset (rst_iwdg2)\n");
|
|
- return;
|
|
- }
|
|
-
|
|
- if ((rstsr & RCC_MP_RSTSCLRR_PADRSTF) != 0U) {
|
|
- INFO(" Pad Reset from NRST\n");
|
|
- return;
|
|
- }
|
|
-
|
|
- if ((rstsr & RCC_MP_RSTSCLRR_VCORERSTF) != 0U) {
|
|
- INFO(" Reset due to a failure of VDD_CORE\n");
|
|
- return;
|
|
- }
|
|
-
|
|
- ERROR(" Unidentified reset reason\n");
|
|
-}
|
|
-
|
|
-void stm32mp1_io_setup(void)
|
|
-{
|
|
- int io_result __unused;
|
|
- boot_api_context_t *boot_context =
|
|
- (boot_api_context_t *)stm32mp1_get_boot_ctx_address();
|
|
-
|
|
- print_reset_reason();
|
|
-
|
|
- print_boot_device(boot_context);
|
|
-
|
|
- if ((boot_context->boot_partition_used_toboot == 1U) ||
|
|
- (boot_context->boot_partition_used_toboot == 2U)) {
|
|
- INFO("Boot used partition fsbl%d\n",
|
|
- boot_context->boot_partition_used_toboot);
|
|
- }
|
|
-
|
|
- io_result = register_io_dev_dummy(&dummy_dev_con);
|
|
- assert(io_result == 0);
|
|
-
|
|
- io_result = io_dev_open(dummy_dev_con, dummy_dev_spec,
|
|
- &dummy_dev_handle);
|
|
- assert(io_result == 0);
|
|
-}
|
|
-
|
|
-/*
|
|
- * Return an IO device handle and specification which can be used to access
|
|
- * an image. Use this to enforce platform load policy.
|
|
- */
|
|
-int plat_get_image_source(unsigned int image_id, uintptr_t *dev_handle,
|
|
- uintptr_t *image_spec)
|
|
-{
|
|
- int rc;
|
|
- const struct plat_io_policy *policy;
|
|
-
|
|
- assert(image_id < ARRAY_SIZE(policies));
|
|
-
|
|
- policy = &policies[image_id];
|
|
- rc = policy->check(policy->image_spec);
|
|
- if (rc == 0) {
|
|
- *image_spec = policy->image_spec;
|
|
- *dev_handle = *(policy->dev_handle);
|
|
- }
|
|
-
|
|
- return rc;
|
|
-}
|
|
diff --git a/plat/st/stm32mp1/bl2_plat_setup.c b/plat/st/stm32mp1/bl2_plat_setup.c
|
|
index 9f2d8bd..cd5d5b3 100644
|
|
--- a/plat/st/stm32mp1/bl2_plat_setup.c
|
|
+++ b/plat/st/stm32mp1/bl2_plat_setup.c
|
|
@@ -1,5 +1,5 @@
|
|
/*
|
|
- * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
|
|
+ * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved.
|
|
*
|
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
*/
|
|
@@ -8,38 +8,154 @@
|
|
#include <assert.h>
|
|
#include <bl_common.h>
|
|
#include <boot_api.h>
|
|
-#include <console.h>
|
|
+#include <bsec.h>
|
|
#include <debug.h>
|
|
#include <delay_timer.h>
|
|
#include <desc_image_load.h>
|
|
+#include <dt-bindings/clock/stm32mp1-clks.h>
|
|
+#include <dt-bindings/reset/stm32mp1-resets.h>
|
|
#include <generic_delay_timer.h>
|
|
#include <mmio.h>
|
|
+#include <optee_utils.h>
|
|
#include <platform.h>
|
|
#include <platform_def.h>
|
|
+#include <stm32_console.h>
|
|
+#include <stm32_gpio.h>
|
|
+#include <stm32_iwdg.h>
|
|
+#include <stm32mp_common.h>
|
|
+#include <stm32mp_dt.h>
|
|
+#include <stm32mp_pmic.h>
|
|
+#include <stm32mp_reset.h>
|
|
+#include <stm32mp1xx_hal_uart.h>
|
|
#include <stm32mp1_clk.h>
|
|
-#include <stm32mp1_dt.h>
|
|
-#include <stm32mp1_pmic.h>
|
|
-#include <stm32mp1_private.h>
|
|
#include <stm32mp1_context.h>
|
|
+#include <stm32mp1_dbgmcu.h>
|
|
+#include <stm32mp1_private.h>
|
|
#include <stm32mp1_pwr.h>
|
|
#include <stm32mp1_ram.h>
|
|
#include <stm32mp1_rcc.h>
|
|
-#include <stm32mp1_reset.h>
|
|
+#include <stm32mp1_shared_resources.h>
|
|
#include <string.h>
|
|
#include <xlat_tables_v2.h>
|
|
|
|
-void bl2_el3_early_platform_setup(u_register_t arg0, u_register_t arg1,
|
|
- u_register_t arg2, u_register_t arg3)
|
|
+#define PWRLP_TEMPO_5_HSI 5
|
|
+
|
|
+static struct console_stm32 console;
|
|
+static enum boot_device_e boot_device = BOOT_DEVICE_BOARD;
|
|
+
|
|
+static void print_reset_reason(void)
|
|
{
|
|
- stm32mp1_save_boot_ctx_address(arg0);
|
|
+ uint32_t rstsr = mmio_read_32(stm32mp_rcc_base() + RCC_MP_RSTSCLRR);
|
|
+
|
|
+ if (rstsr == 0U) {
|
|
+ WARN("Reset reason unknown\n");
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ INFO("Reset reason (0x%x):\n", rstsr);
|
|
+
|
|
+ if ((rstsr & RCC_MP_RSTSCLRR_PADRSTF) == 0U) {
|
|
+ if ((rstsr & RCC_MP_RSTSCLRR_STDBYRSTF) != 0U) {
|
|
+ INFO("System exits from STANDBY\n");
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ if ((rstsr & RCC_MP_RSTSCLRR_CSTDBYRSTF) != 0U) {
|
|
+ INFO("MPU exits from CSTANDBY\n");
|
|
+ return;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if ((rstsr & RCC_MP_RSTSCLRR_PORRSTF) != 0U) {
|
|
+ INFO(" Power-on Reset (rst_por)\n");
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ if ((rstsr & RCC_MP_RSTSCLRR_BORRSTF) != 0U) {
|
|
+ INFO(" Brownout Reset (rst_bor)\n");
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ if ((rstsr & RCC_MP_RSTSCLRR_MCSYSRSTF) != 0U) {
|
|
+ if ((rstsr & RCC_MP_RSTSCLRR_PADRSTF) != 0U)
|
|
+ INFO(" System reset generated by MCU (MCSYSRST)\n");
|
|
+ else
|
|
+ INFO(" Local reset generated by MCU (MCSYSRST)\n");
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ if ((rstsr & RCC_MP_RSTSCLRR_MPSYSRSTF) != 0U) {
|
|
+ INFO(" System reset generated by MPU (MPSYSRST)\n");
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ if ((rstsr & RCC_MP_RSTSCLRR_HCSSRSTF) != 0U) {
|
|
+ INFO(" Reset due to a clock failure on HSE\n");
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ if ((rstsr & RCC_MP_RSTSCLRR_IWDG1RSTF) != 0U) {
|
|
+ INFO(" IWDG1 Reset (rst_iwdg1)\n");
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ if ((rstsr & RCC_MP_RSTSCLRR_IWDG2RSTF) != 0U) {
|
|
+ INFO(" IWDG2 Reset (rst_iwdg2)\n");
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ if ((rstsr & RCC_MP_RSTSCLRR_MPUP0RSTF) != 0U) {
|
|
+ INFO(" MPU Processor 0 Reset\n");
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ if ((rstsr & RCC_MP_RSTSCLRR_MPUP1RSTF) != 0U) {
|
|
+ INFO(" MPU Processor 1 Reset\n");
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ if ((rstsr & RCC_MP_RSTSCLRR_PADRSTF) != 0U) {
|
|
+ INFO(" Pad Reset from NRST\n");
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ if ((rstsr & RCC_MP_RSTSCLRR_VCORERSTF) != 0U) {
|
|
+ INFO(" Reset due to a failure of VDD_CORE\n");
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ ERROR(" Unidentified reset reason\n");
|
|
+}
|
|
+
|
|
+enum boot_device_e get_boot_device(void)
|
|
+{
|
|
+ return boot_device;
|
|
+}
|
|
+
|
|
+void bl2_el3_early_platform_setup(u_register_t arg0,
|
|
+ u_register_t arg1 __unused,
|
|
+ u_register_t arg2 __unused,
|
|
+ u_register_t arg3 __unused)
|
|
+{
|
|
+ stm32mp_save_boot_ctx_address(arg0);
|
|
}
|
|
|
|
void bl2_platform_setup(void)
|
|
{
|
|
int ret;
|
|
|
|
- if (dt_check_pmic()) {
|
|
+ if (dt_pmic_status() > 0) {
|
|
initialize_pmic();
|
|
+#if STM32MP1_DEBUG_ENABLE
|
|
+ /* Program PMIC to keep debug ON */
|
|
+ if ((stm32mp1_dbgmcu_boot_debug_info() == 1) &&
|
|
+ (stm32mp1_dbgmcu_is_debug_on() != 0)) {
|
|
+ VERBOSE("Program PMIC to keep debug ON\n");
|
|
+ if (pmic_keep_debug_unit() != 0) {
|
|
+ ERROR("PMIC not properly set for debug\n");
|
|
+ }
|
|
+ }
|
|
+#endif
|
|
}
|
|
|
|
ret = stm32mp1_ddr_probe();
|
|
@@ -48,62 +164,156 @@ void bl2_platform_setup(void)
|
|
panic();
|
|
}
|
|
|
|
+#ifdef AARCH32_SP_OPTEE
|
|
+ INFO("BL2 runs OP-TEE setup\n");
|
|
+ /* Initialize tzc400 after DDR initialization */
|
|
+ stm32mp1_security_setup();
|
|
+#else
|
|
INFO("BL2 runs SP_MIN setup\n");
|
|
+#endif
|
|
}
|
|
|
|
void bl2_el3_plat_arch_setup(void)
|
|
{
|
|
int32_t result;
|
|
- struct dt_node_info dt_dev_info;
|
|
+ struct dt_node_info dt_uart_info;
|
|
const char *board_model;
|
|
boot_api_context_t *boot_context =
|
|
- (boot_api_context_t *)stm32mp1_get_boot_ctx_address();
|
|
+ (boot_api_context_t *)stm32mp_get_boot_ctx_address();
|
|
uint32_t clk_rate;
|
|
+ uintptr_t pwr_base;
|
|
+ uintptr_t rcc_base;
|
|
+ uint32_t bkpr_core1_magic =
|
|
+ tamp_bkpr(BOOT_API_CORE1_MAGIC_NUMBER_TAMP_BCK_REG_IDX);
|
|
+ uint32_t bkpr_core1_addr =
|
|
+ tamp_bkpr(BOOT_API_CORE1_BRANCH_ADDRESS_TAMP_BCK_REG_IDX);
|
|
+
|
|
+ mmap_add_region(BL_CODE_BASE, BL_CODE_BASE,
|
|
+ BL_CODE_END - BL_CODE_BASE,
|
|
+ MT_CODE | MT_SECURE);
|
|
+
|
|
+#if SEPARATE_CODE_AND_RODATA
|
|
+ mmap_add_region(BL_RO_DATA_BASE, BL_RO_DATA_BASE,
|
|
+ BL_RO_DATA_LIMIT - BL_RO_DATA_BASE,
|
|
+ MT_RO_DATA | MT_SECURE);
|
|
+#endif
|
|
+
|
|
+#ifdef AARCH32_SP_OPTEE
|
|
+ /* OP-TEE image needs post load processing: keep RAM read/write */
|
|
+ mmap_add_region(STM32MP_DDR_BASE + dt_get_ddr_size() -
|
|
+ STM32MP_DDR_S_SIZE,
|
|
+ STM32MP_DDR_BASE + dt_get_ddr_size() -
|
|
+ STM32MP_DDR_S_SIZE,
|
|
+ STM32MP_DDR_S_SIZE,
|
|
+ MT_MEMORY | MT_RW | MT_SECURE);
|
|
+
|
|
+ mmap_add_region(STM32MP_OPTEE_BASE, STM32MP_OPTEE_BASE,
|
|
+ STM32MP_OPTEE_SIZE,
|
|
+ MT_MEMORY | MT_RW | MT_SECURE);
|
|
+#else
|
|
+ /* Prevent corruption of preloaded BL32 */
|
|
+ mmap_add_region(BL32_BASE, BL32_BASE,
|
|
+ BL32_LIMIT - BL32_BASE,
|
|
+ MT_MEMORY | MT_RO | MT_SECURE);
|
|
+
|
|
+#endif
|
|
+ /* Map non secure DDR for BL33 load and DDR training area restore */
|
|
+ mmap_add_region(STM32MP_DDR_BASE,
|
|
+ STM32MP_DDR_BASE,
|
|
+ STM32MP_DDR_MAX_SIZE,
|
|
+ MT_MEMORY | MT_RW | MT_NS);
|
|
+
|
|
+ /* Prevent corruption of preloaded Device Tree */
|
|
+ mmap_add_region(DTB_BASE, DTB_BASE,
|
|
+ DTB_LIMIT - DTB_BASE,
|
|
+ MT_MEMORY | MT_RO | MT_SECURE);
|
|
+
|
|
+ configure_mmu();
|
|
+
|
|
+ if (dt_open_and_check() < 0) {
|
|
+ panic();
|
|
+ }
|
|
+
|
|
+ pwr_base = stm32mp_pwr_base();
|
|
+ rcc_base = stm32mp_rcc_base();
|
|
+
|
|
+ /* Clear Stop Request bits to correctly manage low-power exit */
|
|
+ mmio_write_32(rcc_base + RCC_MP_SREQCLRR,
|
|
+ (uint32_t)(RCC_MP_SREQCLRR_STPREQ_P0 |
|
|
+ RCC_MP_SREQCLRR_STPREQ_P1));
|
|
|
|
/*
|
|
* Disable the backup domain write protection.
|
|
* The protection is enable at each reset by hardware
|
|
* and must be disabled by software.
|
|
*/
|
|
- mmio_setbits_32(PWR_BASE + PWR_CR1, PWR_CR1_DBP);
|
|
+ mmio_setbits_32(pwr_base + PWR_CR1, PWR_CR1_DBP);
|
|
|
|
- while ((mmio_read_32(PWR_BASE + PWR_CR1) & PWR_CR1_DBP) == 0U) {
|
|
+ while ((mmio_read_32(pwr_base + PWR_CR1) & PWR_CR1_DBP) == 0U) {
|
|
;
|
|
}
|
|
|
|
+ /*
|
|
+ * Configure Standby mode available for MCU by default
|
|
+ * and allow to switch in standby SoC in all case
|
|
+ */
|
|
+ mmio_setbits_32(pwr_base + PWR_MCUCR, PWR_MCUCR_PDDS);
|
|
+
|
|
+ if (bsec_probe() != 0) {
|
|
+ panic();
|
|
+ }
|
|
+
|
|
/* Reset backup domain on cold boot cases */
|
|
- if ((mmio_read_32(RCC_BASE + RCC_BDCR) & RCC_BDCR_RTCSRC_MASK) == 0U) {
|
|
- mmio_setbits_32(RCC_BASE + RCC_BDCR, RCC_BDCR_VSWRST);
|
|
+ if ((mmio_read_32(rcc_base + RCC_BDCR) & RCC_BDCR_RTCSRC_MASK) == 0U) {
|
|
+ mmio_setbits_32(rcc_base + RCC_BDCR, RCC_BDCR_VSWRST);
|
|
|
|
- while ((mmio_read_32(RCC_BASE + RCC_BDCR) & RCC_BDCR_VSWRST) ==
|
|
+ while ((mmio_read_32(rcc_base + RCC_BDCR) & RCC_BDCR_VSWRST) ==
|
|
0U) {
|
|
;
|
|
}
|
|
|
|
- mmio_clrbits_32(RCC_BASE + RCC_BDCR, RCC_BDCR_VSWRST);
|
|
+ mmio_clrbits_32(rcc_base + RCC_BDCR, RCC_BDCR_VSWRST);
|
|
}
|
|
|
|
- mmap_add_region(BL_CODE_BASE, BL_CODE_BASE,
|
|
- BL_CODE_END - BL_CODE_BASE,
|
|
- MT_CODE | MT_SECURE);
|
|
+ /* Wait 5 HSI periods before re-enabling PLLs after STOP modes */
|
|
+ mmio_clrsetbits_32(rcc_base + RCC_PWRLPDLYCR,
|
|
+ RCC_PWRLPDLYCR_PWRLP_DLY_MASK,
|
|
+ PWRLP_TEMPO_5_HSI);
|
|
|
|
- /* Prevent corruption of preloaded BL32 */
|
|
- mmap_add_region(BL32_BASE, BL32_BASE,
|
|
- BL32_LIMIT - BL32_BASE,
|
|
- MT_MEMORY | MT_RO | MT_SECURE);
|
|
+ /* Keep retention and backup ram content in standby */
|
|
+ mmio_setbits_32(pwr_base + PWR_CR2, PWR_CR2_BREN);
|
|
+ mmio_setbits_32(pwr_base + PWR_CR2, PWR_CR2_RREN);
|
|
|
|
- /* Prevent corruption of preloaded Device Tree */
|
|
- mmap_add_region(DTB_BASE, DTB_BASE,
|
|
- DTB_LIMIT - DTB_BASE,
|
|
- MT_MEMORY | MT_RO | MT_SECURE);
|
|
+ /* Disable MCKPROT */
|
|
+ mmio_clrbits_32(rcc_base + RCC_TZCR, RCC_TZCR_MCKPROT);
|
|
|
|
- configure_mmu();
|
|
+ if ((boot_context->boot_action !=
|
|
+ BOOT_API_CTX_BOOT_ACTION_WAKEUP_CSTANDBY) &&
|
|
+ (boot_context->boot_action !=
|
|
+ BOOT_API_CTX_BOOT_ACTION_WAKEUP_STANDBY)) {
|
|
+ mmio_write_32(bkpr_core1_addr, 0);
|
|
+ mmio_write_32(bkpr_core1_magic, 0);
|
|
+ }
|
|
|
|
generic_delay_timer_init();
|
|
|
|
- if (dt_open_and_check() < 0) {
|
|
- panic();
|
|
+#ifdef STM32MP_USB
|
|
+ if (boot_context->boot_interface_selected ==
|
|
+ BOOT_API_CTX_BOOT_INTERFACE_SEL_SERIAL_USB) {
|
|
+ boot_device = BOOT_DEVICE_USB;
|
|
}
|
|
+#endif
|
|
+
|
|
+#if STM32MP_UART_PROGRAMMER
|
|
+ /* Disable programmer UART before changing clock tree */
|
|
+ if (boot_context->boot_interface_selected ==
|
|
+ BOOT_API_CTX_BOOT_INTERFACE_SEL_SERIAL_UART) {
|
|
+ uintptr_t uart_prog_addr =
|
|
+ get_uart_address(boot_context->boot_interface_instance);
|
|
+
|
|
+ ((USART_TypeDef *)uart_prog_addr)->CR1 &= ~USART_CR1_UE;
|
|
+ }
|
|
+#endif
|
|
|
|
if (stm32mp1_clk_probe() < 0) {
|
|
panic();
|
|
@@ -113,12 +323,18 @@ void bl2_el3_plat_arch_setup(void)
|
|
panic();
|
|
}
|
|
|
|
- result = dt_get_stdout_uart_info(&dt_dev_info);
|
|
+ result = dt_get_stdout_uart_info(&dt_uart_info);
|
|
|
|
if ((result <= 0) ||
|
|
- (dt_dev_info.status == 0U) ||
|
|
- (dt_dev_info.clock < 0) ||
|
|
- (dt_dev_info.reset < 0)) {
|
|
+ (dt_uart_info.status == 0U) ||
|
|
+#if STM32MP_UART_PROGRAMMER
|
|
+ ((boot_context->boot_interface_selected ==
|
|
+ BOOT_API_CTX_BOOT_INTERFACE_SEL_SERIAL_UART) &&
|
|
+ (get_uart_address(boot_context->boot_interface_instance) ==
|
|
+ dt_uart_info.base)) ||
|
|
+#endif
|
|
+ (dt_uart_info.clock < 0) ||
|
|
+ (dt_uart_info.reset < 0)) {
|
|
goto skip_console_init;
|
|
}
|
|
|
|
@@ -126,29 +342,57 @@ void bl2_el3_plat_arch_setup(void)
|
|
goto skip_console_init;
|
|
}
|
|
|
|
- if (stm32mp1_clk_enable((unsigned long)dt_dev_info.clock) != 0) {
|
|
- goto skip_console_init;
|
|
+ if (dt_uart_info.status == DT_DISABLED) {
|
|
+ panic();
|
|
+ } else if (dt_uart_info.status == DT_SECURE) {
|
|
+ stm32mp_register_secure_periph_iomem(dt_uart_info.base);
|
|
+ } else {
|
|
+ stm32mp_register_non_secure_periph_iomem(dt_uart_info.base);
|
|
}
|
|
|
|
- stm32mp1_reset_assert((uint32_t)dt_dev_info.reset);
|
|
+ stm32mp_clk_enable((unsigned long)dt_uart_info.clock);
|
|
+
|
|
+ stm32mp_reset_assert((uint32_t)dt_uart_info.reset);
|
|
udelay(2);
|
|
- stm32mp1_reset_deassert((uint32_t)dt_dev_info.reset);
|
|
+ stm32mp_reset_deassert((uint32_t)dt_uart_info.reset);
|
|
mdelay(1);
|
|
|
|
- clk_rate = stm32mp1_clk_get_rate((unsigned long)dt_dev_info.clock);
|
|
+ clk_rate = stm32mp_clk_get_rate((unsigned long)dt_uart_info.clock);
|
|
|
|
- if (console_init(dt_dev_info.base, clk_rate,
|
|
- STM32MP1_UART_BAUDRATE) == 0) {
|
|
+ if (console_stm32_register(dt_uart_info.base, clk_rate,
|
|
+ STM32MP_UART_BAUDRATE, &console) == 0) {
|
|
panic();
|
|
}
|
|
|
|
+ stm32mp_print_cpuinfo();
|
|
board_model = dt_get_board_model();
|
|
if (board_model != NULL) {
|
|
- NOTICE("%s\n", board_model);
|
|
+ NOTICE("Model: %s\n", board_model);
|
|
+ }
|
|
+ stm32mp_print_boardinfo();
|
|
+
|
|
+ if (boot_context->auth_status != BOOT_API_CTX_AUTH_NO) {
|
|
+ NOTICE("%s\n", (boot_context->auth_status ==
|
|
+ BOOT_API_CTX_AUTH_FAILED) ?
|
|
+ "Boot authentication Failed" :
|
|
+ "Boot authentication Success");
|
|
}
|
|
|
|
skip_console_init:
|
|
|
|
+ /* Initialize IWDG Status, no startup */
|
|
+ if (stm32_iwdg_init() < 0) {
|
|
+ panic();
|
|
+ }
|
|
+
|
|
+ /* Reload watchdog */
|
|
+ stm32_iwdg_refresh(IWDG2_INST);
|
|
+
|
|
+ result = stm32mp1_dbgmcu_freeze_iwdg2();
|
|
+ if (result != 0) {
|
|
+ INFO("IWDG2 freeze error : %i\n", result);
|
|
+ }
|
|
+
|
|
if (stm32_save_boot_interface(boot_context->boot_interface_selected,
|
|
boot_context->boot_interface_instance) !=
|
|
0) {
|
|
@@ -157,5 +401,118 @@ skip_console_init:
|
|
|
|
stm32mp1_arch_security_setup();
|
|
|
|
- stm32mp1_io_setup();
|
|
+ print_reset_reason();
|
|
+
|
|
+ stm32mp_io_setup();
|
|
+
|
|
+ stm32mp1_syscfg_init();
|
|
+}
|
|
+
|
|
+#if defined(AARCH32_SP_OPTEE)
|
|
+static void set_mem_params_info(entry_point_info_t *ep_info,
|
|
+ image_info_t *unpaged, image_info_t *paged)
|
|
+{
|
|
+ uintptr_t bl32_ep = 0;
|
|
+
|
|
+ /* Use the default dram setup if no valid ep found */
|
|
+ if (get_optee_header_ep(ep_info, &bl32_ep) &&
|
|
+ (bl32_ep >= STM32MP_OPTEE_BASE) &&
|
|
+ (bl32_ep < (STM32MP_OPTEE_BASE + STM32MP_OPTEE_SIZE))) {
|
|
+ assert((STM32MP_OPTEE_BASE >= BL2_LIMIT) ||
|
|
+ ((STM32MP_OPTEE_BASE + STM32MP_OPTEE_SIZE) <= BL2_BASE));
|
|
+
|
|
+ unpaged->image_base = STM32MP_OPTEE_BASE;
|
|
+ unpaged->image_max_size = STM32MP_OPTEE_SIZE;
|
|
+ } else {
|
|
+ unpaged->image_base = STM32MP_DDR_BASE + dt_get_ddr_size() -
|
|
+ STM32MP_DDR_S_SIZE;
|
|
+ unpaged->image_max_size = STM32MP_DDR_S_SIZE;
|
|
+ }
|
|
+ paged->image_base = STM32MP_DDR_BASE + dt_get_ddr_size() -
|
|
+ STM32MP_DDR_S_SIZE;
|
|
+ paged->image_max_size = STM32MP_DDR_S_SIZE;
|
|
+}
|
|
+#endif
|
|
+
|
|
+/*******************************************************************************
|
|
+ * This function can be used by the platforms to update/use image
|
|
+ * information for given `image_id`.
|
|
+ ******************************************************************************/
|
|
+int bl2_plat_handle_post_image_load(unsigned int image_id)
|
|
+{
|
|
+ int err = 0;
|
|
+ bl_mem_params_node_t *bl_mem_params = get_bl_mem_params_node(image_id);
|
|
+#if defined(AARCH32_SP_OPTEE)
|
|
+ bl_mem_params_node_t *bl32_mem_params;
|
|
+ bl_mem_params_node_t *pager_mem_params;
|
|
+ bl_mem_params_node_t *paged_mem_params;
|
|
+#endif
|
|
+
|
|
+ assert(bl_mem_params != NULL);
|
|
+
|
|
+ switch (image_id) {
|
|
+ case BL32_IMAGE_ID:
|
|
+#if defined(AARCH32_SP_OPTEE)
|
|
+ pager_mem_params = get_bl_mem_params_node(BL32_EXTRA1_IMAGE_ID);
|
|
+ assert(pager_mem_params);
|
|
+
|
|
+ paged_mem_params = get_bl_mem_params_node(BL32_EXTRA2_IMAGE_ID);
|
|
+ assert(paged_mem_params);
|
|
+
|
|
+ bl_mem_params->ep_info.pc =
|
|
+ bl_mem_params->image_info.image_base;
|
|
+
|
|
+ set_mem_params_info(&bl_mem_params->ep_info,
|
|
+ &pager_mem_params->image_info,
|
|
+ &paged_mem_params->image_info);
|
|
+
|
|
+ err = parse_optee_header(&bl_mem_params->ep_info,
|
|
+ &pager_mem_params->image_info,
|
|
+ &paged_mem_params->image_info);
|
|
+ if (err) {
|
|
+ ERROR("OPTEE header parse error.\n");
|
|
+ panic();
|
|
+ }
|
|
+
|
|
+ /* Set optee boot info from parsed header data */
|
|
+ bl_mem_params->ep_info.pc =
|
|
+ pager_mem_params->image_info.image_base;
|
|
+ bl_mem_params->ep_info.args.arg0 =
|
|
+ paged_mem_params->image_info.image_base;
|
|
+ bl_mem_params->ep_info.args.arg1 = 0; /* Unused */
|
|
+ bl_mem_params->ep_info.args.arg2 = 0; /* No DT supported */
|
|
+#endif
|
|
+ break;
|
|
+
|
|
+ case BL33_IMAGE_ID:
|
|
+#ifdef AARCH32_SP_OPTEE
|
|
+ bl32_mem_params = get_bl_mem_params_node(BL32_IMAGE_ID);
|
|
+ assert(bl32_mem_params);
|
|
+ bl32_mem_params->ep_info.lr_svc = bl_mem_params->ep_info.pc;
|
|
+#else
|
|
+ /* BL33 expects to receive : TBD */
|
|
+ bl_mem_params->ep_info.args.arg0 = 0;
|
|
+ bl_mem_params->ep_info.spsr =
|
|
+ SPSR_MODE32(MODE32_svc, SPSR_T_ARM, SPSR_E_LITTLE,
|
|
+ DISABLE_ALL_EXCEPTIONS);
|
|
+#endif
|
|
+ flush_dcache_range(bl_mem_params->image_info.image_base,
|
|
+ bl_mem_params->image_info.image_max_size);
|
|
+ break;
|
|
+
|
|
+#ifdef AARCH32_SP_OPTEE
|
|
+ case BL32_EXTRA1_IMAGE_ID:
|
|
+ case BL32_EXTRA2_IMAGE_ID:
|
|
+ clean_dcache_range(bl_mem_params->image_info.image_base,
|
|
+ bl_mem_params->image_info.image_max_size);
|
|
+ break;
|
|
+#endif
|
|
+
|
|
+ default:
|
|
+ err = -1;
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ return err;
|
|
}
|
|
+
|
|
diff --git a/plat/st/stm32mp1/include/boot_api.h b/plat/st/stm32mp1/include/boot_api.h
|
|
index 71c3593..5953e6e 100644
|
|
--- a/plat/st/stm32mp1/include/boot_api.h
|
|
+++ b/plat/st/stm32mp1/include/boot_api.h
|
|
@@ -1,13 +1,108 @@
|
|
/*
|
|
- * Copyright (c) 2017, STMicroelectronics - All Rights Reserved
|
|
+ * Copyright (c) 2017-2018, STMicroelectronics - All Rights Reserved
|
|
*
|
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
*/
|
|
|
|
-#ifndef __BOOT_API_H
|
|
-#define __BOOT_API_H
|
|
+#ifndef BOOT_API_H
|
|
+#define BOOT_API_H
|
|
|
|
#include <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'
|
|
+ */
|
|
+ /* No authentication done */
|
|
+#define BOOT_API_CTX_AUTH_NO 0x00
|
|
+ /* Authentication done and failed */
|
|
+#define BOOT_API_CTX_AUTH_FAILED 0x01
|
|
+ /* Authentication done and success */
|
|
+#define BOOT_API_CTX_AUTH_SUCCESS 0x02
|
|
|
|
/*
|
|
* Possible value of boot context field 'boot_interface_sel'
|
|
@@ -22,6 +117,21 @@
|
|
/* Boot occurred on EMMC */
|
|
#define BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_EMMC 0x2U
|
|
|
|
+/* boot occurred on NAND FMC */
|
|
+#define BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_NAND_FMC 0x3U
|
|
+
|
|
+/* boot occurred on QSPI NOR */
|
|
+#define BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_NOR_QSPI 0x4U
|
|
+
|
|
+/* boot occurred on UART */
|
|
+#define BOOT_API_CTX_BOOT_INTERFACE_SEL_SERIAL_UART 0x5U
|
|
+
|
|
+/* boot occurred on USB */
|
|
+#define BOOT_API_CTX_BOOT_INTERFACE_SEL_SERIAL_USB 0x6U
|
|
+
|
|
+/* boot occurred on NAND QSPI */
|
|
+#define BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_NAND_QSPI 0x7U
|
|
+
|
|
/**
|
|
* @brief Possible value of boot context field 'EmmcXferStatus'
|
|
*/
|
|
@@ -45,6 +155,10 @@
|
|
#define BOOT_API_CTX_EMMC_ERROR_STATUS_HEADER_SIZE_ZERO 0x6U
|
|
#define BOOT_API_CTX_EMMC_ERROR_STATUS_IMAGE_NOT_COMPLETE 0x7U
|
|
|
|
+/* Definitions relative to 'p_rom_version_info->platform_type_ver' field */
|
|
+#define BOOT_API_CTX_ROM_VERSION_PLAT_VER_IC_EMU_FPGA 0xAA
|
|
+#define BOOT_API_CTX_ROM_VERSION_PLAT_VER_FPGA_ONLY 0xBB
|
|
+
|
|
/* Image Header related definitions */
|
|
|
|
/* Definition of header version */
|
|
@@ -76,6 +190,64 @@
|
|
#define BOOT_API_A7_CORE1_MAGIC_NUMBER 0xCA7FACE1U
|
|
|
|
/*
|
|
+ * MCU Code Integrity Check related definitions
|
|
+ */
|
|
+
|
|
+/*
|
|
+ * Defines to identify RTC backup registers to be used for MCU code integrity
|
|
+ * check
|
|
+ */
|
|
+
|
|
+/*
|
|
+ * TAMP_BCK0R contains two bits
|
|
+ * bit 0 : wanted value of 'RCC_TZCR.TZEN'
|
|
+ * bit 1 : wanted value of 'RCC_TZCR.MCKPROT'
|
|
+ */
|
|
+
|
|
+/*
|
|
+ * TAMP_BCK0R bit position coding wanted value of 'RCC_TZCR.TZEN'
|
|
+ * trustZone aware domain enabling/disabling
|
|
+ */
|
|
+#define BOOT_API_MCIC_MCU_SECURITY_PERIMETER_TZEN_BIT 0
|
|
+
|
|
+/*
|
|
+ * TAMP_BCK0R bit position coding wanted value of 'RCC_TZCR.MCKPROT'
|
|
+ * ability of MCU to modify some clock settings in RCC
|
|
+ */
|
|
+#define BOOT_API_MCIC_MCU_SECURITY_PERIMETER_MCKPROT_BIT 1
|
|
+
|
|
+/* TAMP_BCK0R register index */
|
|
+#define \
|
|
+BOOT_API_MCIC_MCU_SECURITY_PERIMETER_TZEN_MCKPROT_TAMP_BCK_REG_IDX 0
|
|
+
|
|
+/*
|
|
+ * TAMP_BCK1R register index
|
|
+ * This register is coding the wanted value of register 'EXTI_TZENR1'
|
|
+ * to be programmed by bootROM on wakeup from STANDBY when MCUBEN=1
|
|
+ * that is MCU quick restart requested
|
|
+ */
|
|
+#define \
|
|
+BOOT_API_MCIC_MCU_SECURITY_PERIMETER_EXTI_TZENR1_TAMP_BCK_REG_IDX 1
|
|
+
|
|
+/*
|
|
+ * TAMP_BCK2R register index
|
|
+ * This register is coding the wanted value of register 'EXTI_TZENR2'
|
|
+ * to be programmed by bootROM on wakeup from STANDBY when MCUBEN=1
|
|
+ * that is MCU quick restart requested
|
|
+ */
|
|
+#define \
|
|
+BOOT_API_MCIC_MCU_SECURITY_PERIMETER_EXTI_TZENR2_TAMP_BCK_REG_IDX 2
|
|
+
|
|
+/*
|
|
+ * TAMP_BCK3R register index
|
|
+ * This register is coding the wanted value of register 'EXTI_TZENR3'
|
|
+ * to be programmed by bootROM on wakeup from STANDBY when MCUBEN=1
|
|
+ * that is MCU quick restart requested
|
|
+ */
|
|
+#define \
|
|
+BOOT_API_MCIC_MCU_SECURITY_PERIMETER_EXTI_TZENR3_TAMP_BCK_REG_IDX 3
|
|
+
|
|
+/*
|
|
* TAMP_BCK4R register index
|
|
* This register is used to write a Magic Number in order to restart
|
|
* Cortex A7 Core 1 and make it execute @ branch address from TAMP_BCK5R
|
|
@@ -90,6 +262,39 @@
|
|
#define BOOT_API_CORE1_BRANCH_ADDRESS_TAMP_BCK_REG_IDX 5U
|
|
|
|
/*
|
|
+ * TAMP_BCK22R register index
|
|
+ * This register contains offset in bytes of code to Hash in RETRAM region
|
|
+ * Note : offset is intended as relative value from start of RETRAM
|
|
+ */
|
|
+#define \
|
|
+BOOT_API_MCIC_OFFSET_IN_BYTES_CODE_TO_HASH_RETRAM_TAMP_BCK_REG_IDX 22
|
|
+
|
|
+/*
|
|
+ * TAMP_BCK23R register index
|
|
+ * This register contains the size in bytes of the single consecutive region
|
|
+ * of MCU Firmware in RETRAM (Retention RAM) to hash (by SHA-256)
|
|
+ * Note : This is required as a MCU firmware Code Integrity Check (aka : MCIC)
|
|
+ * to avoid bootROM restarting MCU on a corrupted firmware
|
|
+ */
|
|
+#define \
|
|
+BOOT_API_MCIC_RETRAM_REGION_TO_HASH_IN_BYTES_TAMP_BCK_REG_IDX 23
|
|
+
|
|
+/*
|
|
+ * TAMP_BCK24R to TAMP_BCK31R register indexes
|
|
+ * Those registers contains SHA-256 digest of RETRAM MCU Firmware code between
|
|
+ * [(RETRAM_start + offset) -- (RETRAM_start + offset + size_to_hash)]
|
|
+ * in this order
|
|
+ * This is the MCU Code Integrity Check MCU Firmware signature
|
|
+ * value on 256 bits
|
|
+ */
|
|
+
|
|
+/* First TAMP_BKP index of MCU Firmware signature : ie TAMP_BCK24R */
|
|
+#define BOOT_API_MCIC_SHA_DIGEST_FIRST_TAMP_BCK_REG_IDX 24
|
|
+
|
|
+/* Last TAMP_BKP index of MCU Firmware signature : ie TAMP_BCK31R */
|
|
+#define BOOT_API_MCIC_SHA_DIGEST_LAST_TAMP_BCK_REG_IDX 31
|
|
+
|
|
+/*
|
|
* Possible value of boot context field 'hse_clock_value_in_hz'
|
|
*/
|
|
#define BOOT_API_CTX_HSE_CLOCK_VALUE_UNDEFINED 0U
|
|
@@ -113,6 +318,57 @@
|
|
/* Closed = OTP_CFG0[6] */
|
|
#define BOOT_API_OTP_MODE_CLOSED_BIT_POS 6
|
|
|
|
+/* Mapping of OTP Word and OTP bits managing SSP and useful to FSBL-SSP */
|
|
+/* OTP_CFG8 */
|
|
+#define BOOT_API_OTP_SSP_WORD_NB 8U
|
|
+/* SSP_REQ = OTP_CFG8[8] */
|
|
+#define BOOT_API_OTP_SSP_REQ_BIT_POS 8
|
|
+/* SSP_SUCCESS = OTP_CFG8[9] */
|
|
+#define BOOT_API_OTP_SSP_SUCCESS_BIT_POS 9
|
|
+
|
|
+/*
|
|
+ * Possible values of boot context field
|
|
+ * 'ssp_config_ptr_in->ssp_cmd'
|
|
+ */
|
|
+/* 'K' 'B' 'U' 'P' -.> 'PUBK' */
|
|
+#define BOOT_API_CTX_SSP_CMD_CALC_CHIP_PUBK 0x4B425550
|
|
+
|
|
+/*
|
|
+ * Exported types
|
|
+ */
|
|
+
|
|
+/* SSP Configuration structure */
|
|
+typedef struct {
|
|
+ /* SSP Command*/
|
|
+ uint32_t ssp_cmd;
|
|
+ uint8_t reserved[20];
|
|
+} boot_api_ssp_config_t;
|
|
+
|
|
+/*
|
|
+ * bootROM version information structure definition
|
|
+ * Total size = 24 bytes = 6 uint32_t
|
|
+ */
|
|
+typedef struct {
|
|
+ /* Chip Version */
|
|
+ uint32_t chip_ver;
|
|
+
|
|
+ /* Cut version within a fixed chip version */
|
|
+ uint32_t cut_ver;
|
|
+
|
|
+ /* Version of ROM Mask within a fixed cut version */
|
|
+ uint32_t rom_mask_ver;
|
|
+
|
|
+ /* Internal Version of bootROM code */
|
|
+ uint32_t bootrom_ver;
|
|
+
|
|
+ /* Version of bootROM adapted */
|
|
+ uint32_t for_chip_design_rtl_ver;
|
|
+
|
|
+ /* Restriction on compiled platform when it applies */
|
|
+ uint32_t platform_type_ver;
|
|
+
|
|
+} boot_api_rom_version_info_t;
|
|
+
|
|
/*
|
|
* Boot Context related definitions
|
|
*/
|
|
@@ -129,9 +385,133 @@ typedef struct {
|
|
*/
|
|
uint16_t boot_interface_selected;
|
|
uint16_t boot_interface_instance;
|
|
- uint32_t reserved1[13];
|
|
+ uint32_t reserved1;
|
|
+ uint32_t nand_data_width;
|
|
+ uint32_t nand_block_size;
|
|
+ uint32_t nand_page_size;
|
|
+ uint32_t reserved2;
|
|
+ uint32_t nand_ecc_bits;
|
|
+ uint32_t nand_block_nb;
|
|
+ uint32_t reserved3[4];
|
|
+ uint32_t nor_isdual;
|
|
+ uint32_t usb_context;
|
|
uint32_t otp_afmux_values[3];
|
|
- uint32_t reserved[9];
|
|
+ uint32_t reserved[2];
|
|
+ /*
|
|
+ * Log to boot context, what was the kind of boot action
|
|
+ * takes values from defines BOOT_API_BOOT_ACTION_XXX above
|
|
+ */
|
|
+ uint32_t boot_action;
|
|
+ /*
|
|
+ * STANDBY Exit status to be checked by FSBL in case
|
|
+ * field 'boot_action' == BOOT_API_CTX_BOOT_ACTION_WAKEUP_STANDBY
|
|
+ * take values from defines above 'BOOT_API_CTX_STBY_EXIT_STATUS_XXX'
|
|
+ * depending on encountered situation
|
|
+ */
|
|
+ uint32_t stby_exit_status;
|
|
+ /*
|
|
+ * CSTANDBY Exit status to be checked by FSBL in case
|
|
+ * boot_action == BOOT_API_CTX_BOOT_ACTION_WAKEUP_CSTANDBY
|
|
+ * take values from defines above 'BOOT_API_CTX_CSTBY_EXIT_STATUS_XXX'
|
|
+ * depending on encountered situation
|
|
+ */
|
|
+ uint32_t cstby_exit_status;
|
|
+ /*
|
|
+ * Returned authentication status : take values from defines
|
|
+ * BOOT_API_CTX_AUTH_XXX above
|
|
+ */
|
|
+ uint32_t auth_status;
|
|
+
|
|
+ /*
|
|
+ *******************************************************
|
|
+ * Pointers to bootROM External Secure Services
|
|
+ * External Secure Services offered by bootROM
|
|
+ * - ECDSA check key
|
|
+ * - ECDSA verify signature
|
|
+ * - ECDSA verify signature and go
|
|
+ *******************************************************
|
|
+ */
|
|
+ /*
|
|
+ * Check if hash of p_pub_key_in is equal to hash by SHA-256
|
|
+ * of OEM public key from OTP
|
|
+ *
|
|
+ * If no: => infinite loop in bootROM : boot failed
|
|
+ *
|
|
+ * else: copy p_pub_key_in to p_pub_key_out if
|
|
+ * p_pub_key_out not NULL.
|
|
+ * and return to caller.
|
|
+ *
|
|
+ * @param[in] p_pub_key_in points to an ECDSA public key :
|
|
+ * Very Important : address alignment constraint :
|
|
+ * This address should be multiple of 4 bytes only.
|
|
+ * @param[in/out] p_pub_key_out points to area where to store copy
|
|
+ * of public key.
|
|
+ * Very Important : address alignment constraint :
|
|
+ * This address should be multiple of 4 bytes only.
|
|
+ * @retval STD_OK (0x77) or STD_NOT_OK (0x66)
|
|
+ */
|
|
+ uint32_t (*p_bootrom_ext_service_ecdsa_check_key)
|
|
+ (uint8_t *p_pub_key_in,
|
|
+ uint8_t *p_pub_key_out);
|
|
+ /*
|
|
+ * verify ECDSA signature
|
|
+ *
|
|
+ * Decrypt EDCSA signature from 'p_signature'
|
|
+ * using public key passed in parameter 'p_pub_key_in'
|
|
+ * Then compare it to hash from 'p_hash_in' (SHA-256)
|
|
+ *
|
|
+ * If no match: => infinite loop in bootROM
|
|
+ *
|
|
+ * else: return to caller
|
|
+ *
|
|
+ * @param[in] p_hash_in : points on hash in (SHA-256)
|
|
+ * Very Important : address alignment constraint :
|
|
+ * This address should be multiple of 4 bytes only.
|
|
+ * @param[in] p_pub_key_in : points to an ECDSA public key
|
|
+ * Very Important : address alignment constraint :
|
|
+ * This address should be multiple of 4 bytes only.
|
|
+ * @param[in] p_signature : points to an EDCSA signature.
|
|
+ * Very Important : address alignment constraint :
|
|
+ * This address should be multiple of 4 bytes only.
|
|
+ * @param[in] ecc_algo : Ecc algorithm to be used P256 NIST or
|
|
+ * Brain_pool 256.
|
|
+ *
|
|
+ * @retval STD_OK (0x77) or STD_NOT_OK (0x66)
|
|
+ */
|
|
+ uint32_t (*p_bootrom_ext_service_ecdsa_verify_signature)
|
|
+ (uint8_t *p_hash_in, uint8_t *p_pub_key_in,
|
|
+ uint8_t *p_signature, uint32_t ecc_algo);
|
|
+ /*
|
|
+ * verify ECDSA signature and branch to entry point if match
|
|
+ *
|
|
+ * Decrypt EDCSA signature from 'p_signature'
|
|
+ * using public key passed in parameter 'p_pub_key_in'
|
|
+ * Then compare it to hash from 'p_hash_in' (SHA-256)
|
|
+ *
|
|
+ * If no match: => infinite loop in bootROM
|
|
+ *
|
|
+ * else: branch CA7-0 to branch address 'p_entry_in'
|
|
+ *
|
|
+ * @param[in] p_hash_in : points on hash in (SHA-256)
|
|
+ * Very Important : address alignment constraint :
|
|
+ * This address should be multiple of 4 bytes only.
|
|
+ * @param[in] p_pub_key_in : points to an ECDSA public key
|
|
+ * Very Important : address alignment constraint :
|
|
+ * This address should be multiple of 4 bytes only.
|
|
+ * @param[in] p_signature : points to an EDCSA signature.
|
|
+ * Very Important : address alignment constraint :
|
|
+ * This address should be multiple of 4 bytes only.
|
|
+ * @param[in] ecc_algo : Ecc algorithm to be used P256 NIST or
|
|
+ * Brain_pool 256.
|
|
+ * @param[in] p_entry_in : points to branch entry point.
|
|
+ *
|
|
+ * @retval STD_NOT_OK (0x66)
|
|
+ */
|
|
+ uint32_t (*p_bootrom_ext_service_ecdsa_verify_and_go)
|
|
+ (uint8_t *p_hash_in, uint8_t *p_pub_key_in,
|
|
+ uint8_t *p_signature_in, uint32_t ecc_algo,
|
|
+ uint32_t *p_entry_in);
|
|
+
|
|
/*
|
|
* Information specific to an SD boot
|
|
* Updated each time an SD boot is at least attempted,
|
|
@@ -161,6 +541,21 @@ typedef struct {
|
|
* ie FSBL partition on which the boot was successful
|
|
*/
|
|
uint32_t boot_partition_used_toboot;
|
|
+ /*
|
|
+ * Address of SSP configuration structure :
|
|
+ * given and defined by bootROM
|
|
+ * and used by FSBL. The structure is of type
|
|
+ * 'boot_api_ssp_config_t'
|
|
+ */
|
|
+ boot_api_ssp_config_t *p_ssp_config;
|
|
+ /*
|
|
+ * boot context field containing bootROM updated SSP Status
|
|
+ * Values can be of type BOOT_API_CTX_SSP_STATUS_XXX
|
|
+ */
|
|
+ uint32_t ssp_status;
|
|
+
|
|
+ /* Pointer on ROM constant containing ROM information */
|
|
+ const boot_api_rom_version_info_t *p_rom_version_info;
|
|
|
|
} __packed boot_api_context_t;
|
|
|
|
@@ -229,7 +624,9 @@ typedef struct {
|
|
*/
|
|
uint8_t ecc_pubk[BOOT_API_ECDSA_PUB_KEY_LEN_IN_BYTES];
|
|
/* Pad up to 256 byte total size */
|
|
- uint8_t pad[84];
|
|
+ uint8_t pad[83];
|
|
+ /* Add binary type information */
|
|
+ uint8_t binary_type;
|
|
} __packed boot_api_image_header_t;
|
|
|
|
-#endif /* __BOOT_API_H */
|
|
+#endif /* BOOT_API_H */
|
|
diff --git a/plat/st/stm32mp1/include/platform_def.h b/plat/st/stm32mp1/include/platform_def.h
|
|
index 47e1ffc..fd1ccbf 100644
|
|
--- a/plat/st/stm32mp1/include/platform_def.h
|
|
+++ b/plat/st/stm32mp1/include/platform_def.h
|
|
@@ -24,12 +24,22 @@
|
|
#define PLATFORM_STACK_SIZE 0xC00
|
|
#endif
|
|
|
|
+#ifdef AARCH32_SP_OPTEE
|
|
+#define OPTEE_HEADER_IMAGE_NAME "teeh"
|
|
+#define OPTEE_PAGED_IMAGE_NAME "teed"
|
|
+#define OPTEE_PAGER_IMAGE_NAME "teex"
|
|
+#define OPTEE_HEADER_BINARY_TYPE U(0x20)
|
|
+#define OPTEE_PAGER_BINARY_TYPE U(0x21)
|
|
+#define OPTEE_PAGED_BINARY_TYPE U(0x22)
|
|
+#endif
|
|
+
|
|
/* SSBL = second stage boot loader */
|
|
#define BL33_IMAGE_NAME "ssbl"
|
|
+#define BL33_BINARY_TYPE U(0x0)
|
|
|
|
-#define STM32MP1_PRIMARY_CPU U(0x0)
|
|
+#define STM32MP_PRIMARY_CPU U(0x0)
|
|
+#define STM32MP_SECONDARY_CPU U(0x1)
|
|
|
|
-#define PLATFORM_CACHE_LINE_SIZE 64
|
|
#define PLATFORM_CLUSTER_COUNT ULL(1)
|
|
#define PLATFORM_CLUSTER0_CORE_COUNT U(2)
|
|
#define PLATFORM_CLUSTER1_CORE_COUNT U(0)
|
|
@@ -37,8 +47,9 @@
|
|
PLATFORM_CLUSTER0_CORE_COUNT)
|
|
#define PLATFORM_MAX_CPUS_PER_CLUSTER 2
|
|
|
|
-#define MAX_IO_DEVICES 4
|
|
-#define MAX_IO_HANDLES 4
|
|
+#define MAX_IO_DEVICES U(4)
|
|
+#define MAX_IO_HANDLES U(4)
|
|
+#define MAX_IO_BLOCK_DEVICES U(1)
|
|
|
|
/*******************************************************************************
|
|
* BL2 specific defines.
|
|
@@ -47,39 +58,45 @@
|
|
* Put BL2 just below BL3-1. BL2_BASE is calculated using the current BL2 debug
|
|
* size plus a little space for growth.
|
|
*/
|
|
-#define BL2_BASE STM32MP1_BL2_BASE
|
|
-#define BL2_LIMIT (STM32MP1_BL2_BASE + \
|
|
- STM32MP1_BL2_SIZE)
|
|
+#define BL2_BASE STM32MP_BL2_BASE
|
|
+#define BL2_LIMIT (STM32MP_BL2_BASE + \
|
|
+ STM32MP_BL2_SIZE)
|
|
|
|
/*******************************************************************************
|
|
* BL32 specific defines.
|
|
******************************************************************************/
|
|
-#define BL32_BASE STM32MP1_BL32_BASE
|
|
-#define BL32_LIMIT (STM32MP1_BL32_BASE + \
|
|
- STM32MP1_BL32_SIZE)
|
|
+#ifndef AARCH32_SP_OPTEE
|
|
+#define BL32_BASE STM32MP_BL32_BASE
|
|
+#define BL32_LIMIT (STM32MP_BL32_BASE + \
|
|
+ STM32MP_BL32_SIZE)
|
|
+#endif
|
|
|
|
/*******************************************************************************
|
|
* BL33 specific defines.
|
|
******************************************************************************/
|
|
-#define BL33_BASE STM32MP1_BL33_BASE
|
|
+#define BL33_BASE STM32MP_BL33_BASE
|
|
|
|
/*
|
|
* Load address of BL33 for this platform port
|
|
*/
|
|
-#define PLAT_STM32MP1_NS_IMAGE_OFFSET BL33_BASE
|
|
+#define PLAT_STM32MP_NS_IMAGE_OFFSET BL33_BASE
|
|
+
|
|
+/* need by flash programmer */
|
|
+#define FLASHLAYOUT_BASE STM32MP_DDR_BASE
|
|
+#define FLASHLAYOUT_LIMIT STM32MP_BL33_BASE
|
|
|
|
/*******************************************************************************
|
|
* DTB specific defines.
|
|
******************************************************************************/
|
|
-#define DTB_BASE STM32MP1_DTB_BASE
|
|
-#define DTB_LIMIT (STM32MP1_DTB_BASE + \
|
|
- STM32MP1_DTB_SIZE)
|
|
+#define DTB_BASE STM32MP_DTB_BASE
|
|
+#define DTB_LIMIT (STM32MP_DTB_BASE + \
|
|
+ STM32MP_DTB_SIZE)
|
|
|
|
/*******************************************************************************
|
|
* Platform specific page table and MMU setup constants
|
|
******************************************************************************/
|
|
-#define PLAT_PHY_ADDR_SPACE_SIZE (1ULL << 32)
|
|
-#define PLAT_VIRT_ADDR_SPACE_SIZE (1ULL << 32)
|
|
+#define PLAT_PHY_ADDR_SPACE_SIZE (ULL(1) << 32)
|
|
+#define PLAT_VIRT_ADDR_SPACE_SIZE (ULL(1) << 32)
|
|
|
|
/*******************************************************************************
|
|
* Declarations and constants to access the mailboxes safely. Each mailbox is
|
|
@@ -98,6 +115,8 @@
|
|
*/
|
|
#define ARM_IRQ_SEC_PHY_TIMER U(29)
|
|
|
|
+#define ARM_IRQ_NON_SEC_SGI_0 U(0)
|
|
+
|
|
#define ARM_IRQ_SEC_SGI_0 U(8)
|
|
#define ARM_IRQ_SEC_SGI_1 U(9)
|
|
#define ARM_IRQ_SEC_SGI_2 U(10)
|
|
@@ -107,7 +126,15 @@
|
|
#define ARM_IRQ_SEC_SGI_6 U(14)
|
|
#define ARM_IRQ_SEC_SGI_7 U(15)
|
|
|
|
+/* Platform IRQ Priority */
|
|
+#define STM32MP1_IRQ_RCC_SEC_PRIO U(0x6)
|
|
+#define STM32MP1_IRQ_SEC_SPI_PRIO U(0x10)
|
|
+
|
|
#define STM32MP1_IRQ_TZC400 U(36)
|
|
+#define STM32MP1_IRQ_MCU_SEV U(176)
|
|
+#define STM32MP1_IRQ_RCC_WAKEUP U(177)
|
|
+#define STM32MP1_IRQ_IWDG1 U(182)
|
|
+#define STM32MP1_IRQ_IWDG2 U(183)
|
|
#define STM32MP1_IRQ_TAMPSERRS U(229)
|
|
#define STM32MP1_IRQ_AXIERRIRQ U(244)
|
|
|
|
@@ -120,9 +147,6 @@
|
|
INTR_PROP_DESC(ARM_IRQ_SEC_PHY_TIMER, \
|
|
GIC_HIGHEST_SEC_PRIORITY, \
|
|
grp, GIC_INTR_CFG_LEVEL), \
|
|
- INTR_PROP_DESC(STM32MP1_IRQ_TAMPSERRS, \
|
|
- GIC_HIGHEST_SEC_PRIORITY, \
|
|
- grp, GIC_INTR_CFG_LEVEL), \
|
|
INTR_PROP_DESC(STM32MP1_IRQ_AXIERRIRQ, \
|
|
GIC_HIGHEST_SEC_PRIORITY, \
|
|
grp, GIC_INTR_CFG_LEVEL), \
|
|
diff --git a/plat/st/stm32mp1/include/stm32mp1_context.h b/plat/st/stm32mp1/include/stm32mp1_context.h
|
|
index fd08afc..4cd6643 100644
|
|
--- a/plat/st/stm32mp1/include/stm32mp1_context.h
|
|
+++ b/plat/st/stm32mp1/include/stm32mp1_context.h
|
|
@@ -4,11 +4,23 @@
|
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
*/
|
|
|
|
-#ifndef __STM32MP1_CONTEXT_H__
|
|
-#define __STM32MP1_CONTEXT_H__
|
|
+#ifndef STM32MP1_CONTEXT_H
|
|
+#define STM32MP1_CONTEXT_H
|
|
|
|
+#include <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);
|
|
+int stm32_restore_backup_reg(void);
|
|
+uint32_t stm32_get_zdata_from_context(void);
|
|
int stm32_save_boot_interface(uint32_t interface, uint32_t instance);
|
|
+int stm32_get_boot_interface(uint32_t *interface, uint32_t *instance);
|
|
+void stm32_save_ddr_training_area(void);
|
|
+void stm32_restore_ddr_training_area(void);
|
|
+uint32_t stm32_pm_get_optee_ep(void);
|
|
|
|
-#endif /* __STM32MP1_CONTEXT_H__ */
|
|
+#endif /* STM32MP1_CONTEXT_H */
|
|
diff --git a/plat/st/stm32mp1/include/stm32mp1_dbgmcu.h b/plat/st/stm32mp1/include/stm32mp1_dbgmcu.h
|
|
new file mode 100644
|
|
index 0000000..fd97a16
|
|
--- /dev/null
|
|
+++ b/plat/st/stm32mp1/include/stm32mp1_dbgmcu.h
|
|
@@ -0,0 +1,26 @@
|
|
+/*
|
|
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
|
|
+ *
|
|
+ * SPDX-License-Identifier: BSD-3-Clause
|
|
+ */
|
|
+
|
|
+#ifndef __PLAT_DBGMCU_H__
|
|
+#define __PLAT_DBGMCU_H__
|
|
+
|
|
+#include <stdint.h>
|
|
+
|
|
+#if LOG_LEVEL >= LOG_LEVEL_VERBOSE
|
|
+#define VERBOSE_HEXDUMP8(buf, len) stm32mp1_dbgmcu_hexdump8(buf, len)
|
|
+#else
|
|
+#define VERBOSE_HEXDUMP8(buf, len)
|
|
+#endif
|
|
+
|
|
+uint32_t stm32mp1_dbgmcu_get_chip_version(void);
|
|
+uint32_t stm32mp1_dbgmcu_get_chip_dev_id(void);
|
|
+int stm32mp1_dbgmcu_freeze_iwdg2(void);
|
|
+int stm32mp1_dbgmcu_boot_debug_info(void);
|
|
+int stm32mp1_dbgmcu_clear_boot_info(void);
|
|
+uint32_t stm32mp1_dbgmcu_is_debug_on(void);
|
|
+void stm32mp1_dbgmcu_hexdump8(uint8_t *buf, uint32_t len);
|
|
+
|
|
+#endif /* __PLAT_DBGMCU_H__ */
|
|
diff --git a/plat/st/stm32mp1/include/stm32mp1_dt.h b/plat/st/stm32mp1/include/stm32mp1_dt.h
|
|
deleted file mode 100644
|
|
index 58e10d1..0000000
|
|
--- a/plat/st/stm32mp1/include/stm32mp1_dt.h
|
|
+++ /dev/null
|
|
@@ -1,41 +0,0 @@
|
|
-/*
|
|
- * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
|
|
- *
|
|
- * SPDX-License-Identifier: BSD-3-Clause
|
|
- */
|
|
-
|
|
-#ifndef __STM32MP1_DT_H__
|
|
-#define __STM32MP1_DT_H__
|
|
-
|
|
-#include <stdbool.h>
|
|
-
|
|
-struct dt_node_info {
|
|
- uint32_t base;
|
|
- int32_t clock;
|
|
- int32_t reset;
|
|
- bool status;
|
|
- bool sec_status;
|
|
-};
|
|
-
|
|
-/*******************************************************************************
|
|
- * Function and variable prototypes
|
|
- ******************************************************************************/
|
|
-int dt_open_and_check(void);
|
|
-int fdt_get_address(void **fdt_addr);
|
|
-bool fdt_check_node(int node);
|
|
-bool fdt_check_status(int node);
|
|
-bool fdt_check_secure_status(int node);
|
|
-uint32_t fdt_read_uint32_default(int node, const char *prop_name,
|
|
- uint32_t dflt_value);
|
|
-int fdt_read_uint32_array(int node, const char *prop_name,
|
|
- uint32_t *array, uint32_t count);
|
|
-int dt_set_pinctrl_config(int node);
|
|
-int dt_set_stdout_pinctrl(void);
|
|
-void dt_fill_device_info(struct dt_node_info *info, int node);
|
|
-int dt_get_node(struct dt_node_info *info, int offset, const char *compat);
|
|
-int dt_get_stdout_uart_info(struct dt_node_info *info);
|
|
-int dt_get_stdout_node_offset(void);
|
|
-uint32_t dt_get_ddr_size(void);
|
|
-const char *dt_get_board_model(void);
|
|
-
|
|
-#endif /* __STM32MP1_DT_H__ */
|
|
diff --git a/plat/st/stm32mp1/include/stm32mp1_low_power.h b/plat/st/stm32mp1/include/stm32mp1_low_power.h
|
|
new file mode 100644
|
|
index 0000000..a9b2778
|
|
--- /dev/null
|
|
+++ b/plat/st/stm32mp1/include/stm32mp1_low_power.h
|
|
@@ -0,0 +1,19 @@
|
|
+/*
|
|
+ * Copyright (c) 2017-2018, STMicroelectronics - All Rights Reserved
|
|
+ *
|
|
+ * SPDX-License-Identifier: BSD-3-Clause
|
|
+ */
|
|
+
|
|
+#ifndef STM32MP1_LOW_POWER_H
|
|
+#define STM32MP1_LOW_POWER_H
|
|
+
|
|
+#include <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 0000000..bcee6b6
|
|
--- /dev/null
|
|
+++ b/plat/st/stm32mp1/include/stm32mp1_power_config.h
|
|
@@ -0,0 +1,28 @@
|
|
+/*
|
|
+ * Copyright (c) 2017-2018, STMicroelectronics - All Rights Reserved
|
|
+ *
|
|
+ * SPDX-License-Identifier: BSD-3-Clause
|
|
+ */
|
|
+
|
|
+#ifndef STM32MP1_POWER_CONFIG_H
|
|
+#define STM32MP1_POWER_CONFIG_H
|
|
+
|
|
+#include <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 a789d53..cc6c9e7 100644
|
|
--- a/plat/st/stm32mp1/include/stm32mp1_private.h
|
|
+++ b/plat/st/stm32mp1/include/stm32mp1_private.h
|
|
@@ -1,22 +1,38 @@
|
|
/*
|
|
- * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
|
|
+ * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved.
|
|
*
|
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
*/
|
|
|
|
-#ifndef __STM32MP1_PRIVATE_H__
|
|
-#define __STM32MP1_PRIVATE_H__
|
|
+#ifndef STM32MP1_PRIVATE_H
|
|
+#define STM32MP1_PRIVATE_H
|
|
+
|
|
+#include <bl_common.h>
|
|
+#include <boot_api.h>
|
|
+#include <stdbool.h>
|
|
+
|
|
+enum boot_device_e {
|
|
+ BOOT_DEVICE_USB,
|
|
+ BOOT_DEVICE_BOARD
|
|
+};
|
|
|
|
-void stm32mp1_io_setup(void);
|
|
void configure_mmu(void);
|
|
|
|
void stm32mp1_arch_security_setup(void);
|
|
void stm32mp1_security_setup(void);
|
|
+void stm32mp1_sp_min_security_setup(void);
|
|
+
|
|
+enum boot_device_e get_boot_device(void);
|
|
|
|
-void stm32mp1_save_boot_ctx_address(uintptr_t address);
|
|
-uintptr_t stm32mp1_get_boot_ctx_address(void);
|
|
+#if STM32MP_UART_PROGRAMMER
|
|
+uintptr_t get_uart_address(uint32_t instance_nb);
|
|
+#endif
|
|
|
|
void stm32mp1_gic_pcpu_init(void);
|
|
void stm32mp1_gic_init(void);
|
|
|
|
-#endif /* __STM32MP1_PRIVATE_H__ */
|
|
+enum etzpc_decprot_attributes stm32mp_etzpc_binding2decprot(uint32_t mode);
|
|
+
|
|
+void stm32mp1_syscfg_init(void);
|
|
+
|
|
+#endif /* STM32MP1_PRIVATE_H */
|
|
diff --git a/plat/st/stm32mp1/include/stm32mp1_shared_resources.h b/plat/st/stm32mp1/include/stm32mp1_shared_resources.h
|
|
new file mode 100644
|
|
index 0000000..b161cab
|
|
--- /dev/null
|
|
+++ b/plat/st/stm32mp1/include/stm32mp1_shared_resources.h
|
|
@@ -0,0 +1,83 @@
|
|
+/* SPDX-License-Identifier: BSD-3-Clause */
|
|
+/*
|
|
+ * Copyright (c) 2017-2018, STMicroelectronics
|
|
+ */
|
|
+
|
|
+#ifndef STM32MP1_SHARED_RESOURCES_H
|
|
+#define STM32MP1_SHARED_RESOURCES_H
|
|
+
|
|
+#include <debug.h>
|
|
+#include <etzpc.h>
|
|
+#include <stdbool.h>
|
|
+
|
|
+void stm32mp_clk_enable(unsigned long id);
|
|
+void stm32mp_clk_disable(unsigned long id);
|
|
+
|
|
+#define STM32MP1_SHRES_GPIOZ(i) (STM32MP1_SHRES_GPIOZ_0 + i)
|
|
+
|
|
+enum stm32mp_shres {
|
|
+ STM32MP1_SHRES_GPIOZ_0 = 0,
|
|
+ STM32MP1_SHRES_GPIOZ_1,
|
|
+ STM32MP1_SHRES_GPIOZ_2,
|
|
+ STM32MP1_SHRES_GPIOZ_3,
|
|
+ STM32MP1_SHRES_GPIOZ_4,
|
|
+ STM32MP1_SHRES_GPIOZ_5,
|
|
+ STM32MP1_SHRES_GPIOZ_6,
|
|
+ STM32MP1_SHRES_GPIOZ_7,
|
|
+ STM32MP1_SHRES_IWDG1,
|
|
+ STM32MP1_SHRES_USART1,
|
|
+ STM32MP1_SHRES_SPI6,
|
|
+ STM32MP1_SHRES_I2C4,
|
|
+ STM32MP1_SHRES_RNG1,
|
|
+ STM32MP1_SHRES_HASH1,
|
|
+ STM32MP1_SHRES_CRYP1,
|
|
+ STM32MP1_SHRES_I2C6,
|
|
+ STM32MP1_SHRES_RTC,
|
|
+ STM32MP1_SHRES_MCU,
|
|
+ STM32MP1_SHRES_HSI,
|
|
+ STM32MP1_SHRES_LSI,
|
|
+ STM32MP1_SHRES_HSE,
|
|
+ STM32MP1_SHRES_LSE,
|
|
+ STM32MP1_SHRES_CSI,
|
|
+ STM32MP1_SHRES_PLL1,
|
|
+ STM32MP1_SHRES_PLL1_P,
|
|
+ STM32MP1_SHRES_PLL1_Q,
|
|
+ STM32MP1_SHRES_PLL1_R,
|
|
+ STM32MP1_SHRES_PLL2,
|
|
+ STM32MP1_SHRES_PLL2_P,
|
|
+ STM32MP1_SHRES_PLL2_Q,
|
|
+ STM32MP1_SHRES_PLL2_R,
|
|
+ STM32MP1_SHRES_PLL3,
|
|
+ STM32MP1_SHRES_PLL3_P,
|
|
+ STM32MP1_SHRES_PLL3_Q,
|
|
+ STM32MP1_SHRES_PLL3_R,
|
|
+
|
|
+ STM32MP1_SHRES_COUNT
|
|
+};
|
|
+
|
|
+void stm32mp1_register_secure_periph(unsigned int id);
|
|
+void stm32mp1_register_shared_periph(unsigned int id);
|
|
+void stm32mp1_register_non_secure_periph(unsigned int id);
|
|
+void stm32mp_register_secure_periph_iomem(uintptr_t base);
|
|
+void stm32mp_register_non_secure_periph_iomem(uintptr_t base);
|
|
+void stm32mp_register_secure_gpio(unsigned int bank, unsigned int pin);
|
|
+void stm32mp_register_non_secure_gpio(unsigned int bank, unsigned int pin);
|
|
+void stm32mp1_register_etzpc_decprot(unsigned int id,
|
|
+ enum etzpc_decprot_attributes attr);
|
|
+
|
|
+bool stm32mp1_periph_is_shared(unsigned long id);
|
|
+bool stm32mp1_periph_is_non_secure(unsigned long id);
|
|
+bool stm32mp1_periph_is_secure(unsigned long id);
|
|
+bool stm32mp1_periph_is_unregistered(unsigned long id);
|
|
+
|
|
+bool stm32mp_gpio_bank_is_shared(unsigned int bank);
|
|
+bool stm32mp_gpio_bank_is_non_secure(unsigned int bank);
|
|
+bool stm32mp_gpio_bank_is_secure(unsigned int bank);
|
|
+
|
|
+bool stm32mp1_clock_is_shareable(unsigned long clock_id);
|
|
+bool stm32mp1_clock_is_shared(unsigned long clock_id);
|
|
+bool stm32mp1_clock_is_non_secure(unsigned long clock_id);
|
|
+
|
|
+void stm32mp1_driver_init_late(void);
|
|
+
|
|
+#endif /* STM32MP1_SHARED_RESOURCES_H */
|
|
diff --git a/plat/st/stm32mp1/include/stm32mp1_smc.h b/plat/st/stm32mp1/include/stm32mp1_smc.h
|
|
new file mode 100644
|
|
index 0000000..956493f
|
|
--- /dev/null
|
|
+++ b/plat/st/stm32mp1/include/stm32mp1_smc.h
|
|
@@ -0,0 +1,68 @@
|
|
+/*
|
|
+ * Copyright (c) 2016-2018, STMicroelectronics - All Rights Reserved
|
|
+ *
|
|
+ * SPDX-License-Identifier: BSD-3-Clause
|
|
+ */
|
|
+
|
|
+#ifndef __STM32MP1_SMC_H__
|
|
+#define __STM32MP1_SMC_H__
|
|
+
|
|
+#include <platform_def.h>
|
|
+
|
|
+/*
|
|
+ * SMC function IDs for STM32 Service queries
|
|
+ * STM32 SMC services use the space between 0x82000000 and 0x8200FFFF
|
|
+ * like this is defined in SMC calling Convention by ARM
|
|
+ * for SiP (silicon Partner)
|
|
+ * https://developer.arm.com/docs/den0028/latest
|
|
+ */
|
|
+
|
|
+/* Secure Service access from Non-secure */
|
|
+#define STM32_SMC_RCC 0x82001000
|
|
+#define STM32_SMC_PWR 0x82001001
|
|
+#define STM32_SMC_RCC_CAL 0x82001002
|
|
+#define STM32_SMC_BSEC 0x82001003
|
|
+
|
|
+/* Low Power services */
|
|
+#define STM32_SMC_SR_MODE 0x82001004
|
|
+#define STM32_SMC_PD_DOMAIN 0x82001008
|
|
+
|
|
+/* SMC function IDs for SiP Service queries */
|
|
+#define STM32_SIP_SVC_CALL_COUNT 0x8200ff00
|
|
+#define STM32_SIP_SVC_UID 0x8200ff01
|
|
+/* 0x8200ff02 is reserved */
|
|
+#define STM32_SIP_SVC_VERSION 0x8200ff03
|
|
+
|
|
+/* STM32 SiP Service Calls version numbers */
|
|
+#define STM32_SIP_SVC_VERSION_MAJOR 0x0
|
|
+#define STM32_SIP_SVC_VERSION_MINOR 0x1
|
|
+
|
|
+/* Number of STM32 SiP Calls implemented */
|
|
+#define STM32_COMMON_SIP_NUM_CALLS 10
|
|
+
|
|
+/* Register access service use for RCC/RTC/PWR */
|
|
+#define STM32_SMC_REG_READ 0x0
|
|
+#define STM32_SMC_REG_WRITE 0x1
|
|
+#define STM32_SMC_REG_SET 0x2
|
|
+#define STM32_SMC_REG_CLEAR 0x3
|
|
+
|
|
+/* Service for BSEC */
|
|
+#define STM32_SMC_READ_SHADOW 0x01
|
|
+#define STM32_SMC_PROG_OTP 0x02
|
|
+#define STM32_SMC_WRITE_SHADOW 0x03
|
|
+#define STM32_SMC_READ_OTP 0x04
|
|
+#define STM32_SMC_READ_ALL 0x05
|
|
+#define STM32_SMC_WRITE_ALL 0x06
|
|
+
|
|
+/* SMC error codes */
|
|
+#define STM32_SMC_OK 0x00000000U
|
|
+#define STM32_SMC_NOT_SUPPORTED 0xFFFFFFFFU
|
|
+#define STM32_SMC_FAILED 0xFFFFFFFEU
|
|
+#define STM32_SMC_INVALID_PARAMS 0xFFFFFFFDU
|
|
+
|
|
+/* DDR Self-Refresh modes */
|
|
+#define STM32_SMC_SR_MODE_SSR 0x0
|
|
+#define STM32_SMC_SR_MODE_ASR 0x1
|
|
+#define STM32_SMC_SR_MODE_HSR 0x2
|
|
+
|
|
+#endif /* __STM32MP1_SMC_H__ */
|
|
diff --git a/plat/st/stm32mp1/include/stm32mp1_usb_desc.h b/plat/st/stm32mp1/include/stm32mp1_usb_desc.h
|
|
new file mode 100644
|
|
index 0000000..71cacb3
|
|
--- /dev/null
|
|
+++ b/plat/st/stm32mp1/include/stm32mp1_usb_desc.h
|
|
@@ -0,0 +1,55 @@
|
|
+/*
|
|
+ * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved.
|
|
+ *
|
|
+ * SPDX-License-Identifier: BSD-3-Clause
|
|
+ */
|
|
+
|
|
+#ifndef __USBD_DESC_H
|
|
+#define __USBD_DESC_H
|
|
+
|
|
+#include <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 /* __USBD_DESC_H */
|
|
diff --git a/plat/st/stm32mp1/include/usb_ctx.h b/plat/st/stm32mp1/include/usb_ctx.h
|
|
new file mode 100644
|
|
index 0000000..0046bd0
|
|
--- /dev/null
|
|
+++ b/plat/st/stm32mp1/include/usb_ctx.h
|
|
@@ -0,0 +1,17 @@
|
|
+/*
|
|
+ * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved.
|
|
+ *
|
|
+ * SPDX-License-Identifier: BSD-3-Clause
|
|
+ */
|
|
+
|
|
+#ifndef __USB_CTX_H
|
|
+#define __USB_CTX_H
|
|
+
|
|
+#include <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_bl2_mem_params_desc.c b/plat/st/stm32mp1/plat_bl2_mem_params_desc.c
|
|
index 6f5bc4c..4ef135e 100644
|
|
--- a/plat/st/stm32mp1/plat_bl2_mem_params_desc.c
|
|
+++ b/plat/st/stm32mp1/plat_bl2_mem_params_desc.c
|
|
@@ -26,7 +26,9 @@ static bl_mem_params_node_t bl2_mem_params_descs[] = {
|
|
VERSION_2, entry_point_info_t,
|
|
SECURE | EXECUTABLE | EP_FIRST_EXE),
|
|
|
|
+#if !defined(AARCH32_SP_OPTEE)
|
|
.ep_info.pc = BL32_BASE,
|
|
+#endif
|
|
.ep_info.spsr = SPSR_MODE32(MODE32_svc, SPSR_T_ARM,
|
|
SPSR_E_LITTLE,
|
|
DISABLE_ALL_EXCEPTIONS),
|
|
@@ -34,13 +36,48 @@ static bl_mem_params_node_t bl2_mem_params_descs[] = {
|
|
SET_STATIC_PARAM_HEAD(image_info, PARAM_EP,
|
|
VERSION_2, image_info_t,
|
|
IMAGE_ATTRIB_PLAT_SETUP),
|
|
-
|
|
+#if defined(AARCH32_SP_OPTEE)
|
|
+ /* optee header is loaded is SYSRAM above BL2 */
|
|
+ .image_info.image_base = STM32MP_OPTEE_BASE,
|
|
+ .image_info.image_max_size = STM32MP_OPTEE_SIZE,
|
|
+#else
|
|
.image_info.image_base = BL32_BASE,
|
|
.image_info.image_max_size = BL32_LIMIT - BL32_BASE,
|
|
-
|
|
+#endif
|
|
.next_handoff_image_id = BL33_IMAGE_ID,
|
|
},
|
|
|
|
+#if defined(AARCH32_SP_OPTEE)
|
|
+ /* Fill BL32 external 1 image related information */
|
|
+ {
|
|
+ .image_id = BL32_EXTRA1_IMAGE_ID,
|
|
+
|
|
+ SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP,
|
|
+ VERSION_2, entry_point_info_t,
|
|
+ SECURE | NON_EXECUTABLE),
|
|
+
|
|
+ SET_STATIC_PARAM_HEAD(image_info, PARAM_EP,
|
|
+ VERSION_2, image_info_t,
|
|
+ IMAGE_ATTRIB_SKIP_LOADING),
|
|
+
|
|
+ .next_handoff_image_id = INVALID_IMAGE_ID,
|
|
+ },
|
|
+ /* Fill BL32 external 2 image related information */
|
|
+ {
|
|
+ .image_id = BL32_EXTRA2_IMAGE_ID,
|
|
+
|
|
+ SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP,
|
|
+ VERSION_2, entry_point_info_t,
|
|
+ SECURE | NON_EXECUTABLE),
|
|
+
|
|
+ SET_STATIC_PARAM_HEAD(image_info, PARAM_EP,
|
|
+ VERSION_2, image_info_t,
|
|
+ IMAGE_ATTRIB_SKIP_LOADING),
|
|
+
|
|
+ .next_handoff_image_id = INVALID_IMAGE_ID,
|
|
+ },
|
|
+#endif /* AARCH32_SP_OPTEE */
|
|
+
|
|
/* Fill BL33 related information */
|
|
{
|
|
.image_id = BL33_IMAGE_ID,
|
|
@@ -49,7 +86,7 @@ static bl_mem_params_node_t bl2_mem_params_descs[] = {
|
|
VERSION_2, entry_point_info_t,
|
|
NON_SECURE | EXECUTABLE),
|
|
|
|
- .ep_info.pc = PLAT_STM32MP1_NS_IMAGE_OFFSET,
|
|
+ .ep_info.pc = PLAT_STM32MP_NS_IMAGE_OFFSET,
|
|
.ep_info.spsr = SPSR_MODE32(MODE32_svc, SPSR_T_ARM,
|
|
SPSR_E_LITTLE,
|
|
DISABLE_ALL_EXCEPTIONS),
|
|
@@ -57,9 +94,9 @@ static bl_mem_params_node_t bl2_mem_params_descs[] = {
|
|
SET_STATIC_PARAM_HEAD(image_info, PARAM_EP,
|
|
VERSION_2, image_info_t, 0),
|
|
|
|
- .image_info.image_base = PLAT_STM32MP1_NS_IMAGE_OFFSET,
|
|
- .image_info.image_max_size = STM32MP1_DDR_MAX_SIZE -
|
|
- (PLAT_STM32MP1_NS_IMAGE_OFFSET - STM32MP1_DDR_BASE),
|
|
+ .image_info.image_base = PLAT_STM32MP_NS_IMAGE_OFFSET,
|
|
+ .image_info.image_max_size = STM32MP_DDR_MAX_SIZE -
|
|
+ (PLAT_STM32MP_NS_IMAGE_OFFSET - STM32MP_DDR_BASE),
|
|
|
|
.next_handoff_image_id = INVALID_IMAGE_ID,
|
|
}
|
|
diff --git a/plat/st/stm32mp1/plat_image_load.c b/plat/st/stm32mp1/plat_image_load.c
|
|
index 3c6d677..db53c37 100644
|
|
--- a/plat/st/stm32mp1/plat_image_load.c
|
|
+++ b/plat/st/stm32mp1/plat_image_load.c
|
|
@@ -4,7 +4,23 @@
|
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
*/
|
|
|
|
+#include <bl_common.h>
|
|
+#include <boot_api.h>
|
|
+#include <bsec.h>
|
|
+#include <cassert.h>
|
|
+#include <debug.h>
|
|
#include <desc_image_load.h>
|
|
+#include <dt-bindings/clock/stm32mp1-clks.h>
|
|
+#include <mmio.h>
|
|
+#include <platform.h>
|
|
+#include <stm32mp_common.h>
|
|
+#include <stm32mp_dt.h>
|
|
+#include <stm32mp1_context.h>
|
|
+#include <stm32mp1_private.h>
|
|
+#include <stm32mp1_pwr.h>
|
|
+#include <stm32mp1_rcc.h>
|
|
+#include <stm32mp1_shared_resources.h>
|
|
+#include <utils_def.h>
|
|
|
|
/*******************************************************************************
|
|
* This function flushes the data structures so that they are visible
|
|
@@ -12,14 +28,101 @@
|
|
******************************************************************************/
|
|
void plat_flush_next_bl_params(void)
|
|
{
|
|
+ uint32_t version;
|
|
+
|
|
flush_bl_params_desc();
|
|
+
|
|
+ CASSERT(STM32_TF_VERSION <= MAX_MONOTONIC_VALUE,
|
|
+ assert_stm32mp1_monotonic_counter_reach_max);
|
|
+
|
|
+ /* Check if monotonic counter need to be incremented */
|
|
+ ;
|
|
+ if (bsec_shadow_read_otp(&version, MONOTONIC_OTP) != BSEC_OK) {
|
|
+ ERROR("BSEC: MONOTONIC_OTP Error\n");
|
|
+ panic();
|
|
+ }
|
|
+
|
|
+ INFO("read version %i current version %i\n", version, STM32_TF_VERSION);
|
|
+
|
|
+ if ((version + 1U) < BIT(STM32_TF_VERSION)) {
|
|
+ uint32_t result;
|
|
+
|
|
+ /* need to increment the monotonic counter */
|
|
+ version = BIT(STM32_TF_VERSION) - 1U;
|
|
+
|
|
+ result = bsec_program_otp(version, MONOTONIC_OTP);
|
|
+ if (result != BSEC_OK) {
|
|
+ ERROR("BSEC: MONOTONIC_OTP program Error %i\n",
|
|
+ result);
|
|
+ panic();
|
|
+ }
|
|
+ INFO("Monotonic counter has been incremented value 0x%x\n",
|
|
+ version);
|
|
+ }
|
|
}
|
|
|
|
+#ifdef AARCH32_SP_OPTEE
|
|
+static bool addr_inside_backupsram(uintptr_t addr)
|
|
+{
|
|
+ return (addr >= STM32MP_BACKUP_RAM_BASE) &&
|
|
+ (addr < (STM32MP_BACKUP_RAM_BASE + STM32MP_BACKUP_RAM_SIZE));
|
|
+}
|
|
+#endif
|
|
+
|
|
/*******************************************************************************
|
|
* This function returns the list of loadable images.
|
|
******************************************************************************/
|
|
bl_load_info_t *plat_get_bl_image_load_info(void)
|
|
{
|
|
+ boot_api_context_t *boot_context =
|
|
+ (boot_api_context_t *)stm32mp_get_boot_ctx_address();
|
|
+#ifdef AARCH32_SP_OPTEE
|
|
+ bl_mem_params_node_t *bl32 = get_bl_mem_params_node(BL32_IMAGE_ID);
|
|
+#endif
|
|
+ bl_mem_params_node_t *bl33 = get_bl_mem_params_node(BL33_IMAGE_ID);
|
|
+ uint32_t rstsr = mmio_read_32(stm32mp_rcc_base() + RCC_MP_RSTSCLRR);
|
|
+ uint32_t bkpr_core1_addr =
|
|
+ tamp_bkpr(BOOT_API_CORE1_BRANCH_ADDRESS_TAMP_BCK_REG_IDX);
|
|
+ uintptr_t pwr_base = stm32mp_pwr_base();
|
|
+
|
|
+ /*
|
|
+ * If going back from CSTANDBY / STANDBY and DDR was in Self-Refresh,
|
|
+ * BL33 must not be loaded as it would overwrite the code already
|
|
+ * in DDR. For this, the BL33 part of the bl_mem_params_desc_ptr
|
|
+ * struct should be modified to skip its loading
|
|
+ */
|
|
+ if (((boot_context->boot_action ==
|
|
+ BOOT_API_CTX_BOOT_ACTION_WAKEUP_CSTANDBY) ||
|
|
+ (boot_context->boot_action ==
|
|
+ BOOT_API_CTX_BOOT_ACTION_WAKEUP_STANDBY)) &&
|
|
+ ((mmio_read_32(pwr_base + PWR_CR3) & PWR_CR3_DDRSREN) != 0U) &&
|
|
+ ((rstsr & RCC_MP_RSTSCLRR_PADRSTF) == 0U)) {
|
|
+ stm32mp_clk_enable(RTCAPB);
|
|
+
|
|
+ if (mmio_read_32(bkpr_core1_addr) != 0U) {
|
|
+ bl33->image_info.h.attr |= IMAGE_ATTRIB_SKIP_LOADING;
|
|
+
|
|
+#ifdef AARCH32_SP_OPTEE
|
|
+ bl32->image_info.h.attr |= IMAGE_ATTRIB_SKIP_LOADING;
|
|
+ bl32->ep_info.pc = stm32_pm_get_optee_ep();
|
|
+
|
|
+ if (addr_inside_backupsram(bl32->ep_info.pc)) {
|
|
+ stm32mp_clk_enable(BKPSRAM);
|
|
+ }
|
|
+#else
|
|
+ /*
|
|
+ * Set ep_info PC to 0, to inform BL32 it is a reset
|
|
+ * after STANDBY
|
|
+ */
|
|
+ bl33->ep_info.pc = 0;
|
|
+#endif
|
|
+ }
|
|
+
|
|
+ stm32mp_clk_disable(RTCAPB);
|
|
+ }
|
|
+
|
|
+ bl33->image_info.image_max_size = dt_get_ddr_size();
|
|
+
|
|
return get_bl_load_info_from_mem_params_desc();
|
|
}
|
|
|
|
diff --git a/plat/st/stm32mp1/platform.mk b/plat/st/stm32mp1/platform.mk
|
|
index 30b2932..06594f0 100644
|
|
--- a/plat/st/stm32mp1/platform.mk
|
|
+++ b/plat/st/stm32mp1/platform.mk
|
|
@@ -1,5 +1,5 @@
|
|
#
|
|
-# Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
|
|
+# Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved.
|
|
#
|
|
# SPDX-License-Identifier: BSD-3-Clause
|
|
#
|
|
@@ -8,24 +8,78 @@ ARM_CORTEX_A7 := yes
|
|
ARM_WITH_NEON := yes
|
|
BL2_AT_EL3 := 1
|
|
USE_COHERENT_MEM := 0
|
|
+MULTI_CONSOLE_API := 1
|
|
|
|
+# Please don't increment this value without good understanding of
|
|
+# the monotonic counter
|
|
STM32_TF_VERSION ?= 0
|
|
+$(eval $(call add_define_val,STM32_TF_VERSION,${STM32_TF_VERSION}))
|
|
+
|
|
+# Enable software PMIC programming in case of debug purpose
|
|
+STM32MP1_DEBUG_ENABLE ?= 1
|
|
+$(eval $(call add_define_val,STM32MP1_DEBUG_ENABLE,${STM32MP1_DEBUG_ENABLE}))
|
|
|
|
# Not needed for Cortex-A7
|
|
WORKAROUND_CVE_2017_5715:= 0
|
|
|
|
-PLAT_INCLUDES := -Iplat/st/stm32mp1/include/
|
|
-PLAT_INCLUDES += -Iinclude/common/tbbr
|
|
+# Specific modification for reset halt workaround
|
|
+STM32MP1_RESET_HALT_WORKAROUND ?= 1
|
|
+$(eval $(call add_define,STM32MP1_RESET_HALT_WORKAROUND))
|
|
+
|
|
+AARCH32_EXCEPTION_DEBUG := 1
|
|
+
|
|
+ifeq ($(AARCH32_SP),optee)
|
|
+$(eval $(call add_define,AARCH32_SP_OPTEE))
|
|
+endif
|
|
+
|
|
+# Number of TF-A copies in the device
|
|
+STM32_TF_A_COPIES := 2
|
|
+$(eval $(call add_define,STM32_TF_A_COPIES))
|
|
+ifeq ($(AARCH32_SP),optee)
|
|
+PLAT_PARTITION_MAX_ENTRIES := $(shell echo $$(($(STM32_TF_A_COPIES) + 4)))
|
|
+else
|
|
+PLAT_PARTITION_MAX_ENTRIES := $(shell echo $$(($(STM32_TF_A_COPIES) + 1)))
|
|
+endif
|
|
+$(eval $(call add_define,PLAT_PARTITION_MAX_ENTRIES))
|
|
+
|
|
+# Boot devices
|
|
+STM32MP1_QSPI_NOR := 1
|
|
+$(eval $(call add_define,STM32MP1_QSPI_NOR))
|
|
+STM32MP_FMC_NAND := 1
|
|
+$(eval $(call add_define,STM32MP_FMC_NAND))
|
|
+STM32MP_EMMC := 1
|
|
+$(eval $(call add_define,STM32MP_EMMC))
|
|
+STM32MP_SDMMC := 1
|
|
+$(eval $(call add_define,STM32MP_SDMMC))
|
|
+STM32MP1_QSPI_NAND := 1
|
|
+$(eval $(call add_define,STM32MP1_QSPI_NAND))
|
|
+
|
|
+ifeq ($(filter 1,${STM32MP1_QSPI_NOR} ${STM32MP_FMC_NAND} ${STM32MP_EMMC} ${STM32MP_SDMMC}),)
|
|
+$(error "No boot device driver is enabled")
|
|
+endif
|
|
+
|
|
+STM32MP_UART_PROGRAMMER := 1
|
|
+$(eval $(call add_define,STM32MP_UART_PROGRAMMER))
|
|
+
|
|
+PLAT_INCLUDES := -Iinclude/common/tbbr
|
|
+PLAT_INCLUDES += -Iinclude/drivers/partition
|
|
PLAT_INCLUDES += -Iinclude/drivers/st
|
|
+PLAT_INCLUDES += -Iplat/st/common/include/
|
|
+PLAT_INCLUDES += -Iplat/st/stm32mp1/include/
|
|
+
|
|
+PLAT_INCLUDES += -Iinclude/lib/usb
|
|
+
|
|
+STM32MP_USB := 1
|
|
|
|
# Device tree
|
|
-STM32_DTB_FILE_NAME ?= stm32mp157c-ev1.dtb
|
|
-FDT_SOURCES := $(addprefix fdts/, $(patsubst %.dtb,%.dts,$(STM32_DTB_FILE_NAME)))
|
|
+DTB_FILE_NAME ?= stm32mp157c-ev1.dtb
|
|
+FDT_SOURCES := $(addprefix fdts/, $(patsubst %.dtb,%.dts,$(DTB_FILE_NAME)))
|
|
DTC_FLAGS += -Wno-unit_address_vs_reg
|
|
|
|
include lib/libfdt/libfdt.mk
|
|
|
|
-PLAT_BL_COMMON_SOURCES := plat/st/stm32mp1/stm32mp1_common.c
|
|
+PLAT_BL_COMMON_SOURCES := plat/st/common/stm32mp_common.c \
|
|
+ plat/st/stm32mp1/stm32mp1_private.c
|
|
|
|
PLAT_BL_COMMON_SOURCES += drivers/console/aarch32/console.S \
|
|
drivers/st/uart/aarch32/stm32_console.S
|
|
@@ -43,23 +97,56 @@ PLAT_BL_COMMON_SOURCES += ${LIBFDT_SRCS} \
|
|
drivers/arm/tzc/tzc400.c \
|
|
drivers/delay_timer/delay_timer.c \
|
|
drivers/delay_timer/generic_delay_timer.c \
|
|
+ drivers/st/bsec/bsec.c \
|
|
+ drivers/st/clk/stm32mp_clkfunc.c \
|
|
drivers/st/clk/stm32mp1_clk.c \
|
|
drivers/st/clk/stm32mp1_clkfunc.c \
|
|
drivers/st/ddr/stm32mp1_ddr_helpers.c \
|
|
drivers/st/gpio/stm32_gpio.c \
|
|
- drivers/st/pmic/stm32_i2c.c \
|
|
- drivers/st/pmic/stm32mp1_pmic.c \
|
|
- drivers/st/pmic/stpmu1.c \
|
|
+ drivers/st/i2c/stm32_i2c.c \
|
|
+ drivers/st/iwdg/stm32_iwdg.c \
|
|
+ drivers/st/pmic/stm32mp_pmic.c \
|
|
+ drivers/st/pmic/stpmic1.c \
|
|
drivers/st/reset/stm32mp1_reset.c \
|
|
+ plat/st/common/stm32mp_dt.c \
|
|
+ plat/st/common/stm32mp_shres_helpers.c \
|
|
plat/st/stm32mp1/stm32mp1_context.c \
|
|
- plat/st/stm32mp1/stm32mp1_dt.c \
|
|
+ plat/st/stm32mp1/stm32mp1_dbgmcu.c \
|
|
plat/st/stm32mp1/stm32mp1_helper.S \
|
|
- plat/st/stm32mp1/stm32mp1_security.c
|
|
+ plat/st/stm32mp1/stm32mp1_security.c \
|
|
+ plat/st/stm32mp1/stm32mp1_shared_resources.c
|
|
|
|
-BL2_SOURCES += drivers/io/io_dummy.c \
|
|
+BL2_SOURCES += drivers/io/io_block.c \
|
|
+ drivers/io/io_dummy.c \
|
|
drivers/io/io_storage.c \
|
|
- plat/st/stm32mp1/bl2_io_storage.c \
|
|
- plat/st/stm32mp1/bl2_plat_setup.c
|
|
+ drivers/st/hash/hash_sec.c \
|
|
+ drivers/st/io/io_stm32image.c \
|
|
+ plat/st/common/bl2_io_storage.c \
|
|
+ plat/st/common/stm32mp_auth.c \
|
|
+ plat/st/stm32mp1/bl2_plat_setup.c \
|
|
+ plat/st/stm32mp1/stm32mp1_syscfg.c
|
|
+
|
|
+ifeq (${STM32MP1_QSPI_NOR},1)
|
|
+BL2_SOURCES += drivers/st/qspi/io_qspi.c
|
|
+endif
|
|
+
|
|
+ifeq (${STM32MP_FMC_NAND},1)
|
|
+BL2_SOURCES += drivers/st/nand/io_nand.c \
|
|
+ drivers/st/nand/nand.c
|
|
+endif
|
|
+
|
|
+ifneq ($(filter 1,${STM32MP_EMMC} ${STM32MP_SDMMC}),)
|
|
+BL2_SOURCES += drivers/mmc/mmc.c \
|
|
+ drivers/partition/gpt.c \
|
|
+ drivers/partition/partition.c \
|
|
+ drivers/st/io/io_mmc.c \
|
|
+ drivers/st/mmc/stm32_sdmmc2.c
|
|
+endif
|
|
+
|
|
+ifeq (${STM32MP_UART_PROGRAMMER},1)
|
|
+BL2_SOURCES += drivers/st/uart/io_programmer_uart.c \
|
|
+ drivers/st/uart/stm32mp1xx_hal_uart.c
|
|
+endif
|
|
|
|
BL2_SOURCES += drivers/st/ddr/stm32mp1_ddr.c \
|
|
drivers/st/ddr/stm32mp1_ram.c
|
|
@@ -68,19 +155,36 @@ BL2_SOURCES += common/desc_image_load.c \
|
|
plat/st/stm32mp1/plat_bl2_mem_params_desc.c \
|
|
plat/st/stm32mp1/plat_image_load.c
|
|
|
|
-# For memory footprint optimization, build with thumb and interwork support
|
|
-ASFLAGS += -mthumb -mthumb-interwork
|
|
-TF_CFLAGS += -mthumb -mthumb-interwork
|
|
+ifneq (${STM32MP_USB},0)
|
|
+BL2_SOURCES += drivers/st/io/io_programmer_st_usb.c \
|
|
+ drivers/st/usb_dwc2/usb_dwc2.c \
|
|
+ lib/usb/usb_core.c \
|
|
+ lib/usb/usb_st_dfu.c \
|
|
+ plat/st/stm32mp1/stm32mp1_usb_desc.c
|
|
+
|
|
+TF_CFLAGS += -DSTM32MP_USB
|
|
+endif
|
|
+
|
|
+ifeq ($(AARCH32_SP),optee)
|
|
+BL2_SOURCES += lib/optee/optee_utils.c
|
|
+endif
|
|
+
|
|
+ifeq (${STM32MP1_RESET_HALT_WORKAROUND},1)
|
|
+BL2_SOURCES += plat/st/stm32mp1/stm32mp1_helper_dbg.S
|
|
+endif
|
|
+
|
|
+# Do not use neon in TF-A code, it leads to issues in low-power functions
|
|
+TF_CFLAGS += -mfloat-abi=soft
|
|
|
|
# Macros and rules to build TF binary
|
|
STM32_TF_ELF_LDFLAGS := --hash-style=gnu --as-needed
|
|
-STM32_DT_BASENAME := $(STM32_DTB_FILE_NAME:.dtb=)
|
|
+STM32_DT_BASENAME := $(DTB_FILE_NAME:.dtb=)
|
|
STM32_TF_STM32 := ${BUILD_PLAT}/tf-a-${STM32_DT_BASENAME}.stm32
|
|
STM32_TF_BINARY := $(STM32_TF_STM32:.stm32=.bin)
|
|
STM32_TF_MAPFILE := $(STM32_TF_STM32:.stm32=.map)
|
|
STM32_TF_LINKERFILE := $(STM32_TF_STM32:.stm32=.ld)
|
|
STM32_TF_ELF := $(STM32_TF_STM32:.stm32=.elf)
|
|
-STM32_TF_DTBFILE := ${BUILD_PLAT}/fdts/${STM32_DTB_FILE_NAME}
|
|
+STM32_TF_DTBFILE := ${BUILD_PLAT}/fdts/${DTB_FILE_NAME}
|
|
STM32_TF_OBJS := ${BUILD_PLAT}/stm32mp1.o
|
|
|
|
# Variables for use with stm32image
|
|
@@ -123,7 +227,7 @@ ${STM32_TF_OBJS}: plat/st/stm32mp1/stm32mp1.S bl2 ${BL32_DEP} ${STM32_TF_DTBFILE
|
|
-DDTB_BIN_PATH=\"${STM32_TF_DTBFILE}\" \
|
|
-c plat/st/stm32mp1/stm32mp1.S -o $@
|
|
|
|
-${STM32_TF_LINKERFILE}: plat/st/stm32mp1/stm32mp1.ld.S
|
|
+${STM32_TF_LINKERFILE}: plat/st/stm32mp1/stm32mp1.ld.S ${BUILD_PLAT}
|
|
@echo " LDS $<"
|
|
${Q}${AS} ${ASFLAGS} ${TF_CFLAGS} -P -E $< -o $@
|
|
|
|
diff --git a/plat/st/stm32mp1/services/bsec_svc.c b/plat/st/stm32mp1/services/bsec_svc.c
|
|
new file mode 100644
|
|
index 0000000..e4f86a2
|
|
--- /dev/null
|
|
+++ b/plat/st/stm32mp1/services/bsec_svc.c
|
|
@@ -0,0 +1,460 @@
|
|
+/*
|
|
+ * Copyright (c) 2016-2018, STMicroelectronics - All Rights Reserved
|
|
+ *
|
|
+ * SPDX-License-Identifier: BSD-3-Clause
|
|
+ */
|
|
+
|
|
+#include <arch.h>
|
|
+#include <arch_helpers.h>
|
|
+#include <assert.h>
|
|
+#include <boot_api.h>
|
|
+#include <debug.h>
|
|
+#include <mmio.h>
|
|
+#include <platform_def.h>
|
|
+#include <runtime_svc.h>
|
|
+#include <std_svc.h>
|
|
+#include <stm32mp_pmic.h>
|
|
+#include <stm32mp1_dbgmcu.h>
|
|
+#include <stm32mp1_ddr_helpers.h>
|
|
+#include <stm32mp1_smc.h>
|
|
+#include <stpmic1.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) {
|
|
+ initialize_pmic();
|
|
+ stpmic1_regulator_mask_reset_set("buck1");
|
|
+ }
|
|
+
|
|
+ return BSEC_SSP_SET;
|
|
+ }
|
|
+ return BSEC_NO_SSP;
|
|
+}
|
|
+
|
|
+static uint32_t bsec_read_all_bsec(struct otp_exchange *exchange)
|
|
+{
|
|
+ uint32_t i;
|
|
+ uint32_t result;
|
|
+
|
|
+ if (exchange == NULL) {
|
|
+ return BSEC_ERROR;
|
|
+ }
|
|
+
|
|
+ exchange->version = BSEC_SERVICE_VERSION;
|
|
+
|
|
+ for (i = 0U; i <= STM32MP1_OTP_MAX_ID; i++) {
|
|
+ if (bsec_check_nsec_access_rights(i) == BSEC_OK) {
|
|
+ result = bsec_shadow_register(i);
|
|
+ if (result != BSEC_OK) {
|
|
+ return result;
|
|
+ }
|
|
+
|
|
+ result = bsec_read_otp(&exchange->otp_value[i], i);
|
|
+ if (result != BSEC_OK) {
|
|
+ return result;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ exchange->configuration = mmio_read_32(bsec_get_base() +
|
|
+ BSEC_OTP_CONF_OFF);
|
|
+
|
|
+ exchange->status = mmio_read_32(bsec_get_base() + BSEC_OTP_STATUS_OFF);
|
|
+
|
|
+ exchange->general_lock = mmio_read_32(bsec_get_base() +
|
|
+ BSEC_OTP_LOCK_OFF);
|
|
+
|
|
+ exchange->debug_conf = mmio_read_32(bsec_get_base() + BSEC_DEN_OFF);
|
|
+
|
|
+ exchange->otp_disturb[0] = mmio_read_32(bsec_get_base() +
|
|
+ BSEC_DISTURBED_OFF);
|
|
+
|
|
+ exchange->otp_disturb[1] = mmio_read_32(bsec_get_base() +
|
|
+ BSEC_DISTURBED1_OFF);
|
|
+
|
|
+ exchange->otp_disturb[2] = mmio_read_32(bsec_get_base() +
|
|
+ BSEC_DISTURBED2_OFF);
|
|
+
|
|
+ exchange->error_status[0] = mmio_read_32(bsec_get_base() +
|
|
+ BSEC_ERROR_OFF);
|
|
+
|
|
+ exchange->error_status[1] = mmio_read_32(bsec_get_base() +
|
|
+ BSEC_ERROR1_OFF);
|
|
+
|
|
+ exchange->error_status[2] = mmio_read_32(bsec_get_base() +
|
|
+ BSEC_ERROR2_OFF);
|
|
+
|
|
+ exchange->permanent_lock[0] = mmio_read_32(bsec_get_base() +
|
|
+ BSEC_WRLOCK_OFF);
|
|
+
|
|
+ exchange->permanent_lock[1] = mmio_read_32(bsec_get_base() +
|
|
+ BSEC_WRLOCK1_OFF);
|
|
+
|
|
+ exchange->permanent_lock[2] = mmio_read_32(bsec_get_base() +
|
|
+ BSEC_WRLOCK2_OFF);
|
|
+
|
|
+ exchange->programming_lock[0] = mmio_read_32(bsec_get_base() +
|
|
+ BSEC_SPLOCK_OFF);
|
|
+
|
|
+ exchange->programming_lock[1] = mmio_read_32(bsec_get_base() +
|
|
+ BSEC_SPLOCK1_OFF);
|
|
+
|
|
+ exchange->programming_lock[2] = mmio_read_32(bsec_get_base() +
|
|
+ BSEC_SPLOCK2_OFF);
|
|
+
|
|
+ exchange->shadow_write_lock[0] = mmio_read_32(bsec_get_base() +
|
|
+ BSEC_SWLOCK_OFF);
|
|
+
|
|
+ exchange->shadow_write_lock[1] = mmio_read_32(bsec_get_base() +
|
|
+ BSEC_SWLOCK1_OFF);
|
|
+
|
|
+ exchange->shadow_write_lock[2] = mmio_read_32(bsec_get_base() +
|
|
+ BSEC_SWLOCK2_OFF);
|
|
+
|
|
+ exchange->shadow_read_lock[0] = mmio_read_32(bsec_get_base() +
|
|
+ BSEC_SRLOCK_OFF);
|
|
+
|
|
+ exchange->shadow_read_lock[1] = mmio_read_32(bsec_get_base() +
|
|
+ BSEC_SRLOCK1_OFF);
|
|
+
|
|
+ exchange->shadow_read_lock[2] = mmio_read_32(bsec_get_base() +
|
|
+ BSEC_SRLOCK2_OFF);
|
|
+
|
|
+ exchange->bsec_hw_conf = mmio_read_32(bsec_get_base() +
|
|
+ BSEC_IPHW_CFG_OFF);
|
|
+
|
|
+ exchange->ip_version = mmio_read_32(bsec_get_base() + BSEC_IPVR_OFF);
|
|
+
|
|
+ exchange->ip_id = mmio_read_32(bsec_get_base() + BSEC_IP_ID_OFF);
|
|
+
|
|
+ exchange->ip_magic_id = mmio_read_32(bsec_get_base() +
|
|
+ BSEC_IP_MAGIC_ID_OFF);
|
|
+
|
|
+ return BSEC_OK;
|
|
+}
|
|
+
|
|
+static uint32_t bsec_write_all_bsec(struct otp_exchange *exchange,
|
|
+ uint32_t *ret_otp_value)
|
|
+{
|
|
+ uint32_t i;
|
|
+ uint32_t j;
|
|
+ uint32_t start_otp = 0U;
|
|
+ uint32_t value = 0U;
|
|
+ uint32_t ret;
|
|
+ struct bsec_config config_param;
|
|
+
|
|
+ *ret_otp_value = 0U;
|
|
+
|
|
+ if (exchange == NULL) {
|
|
+ return BSEC_ERROR;
|
|
+ }
|
|
+
|
|
+ if (exchange->version != BSEC_SERVICE_VERSION) {
|
|
+ return BSEC_ERROR;
|
|
+ }
|
|
+
|
|
+ for (i = start_otp; i <= STM32MP1_OTP_MAX_ID; i++) {
|
|
+ if (bsec_check_nsec_access_rights(i) != BSEC_OK) {
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ ret = bsec_shadow_register(i);
|
|
+ if (ret != BSEC_OK) {
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
+ ret = bsec_read_otp(&value, i);
|
|
+ if (ret != BSEC_OK) {
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
+ if ((value == exchange->otp_value[i]) &&
|
|
+ (i != BOOT_API_OTP_SSP_WORD_NB)) {
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ if (i == BOOT_API_OTP_SSP_WORD_NB) {
|
|
+ *ret_otp_value = (uint32_t)bsec_check_ssp(value,
|
|
+ exchange->otp_value[i]);
|
|
+ VERBOSE("Result OTP SSP %d\n", *ret_otp_value);
|
|
+ if (*ret_otp_value == (uint32_t)BSEC_SSP_ERROR) {
|
|
+ continue;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ ret = bsec_program_otp(exchange->otp_value[i], i);
|
|
+ if (ret != BSEC_OK) {
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
+ ret = bsec_write_otp(exchange->otp_value[i], i);
|
|
+ if (ret != BSEC_OK) {
|
|
+ return ret;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ ret = bsec_write_debug_conf(exchange->debug_conf);
|
|
+ if (ret != BSEC_OK) {
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
+ for (j = 0U; j < 3U; j++) {
|
|
+ if (exchange->permanent_lock[j] == 0U) {
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ for (i = 0U; i < 32U; i++) {
|
|
+ if (bsec_check_nsec_access_rights((32U * j) + i) !=
|
|
+ BSEC_OK) {
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ value = (exchange->permanent_lock[j] >> i) & 1U;
|
|
+ if (value != 0U) {
|
|
+ ret = bsec_permanent_lock_otp((32U * j) + i);
|
|
+ if (ret != BSEC_OK) {
|
|
+ return ret;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ for (j = 0U; j < 3U; j++) {
|
|
+ if (exchange->programming_lock[j] == 0U) {
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ for (i = 0U; i < 32U; i++) {
|
|
+ if (bsec_check_nsec_access_rights((32U * j) + i) !=
|
|
+ BSEC_OK) {
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ value = (exchange->programming_lock[j] >> i) & 1U;
|
|
+ if (value != 0U) {
|
|
+ if (!bsec_write_sp_lock((32U * j) + i, 1U)) {
|
|
+ return BSEC_ERROR;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ for (j = 0U; j < 3U; j++) {
|
|
+ if (exchange->shadow_write_lock[j] == 0U) {
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ for (i = 0U; i < 32U; i++) {
|
|
+ if (bsec_check_nsec_access_rights((32U * j) + i) !=
|
|
+ BSEC_OK) {
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ value = (exchange->shadow_write_lock[j] >> i) & 1U;
|
|
+ if (value != 0U) {
|
|
+ if (!bsec_write_sw_lock((32U * j) + i, 1U)) {
|
|
+ return BSEC_ERROR;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ for (j = 0U; j < 3U; j++) {
|
|
+ if (exchange->shadow_read_lock[j] == 0U) {
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ for (i = 0U; i < 32U; i++) {
|
|
+ if (bsec_check_nsec_access_rights((32U * j) + i) !=
|
|
+ BSEC_OK) {
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ value = (exchange->shadow_read_lock[j] >> i) & 1U;
|
|
+ if (value != 0U) {
|
|
+ if (!bsec_write_sr_lock((32U * j) + i, 1U)) {
|
|
+ return BSEC_ERROR;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ ret = bsec_get_config(&config_param);
|
|
+ if (ret != BSEC_OK) {
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
+ config_param.power =
|
|
+ (uint8_t)(exchange->configuration & BSEC_CONF_POWER_UP_MASK) >>
|
|
+ BSEC_CONF_POWER_UP_SHIFT;
|
|
+ config_param.freq =
|
|
+ (uint8_t)(exchange->configuration & BSEC_CONF_FRQ_MASK) >>
|
|
+ BSEC_CONF_FRQ_SHIFT;
|
|
+ config_param.pulse_width =
|
|
+ (uint8_t)(exchange->configuration & BSEC_CONF_PRG_WIDTH_MASK) >>
|
|
+ BSEC_CONF_PRG_WIDTH_SHIFT;
|
|
+ config_param.tread =
|
|
+ (uint8_t)((exchange->configuration & BSEC_CONF_TREAD_MASK) >>
|
|
+ BSEC_CONF_TREAD_SHIFT);
|
|
+ config_param.den_lock =
|
|
+ (uint8_t)(exchange->general_lock & DENREG_LOCK_MASK) >>
|
|
+ DENREG_LOCK_SHIFT;
|
|
+ config_param.prog_lock =
|
|
+ (uint8_t)(exchange->general_lock & GPLOCK_LOCK_MASK) >>
|
|
+ GPLOCK_LOCK_SHIFT;
|
|
+
|
|
+ if (!bsec_mode_is_closed_device()) {
|
|
+ config_param.upper_otp_lock =
|
|
+ (uint8_t)(exchange->general_lock &
|
|
+ UPPER_OTP_LOCK_MASK) >>
|
|
+ UPPER_OTP_LOCK_SHIFT;
|
|
+ }
|
|
+
|
|
+ ret = bsec_set_config(&config_param);
|
|
+ if (ret != BSEC_OK) {
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
+ INFO("write all otp succeed\n");
|
|
+
|
|
+ return BSEC_OK;
|
|
+}
|
|
+
|
|
+uint32_t bsec_main(uint32_t x1, uint32_t x2, uint32_t x3,
|
|
+ uint32_t *ret_otp_value)
|
|
+{
|
|
+ uint32_t result;
|
|
+ uint32_t tmp_data = 0U;
|
|
+ struct otp_exchange *otp_exch = (struct otp_exchange *)(uintptr_t)x2;
|
|
+
|
|
+ if ((x1 != STM32_SMC_READ_ALL) && (x1 != STM32_SMC_WRITE_ALL) &&
|
|
+ (bsec_check_nsec_access_rights(x2) != BSEC_OK)) {
|
|
+ return BSEC_ERROR;
|
|
+ }
|
|
+
|
|
+ if (((x1 == STM32_SMC_READ_ALL) || (x1 == STM32_SMC_WRITE_ALL)) &&
|
|
+ (!ddr_is_nonsecured_area((uintptr_t)x2,
|
|
+ sizeof(struct otp_exchange)))) {
|
|
+ return BSEC_ERROR;
|
|
+ }
|
|
+
|
|
+ switch (x1) {
|
|
+ case STM32_SMC_READ_SHADOW:
|
|
+ result = bsec_read_otp(ret_otp_value, x2);
|
|
+ break;
|
|
+ case STM32_SMC_PROG_OTP:
|
|
+ *ret_otp_value = 0U;
|
|
+ if (x2 == BOOT_API_OTP_SSP_WORD_NB) {
|
|
+ result = bsec_read_otp(&tmp_data, x2);
|
|
+ if (result != BSEC_OK) {
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ *ret_otp_value = (uint32_t)bsec_check_ssp(tmp_data,
|
|
+ otp_exch->otp_value[x2]);
|
|
+ if (*ret_otp_value == (uint32_t)BSEC_SSP_ERROR) {
|
|
+ result = BSEC_OK;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ result = bsec_program_otp(x3, x2);
|
|
+ break;
|
|
+ case STM32_SMC_WRITE_SHADOW:
|
|
+ *ret_otp_value = 0;
|
|
+ result = bsec_write_otp(x3, x2);
|
|
+ break;
|
|
+ case STM32_SMC_READ_OTP:
|
|
+ *ret_otp_value = 0;
|
|
+ result = bsec_read_otp(&tmp_data, x2);
|
|
+ if (result != BSEC_OK) {
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ result = bsec_shadow_register(x2);
|
|
+ if (result != BSEC_OK) {
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ result = bsec_read_otp(ret_otp_value, x2);
|
|
+ if (result != BSEC_OK) {
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ result = bsec_write_otp(tmp_data, x2);
|
|
+ break;
|
|
+ case STM32_SMC_READ_ALL:
|
|
+ result = bsec_read_all_bsec(otp_exch);
|
|
+ break;
|
|
+ case STM32_SMC_WRITE_ALL:
|
|
+ result = bsec_write_all_bsec(otp_exch, ret_otp_value);
|
|
+ break;
|
|
+ default:
|
|
+ result = BSEC_ERROR;
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ return result;
|
|
+}
|
|
diff --git a/plat/st/stm32mp1/services/bsec_svc.h b/plat/st/stm32mp1/services/bsec_svc.h
|
|
new file mode 100644
|
|
index 0000000..75c9aa3
|
|
--- /dev/null
|
|
+++ b/plat/st/stm32mp1/services/bsec_svc.h
|
|
@@ -0,0 +1,21 @@
|
|
+/*
|
|
+ * Copyright (c) 2016-2017, STMicroelectronics - All Rights Reserved
|
|
+ *
|
|
+ * SPDX-License-Identifier: BSD-3-Clause
|
|
+ */
|
|
+
|
|
+#ifndef BSEC_SVC_H
|
|
+#define BSEC_SVC_H
|
|
+
|
|
+#include <arch.h>
|
|
+#include <bl_common.h>
|
|
+#include <bsec.h>
|
|
+
|
|
+/* version of this service */
|
|
+/* must be increase at each structure modification */
|
|
+#define BSEC_SERVICE_VERSION 0x01U
|
|
+
|
|
+uint32_t bsec_main(uint32_t x1, uint32_t x2, uint32_t x3,
|
|
+ uint32_t *ret_otp_value);
|
|
+
|
|
+#endif /* BSEC_SVC_H */
|
|
diff --git a/plat/st/stm32mp1/services/low_power_svc.c b/plat/st/stm32mp1/services/low_power_svc.c
|
|
new file mode 100644
|
|
index 0000000..a7fe026
|
|
--- /dev/null
|
|
+++ b/plat/st/stm32mp1/services/low_power_svc.c
|
|
@@ -0,0 +1,46 @@
|
|
+/*
|
|
+ * Copyright (c) 2017-2018, STMicroelectronics - All Rights Reserved
|
|
+ *
|
|
+ * SPDX-License-Identifier: BSD-3-Clause
|
|
+ */
|
|
+
|
|
+#include <smccc_helpers.h>
|
|
+#include <stm32mp1_ddr_helpers.h>
|
|
+#include <stm32mp1_power_config.h>
|
|
+#include <stm32mp1_smc.h>
|
|
+#include "low_power_svc.h"
|
|
+
|
|
+uint32_t sr_mode_scv_handler(uint32_t x1, uint32_t x2)
|
|
+{
|
|
+ uint32_t ret = STM32_SMC_OK;
|
|
+
|
|
+ switch (x2) {
|
|
+ case STM32_SMC_SR_MODE_SSR:
|
|
+ ddr_sr_mode_ssr();
|
|
+ break;
|
|
+
|
|
+ case STM32_SMC_SR_MODE_ASR:
|
|
+ ddr_sr_mode_asr();
|
|
+ break;
|
|
+
|
|
+ case STM32_SMC_SR_MODE_HSR:
|
|
+ ddr_sr_mode_hsr();
|
|
+ break;
|
|
+
|
|
+ default:
|
|
+ ret = STM32_SMC_INVALID_PARAMS;
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+uint32_t pm_domain_scv_handler(uint32_t x1, uint32_t x2)
|
|
+{
|
|
+ if (stm32mp1_set_pm_domain_state((enum stm32mp1_pm_domain)x1,
|
|
+ (bool)x2) < 0) {
|
|
+ return STM32_SMC_FAILED;
|
|
+ }
|
|
+
|
|
+ return STM32_SMC_OK;
|
|
+}
|
|
diff --git a/plat/st/stm32mp1/services/low_power_svc.h b/plat/st/stm32mp1/services/low_power_svc.h
|
|
new file mode 100644
|
|
index 0000000..1264fa1
|
|
--- /dev/null
|
|
+++ b/plat/st/stm32mp1/services/low_power_svc.h
|
|
@@ -0,0 +1,15 @@
|
|
+/*
|
|
+ * Copyright (c) 2017-2018, STMicroelectronics - All Rights Reserved
|
|
+ *
|
|
+ * SPDX-License-Identifier: BSD-3-Clause
|
|
+ */
|
|
+
|
|
+#ifndef LOW_POWER_SVC_H
|
|
+#define LOW_POWER_SVC_H
|
|
+
|
|
+#include <stdint.h>
|
|
+
|
|
+uint32_t sr_mode_scv_handler(uint32_t x1, uint32_t x2);
|
|
+uint32_t pm_domain_scv_handler(uint32_t x1, uint32_t x2);
|
|
+
|
|
+#endif /* LOW_POWER_SVC_H */
|
|
diff --git a/plat/st/stm32mp1/services/pwr_svc.c b/plat/st/stm32mp1/services/pwr_svc.c
|
|
new file mode 100644
|
|
index 0000000..80dcc7c
|
|
--- /dev/null
|
|
+++ b/plat/st/stm32mp1/services/pwr_svc.c
|
|
@@ -0,0 +1,124 @@
|
|
+/*
|
|
+ * Copyright (c) 2017-2018, STMicroelectronics - All Rights Reserved
|
|
+ * Copyright (c) 2017-2018 ARM Limited and Contributors. All rights reserved.
|
|
+ *
|
|
+ * SPDX-License-Identifier: BSD-3-Clause
|
|
+ */
|
|
+
|
|
+#include <arch_helpers.h>
|
|
+#include <debug.h>
|
|
+#include <mmio.h>
|
|
+#include <platform_def.h>
|
|
+#include <spinlock.h>
|
|
+#include <stm32mp_common.h>
|
|
+#include <stm32mp1_pwr.h>
|
|
+#include <stm32mp1_smc.h>
|
|
+#include "pwr_svc.h"
|
|
+
|
|
+static struct spinlock lock;
|
|
+
|
|
+void pwr_regs_lock(void)
|
|
+{
|
|
+ const uint32_t mask = SCTLR_M_BIT | SCTLR_C_BIT;
|
|
+
|
|
+ /* Lock is currently required only when MMU and cache are enabled */
|
|
+ if ((read_sctlr() & mask) == mask) {
|
|
+ spin_lock(&lock);
|
|
+ }
|
|
+}
|
|
+
|
|
+void pwr_regs_unlock(void)
|
|
+{
|
|
+ const uint32_t mask = SCTLR_M_BIT | SCTLR_C_BIT;
|
|
+
|
|
+ /* Unlock is required only when MMU and cache are enabled */
|
|
+ if ((read_sctlr() & mask) == mask) {
|
|
+ spin_unlock(&lock);
|
|
+ }
|
|
+}
|
|
+
|
|
+static void access_allowed_mask(uint32_t request, uint32_t offset,
|
|
+ uint32_t value, uint32_t allowed_mask)
|
|
+{
|
|
+ uint32_t addr = stm32mp_pwr_base() + offset;
|
|
+ uint32_t masked_value = value & allowed_mask;
|
|
+
|
|
+ pwr_regs_lock();
|
|
+
|
|
+ switch (request) {
|
|
+ case STM32_SMC_REG_WRITE:
|
|
+ mmio_clrsetbits_32(addr, allowed_mask, masked_value);
|
|
+ VERBOSE("wrt 0x%x = 0x%x => 0x%x\n", offset, value,
|
|
+ mmio_read_32(addr));
|
|
+ break;
|
|
+
|
|
+ case STM32_SMC_REG_SET:
|
|
+ mmio_setbits_32(addr, masked_value);
|
|
+ VERBOSE("set 0x%x = 0x%x => 0x%x\n", offset, value,
|
|
+ mmio_read_32(addr));
|
|
+ break;
|
|
+
|
|
+ case STM32_SMC_REG_CLEAR:
|
|
+ mmio_clrbits_32(addr, masked_value);
|
|
+ VERBOSE("clear 0x%x = 0x%x => 0x%x\n", offset, value,
|
|
+ mmio_read_32(addr));
|
|
+ break;
|
|
+
|
|
+ default:
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ pwr_regs_unlock();
|
|
+}
|
|
+
|
|
+static void raw_allowed_access_request(uint32_t request,
|
|
+ uint32_t offset, uint32_t value)
|
|
+{
|
|
+ uint32_t allowed_mask = 0;
|
|
+
|
|
+ switch (offset) {
|
|
+ case PWR_CR3:
|
|
+ allowed_mask |= PWR_CR3_VBE | PWR_CR3_VBRS | PWR_CR3_USB33DEN |
|
|
+ PWR_CR3_REG18EN | PWR_CR3_REG11EN;
|
|
+ break;
|
|
+
|
|
+ case PWR_WKUPCR:
|
|
+ allowed_mask |= PWR_WKUPCR_MASK;
|
|
+ break;
|
|
+
|
|
+ case PWR_MPUWKUPENR:
|
|
+ allowed_mask |= PWR_MPUWKUPENR_MASK;
|
|
+ break;
|
|
+
|
|
+ default:
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ if (allowed_mask != 0U) {
|
|
+ access_allowed_mask(request, offset, value, allowed_mask);
|
|
+ }
|
|
+}
|
|
+
|
|
+uint32_t pwr_scv_handler(uint32_t x1, uint32_t x2, uint32_t x3)
|
|
+{
|
|
+ uint32_t request = x1;
|
|
+ uint32_t offset = x2;
|
|
+ uint32_t value = x3;
|
|
+
|
|
+ /*
|
|
+ * x2 may be either the PWR register offset or the register
|
|
+ * full physical address.
|
|
+ */
|
|
+ if ((offset & ~PWR_OFFSET_MASK) != 0) {
|
|
+ if ((offset & ~PWR_OFFSET_MASK) != stm32mp_pwr_base()) {
|
|
+ return STM32_SMC_INVALID_PARAMS;
|
|
+ }
|
|
+
|
|
+ offset &= PWR_OFFSET_MASK;
|
|
+ }
|
|
+
|
|
+ /* PWR controls for non secure resource may be accessed straight */
|
|
+ raw_allowed_access_request(request, offset, value);
|
|
+
|
|
+ return STM32_SMC_OK;
|
|
+}
|
|
diff --git a/plat/st/stm32mp1/services/pwr_svc.h b/plat/st/stm32mp1/services/pwr_svc.h
|
|
new file mode 100644
|
|
index 0000000..90cf1a3
|
|
--- /dev/null
|
|
+++ b/plat/st/stm32mp1/services/pwr_svc.h
|
|
@@ -0,0 +1,13 @@
|
|
+/*
|
|
+ * Copyright (c) 2017, STMicroelectronics - All Rights Reserved
|
|
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
|
|
+ *
|
|
+ * SPDX-License-Identifier: BSD-3-Clause
|
|
+ */
|
|
+
|
|
+#ifndef PWR_SVC_H
|
|
+#define PWR_SVC_H
|
|
+
|
|
+uint32_t pwr_scv_handler(uint32_t x1, uint32_t x2, uint32_t x3);
|
|
+
|
|
+#endif /* PWR_SVC_H */
|
|
diff --git a/plat/st/stm32mp1/services/rcc_svc.c b/plat/st/stm32mp1/services/rcc_svc.c
|
|
new file mode 100644
|
|
index 0000000..1df6903
|
|
--- /dev/null
|
|
+++ b/plat/st/stm32mp1/services/rcc_svc.c
|
|
@@ -0,0 +1,477 @@
|
|
+/*
|
|
+ * Copyright (c) 2017-2018, STMicroelectronics - All Rights Reserved
|
|
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
|
|
+ *
|
|
+ * SPDX-License-Identifier: BSD-3-Clause
|
|
+ */
|
|
+
|
|
+#include <debug.h>
|
|
+#include <limits.h>
|
|
+#include <mmio.h>
|
|
+#include <platform_def.h>
|
|
+#include <stm32_gpio.h>
|
|
+#include <stm32mp_common.h>
|
|
+#include <stm32mp_shres_helpers.h>
|
|
+#include <stm32mp1_clk.h>
|
|
+#include <stm32mp1_rcc.h>
|
|
+#include <stm32mp1_shared_resources.h>
|
|
+#include <stm32mp1_smc.h>
|
|
+#include "rcc_svc.h"
|
|
+
|
|
+#define STD_REG 0
|
|
+#define SET_REG 1
|
|
+#define CLR_REG 2
|
|
+
|
|
+static void shared_clk_request(uint32_t request,
|
|
+ uint32_t offset, uint32_t value)
|
|
+{
|
|
+ unsigned long id;
|
|
+ unsigned int bit;
|
|
+ uint32_t enable_bits = 0;
|
|
+ int clr_std_set = STD_REG;
|
|
+
|
|
+ switch (request) {
|
|
+ case STM32_SMC_REG_WRITE:
|
|
+ case STM32_SMC_REG_SET:
|
|
+ case STM32_SMC_REG_CLEAR:
|
|
+ break;
|
|
+ default:
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ switch (offset) {
|
|
+ case RCC_MP_APB5ENSETR:
|
|
+ clr_std_set = SET_REG;
|
|
+ /* Non secure backup registers requires RTCAPB clock */
|
|
+ enable_bits |= RCC_MP_APB5ENSETR_RTCAPBEN;
|
|
+ break;
|
|
+ case RCC_MP_APB5ENCLRR:
|
|
+ clr_std_set = CLR_REG;
|
|
+ /* Non secure backup registers requires RTCAPB clock */
|
|
+ enable_bits |= RCC_MP_APB5ENSETR_RTCAPBEN;
|
|
+ break;
|
|
+
|
|
+ case RCC_MP_AHB5ENSETR:
|
|
+ clr_std_set = SET_REG;
|
|
+ if (stm32mp_gpio_bank_is_shared(GPIO_BANK_Z)) {
|
|
+ enable_bits |= RCC_MP_AHB5ENSETR_GPIOZEN;
|
|
+ }
|
|
+ break;
|
|
+ case RCC_MP_AHB5ENCLRR:
|
|
+ clr_std_set = CLR_REG;
|
|
+ if (stm32mp_gpio_bank_is_shared(GPIO_BANK_Z)) {
|
|
+ enable_bits |= RCC_MP_AHB5ENSETR_GPIOZEN;
|
|
+ }
|
|
+ break;
|
|
+ default:
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ if ((clr_std_set != STD_REG) && (request == STM32_SMC_REG_CLEAR)) {
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * Parse bit that relate to a functional clock.
|
|
+ * Call stm32mp1_clk_enable/disable_non_secure() for that clock
|
|
+ * according to request (write/set/clear) and target register
|
|
+ * (write or set/clear).
|
|
+ */
|
|
+ for (bit = 0; bit < __WORD_BIT; bit++) {
|
|
+
|
|
+ if ((BIT(bit) & enable_bits) == 0U) {
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ id = stm32mp1_clk_rcc2id(offset, bit);
|
|
+ if (id == ~0U) {
|
|
+ panic();
|
|
+ }
|
|
+
|
|
+ switch (clr_std_set) {
|
|
+ case SET_REG:
|
|
+ if ((BIT(bit) & value) != 0U) {
|
|
+ stm32mp1_clk_enable_non_secure(id);
|
|
+ }
|
|
+ break;
|
|
+ case CLR_REG:
|
|
+ if ((BIT(bit) & value) != 0U) {
|
|
+ stm32mp1_clk_disable_non_secure(id);
|
|
+ }
|
|
+ break;
|
|
+ default:
|
|
+ /* Standard registers case */
|
|
+ switch (request) {
|
|
+ case STM32_SMC_REG_WRITE:
|
|
+ if ((BIT(bit) & value) != 0U) {
|
|
+ stm32mp1_clk_enable_non_secure(id);
|
|
+ } else {
|
|
+ stm32mp1_clk_disable_non_secure(id);
|
|
+ }
|
|
+ break;
|
|
+ case STM32_SMC_REG_SET:
|
|
+ if ((BIT(bit) & value) != 0U) {
|
|
+ stm32mp1_clk_enable_non_secure(id);
|
|
+ }
|
|
+ break;
|
|
+ case STM32_SMC_REG_CLEAR:
|
|
+ if ((BIT(bit) & value) != 0U) {
|
|
+ stm32mp1_clk_disable_non_secure(id);
|
|
+ }
|
|
+ break;
|
|
+ default:
|
|
+ return;
|
|
+ }
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ enable_bits &= ~BIT(bit);
|
|
+ if (enable_bits == 0U) {
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
+static void access_allowed_mask(uint32_t request, uint32_t offset,
|
|
+ uint32_t value, uint32_t allowed_mask)
|
|
+{
|
|
+ uint32_t addr = stm32mp_rcc_base() + offset;
|
|
+ uint32_t masked_value = value & allowed_mask;
|
|
+
|
|
+ switch (request) {
|
|
+ case STM32_SMC_REG_WRITE:
|
|
+ switch (offset) {
|
|
+ /* CLR registers show the SET state, not the CLR state */
|
|
+ case RCC_OCENCLRR:
|
|
+ case RCC_MP_SREQCLRR:
|
|
+ case RCC_APB5RSTCLRR:
|
|
+ case RCC_AHB5RSTCLRR:
|
|
+ case RCC_MP_APB5ENCLRR:
|
|
+ case RCC_MP_AHB5ENCLRR:
|
|
+ case RCC_MP_APB5LPENCLRR:
|
|
+ case RCC_MP_AHB5LPENCLRR:
|
|
+ case RCC_MP_IWDGFZCLRR:
|
|
+ mmio_write_32(addr, masked_value);
|
|
+ break;
|
|
+ default:
|
|
+ stm32mp_mmio_clrsetbits_32_shregs(addr, allowed_mask,
|
|
+ masked_value);
|
|
+ break;
|
|
+ }
|
|
+ VERBOSE("wrt 0x%x = 0x%x => 0x%x\n", offset, value,
|
|
+ mmio_read_32(addr));
|
|
+ break;
|
|
+
|
|
+ case STM32_SMC_REG_SET:
|
|
+ switch (offset) {
|
|
+ /* CLR registers show the SET state, not the CLR state */
|
|
+ case RCC_OCENCLRR:
|
|
+ case RCC_MP_SREQCLRR:
|
|
+ case RCC_APB5RSTCLRR:
|
|
+ case RCC_AHB5RSTCLRR:
|
|
+ case RCC_MP_APB5ENCLRR:
|
|
+ case RCC_MP_AHB5ENCLRR:
|
|
+ case RCC_MP_APB5LPENCLRR:
|
|
+ case RCC_MP_AHB5LPENCLRR:
|
|
+ case RCC_MP_IWDGFZCLRR:
|
|
+ mmio_write_32(addr, masked_value);
|
|
+ break;
|
|
+ default:
|
|
+ stm32mp_mmio_setbits_32_shregs(addr, masked_value);
|
|
+ break;
|
|
+ }
|
|
+ VERBOSE("set 0x%x = 0x%x => 0x%x\n", offset, value,
|
|
+ mmio_read_32(addr));
|
|
+ break;
|
|
+
|
|
+ case STM32_SMC_REG_CLEAR:
|
|
+ switch (offset) {
|
|
+ case RCC_OCENCLRR:
|
|
+ case RCC_MP_SREQCLRR:
|
|
+ case RCC_APB5RSTCLRR:
|
|
+ case RCC_AHB5RSTCLRR:
|
|
+ case RCC_MP_APB5ENCLRR:
|
|
+ case RCC_MP_AHB5ENCLRR:
|
|
+ case RCC_MP_APB5LPENCLRR:
|
|
+ case RCC_MP_AHB5LPENCLRR:
|
|
+ case RCC_MP_IWDGFZCLRR:
|
|
+ /* Nothing to do on CLR registers */
|
|
+ break;
|
|
+ default:
|
|
+ stm32mp_mmio_clrbits_32_shregs(addr, masked_value);
|
|
+ break;
|
|
+ }
|
|
+ VERBOSE("clear 0x%x = 0x%x => 0x%x\n", offset, value,
|
|
+ mmio_read_32(addr));
|
|
+ break;
|
|
+
|
|
+ default:
|
|
+ break;
|
|
+ }
|
|
+}
|
|
+
|
|
+static void raw_allowed_access_request(uint32_t request,
|
|
+ uint32_t offset, uint32_t value)
|
|
+{
|
|
+ uint32_t allowed_mask = 0;
|
|
+
|
|
+ /* Use UINT32_MAX if no secure restriction on register access */
|
|
+ switch (offset) {
|
|
+ case RCC_OCENSETR:
|
|
+ case RCC_OCENCLRR:
|
|
+ if (stm32mp1_periph_is_non_secure(STM32MP1_SHRES_HSI)) {
|
|
+ allowed_mask |= RCC_OCENR_HSION | RCC_OCENR_HSIKERON;
|
|
+ }
|
|
+ if (stm32mp1_periph_is_non_secure(STM32MP1_SHRES_CSI)) {
|
|
+ allowed_mask |= RCC_OCENR_CSION | RCC_OCENR_CSIKERON;
|
|
+ }
|
|
+ if (stm32mp1_periph_is_non_secure(STM32MP1_SHRES_HSE)) {
|
|
+ allowed_mask |= RCC_OCENR_HSEON | RCC_OCENR_HSEKERON |
|
|
+ RCC_OCENR_HSEBYP | RCC_OCENR_HSECSSON |
|
|
+ RCC_OCENR_DIGBYP;
|
|
+ }
|
|
+ break;
|
|
+
|
|
+ case RCC_HSICFGR:
|
|
+ if (stm32mp1_periph_is_non_secure(STM32MP1_SHRES_HSI)) {
|
|
+ allowed_mask = UINT32_MAX;
|
|
+ }
|
|
+ break;
|
|
+
|
|
+ case RCC_CSICFGR:
|
|
+ if (stm32mp1_periph_is_non_secure(STM32MP1_SHRES_CSI)) {
|
|
+ allowed_mask = UINT32_MAX;
|
|
+ }
|
|
+ break;
|
|
+
|
|
+ case RCC_MP_CIER:
|
|
+ case RCC_MP_CIFR:
|
|
+ /* RCC_MP_CIFR_xxxRDYF matches CIER and CIFR bit mapping */
|
|
+ allowed_mask |= RCC_MP_CIFR_WKUPF | RCC_MP_CIFR_PLL4DYF;
|
|
+
|
|
+ if (stm32mp1_periph_is_non_secure(STM32MP1_SHRES_LSI)) {
|
|
+ allowed_mask |= RCC_MP_CIFR_LSIRDYF;
|
|
+ }
|
|
+ if (stm32mp1_periph_is_non_secure(STM32MP1_SHRES_LSE)) {
|
|
+ allowed_mask |= RCC_MP_CIFR_LSERDYF;
|
|
+ }
|
|
+ if (stm32mp1_periph_is_non_secure(STM32MP1_SHRES_HSI)) {
|
|
+ allowed_mask |= RCC_MP_CIFR_HSIRDYF;
|
|
+ }
|
|
+ if (stm32mp1_periph_is_non_secure(STM32MP1_SHRES_HSE)) {
|
|
+ allowed_mask |= RCC_MP_CIFR_HSERDYF;
|
|
+ }
|
|
+ if (stm32mp1_periph_is_non_secure(STM32MP1_SHRES_CSI)) {
|
|
+ allowed_mask |= RCC_MP_CIFR_CSIRDYF;
|
|
+ }
|
|
+ if (stm32mp1_periph_is_non_secure(STM32MP1_SHRES_PLL1)) {
|
|
+ allowed_mask |= RCC_MP_CIFR_PLL1DYF;
|
|
+ }
|
|
+ if (stm32mp1_periph_is_non_secure(STM32MP1_SHRES_PLL2)) {
|
|
+ allowed_mask |= RCC_MP_CIFR_PLL2DYF;
|
|
+ }
|
|
+ if (stm32mp1_periph_is_non_secure(STM32MP1_SHRES_PLL3)) {
|
|
+ allowed_mask |= RCC_MP_CIFR_PLL3DYF;
|
|
+ }
|
|
+ break;
|
|
+
|
|
+ case RCC_PLL1CR:
|
|
+ if (stm32mp1_periph_is_non_secure(STM32MP1_SHRES_PLL1_P)) {
|
|
+ allowed_mask |= RCC_PLLNCR_DIVPEN;
|
|
+ }
|
|
+ if (stm32mp1_periph_is_non_secure(STM32MP1_SHRES_PLL1_Q)) {
|
|
+ allowed_mask |= RCC_PLLNCR_DIVQEN;
|
|
+ }
|
|
+ if (stm32mp1_periph_is_non_secure(STM32MP1_SHRES_PLL1_R)) {
|
|
+ allowed_mask |= RCC_PLLNCR_DIVREN;
|
|
+ }
|
|
+ if (stm32mp1_periph_is_non_secure(STM32MP1_SHRES_PLL1)) {
|
|
+ allowed_mask |= RCC_PLLNCR_PLLON | RCC_PLLNCR_PLLRDY |
|
|
+ RCC_PLLNCR_SSCG_CTRL;
|
|
+ }
|
|
+ break;
|
|
+
|
|
+ case RCC_PLL2CR:
|
|
+ if (stm32mp1_periph_is_non_secure(STM32MP1_SHRES_PLL2_P)) {
|
|
+ allowed_mask |= RCC_PLLNCR_DIVPEN;
|
|
+ }
|
|
+ if (stm32mp1_periph_is_non_secure(STM32MP1_SHRES_PLL2_Q)) {
|
|
+ allowed_mask |= RCC_PLLNCR_DIVQEN;
|
|
+ }
|
|
+ if (stm32mp1_periph_is_non_secure(STM32MP1_SHRES_PLL2_R)) {
|
|
+ allowed_mask |= RCC_PLLNCR_DIVREN;
|
|
+ }
|
|
+ if (stm32mp1_periph_is_non_secure(STM32MP1_SHRES_PLL2)) {
|
|
+ allowed_mask |= RCC_PLLNCR_PLLON | RCC_PLLNCR_PLLRDY |
|
|
+ RCC_PLLNCR_SSCG_CTRL;
|
|
+ }
|
|
+ break;
|
|
+
|
|
+ case RCC_PLL3CR:
|
|
+ if (stm32mp1_periph_is_non_secure(STM32MP1_SHRES_PLL3_P)) {
|
|
+ allowed_mask |= RCC_PLLNCR_DIVPEN;
|
|
+ }
|
|
+ if (stm32mp1_periph_is_non_secure(STM32MP1_SHRES_PLL3_Q)) {
|
|
+ allowed_mask |= RCC_PLLNCR_DIVQEN;
|
|
+ }
|
|
+ if (stm32mp1_periph_is_non_secure(STM32MP1_SHRES_PLL3_R)) {
|
|
+ allowed_mask |= RCC_PLLNCR_DIVREN;
|
|
+ }
|
|
+ if (stm32mp1_periph_is_non_secure(STM32MP1_SHRES_PLL3)) {
|
|
+ allowed_mask |= RCC_PLLNCR_PLLON | RCC_PLLNCR_PLLRDY |
|
|
+ RCC_PLLNCR_SSCG_CTRL;
|
|
+ }
|
|
+ break;
|
|
+
|
|
+ case RCC_MP_BOOTCR: /* Allowed MPU/MCU reboot cfg */
|
|
+ case RCC_MP_GCR: /* Allowed MPU/MCU reboot cfg */
|
|
+ case RCC_MP_GRSTCSETR: /* Allowed MCU and system reset */
|
|
+ case RCC_BR_RSTSCLRR: /* Allowed system reset status */
|
|
+ case RCC_MC_RSTSCLRR: /* Allowed system reset status */
|
|
+ case RCC_MP_RSTSCLRR: /* Allowed system reset status */
|
|
+ allowed_mask = UINT32_MAX;
|
|
+ break;
|
|
+ case RCC_APB5RSTSETR:
|
|
+ case RCC_APB5RSTCLRR:
|
|
+ case RCC_MP_APB5ENSETR:
|
|
+ case RCC_MP_APB5ENCLRR:
|
|
+ case RCC_MP_APB5LPENSETR:
|
|
+ case RCC_MP_APB5LPENCLRR:
|
|
+ /*
|
|
+ * SPI6/I2C4/I2C6/USART1/IWDG1 resources may be non secure.
|
|
+ * TZPC/TZC/BSEC/STGEN resources are secure only.
|
|
+ * Bit mask RCC_MP_APB5ENSETR_xxxEN fits EN, RST and LPEN.
|
|
+ */
|
|
+ if (stm32mp1_periph_is_non_secure(STM32MP1_SHRES_SPI6)) {
|
|
+ allowed_mask |= RCC_MP_APB5ENSETR_SPI6EN;
|
|
+ }
|
|
+ if (stm32mp1_periph_is_non_secure(STM32MP1_SHRES_I2C4)) {
|
|
+ allowed_mask |= RCC_MP_APB5ENSETR_I2C4EN;
|
|
+ }
|
|
+ if (stm32mp1_periph_is_non_secure(STM32MP1_SHRES_I2C6)) {
|
|
+ allowed_mask |= RCC_MP_APB5ENSETR_I2C6EN;
|
|
+ }
|
|
+ if (stm32mp1_periph_is_non_secure(STM32MP1_SHRES_USART1)) {
|
|
+ allowed_mask |= RCC_MP_APB5ENSETR_USART1EN;
|
|
+ }
|
|
+ if (stm32mp1_periph_is_non_secure(STM32MP1_SHRES_IWDG1)) {
|
|
+ allowed_mask |= RCC_MP_APB5ENSETR_IWDG1APBEN;
|
|
+ }
|
|
+ break;
|
|
+ case RCC_AHB5RSTSETR:
|
|
+ case RCC_AHB5RSTCLRR:
|
|
+ case RCC_MP_AHB5ENSETR:
|
|
+ case RCC_MP_AHB5ENCLRR:
|
|
+ case RCC_MP_AHB5LPENSETR:
|
|
+ case RCC_MP_AHB5LPENCLRR:
|
|
+ /*
|
|
+ * RNG1/HASH1/CRYP1/GPIOZ resources are accessible if
|
|
+ * related BKPSRAM resources are reserved to secure services.
|
|
+ * Bit mask RCC_MP_AHB5ENSETR_xxxEN fits EN, RST and LPEN.
|
|
+ */
|
|
+ if (stm32mp_gpio_bank_is_non_secure(GPIO_BANK_Z)) {
|
|
+ allowed_mask |= RCC_MP_AHB5ENSETR_GPIOZEN;
|
|
+ }
|
|
+ if (stm32mp1_periph_is_non_secure(STM32MP1_SHRES_CRYP1)) {
|
|
+ allowed_mask |= RCC_MP_AHB5ENSETR_CRYP1EN;
|
|
+ }
|
|
+ if (stm32mp1_periph_is_non_secure(STM32MP1_SHRES_HASH1)) {
|
|
+ allowed_mask |= RCC_MP_AHB5ENSETR_HASH1EN;
|
|
+ }
|
|
+ if (stm32mp1_periph_is_non_secure(STM32MP1_SHRES_RNG1)) {
|
|
+ allowed_mask |= RCC_MP_AHB5ENSETR_RNG1EN;
|
|
+ }
|
|
+ break;
|
|
+ case RCC_RTCDIVR:
|
|
+ if (stm32mp1_periph_is_non_secure(STM32MP1_SHRES_RTC)) {
|
|
+ allowed_mask = UINT32_MAX;
|
|
+ }
|
|
+ break;
|
|
+ case RCC_I2C46CKSELR:
|
|
+ if (stm32mp1_periph_is_non_secure(STM32MP1_SHRES_I2C4) &&
|
|
+ stm32mp1_periph_is_non_secure(STM32MP1_SHRES_I2C6)) {
|
|
+ allowed_mask = UINT32_MAX;
|
|
+ }
|
|
+ break;
|
|
+ case RCC_SPI6CKSELR:
|
|
+ if (stm32mp1_periph_is_non_secure(STM32MP1_SHRES_SPI6)) {
|
|
+ allowed_mask = UINT32_MAX;
|
|
+ }
|
|
+ break;
|
|
+ case RCC_UART1CKSELR:
|
|
+ if (stm32mp1_periph_is_non_secure(STM32MP1_SHRES_USART1)) {
|
|
+ allowed_mask = UINT32_MAX;
|
|
+ }
|
|
+ break;
|
|
+ case RCC_RNG1CKSELR:
|
|
+ if (stm32mp1_periph_is_non_secure(STM32MP1_SHRES_RNG1)) {
|
|
+ allowed_mask = UINT32_MAX;
|
|
+ }
|
|
+ break;
|
|
+ case RCC_MP_IWDGFZSETR:
|
|
+ case RCC_MP_IWDGFZCLRR:
|
|
+ if (stm32mp1_periph_is_non_secure(STM32MP1_SHRES_IWDG1)) {
|
|
+ allowed_mask |= RCC_MP_IWDGFZSETR_IWDG1;
|
|
+ }
|
|
+ allowed_mask |= RCC_MP_IWDGFZSETR_IWDG2;
|
|
+ break;
|
|
+ default:
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ if (allowed_mask != 0U) {
|
|
+ access_allowed_mask(request, offset, value, allowed_mask);
|
|
+ }
|
|
+}
|
|
+
|
|
+uint32_t rcc_scv_handler(uint32_t x1, uint32_t x2, uint32_t x3)
|
|
+{
|
|
+ uint32_t request = x1;
|
|
+ uint32_t offset = x2;
|
|
+ uint32_t value = x3;
|
|
+
|
|
+ /*
|
|
+ * x2 may be either the RCC register offset or the register
|
|
+ * full physical address.
|
|
+ */
|
|
+ if ((offset & ~RCC_OFFSET_MASK) != 0) {
|
|
+ if ((offset & ~RCC_OFFSET_MASK) != stm32mp_rcc_base()) {
|
|
+ return STM32_SMC_INVALID_PARAMS;
|
|
+ }
|
|
+
|
|
+ offset &= RCC_OFFSET_MASK;
|
|
+ }
|
|
+
|
|
+ /* Some clocks may be managed by some secure services */
|
|
+ shared_clk_request(request, offset, value);
|
|
+
|
|
+ /* RCC controls for non secure resource may be accessed straight */
|
|
+ raw_allowed_access_request(request, offset, value);
|
|
+
|
|
+ return STM32_SMC_OK;
|
|
+}
|
|
+
|
|
+uint32_t rcc_cal_scv_handler(uint32_t x1)
|
|
+{
|
|
+ uint32_t ret = STM32_SMC_FAILED;
|
|
+
|
|
+ switch (x1) {
|
|
+ case CK_CSI:
|
|
+ if (stm32mp1_rcc_start_csi_cal() == 0) {
|
|
+ ret = STM32_SMC_OK;
|
|
+ }
|
|
+ break;
|
|
+
|
|
+ case CK_HSI:
|
|
+ if (stm32mp1_rcc_start_hsi_cal() == 0) {
|
|
+ ret = STM32_SMC_OK;
|
|
+ }
|
|
+ break;
|
|
+
|
|
+ default:
|
|
+ ret = STM32_SMC_INVALID_PARAMS;
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ return ret;
|
|
+}
|
|
diff --git a/plat/st/stm32mp1/services/rcc_svc.h b/plat/st/stm32mp1/services/rcc_svc.h
|
|
new file mode 100644
|
|
index 0000000..75d4a3c
|
|
--- /dev/null
|
|
+++ b/plat/st/stm32mp1/services/rcc_svc.h
|
|
@@ -0,0 +1,14 @@
|
|
+/*
|
|
+ * Copyright (c) 2017, STMicroelectronics - All Rights Reserved
|
|
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
|
|
+ *
|
|
+ * SPDX-License-Identifier: BSD-3-Clause
|
|
+ */
|
|
+
|
|
+#ifndef RCC_SVC_H
|
|
+#define RCC_SVC_H
|
|
+
|
|
+uint32_t rcc_scv_handler(uint32_t x1, uint32_t x2, uint32_t x3);
|
|
+uint32_t rcc_cal_scv_handler(uint32_t x1);
|
|
+
|
|
+#endif /* RCC_SVC_H */
|
|
diff --git a/plat/st/stm32mp1/services/stm32mp1_svc_setup.c b/plat/st/stm32mp1/services/stm32mp1_svc_setup.c
|
|
new file mode 100644
|
|
index 0000000..fff91c0
|
|
--- /dev/null
|
|
+++ b/plat/st/stm32mp1/services/stm32mp1_svc_setup.c
|
|
@@ -0,0 +1,113 @@
|
|
+/*
|
|
+ * Copyright (c) 2014-2018, STMicroelectronics - All Rights Reserved
|
|
+ * Copyright (c) 2014, ARM Limited and Contributors. All rights reserved.
|
|
+ *
|
|
+ * SPDX-License-Identifier: BSD-3-Clause
|
|
+ */
|
|
+
|
|
+#include <debug.h>
|
|
+#include <psci.h>
|
|
+#include <runtime_svc.h>
|
|
+#include <stm32mp1_smc.h>
|
|
+#include <stdbool.h>
|
|
+#include <stdint.h>
|
|
+#include <uuid.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,
|
|
+ 0xa778aa50, 0xf49b, 0x144a, 0x8a, 0x5e,
|
|
+ 0x26, 0x4d, 0x59, 0x94, 0xc2, 0x14);
|
|
+
|
|
+/* Setup STM32MP1 Standard Services */
|
|
+static int32_t stm32mp1_svc_setup(void)
|
|
+{
|
|
+ /*
|
|
+ * PSCI is the only specification implemented as a Standard Service.
|
|
+ * Invoke PSCI setup from here.
|
|
+ */
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * Top-level Standard Service SMC handler. This handler will in turn dispatch
|
|
+ * calls to PSCI SMC handler.
|
|
+ */
|
|
+static uintptr_t stm32mp1_svc_smc_handler(uint32_t smc_fid, u_register_t x1,
|
|
+ u_register_t x2, u_register_t x3,
|
|
+ u_register_t x4, void *cookie,
|
|
+ void *handle, u_register_t flags)
|
|
+{
|
|
+ uint32_t ret1 = 0U, ret2 = 0U;
|
|
+ bool ret_uid = false, ret2_enabled = false;
|
|
+
|
|
+ switch (smc_fid) {
|
|
+ case STM32_SIP_SVC_CALL_COUNT:
|
|
+ ret1 = STM32_COMMON_SIP_NUM_CALLS;
|
|
+ break;
|
|
+
|
|
+ case STM32_SIP_SVC_UID:
|
|
+ /* Return UUID to the caller */
|
|
+ ret_uid = true;
|
|
+ break;
|
|
+
|
|
+ case STM32_SIP_SVC_VERSION:
|
|
+ /* Return the version of current implementation */
|
|
+ ret1 = STM32_SIP_SVC_VERSION_MAJOR;
|
|
+ ret2 = STM32_SIP_SVC_VERSION_MINOR;
|
|
+ ret2_enabled = true;
|
|
+ break;
|
|
+
|
|
+ case STM32_SMC_BSEC:
|
|
+ ret1 = bsec_main(x1, x2, x3, &ret2);
|
|
+ ret2_enabled = true;
|
|
+ break;
|
|
+
|
|
+ case STM32_SMC_RCC:
|
|
+ ret1 = rcc_scv_handler(x1, x2, x3);
|
|
+ break;
|
|
+
|
|
+ case STM32_SMC_RCC_CAL:
|
|
+ ret1 = rcc_cal_scv_handler(x1);
|
|
+ break;
|
|
+
|
|
+ case STM32_SMC_PWR:
|
|
+ ret1 = pwr_scv_handler(x1, x2, x3);
|
|
+ break;
|
|
+
|
|
+ case STM32_SMC_SR_MODE:
|
|
+ ret1 = sr_mode_scv_handler(x1, x2);
|
|
+ break;
|
|
+
|
|
+ case STM32_SMC_PD_DOMAIN:
|
|
+ ret1 = pm_domain_scv_handler(x1, x2);
|
|
+ break;
|
|
+
|
|
+ default:
|
|
+ WARN("Unimplemented STM32MP1 Service Call: 0x%x\n", smc_fid);
|
|
+ ret1 = SMC_UNK;
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ if (ret_uid) {
|
|
+ SMC_UUID_RET(handle, stm32_sip_svc_uid);
|
|
+ }
|
|
+
|
|
+ if (ret2_enabled) {
|
|
+ SMC_RET2(handle, ret1, ret2);
|
|
+ }
|
|
+
|
|
+ SMC_RET1(handle, ret1);
|
|
+}
|
|
+
|
|
+/* Register Standard Service Calls as runtime service */
|
|
+DECLARE_RT_SVC(stm32mp1_sip_svc,
|
|
+ OEN_SIP_START,
|
|
+ OEN_SIP_END,
|
|
+ SMC_TYPE_FAST,
|
|
+ stm32mp1_svc_setup,
|
|
+ stm32mp1_svc_smc_handler
|
|
+);
|
|
diff --git a/plat/st/stm32mp1/sp_min/sp_min-stm32mp1.mk b/plat/st/stm32mp1/sp_min/sp_min-stm32mp1.mk
|
|
index 9fde153..322d389 100644
|
|
--- a/plat/st/stm32mp1/sp_min/sp_min-stm32mp1.mk
|
|
+++ b/plat/st/stm32mp1/sp_min/sp_min-stm32mp1.mk
|
|
@@ -7,8 +7,15 @@
|
|
SP_MIN_WITH_SECURE_FIQ := 1
|
|
|
|
BL32_SOURCES += plat/common/aarch32/platform_mp_stack.S \
|
|
+ drivers/st/etzpc/etzpc.c \
|
|
+ drivers/st/rng/stm32_rng.c \
|
|
+ drivers/st/rtc/stm32_rtc.c \
|
|
+ drivers/st/tamper/stm32_tamp.c \
|
|
+ drivers/st/timer/stm32_timer.c \
|
|
plat/st/stm32mp1/sp_min/sp_min_setup.c \
|
|
+ plat/st/stm32mp1/stm32mp1_low_power.c \
|
|
plat/st/stm32mp1/stm32mp1_pm.c \
|
|
+ plat/st/stm32mp1/stm32mp1_power_config.c \
|
|
plat/st/stm32mp1/stm32mp1_topology.c
|
|
# Generic GIC v2
|
|
BL32_SOURCES += drivers/arm/gic/common/gic_common.c \
|
|
@@ -19,3 +26,10 @@ BL32_SOURCES += drivers/arm/gic/common/gic_common.c \
|
|
|
|
# Generic PSCI
|
|
BL32_SOURCES += plat/common/plat_psci_common.c
|
|
+
|
|
+# stm32mp1 specific services
|
|
+BL32_SOURCES += plat/st/stm32mp1/services/bsec_svc.c \
|
|
+ plat/st/stm32mp1/services/low_power_svc.c \
|
|
+ plat/st/stm32mp1/services/pwr_svc.c \
|
|
+ plat/st/stm32mp1/services/rcc_svc.c \
|
|
+ plat/st/stm32mp1/services/stm32mp1_svc_setup.c
|
|
diff --git a/plat/st/stm32mp1/sp_min/sp_min_setup.c b/plat/st/stm32mp1/sp_min/sp_min_setup.c
|
|
index 56598c8..e8dc409 100644
|
|
--- a/plat/st/stm32mp1/sp_min/sp_min_setup.c
|
|
+++ b/plat/st/stm32mp1/sp_min/sp_min_setup.c
|
|
@@ -7,19 +7,32 @@
|
|
#include <arch_helpers.h>
|
|
#include <assert.h>
|
|
#include <bl_common.h>
|
|
-#include <console.h>
|
|
+#include <bsec.h>
|
|
#include <context.h>
|
|
#include <context_mgmt.h>
|
|
#include <debug.h>
|
|
#include <dt-bindings/clock/stm32mp1-clks.h>
|
|
+#include <etzpc.h>
|
|
#include <generic_delay_timer.h>
|
|
+#include <gicv2.h>
|
|
#include <mmio.h>
|
|
#include <platform.h>
|
|
#include <platform_def.h>
|
|
#include <platform_sp_min.h>
|
|
+#include <stm32_console.h>
|
|
+#include <stm32_gpio.h>
|
|
+#include <stm32_iwdg.h>
|
|
+#include <stm32_rng.h>
|
|
+#include <stm32_rtc.h>
|
|
+#include <stm32_tamp.h>
|
|
+#include <stm32_timer.h>
|
|
+#include <stm32mp_dt.h>
|
|
+#include <stm32mp_pmic.h>
|
|
#include <stm32mp1_clk.h>
|
|
-#include <stm32mp1_dt.h>
|
|
+#include <stm32mp1_context.h>
|
|
+#include <stm32mp1_power_config.h>
|
|
#include <stm32mp1_private.h>
|
|
+#include <stm32mp1_shared_resources.h>
|
|
#include <string.h>
|
|
#include <tzc400.h>
|
|
#include <xlat_tables_v2.h>
|
|
@@ -30,22 +43,107 @@
|
|
******************************************************************************/
|
|
static entry_point_info_t bl33_image_ep_info;
|
|
|
|
+static struct console_stm32 console;
|
|
+
|
|
+static struct stm32_tamp_int int_tamp[PLAT_MAX_TAMP_INT] = {
|
|
+ TAMP_UNUSED,
|
|
+ TAMP_UNUSED,
|
|
+ TAMP_UNUSED,
|
|
+ TAMP_UNUSED,
|
|
+ TAMP_UNUSED,
|
|
+};
|
|
+
|
|
+static struct stm32_tamp_ext ext_tamp[PLAT_MAX_TAMP_EXT] = {
|
|
+ TAMP_UNUSED,
|
|
+ TAMP_UNUSED,
|
|
+ TAMP_UNUSED,
|
|
+};
|
|
+
|
|
+static void tzc_it_handler(void)
|
|
+{
|
|
+ ERROR("No IT handler in ARM tzc400 driver\n");
|
|
+}
|
|
+
|
|
+static void stm32_sgi1_it_handler(void)
|
|
+{
|
|
+ uint32_t id;
|
|
+
|
|
+ gicv2_end_of_interrupt(ARM_IRQ_SEC_SGI_1);
|
|
+
|
|
+ do {
|
|
+ id = plat_ic_get_pending_interrupt_id();
|
|
+
|
|
+ if (id <= MAX_SPI_ID) {
|
|
+ gicv2_end_of_interrupt(id);
|
|
+
|
|
+ plat_ic_disable_interrupt(id);
|
|
+ }
|
|
+ } while (id <= MAX_SPI_ID);
|
|
+
|
|
+
|
|
+ isb();
|
|
+ dsb();
|
|
+
|
|
+ /* Flush L1/L2 data caches */
|
|
+ write_sctlr(read_sctlr() & ~SCTLR_C_BIT);
|
|
+ dcsw_op_all(DC_OP_CISW);
|
|
+
|
|
+ for ( ; ; ) {
|
|
+ wfi();
|
|
+ }
|
|
+}
|
|
+
|
|
/*******************************************************************************
|
|
* Interrupt handler for FIQ (secure IRQ)
|
|
******************************************************************************/
|
|
void sp_min_plat_fiq_handler(uint32_t id)
|
|
{
|
|
- switch (id) {
|
|
+ uint32_t value = 0;
|
|
+
|
|
+ switch (id & INT_ID_MASK) {
|
|
+ case ARM_IRQ_SEC_PHY_TIMER:
|
|
+ case STM32MP1_IRQ_MCU_SEV:
|
|
+ case STM32MP1_IRQ_RCC_WAKEUP:
|
|
+ stm32mp1_rcc_it_handler(id);
|
|
+ break;
|
|
case STM32MP1_IRQ_TZC400:
|
|
- ERROR("STM32MP1_IRQ_TZC400 generated\n");
|
|
+ tzc400_init(STM32MP1_TZC_BASE);
|
|
+ tzc400_it_handler();
|
|
panic();
|
|
break;
|
|
+ case STM32MP1_IRQ_TAMPSERRS:
|
|
+ stm32_tamp_it_handler();
|
|
+ break;
|
|
+ case ARM_IRQ_SEC_SGI_1:
|
|
+ stm32_sgi1_it_handler();
|
|
+ break;
|
|
+ case STM32MP1_IRQ_IWDG1:
|
|
+ case STM32MP1_IRQ_IWDG2:
|
|
+ stm32_iwdg_it_handler(id);
|
|
+ break;
|
|
case STM32MP1_IRQ_AXIERRIRQ:
|
|
ERROR("STM32MP1_IRQ_AXIERRIRQ generated\n");
|
|
+ tzc400_init(STM32MP1_TZC_BASE);
|
|
+ __asm__("mrc p15, 1, %0, c9, c0, 3" : "=r" (value));
|
|
+ if (value) {
|
|
+ /* we have a pending IT clear it */
|
|
+ value = 0;
|
|
+ __asm__("mcr p15, 1, %0, c9, c0, 3" :: "r" (value));
|
|
+ } else {
|
|
+ ERROR("IRQ_AXIERRIRQ handle call w/o any flag set!!\n");
|
|
+ }
|
|
+
|
|
+ /* Check if FIQ has been generated due to TZC400 abort*/
|
|
+ if (tzc400_is_pending_interrupt()) {
|
|
+ tzc_it_handler();
|
|
+ } else {
|
|
+ ERROR("IRQ_AXIERRIRQ cause can't be detected");
|
|
+ }
|
|
+
|
|
panic();
|
|
break;
|
|
default:
|
|
- ERROR("SECURE IT handler not define for it : %i", id);
|
|
+ ERROR("SECURE IT handler not define for it : %u", id);
|
|
break;
|
|
}
|
|
}
|
|
@@ -59,11 +157,54 @@ void sp_min_plat_fiq_handler(uint32_t id)
|
|
entry_point_info_t *sp_min_plat_get_bl33_ep_info(void)
|
|
{
|
|
entry_point_info_t *next_image_info;
|
|
+ uint32_t bkpr_core1_addr =
|
|
+ tamp_bkpr(BOOT_API_CORE1_BRANCH_ADDRESS_TAMP_BCK_REG_IDX);
|
|
+ uint32_t bkpr_core1_magic =
|
|
+ tamp_bkpr(BOOT_API_CORE1_MAGIC_NUMBER_TAMP_BCK_REG_IDX);
|
|
|
|
next_image_info = &bl33_image_ep_info;
|
|
|
|
+ /*
|
|
+ * PC is set to 0 when resetting after STANDBY
|
|
+ * The context should be restored, and the image information
|
|
+ * should be filled with what what was saved
|
|
+ */
|
|
if (next_image_info->pc == 0U) {
|
|
- return NULL;
|
|
+ void *cpu_context;
|
|
+ uint32_t magic_nb, saved_pc;
|
|
+
|
|
+ stm32mp_clk_enable(RTCAPB);
|
|
+
|
|
+ magic_nb = mmio_read_32(bkpr_core1_magic);
|
|
+ saved_pc = mmio_read_32(bkpr_core1_addr);
|
|
+
|
|
+ stm32mp_clk_disable(RTCAPB);
|
|
+
|
|
+ if (stm32_restore_context() != 0) {
|
|
+ panic();
|
|
+ }
|
|
+
|
|
+ cpu_context = cm_get_context(NON_SECURE);
|
|
+
|
|
+ next_image_info->spsr = read_ctx_reg(get_regs_ctx(cpu_context),
|
|
+ CTX_SPSR);
|
|
+
|
|
+ /* PC should be retrieved in backup register if OK, else it can
|
|
+ * be retrieved from non-secure context
|
|
+ */
|
|
+ if (magic_nb == BOOT_API_A7_CORE0_MAGIC_NUMBER) {
|
|
+ /* BL33 return address should be in DDR */
|
|
+ if ((saved_pc < STM32MP_DDR_BASE) ||
|
|
+ (saved_pc > (STM32MP_DDR_BASE +
|
|
+ (dt_get_ddr_size() - 1U)))) {
|
|
+ panic();
|
|
+ }
|
|
+
|
|
+ next_image_info->pc = saved_pc;
|
|
+ } else {
|
|
+ next_image_info->pc =
|
|
+ read_ctx_reg(get_regs_ctx(cpu_context), CTX_LR);
|
|
+ }
|
|
}
|
|
|
|
return next_image_info;
|
|
@@ -75,6 +216,9 @@ entry_point_info_t *sp_min_plat_get_bl33_ep_info(void)
|
|
void sp_min_early_platform_setup2(u_register_t arg0, u_register_t arg1,
|
|
u_register_t arg2, u_register_t arg3)
|
|
{
|
|
+#if STM32MP_UART_PROGRAMMER
|
|
+ uint32_t boot_itf, boot_instance;
|
|
+#endif
|
|
struct dt_node_info dt_dev_info;
|
|
int result;
|
|
bl_params_t *params_from_bl2 = (bl_params_t *)arg0;
|
|
@@ -105,18 +249,78 @@ void sp_min_early_platform_setup2(u_register_t arg0, u_register_t arg1,
|
|
panic();
|
|
}
|
|
|
|
+ if (bsec_probe() != 0) {
|
|
+ panic();
|
|
+ }
|
|
+
|
|
if (stm32mp1_clk_probe() < 0) {
|
|
panic();
|
|
}
|
|
|
|
+ /* Initialize uart for console except if it is used by programmer */
|
|
result = dt_get_stdout_uart_info(&dt_dev_info);
|
|
+#if STM32MP_UART_PROGRAMMER
|
|
+ stm32_get_boot_interface(&boot_itf, &boot_instance);
|
|
|
|
+ if ((result > 0) && dt_dev_info.status &&
|
|
+ !((boot_itf == BOOT_API_CTX_BOOT_INTERFACE_SEL_SERIAL_UART) &&
|
|
+ (get_uart_address(boot_instance) == dt_dev_info.base))) {
|
|
+#else
|
|
if ((result > 0) && dt_dev_info.status) {
|
|
- if (console_init(dt_dev_info.base, 0, STM32MP1_UART_BAUDRATE)
|
|
- == 0) {
|
|
+#endif
|
|
+ if (console_stm32_register(dt_dev_info.base, 0,
|
|
+ STM32MP_UART_BAUDRATE, &console) ==
|
|
+ 0) {
|
|
panic();
|
|
}
|
|
}
|
|
+
|
|
+ if (dt_pmic_status() > 0) {
|
|
+ initialize_pmic();
|
|
+ }
|
|
+
|
|
+ stm32mp1_init_lp_states();
|
|
+}
|
|
+
|
|
+/*******************************************************************************
|
|
+ * Set security setup in sp_min
|
|
+ ******************************************************************************/
|
|
+void stm32mp1_sp_min_security_setup(void)
|
|
+{
|
|
+ uint32_t filter_conf = 0;
|
|
+ uint32_t active_conf = 0;
|
|
+ int ret;
|
|
+
|
|
+ if (etzpc_init() != 0) {
|
|
+ ERROR("ETZPC configuration issue\n");
|
|
+ panic();
|
|
+ }
|
|
+
|
|
+ /* Init rtc driver */
|
|
+ ret = stm32_rtc_init();
|
|
+ if (ret < 0) {
|
|
+ WARN("RTC driver init error %i\n", ret);
|
|
+ }
|
|
+
|
|
+ /* Init rng driver */
|
|
+ ret = stm32_rng_init();
|
|
+ if (ret < 0) {
|
|
+ WARN("RNG driver init error %i\n", ret);
|
|
+ }
|
|
+
|
|
+ /* Init tamper */
|
|
+ if (stm32_tamp_init() > 0) {
|
|
+ stm32_tamp_configure_internal(int_tamp, PLAT_MAX_TAMP_INT);
|
|
+ stm32_tamp_configure_external(ext_tamp, PLAT_MAX_TAMP_EXT,
|
|
+ filter_conf, active_conf);
|
|
+
|
|
+ /* Enable timestamp for tamper */
|
|
+ stm32_rtc_set_tamper_timestamp();
|
|
+ }
|
|
+
|
|
+ if (stm32_timer_init() == 0) {
|
|
+ stm32mp1_cal_init();
|
|
+ }
|
|
}
|
|
|
|
/*******************************************************************************
|
|
@@ -128,6 +332,16 @@ void sp_min_platform_setup(void)
|
|
BL_CODE_END - BL_CODE_BASE,
|
|
MT_CODE | MT_SECURE);
|
|
|
|
+#if SEPARATE_CODE_AND_RODATA
|
|
+ mmap_add_region(BL_RO_DATA_BASE, BL_RO_DATA_BASE,
|
|
+ BL_RO_DATA_LIMIT - BL_RO_DATA_BASE,
|
|
+ MT_RO_DATA | MT_SECURE);
|
|
+#endif
|
|
+
|
|
+ mmap_add_region(STM32MP_DDR_BASE, STM32MP_DDR_BASE,
|
|
+ dt_get_ddr_size() - STM32MP_DDR_S_SIZE,
|
|
+ MT_MEMORY | MT_RW | MT_NS);
|
|
+
|
|
configure_mmu();
|
|
|
|
/* Initialize tzc400 after DDR initialization */
|
|
@@ -136,8 +350,21 @@ void sp_min_platform_setup(void)
|
|
generic_delay_timer_init();
|
|
|
|
stm32mp1_gic_init();
|
|
+
|
|
+ /* Update security settings */
|
|
+ stm32mp1_sp_min_security_setup();
|
|
+
|
|
+ if (stm32_iwdg_init() < 0) {
|
|
+ panic();
|
|
+ }
|
|
+
|
|
+ stm32mp1_driver_init_late();
|
|
}
|
|
|
|
void sp_min_plat_arch_setup(void)
|
|
{
|
|
}
|
|
+
|
|
+void sp_min_plat_runtime_setup(void)
|
|
+{
|
|
+}
|
|
diff --git a/plat/st/stm32mp1/stm32mp1.ld.S b/plat/st/stm32mp1/stm32mp1.ld.S
|
|
index 0d7a8bb..a9cc26b 100644
|
|
--- a/plat/st/stm32mp1/stm32mp1.ld.S
|
|
+++ b/plat/st/stm32mp1/stm32mp1.ld.S
|
|
@@ -4,8 +4,9 @@
|
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
*/
|
|
|
|
-#ifndef __STM32MP1_LD_S__
|
|
-#define __STM32MP1_LD_S__
|
|
+#ifndef STM32MP1_LD_S
|
|
+#define STM32MP1_LD_S
|
|
+
|
|
#include <platform_def.h>
|
|
#include <xlat_tables_defs.h>
|
|
|
|
@@ -16,7 +17,7 @@ ENTRY(__BL2_IMAGE_START__)
|
|
|
|
MEMORY {
|
|
HEADER (rw) : ORIGIN = 0x00000000, LENGTH = 0x3000
|
|
- RAM (rwx) : ORIGIN = STM32MP1_BINARY_BASE, LENGTH = STM32MP1_BINARY_SIZE
|
|
+ RAM (rwx) : ORIGIN = STM32MP_BINARY_BASE, LENGTH = STM32MP_BINARY_SIZE
|
|
}
|
|
|
|
SECTIONS
|
|
@@ -31,7 +32,7 @@ SECTIONS
|
|
__HEADER_END__ = .;
|
|
} >HEADER
|
|
|
|
- . = STM32MP1_BINARY_BASE;
|
|
+ . = STM32MP_BINARY_BASE;
|
|
.data . : {
|
|
. = ALIGN(PAGE_SIZE);
|
|
__DATA_START__ = .;
|
|
@@ -42,7 +43,7 @@ SECTIONS
|
|
* The strongest and only alignment contraint is MMU 4K page.
|
|
* Indeed as images below will be removed, 4K pages will be re-used.
|
|
*/
|
|
- . = ( STM32MP1_DTB_BASE - STM32MP1_BINARY_BASE );
|
|
+ . = ( STM32MP_DTB_BASE - STM32MP_BINARY_BASE );
|
|
__DTB_IMAGE_START__ = .;
|
|
*(.dtb_image*)
|
|
__DTB_IMAGE_END__ = .;
|
|
@@ -52,20 +53,22 @@ SECTIONS
|
|
* The strongest and only alignment contraint is MMU 4K page.
|
|
* Indeed as images below will be removed, 4K pages will be re-used.
|
|
*/
|
|
- . = ( STM32MP1_BL2_BASE - STM32MP1_BINARY_BASE );
|
|
+ . = ( STM32MP_BL2_BASE - STM32MP_BINARY_BASE );
|
|
__BL2_IMAGE_START__ = .;
|
|
*(.bl2_image*)
|
|
__BL2_IMAGE_END__ = .;
|
|
|
|
+#ifndef AARCH32_SP_OPTEE
|
|
/*
|
|
* bl32 will be settled by bl2.
|
|
* The strongest and only alignment constraint is 8 words to simplify
|
|
* memraise8 assembly code.
|
|
*/
|
|
- . = ( STM32MP1_BL32_BASE - STM32MP1_BINARY_BASE );
|
|
+ . = ( STM32MP_BL32_BASE - STM32MP_BINARY_BASE );
|
|
__BL32_IMAGE_START__ = .;
|
|
*(.bl32_image*)
|
|
__BL32_IMAGE_END__ = .;
|
|
+#endif
|
|
|
|
__DATA_END__ = .;
|
|
} >RAM
|
|
@@ -73,4 +76,4 @@ SECTIONS
|
|
__TF_END__ = .;
|
|
|
|
}
|
|
-#endif /*__STM32MP1_LD_S__*/
|
|
+#endif /* STM32MP1_LD_S */
|
|
diff --git a/plat/st/stm32mp1/stm32mp1_common.c b/plat/st/stm32mp1/stm32mp1_common.c
|
|
deleted file mode 100644
|
|
index 7d84da1..0000000
|
|
--- a/plat/st/stm32mp1/stm32mp1_common.c
|
|
+++ /dev/null
|
|
@@ -1,101 +0,0 @@
|
|
-/*
|
|
- * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
|
|
- *
|
|
- * SPDX-License-Identifier: BSD-3-Clause
|
|
- */
|
|
-
|
|
-#include <arch_helpers.h>
|
|
-#include <assert.h>
|
|
-#include <bl_common.h>
|
|
-#include <debug.h>
|
|
-#include <gicv2.h>
|
|
-#include <mmio.h>
|
|
-#include <platform_def.h>
|
|
-#include <platform.h>
|
|
-#include <stm32mp1_private.h>
|
|
-#include <xlat_tables_v2.h>
|
|
-
|
|
-#define MAP_SRAM MAP_REGION_FLAT(STM32MP1_SRAM_BASE, \
|
|
- STM32MP1_SRAM_SIZE, \
|
|
- MT_MEMORY | \
|
|
- MT_RW | \
|
|
- MT_SECURE | \
|
|
- MT_EXECUTE_NEVER)
|
|
-
|
|
-#define MAP_DEVICE1 MAP_REGION_FLAT(STM32MP1_DEVICE1_BASE, \
|
|
- STM32MP1_DEVICE1_SIZE, \
|
|
- MT_DEVICE | \
|
|
- MT_RW | \
|
|
- MT_SECURE | \
|
|
- MT_EXECUTE_NEVER)
|
|
-
|
|
-#define MAP_DEVICE2 MAP_REGION_FLAT(STM32MP1_DEVICE2_BASE, \
|
|
- STM32MP1_DEVICE2_SIZE, \
|
|
- MT_DEVICE | \
|
|
- MT_RW | \
|
|
- MT_SECURE | \
|
|
- MT_EXECUTE_NEVER)
|
|
-
|
|
-#define MAP_DDR MAP_REGION_FLAT(STM32MP1_DDR_BASE, \
|
|
- STM32MP1_DDR_MAX_SIZE, \
|
|
- MT_MEMORY | \
|
|
- MT_RW | \
|
|
- MT_SECURE | \
|
|
- MT_EXECUTE_NEVER)
|
|
-
|
|
-#define MAP_DDR_NS MAP_REGION_FLAT(STM32MP1_DDR_BASE, \
|
|
- STM32MP1_DDR_MAX_SIZE, \
|
|
- MT_MEMORY | \
|
|
- MT_RW | \
|
|
- MT_NS | \
|
|
- MT_EXECUTE_NEVER)
|
|
-
|
|
-#if defined(IMAGE_BL2)
|
|
-static const mmap_region_t stm32mp1_mmap[] = {
|
|
- MAP_SRAM,
|
|
- MAP_DEVICE1,
|
|
- MAP_DEVICE2,
|
|
- MAP_DDR,
|
|
- {0}
|
|
-};
|
|
-#endif
|
|
-#if defined(IMAGE_BL32)
|
|
-static const mmap_region_t stm32mp1_mmap[] = {
|
|
- MAP_SRAM,
|
|
- MAP_DEVICE1,
|
|
- MAP_DEVICE2,
|
|
- MAP_DDR_NS,
|
|
- {0}
|
|
-};
|
|
-#endif
|
|
-
|
|
-void configure_mmu(void)
|
|
-{
|
|
- mmap_add(stm32mp1_mmap);
|
|
- init_xlat_tables();
|
|
-
|
|
- enable_mmu_svc_mon(0);
|
|
-}
|
|
-
|
|
-uintptr_t plat_get_ns_image_entrypoint(void)
|
|
-{
|
|
- return BL33_BASE;
|
|
-}
|
|
-
|
|
-unsigned int plat_get_syscnt_freq2(void)
|
|
-{
|
|
- return read_cntfrq_el0();
|
|
-}
|
|
-
|
|
-/* Functions to save and get boot context address given by ROM code */
|
|
-static uintptr_t boot_ctx_address;
|
|
-
|
|
-void stm32mp1_save_boot_ctx_address(uintptr_t address)
|
|
-{
|
|
- boot_ctx_address = address;
|
|
-}
|
|
-
|
|
-uintptr_t stm32mp1_get_boot_ctx_address(void)
|
|
-{
|
|
- return boot_ctx_address;
|
|
-}
|
|
diff --git a/plat/st/stm32mp1/stm32mp1_context.c b/plat/st/stm32mp1/stm32mp1_context.c
|
|
index 245fd17..8dc1146 100644
|
|
--- a/plat/st/stm32mp1/stm32mp1_context.c
|
|
+++ b/plat/st/stm32mp1/stm32mp1_context.c
|
|
@@ -4,39 +4,235 @@
|
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
*/
|
|
|
|
+#include <arch_helpers.h>
|
|
+#include <boot_api.h>
|
|
+#include <context.h>
|
|
+#include <context_mgmt.h>
|
|
#include <dt-bindings/clock/stm32mp1-clks.h>
|
|
#include <errno.h>
|
|
#include <mmio.h>
|
|
#include <platform_def.h>
|
|
+#include <smccc_helpers.h>
|
|
+#include <stm32_rtc.h>
|
|
#include <stm32mp1_clk.h>
|
|
#include <stm32mp1_context.h>
|
|
+#include <stm32mp1_ddr_regs.h>
|
|
+#include <stm32mp1_shared_resources.h>
|
|
+#include <string.h>
|
|
+#include <utils.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 */
|
|
+#define OPTEE_MAILBOX_MAGIC_V1 0x01
|
|
+#define OPTEE_MAILBOX_MAGIC ((OPTEE_MAILBOX_MAGIC_V1 << 16) + \
|
|
+ TRAINING_AREA_SIZE)
|
|
+#endif
|
|
+
|
|
+struct backup_data_s {
|
|
+#ifdef AARCH32_SP_OPTEE
|
|
+ uint32_t magic;
|
|
+ uint32_t core0_resume_hint;
|
|
+ uint32_t zq0cr0_zdata;
|
|
+ uint8_t ddr_training_backup[TRAINING_AREA_SIZE];
|
|
+#else
|
|
+ smc_ctx_t saved_smc_context[PLATFORM_CORE_COUNT];
|
|
+ cpu_context_t saved_cpu_context[PLATFORM_CORE_COUNT];
|
|
+ uint32_t zq0cr0_zdata;
|
|
+ struct stm32_rtc_calendar rtc;
|
|
+ uint8_t ddr_training_backup[TRAINING_AREA_SIZE];
|
|
+#endif
|
|
+};
|
|
+
|
|
+#ifdef AARCH32_SP_OPTEE
|
|
+uint32_t stm32_pm_get_optee_ep(void)
|
|
+{
|
|
+ struct backup_data_s *backup_data;
|
|
+ uint32_t ep;
|
|
+
|
|
+ stm32mp_clk_enable(BKPSRAM);
|
|
+
|
|
+ /* Context & Data to be saved at the beginning of Backup SRAM */
|
|
+ backup_data = (struct backup_data_s *)STM32MP_BACKUP_RAM_BASE;
|
|
+
|
|
+ if (backup_data->magic != OPTEE_MAILBOX_MAGIC) {
|
|
+ panic();
|
|
+ }
|
|
+
|
|
+ ep = backup_data->core0_resume_hint;
|
|
+
|
|
+ stm32mp_clk_disable(BKPSRAM);
|
|
+
|
|
+ return ep;
|
|
+}
|
|
+#else /*AARCH32_SP_OPTEE*/
|
|
+void stm32_clean_context(void)
|
|
+{
|
|
+ stm32mp_clk_enable(BKPSRAM);
|
|
+
|
|
+ zeromem((void *)STM32MP_BACKUP_RAM_BASE, sizeof(struct backup_data_s));
|
|
+
|
|
+ stm32mp_clk_disable(BKPSRAM);
|
|
+}
|
|
+
|
|
+int stm32_save_context(uint32_t zq0cr0_zdata)
|
|
+{
|
|
+ void *smc_context;
|
|
+ void *cpu_context;
|
|
+ struct backup_data_s *backup_data;
|
|
+
|
|
+ stm32mp_clk_enable(BKPSRAM);
|
|
+
|
|
+ /* Context & Data to be saved at the beginning of Backup SRAM */
|
|
+ backup_data = (struct backup_data_s *)STM32MP_BACKUP_RAM_BASE;
|
|
+
|
|
+ /* Retrieve smc context struct address */
|
|
+ smc_context = smc_get_ctx(NON_SECURE);
|
|
+
|
|
+ /* Retrieve smc context struct address */
|
|
+ cpu_context = cm_get_context(NON_SECURE);
|
|
+
|
|
+ /* Save context in Backup SRAM */
|
|
+ memcpy(&backup_data->saved_smc_context[0], smc_context,
|
|
+ sizeof(smc_ctx_t) * PLATFORM_CORE_COUNT);
|
|
+ memcpy(&backup_data->saved_cpu_context[0], cpu_context,
|
|
+ sizeof(cpu_context_t) * PLATFORM_CORE_COUNT);
|
|
+
|
|
+ backup_data->zq0cr0_zdata = zq0cr0_zdata;
|
|
+
|
|
+ stm32_rtc_get_calendar(&backup_data->rtc);
|
|
+
|
|
+ stm32mp_clk_disable(BKPSRAM);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+int stm32_restore_context(void)
|
|
+{
|
|
+ void *smc_context;
|
|
+ void *cpu_context;
|
|
+ struct backup_data_s *backup_data;
|
|
+ struct stm32_rtc_calendar current_calendar;
|
|
+ unsigned long long stdby_time_in_ms;
|
|
+
|
|
+ stm32mp_clk_enable(BKPSRAM);
|
|
+
|
|
+ /* Context & Data to be saved at the beginning of Backup SRAM */
|
|
+ backup_data = (struct backup_data_s *)STM32MP_BACKUP_RAM_BASE;
|
|
+
|
|
+ /* Retrieve smc context struct address */
|
|
+ smc_context = smc_get_ctx(NON_SECURE);
|
|
+
|
|
+ /* Retrieve smc context struct address */
|
|
+ cpu_context = cm_get_context(NON_SECURE);
|
|
+
|
|
+ /* Restore data from Backup SRAM */
|
|
+ memcpy(smc_context, backup_data->saved_smc_context,
|
|
+ sizeof(smc_ctx_t) * PLATFORM_CORE_COUNT);
|
|
+ memcpy(cpu_context, backup_data->saved_cpu_context,
|
|
+ sizeof(cpu_context_t) * PLATFORM_CORE_COUNT);
|
|
+
|
|
+ /* update STGEN counter with standby mode length */
|
|
+ stm32_rtc_get_calendar(¤t_calendar);
|
|
+ stdby_time_in_ms = stm32_rtc_diff_calendar(¤t_calendar,
|
|
+ &backup_data->rtc);
|
|
+ stm32mp1_stgen_increment(stdby_time_in_ms);
|
|
+
|
|
+ stm32mp_clk_disable(BKPSRAM);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+#endif /*AARCH32_SP_OPTEE*/
|
|
+
|
|
+uint32_t stm32_get_zdata_from_context(void)
|
|
+{
|
|
+ struct backup_data_s *backup_data;
|
|
+ uint32_t zdata;
|
|
+
|
|
+ stm32mp_clk_enable(BKPSRAM);
|
|
+
|
|
+ backup_data = (struct backup_data_s *)STM32MP_BACKUP_RAM_BASE;
|
|
+
|
|
+ zdata = (backup_data->zq0cr0_zdata >> DDRPHYC_ZQ0CRN_ZDATA_SHIFT) &
|
|
+ DDRPHYC_ZQ0CRN_ZDATA_MASK;
|
|
+
|
|
+ stm32mp_clk_disable(BKPSRAM);
|
|
+
|
|
+ return zdata;
|
|
+}
|
|
+
|
|
int stm32_save_boot_interface(uint32_t interface, uint32_t instance)
|
|
{
|
|
- uint32_t tamp_clk_off = 0;
|
|
uint32_t bkpr_itf_idx = tamp_bkpr(TAMP_BOOT_ITF_BACKUP_REG_ID);
|
|
|
|
- if (!stm32mp1_clk_is_enabled(RTCAPB)) {
|
|
- tamp_clk_off = 1;
|
|
- if (stm32mp1_clk_enable(RTCAPB) != 0) {
|
|
- return -EINVAL;
|
|
- }
|
|
- }
|
|
+ stm32mp_clk_enable(RTCAPB);
|
|
|
|
mmio_clrsetbits_32(bkpr_itf_idx,
|
|
TAMP_BOOT_ITF_MASK,
|
|
((interface << 4) | (instance & 0xFU)) <<
|
|
TAMP_BOOT_ITF_SHIFT);
|
|
|
|
- if (tamp_clk_off != 0U) {
|
|
- if (stm32mp1_clk_disable(RTCAPB) != 0) {
|
|
- return -EINVAL;
|
|
- }
|
|
- }
|
|
+ stm32mp_clk_disable(RTCAPB);
|
|
|
|
return 0;
|
|
}
|
|
+
|
|
+int stm32_get_boot_interface(uint32_t *interface, uint32_t *instance)
|
|
+{
|
|
+ uint32_t backup_reg_itf;
|
|
+ uint32_t bkpr_itf_idx = tamp_bkpr(TAMP_BOOT_ITF_BACKUP_REG_ID);
|
|
+
|
|
+ stm32mp_clk_enable(RTCAPB);
|
|
+
|
|
+ backup_reg_itf = (mmio_read_32(bkpr_itf_idx) &
|
|
+ TAMP_BOOT_ITF_MASK) >> TAMP_BOOT_ITF_SHIFT;
|
|
+
|
|
+ stm32mp_clk_disable(RTCAPB);
|
|
+
|
|
+ *interface = backup_reg_itf >> 4;
|
|
+ *instance = backup_reg_itf & 0xFU;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * When returning from STANDBY, the 64 first bytes of DDR will be overwritten
|
|
+ * during DDR DQS training. This area must then be saved before going to
|
|
+ * standby, and will be restored after
|
|
+ */
|
|
+void stm32_save_ddr_training_area(void)
|
|
+{
|
|
+ struct backup_data_s *backup_data;
|
|
+
|
|
+ stm32mp_clk_enable(BKPSRAM);
|
|
+
|
|
+ backup_data = (struct backup_data_s *)STM32MP_BACKUP_RAM_BASE;
|
|
+
|
|
+ memcpy(&backup_data->ddr_training_backup,
|
|
+ (const uint32_t *)STM32MP_DDR_BASE,
|
|
+ TRAINING_AREA_SIZE);
|
|
+ dsb();
|
|
+
|
|
+ stm32mp_clk_disable(BKPSRAM);
|
|
+}
|
|
+
|
|
+void stm32_restore_ddr_training_area(void)
|
|
+{
|
|
+ struct backup_data_s *backup_data;
|
|
+
|
|
+ stm32mp_clk_enable(BKPSRAM);
|
|
+
|
|
+ backup_data = (struct backup_data_s *)STM32MP_BACKUP_RAM_BASE;
|
|
+
|
|
+ memcpy((uint32_t *)STM32MP_DDR_BASE,
|
|
+ &backup_data->ddr_training_backup,
|
|
+ TRAINING_AREA_SIZE);
|
|
+ dsb();
|
|
+
|
|
+ stm32mp_clk_disable(BKPSRAM);
|
|
+}
|
|
diff --git a/plat/st/stm32mp1/stm32mp1_dbgmcu.c b/plat/st/stm32mp1/stm32mp1_dbgmcu.c
|
|
new file mode 100644
|
|
index 0000000..716f7d8
|
|
--- /dev/null
|
|
+++ b/plat/st/stm32mp1/stm32mp1_dbgmcu.c
|
|
@@ -0,0 +1,153 @@
|
|
+/*
|
|
+ * Copyright (c) 2016-2018, STMicroelectronics - All Rights Reserved
|
|
+ *
|
|
+ * SPDX-License-Identifier: BSD-3-Clause
|
|
+ */
|
|
+
|
|
+#include <bsec.h>
|
|
+#include <debug.h>
|
|
+#include <dt-bindings/clock/stm32mp1-clks.h>
|
|
+#include <errno.h>
|
|
+#include <mmio.h>
|
|
+#include <platform_def.h>
|
|
+#include <stm32mp1_dbgmcu.h>
|
|
+#include <stm32mp1_rcc.h>
|
|
+#include <stm32mp1_shared_resources.h>
|
|
+#include <utils_def.h>
|
|
+
|
|
+#define DBGMCU_IDC 0x0U
|
|
+#define IDC_DEV_ID_MASK GENMASK(11, 0)
|
|
+#define DBGMCU_APB4FZ1 0x2CU
|
|
+#define DBGMCU_APB4FZ1_IWDG2 BIT(2)
|
|
+
|
|
+#define TAMP_DBG_BACKUP_REG_ID 20
|
|
+#define TAMP_DBG_DEBUG BIT(16)
|
|
+
|
|
+static uintptr_t get_rcc_base(void)
|
|
+{
|
|
+ /* This is called before stm32mp_rcc_base() is available */
|
|
+ return RCC_BASE;
|
|
+}
|
|
+
|
|
+static int stm32mp1_dbgmcu_init(void)
|
|
+{
|
|
+ uint32_t dbg_conf;
|
|
+ uintptr_t rcc_base = get_rcc_base();
|
|
+
|
|
+ dbg_conf = bsec_read_debug_conf();
|
|
+
|
|
+ if ((dbg_conf & BSEC_DBGSWGEN) == 0U) {
|
|
+ uint32_t result = bsec_write_debug_conf(dbg_conf |
|
|
+ BSEC_DBGSWGEN);
|
|
+
|
|
+ if (result != BSEC_OK) {
|
|
+ ERROR("Error enabling DBGSWGEN\n");
|
|
+ return (int)result;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if ((mmio_read_32(rcc_base + RCC_DBGCFGR) & RCC_DBGCFGR_DBGCKEN) ==
|
|
+ 0U) {
|
|
+ mmio_setbits_32(rcc_base + RCC_DBGCFGR, RCC_DBGCFGR_DBGCKEN);
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+#if STM32MP1_DEBUG_ENABLE
|
|
+int stm32mp1_dbgmcu_boot_debug_info(void)
|
|
+{
|
|
+ uint32_t backup_reg_dbg;
|
|
+
|
|
+ stm32mp_clk_enable(RTCAPB);
|
|
+
|
|
+ backup_reg_dbg = (mmio_read_32(tamp_bkpr(TAMP_DBG_BACKUP_REG_ID))
|
|
+ & TAMP_DBG_DEBUG);
|
|
+
|
|
+ stm32mp_clk_disable(RTCAPB);
|
|
+
|
|
+ if (backup_reg_dbg != 0U) {
|
|
+ return 1;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+int stm32mp1_dbgmcu_clear_boot_info(void)
|
|
+{
|
|
+ stm32mp_clk_enable(RTCAPB);
|
|
+
|
|
+ mmio_clrbits_32(tamp_bkpr(TAMP_DBG_BACKUP_REG_ID),
|
|
+ TAMP_DBG_DEBUG);
|
|
+
|
|
+ stm32mp_clk_disable(RTCAPB);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+uint32_t stm32mp1_dbgmcu_is_debug_on(void)
|
|
+{
|
|
+ uint32_t dbg_conf;
|
|
+
|
|
+ dbg_conf = bsec_read_debug_conf();
|
|
+
|
|
+ return (dbg_conf & (BSEC_SPIDEN | BSEC_SPINDEN));
|
|
+}
|
|
+
|
|
+#if LOG_LEVEL >= LOG_LEVEL_VERBOSE
|
|
+void stm32mp1_dbgmcu_hexdump8(uint8_t *buf, uint32_t len)
|
|
+{
|
|
+ uint32_t i;
|
|
+
|
|
+ VERBOSE(" ");
|
|
+ for (i = 0; i < len; i++) {
|
|
+ printf("%02x ", buf[i]);
|
|
+ if (((i + 1) % 16) == 0) {
|
|
+ if ((i + 1) < len) {
|
|
+ printf("\n");
|
|
+ VERBOSE(" ");
|
|
+ }
|
|
+ } else if (((i + 1) % 8) == 0) {
|
|
+ printf(" ");
|
|
+ }
|
|
+ }
|
|
+ printf("\n");
|
|
+}
|
|
+#endif
|
|
+#endif
|
|
+
|
|
+uint32_t stm32mp1_dbgmcu_get_chip_version(void)
|
|
+{
|
|
+ if (stm32mp1_dbgmcu_init() == 0) {
|
|
+ return (mmio_read_32(DBGMCU_BASE + DBGMCU_IDC) >> 16);
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+uint32_t stm32mp1_dbgmcu_get_chip_dev_id(void)
|
|
+{
|
|
+ if (stm32mp1_dbgmcu_init() == 0) {
|
|
+ return (mmio_read_32(DBGMCU_BASE + DBGMCU_IDC) &
|
|
+ IDC_DEV_ID_MASK);
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+int stm32mp1_dbgmcu_freeze_iwdg2(void)
|
|
+{
|
|
+ if (stm32mp1_dbgmcu_init() == 0) {
|
|
+ uint32_t dbg_conf = bsec_read_debug_conf();
|
|
+
|
|
+ if (((dbg_conf & BSEC_SPIDEN) != 0U) ||
|
|
+ ((dbg_conf & BSEC_SPINDEN) != 0U)) {
|
|
+ mmio_setbits_32(DBGMCU_BASE + DBGMCU_APB4FZ1,
|
|
+ DBGMCU_APB4FZ1_IWDG2);
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ return -EPERM;
|
|
+}
|
|
diff --git a/plat/st/stm32mp1/stm32mp1_def.h b/plat/st/stm32mp1/stm32mp1_def.h
|
|
index bb3fecf..a6b1a7b 100644
|
|
--- a/plat/st/stm32mp1/stm32mp1_def.h
|
|
+++ b/plat/st/stm32mp1/stm32mp1_def.h
|
|
@@ -1,5 +1,5 @@
|
|
/*
|
|
- * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
|
|
+ * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved.
|
|
*
|
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
*/
|
|
@@ -7,84 +7,206 @@
|
|
#ifndef STM32MP1_DEF_H
|
|
#define STM32MP1_DEF_H
|
|
|
|
+#ifndef __ASSEMBLY__
|
|
+#include <bsec.h>
|
|
+#include <dt-bindings/clock/stm32mp1-clks.h>
|
|
+#include <dt-bindings/clock/stm32mp1-clksrc.h>
|
|
+#include <dt-bindings/reset/stm32mp1-resets.h>
|
|
+#include <dt-bindings/soc/st,stm32-etzpc.h>
|
|
+#include <etzpc.h>
|
|
+#include <stm32mp1_clkfunc.h>
|
|
+#include <stm32mp1_clk.h>
|
|
+#include <stm32mp1_context.h>
|
|
+#include <stm32mp1_dbgmcu.h>
|
|
+#include <stm32mp1_ddr.h>
|
|
+#include <stm32mp1_ddr_helpers.h>
|
|
+#include <stm32mp1_ddr_regs.h>
|
|
+#include <stm32mp1_private.h>
|
|
+#include <stm32mp1_pwr.h>
|
|
+#include <stm32mp1_ram.h>
|
|
+#include <stm32mp1_rcc.h>
|
|
+#include <stm32mp1_shared_resources.h>
|
|
+#include <stm32mp1_usb_desc.h>
|
|
+#include <stm32mp1xx_hal_uart.h>
|
|
+#endif
|
|
#include <tbbr_img_def.h>
|
|
#include <utils_def.h>
|
|
#include <xlat_tables_defs.h>
|
|
|
|
+#define AUTHENTICATE_BL33
|
|
+
|
|
+/*******************************************************************************
|
|
+ * CHIP ID
|
|
+ ******************************************************************************/
|
|
+#define STM32MP157C_PART_NB U(0x05000000)
|
|
+#define STM32MP157A_PART_NB U(0x05000001)
|
|
+#define STM32MP153C_PART_NB U(0x05000024)
|
|
+#define STM32MP153A_PART_NB U(0x05000025)
|
|
+#define STM32MP151C_PART_NB U(0x0500002E)
|
|
+#define STM32MP151A_PART_NB U(0x0500002F)
|
|
+
|
|
+#define STM32MP1_REV_A U(0x1000)
|
|
+#define STM32MP1_REV_B U(0x2000)
|
|
+
|
|
+/*******************************************************************************
|
|
+ * PACKAGE ID
|
|
+ ******************************************************************************/
|
|
+#define PKG_AA_LBGA448 U(4)
|
|
+#define PKG_AB_LBGA354 U(3)
|
|
+#define PKG_AC_TFBGA361 U(2)
|
|
+#define PKG_AD_TFBGA257 U(1)
|
|
+
|
|
+/*******************************************************************************
|
|
+ * BOOT PARAM
|
|
+ ******************************************************************************/
|
|
+#define BOOT_PARAM_ADDR U(0x2FFC0078)
|
|
+
|
|
/*******************************************************************************
|
|
* STM32MP1 memory map related constants
|
|
******************************************************************************/
|
|
+#define STM32MP_ROM_BASE U(0x00000000)
|
|
+#define STM32MP_ROM_SIZE U(0x00020000)
|
|
+
|
|
+#define STM32MP_SYSRAM_BASE U(0x2FFC0000)
|
|
+#define STM32MP_SYSRAM_SIZE U(0x00040000)
|
|
+
|
|
+/* 384 Ko (128 x 3) Non secure from MCU available for TF*/
|
|
+#define STM32MP_SRAM_MCU_BASE U(0x30000000)
|
|
+#define STM32MP_SRAM_MCU_SIZE U(0x00060000)
|
|
|
|
-#define STM32MP1_SRAM_BASE U(0x2FFC0000)
|
|
-#define STM32MP1_SRAM_SIZE U(0x00040000)
|
|
+#define STM32MP_RETRAM_BASE U(0x38000000)
|
|
+#define STM32MP_RETRAM_SIZE U(0x00010000)
|
|
+
|
|
+#define STM32MP_BACKUP_RAM_BASE U(0x54000000)
|
|
+#define STM32MP_BACKUP_RAM_SIZE U(0x00001000)
|
|
|
|
/* DDR configuration */
|
|
-#define STM32MP1_DDR_BASE U(0xC0000000)
|
|
-#define STM32MP1_DDR_SIZE_DFLT U(0x20000000) /* 512 MB */
|
|
-#define STM32MP1_DDR_MAX_SIZE U(0x40000000) /* Max 1GB */
|
|
-#define STM32MP1_DDR_SPEED_DFLT 528
|
|
+#define STM32MP_DDR_BASE U(0xC0000000)
|
|
+#define STM32MP_DDR_MAX_SIZE U(0x40000000) /* Max 1GB */
|
|
+#ifdef AARCH32_SP_OPTEE
|
|
+#define STM32MP_DDR_S_SIZE U(0x02000000) /* 32 MB */
|
|
+#define STM32MP_DDR_SHMEM_SIZE U(0x00200000) /* 2 MB */
|
|
+#else
|
|
+#define STM32MP_DDR_S_SIZE U(0) /* DDR is non secure */
|
|
+#endif
|
|
|
|
/* DDR power initializations */
|
|
#ifndef __ASSEMBLY__
|
|
enum ddr_type {
|
|
STM32MP_DDR3,
|
|
STM32MP_LPDDR2,
|
|
+ STM32MP_LPDDR3,
|
|
};
|
|
#endif
|
|
|
|
/* Section used inside TF binaries */
|
|
-#define STM32MP1_PARAM_LOAD_SIZE U(0x00002400) /* 9 Ko for param */
|
|
+#define STM32MP_PARAM_LOAD_SIZE U(0x00002400) /* 9 Ko for param */
|
|
/* 256 Octets reserved for header */
|
|
-#define STM32MP1_HEADER_SIZE U(0x00000100)
|
|
+#define STM32MP_HEADER_SIZE U(0x00000100)
|
|
|
|
-#define STM32MP1_BINARY_BASE (STM32MP1_SRAM_BASE + \
|
|
- STM32MP1_PARAM_LOAD_SIZE + \
|
|
- STM32MP1_HEADER_SIZE)
|
|
+#define STM32MP_BINARY_BASE (STM32MP_SYSRAM_BASE + \
|
|
+ STM32MP_PARAM_LOAD_SIZE + \
|
|
+ STM32MP_HEADER_SIZE)
|
|
|
|
-#define STM32MP1_BINARY_SIZE (STM32MP1_SRAM_SIZE - \
|
|
- (STM32MP1_PARAM_LOAD_SIZE + \
|
|
- STM32MP1_HEADER_SIZE))
|
|
+#define STM32MP_BINARY_SIZE (STM32MP_SYSRAM_SIZE - \
|
|
+ (STM32MP_PARAM_LOAD_SIZE + \
|
|
+ STM32MP_HEADER_SIZE))
|
|
|
|
+#ifdef AARCH32_SP_OPTEE
|
|
+#define STM32MP_BL32_SIZE U(0)
|
|
+
|
|
+#define STM32MP_OPTEE_BASE STM32MP_SYSRAM_BASE
|
|
+
|
|
+#define STM32MP_OPTEE_SIZE (STM32MP_DTB_BASE - \
|
|
+ STM32MP_OPTEE_BASE)
|
|
+#else
|
|
#if STACK_PROTECTOR_ENABLED
|
|
-#define STM32MP1_BL32_SIZE U(0x00012000) /* 72 Ko for BL32 */
|
|
+#define STM32MP_BL32_SIZE U(0x00011000) /* 68 Ko for BL32 */
|
|
#else
|
|
-#define STM32MP1_BL32_SIZE U(0x00011000) /* 68 Ko for BL32 */
|
|
+#define STM32MP_BL32_SIZE U(0x00010000) /* 64 Ko for BL32 */
|
|
+#endif
|
|
#endif
|
|
|
|
-#define STM32MP1_BL32_BASE (STM32MP1_SRAM_BASE + \
|
|
- STM32MP1_SRAM_SIZE - \
|
|
- STM32MP1_BL32_SIZE)
|
|
+#define STM32MP_BL32_BASE (STM32MP_SYSRAM_BASE + \
|
|
+ STM32MP_SYSRAM_SIZE - \
|
|
+ STM32MP_BL32_SIZE)
|
|
|
|
+#ifdef AARCH32_SP_OPTEE
|
|
#if STACK_PROTECTOR_ENABLED
|
|
-#define STM32MP1_BL2_SIZE U(0x00015000) /* 84 Ko for BL2 */
|
|
+#define STM32MP_BL2_SIZE U(0x00019000) /* 100 Ko for BL2 */
|
|
#else
|
|
-#define STM32MP1_BL2_SIZE U(0x00013000) /* 76 Ko for BL2 */
|
|
+#define STM32MP_BL2_SIZE U(0x00017000) /* 92 Ko for BL2 */
|
|
+#endif
|
|
+#else
|
|
+#if STACK_PROTECTOR_ENABLED
|
|
+#define STM32MP_BL2_SIZE U(0x00018000) /* 96 Ko for BL2 */
|
|
+#else
|
|
+#define STM32MP_BL2_SIZE U(0x00016000) /* 88 Ko for BL2 */
|
|
+#endif
|
|
#endif
|
|
|
|
-#define STM32MP1_BL2_BASE (STM32MP1_BL32_BASE - \
|
|
- STM32MP1_BL2_SIZE)
|
|
+#define STM32MP_BL2_BASE (STM32MP_BL32_BASE - \
|
|
+ STM32MP_BL2_SIZE)
|
|
|
|
-/* BL2 and BL32/sp_min require 5 tables */
|
|
-#define MAX_XLAT_TABLES 5
|
|
+/* BL2 and BL32/sp_min require 7 tables */
|
|
+#define MAX_XLAT_TABLES U(7) /* 28 Ko for mapping */
|
|
|
|
/*
|
|
* MAX_MMAP_REGIONS is usually:
|
|
* BL stm32mp1_mmap size + mmap regions in *_plat_arch_setup
|
|
*/
|
|
#if defined(IMAGE_BL2)
|
|
+ #if (defined STM32MP_USB)
|
|
+ #define MAX_MMAP_REGIONS 12
|
|
+ #else
|
|
#define MAX_MMAP_REGIONS 11
|
|
+ #endif
|
|
#endif
|
|
#if defined(IMAGE_BL32)
|
|
- #define MAX_MMAP_REGIONS 6
|
|
+ #define MAX_MMAP_REGIONS 6
|
|
#endif
|
|
|
|
+#define XLAT_TABLE_OCTETSIZE U(0x1000)
|
|
+#define PLAT_XLAT_SIZE (MAX_XLAT_TABLES * \
|
|
+ XLAT_TABLE_OCTETSIZE)
|
|
+
|
|
+#define PLAT_XLAT_BASE (STM32MP_BL2_BASE - \
|
|
+ PLAT_XLAT_SIZE)
|
|
+
|
|
+/*
|
|
+ * Uncomment this to get the xlat tables back in each binary image
|
|
+ * (xlat_table sections in .lds)
|
|
+ *
|
|
+ * #undef PLAT_XLAT_BASE
|
|
+ */
|
|
+
|
|
/* DTB initialization value */
|
|
-#define STM32MP1_DTB_SIZE U(0x00004000) /* 16Ko for DTB */
|
|
+#define STM32MP_DTB_SIZE U(0x00005000) /* 20Ko for DTB */
|
|
+
|
|
+#define STM32MP_DTB_BASE (PLAT_XLAT_BASE - \
|
|
+ STM32MP_DTB_SIZE)
|
|
|
|
-#define STM32MP1_DTB_BASE (STM32MP1_BL2_BASE - \
|
|
- STM32MP1_DTB_SIZE)
|
|
+#define STM32MP_BL33_BASE (STM32MP_DDR_BASE + U(0x100000))
|
|
|
|
-#define STM32MP1_BL33_BASE (STM32MP1_DDR_BASE + U(0x100000))
|
|
+/* Define Temporary Stack size use during low power mode */
|
|
+#define STM32MP_INT_STACK_SIZE 0x400
|
|
+
|
|
+/*******************************************************************************
|
|
+ * STM32MP1 RAW partition offset for MTD devices
|
|
+ ******************************************************************************/
|
|
+#define STM32MP_NOR_BL33_OFFSET U(0x00080000)
|
|
+#ifdef AARCH32_SP_OPTEE
|
|
+#define STM32MP_NOR_TEEH_OFFSET U(0x00280000)
|
|
+#define STM32MP_NOR_TEED_OFFSET U(0x002C0000)
|
|
+#define STM32MP_NOR_TEEX_OFFSET U(0x00300000)
|
|
+#endif
|
|
+
|
|
+#define STM32MP_NAND_BL33_OFFSET U(0x00200000)
|
|
+#ifdef AARCH32_SP_OPTEE
|
|
+#define STM32MP_NAND_TEEH_OFFSET U(0x00400000)
|
|
+#define STM32MP_NAND_TEED_OFFSET U(0x00480000)
|
|
+#define STM32MP_NAND_TEEX_OFFSET U(0x00500000)
|
|
+#endif
|
|
|
|
/*******************************************************************************
|
|
* STM32MP1 device/io map related constants (used for MMU)
|
|
@@ -106,6 +228,60 @@ enum ddr_type {
|
|
#define PWR_BASE U(0x50001000)
|
|
|
|
/*******************************************************************************
|
|
+ * STM32MP1 EXTI
|
|
+ ******************************************************************************/
|
|
+#define EXTI_BASE U(0x5000D000)
|
|
+#define EXTI_TZENR1 U(0x14)
|
|
+#define EXTI_RPR3 U(0x4C)
|
|
+#define EXTI_FPR3 U(0x50)
|
|
+#define EXTI_C1IMR1 U(0x80)
|
|
+#define EXTI_C2IMR1 U(0xC0)
|
|
+#define EXTI_C2IMR2 U(0xD0)
|
|
+#define EXTI_C2IMR3 U(0xE0)
|
|
+#define EXTI_TZENR1_TZEN18 BIT(18)
|
|
+#define EXTI_IMR1_IM18 BIT(18)
|
|
+#define EXTI_RPR3_RPIF65 BIT(1)
|
|
+#define EXTI_FPR3_FPIF65 BIT(1)
|
|
+
|
|
+/*******************************************************************************
|
|
+ * STM32MP1 RTC
|
|
+ ******************************************************************************/
|
|
+#define RTC_BASE U(0x5C004000)
|
|
+
|
|
+/*******************************************************************************
|
|
+ * STM32MP1 GPIO
|
|
+ ******************************************************************************/
|
|
+#define GPIOA_BASE U(0x50002000)
|
|
+#define GPIOB_BASE U(0x50003000)
|
|
+#define GPIOC_BASE U(0x50004000)
|
|
+#define GPIOD_BASE U(0x50005000)
|
|
+#define GPIOE_BASE U(0x50006000)
|
|
+#define GPIOF_BASE U(0x50007000)
|
|
+#define GPIOG_BASE U(0x50008000)
|
|
+#define GPIOH_BASE U(0x50009000)
|
|
+#define GPIOI_BASE U(0x5000A000)
|
|
+#define GPIOJ_BASE U(0x5000B000)
|
|
+#define GPIOK_BASE U(0x5000C000)
|
|
+#define GPIOZ_BASE U(0x54004000)
|
|
+#define GPIO_BANK_OFFSET U(0x1000)
|
|
+
|
|
+/* Bank IDs used in GPIO driver API */
|
|
+#define GPIO_BANK_A U(0)
|
|
+#define GPIO_BANK_B U(1)
|
|
+#define GPIO_BANK_C U(2)
|
|
+#define GPIO_BANK_D U(3)
|
|
+#define GPIO_BANK_E U(4)
|
|
+#define GPIO_BANK_F U(5)
|
|
+#define GPIO_BANK_G U(6)
|
|
+#define GPIO_BANK_H U(7)
|
|
+#define GPIO_BANK_I U(8)
|
|
+#define GPIO_BANK_J U(9)
|
|
+#define GPIO_BANK_K U(10)
|
|
+#define GPIO_BANK_Z U(25)
|
|
+
|
|
+#define STM32MP_GPIOZ_PIN_MAX_COUNT 8
|
|
+
|
|
+/*******************************************************************************
|
|
* STM32MP1 UART
|
|
******************************************************************************/
|
|
#define USART1_BASE U(0x5C000000)
|
|
@@ -116,16 +292,31 @@ enum ddr_type {
|
|
#define USART6_BASE U(0x44003000)
|
|
#define UART7_BASE U(0x40018000)
|
|
#define UART8_BASE U(0x40019000)
|
|
-#define STM32MP1_DEBUG_USART_BASE UART4_BASE
|
|
-#define STM32MP1_UART_BAUDRATE 115200
|
|
+#define STM32MP_UART_BAUDRATE U(115200)
|
|
+
|
|
+/* For UART crash console */
|
|
+#define STM32MP_DEBUG_USART_BASE UART4_BASE
|
|
+/* UART4 on HSI@64MHz, TX on GPIOG11 Alternate 6 */
|
|
+#define STM32MP_DEBUG_USART_CLK_FRQ 64000000
|
|
+#define DEBUG_UART_TX_GPIO_BANK_ADDRESS GPIOG_BASE
|
|
+#define DEBUG_UART_TX_GPIO_BANK_CLK_REG RCC_MP_AHB4ENSETR
|
|
+#define DEBUG_UART_TX_GPIO_BANK_CLK_EN RCC_MP_AHB4ENSETR_GPIOGEN
|
|
+#define DEBUG_UART_TX_GPIO_PORT 11
|
|
+#define DEBUG_UART_TX_GPIO_ALTERNATE 6
|
|
+#define DEBUG_UART_TX_CLKSRC_REG RCC_UART24CKSELR
|
|
+#define DEBUG_UART_TX_CLKSRC RCC_UART24CKSELR_HSI
|
|
+#define DEBUG_UART_TX_EN_REG RCC_MP_APB1ENSETR
|
|
+#define DEBUG_UART_TX_EN RCC_MP_APB1ENSETR_UART4EN
|
|
|
|
/*******************************************************************************
|
|
- * STM32MP1 GIC-400
|
|
+ * STM32MP1 TZPC
|
|
******************************************************************************/
|
|
-#define STM32MP1_GICD_BASE U(0xA0021000)
|
|
-#define STM32MP1_GICC_BASE U(0xA0022000)
|
|
-#define STM32MP1_GICH_BASE U(0xA0024000)
|
|
-#define STM32MP1_GICV_BASE U(0xA0026000)
|
|
+#define STM32MP1_ETZPC_BASE U(0x5C007000)
|
|
+#define STM32MP1_ETZPC_SIZE U(0x000003FF)
|
|
+
|
|
+#define STM32MP1_ETZPC_TZMA_ROM_ID U(0)
|
|
+/*SYSRAM internal RAM*/
|
|
+#define STM32MP1_ETZPC_TZMA_RAM_ID U(1)
|
|
|
|
/*******************************************************************************
|
|
* STM32MP1 TZC (TZ400)
|
|
@@ -133,6 +324,7 @@ enum ddr_type {
|
|
#define STM32MP1_TZC_BASE U(0x5C006000)
|
|
|
|
#define STM32MP1_TZC_A7_ID U(0)
|
|
+#define STM32MP1_TZC_M4_ID U(1)
|
|
#define STM32MP1_TZC_LCD_ID U(3)
|
|
#define STM32MP1_TZC_GPU_ID U(4)
|
|
#define STM32MP1_TZC_MDMA_ID U(5)
|
|
@@ -143,28 +335,117 @@ enum ddr_type {
|
|
#define STM32MP1_TZC_ETH_ID U(10)
|
|
#define STM32MP1_TZC_DAP_ID U(15)
|
|
|
|
-#define STM32MP1_MEMORY_NS 0
|
|
-#define STM32MP1_MEMORY_SECURE 1
|
|
-
|
|
-#define STM32MP1_FILTER_BIT_ALL 3
|
|
+#define STM32MP1_FILTER_BIT_ALL U(3)
|
|
|
|
/*******************************************************************************
|
|
* STM32MP1 SDMMC
|
|
******************************************************************************/
|
|
-#define STM32MP1_SDMMC1_BASE U(0x58005000)
|
|
-#define STM32MP1_SDMMC2_BASE U(0x58007000)
|
|
-#define STM32MP1_SDMMC3_BASE U(0x48004000)
|
|
+#define STM32MP_SDMMC1_BASE U(0x58005000)
|
|
+#define STM32MP_SDMMC2_BASE U(0x58007000)
|
|
+#define STM32MP_SDMMC3_BASE U(0x48004000)
|
|
|
|
-#define STM32MP1_SD_INIT_FREQ 400000 /*400 KHz*/
|
|
-#define STM32MP1_SD_NORMAL_SPEED_MAX_FREQ 25000000 /*25 MHz*/
|
|
-#define STM32MP1_SD_HIGH_SPEED_MAX_FREQ 50000000 /*50 MHz*/
|
|
-#define STM32MP1_EMMC_INIT_FREQ STM32MP1_SD_INIT_FREQ
|
|
-#define STM32MP1_EMMC_NORMAL_SPEED_MAX_FREQ 26000000 /*26 MHz*/
|
|
-#define STM32MP1_EMMC_HIGH_SPEED_MAX_FREQ 52000000 /*52 MHz*/
|
|
+#define STM32MP_MMC_INIT_FREQ U(400000) /*400 KHz*/
|
|
+#define STM32MP_SD_NORMAL_SPEED_MAX_FREQ U(25000000) /*25 MHz*/
|
|
+#define STM32MP_SD_HIGH_SPEED_MAX_FREQ U(50000000) /*50 MHz*/
|
|
+#define STM32MP_EMMC_NORMAL_SPEED_MAX_FREQ U(26000000) /*26 MHz*/
|
|
+#define STM32MP_EMMC_HIGH_SPEED_MAX_FREQ U(52000000) /*52 MHz*/
|
|
+
|
|
+/*******************************************************************************
|
|
+ * STM32MP1 QSPI
|
|
+ ******************************************************************************/
|
|
+#define STM32MP1_QSPI1_BASE U(0x58003000)
|
|
+
|
|
+/*******************************************************************************
|
|
+ * STM32MP1 BSEC / OTP
|
|
+ ******************************************************************************/
|
|
+#define STM32MP1_BSEC_BASE U(0x5C005000)
|
|
+#define STM32MP1_OTP_MAX_ID 0x5FU
|
|
+#define STM32MP1_UPPER_OTP_START 0x20U
|
|
+
|
|
+#define OTP_MAX_SIZE (STM32MP1_OTP_MAX_ID + 1U)
|
|
+
|
|
+/* OTP offsets */
|
|
+#define DATA0_OTP U(0)
|
|
+#define PART_NUMBER_OTP U(1)
|
|
+#define MONOTONIC_OTP U(4)
|
|
+#define NAND_OTP U(9)
|
|
+#define UID0_OTP U(13)
|
|
+#define UID1_OTP U(14)
|
|
+#define UID2_OTP U(15)
|
|
+#define PACKAGE_OTP U(16)
|
|
+#define HW2_OTP U(18) /* HW watchdog OTP */
|
|
+#define BOARD_OTP U(59)
|
|
+
|
|
+/* OTP mask */
|
|
+/* DATA0 */
|
|
+#define DATA0_OTP_SECURED BIT(6)
|
|
+
|
|
+/* PART NUMBER */
|
|
+#define PART_SHIFT 0
|
|
+#define PART_MASK GENMASK_32(7, 0)
|
|
+
|
|
+/* PACKAGE */
|
|
+#define PKG_SHIFT 27
|
|
+#define PKG_MASK GENMASK_32(29, 27)
|
|
+
|
|
+/* IWDG OTP */
|
|
+#define IWDG_HW_POS 3
|
|
+#define IWDG_FZ_STOP_POS 5
|
|
+#define IWDG_FZ_STANDBY_POS 7
|
|
+
|
|
+/* NAND OTP */
|
|
+/* NAND parameter storage flag */
|
|
+#define NAND_PARAM_STORED_IN_OTP U(0x80000000)
|
|
+
|
|
+/* NAND page size in bytes */
|
|
+#define NAND_PAGE_SIZE_OFFSET 29
|
|
+#define NAND_PAGE_SIZE_MASK U(0x60000000)
|
|
+#define NAND_PAGE_SIZE_2K 0
|
|
+#define NAND_PAGE_SIZE_4K 1
|
|
+#define NAND_PAGE_SIZE_8K 2
|
|
+
|
|
+/* NAND block size in pages */
|
|
+#define NAND_BLOCK_SIZE_OFFSET 27
|
|
+#define NAND_BLOCK_SIZE_MASK U(0x18000000)
|
|
+#define NAND_BLOCK_SIZE_64_PAGES 0
|
|
+#define NAND_BLOCK_SIZE_128_PAGES 1
|
|
+#define NAND_BLOCK_SIZE_256_PAGES 2
|
|
+
|
|
+/* NAND number of block (in unit of 256 blocs) */
|
|
+#define NAND_BLOCK_NB_OFFSET 19
|
|
+#define NAND_BLOCK_NB_MASK U(0x07F80000)
|
|
+#define NAND_BLOCK_NB_UNIT U(256)
|
|
+
|
|
+/* NAND bus width in bits */
|
|
+#define NAND_WIDTH_OFFSET 18
|
|
+#define NAND_WIDTH_MASK 0x00040000
|
|
+
|
|
+/* NAND number of ECC bits per 512 bytes */
|
|
+#define NAND_ECC_BIT_NB_OFFSET 16
|
|
+#define NAND_ECC_BIT_NB_MASK U(0x00030000)
|
|
+#define NAND_ECC_BIT_NB_UNSET 0
|
|
+#define NAND_ECC_BIT_NB_1_BITS 1
|
|
+#define NAND_ECC_BIT_NB_4_BITS 2
|
|
+#define NAND_ECC_BIT_NB_8_BITS 3
|
|
+
|
|
+#define MAX_MONOTONIC_VALUE 32
|
|
+
|
|
+/*******************************************************************************
|
|
+ * STM32MP1 FMC
|
|
+ ******************************************************************************/
|
|
+#define STM32MP_FMC_BASE U(0x58002000)
|
|
+
|
|
+/*******************************************************************************
|
|
+ * STM32MP1 HASH
|
|
+ ******************************************************************************/
|
|
+#define HASH1_BASE U(0x54002000)
|
|
+#define HASH_BASE HASH1_BASE
|
|
|
|
/*******************************************************************************
|
|
* STM32MP1 TAMP
|
|
******************************************************************************/
|
|
+#define PLAT_MAX_TAMP_INT U(5)
|
|
+#define PLAT_MAX_TAMP_EXT U(3)
|
|
#define TAMP_BASE U(0x5C00A000)
|
|
#define TAMP_BKP_REGISTER_BASE (TAMP_BASE + U(0x100))
|
|
|
|
@@ -174,6 +455,10 @@ static inline uint32_t tamp_bkpr(uint32_t idx)
|
|
return TAMP_BKP_REGISTER_BASE + (idx << 2);
|
|
}
|
|
#endif
|
|
+/*******************************************************************************
|
|
+ * STM32MP1 USB
|
|
+ ******************************************************************************/
|
|
+#define USB_OTG_BASE U(0x49000000)
|
|
|
|
/*******************************************************************************
|
|
* STM32MP1 DDRCTRL
|
|
@@ -186,8 +471,60 @@ static inline uint32_t tamp_bkpr(uint32_t idx)
|
|
#define DDRPHYC_BASE U(0x5A004000)
|
|
|
|
/*******************************************************************************
|
|
- * STM32MP1 I2C4
|
|
+ * STM32MP1 IWDG
|
|
+ ******************************************************************************/
|
|
+#define IWDG_MAX_INSTANCE U(2)
|
|
+#define IWDG1_INST U(0)
|
|
+#define IWDG2_INST U(1)
|
|
+
|
|
+#define IWDG1_BASE U(0x5C003000)
|
|
+#define IWDG2_BASE U(0x5A002000)
|
|
+
|
|
+/*******************************************************************************
|
|
+ * STM32MP1 I2C
|
|
******************************************************************************/
|
|
#define I2C4_BASE U(0x5C002000)
|
|
+#define I2C6_BASE U(0x5C009000)
|
|
+
|
|
+/*******************************************************************************
|
|
+ * STM32MP1 DBGMCU
|
|
+ ******************************************************************************/
|
|
+#define DBGMCU_BASE U(0x50081000)
|
|
+
|
|
+/*******************************************************************************
|
|
+ * STM32MP1 SPI
|
|
+ ******************************************************************************/
|
|
+#define SPI6_BASE U(0x5C001000)
|
|
+
|
|
+/*******************************************************************************
|
|
+ * STM32MP1 RNG
|
|
+ ******************************************************************************/
|
|
+#define RNG1_BASE U(0x54003000)
|
|
+
|
|
+/*******************************************************************************
|
|
+ * STM32MP1 CRYP
|
|
+ ******************************************************************************/
|
|
+#define CRYP1_BASE U(0x54001000)
|
|
+
|
|
+/*******************************************************************************
|
|
+ * STM32MP1 TIMERS
|
|
+ ******************************************************************************/
|
|
+#define TIM12_BASE U(0x40006000)
|
|
+#define TIM15_BASE U(0x44006000)
|
|
+#define TIM_MAX_INSTANCE U(2)
|
|
+
|
|
+/*******************************************************************************
|
|
+ * DEBUG
|
|
+ ******************************************************************************/
|
|
+/*#define ICACHE_OFF*/
|
|
+/*#define DCACHE_OFF*/
|
|
+/*#define MMU_OFF*/
|
|
+
|
|
+/*******************************************************************************
|
|
+ * Device Tree defines
|
|
+ ******************************************************************************/
|
|
+#define DT_PWR_COMPAT "st,stm32mp1-pwr"
|
|
+#define DT_RCC_CLK_COMPAT "st,stm32mp1-rcc"
|
|
+#define DT_SYSCFG_COMPAT "st,stm32mp157-syscfg"
|
|
|
|
#endif /* STM32MP1_DEF_H */
|
|
diff --git a/plat/st/stm32mp1/stm32mp1_dt.c b/plat/st/stm32mp1/stm32mp1_dt.c
|
|
deleted file mode 100644
|
|
index bde968a..0000000
|
|
--- a/plat/st/stm32mp1/stm32mp1_dt.c
|
|
+++ /dev/null
|
|
@@ -1,476 +0,0 @@
|
|
-/*
|
|
- * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
|
|
- *
|
|
- * SPDX-License-Identifier: BSD-3-Clause
|
|
- */
|
|
-
|
|
-#include <assert.h>
|
|
-#include <debug.h>
|
|
-#include <libfdt.h>
|
|
-#include <platform_def.h>
|
|
-#include <stm32_gpio.h>
|
|
-#include <stm32mp1_clk.h>
|
|
-#include <stm32mp1_clkfunc.h>
|
|
-#include <stm32mp1_ddr.h>
|
|
-#include <stm32mp1_dt.h>
|
|
-#include <stm32mp1_ram.h>
|
|
-
|
|
-#define DT_GPIO_BANK_SHIFT 12
|
|
-#define DT_GPIO_BANK_MASK 0x1F000U
|
|
-#define DT_GPIO_PIN_SHIFT 8
|
|
-#define DT_GPIO_PIN_MASK 0xF00U
|
|
-#define DT_GPIO_MODE_MASK 0xFFU
|
|
-
|
|
-static int fdt_checked;
|
|
-
|
|
-static void *fdt = (void *)(uintptr_t)STM32MP1_DTB_BASE;
|
|
-
|
|
-/*******************************************************************************
|
|
- * This function gets the pin settings from DT information.
|
|
- * When analyze and parsing is done, set the GPIO registers.
|
|
- * Return 0 on success, else return a negative FDT_ERR_xxx error code.
|
|
- ******************************************************************************/
|
|
-static int dt_set_gpio_config(int node)
|
|
-{
|
|
- const fdt32_t *cuint, *slewrate;
|
|
- int len, pinctrl_node, pinctrl_subnode;
|
|
- uint32_t i;
|
|
- uint32_t speed = GPIO_SPEED_LOW;
|
|
- uint32_t pull = GPIO_NO_PULL;
|
|
-
|
|
- cuint = fdt_getprop(fdt, node, "pinmux", &len);
|
|
- if (cuint == NULL) {
|
|
- return -FDT_ERR_NOTFOUND;
|
|
- }
|
|
-
|
|
- pinctrl_node = fdt_parent_offset(fdt, fdt_parent_offset(fdt, node));
|
|
- if (pinctrl_node < 0) {
|
|
- return -FDT_ERR_NOTFOUND;
|
|
- }
|
|
-
|
|
- slewrate = fdt_getprop(fdt, node, "slew-rate", NULL);
|
|
- if (slewrate != NULL) {
|
|
- speed = fdt32_to_cpu(*slewrate);
|
|
- }
|
|
-
|
|
- if (fdt_getprop(fdt, node, "bias-pull-up", NULL) != NULL) {
|
|
- pull = GPIO_PULL_UP;
|
|
- } else if (fdt_getprop(fdt, node, "bias-pull-down", NULL) != NULL) {
|
|
- pull = GPIO_PULL_DOWN;
|
|
- } else {
|
|
- VERBOSE("No bias configured in node %d\n", node);
|
|
- }
|
|
-
|
|
- for (i = 0; i < ((uint32_t)len / sizeof(uint32_t)); i++) {
|
|
- uint32_t pincfg;
|
|
- uint32_t bank;
|
|
- uint32_t pin;
|
|
- uint32_t mode;
|
|
- uint32_t alternate = GPIO_ALTERNATE_0;
|
|
-
|
|
- pincfg = fdt32_to_cpu(*cuint);
|
|
- cuint++;
|
|
-
|
|
- bank = (pincfg & DT_GPIO_BANK_MASK) >> DT_GPIO_BANK_SHIFT;
|
|
-
|
|
- pin = (pincfg & DT_GPIO_PIN_MASK) >> DT_GPIO_PIN_SHIFT;
|
|
-
|
|
- mode = pincfg & DT_GPIO_MODE_MASK;
|
|
-
|
|
- switch (mode) {
|
|
- case 0:
|
|
- mode = GPIO_MODE_INPUT;
|
|
- break;
|
|
- case 1 ... 16:
|
|
- alternate = mode - 1U;
|
|
- mode = GPIO_MODE_ALTERNATE;
|
|
- break;
|
|
- case 17:
|
|
- mode = GPIO_MODE_ANALOG;
|
|
- break;
|
|
- default:
|
|
- mode = GPIO_MODE_OUTPUT;
|
|
- break;
|
|
- }
|
|
-
|
|
- if (fdt_getprop(fdt, node, "drive-open-drain", NULL) != NULL) {
|
|
- mode |= GPIO_OPEN_DRAIN;
|
|
- }
|
|
-
|
|
- fdt_for_each_subnode(pinctrl_subnode, fdt, pinctrl_node) {
|
|
- uint32_t bank_offset;
|
|
- const fdt32_t *cuint2;
|
|
-
|
|
- if (fdt_getprop(fdt, pinctrl_subnode,
|
|
- "gpio-controller", NULL) == NULL) {
|
|
- continue;
|
|
- }
|
|
-
|
|
- cuint2 = fdt_getprop(fdt, pinctrl_subnode, "reg", NULL);
|
|
- if (cuint2 == NULL) {
|
|
- continue;
|
|
- }
|
|
-
|
|
- if (bank == GPIO_BANK_Z) {
|
|
- bank_offset = 0;
|
|
- } else {
|
|
- bank_offset = bank * STM32_GPIO_BANK_OFFSET;
|
|
- }
|
|
-
|
|
- if (fdt32_to_cpu(*cuint2) == bank_offset) {
|
|
- int clk_id = fdt_get_clock_id(pinctrl_subnode);
|
|
-
|
|
- if (clk_id < 0) {
|
|
- return -FDT_ERR_NOTFOUND;
|
|
- }
|
|
-
|
|
- if (stm32mp1_clk_enable((unsigned long)clk_id) <
|
|
- 0) {
|
|
- return -FDT_ERR_BADVALUE;
|
|
- }
|
|
-
|
|
- break;
|
|
- }
|
|
- }
|
|
-
|
|
- set_gpio(bank, pin, mode, speed, pull, alternate);
|
|
- }
|
|
-
|
|
- return 0;
|
|
-}
|
|
-
|
|
-/*******************************************************************************
|
|
- * This function checks device tree file with its header.
|
|
- * Returns 0 if success, and a negative value else.
|
|
- ******************************************************************************/
|
|
-int dt_open_and_check(void)
|
|
-{
|
|
- int ret = fdt_check_header(fdt);
|
|
-
|
|
- if (ret == 0) {
|
|
- fdt_checked = 1;
|
|
- }
|
|
-
|
|
- return ret;
|
|
-}
|
|
-
|
|
-/*******************************************************************************
|
|
- * This function gets the address of the DT.
|
|
- * If DT is OK, fdt_addr is filled with DT address.
|
|
- * Returns 1 if success, 0 otherwise.
|
|
- ******************************************************************************/
|
|
-int fdt_get_address(void **fdt_addr)
|
|
-{
|
|
- if (fdt_checked == 1) {
|
|
- *fdt_addr = fdt;
|
|
- }
|
|
-
|
|
- return fdt_checked;
|
|
-}
|
|
-
|
|
-/*******************************************************************************
|
|
- * This function check the presence of a node (generic use of fdt library).
|
|
- * Returns true if present, false else.
|
|
- ******************************************************************************/
|
|
-bool fdt_check_node(int node)
|
|
-{
|
|
- int len;
|
|
- const char *cchar;
|
|
-
|
|
- cchar = fdt_get_name(fdt, node, &len);
|
|
-
|
|
- return (cchar != NULL) && (len >= 0);
|
|
-}
|
|
-
|
|
-/*******************************************************************************
|
|
- * This function check the status of a node (generic use of fdt library).
|
|
- * Returns true if "okay" or missing, false else.
|
|
- ******************************************************************************/
|
|
-bool fdt_check_status(int node)
|
|
-{
|
|
- int len;
|
|
- const char *cchar;
|
|
-
|
|
- cchar = fdt_getprop(fdt, node, "status", &len);
|
|
- if (cchar == NULL) {
|
|
- return true;
|
|
- }
|
|
-
|
|
- return strncmp(cchar, "okay", (size_t)len) == 0;
|
|
-}
|
|
-
|
|
-/*******************************************************************************
|
|
- * This function check the secure-status of a node (generic use of fdt library).
|
|
- * Returns true if "okay" or missing, false else.
|
|
- ******************************************************************************/
|
|
-bool fdt_check_secure_status(int node)
|
|
-{
|
|
- int len;
|
|
- const char *cchar;
|
|
-
|
|
- cchar = fdt_getprop(fdt, node, "secure-status", &len);
|
|
- if (cchar == NULL) {
|
|
- return true;
|
|
- }
|
|
-
|
|
- return strncmp(cchar, "okay", (size_t)len) == 0;
|
|
-}
|
|
-
|
|
-/*******************************************************************************
|
|
- * This function reads a value of a node property (generic use of fdt
|
|
- * library).
|
|
- * Returns value if success, and a default value if property not found.
|
|
- * Default value is passed as parameter.
|
|
- ******************************************************************************/
|
|
-uint32_t fdt_read_uint32_default(int node, const char *prop_name,
|
|
- uint32_t dflt_value)
|
|
-{
|
|
- const fdt32_t *cuint;
|
|
- int lenp;
|
|
-
|
|
- cuint = fdt_getprop(fdt, node, prop_name, &lenp);
|
|
- if (cuint == NULL) {
|
|
- return dflt_value;
|
|
- }
|
|
-
|
|
- return fdt32_to_cpu(*cuint);
|
|
-}
|
|
-
|
|
-/*******************************************************************************
|
|
- * This function reads a series of parameters in a node property
|
|
- * (generic use of fdt library).
|
|
- * It reads the values inside the device tree, from property name and node.
|
|
- * The number of parameters is also indicated as entry parameter.
|
|
- * Returns 0 if success, and a negative value else.
|
|
- * If success, values are stored at the third parameter address.
|
|
- ******************************************************************************/
|
|
-int fdt_read_uint32_array(int node, const char *prop_name, uint32_t *array,
|
|
- uint32_t count)
|
|
-{
|
|
- const fdt32_t *cuint;
|
|
- int len;
|
|
- uint32_t i;
|
|
-
|
|
- cuint = fdt_getprop(fdt, node, prop_name, &len);
|
|
- if (cuint == NULL) {
|
|
- return -FDT_ERR_NOTFOUND;
|
|
- }
|
|
-
|
|
- if ((uint32_t)len != (count * sizeof(uint32_t))) {
|
|
- return -FDT_ERR_BADLAYOUT;
|
|
- }
|
|
-
|
|
- for (i = 0; i < ((uint32_t)len / sizeof(uint32_t)); i++) {
|
|
- *array = fdt32_to_cpu(*cuint);
|
|
- array++;
|
|
- cuint++;
|
|
- }
|
|
-
|
|
- return 0;
|
|
-}
|
|
-
|
|
-/*******************************************************************************
|
|
- * This function gets the pin settings from DT information.
|
|
- * When analyze and parsing is done, set the GPIO registers.
|
|
- * Returns 0 if success, and a negative value else.
|
|
- ******************************************************************************/
|
|
-int dt_set_pinctrl_config(int node)
|
|
-{
|
|
- const fdt32_t *cuint;
|
|
- int lenp = 0;
|
|
- uint32_t i;
|
|
-
|
|
- if (!fdt_check_status(node)) {
|
|
- return -FDT_ERR_NOTFOUND;
|
|
- }
|
|
-
|
|
- cuint = fdt_getprop(fdt, node, "pinctrl-0", &lenp);
|
|
- if (cuint == NULL) {
|
|
- return -FDT_ERR_NOTFOUND;
|
|
- }
|
|
-
|
|
- for (i = 0; i < ((uint32_t)lenp / 4U); i++) {
|
|
- int phandle_node, phandle_subnode;
|
|
-
|
|
- phandle_node =
|
|
- fdt_node_offset_by_phandle(fdt, fdt32_to_cpu(*cuint));
|
|
- if (phandle_node < 0) {
|
|
- return -FDT_ERR_NOTFOUND;
|
|
- }
|
|
-
|
|
- fdt_for_each_subnode(phandle_subnode, fdt, phandle_node) {
|
|
- int ret = dt_set_gpio_config(phandle_subnode);
|
|
-
|
|
- if (ret < 0) {
|
|
- return ret;
|
|
- }
|
|
- }
|
|
-
|
|
- cuint++;
|
|
- }
|
|
-
|
|
- return 0;
|
|
-}
|
|
-
|
|
-/*******************************************************************************
|
|
- * This function gets the stdout pin configuration information from the DT.
|
|
- * And then calls the sub-function to treat it and set GPIO registers.
|
|
- * Returns 0 if success, and a negative value else.
|
|
- ******************************************************************************/
|
|
-int dt_set_stdout_pinctrl(void)
|
|
-{
|
|
- int node;
|
|
-
|
|
- node = dt_get_stdout_node_offset();
|
|
- if (node < 0) {
|
|
- return -FDT_ERR_NOTFOUND;
|
|
- }
|
|
-
|
|
- return dt_set_pinctrl_config(node);
|
|
-}
|
|
-
|
|
-/*******************************************************************************
|
|
- * This function fills the generic information from a given node.
|
|
- ******************************************************************************/
|
|
-void dt_fill_device_info(struct dt_node_info *info, int node)
|
|
-{
|
|
- const fdt32_t *cuint;
|
|
-
|
|
- cuint = fdt_getprop(fdt, node, "reg", NULL);
|
|
- if (cuint != NULL) {
|
|
- info->base = fdt32_to_cpu(*cuint);
|
|
- } else {
|
|
- info->base = 0;
|
|
- }
|
|
-
|
|
- cuint = fdt_getprop(fdt, node, "clocks", NULL);
|
|
- if (cuint != NULL) {
|
|
- cuint++;
|
|
- info->clock = (int)fdt32_to_cpu(*cuint);
|
|
- } else {
|
|
- info->clock = -1;
|
|
- }
|
|
-
|
|
- cuint = fdt_getprop(fdt, node, "resets", NULL);
|
|
- if (cuint != NULL) {
|
|
- cuint++;
|
|
- info->reset = (int)fdt32_to_cpu(*cuint);
|
|
- } else {
|
|
- info->reset = -1;
|
|
- }
|
|
-
|
|
- info->status = fdt_check_status(node);
|
|
- info->sec_status = fdt_check_secure_status(node);
|
|
-}
|
|
-
|
|
-/*******************************************************************************
|
|
- * This function retrieve the generic information from DT.
|
|
- * Returns node if success, and a negative value else.
|
|
- ******************************************************************************/
|
|
-int dt_get_node(struct dt_node_info *info, int offset, const char *compat)
|
|
-{
|
|
- int node;
|
|
-
|
|
- node = fdt_node_offset_by_compatible(fdt, offset, compat);
|
|
- if (node < 0) {
|
|
- return -FDT_ERR_NOTFOUND;
|
|
- }
|
|
-
|
|
- dt_fill_device_info(info, node);
|
|
-
|
|
- return node;
|
|
-}
|
|
-
|
|
-/*******************************************************************************
|
|
- * This function gets the UART instance info of stdout from the DT.
|
|
- * Returns node if success, and a negative value else.
|
|
- ******************************************************************************/
|
|
-int dt_get_stdout_uart_info(struct dt_node_info *info)
|
|
-{
|
|
- int node;
|
|
-
|
|
- node = dt_get_stdout_node_offset();
|
|
- if (node < 0) {
|
|
- return -FDT_ERR_NOTFOUND;
|
|
- }
|
|
-
|
|
- dt_fill_device_info(info, node);
|
|
-
|
|
- return node;
|
|
-}
|
|
-
|
|
-/*******************************************************************************
|
|
- * This function gets the stdout path node.
|
|
- * It reads the value indicated inside the device tree.
|
|
- * Returns node if success, and a negative value else.
|
|
- ******************************************************************************/
|
|
-int dt_get_stdout_node_offset(void)
|
|
-{
|
|
- int node;
|
|
- const char *cchar;
|
|
-
|
|
- node = fdt_path_offset(fdt, "/chosen");
|
|
- if (node < 0) {
|
|
- return -FDT_ERR_NOTFOUND;
|
|
- }
|
|
-
|
|
- cchar = fdt_getprop(fdt, node, "stdout-path", NULL);
|
|
- if (cchar == NULL) {
|
|
- return -FDT_ERR_NOTFOUND;
|
|
- }
|
|
-
|
|
- node = -FDT_ERR_NOTFOUND;
|
|
- if (strchr(cchar, (int)':') != NULL) {
|
|
- const char *name;
|
|
- char *str = (char *)cchar;
|
|
- int len = 0;
|
|
-
|
|
- while (strncmp(":", str, 1)) {
|
|
- len++;
|
|
- str++;
|
|
- }
|
|
-
|
|
- name = fdt_get_alias_namelen(fdt, cchar, len);
|
|
-
|
|
- if (name != NULL) {
|
|
- node = fdt_path_offset(fdt, name);
|
|
- }
|
|
- } else {
|
|
- node = fdt_path_offset(fdt, cchar);
|
|
- }
|
|
-
|
|
- return node;
|
|
-}
|
|
-
|
|
-/*******************************************************************************
|
|
- * This function gets DDR size information from the DT.
|
|
- * Returns value in bytes if success, and STM32MP1_DDR_SIZE_DFLT else.
|
|
- ******************************************************************************/
|
|
-uint32_t dt_get_ddr_size(void)
|
|
-{
|
|
- int node;
|
|
-
|
|
- node = fdt_node_offset_by_compatible(fdt, -1, DT_DDR_COMPAT);
|
|
- if (node < 0) {
|
|
- INFO("%s: Cannot read DDR node in DT\n", __func__);
|
|
- return STM32MP1_DDR_SIZE_DFLT;
|
|
- }
|
|
-
|
|
- return fdt_read_uint32_default(node, "st,mem-size",
|
|
- STM32MP1_DDR_SIZE_DFLT);
|
|
-}
|
|
-
|
|
-/*******************************************************************************
|
|
- * This function retrieves board model from DT
|
|
- * Returns string taken from model node, NULL otherwise
|
|
- ******************************************************************************/
|
|
-const char *dt_get_board_model(void)
|
|
-{
|
|
- int node = fdt_path_offset(fdt, "/");
|
|
-
|
|
- if (node < 0) {
|
|
- return NULL;
|
|
- }
|
|
-
|
|
- return (const char *)fdt_getprop(fdt, node, "model", NULL);
|
|
-}
|
|
diff --git a/plat/st/stm32mp1/stm32mp1_gic.c b/plat/st/stm32mp1/stm32mp1_gic.c
|
|
index 11eb0a3..498093d 100644
|
|
--- a/plat/st/stm32mp1/stm32mp1_gic.c
|
|
+++ b/plat/st/stm32mp1/stm32mp1_gic.c
|
|
@@ -4,13 +4,21 @@
|
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
*/
|
|
|
|
+#include <assert.h>
|
|
#include <bl_common.h>
|
|
+#include <dt-bindings/interrupt-controller/arm-gic.h>
|
|
#include <gicv2.h>
|
|
+#include <libfdt.h>
|
|
#include <platform.h>
|
|
#include <platform_def.h>
|
|
+#include <stm32mp_common.h>
|
|
+#include <stm32mp_dt.h>
|
|
#include <utils.h>
|
|
|
|
-#include <stm32mp1_private.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
|
|
@@ -21,19 +29,114 @@ static const interrupt_prop_t stm32mp1_interrupt_props[] = {
|
|
PLATFORM_G0_PROPS(GICV2_INTR_GROUP0)
|
|
};
|
|
|
|
-static unsigned int target_mask_array[PLATFORM_CORE_COUNT];
|
|
+/* Fix target_mask_array as secondary core is not able to initialize it */
|
|
+static unsigned int target_mask_array[PLATFORM_CORE_COUNT] = {1, 2};
|
|
|
|
-static const gicv2_driver_data_t platform_gic_data = {
|
|
- .gicd_base = STM32MP1_GICD_BASE,
|
|
- .gicc_base = STM32MP1_GICC_BASE,
|
|
+static gicv2_driver_data_t platform_gic_data = {
|
|
.interrupt_props = stm32mp1_interrupt_props,
|
|
.interrupt_props_num = ARRAY_SIZE(stm32mp1_interrupt_props),
|
|
.target_masks = target_mask_array,
|
|
.target_masks_num = ARRAY_SIZE(target_mask_array),
|
|
};
|
|
|
|
+static struct stm32_gic_instance stm32_gic;
|
|
+
|
|
+static uint32_t enable_gic_interrupt(const fdt32_t *array)
|
|
+{
|
|
+ unsigned int id, cfg;
|
|
+
|
|
+ switch (fdt32_to_cpu(*array)) {
|
|
+ case GIC_SPI:
|
|
+ id = MIN_SPI_ID;
|
|
+ break;
|
|
+
|
|
+ case GIC_PPI:
|
|
+ id = MIN_PPI_ID;
|
|
+ break;
|
|
+
|
|
+ default:
|
|
+ id = MIN_SGI_ID;
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ id += fdt32_to_cpu(*(array + 1));
|
|
+ cfg = (fdt32_to_cpu(*(array + 2)) < IRQ_TYPE_LEVEL_HIGH) ?
|
|
+ GIC_INTR_CFG_EDGE : GIC_INTR_CFG_LEVEL;
|
|
+
|
|
+ if ((id >= MIN_SPI_ID) && (id <= MAX_SPI_ID)) {
|
|
+ VERBOSE("Enable IT %i\n", id);
|
|
+ gicv2_set_interrupt_type(id, GICV2_INTR_GROUP0);
|
|
+ gicv2_set_interrupt_priority(id, STM32MP1_IRQ_SEC_SPI_PRIO);
|
|
+ gicv2_set_spi_routing(id, STM32MP_PRIMARY_CPU);
|
|
+ gicv2_interrupt_set_cfg(id, cfg);
|
|
+ gicv2_enable_interrupt(id);
|
|
+ }
|
|
+
|
|
+ return id;
|
|
+}
|
|
+
|
|
+static void find_next_interrupt(const fdt32_t **array)
|
|
+{
|
|
+ int node;
|
|
+ const fdt32_t *cuint;
|
|
+ void *fdt;
|
|
+
|
|
+ assert(fdt32_to_cpu(**array) != stm32_gic.phandle_node);
|
|
+
|
|
+ if (fdt_get_address(&fdt) == 0) {
|
|
+ panic();
|
|
+ }
|
|
+
|
|
+ node = fdt_node_offset_by_phandle(fdt, fdt32_to_cpu(**array));
|
|
+ if (node < 0) {
|
|
+ panic();
|
|
+ }
|
|
+
|
|
+ cuint = fdt_getprop(fdt, node, "#interrupt-cells", NULL);
|
|
+ if (cuint == NULL) {
|
|
+ panic();
|
|
+ }
|
|
+
|
|
+ *array += fdt32_to_cpu(*cuint) + 1;
|
|
+}
|
|
+
|
|
void stm32mp1_gic_init(void)
|
|
{
|
|
+ int node;
|
|
+ void *fdt;
|
|
+ const fdt32_t *cuint;
|
|
+ struct dt_node_info dt_gic;
|
|
+
|
|
+ if (fdt_get_address(&fdt) == 0) {
|
|
+ panic();
|
|
+ }
|
|
+
|
|
+ node = dt_get_node(&dt_gic, -1, "arm,cortex-a7-gic");
|
|
+ if (node < 0) {
|
|
+ panic();
|
|
+ }
|
|
+
|
|
+ platform_gic_data.gicd_base = dt_gic.base;
|
|
+
|
|
+ cuint = fdt_getprop(fdt, node, "reg", NULL);
|
|
+ if (cuint == NULL) {
|
|
+ panic();
|
|
+ }
|
|
+
|
|
+ platform_gic_data.gicc_base = fdt32_to_cpu(*(cuint + 2));
|
|
+
|
|
+ cuint = fdt_getprop(fdt, node, "#interrupt-cells", NULL);
|
|
+ if (cuint == NULL) {
|
|
+ panic();
|
|
+ }
|
|
+
|
|
+ stm32_gic.cells = fdt32_to_cpu(*cuint);
|
|
+
|
|
+ stm32_gic.phandle_node = fdt_get_phandle(fdt, node);
|
|
+ if (stm32_gic.phandle_node == 0U) {
|
|
+ panic();
|
|
+ }
|
|
+
|
|
gicv2_driver_init(&platform_gic_data);
|
|
gicv2_distif_init();
|
|
|
|
@@ -46,3 +149,63 @@ void stm32mp1_gic_pcpu_init(void)
|
|
gicv2_set_pe_target_mask(plat_my_core_pos());
|
|
gicv2_cpuif_enable();
|
|
}
|
|
+
|
|
+int stm32_gic_enable_spi(int node, const char *name)
|
|
+{
|
|
+ const fdt32_t *cuint;
|
|
+ void *fdt;
|
|
+ int res, len;
|
|
+ int index = -1;
|
|
+ int i = 0;
|
|
+ int id = -1;
|
|
+ bool extended;
|
|
+ const fdt32_t *t_array, *max;
|
|
+
|
|
+ if (fdt_get_address(&fdt) == 0) {
|
|
+ panic();
|
|
+ }
|
|
+
|
|
+ cuint = fdt_getprop(fdt, node, "interrupt-parent", NULL);
|
|
+ if (cuint != NULL) {
|
|
+ if (stm32_gic.phandle_node != fdt32_to_cpu(*cuint)) {
|
|
+ return -FDT_ERR_NOTFOUND;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (name != NULL) {
|
|
+ index = fdt_stringlist_search(fdt, node, "interrupt-names",
|
|
+ name);
|
|
+ if (index < 0) {
|
|
+ return index;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ res = fdt_get_interrupt(node, &t_array, &len, &extended);
|
|
+ if (res < 0) {
|
|
+ return res;
|
|
+ }
|
|
+
|
|
+ max = t_array + (len / sizeof(uint32_t));
|
|
+
|
|
+ while ((t_array < max) && ((i <= index) || (index == -1))) {
|
|
+ if (!extended) {
|
|
+ if ((index == -1) || (i == index)) {
|
|
+ id = enable_gic_interrupt(t_array);
|
|
+ }
|
|
+ t_array += stm32_gic.cells;
|
|
+ } else {
|
|
+ if (fdt32_to_cpu(*t_array) == stm32_gic.phandle_node) {
|
|
+ t_array++;
|
|
+ if ((index == -1) || (i == index)) {
|
|
+ id = enable_gic_interrupt(t_array);
|
|
+ }
|
|
+ t_array += stm32_gic.cells;
|
|
+ } else {
|
|
+ find_next_interrupt(&t_array);
|
|
+ }
|
|
+ }
|
|
+ i++;
|
|
+ }
|
|
+
|
|
+ return id;
|
|
+}
|
|
diff --git a/plat/st/stm32mp1/stm32mp1_helper.S b/plat/st/stm32mp1/stm32mp1_helper.S
|
|
index b0ea0d8..1adaaee 100644
|
|
--- a/plat/st/stm32mp1/stm32mp1_helper.S
|
|
+++ b/plat/st/stm32mp1/stm32mp1_helper.S
|
|
@@ -8,17 +8,20 @@
|
|
#include <asm_macros.S>
|
|
#include <bl_common.h>
|
|
#include <platform_def.h>
|
|
+#include <smccc_helpers.h>
|
|
#include <stm32_gpio.h>
|
|
#include <stm32mp1_rcc.h>
|
|
|
|
-#define GPIO_BANK_G_ADDRESS 0x50008000
|
|
-#define GPIO_TX_PORT 11
|
|
-#define GPIO_TX_SHIFT (GPIO_TX_PORT << 1)
|
|
-#define GPIO_TX_ALT_SHIFT ((GPIO_TX_PORT - GPIO_ALT_LOWER_LIMIT) << 2)
|
|
-#define STM32MP1_HSI_CLK 64000000
|
|
+#define GPIO_TX_SHIFT (DEBUG_UART_TX_GPIO_PORT << 1)
|
|
+#define GPIO_TX_ALT_SHIFT ((DEBUG_UART_TX_GPIO_PORT - GPIO_ALT_LOWER_LIMIT) << 2)
|
|
|
|
.globl platform_mem_init
|
|
.globl plat_report_exception
|
|
+#if AARCH32_EXCEPTION_DEBUG
|
|
+ .globl plat_report_undef_inst
|
|
+ .globl plat_report_prefetch_abort
|
|
+ .globl plat_report_data_abort
|
|
+#endif
|
|
.globl plat_get_my_entrypoint
|
|
.globl plat_secondary_cold_boot_setup
|
|
.globl plat_reset_handler
|
|
@@ -28,6 +31,7 @@
|
|
.globl plat_crash_console_flush
|
|
.globl plat_crash_console_putc
|
|
.globl plat_panic_handler
|
|
+ .globl wfi_svc_int_enable
|
|
|
|
func platform_mem_init
|
|
/* Nothing to do, don't need to init SYSRAM */
|
|
@@ -35,9 +39,138 @@ func platform_mem_init
|
|
endfunc platform_mem_init
|
|
|
|
func plat_report_exception
|
|
+#if DEBUG
|
|
+ mov r8, lr
|
|
+
|
|
+ /* Test if an abort occurred */
|
|
+ cmp r0, #MODE32_abt
|
|
+ bne undef_inst_lbl
|
|
+ ldr r4, =abort_str
|
|
+ bl asm_print_str
|
|
+ b print_excpetion_info
|
|
+
|
|
+undef_inst_lbl:
|
|
+ /* Test for an undefined instruction */
|
|
+ cmp r0, #MODE32_und
|
|
+ bne other_excpetion_lbl
|
|
+ ldr r4, =undefined_str
|
|
+ bl asm_print_str
|
|
+ b print_excpetion_info
|
|
+
|
|
+other_excpetion_lbl:
|
|
+ /* Other exceptions */
|
|
+ mov r9, r0
|
|
+ ldr r4, =exception_start_str
|
|
+ bl asm_print_str
|
|
+ mov r4, r9
|
|
+ bl asm_print_hex
|
|
+ ldr r4, =exception_end_str
|
|
+ bl asm_print_str
|
|
+
|
|
+print_excpetion_info:
|
|
+ mrs r4, lr_svc
|
|
+ sub r4, r4, #4
|
|
+ bl asm_print_hex
|
|
+
|
|
+ ldr r4, =end_error_str
|
|
+ bl asm_print_str
|
|
+
|
|
+ bx r8
|
|
+#else
|
|
bx lr
|
|
+#endif
|
|
endfunc plat_report_exception
|
|
|
|
+#if AARCH32_EXCEPTION_DEBUG
|
|
+func plat_report_undef_inst
|
|
+#if DEBUG
|
|
+ mov r8, lr
|
|
+
|
|
+ mov r9, r0
|
|
+
|
|
+ ldr r4, =undefined_str
|
|
+ bl asm_print_str
|
|
+
|
|
+ mov r4, r9
|
|
+ sub r4, r4, #4
|
|
+ bl asm_print_hex
|
|
+
|
|
+ ldr r4, =end_error_str
|
|
+ bl asm_print_str
|
|
+
|
|
+ bx r8
|
|
+#else
|
|
+ bx lr
|
|
+#endif
|
|
+endfunc plat_report_undef_inst
|
|
+
|
|
+func plat_report_prefetch_abort
|
|
+#if DEBUG
|
|
+ mov r8, lr
|
|
+ mov r9, r0
|
|
+
|
|
+ ldr r4, =prefetch_abort_str
|
|
+ bl asm_print_str
|
|
+
|
|
+ mov r4, r9
|
|
+ sub r4, r4, #4
|
|
+ bl asm_print_hex
|
|
+
|
|
+ ldr r4, =ifsr_str
|
|
+ bl asm_print_str
|
|
+
|
|
+ ldcopr r4, IFSR
|
|
+ bl asm_print_hex
|
|
+
|
|
+ ldr r4, =ifar_str
|
|
+ bl asm_print_str
|
|
+
|
|
+ ldcopr r4, IFAR
|
|
+ bl asm_print_hex
|
|
+
|
|
+ ldr r4, =end_error_str
|
|
+ bl asm_print_str
|
|
+
|
|
+ bx r8
|
|
+#else
|
|
+ bx lr
|
|
+#endif
|
|
+endfunc plat_report_prefetch_abort
|
|
+
|
|
+func plat_report_data_abort
|
|
+#if DEBUG
|
|
+ mov r8, lr
|
|
+ mov r9, r0
|
|
+
|
|
+ ldr r4, =data_abort_str
|
|
+ bl asm_print_str
|
|
+
|
|
+ mov r4, r9
|
|
+ sub r4, r4, #8
|
|
+ bl asm_print_hex
|
|
+
|
|
+ ldr r4, =dfsr_str
|
|
+ bl asm_print_str
|
|
+
|
|
+ ldcopr r4, DFSR
|
|
+ bl asm_print_hex
|
|
+
|
|
+ ldr r4, =dfar_str
|
|
+ bl asm_print_str
|
|
+
|
|
+ ldcopr r4, DFAR
|
|
+ bl asm_print_hex
|
|
+
|
|
+ ldr r4, =end_error_str
|
|
+ bl asm_print_str
|
|
+
|
|
+ bx r8
|
|
+#else
|
|
+ bx lr
|
|
+#endif
|
|
+endfunc plat_report_data_abort
|
|
+#endif
|
|
+
|
|
func plat_reset_handler
|
|
bx lr
|
|
endfunc plat_reset_handler
|
|
@@ -76,7 +209,7 @@ func plat_is_my_cpu_primary
|
|
ldcopr r0, MPIDR
|
|
ldr r1, =(MPIDR_CLUSTER_MASK | MPIDR_CPU_MASK)
|
|
and r0, r1
|
|
- cmp r0, #STM32MP1_PRIMARY_CPU
|
|
+ cmp r0, #STM32MP_PRIMARY_CPU
|
|
moveq r0, #1
|
|
movne r0, #0
|
|
bx lr
|
|
@@ -111,13 +244,13 @@ endfunc plat_my_core_pos
|
|
* ---------------------------------------------
|
|
*/
|
|
func plat_crash_console_init
|
|
- /* Enable GPIOs for UART4 TX */
|
|
- ldr r1, =(RCC_BASE + RCC_MP_AHB4ENSETR)
|
|
+ /* Enable GPIOs for UART TX */
|
|
+ ldr r1, =(RCC_BASE + DEBUG_UART_TX_GPIO_BANK_CLK_REG)
|
|
ldr r2, [r1]
|
|
- /* Configure GPIO G11 */
|
|
- orr r2, r2, #RCC_MP_AHB4ENSETR_GPIOGEN
|
|
+ /* Configure GPIO */
|
|
+ orr r2, r2, #DEBUG_UART_TX_GPIO_BANK_CLK_EN
|
|
str r2, [r1]
|
|
- ldr r1, =GPIO_BANK_G_ADDRESS
|
|
+ ldr r1, =DEBUG_UART_TX_GPIO_BANK_ADDRESS
|
|
/* Set GPIO mode alternate */
|
|
ldr r2, [r1, #GPIO_MODE_OFFSET]
|
|
bic r2, r2, #(GPIO_MODE_MASK << GPIO_TX_SHIFT)
|
|
@@ -131,25 +264,24 @@ func plat_crash_console_init
|
|
ldr r2, [r1, #GPIO_PUPD_OFFSET]
|
|
bic r2, r2, #(GPIO_PULL_MASK << GPIO_TX_SHIFT)
|
|
str r2, [r1, #GPIO_PUPD_OFFSET]
|
|
- /* Set alternate AF6 */
|
|
+ /* Set alternate */
|
|
ldr r2, [r1, #GPIO_AFRH_OFFSET]
|
|
bic r2, r2, #(GPIO_ALTERNATE_MASK << GPIO_TX_ALT_SHIFT)
|
|
- orr r2, r2, #(GPIO_ALTERNATE_6 << GPIO_TX_ALT_SHIFT)
|
|
+ orr r2, r2, #(DEBUG_UART_TX_GPIO_ALTERNATE << GPIO_TX_ALT_SHIFT)
|
|
str r2, [r1, #GPIO_AFRH_OFFSET]
|
|
-
|
|
- /* Enable UART clock, with HSI source */
|
|
- ldr r1, =(RCC_BASE + RCC_UART24CKSELR)
|
|
- mov r2, #RCC_UART24CKSELR_HSI
|
|
+ /* Enable UART clock, with its source */
|
|
+ ldr r1, =(RCC_BASE + DEBUG_UART_TX_CLKSRC_REG)
|
|
+ mov r2, #DEBUG_UART_TX_CLKSRC
|
|
str r2, [r1]
|
|
- ldr r1, =(RCC_BASE + RCC_MP_APB1ENSETR)
|
|
+ ldr r1, =(RCC_BASE + DEBUG_UART_TX_EN_REG)
|
|
ldr r2, [r1]
|
|
- orr r2, r2, #RCC_MP_APB1ENSETR_UART4EN
|
|
+ orr r2, r2, #DEBUG_UART_TX_EN
|
|
str r2, [r1]
|
|
|
|
- ldr r0, =STM32MP1_DEBUG_USART_BASE
|
|
- ldr r1, =STM32MP1_HSI_CLK
|
|
- ldr r2, =STM32MP1_UART_BAUDRATE
|
|
- b console_core_init
|
|
+ ldr r0, =STM32MP_DEBUG_USART_BASE
|
|
+ ldr r1, =STM32MP_DEBUG_USART_CLK_FRQ
|
|
+ ldr r2, =STM32MP_UART_BAUDRATE
|
|
+ b console_stm32_core_init
|
|
endfunc plat_crash_console_init
|
|
|
|
/* ---------------------------------------------
|
|
@@ -159,8 +291,8 @@ endfunc plat_crash_console_init
|
|
* ---------------------------------------------
|
|
*/
|
|
func plat_crash_console_flush
|
|
- ldr r1, =STM32MP1_DEBUG_USART_BASE
|
|
- b console_core_flush
|
|
+ ldr r1, =STM32MP_DEBUG_USART_BASE
|
|
+ b console_stm32_core_flush
|
|
endfunc plat_crash_console_flush
|
|
|
|
/* ---------------------------------------------
|
|
@@ -175,6 +307,68 @@ endfunc plat_crash_console_flush
|
|
* ---------------------------------------------
|
|
*/
|
|
func plat_crash_console_putc
|
|
- ldr r1, =STM32MP1_DEBUG_USART_BASE
|
|
- b console_core_putc
|
|
+ ldr r1, =STM32MP_DEBUG_USART_BASE
|
|
+ b console_stm32_core_putc
|
|
endfunc plat_crash_console_putc
|
|
+
|
|
+ /* -----------------------------------------------------
|
|
+ * void plat_panic_handler(void) __dead2;
|
|
+ * Report exception + endless loop.
|
|
+ * -----------------------------------------------------
|
|
+ */
|
|
+func plat_panic_handler
|
|
+ mrs r0, cpsr
|
|
+ and r0, #MODE32_MASK
|
|
+ bl plat_report_exception
|
|
+ b .
|
|
+endfunc plat_panic_handler
|
|
+
|
|
+#if DEBUG
|
|
+.section .rodata.rev_err_str, "aS"
|
|
+abort_str:
|
|
+ .asciz "\nAbort at: 0x"
|
|
+#if AARCH32_EXCEPTION_DEBUG
|
|
+prefetch_abort_str:
|
|
+ .asciz "\nPrefetch Abort at: 0x"
|
|
+data_abort_str:
|
|
+ .asciz "\nData Abort at: 0x"
|
|
+#endif
|
|
+undefined_str:
|
|
+ .asciz "\nUndefined instruction at: 0x"
|
|
+exception_start_str:
|
|
+ .asciz "\nException mode=0x"
|
|
+exception_end_str:
|
|
+ .asciz " at: 0x"
|
|
+#if AARCH32_EXCEPTION_DEBUG
|
|
+dfsr_str:
|
|
+ .asciz " DFSR = 0x"
|
|
+dfar_str:
|
|
+ .asciz " DFAR = 0x"
|
|
+ifsr_str:
|
|
+ .asciz " IFSR = 0x"
|
|
+ifar_str:
|
|
+ .asciz " IFAR = 0x"
|
|
+#endif
|
|
+end_error_str:
|
|
+ .asciz "\n\r"
|
|
+#endif
|
|
+
|
|
+func wfi_svc_int_enable
|
|
+ push {r4,r8,lr}
|
|
+ ldcopr r4, SCR
|
|
+ mov r8, sp
|
|
+ mov sp, r0
|
|
+ add r0, r0, #STM32MP_INT_STACK_SIZE
|
|
+ str r0, [sp, #SMC_CTX_SP_MON]
|
|
+ str r4, [sp, #SMC_CTX_SCR]
|
|
+ cps #MODE32_svc
|
|
+ cpsie af
|
|
+ isb
|
|
+ dsb
|
|
+ wfi
|
|
+ cpsid af
|
|
+ cps #MODE32_mon
|
|
+ mov sp, r8
|
|
+ pop {r4,r8,lr}
|
|
+ bx lr
|
|
+endfunc wfi_svc_int_enable
|
|
diff --git a/plat/st/stm32mp1/stm32mp1_helper_dbg.S b/plat/st/stm32mp1/stm32mp1_helper_dbg.S
|
|
new file mode 100644
|
|
index 0000000..32a86fb
|
|
--- /dev/null
|
|
+++ b/plat/st/stm32mp1/stm32mp1_helper_dbg.S
|
|
@@ -0,0 +1,227 @@
|
|
+/*
|
|
+ * Copyright (c) 2019, STMicroelectronics - All Rights Reserved
|
|
+ *
|
|
+ * SPDX-License-Identifier: BSD-3-Clause
|
|
+ */
|
|
+
|
|
+/*****************************************************************************
|
|
+ * This file is only needed for current Soc revision which has a limitation on
|
|
+ * debug reset halt. This can be removed when using the Soc revision that
|
|
+ * fixes the limitation. Anyway, this source code identifies the Soc revision
|
|
+ * and is only executed if it corresponds, so it can be kept on other
|
|
+ * revisions without any consequence.
|
|
+ ****************************************************************************/
|
|
+
|
|
+/*****************************************************************************
|
|
+ * This file has been intentionally transformed in order to use only ASM
|
|
+ * standard macros and instructions. It could then be easily back-ported to
|
|
+ * other pieces of software.
|
|
+ ****************************************************************************/
|
|
+
|
|
+#define BIT_(nr) ((1) << (nr))
|
|
+
|
|
+#define BSEC_BASE 0x5C005000
|
|
+#define BSEC_OTP_DATA_OFF (BSEC_BASE + 0x200)
|
|
+#define BSEC_OTP_DATA0 BSEC_OTP_DATA_OFF
|
|
+#define BSEC_OTP_DATA0_CLOSED BIT_(6)
|
|
+
|
|
+#define DBGMCU_BASE 0x50081000
|
|
+#define DBGMCU_IDC 0x00
|
|
+#define DBGMCU_IDC_REV_ID_DEV_ID_MSK 0xFFFF0FFF
|
|
+#define DBGMCU_IDC_REV_ID_DEV_ID_VALUE 0x20000500
|
|
+
|
|
+#define RCC_BASE 0x50000000
|
|
+#define RCC_MP_APB5ENSETR 0x208
|
|
+#define RCC_MP_APB5ENSETR_RTCAPBEN BIT_(8)
|
|
+#define RCC_DBGCFGR 0x80C
|
|
+#define RCC_DBGCFGR_DBGCKEN BIT_(8)
|
|
+
|
|
+#define PWR_BASE 0x50001000
|
|
+#define PWR_CR1 0x00
|
|
+#define PWR_CR1_DBP BIT_(8)
|
|
+
|
|
+#define TAMP_BASE 0x5C00A000
|
|
+#define TAMP_BKP_REGISTER_BASE TAMP_BASE + 0x100
|
|
+#define TAMP_BKP_REGISTER_20 TAMP_BKP_REGISTER_BASE + (20 << 2)
|
|
+
|
|
+#define CA7_DBG0_BASE 0x500D0000
|
|
+#define DBG_DSCR 0x88
|
|
+#define DBG_DSCR_HDBGEN BIT_(14)
|
|
+
|
|
+#define FSBL_ENTRYPOINT bl2_entrypoint
|
|
+
|
|
+ .globl plat_dbg_attach_loop
|
|
+
|
|
+
|
|
+plat_dbg_attach_loop:
|
|
+ /*
|
|
+ * This function is the first call of FSBL_ENTRYPOINT.
|
|
+ * Boot rom parameters are stored in r0..r3, so we mustn't use them
|
|
+ * here. And because they are saved in r9..r12 just after the
|
|
+ * execution of this function, we should only use these registers.
|
|
+ * By this way, debug will be done in conditions closed to the initial
|
|
+ * context.
|
|
+ */
|
|
+
|
|
+ /*
|
|
+ * Check Sec Close bit in OTP (word 0 bit 6). If enabled, do not allow
|
|
+ * debug session and exit function.
|
|
+ */
|
|
+ ldr r12, =BSEC_OTP_DATA0
|
|
+ ldr r12, [r12]
|
|
+ ands r11, r12, #BSEC_OTP_DATA0_CLOSED
|
|
+ bne func_exit
|
|
+
|
|
+ /*
|
|
+ * Enable DBGMCU clock (only if not done).
|
|
+ * Initial register content will be saved in r10.
|
|
+ * So r10 mustn't be used before restore part.
|
|
+ */
|
|
+ ldr r12, =(RCC_BASE + RCC_DBGCFGR)
|
|
+ ldr r10, [r12]
|
|
+ tst r10, #RCC_DBGCFGR_DBGCKEN
|
|
+ bne dbgmcu_clk_enabled
|
|
+ orr r11, r10, #RCC_DBGCFGR_DBGCKEN
|
|
+ str r11, [r12]
|
|
+
|
|
+ /* Get SoC revision ID and device ID in r11 */
|
|
+dbgmcu_clk_enabled:
|
|
+ ldr r12, =(DBGMCU_BASE + DBGMCU_IDC)
|
|
+ ldr r12, [r12]
|
|
+ and r11, r12, #DBGMCU_IDC_REV_ID_DEV_ID_MSK
|
|
+
|
|
+ /* Restore initial RCC_DBGCFGR content saved in r10 */
|
|
+ ldr r12, =(RCC_BASE + RCC_DBGCFGR)
|
|
+ str r10, [r12]
|
|
+
|
|
+ /*
|
|
+ * Check SoC revision ID and device ID in r11,
|
|
+ * exit if different from REV_ID_DEV_ID_VALUE
|
|
+ */
|
|
+ ldr r12, =(DBGMCU_IDC_REV_ID_DEV_ID_VALUE)
|
|
+ teq r11, r12
|
|
+ bne func_exit
|
|
+
|
|
+ /*
|
|
+ * Enable RTC clock before reading tamper (only if not done).
|
|
+ * Initial register content will be saved in r10.
|
|
+ * So r10 mustn't be used before restore part.
|
|
+ */
|
|
+ ldr r12, =(RCC_BASE + RCC_MP_APB5ENSETR)
|
|
+ ldr r10, [r12]
|
|
+ tst r10, #RCC_MP_APB5ENSETR_RTCAPBEN
|
|
+ bne rtc_clk_enabled
|
|
+ orr r11, r10, #RCC_MP_APB5ENSETR_RTCAPBEN
|
|
+ str r11, [r12]
|
|
+
|
|
+rtc_clk_enabled:
|
|
+ /*
|
|
+ * Disable the backup domain write protection (only if not done).
|
|
+ * Initial register content will be saved in r9.
|
|
+ * So r9 mustn't be used before restore part.
|
|
+ */
|
|
+ ldr r12, =(PWR_BASE + PWR_CR1)
|
|
+ ldr r9, [r12]
|
|
+ tst r9, #PWR_CR1_DBP
|
|
+ bne poll_dbp
|
|
+ orr r11, r9, #PWR_CR1_DBP
|
|
+ str r11, [r12]
|
|
+poll_dbp:
|
|
+ /* poll loop to ensure write is effective */
|
|
+ ldr r11, [r12]
|
|
+ tst r11, #PWR_CR1_DBP
|
|
+ beq poll_dbp
|
|
+
|
|
+ /*
|
|
+ * Clear bit 16 of TAMPER backup register 20 (only if set).
|
|
+ * Firstly read the register value.
|
|
+ * - If bit = 0, r11 = 0 after 'ands' operation. Next step is to
|
|
+ * restore RCC_MP_APB5ENSETR and PWR_CR1 contents and exit.
|
|
+ * - If bit = 1, r11 != 0 after 'ands' operation, but could be
|
|
+ * equal to 0 after 'bic' operation. Here, after clearing the bit,
|
|
+ * r11 has to be set to a non-zero value. Next step is to restore
|
|
+ * register contents and continue.
|
|
+ *
|
|
+ * So r11 mustn't be used in restore part, to keep this information
|
|
+ * for the next step, i.e. decide to continue execution (r11 = 1) or
|
|
+ * exit function (r11 = 0).
|
|
+ */
|
|
+ ldr r12, =(TAMP_BKP_REGISTER_20)
|
|
+ ldr r11, [r12]
|
|
+ ands r11, r11, #(BIT_(16))
|
|
+ beq restore_reg
|
|
+ ldr r11, [r12]
|
|
+ bic r11, #(BIT_(16))
|
|
+ str r11, [r12]
|
|
+ ldr r11, =(1)
|
|
+
|
|
+restore_reg:
|
|
+ /* Restore initial RCC_MP_APB5ENSETR content saved in r10 */
|
|
+ ldr r12, =(RCC_BASE + RCC_MP_APB5ENSETR)
|
|
+ str r10, [r12]
|
|
+
|
|
+ /* Restore initial PWR_CR1 content saved in r9 */
|
|
+ ldr r12, =(PWR_BASE + PWR_CR1)
|
|
+ str r9, [r12]
|
|
+poll_cr1:
|
|
+ /* poll loop to ensure write is effective */
|
|
+ ldr r12, =(PWR_BASE + PWR_CR1)
|
|
+ ldr r12, [r12]
|
|
+ teq r12, r9
|
|
+ bne poll_cr1
|
|
+
|
|
+ /*
|
|
+ * Exit if bit 16 of TAMPER backup register 20 has been cleared.
|
|
+ * Information is saved in r11 register.
|
|
+ */
|
|
+ teq r11, #0
|
|
+ beq func_exit
|
|
+
|
|
+ /* Get time counter frequency */
|
|
+ mrc 15, 0, r12, cr14, cr0, 0
|
|
+ /* Get current time counter value, save it in r11 as start value */
|
|
+ mrrc 15, 0, r11, r10, cr14
|
|
+ /*
|
|
+ * Compute (current time + 1 second) counter value, save it in r12 as
|
|
+ * end value.
|
|
+ */
|
|
+ add r12, r12, r11
|
|
+
|
|
+loop:
|
|
+ /*
|
|
+ * Read CA7_DBG0 DBG_DSCR HDBGEN bit value.
|
|
+ * If set, put a software breakpoint and branch to FSBL_ENTRYPOINT.
|
|
+ * If cleared, continue and check loop time expiry
|
|
+ */
|
|
+ ldr r10, =(CA7_DBG0_BASE + DBG_DSCR)
|
|
+ ldr r10, [r10]
|
|
+ tst r10, #DBG_DSCR_HDBGEN
|
|
+ beq loop_continue
|
|
+ /* Set a software breakpoint (ID 5) */
|
|
+ bkpt 5
|
|
+ /* Jump to entrypoint */
|
|
+ b FSBL_ENTRYPOINT
|
|
+loop_continue:
|
|
+ /*
|
|
+ * Check 1 second expiry by using r11 and r12 saved values.
|
|
+ * Get current time counter value, save it in r10 as current value.
|
|
+ */
|
|
+ mrrc 15, 0, r10, r9, cr14
|
|
+ /* Check if MSB 64-bit increment done between start and end values */
|
|
+ cmp r12, r11
|
|
+ bmi msb_incr
|
|
+ /* No increment, simply check if current < end, exit if yes */
|
|
+ cmp r12, r10
|
|
+ bmi func_exit
|
|
+ b loop
|
|
+msb_incr:
|
|
+ /*
|
|
+ * Increment happened between start and end, here we need to check if
|
|
+ * (current > end) && (current < start). Exit if yes.
|
|
+ */
|
|
+ cmp r12, r10
|
|
+ bpl loop
|
|
+ cmp r11, r10
|
|
+ bmi loop
|
|
+func_exit:
|
|
+ bx lr
|
|
diff --git a/plat/st/stm32mp1/stm32mp1_low_power.c b/plat/st/stm32mp1/stm32mp1_low_power.c
|
|
new file mode 100644
|
|
index 0000000..de9035c
|
|
--- /dev/null
|
|
+++ b/plat/st/stm32mp1/stm32mp1_low_power.c
|
|
@@ -0,0 +1,311 @@
|
|
+/*
|
|
+ * Copyright (c) 2017-2018, STMicroelectronics - All Rights Reserved
|
|
+ *
|
|
+ * SPDX-License-Identifier: BSD-3-Clause
|
|
+ */
|
|
+
|
|
+#include <arch_helpers.h>
|
|
+#include <assert.h>
|
|
+#include <boot_api.h>
|
|
+#include <debug.h>
|
|
+#include <delay_timer.h>
|
|
+#include <dt-bindings/clock/stm32mp1-clks.h>
|
|
+#include <dt-bindings/power/stm32mp1-power.h>
|
|
+#include <gic_common.h>
|
|
+#include <gicv2.h>
|
|
+#include <libfdt.h>
|
|
+#include <mmio.h>
|
|
+#include <platform.h>
|
|
+#include <stm32_iwdg.h>
|
|
+#include <stm32_rtc.h>
|
|
+#include <stm32mp_common.h>
|
|
+#include <stm32mp_dt.h>
|
|
+#include <stm32mp_pmic.h>
|
|
+#include <stm32mp1_clk.h>
|
|
+#include <stm32mp1_context.h>
|
|
+#include <stm32mp1_ddr_helpers.h>
|
|
+#include <stm32mp1_low_power.h>
|
|
+#include <stm32mp1_private.h>
|
|
+#include <stm32mp1_pwr.h>
|
|
+#include <stm32mp1_rcc.h>
|
|
+#include <stm32mp1_shared_resources.h>
|
|
+#include <stpmic1.h>
|
|
+
|
|
+static unsigned int gicc_pmr;
|
|
+static struct stm32_rtc_calendar sleep_time, current_calendar;
|
|
+static unsigned long long stdby_time_in_ms;
|
|
+static bool enter_cstop_done;
|
|
+static uint8_t int_stack[STM32MP_INT_STACK_SIZE];
|
|
+
|
|
+extern void wfi_svc_int_enable(uintptr_t stack_addr);
|
|
+
|
|
+struct pwr_lp_config {
|
|
+ uint32_t pwr_cr1;
|
|
+ uint32_t pwr_mpucr;
|
|
+ const char *regul_suspend_node_name;
|
|
+};
|
|
+
|
|
+#define PWR_CR1_MASK (PWR_CR1_LPDS | PWR_CR1_LPCFG | PWR_CR1_LVDS)
|
|
+#define PWR_MPUCR_MASK (PWR_MPUCR_CSTDBYDIS | PWR_MPUCR_CSSF | PWR_MPUCR_PDDS)
|
|
+
|
|
+static const struct pwr_lp_config config_pwr[STM32_PM_MAX_SOC_MODE] = {
|
|
+ [STM32_PM_CSLEEP_RUN] = {
|
|
+ .pwr_cr1 = 0U,
|
|
+ .pwr_mpucr = PWR_MPUCR_CSSF,
|
|
+ .regul_suspend_node_name = NULL,
|
|
+ },
|
|
+ [STM32_PM_CSTOP_ALLOW_STOP] = {
|
|
+ .pwr_cr1 = 0U,
|
|
+ .pwr_mpucr = PWR_MPUCR_CSTDBYDIS | PWR_MPUCR_CSSF,
|
|
+ .regul_suspend_node_name = NULL,
|
|
+ },
|
|
+ [STM32_PM_CSTOP_ALLOW_LP_STOP] = {
|
|
+ .pwr_cr1 = PWR_CR1_LPDS,
|
|
+ .pwr_mpucr = PWR_MPUCR_CSTDBYDIS | PWR_MPUCR_CSSF,
|
|
+ .regul_suspend_node_name = "lp-stop",
|
|
+ },
|
|
+ [STM32_PM_CSTOP_ALLOW_LPLV_STOP] = {
|
|
+ .pwr_cr1 = PWR_CR1_LVDS | PWR_CR1_LPDS | PWR_CR1_LPCFG,
|
|
+ .pwr_mpucr = PWR_MPUCR_CSTDBYDIS | PWR_MPUCR_CSSF,
|
|
+ .regul_suspend_node_name = "lplv-stop",
|
|
+ },
|
|
+ [STM32_PM_CSTOP_ALLOW_STANDBY_DDR_SR] = {
|
|
+ .pwr_cr1 = 0U,
|
|
+ .pwr_mpucr = PWR_MPUCR_CSTDBYDIS | PWR_MPUCR_CSSF |
|
|
+ PWR_MPUCR_PDDS,
|
|
+ .regul_suspend_node_name = "standby-ddr-sr",
|
|
+ },
|
|
+ [STM32_PM_CSTOP_ALLOW_STANDBY_DDR_OFF] = {
|
|
+ .pwr_cr1 = 0U,
|
|
+ .pwr_mpucr = PWR_MPUCR_CSTDBYDIS | PWR_MPUCR_CSSF |
|
|
+ PWR_MPUCR_PDDS,
|
|
+ .regul_suspend_node_name = "standby-ddr-off",
|
|
+ },
|
|
+ [STM32_PM_SHUTDOWN] = {
|
|
+ .pwr_cr1 = 0U,
|
|
+ .pwr_mpucr = 0U,
|
|
+ .regul_suspend_node_name = "standby-ddr-off",
|
|
+ },
|
|
+};
|
|
+
|
|
+#define GICC_PMR_PRIORITY_8 U(0x8)
|
|
+
|
|
+void stm32_apply_pmic_suspend_config(uint32_t mode)
|
|
+{
|
|
+ const char *node_name = config_pwr[mode].regul_suspend_node_name;
|
|
+
|
|
+ assert(mode < ARRAY_SIZE(config_pwr));
|
|
+
|
|
+ if (node_name != NULL) {
|
|
+ if (!initialize_pmic_i2c()) {
|
|
+ panic();
|
|
+ }
|
|
+
|
|
+ if (dt_pmic_set_lp_config(node_name) != 0) {
|
|
+ panic();
|
|
+ }
|
|
+
|
|
+ if (dt_pmic_configure_boot_on_regulators() != 0) {
|
|
+ panic();
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
+/*
|
|
+ * stm32_enter_cstop - Prepare CSTOP mode
|
|
+ *
|
|
+ * @mode - Target low power mode
|
|
+ * @nsec_addr - Non secure resume entry point
|
|
+ * Return 0 if succeed to suspend, non 0 else.
|
|
+ */
|
|
+static void enter_cstop(uint32_t mode, uint32_t nsec_addr)
|
|
+{
|
|
+ uint32_t zq0cr0_zdata;
|
|
+ uint32_t bkpr_core1_addr =
|
|
+ tamp_bkpr(BOOT_API_CORE1_BRANCH_ADDRESS_TAMP_BCK_REG_IDX);
|
|
+ uint32_t bkpr_core1_magic =
|
|
+ tamp_bkpr(BOOT_API_CORE1_MAGIC_NUMBER_TAMP_BCK_REG_IDX);
|
|
+ uint32_t pwr_cr1 = config_pwr[mode].pwr_cr1;
|
|
+ uintptr_t pwr_base = stm32mp_pwr_base();
|
|
+ uintptr_t rcc_base = stm32mp_rcc_base();
|
|
+
|
|
+ dcsw_op_all(DC_OP_CISW);
|
|
+
|
|
+ stm32_clean_context();
|
|
+
|
|
+ if (mode == STM32_PM_CSTOP_ALLOW_STANDBY_DDR_SR) {
|
|
+ /*
|
|
+ * The first 64 bytes of DDR need to be saved for DDR DQS
|
|
+ * training
|
|
+ */
|
|
+ stm32_save_ddr_training_area();
|
|
+ }
|
|
+
|
|
+ if (dt_pmic_status() > 0) {
|
|
+ stm32_apply_pmic_suspend_config(mode);
|
|
+
|
|
+ if (mode == STM32_PM_CSTOP_ALLOW_LP_STOP) {
|
|
+ pwr_cr1 |= PWR_CR1_LPCFG;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /* Clear RCC interrupt before enabling it */
|
|
+ mmio_setbits_32(rcc_base + RCC_MP_CIFR, RCC_MP_CIFR_WKUPF);
|
|
+
|
|
+ /* Enable RCC Wake-up */
|
|
+ mmio_setbits_32(rcc_base + RCC_MP_CIER, RCC_MP_CIFR_WKUPF);
|
|
+
|
|
+ /* Configure low power mode */
|
|
+ mmio_clrsetbits_32(pwr_base + PWR_MPUCR, PWR_MPUCR_MASK,
|
|
+ config_pwr[mode].pwr_mpucr);
|
|
+ mmio_clrsetbits_32(pwr_base + PWR_CR1, PWR_CR1_MASK,
|
|
+ pwr_cr1);
|
|
+
|
|
+ /* Clear RCC pending interrupt flags */
|
|
+ mmio_write_32(rcc_base + RCC_MP_CIFR, RCC_MP_CIFR_MASK);
|
|
+
|
|
+ /* Request CSTOP mode to RCC */
|
|
+ mmio_setbits_32(rcc_base + RCC_MP_SREQSETR,
|
|
+ RCC_MP_SREQSETR_STPREQ_P0 | RCC_MP_SREQSETR_STPREQ_P1);
|
|
+
|
|
+ stm32_iwdg_refresh(IWDG2_INST);
|
|
+
|
|
+ gicc_pmr = plat_ic_set_priority_mask(GICC_PMR_PRIORITY_8);
|
|
+
|
|
+ /*
|
|
+ * Set DDR in Self-refresh, even if no return address is given.
|
|
+ * This is also the procedure awaited when switching off power supply.
|
|
+ */
|
|
+ if (ddr_standby_sr_entry(&zq0cr0_zdata) != 0) {
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ stm32mp_clk_enable(RTCAPB);
|
|
+
|
|
+ mmio_write_32(bkpr_core1_addr, 0);
|
|
+ mmio_write_32(bkpr_core1_magic, 0);
|
|
+
|
|
+ if (mode == STM32_PM_CSTOP_ALLOW_STANDBY_DDR_SR) {
|
|
+
|
|
+ /*
|
|
+ * Save non-secure world entrypoint after standby in Backup
|
|
+ * register
|
|
+ */
|
|
+ mmio_write_32(bkpr_core1_addr, nsec_addr);
|
|
+ mmio_write_32(bkpr_core1_magic,
|
|
+ BOOT_API_A7_CORE0_MAGIC_NUMBER);
|
|
+
|
|
+ if (stm32_save_context(zq0cr0_zdata) != 0) {
|
|
+ panic();
|
|
+ }
|
|
+ }
|
|
+
|
|
+ stm32mp_clk_disable(RTCAPB);
|
|
+
|
|
+ stm32_rtc_get_calendar(&sleep_time);
|
|
+
|
|
+ enter_cstop_done = true;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * stm32_exit_cstop - Exit from CSTOP mode
|
|
+ */
|
|
+void stm32_exit_cstop(void)
|
|
+{
|
|
+ uintptr_t rcc_base = stm32mp_rcc_base();
|
|
+
|
|
+ if (!enter_cstop_done) {
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ enter_cstop_done = false;
|
|
+
|
|
+ if (ddr_sw_self_refresh_exit() != 0) {
|
|
+ panic();
|
|
+ }
|
|
+
|
|
+ plat_ic_set_priority_mask(gicc_pmr);
|
|
+
|
|
+ /* Disable RCC Wake-up */
|
|
+ mmio_clrbits_32(rcc_base + RCC_MP_CIER, RCC_MP_CIFR_WKUPF);
|
|
+
|
|
+ /* Disable STOP request */
|
|
+ mmio_setbits_32(rcc_base + RCC_MP_SREQCLRR,
|
|
+ RCC_MP_SREQSETR_STPREQ_P0 | RCC_MP_SREQSETR_STPREQ_P1);
|
|
+
|
|
+ dsb();
|
|
+ isb();
|
|
+
|
|
+ /* Update STGEN counter with low power mode duration */
|
|
+ stm32_rtc_get_calendar(¤t_calendar);
|
|
+
|
|
+ stdby_time_in_ms = stm32_rtc_diff_calendar(¤t_calendar,
|
|
+ &sleep_time);
|
|
+
|
|
+ stm32mp1_stgen_increment(stdby_time_in_ms);
|
|
+}
|
|
+
|
|
+static void enter_shutdown(void)
|
|
+{
|
|
+ if (dt_pmic_status() > 0) {
|
|
+ if (!initialize_pmic_i2c()) {
|
|
+ panic();
|
|
+ }
|
|
+
|
|
+ stpmic1_switch_off();
|
|
+
|
|
+ udelay(100);
|
|
+
|
|
+ /* Shouldn't be reached */
|
|
+ panic();
|
|
+ }
|
|
+}
|
|
+
|
|
+static void enter_csleep(void)
|
|
+{
|
|
+ uintptr_t pwr_base = stm32mp_pwr_base();
|
|
+
|
|
+ mmio_clrsetbits_32(pwr_base + PWR_MPUCR, PWR_MPUCR_MASK,
|
|
+ config_pwr[STM32_PM_CSLEEP_RUN].pwr_mpucr);
|
|
+ mmio_clrsetbits_32(pwr_base + PWR_CR1, PWR_CR1_MASK,
|
|
+ config_pwr[STM32_PM_CSLEEP_RUN].pwr_cr1);
|
|
+
|
|
+ stm32_pwr_down_wfi();
|
|
+}
|
|
+
|
|
+void stm32_enter_low_power(uint32_t mode, uint32_t nsec_addr)
|
|
+{
|
|
+ switch (mode) {
|
|
+ case STM32_PM_SHUTDOWN:
|
|
+ enter_shutdown();
|
|
+ break;
|
|
+
|
|
+ case STM32_PM_CSLEEP_RUN:
|
|
+ enter_csleep();
|
|
+ break;
|
|
+
|
|
+ default:
|
|
+ enter_cstop(mode, nsec_addr);
|
|
+ break;
|
|
+ }
|
|
+}
|
|
+
|
|
+void stm32_pwr_down_wfi(void)
|
|
+{
|
|
+ uint32_t interrupt = GIC_SPURIOUS_INTERRUPT;
|
|
+
|
|
+ stm32mp1_rcc_set_wakeup(false);
|
|
+
|
|
+ while (interrupt == GIC_SPURIOUS_INTERRUPT &&
|
|
+ !stm32mp1_rcc_get_wakeup()) {
|
|
+ wfi_svc_int_enable((uintptr_t)&int_stack[0]);
|
|
+
|
|
+ interrupt = gicv2_acknowledge_interrupt();
|
|
+
|
|
+ if (interrupt != GIC_SPURIOUS_INTERRUPT) {
|
|
+ gicv2_end_of_interrupt(interrupt);
|
|
+ }
|
|
+
|
|
+ stm32_iwdg_refresh(IWDG2_INST);
|
|
+ }
|
|
+}
|
|
diff --git a/plat/st/stm32mp1/stm32mp1_pm.c b/plat/st/stm32mp1/stm32mp1_pm.c
|
|
index e24af0e..20a2f5c 100644
|
|
--- a/plat/st/stm32mp1/stm32mp1_pm.c
|
|
+++ b/plat/st/stm32mp1/stm32mp1_pm.c
|
|
@@ -7,7 +7,9 @@
|
|
#include <arch_helpers.h>
|
|
#include <assert.h>
|
|
#include <boot_api.h>
|
|
+#include <bsec.h>
|
|
#include <debug.h>
|
|
+#include <delay_timer.h>
|
|
#include <dt-bindings/clock/stm32mp1-clks.h>
|
|
#include <errno.h>
|
|
#include <gic_common.h>
|
|
@@ -16,14 +18,16 @@
|
|
#include <platform_def.h>
|
|
#include <platform.h>
|
|
#include <psci.h>
|
|
-#include <stm32mp1_clk.h>
|
|
+#include <stm32mp_common.h>
|
|
+#include <stm32mp1_low_power.h>
|
|
+#include <stm32mp1_power_config.h>
|
|
#include <stm32mp1_private.h>
|
|
#include <stm32mp1_rcc.h>
|
|
+#include <stm32mp1_shared_resources.h>
|
|
|
|
-static uint32_t stm32_sec_entrypoint;
|
|
+static uintptr_t stm32_sec_entrypoint;
|
|
static uint32_t cntfrq_core0;
|
|
-
|
|
-#define SEND_SECURE_IT_TO_CORE_1 0x20000U
|
|
+static uintptr_t saved_entrypoint;
|
|
|
|
/*******************************************************************************
|
|
* STM32MP1 handler called when a CPU is about to enter standby.
|
|
@@ -39,6 +43,7 @@ static void stm32_cpu_standby(plat_local_state_t cpu_state)
|
|
* Enter standby state
|
|
* dsb is good practice before using wfi to enter low power states
|
|
*/
|
|
+ isb();
|
|
dsb();
|
|
while (interrupt == GIC_SPURIOUS_INTERRUPT) {
|
|
wfi();
|
|
@@ -56,33 +61,43 @@ static void stm32_cpu_standby(plat_local_state_t cpu_state)
|
|
/*******************************************************************************
|
|
* STM32MP1 handler called when a power domain is about to be turned on. The
|
|
* mpidr determines the CPU to be turned on.
|
|
- * call by core 0 to activate core 1
|
|
+ * call by core 0 to activate core 1
|
|
******************************************************************************/
|
|
static int stm32_pwr_domain_on(u_register_t mpidr)
|
|
{
|
|
unsigned long current_cpu_mpidr = read_mpidr_el1();
|
|
- uint32_t tamp_clk_off = 0;
|
|
uint32_t bkpr_core1_addr =
|
|
tamp_bkpr(BOOT_API_CORE1_BRANCH_ADDRESS_TAMP_BCK_REG_IDX);
|
|
uint32_t bkpr_core1_magic =
|
|
tamp_bkpr(BOOT_API_CORE1_MAGIC_NUMBER_TAMP_BCK_REG_IDX);
|
|
+ int result;
|
|
+
|
|
+ result = stm32mp_is_single_core();
|
|
+ if (result < 0) {
|
|
+ return PSCI_E_INTERN_FAIL;
|
|
+ }
|
|
+
|
|
+ if (result == 1) {
|
|
+ return PSCI_E_INTERN_FAIL;
|
|
+ }
|
|
|
|
if (mpidr == current_cpu_mpidr) {
|
|
return PSCI_E_INVALID_PARAMS;
|
|
}
|
|
|
|
- if ((stm32_sec_entrypoint < STM32MP1_SRAM_BASE) ||
|
|
- (stm32_sec_entrypoint > (STM32MP1_SRAM_BASE +
|
|
- (STM32MP1_SRAM_SIZE - 1)))) {
|
|
+ /* Need to send additional IT 0 after individual core 1 reset */
|
|
+ gicv2_raise_sgi(ARM_IRQ_NON_SEC_SGI_0, STM32MP_SECONDARY_CPU);
|
|
+
|
|
+ /* Wait for this IT to be acknowledged by ROM code. */
|
|
+ udelay(10);
|
|
+
|
|
+ if ((stm32_sec_entrypoint < STM32MP_SYSRAM_BASE) ||
|
|
+ (stm32_sec_entrypoint > (STM32MP_SYSRAM_BASE +
|
|
+ (STM32MP_SYSRAM_SIZE - 1)))) {
|
|
return PSCI_E_INVALID_ADDRESS;
|
|
}
|
|
|
|
- if (!stm32mp1_clk_is_enabled(RTCAPB)) {
|
|
- tamp_clk_off = 1;
|
|
- if (stm32mp1_clk_enable(RTCAPB) != 0) {
|
|
- panic();
|
|
- }
|
|
- }
|
|
+ stm32mp_clk_enable(RTCAPB);
|
|
|
|
cntfrq_core0 = read_cntfrq_el0();
|
|
|
|
@@ -92,15 +107,10 @@ static int stm32_pwr_domain_on(u_register_t mpidr)
|
|
/* Write magic number in backup register */
|
|
mmio_write_32(bkpr_core1_magic, BOOT_API_A7_CORE1_MAGIC_NUMBER);
|
|
|
|
- if (tamp_clk_off != 0U) {
|
|
- if (stm32mp1_clk_disable(RTCAPB) != 0) {
|
|
- panic();
|
|
- }
|
|
- }
|
|
+ stm32mp_clk_disable(RTCAPB);
|
|
|
|
/* Generate an IT to core 1 */
|
|
- mmio_write_32(STM32MP1_GICD_BASE + GICD_SGIR,
|
|
- SEND_SECURE_IT_TO_CORE_1 | ARM_IRQ_SEC_SGI_0);
|
|
+ gicv2_raise_sgi(ARM_IRQ_SEC_SGI_0, STM32MP_SECONDARY_CPU);
|
|
|
|
return PSCI_E_SUCCESS;
|
|
}
|
|
@@ -120,7 +130,9 @@ static void stm32_pwr_domain_off(const psci_power_state_t *target_state)
|
|
******************************************************************************/
|
|
static void stm32_pwr_domain_suspend(const psci_power_state_t *target_state)
|
|
{
|
|
- /* Nothing to do, power domain is not disabled */
|
|
+ uint32_t soc_mode = stm32mp1_get_lp_soc_mode(PSCI_MODE_SYSTEM_SUSPEND);
|
|
+
|
|
+ stm32_enter_low_power(soc_mode, saved_entrypoint);
|
|
}
|
|
|
|
/*******************************************************************************
|
|
@@ -147,22 +159,63 @@ static void stm32_pwr_domain_suspend_finish(const psci_power_state_t
|
|
/* Nothing to do, power domain is not disabled */
|
|
}
|
|
|
|
+/*******************************************************************************
|
|
+ * STM32MP1 handler called when a core tries to power itself down. If this
|
|
+ * call is made by core 0, it is a return from stop mode. In this case, we
|
|
+ * should restore previous context and jump to secure entrypoint.
|
|
+ ******************************************************************************/
|
|
static void __dead2 stm32_pwr_domain_pwr_down_wfi(const psci_power_state_t
|
|
*target_state)
|
|
{
|
|
- ERROR("stm32mpu1 Power Down WFI: operation not handled.\n");
|
|
+ if (MPIDR_AFFLVL0_VAL(read_mpidr_el1()) == STM32MP_PRIMARY_CPU) {
|
|
+ void (*warm_entrypoint)(void) =
|
|
+ (void (*)(void))stm32_sec_entrypoint;
|
|
+
|
|
+ stm32_pwr_down_wfi();
|
|
+
|
|
+ stm32_exit_cstop();
|
|
+
|
|
+ disable_mmu_icache_secure();
|
|
+
|
|
+ warm_entrypoint();
|
|
+ }
|
|
+
|
|
+ mmio_write_32(stm32mp_rcc_base() + RCC_MP_GRSTCSETR,
|
|
+ RCC_MP_GRSTCSETR_MPUP1RST);
|
|
+
|
|
+ /* wfi is required for an auto-reset */
|
|
+ isb();
|
|
+ dsb();
|
|
+ wfi();
|
|
+
|
|
+ /* This shouldn't be reached */
|
|
panic();
|
|
}
|
|
|
|
static void __dead2 stm32_system_off(void)
|
|
{
|
|
- ERROR("stm32mpu1 System Off: operation not handled.\n");
|
|
+ uint32_t soc_mode = stm32mp1_get_lp_soc_mode(PSCI_MODE_SYSTEM_OFF);
|
|
+
|
|
+ if (stm32mp_is_single_core() == 0) {
|
|
+ /* Prepare Core 1 reset */
|
|
+ mmio_setbits_32(stm32mp_rcc_base() + RCC_MP_GRSTCSETR,
|
|
+ RCC_MP_GRSTCSETR_MPUP1RST);
|
|
+ /* Send IT to core 1 to put itself in WFI */
|
|
+ gicv2_raise_sgi(ARM_IRQ_SEC_SGI_1, STM32MP_SECONDARY_CPU);
|
|
+ }
|
|
+
|
|
+ stm32_enter_low_power(soc_mode, 0);
|
|
+
|
|
+ stm32_pwr_down_wfi();
|
|
+
|
|
+ /* This shouldn't be reached */
|
|
panic();
|
|
}
|
|
|
|
static void __dead2 stm32_system_reset(void)
|
|
{
|
|
- mmio_setbits_32(RCC_BASE + RCC_MP_GRSTCSETR, RCC_MP_GRSTCSETR_MPSYSRST);
|
|
+ mmio_setbits_32(stm32mp_rcc_base() + RCC_MP_GRSTCSETR,
|
|
+ RCC_MP_GRSTCSETR_MPSYSRST);
|
|
|
|
/* Loop in case system reset is not immediately caught */
|
|
for ( ; ; ) {
|
|
@@ -196,10 +249,12 @@ static int stm32_validate_power_state(unsigned int power_state,
|
|
static int stm32_validate_ns_entrypoint(uintptr_t entrypoint)
|
|
{
|
|
/* The non-secure entry point must be in DDR */
|
|
- if (entrypoint < STM32MP1_DDR_BASE) {
|
|
+ if (entrypoint < STM32MP_DDR_BASE) {
|
|
return PSCI_E_INVALID_ADDRESS;
|
|
}
|
|
|
|
+ saved_entrypoint = entrypoint;
|
|
+
|
|
return PSCI_E_SUCCESS;
|
|
}
|
|
|
|
@@ -223,6 +278,12 @@ static int stm32_node_hw_state(u_register_t target_cpu,
|
|
return (int)HW_ON;
|
|
}
|
|
|
|
+static void stm32_get_sys_suspend_power_state(psci_power_state_t *req_state)
|
|
+{
|
|
+ req_state->pwr_domain_state[0] = ARM_LOCAL_STATE_OFF;
|
|
+ req_state->pwr_domain_state[1] = ARM_LOCAL_STATE_OFF;
|
|
+}
|
|
+
|
|
/*******************************************************************************
|
|
* Export the platform handlers. The ARM Standard platform layer will take care
|
|
* of registering the handlers with PSCI.
|
|
@@ -239,7 +300,8 @@ static const plat_psci_ops_t stm32_psci_ops = {
|
|
.system_reset = stm32_system_reset,
|
|
.validate_power_state = stm32_validate_power_state,
|
|
.validate_ns_entrypoint = stm32_validate_ns_entrypoint,
|
|
- .get_node_hw_state = stm32_node_hw_state
|
|
+ .get_node_hw_state = stm32_node_hw_state,
|
|
+ .get_sys_suspend_power_state = stm32_get_sys_suspend_power_state,
|
|
};
|
|
|
|
/*******************************************************************************
|
|
diff --git a/plat/st/stm32mp1/stm32mp1_power_config.c b/plat/st/stm32mp1/stm32mp1_power_config.c
|
|
new file mode 100644
|
|
index 0000000..ec7ecb1
|
|
--- /dev/null
|
|
+++ b/plat/st/stm32mp1/stm32mp1_power_config.c
|
|
@@ -0,0 +1,193 @@
|
|
+/*
|
|
+ * Copyright (c) 2017-2018, STMicroelectronics - All Rights Reserved
|
|
+ *
|
|
+ * SPDX-License-Identifier: BSD-3-Clause
|
|
+ */
|
|
+
|
|
+#include <assert.h>
|
|
+#include <debug.h>
|
|
+#include <dt-bindings/power/stm32mp1-power.h>
|
|
+#include <errno.h>
|
|
+#include <libfdt.h>
|
|
+#include <limits.h>
|
|
+#include <stm32mp_dt.h>
|
|
+#include <stm32mp1_power_config.h>
|
|
+
|
|
+#define DT_PWR_COMPAT "st,stm32mp1-pwr"
|
|
+#define SYSTEM_SUSPEND_SUPPORTED_MODES "system_suspend_supported_soc_modes"
|
|
+#define SYSTEM_OFF_MODE "system_off_soc_mode"
|
|
+
|
|
+static uint32_t deepest_system_suspend_mode;
|
|
+static uint32_t system_off_mode;
|
|
+static uint8_t stm32mp1_supported_soc_modes[STM32_PM_MAX_SOC_MODE];
|
|
+
|
|
+static int dt_get_pwr_node(void *fdt)
|
|
+{
|
|
+ return fdt_node_offset_by_compatible(fdt, -1, DT_PWR_COMPAT);
|
|
+}
|
|
+
|
|
+static void save_supported_mode(void *fdt, int pwr_node)
|
|
+{
|
|
+ int len;
|
|
+ uint32_t count;
|
|
+ unsigned int i;
|
|
+ uint32_t supported[ARRAY_SIZE(stm32mp1_supported_soc_modes)];
|
|
+ const void *prop;
|
|
+
|
|
+ prop = fdt_getprop(fdt, pwr_node, SYSTEM_SUSPEND_SUPPORTED_MODES, &len);
|
|
+ if (prop == NULL) {
|
|
+ panic();
|
|
+ }
|
|
+
|
|
+ count = (uint32_t)len / sizeof(uint32_t);
|
|
+ if (count > STM32_PM_MAX_SOC_MODE) {
|
|
+ panic();
|
|
+ }
|
|
+
|
|
+ if (fdt_read_uint32_array(pwr_node, SYSTEM_SUSPEND_SUPPORTED_MODES,
|
|
+ &supported[0], count) < 0) {
|
|
+ ERROR("PWR DT\n");
|
|
+ panic();
|
|
+ }
|
|
+
|
|
+ for (i = 0; i < count; i++) {
|
|
+ if (supported[i] >= STM32_PM_MAX_SOC_MODE) {
|
|
+ ERROR("Invalid mode\n");
|
|
+ panic();
|
|
+ }
|
|
+ stm32mp1_supported_soc_modes[supported[i]] = 1U;
|
|
+ }
|
|
+
|
|
+ /* Initialize to deepest possible mode */
|
|
+ for (i = STM32_PM_MAX_SOC_MODE - 1U; i != STM32_PM_CSLEEP_RUN; i--) {
|
|
+ if (stm32mp1_supported_soc_modes[i] == 1U) {
|
|
+ deepest_system_suspend_mode = i;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
+static int dt_fill_lp_state(uint32_t *lp_state_config, const char *lp_state)
|
|
+{
|
|
+ int pwr_node;
|
|
+ void *fdt;
|
|
+ const fdt32_t *cuint;
|
|
+
|
|
+ if (fdt_get_address(&fdt) == 0) {
|
|
+ return -ENOENT;
|
|
+ }
|
|
+
|
|
+ pwr_node = dt_get_pwr_node(fdt);
|
|
+ if (pwr_node < 0) {
|
|
+ return -FDT_ERR_NOTFOUND;
|
|
+ }
|
|
+
|
|
+ cuint = fdt_getprop(fdt, pwr_node, lp_state, NULL);
|
|
+ if (cuint == NULL) {
|
|
+ return -FDT_ERR_NOTFOUND;
|
|
+ }
|
|
+
|
|
+ *lp_state_config = fdt32_to_cpu(*cuint);
|
|
+
|
|
+ save_supported_mode(fdt, pwr_node);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+void stm32mp1_init_lp_states(void)
|
|
+{
|
|
+ if (dt_fill_lp_state(&system_off_mode, SYSTEM_OFF_MODE) < 0) {
|
|
+ ERROR("Node %s not found\n", SYSTEM_OFF_MODE);
|
|
+ panic();
|
|
+ }
|
|
+}
|
|
+
|
|
+/* Init with all domains ON */
|
|
+static bool pm_dom[STM32MP1_PD_MAX_PM_DOMAIN] = {
|
|
+ [STM32MP1_PD_VSW] = false,
|
|
+ [STM32MP1_PD_CORE_RET] = false,
|
|
+ [STM32MP1_PD_CORE] = false
|
|
+};
|
|
+
|
|
+static bool stm32mp1_get_pm_domain_state(uint8_t mode)
|
|
+{
|
|
+ bool res = true;
|
|
+ enum stm32mp1_pm_domain id = STM32MP1_PD_MAX_PM_DOMAIN;
|
|
+
|
|
+ while (res && (id > mode)) {
|
|
+ id--;
|
|
+ res &= pm_dom[id];
|
|
+ }
|
|
+
|
|
+ return res;
|
|
+}
|
|
+
|
|
+int stm32mp1_set_pm_domain_state(enum stm32mp1_pm_domain domain, bool status)
|
|
+{
|
|
+ if (domain >= STM32MP1_PD_MAX_PM_DOMAIN) {
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ pm_dom[domain] = status;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static bool is_supported_mode(uint32_t soc_mode)
|
|
+{
|
|
+ assert(soc_mode < ARRAY_SIZE(stm32mp1_supported_soc_modes));
|
|
+
|
|
+ return stm32mp1_supported_soc_modes[soc_mode] == 1U;
|
|
+}
|
|
+
|
|
+uint32_t stm32mp1_get_lp_soc_mode(uint32_t psci_mode)
|
|
+{
|
|
+ uint32_t mode;
|
|
+
|
|
+ if (psci_mode == PSCI_MODE_SYSTEM_OFF) {
|
|
+ return system_off_mode;
|
|
+ }
|
|
+
|
|
+ mode = deepest_system_suspend_mode;
|
|
+
|
|
+ if ((mode == STM32_PM_CSTOP_ALLOW_STANDBY_DDR_SR) &&
|
|
+ ((!stm32mp1_get_pm_domain_state(STM32MP1_PD_CORE_RET)) ||
|
|
+ (!is_supported_mode(mode)))) {
|
|
+ mode = STM32_PM_CSTOP_ALLOW_LPLV_STOP;
|
|
+ }
|
|
+
|
|
+ if ((mode == STM32_PM_CSTOP_ALLOW_LPLV_STOP) &&
|
|
+ ((!stm32mp1_get_pm_domain_state(STM32MP1_PD_CORE)) ||
|
|
+ (!is_supported_mode(mode)))) {
|
|
+ mode = STM32_PM_CSTOP_ALLOW_LP_STOP;
|
|
+ }
|
|
+
|
|
+ if ((mode == STM32_PM_CSTOP_ALLOW_LP_STOP) &&
|
|
+ (!is_supported_mode(mode))) {
|
|
+ mode = STM32_PM_CSTOP_ALLOW_STOP;
|
|
+ }
|
|
+
|
|
+ if ((mode == STM32_PM_CSTOP_ALLOW_STOP) &&
|
|
+ (!is_supported_mode(mode))) {
|
|
+ mode = STM32_PM_CSLEEP_RUN;
|
|
+ }
|
|
+
|
|
+ return mode;
|
|
+}
|
|
+
|
|
+int stm32mp1_set_lp_deepest_soc_mode(uint32_t psci_mode, uint32_t soc_mode)
|
|
+{
|
|
+ if (soc_mode >= STM32_PM_MAX_SOC_MODE) {
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ if (psci_mode == PSCI_MODE_SYSTEM_SUSPEND) {
|
|
+ deepest_system_suspend_mode = soc_mode;
|
|
+ }
|
|
+
|
|
+ if (psci_mode == PSCI_MODE_SYSTEM_OFF) {
|
|
+ system_off_mode = soc_mode;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
diff --git a/plat/st/stm32mp1/stm32mp1_private.c b/plat/st/stm32mp1/stm32mp1_private.c
|
|
new file mode 100644
|
|
index 0000000..c1f4c82
|
|
--- /dev/null
|
|
+++ b/plat/st/stm32mp1/stm32mp1_private.c
|
|
@@ -0,0 +1,379 @@
|
|
+/*
|
|
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
|
|
+ *
|
|
+ * SPDX-License-Identifier: BSD-3-Clause
|
|
+ */
|
|
+
|
|
+#include <arch_helpers.h>
|
|
+#include <assert.h>
|
|
+#include <bl_common.h>
|
|
+#include <debug.h>
|
|
+#include <gicv2.h>
|
|
+#include <mmio.h>
|
|
+#include <platform.h>
|
|
+#include <platform_def.h>
|
|
+#include <stm32_iwdg.h>
|
|
+#include <stm32mp_common.h>
|
|
+#include <stm32mp_dt.h>
|
|
+#include <xlat_tables_v2.h>
|
|
+
|
|
+#define MAP_ROM MAP_REGION_FLAT(STM32MP_ROM_BASE, \
|
|
+ STM32MP_ROM_SIZE, \
|
|
+ MT_MEMORY | \
|
|
+ MT_RO | \
|
|
+ MT_SECURE | \
|
|
+ MT_EXECUTE)
|
|
+
|
|
+#define MAP_SRAM MAP_REGION_FLAT(STM32MP_SYSRAM_BASE, \
|
|
+ STM32MP_SYSRAM_SIZE, \
|
|
+ MT_MEMORY | \
|
|
+ MT_RW | \
|
|
+ MT_SECURE | \
|
|
+ MT_EXECUTE_NEVER)
|
|
+
|
|
+#define MAP_SRAM_MCU MAP_REGION_FLAT(STM32MP_SRAM_MCU_BASE, \
|
|
+ STM32MP_SRAM_MCU_SIZE, \
|
|
+ MT_MEMORY | \
|
|
+ MT_RW | \
|
|
+ MT_NS | \
|
|
+ MT_EXECUTE_NEVER)
|
|
+
|
|
+#define MAP_RETRAM MAP_REGION_FLAT(STM32MP_RETRAM_BASE, \
|
|
+ STM32MP_RETRAM_SIZE, \
|
|
+ MT_MEMORY | \
|
|
+ MT_RW | \
|
|
+ MT_NS | \
|
|
+ MT_EXECUTE_NEVER)
|
|
+
|
|
+#define MAP_DEVICE1 MAP_REGION_FLAT(STM32MP1_DEVICE1_BASE, \
|
|
+ STM32MP1_DEVICE1_SIZE, \
|
|
+ MT_DEVICE | \
|
|
+ MT_RW | \
|
|
+ MT_SECURE | \
|
|
+ MT_EXECUTE_NEVER)
|
|
+
|
|
+#define MAP_DEVICE2 MAP_REGION_FLAT(STM32MP1_DEVICE2_BASE, \
|
|
+ STM32MP1_DEVICE2_SIZE, \
|
|
+ MT_DEVICE | \
|
|
+ MT_RW | \
|
|
+ MT_SECURE | \
|
|
+ MT_EXECUTE_NEVER)
|
|
+
|
|
+#if defined(IMAGE_BL2)
|
|
+static const mmap_region_t stm32mp1_mmap[] = {
|
|
+ MAP_ROM,
|
|
+ MAP_SRAM,
|
|
+#if defined(STM32MP_USB)
|
|
+ MAP_SRAM_MCU,
|
|
+#endif
|
|
+ MAP_DEVICE1,
|
|
+ MAP_DEVICE2,
|
|
+ {0}
|
|
+};
|
|
+#endif
|
|
+#if defined(IMAGE_BL32)
|
|
+static const mmap_region_t stm32mp1_mmap[] = {
|
|
+ MAP_ROM,
|
|
+ MAP_SRAM,
|
|
+ MAP_DEVICE1,
|
|
+ MAP_DEVICE2,
|
|
+ {0}
|
|
+};
|
|
+#endif
|
|
+
|
|
+void configure_mmu(void)
|
|
+{
|
|
+#ifndef MMU_OFF
|
|
+ unsigned int flags = 0;
|
|
+
|
|
+ mmap_add(stm32mp1_mmap);
|
|
+ init_xlat_tables();
|
|
+#ifdef DCACHE_OFF
|
|
+ flags |= DISABLE_DCACHE;
|
|
+#endif
|
|
+ enable_mmu_svc_mon(flags);
|
|
+#endif
|
|
+}
|
|
+
|
|
+#if STM32MP_UART_PROGRAMMER
|
|
+/*
|
|
+ * UART Management
|
|
+ */
|
|
+static const uintptr_t stm32mp1_uart_addresses[8] = {
|
|
+ USART1_BASE,
|
|
+ USART2_BASE,
|
|
+ USART3_BASE,
|
|
+ UART4_BASE,
|
|
+ UART5_BASE,
|
|
+ USART6_BASE,
|
|
+ UART7_BASE,
|
|
+ UART8_BASE,
|
|
+};
|
|
+
|
|
+uintptr_t get_uart_address(uint32_t instance_nb)
|
|
+{
|
|
+ if (!instance_nb || instance_nb > ARRAY_SIZE(stm32mp1_uart_addresses))
|
|
+ return 0;
|
|
+
|
|
+ return stm32mp1_uart_addresses[instance_nb - 1];
|
|
+}
|
|
+#endif
|
|
+
|
|
+void __dead2 stm32mp_plat_reset(int cpu)
|
|
+{
|
|
+ uint32_t reg = RCC_MP_GRSTCSETR_MPUP0RST;
|
|
+
|
|
+ if (stm32mp_is_single_core() == 0) {
|
|
+ unsigned int sec_cpu = (cpu == STM32MP_PRIMARY_CPU) ?
|
|
+ STM32MP_SECONDARY_CPU : STM32MP_PRIMARY_CPU;
|
|
+
|
|
+ gicv2_raise_sgi(ARM_IRQ_SEC_SGI_1, sec_cpu);
|
|
+ reg |= RCC_MP_GRSTCSETR_MPUP1RST;
|
|
+ }
|
|
+
|
|
+ mmio_write_32(stm32mp_rcc_base() + RCC_MP_GRSTCSETR, reg);
|
|
+
|
|
+ isb();
|
|
+ dsb();
|
|
+
|
|
+ /* Flush L1/L2 data caches */
|
|
+ write_sctlr(read_sctlr() & ~SCTLR_C_BIT);
|
|
+ dcsw_op_all(DC_OP_CISW);
|
|
+
|
|
+ for ( ; ; ) {
|
|
+ wfi();
|
|
+ }
|
|
+}
|
|
+
|
|
+static uint32_t get_part_number(void)
|
|
+{
|
|
+ uint32_t part_number = 0;
|
|
+
|
|
+ if (bsec_shadow_read_otp(&part_number, PART_NUMBER_OTP) != BSEC_OK) {
|
|
+ ERROR("BSEC: PART_NUMBER_OTP Error\n");
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ part_number = (part_number & PART_MASK) >> PART_SHIFT;
|
|
+
|
|
+ return (part_number | (stm32mp1_dbgmcu_get_chip_dev_id() << 16));
|
|
+}
|
|
+
|
|
+static uint32_t get_cpu_package(void)
|
|
+{
|
|
+ uint32_t package = 0;
|
|
+
|
|
+ if (bsec_shadow_read_otp(&package, PACKAGE_OTP) != BSEC_OK) {
|
|
+ ERROR("BSEC: PART_NUMBER_OTP Error\n");
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ return ((package & PKG_MASK) >> PKG_SHIFT);
|
|
+}
|
|
+
|
|
+void stm32mp_print_cpuinfo(void)
|
|
+{
|
|
+ const char *cpu_s, *cpu_r, *pkg;
|
|
+
|
|
+ /* MPUs Part Numbers */
|
|
+ switch (get_part_number()) {
|
|
+ case STM32MP157C_PART_NB:
|
|
+ cpu_s = "157C";
|
|
+ break;
|
|
+ case STM32MP157A_PART_NB:
|
|
+ cpu_s = "157A";
|
|
+ break;
|
|
+ case STM32MP153C_PART_NB:
|
|
+ cpu_s = "153C";
|
|
+ break;
|
|
+ case STM32MP153A_PART_NB:
|
|
+ cpu_s = "153A";
|
|
+ break;
|
|
+ case STM32MP151C_PART_NB:
|
|
+ cpu_s = "151C";
|
|
+ break;
|
|
+ case STM32MP151A_PART_NB:
|
|
+ cpu_s = "151A";
|
|
+ break;
|
|
+ default:
|
|
+ cpu_s = "????";
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ /* Package */
|
|
+ switch (get_cpu_package()) {
|
|
+ case PKG_AA_LBGA448:
|
|
+ pkg = "AA";
|
|
+ break;
|
|
+ case PKG_AB_LBGA354:
|
|
+ pkg = "AB";
|
|
+ break;
|
|
+ case PKG_AC_TFBGA361:
|
|
+ pkg = "AC";
|
|
+ break;
|
|
+ case PKG_AD_TFBGA257:
|
|
+ pkg = "AD";
|
|
+ break;
|
|
+ default:
|
|
+ pkg = "??";
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ /* REVISION */
|
|
+ switch (stm32mp1_dbgmcu_get_chip_version()) {
|
|
+ case STM32MP1_REV_A:
|
|
+ cpu_r = "A";
|
|
+ break;
|
|
+ case STM32MP1_REV_B:
|
|
+ cpu_r = "B";
|
|
+ break;
|
|
+ default:
|
|
+ cpu_r = "?";
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ NOTICE("CPU: STM32MP%s%s Rev.%s\n", cpu_s, pkg, cpu_r);
|
|
+}
|
|
+
|
|
+void stm32mp_print_boardinfo(void)
|
|
+{
|
|
+ uint32_t board;
|
|
+ int res = 0;
|
|
+
|
|
+ if (bsec_shadow_read_otp(&board, BOARD_OTP) != BSEC_OK) {
|
|
+ ERROR("BSEC: PART_NUMBER_OTP Error\n");
|
|
+ res = -1;
|
|
+ }
|
|
+
|
|
+ if ((res == 0) && (board != 0U)) {
|
|
+ char rev[1];
|
|
+
|
|
+ *rev = ((board >> 8) & 0xF) - 1 + 'A';
|
|
+ NOTICE("Board: MB%04x Var%d Rev.%s-%02d\n",
|
|
+ board >> 16,
|
|
+ (board >> 12) & 0xF,
|
|
+ rev,
|
|
+ board & 0xF);
|
|
+ }
|
|
+}
|
|
+
|
|
+/*
|
|
+ * This function determines if one single core is presently running. This is
|
|
+ * done by OTP read.
|
|
+ * Returns 1 if yes, 0 if more that one core is running, -1 if error.
|
|
+ */
|
|
+int stm32mp_is_single_core(void)
|
|
+{
|
|
+ uint32_t part_number = get_part_number();
|
|
+
|
|
+ /* STM32MP151x is a single core */
|
|
+ if ((part_number == STM32MP151A_PART_NB) ||
|
|
+ (part_number == STM32MP151C_PART_NB)) {
|
|
+ return 1;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+uint8_t stm32_iwdg_get_instance(uintptr_t base)
|
|
+{
|
|
+ switch (base) {
|
|
+ case IWDG1_BASE:
|
|
+ return IWDG1_INST;
|
|
+ case IWDG2_BASE:
|
|
+ return IWDG2_INST;
|
|
+ default:
|
|
+ panic();
|
|
+ }
|
|
+}
|
|
+
|
|
+uint32_t stm32_iwdg_get_otp_config(uintptr_t base)
|
|
+{
|
|
+ uint8_t idx;
|
|
+ uint32_t iwdg_cfg = 0;
|
|
+ uint32_t otp_value;
|
|
+
|
|
+#if defined(IMAGE_BL2)
|
|
+ if (bsec_shadow_read_otp(&otp_value, HW2_OTP) != BSEC_OK) {
|
|
+ panic();
|
|
+ }
|
|
+#elif defined(IMAGE_BL32)
|
|
+ if (bsec_read_otp(&otp_value, HW2_OTP) != BSEC_OK) {
|
|
+ panic();
|
|
+ }
|
|
+#endif
|
|
+
|
|
+ idx = stm32_iwdg_get_instance(base);
|
|
+
|
|
+ if ((otp_value & BIT(idx + IWDG_HW_POS)) != 0U) {
|
|
+ iwdg_cfg |= IWDG_HW_ENABLED;
|
|
+ }
|
|
+
|
|
+ if ((otp_value & BIT(idx + IWDG_FZ_STOP_POS)) == 0U) {
|
|
+ iwdg_cfg |= IWDG_ENABLE_ON_STOP;
|
|
+ }
|
|
+
|
|
+ if ((otp_value & BIT(idx + IWDG_FZ_STANDBY_POS)) == 0U) {
|
|
+ iwdg_cfg |= IWDG_ENABLE_ON_STANDBY;
|
|
+ }
|
|
+
|
|
+ return iwdg_cfg;
|
|
+}
|
|
+
|
|
+#if defined(IMAGE_BL2)
|
|
+uint32_t stm32_iwdg_shadow_update(uintptr_t base, uint32_t flags)
|
|
+{
|
|
+ uint32_t idx;
|
|
+ uint32_t otp;
|
|
+ uint32_t result;
|
|
+
|
|
+ if (bsec_shadow_read_otp(&otp, HW2_OTP) != BSEC_OK) {
|
|
+ panic();
|
|
+ }
|
|
+
|
|
+ idx = stm32_iwdg_get_instance(base);
|
|
+
|
|
+ if ((flags & IWDG_ENABLE_ON_STOP) != 0) {
|
|
+ otp |= BIT(idx + IWDG_FZ_STOP_POS);
|
|
+ }
|
|
+
|
|
+ if ((flags & IWDG_ENABLE_ON_STANDBY) != 0) {
|
|
+ otp |= BIT(idx + IWDG_FZ_STANDBY_POS);
|
|
+ }
|
|
+
|
|
+ result = bsec_write_otp(otp, HW2_OTP);
|
|
+ if (result != BSEC_OK) {
|
|
+ return result;
|
|
+ }
|
|
+
|
|
+ /* Sticky lock OTP_IWDG (read and write) */
|
|
+ if (!bsec_write_sr_lock(HW2_OTP, 1U) ||
|
|
+ !bsec_write_sw_lock(HW2_OTP, 1U)) {
|
|
+ return BSEC_LOCK_FAIL;
|
|
+ }
|
|
+
|
|
+ return BSEC_OK;
|
|
+}
|
|
+#endif
|
|
+
|
|
+/*
|
|
+ * This function allows to split bindings between platform and ETZPC
|
|
+ * HW mapping. If this conversion was done at driver level, the driver
|
|
+ * should include all supported platform bindings. ETZPC may be used on
|
|
+ * other platforms.
|
|
+ */
|
|
+enum etzpc_decprot_attributes stm32mp_etzpc_binding2decprot(uint32_t mode)
|
|
+{
|
|
+ switch (mode) {
|
|
+ case DECPROT_S_RW:
|
|
+ return TZPC_DECPROT_S_RW;
|
|
+ case DECPROT_NS_R_S_W:
|
|
+ return TZPC_DECPROT_NS_R_S_W;
|
|
+ case DECPROT_MCU_ISOLATION:
|
|
+ return TZPC_DECPROT_MCU_ISOLATION;
|
|
+ case DECPROT_NS_RW:
|
|
+ return TZPC_DECPROT_NS_RW;
|
|
+ default:
|
|
+ panic();
|
|
+ }
|
|
+}
|
|
diff --git a/plat/st/stm32mp1/stm32mp1_security.c b/plat/st/stm32mp1/stm32mp1_security.c
|
|
index e783c14..8dfbe71 100644
|
|
--- a/plat/st/stm32mp1/stm32mp1_security.c
|
|
+++ b/plat/st/stm32mp1/stm32mp1_security.c
|
|
@@ -8,10 +8,10 @@
|
|
#include <dt-bindings/clock/stm32mp1-clks.h>
|
|
#include <mmio.h>
|
|
#include <stdint.h>
|
|
-#include <stm32mp1_clk.h>
|
|
-#include <stm32mp1_dt.h>
|
|
+#include <stm32mp_dt.h>
|
|
#include <stm32mp1_private.h>
|
|
#include <stm32mp1_rcc.h>
|
|
+#include <stm32mp1_shared_resources.h>
|
|
#include <tzc400.h>
|
|
#include "platform_def.h"
|
|
|
|
@@ -22,13 +22,63 @@
|
|
static void init_tzc400(void)
|
|
{
|
|
unsigned long long region_base, region_top;
|
|
- unsigned long long ddr_base = STM32MP1_DDR_BASE;
|
|
+ unsigned long long ddr_base = STM32MP_DDR_BASE;
|
|
unsigned long long ddr_size = (unsigned long long)dt_get_ddr_size();
|
|
|
|
tzc400_init(STM32MP1_TZC_BASE);
|
|
|
|
tzc400_disable_filters();
|
|
|
|
+#ifdef AARCH32_SP_OPTEE
|
|
+ /* Region 1 set to cover all non-secure DRAM at 0xC000_0000. Apply the
|
|
+ * same configuration to all filters in the TZC.
|
|
+ */
|
|
+ region_base = ddr_base;
|
|
+ region_top = ddr_base + (ddr_size - STM32MP_DDR_S_SIZE - 1U);
|
|
+ tzc400_configure_region(STM32MP1_FILTER_BIT_ALL, 1,
|
|
+ region_base,
|
|
+ region_top,
|
|
+ 0,
|
|
+ TZC_REGION_ACCESS_RDWR(STM32MP1_TZC_A7_ID) |
|
|
+ TZC_REGION_ACCESS_RDWR(STM32MP1_TZC_GPU_ID) |
|
|
+ TZC_REGION_ACCESS_RDWR(STM32MP1_TZC_LCD_ID) |
|
|
+ TZC_REGION_ACCESS_RDWR(STM32MP1_TZC_MDMA_ID) |
|
|
+ TZC_REGION_ACCESS_RDWR(STM32MP1_TZC_M4_ID) |
|
|
+ TZC_REGION_ACCESS_RDWR(STM32MP1_TZC_DMA_ID) |
|
|
+ TZC_REGION_ACCESS_RDWR(STM32MP1_TZC_USB_HOST_ID) |
|
|
+ TZC_REGION_ACCESS_RDWR(STM32MP1_TZC_USB_OTG_ID) |
|
|
+ TZC_REGION_ACCESS_RDWR(STM32MP1_TZC_SDMMC_ID) |
|
|
+ TZC_REGION_ACCESS_RDWR(STM32MP1_TZC_ETH_ID) |
|
|
+ TZC_REGION_ACCESS_RDWR(STM32MP1_TZC_DAP_ID));
|
|
+
|
|
+ /* Region 2 set to cover all secure DRAM. */
|
|
+ region_base = ddr_base + (ddr_size - STM32MP_DDR_S_SIZE);
|
|
+ region_top = ddr_base + (ddr_size - STM32MP_DDR_SHMEM_SIZE - 1U);
|
|
+ tzc400_configure_region(STM32MP1_FILTER_BIT_ALL, 2,
|
|
+ region_base,
|
|
+ region_top,
|
|
+ TZC_REGION_S_RDWR,
|
|
+ 0);
|
|
+
|
|
+ /* Region 3 set to cover non-secure shared memory DRAM. */
|
|
+ region_base = ddr_base + (ddr_size - STM32MP_DDR_SHMEM_SIZE);
|
|
+ region_top = ddr_base + (ddr_size - 1U);
|
|
+ tzc400_configure_region(STM32MP1_FILTER_BIT_ALL, 3,
|
|
+ region_base,
|
|
+ region_top,
|
|
+ 0,
|
|
+ TZC_REGION_ACCESS_RDWR(STM32MP1_TZC_A7_ID) |
|
|
+ TZC_REGION_ACCESS_RDWR(STM32MP1_TZC_GPU_ID) |
|
|
+ TZC_REGION_ACCESS_RDWR(STM32MP1_TZC_LCD_ID) |
|
|
+ TZC_REGION_ACCESS_RDWR(STM32MP1_TZC_MDMA_ID) |
|
|
+ TZC_REGION_ACCESS_RDWR(STM32MP1_TZC_M4_ID) |
|
|
+ TZC_REGION_ACCESS_RDWR(STM32MP1_TZC_DMA_ID) |
|
|
+ TZC_REGION_ACCESS_RDWR(STM32MP1_TZC_USB_HOST_ID) |
|
|
+ TZC_REGION_ACCESS_RDWR(STM32MP1_TZC_USB_OTG_ID) |
|
|
+ TZC_REGION_ACCESS_RDWR(STM32MP1_TZC_SDMMC_ID) |
|
|
+ TZC_REGION_ACCESS_RDWR(STM32MP1_TZC_ETH_ID) |
|
|
+ TZC_REGION_ACCESS_RDWR(STM32MP1_TZC_DAP_ID));
|
|
+#else
|
|
/* Region 1 set to cover all DRAM at 0xC000_0000. Apply the
|
|
* same configuration to all filters in the TZC.
|
|
*/
|
|
@@ -42,12 +92,14 @@ static void init_tzc400(void)
|
|
TZC_REGION_ACCESS_RDWR(STM32MP1_TZC_GPU_ID) |
|
|
TZC_REGION_ACCESS_RDWR(STM32MP1_TZC_LCD_ID) |
|
|
TZC_REGION_ACCESS_RDWR(STM32MP1_TZC_MDMA_ID) |
|
|
+ TZC_REGION_ACCESS_RDWR(STM32MP1_TZC_M4_ID) |
|
|
TZC_REGION_ACCESS_RDWR(STM32MP1_TZC_DMA_ID) |
|
|
TZC_REGION_ACCESS_RDWR(STM32MP1_TZC_USB_HOST_ID) |
|
|
TZC_REGION_ACCESS_RDWR(STM32MP1_TZC_USB_OTG_ID) |
|
|
TZC_REGION_ACCESS_RDWR(STM32MP1_TZC_SDMMC_ID) |
|
|
TZC_REGION_ACCESS_RDWR(STM32MP1_TZC_ETH_ID) |
|
|
TZC_REGION_ACCESS_RDWR(STM32MP1_TZC_DAP_ID));
|
|
+#endif
|
|
|
|
/* Raise an exception if a NS device tries to access secure memory */
|
|
tzc400_set_action(TZC_ACTION_ERR);
|
|
@@ -62,30 +114,8 @@ static void init_tzc400(void)
|
|
******************************************************************************/
|
|
static void early_init_tzc400(void)
|
|
{
|
|
- uint32_t rstsr, rst_standby;
|
|
-
|
|
- rstsr = mmio_read_32(RCC_BASE + RCC_MP_RSTSCLRR);
|
|
-
|
|
- /* No warning if return from (C)STANDBY */
|
|
- rst_standby = rstsr &
|
|
- (RCC_MP_RSTSCLRR_STDBYRSTF | RCC_MP_RSTSCLRR_CSTDBYRSTF);
|
|
-
|
|
- if (stm32mp1_clk_is_enabled(TZC1) && (rst_standby == 0U)) {
|
|
- WARN("TZC400 port 1 clock already enable\n");
|
|
- }
|
|
-
|
|
- if (stm32mp1_clk_is_enabled(TZC2) && (rst_standby == 0U)) {
|
|
- WARN("TZC400 port 2 clock already enable\n");
|
|
- }
|
|
-
|
|
- if (stm32mp1_clk_enable(TZC1) != 0) {
|
|
- ERROR("Cannot enable TZC1 clock\n");
|
|
- panic();
|
|
- }
|
|
- if (stm32mp1_clk_enable(TZC2) != 0) {
|
|
- ERROR("Cannot enable TZC2 clock\n");
|
|
- panic();
|
|
- }
|
|
+ stm32mp_clk_enable(TZC1);
|
|
+ stm32mp_clk_enable(TZC2);
|
|
|
|
tzc400_init(STM32MP1_TZC_BASE);
|
|
|
|
@@ -96,10 +126,11 @@ static void early_init_tzc400(void)
|
|
* same configuration to all filters in the TZC.
|
|
*/
|
|
tzc400_configure_region(STM32MP1_FILTER_BIT_ALL, 1,
|
|
- STM32MP1_DDR_BASE,
|
|
- STM32MP1_DDR_BASE +
|
|
- (STM32MP1_DDR_MAX_SIZE - 1U),
|
|
+ STM32MP_DDR_BASE,
|
|
+ STM32MP_DDR_BASE +
|
|
+ (STM32MP_DDR_MAX_SIZE - 1U),
|
|
TZC_REGION_S_RDWR,
|
|
+ TZC_REGION_ACCESS_RDWR(STM32MP1_TZC_A7_ID) |
|
|
TZC_REGION_ACCESS_RDWR(STM32MP1_TZC_SDMMC_ID));
|
|
|
|
/* Raise an exception if a NS device tries to access secure memory */
|
|
diff --git a/plat/st/stm32mp1/stm32mp1_shared_resources.c b/plat/st/stm32mp1/stm32mp1_shared_resources.c
|
|
new file mode 100644
|
|
index 0000000..2c95de0
|
|
--- /dev/null
|
|
+++ b/plat/st/stm32mp1/stm32mp1_shared_resources.c
|
|
@@ -0,0 +1,833 @@
|
|
+// SPDX-License-Identifier: BSD-3-Clause
|
|
+/*
|
|
+ * Copyright (c) 2017-2018, STMicroelectronics
|
|
+ */
|
|
+
|
|
+#include <arch.h>
|
|
+#include <assert.h>
|
|
+#include <debug.h>
|
|
+#include <platform_def.h>
|
|
+#include <stdint.h>
|
|
+#include <stdio.h>
|
|
+#include <stm32_gpio.h>
|
|
+#include <stm32mp_dt.h>
|
|
+#include <stm32mp_shres_helpers.h>
|
|
+
|
|
+static bool registering_locked;
|
|
+static int8_t gpioz_nbpin = -1;
|
|
+
|
|
+/*
|
|
+ * Generic clock enable/disable from secure world.
|
|
+ * Some drivers may use non secure resources in specific execution context:
|
|
+ * when the other SMP core(s) are offline and non secure is never reached.
|
|
+ * In such cases, drivers shall enable/disable the HW clock only if it was not
|
|
+ * left enabled by the non secure world.
|
|
+ *
|
|
+ * During driver initializations, before registering_locked is locked, all
|
|
+ * driver simply enable/disable the clock as if the peripheral was secure.
|
|
+ */
|
|
+void stm32mp_clk_enable(unsigned long id)
|
|
+{
|
|
+ if (registering_locked) {
|
|
+ if (stm32mp1_clock_is_non_secure(id)) {
|
|
+ assert(stm32mp1_clk_get_refcount(id) == 0U);
|
|
+
|
|
+ if (stm32mp1_clk_is_enabled(id)) {
|
|
+ return;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ stm32mp1_clk_enable_secure(id);
|
|
+}
|
|
+
|
|
+void stm32mp_clk_disable(unsigned long id)
|
|
+{
|
|
+ if (registering_locked) {
|
|
+ if (stm32mp1_clock_is_non_secure(id)) {
|
|
+ if (stm32mp1_clk_get_refcount(id) == 0U) {
|
|
+ return;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ stm32mp1_clk_disable_secure(id);
|
|
+}
|
|
+
|
|
+/*
|
|
+ * Shared peripherals and resources.
|
|
+ * Defines resource that may be non secure, secure or shared.
|
|
+ * May be a device, a bus, a clock, a memory.
|
|
+ *
|
|
+ * State default to PERIPH_UNREGISTERED resource is not explicitly
|
|
+ * set here.
|
|
+ *
|
|
+ * Resource driver not built, the resource defaults
|
|
+ * to non secure ownership.
|
|
+ *
|
|
+ * Each IO of the GPIOZ IO can be secure or non secure.
|
|
+ * When the GPIO driver is enabled, the GPIOZ bank is fully non secure
|
|
+ * only if each IO is non secure and the GPIOZ bank is shared if it
|
|
+ * includes secure and non secure IOs.
|
|
+ *
|
|
+ * BKPSRAM is assumed shared.
|
|
+ * DDR control (DDRC and DDRPHY) is secure.
|
|
+ * Inits will define the resource state according the device tree
|
|
+ * and the driver initialization sequences.
|
|
+ *
|
|
+ * The platform initialization uses these information to set the ETZPC
|
|
+ * configuration. Non secure services (as clocks or regulator accesses)
|
|
+ * rely on these information to drive the related service execution.
|
|
+ */
|
|
+#define SHRES_NON_SECURE 3
|
|
+#define SHRES_SHARED 2
|
|
+#define SHRES_SECURE 1
|
|
+#define SHRES_UNREGISTERED 0
|
|
+
|
|
+static uint8_t shres_state[STM32MP1_SHRES_COUNT];
|
|
+
|
|
+static const char *shres2str_id_tbl[STM32MP1_SHRES_COUNT] = {
|
|
+ [STM32MP1_SHRES_GPIOZ(0)] = "GPIOZ0",
|
|
+ [STM32MP1_SHRES_GPIOZ(1)] = "GPIOZ1",
|
|
+ [STM32MP1_SHRES_GPIOZ(2)] = "GPIOZ2",
|
|
+ [STM32MP1_SHRES_GPIOZ(3)] = "GPIOZ3",
|
|
+ [STM32MP1_SHRES_GPIOZ(4)] = "GPIOZ4",
|
|
+ [STM32MP1_SHRES_GPIOZ(5)] = "GPIOZ5",
|
|
+ [STM32MP1_SHRES_GPIOZ(6)] = "GPIOZ6",
|
|
+ [STM32MP1_SHRES_GPIOZ(7)] = "GPIOZ7",
|
|
+ [STM32MP1_SHRES_IWDG1] = "IWDG1",
|
|
+ [STM32MP1_SHRES_USART1] = "USART1",
|
|
+ [STM32MP1_SHRES_SPI6] = "SPI6",
|
|
+ [STM32MP1_SHRES_I2C4] = "I2C4",
|
|
+ [STM32MP1_SHRES_RNG1] = "RNG1",
|
|
+ [STM32MP1_SHRES_HASH1] = "HASH1",
|
|
+ [STM32MP1_SHRES_CRYP1] = "CRYP1",
|
|
+ [STM32MP1_SHRES_I2C6] = "I2C6",
|
|
+ [STM32MP1_SHRES_RTC] = "RTC",
|
|
+ [STM32MP1_SHRES_MCU] = "MCU",
|
|
+ [STM32MP1_SHRES_HSI] = "HSI",
|
|
+ [STM32MP1_SHRES_LSI] = "LSI",
|
|
+ [STM32MP1_SHRES_HSE] = "HSE",
|
|
+ [STM32MP1_SHRES_LSE] = "LSE",
|
|
+ [STM32MP1_SHRES_CSI] = "CSI",
|
|
+ [STM32MP1_SHRES_PLL1] = "PLL1",
|
|
+ [STM32MP1_SHRES_PLL1_P] = "PLL1_P",
|
|
+ [STM32MP1_SHRES_PLL1_Q] = "PLL1_Q",
|
|
+ [STM32MP1_SHRES_PLL1_R] = "PLL1_R",
|
|
+ [STM32MP1_SHRES_PLL2] = "PLL2",
|
|
+ [STM32MP1_SHRES_PLL2_P] = "PLL2_P",
|
|
+ [STM32MP1_SHRES_PLL2_Q] = "PLL2_Q",
|
|
+ [STM32MP1_SHRES_PLL2_R] = "PLL2_R",
|
|
+ [STM32MP1_SHRES_PLL3] = "PLL3",
|
|
+ [STM32MP1_SHRES_PLL3_P] = "PLL3_P",
|
|
+ [STM32MP1_SHRES_PLL3_Q] = "PLL3_Q",
|
|
+ [STM32MP1_SHRES_PLL3_R] = "PLL3_R",
|
|
+};
|
|
+
|
|
+static const char *shres2str_id(unsigned int id)
|
|
+{
|
|
+ return shres2str_id_tbl[id];
|
|
+}
|
|
+
|
|
+static const char *shres2str_state_tbl[4] = {
|
|
+ [SHRES_SHARED] = "shared",
|
|
+ [SHRES_NON_SECURE] = "non secure",
|
|
+ [SHRES_SECURE] = "secure",
|
|
+ [SHRES_UNREGISTERED] = "unregistered",
|
|
+};
|
|
+
|
|
+static const char *shres2str_state(unsigned int id)
|
|
+{
|
|
+ return shres2str_state_tbl[id];
|
|
+}
|
|
+
|
|
+struct shres2decprot {
|
|
+ unsigned int shres_id;
|
|
+ unsigned int decprot_id;
|
|
+ const char *decprot_str;
|
|
+};
|
|
+
|
|
+#define SHRES2DECPROT(shres, decprot, str) { \
|
|
+ .shres_id = shres, \
|
|
+ .decprot_id = decprot, \
|
|
+ .decprot_str = str, \
|
|
+ }
|
|
+
|
|
+#define SHRES_INVALID ~0U
|
|
+static const struct shres2decprot shres2decprot_tbl[] = {
|
|
+ SHRES2DECPROT(STM32MP1_SHRES_IWDG1, STM32MP1_ETZPC_IWDG1_ID, "IWDG1"),
|
|
+ SHRES2DECPROT(STM32MP1_SHRES_USART1, STM32MP1_ETZPC_USART1_ID, "UART1"),
|
|
+ SHRES2DECPROT(STM32MP1_SHRES_SPI6, STM32MP1_ETZPC_SPI6_ID, "SPI6"),
|
|
+ SHRES2DECPROT(STM32MP1_SHRES_I2C4, STM32MP1_ETZPC_I2C4_ID, "I2C4"),
|
|
+ SHRES2DECPROT(STM32MP1_SHRES_RNG1, STM32MP1_ETZPC_RNG1_ID, "RNG1"),
|
|
+ SHRES2DECPROT(STM32MP1_SHRES_HASH1, STM32MP1_ETZPC_HASH1_ID, "HASH1"),
|
|
+ SHRES2DECPROT(STM32MP1_SHRES_CRYP1, STM32MP1_ETZPC_CRYP1_ID, "CRYP1"),
|
|
+ SHRES2DECPROT(STM32MP1_SHRES_I2C6, STM32MP1_ETZPC_I2C6_ID, "I2C6"),
|
|
+ /* Below are specific IDs without a 1-to-1 mapping to SHRES IDs */
|
|
+ SHRES2DECPROT(SHRES_INVALID, STM32MP1_ETZPC_STGENC_ID, "STGEN"),
|
|
+ SHRES2DECPROT(SHRES_INVALID, STM32MP1_ETZPC_BKPSRAM_ID, "BKPSRAM"),
|
|
+ SHRES2DECPROT(SHRES_INVALID, STM32MP1_ETZPC_DDRCTRL_ID, "DDRCTRL"),
|
|
+ SHRES2DECPROT(SHRES_INVALID, STM32MP1_ETZPC_DDRPHYC_ID, "DDRPHY"),
|
|
+};
|
|
+
|
|
+static unsigned int decprot2shres(unsigned int decprot_id)
|
|
+{
|
|
+ uint32_t i;
|
|
+
|
|
+ for (i = 0; i < ARRAY_SIZE(shres2decprot_tbl); i++) {
|
|
+ if (shres2decprot_tbl[i].decprot_id == decprot_id) {
|
|
+ return shres2decprot_tbl[i].shres_id;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ VERBOSE("No shared resource %u", decprot_id);
|
|
+ return SHRES_INVALID;
|
|
+}
|
|
+
|
|
+static const char *decprot2str(unsigned int decprot_id)
|
|
+{
|
|
+ size_t i;
|
|
+
|
|
+ for (i = 0; i < ARRAY_SIZE(shres2decprot_tbl); i++) {
|
|
+ if (shres2decprot_tbl[i].decprot_id == decprot_id) {
|
|
+ return shres2decprot_tbl[i].decprot_str;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ ERROR("Invalid ID %u", decprot_id);
|
|
+ panic();
|
|
+}
|
|
+
|
|
+static unsigned int get_gpioz_nbpin(void)
|
|
+{
|
|
+ if (gpioz_nbpin < 0) {
|
|
+ gpioz_nbpin = (int8_t)fdt_get_gpioz_nbpins_from_dt();
|
|
+ assert((gpioz_nbpin == 0) ||
|
|
+ (gpioz_nbpin == STM32MP_GPIOZ_PIN_MAX_COUNT));
|
|
+ }
|
|
+
|
|
+ return (unsigned int)gpioz_nbpin;
|
|
+}
|
|
+
|
|
+static bool shareable_resource(unsigned int id)
|
|
+{
|
|
+ switch (id) {
|
|
+ default:
|
|
+ /* Currently no shareable resource */
|
|
+ return false;
|
|
+ }
|
|
+}
|
|
+
|
|
+static void register_periph(unsigned int id, unsigned int state)
|
|
+{
|
|
+ assert(id < STM32MP1_SHRES_COUNT &&
|
|
+ state > SHRES_UNREGISTERED &&
|
|
+ state <= SHRES_NON_SECURE);
|
|
+
|
|
+ if (registering_locked) {
|
|
+ if (shres_state[id] == state) {
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ panic();
|
|
+ }
|
|
+
|
|
+ if ((state == SHRES_SHARED && !shareable_resource(id)) ||
|
|
+ ((shres_state[id] != SHRES_UNREGISTERED) &&
|
|
+ (shres_state[id] != state))) {
|
|
+ VERBOSE("Cannot change %s from %s to %s\n",
|
|
+ shres2str_id(id),
|
|
+ shres2str_state(shres_state[id]),
|
|
+ shres2str_state(state));
|
|
+ panic();
|
|
+ }
|
|
+
|
|
+ shres_state[id] = (uint8_t)state;
|
|
+
|
|
+ if (shres_state[id] == SHRES_UNREGISTERED) {
|
|
+ VERBOSE("Register %s as %s\n",
|
|
+ shres2str_id(id), shres2str_state(state));
|
|
+ }
|
|
+
|
|
+ switch (id) {
|
|
+ case STM32MP1_SHRES_GPIOZ(0) ... STM32MP1_SHRES_GPIOZ(7):
|
|
+ if ((id - STM32MP1_SHRES_GPIOZ(0)) >= get_gpioz_nbpin()) {
|
|
+ ERROR("Invalid GPIO pin %u, %u pin(s) available\n",
|
|
+ id - STM32MP1_SHRES_GPIOZ(0),
|
|
+ get_gpioz_nbpin());
|
|
+ panic();
|
|
+ }
|
|
+ break;
|
|
+ default:
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ /* Explore clock tree to lock dependencies */
|
|
+ if ((state == SHRES_SECURE) || (state == SHRES_SHARED)) {
|
|
+ switch (id) {
|
|
+ case STM32MP1_SHRES_GPIOZ(0) ... STM32MP1_SHRES_GPIOZ(7):
|
|
+ stm32mp1_register_clock_parents_secure(GPIOZ);
|
|
+ break;
|
|
+ case STM32MP1_SHRES_IWDG1:
|
|
+ stm32mp1_register_clock_parents_secure(IWDG1);
|
|
+ break;
|
|
+ case STM32MP1_SHRES_USART1:
|
|
+ stm32mp1_register_clock_parents_secure(USART1_K);
|
|
+ break;
|
|
+ case STM32MP1_SHRES_SPI6:
|
|
+ stm32mp1_register_clock_parents_secure(SPI6_K);
|
|
+ break;
|
|
+ case STM32MP1_SHRES_I2C4:
|
|
+ stm32mp1_register_clock_parents_secure(I2C4_K);
|
|
+ break;
|
|
+ case STM32MP1_SHRES_RNG1:
|
|
+ stm32mp1_register_clock_parents_secure(RNG1_K);
|
|
+ break;
|
|
+ case STM32MP1_SHRES_HASH1:
|
|
+ stm32mp1_register_clock_parents_secure(HASH1);
|
|
+ break;
|
|
+ case STM32MP1_SHRES_CRYP1:
|
|
+ stm32mp1_register_clock_parents_secure(CRYP1);
|
|
+ break;
|
|
+ case STM32MP1_SHRES_I2C6:
|
|
+ stm32mp1_register_clock_parents_secure(I2C6_K);
|
|
+ break;
|
|
+ case STM32MP1_SHRES_RTC:
|
|
+ stm32mp1_register_clock_parents_secure(RTC);
|
|
+ break;
|
|
+ case STM32MP1_SHRES_PLL1_P:
|
|
+ case STM32MP1_SHRES_PLL1_Q:
|
|
+ case STM32MP1_SHRES_PLL1_R:
|
|
+ register_periph(STM32MP1_SHRES_PLL1, SHRES_SECURE);
|
|
+ stm32mp1_register_clock_parents_secure(PLL1);
|
|
+ break;
|
|
+ case STM32MP1_SHRES_PLL2_P:
|
|
+ case STM32MP1_SHRES_PLL2_Q:
|
|
+ case STM32MP1_SHRES_PLL2_R:
|
|
+ register_periph(STM32MP1_SHRES_PLL2, SHRES_SECURE);
|
|
+ stm32mp1_register_clock_parents_secure(PLL2);
|
|
+ break;
|
|
+ case STM32MP1_SHRES_PLL3_P:
|
|
+ case STM32MP1_SHRES_PLL3_Q:
|
|
+ case STM32MP1_SHRES_PLL3_R:
|
|
+ register_periph(STM32MP1_SHRES_PLL3, SHRES_SECURE);
|
|
+ stm32mp1_register_clock_parents_secure(PLL3);
|
|
+ break;
|
|
+ default:
|
|
+ /* No expected resource dependency */
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
+static bool stm32mp1_mckprot_resource(unsigned int id)
|
|
+{
|
|
+ switch (id) {
|
|
+ case STM32MP1_SHRES_MCU:
|
|
+ case STM32MP1_SHRES_PLL3:
|
|
+ case STM32MP1_SHRES_PLL3_P:
|
|
+ case STM32MP1_SHRES_PLL3_Q:
|
|
+ case STM32MP1_SHRES_PLL3_R:
|
|
+ return true;
|
|
+ default:
|
|
+ return false;
|
|
+ }
|
|
+}
|
|
+
|
|
+/* Register resource by ID */
|
|
+void stm32mp1_register_secure_periph(unsigned int id)
|
|
+{
|
|
+ register_periph(id, SHRES_SECURE);
|
|
+}
|
|
+
|
|
+void stm32mp1_register_shared_periph(unsigned int id)
|
|
+{
|
|
+ register_periph(id, SHRES_SHARED);
|
|
+}
|
|
+
|
|
+void stm32mp1_register_non_secure_periph(unsigned int id)
|
|
+{
|
|
+ register_periph(id, SHRES_NON_SECURE);
|
|
+}
|
|
+
|
|
+/* Register resource by IO memory base address */
|
|
+static void register_periph_iomem(uintptr_t base, unsigned int state)
|
|
+{
|
|
+ unsigned int id;
|
|
+
|
|
+ switch (base) {
|
|
+ case IWDG1_BASE:
|
|
+ id = STM32MP1_SHRES_IWDG1;
|
|
+ break;
|
|
+ case USART1_BASE:
|
|
+ id = STM32MP1_SHRES_USART1;
|
|
+ break;
|
|
+ case SPI6_BASE:
|
|
+ id = STM32MP1_SHRES_SPI6;
|
|
+ break;
|
|
+ case I2C4_BASE:
|
|
+ id = STM32MP1_SHRES_I2C4;
|
|
+ break;
|
|
+ case I2C6_BASE:
|
|
+ id = STM32MP1_SHRES_I2C6;
|
|
+ break;
|
|
+ case RTC_BASE:
|
|
+ id = STM32MP1_SHRES_RTC;
|
|
+ break;
|
|
+ case RNG1_BASE:
|
|
+ id = STM32MP1_SHRES_RNG1;
|
|
+ break;
|
|
+ case CRYP1_BASE:
|
|
+ id = STM32MP1_SHRES_CRYP1;
|
|
+ break;
|
|
+ case HASH1_BASE:
|
|
+ id = STM32MP1_SHRES_HASH1;
|
|
+ break;
|
|
+
|
|
+ case GPIOA_BASE:
|
|
+ case GPIOB_BASE:
|
|
+ case GPIOC_BASE:
|
|
+ case GPIOD_BASE:
|
|
+ case GPIOE_BASE:
|
|
+ case GPIOF_BASE:
|
|
+ case GPIOG_BASE:
|
|
+ case GPIOH_BASE:
|
|
+ case GPIOI_BASE:
|
|
+ case GPIOJ_BASE:
|
|
+ case GPIOK_BASE:
|
|
+ case USART2_BASE:
|
|
+ case USART3_BASE:
|
|
+ case UART4_BASE:
|
|
+ case UART5_BASE:
|
|
+ case USART6_BASE:
|
|
+ case UART7_BASE:
|
|
+ case UART8_BASE:
|
|
+ case IWDG2_BASE:
|
|
+ /* Allow drivers to register some non secure resources */
|
|
+ VERBOSE("IO for non secure resource 0x%x\n",
|
|
+ (unsigned int)base);
|
|
+ if (state != SHRES_NON_SECURE) {
|
|
+ panic();
|
|
+ }
|
|
+
|
|
+ return;
|
|
+
|
|
+ default:
|
|
+ panic();
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ register_periph(id, state);
|
|
+}
|
|
+
|
|
+void stm32mp_register_secure_periph_iomem(uintptr_t base)
|
|
+{
|
|
+ register_periph_iomem(base, SHRES_SECURE);
|
|
+}
|
|
+
|
|
+void stm32mp_register_non_secure_periph_iomem(uintptr_t base)
|
|
+{
|
|
+ register_periph_iomem(base, SHRES_NON_SECURE);
|
|
+}
|
|
+
|
|
+/* Register GPIO resource */
|
|
+void stm32mp_register_secure_gpio(unsigned int bank, unsigned int pin)
|
|
+{
|
|
+ switch (bank) {
|
|
+ case GPIO_BANK_Z:
|
|
+ register_periph(STM32MP1_SHRES_GPIOZ(pin), SHRES_SECURE);
|
|
+ break;
|
|
+ default:
|
|
+ ERROR("GPIO bank %u cannot be secured\n", bank);
|
|
+ panic();
|
|
+ }
|
|
+}
|
|
+
|
|
+void stm32mp_register_non_secure_gpio(unsigned int bank, unsigned int pin)
|
|
+{
|
|
+ switch (bank) {
|
|
+ case GPIO_BANK_Z:
|
|
+ register_periph(STM32MP1_SHRES_GPIOZ(pin), SHRES_NON_SECURE);
|
|
+ break;
|
|
+ default:
|
|
+ break;
|
|
+ }
|
|
+}
|
|
+
|
|
+void stm32mp1_register_etzpc_decprot(unsigned int id,
|
|
+ enum etzpc_decprot_attributes attr)
|
|
+{
|
|
+ unsigned int state = SHRES_SECURE;
|
|
+ unsigned int id_shres;
|
|
+
|
|
+ switch (attr) {
|
|
+ case TZPC_DECPROT_S_RW:
|
|
+ break;
|
|
+ case TZPC_DECPROT_NS_R_S_W:
|
|
+ case TZPC_DECPROT_MCU_ISOLATION:
|
|
+ case TZPC_DECPROT_NS_RW:
|
|
+ state = SHRES_NON_SECURE;
|
|
+ break;
|
|
+ default:
|
|
+ panic();
|
|
+ }
|
|
+
|
|
+ id_shres = decprot2shres(id);
|
|
+ if (id_shres == SHRES_INVALID) {
|
|
+ if (state == SHRES_SECURE) {
|
|
+ panic();
|
|
+ }
|
|
+ } else {
|
|
+ register_periph(id_shres, state);
|
|
+ }
|
|
+}
|
|
+
|
|
+/* Get resource state: these accesses lock the registering support */
|
|
+static void lock_registering(void)
|
|
+{
|
|
+ registering_locked = true;
|
|
+}
|
|
+
|
|
+bool stm32mp1_periph_is_shared(unsigned long id)
|
|
+{
|
|
+ lock_registering();
|
|
+
|
|
+ return shres_state[id] == SHRES_SHARED;
|
|
+}
|
|
+
|
|
+bool stm32mp1_periph_is_non_secure(unsigned long id)
|
|
+{
|
|
+ lock_registering();
|
|
+
|
|
+ return shres_state[id] == SHRES_NON_SECURE;
|
|
+}
|
|
+
|
|
+bool stm32mp1_periph_is_secure(unsigned long id)
|
|
+{
|
|
+ lock_registering();
|
|
+
|
|
+ return shres_state[id] == SHRES_SECURE;
|
|
+}
|
|
+
|
|
+bool stm32mp1_periph_is_unregistered(unsigned long id)
|
|
+{
|
|
+ lock_registering();
|
|
+
|
|
+ return shres_state[id] == SHRES_UNREGISTERED;
|
|
+}
|
|
+
|
|
+bool stm32mp_gpio_bank_is_shared(unsigned int bank)
|
|
+{
|
|
+ unsigned int non_secure = 0;
|
|
+ unsigned int i;
|
|
+
|
|
+ lock_registering();
|
|
+
|
|
+ if (bank != GPIO_BANK_Z) {
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ for (i = 0U; i < get_gpioz_nbpin(); i++) {
|
|
+ if (stm32mp1_periph_is_non_secure(STM32MP1_SHRES_GPIOZ(i)) ||
|
|
+ stm32mp1_periph_is_unregistered(STM32MP1_SHRES_GPIOZ(i))) {
|
|
+ non_secure++;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return (non_secure != 0) && (non_secure < get_gpioz_nbpin());
|
|
+}
|
|
+
|
|
+bool stm32mp_gpio_bank_is_non_secure(unsigned int bank)
|
|
+{
|
|
+ unsigned int non_secure = 0;
|
|
+ unsigned int i;
|
|
+
|
|
+ lock_registering();
|
|
+
|
|
+ if (bank != GPIO_BANK_Z) {
|
|
+ return true;
|
|
+ }
|
|
+
|
|
+ for (i = 0U; i < get_gpioz_nbpin(); i++) {
|
|
+ if (stm32mp1_periph_is_non_secure(STM32MP1_SHRES_GPIOZ(i)) ||
|
|
+ stm32mp1_periph_is_unregistered(STM32MP1_SHRES_GPIOZ(i))) {
|
|
+ non_secure++;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return non_secure == get_gpioz_nbpin();
|
|
+}
|
|
+
|
|
+bool stm32mp_gpio_bank_is_secure(unsigned int bank)
|
|
+{
|
|
+ unsigned int secure = 0;
|
|
+ unsigned int i;
|
|
+
|
|
+ lock_registering();
|
|
+
|
|
+ if (bank != GPIO_BANK_Z) {
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ for (i = 0U; i < get_gpioz_nbpin(); i++) {
|
|
+ if (stm32mp1_periph_is_secure(STM32MP1_SHRES_GPIOZ(i))) {
|
|
+ secure++;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return secure == get_gpioz_nbpin();
|
|
+}
|
|
+
|
|
+bool stm32mp1_clock_is_shareable(unsigned long clock_id)
|
|
+{
|
|
+ switch (clock_id) {
|
|
+ case GPIOZ:
|
|
+ return get_gpioz_nbpin() > 0;
|
|
+ case RTCAPB:
|
|
+ return true;
|
|
+ default:
|
|
+ return false;
|
|
+ }
|
|
+}
|
|
+
|
|
+bool stm32mp1_clock_is_shared(unsigned long clock_id)
|
|
+{
|
|
+ lock_registering();
|
|
+
|
|
+ switch (clock_id) {
|
|
+ case GPIOZ:
|
|
+ if (get_gpioz_nbpin() > 0) {
|
|
+ return stm32mp_gpio_bank_is_shared(GPIO_BANK_Z);
|
|
+ } else {
|
|
+ return false;
|
|
+ }
|
|
+ case RTCAPB:
|
|
+ /* RTCAPB is shared for non secure backup registers */
|
|
+ return true;
|
|
+ default:
|
|
+ return false;
|
|
+ }
|
|
+}
|
|
+
|
|
+bool stm32mp1_clock_is_non_secure(unsigned long clock_id)
|
|
+{
|
|
+ unsigned int shres_id;
|
|
+
|
|
+ lock_registering();
|
|
+
|
|
+ if (stm32mp1_clock_is_shared(clock_id)) {
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ switch (clock_id) {
|
|
+ case BSEC:
|
|
+ case BKPSRAM:
|
|
+ case TZPC:
|
|
+ case TZC1:
|
|
+ case TZC2:
|
|
+ case STGEN_K:
|
|
+ case DDRC1:
|
|
+ case DDRC1LP:
|
|
+ case DDRC2:
|
|
+ case DDRC2LP:
|
|
+ case DDRPHYC:
|
|
+ case DDRPHYCLP:
|
|
+ case DDRCAPB:
|
|
+ case DDRCAPBLP:
|
|
+ case AXIDCG:
|
|
+ case DDRPHYCAPB:
|
|
+ case DDRPHYCAPBLP:
|
|
+ return false;
|
|
+ case IWDG1:
|
|
+ shres_id = STM32MP1_SHRES_IWDG1;
|
|
+ break;
|
|
+ case USART1_K:
|
|
+ shres_id = STM32MP1_SHRES_USART1;
|
|
+ break;
|
|
+ case SPI6_K:
|
|
+ shres_id = STM32MP1_SHRES_SPI6;
|
|
+ break;
|
|
+ case I2C4_K:
|
|
+ shres_id = STM32MP1_SHRES_I2C4;
|
|
+ break;
|
|
+ case RNG1_K:
|
|
+ shres_id = STM32MP1_SHRES_RNG1;
|
|
+ break;
|
|
+ case HASH1:
|
|
+ shres_id = STM32MP1_SHRES_HASH1;
|
|
+ break;
|
|
+ case CRYP1:
|
|
+ shres_id = STM32MP1_SHRES_CRYP1;
|
|
+ break;
|
|
+ case I2C6_K:
|
|
+ shres_id = STM32MP1_SHRES_I2C6;
|
|
+ break;
|
|
+ case RTC:
|
|
+ shres_id = STM32MP1_SHRES_RTC;
|
|
+ break;
|
|
+ default:
|
|
+ return true;
|
|
+ }
|
|
+
|
|
+ return stm32mp1_periph_is_non_secure(shres_id);
|
|
+}
|
|
+
|
|
+/* ETZPC configuration at drivers initialization completion */
|
|
+static enum etzpc_decprot_attributes decprot_periph_attr(unsigned int id)
|
|
+{
|
|
+ switch (id) {
|
|
+ case STM32MP1_SHRES_GPIOZ(0) ... STM32MP1_SHRES_GPIOZ(7):
|
|
+ assert((id - STM32MP1_SHRES_GPIOZ(0)) < get_gpioz_nbpin());
|
|
+ return TZPC_DECPROT_NS_RW;
|
|
+ default:
|
|
+ if (stm32mp1_periph_is_non_secure(id)) {
|
|
+ return TZPC_DECPROT_NS_RW;
|
|
+ }
|
|
+
|
|
+ return TZPC_DECPROT_S_RW;
|
|
+ }
|
|
+}
|
|
+
|
|
+static bool check_decprot(unsigned int id, enum etzpc_decprot_attributes exp)
|
|
+{
|
|
+ enum etzpc_decprot_attributes cur = etzpc_get_decprot(id);
|
|
+
|
|
+ if (cur == exp) {
|
|
+ return true;
|
|
+ }
|
|
+
|
|
+ switch (exp) {
|
|
+ case TZPC_DECPROT_NS_RW:
|
|
+ if (cur == TZPC_DECPROT_S_RW) {
|
|
+ WARN("ETZPC: %s (%d) could be non secure\n",
|
|
+ decprot2str(id), id);
|
|
+ }
|
|
+ return true;
|
|
+
|
|
+ case TZPC_DECPROT_S_RW:
|
|
+ ERROR("ETZPC: %s (%d) expected secure but DECPROT = %d\n",
|
|
+ decprot2str(id), id, cur);
|
|
+ break;
|
|
+
|
|
+ case TZPC_DECPROT_NS_R_S_W:
|
|
+ case TZPC_DECPROT_MCU_ISOLATION:
|
|
+ default:
|
|
+ panic();
|
|
+ }
|
|
+
|
|
+ return false;
|
|
+}
|
|
+
|
|
+static void check_etzpc_secure_configuration(void)
|
|
+{
|
|
+ bool error = false;
|
|
+
|
|
+ assert(registering_locked);
|
|
+
|
|
+ error |= !check_decprot(STM32MP1_ETZPC_STGENC_ID, TZPC_DECPROT_S_RW);
|
|
+
|
|
+ error |= !check_decprot(STM32MP1_ETZPC_BKPSRAM_ID, TZPC_DECPROT_S_RW);
|
|
+
|
|
+ error |= !check_decprot(STM32MP1_ETZPC_USART1_ID,
|
|
+ decprot_periph_attr(STM32MP1_SHRES_USART1));
|
|
+
|
|
+ error |= !check_decprot(STM32MP1_ETZPC_SPI6_ID,
|
|
+ decprot_periph_attr(STM32MP1_SHRES_SPI6));
|
|
+
|
|
+ error |= !check_decprot(STM32MP1_ETZPC_I2C4_ID,
|
|
+ decprot_periph_attr(STM32MP1_SHRES_I2C4));
|
|
+
|
|
+ error |= !check_decprot(STM32MP1_ETZPC_RNG1_ID,
|
|
+ decprot_periph_attr(STM32MP1_SHRES_RNG1));
|
|
+
|
|
+ error |= !check_decprot(STM32MP1_ETZPC_HASH1_ID,
|
|
+ decprot_periph_attr(STM32MP1_SHRES_HASH1));
|
|
+
|
|
+ error |= !check_decprot(STM32MP1_ETZPC_CRYP1_ID,
|
|
+ decprot_periph_attr(STM32MP1_SHRES_CRYP1));
|
|
+
|
|
+ error |= !check_decprot(STM32MP1_ETZPC_DDRCTRL_ID, TZPC_DECPROT_S_RW);
|
|
+
|
|
+ error |= !check_decprot(STM32MP1_ETZPC_DDRPHYC_ID, TZPC_DECPROT_S_RW);
|
|
+
|
|
+ error |= !check_decprot(STM32MP1_ETZPC_I2C6_ID,
|
|
+ decprot_periph_attr(STM32MP1_SHRES_I2C6));
|
|
+
|
|
+ if (error) {
|
|
+ panic();
|
|
+ }
|
|
+}
|
|
+
|
|
+static void check_rcc_secure_configuration(void)
|
|
+{
|
|
+ uint32_t n;
|
|
+ uint32_t error = 0;
|
|
+ bool mckprot = stm32mp1_rcc_is_mckprot();
|
|
+ bool secure = stm32mp1_rcc_is_secure();
|
|
+
|
|
+ stm32mp1_rcc_init_late();
|
|
+
|
|
+ for (n = 0; n < ARRAY_SIZE(shres_state); n++) {
|
|
+ if ((shres_state[n] == SHRES_SECURE) ||
|
|
+ (shres_state[n] == SHRES_SHARED)) {
|
|
+ if ((stm32mp1_mckprot_resource(n) && (!mckprot)) ||
|
|
+ !secure) {
|
|
+ ERROR("RCC %s MCKPROT %s and %s (%u) secure\n",
|
|
+ secure ? "secure" : "non secure",
|
|
+ mckprot ? "set" : "not set",
|
|
+ shres2str_id(n), n);
|
|
+ error++;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (error != 0U) {
|
|
+ panic();
|
|
+ }
|
|
+}
|
|
+
|
|
+static void check_gpio_secure_configuration(void)
|
|
+{
|
|
+ uint32_t pin;
|
|
+
|
|
+ for (pin = 0U; pin < get_gpioz_nbpin(); pin++) {
|
|
+ bool secure =
|
|
+ stm32mp1_periph_is_secure(STM32MP1_SHRES_GPIOZ(pin));
|
|
+
|
|
+ set_gpio_secure_cfg(GPIO_BANK_Z, pin, secure);
|
|
+ }
|
|
+}
|
|
+
|
|
+void stm32mp1_driver_init_late(void)
|
|
+{
|
|
+ uint32_t __unused id;
|
|
+
|
|
+ registering_locked = true;
|
|
+
|
|
+#if LOG_LEVEL >= LOG_LEVEL_INFO
|
|
+ for (id = 0; id < STM32MP1_SHRES_COUNT; id++) {
|
|
+ uint8_t *state = &shres_state[id];
|
|
+
|
|
+ /* Display only the secure and shared resources */
|
|
+ if ((*state == SHRES_NON_SECURE) ||
|
|
+ ((*state == SHRES_UNREGISTERED))) {
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ INFO("stm32mp %s (%u): %s\n",
|
|
+ shres2str_id(id), id,
|
|
+ *state == SHRES_SECURE ? "Secure only" :
|
|
+ *state == SHRES_SHARED ? "Shared" :
|
|
+ *state == SHRES_NON_SECURE ? "Non secure" :
|
|
+ *state == SHRES_UNREGISTERED ? "Unregistered" :
|
|
+ "<Invalid>");
|
|
+ }
|
|
+#endif
|
|
+
|
|
+ stm32mp1_update_earlyboot_clocks_state();
|
|
+
|
|
+ check_rcc_secure_configuration();
|
|
+ check_etzpc_secure_configuration();
|
|
+ check_gpio_secure_configuration();
|
|
+}
|
|
+
|
|
diff --git a/plat/st/stm32mp1/stm32mp1_syscfg.c b/plat/st/stm32mp1/stm32mp1_syscfg.c
|
|
new file mode 100644
|
|
index 0000000..3eb9893
|
|
--- /dev/null
|
|
+++ b/plat/st/stm32mp1/stm32mp1_syscfg.c
|
|
@@ -0,0 +1,144 @@
|
|
+/*
|
|
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
|
|
+ *
|
|
+ * SPDX-License-Identifier: BSD-3-Clause
|
|
+ */
|
|
+
|
|
+#include <bsec.h>
|
|
+#include <debug.h>
|
|
+#include <mmio.h>
|
|
+#include <platform_def.h>
|
|
+#include <stm32mp_dt.h>
|
|
+#include <stm32mp1_private.h>
|
|
+#include <stpmic1.h>
|
|
+
|
|
+/*
|
|
+ * SYSCFG REGISTER OFFSET (base relative)
|
|
+ */
|
|
+#define SYSCFG_BOOTR 0x00U
|
|
+#define SYSCFG_IOCTRLSETR 0x18U
|
|
+#define SYSCFG_ICNR 0x1CU
|
|
+#define SYSCFG_CMPCR 0x20U
|
|
+#define SYSCFG_CMPENSETR 0x24U
|
|
+
|
|
+/*
|
|
+ * SYSCFG_BOOTR Register
|
|
+ */
|
|
+#define SYSCFG_BOOTR_BOOT_MASK GENMASK(2, 0)
|
|
+#define SYSCFG_BOOTR_BOOTPD_SHIFT 4
|
|
+/*
|
|
+ * SYSCFG_IOCTRLSETR Register
|
|
+ */
|
|
+#define SYSCFG_IOCTRLSETR_HSLVEN_TRACE BIT(0)
|
|
+#define SYSCFG_IOCTRLSETR_HSLVEN_QUADSPI BIT(1)
|
|
+#define SYSCFG_IOCTRLSETR_HSLVEN_ETH BIT(2)
|
|
+#define SYSCFG_IOCTRLSETR_HSLVEN_SDMMC BIT(3)
|
|
+#define SYSCFG_IOCTRLSETR_HSLVEN_SPI BIT(4)
|
|
+
|
|
+/*
|
|
+ * SYSCFG_ICNR Register
|
|
+ */
|
|
+#define SYSCFG_ICNR_AXI_M9 BIT(9)
|
|
+
|
|
+/*
|
|
+ * SYSCFG_CMPCR Register
|
|
+ */
|
|
+#define SYSCFG_CMPCR_SW_CTRL BIT(1)
|
|
+#define SYSCFG_CMPCR_READY BIT(8)
|
|
+
|
|
+/*
|
|
+ * SYSCFG_CMPENSETR Register
|
|
+ */
|
|
+#define SYSCFG_CMPENSETR_MPU_EN BIT(0)
|
|
+
|
|
+#define PRODUCT_BELOW_2V5 BIT(13)
|
|
+
|
|
+void stm32mp1_syscfg_init(void)
|
|
+{
|
|
+ uint32_t bootr;
|
|
+ uint32_t otp = 0;
|
|
+ uint32_t vdd_voltage;
|
|
+ uintptr_t syscfg_base = dt_get_syscfg_base();
|
|
+
|
|
+ /*
|
|
+ * Interconnect update : select master using the port 1.
|
|
+ * LTDC = AXI_M9.
|
|
+ */
|
|
+ mmio_write_32(syscfg_base + SYSCFG_ICNR, SYSCFG_ICNR_AXI_M9);
|
|
+ VERBOSE("[0x%x] SYSCFG.icnr = 0x%08x (LTDC)\n",
|
|
+ (uint32_t)syscfg_base + SYSCFG_ICNR,
|
|
+ mmio_read_32(syscfg_base + SYSCFG_ICNR));
|
|
+
|
|
+ /* Disable Pull-Down for boot pin connected to VDD */
|
|
+ bootr = mmio_read_32(syscfg_base + SYSCFG_BOOTR);
|
|
+ bootr &= ~(SYSCFG_BOOTR_BOOT_MASK << SYSCFG_BOOTR_BOOTPD_SHIFT);
|
|
+ bootr |= (bootr & SYSCFG_BOOTR_BOOT_MASK) << SYSCFG_BOOTR_BOOTPD_SHIFT;
|
|
+ mmio_write_32(syscfg_base + SYSCFG_BOOTR, bootr);
|
|
+ VERBOSE("[0x%x] SYSCFG.bootr = 0x%08x\n",
|
|
+ (uint32_t)syscfg_base + SYSCFG_BOOTR,
|
|
+ mmio_read_32(syscfg_base + SYSCFG_BOOTR));
|
|
+
|
|
+ /*
|
|
+ * High Speed Low Voltage Pad mode Enable for SPI, SDMMC, ETH, QSPI
|
|
+ * and TRACE. Needed above ~50MHz and conditioned by AFMUX selection.
|
|
+ * The customer will have to disable this for low frequencies
|
|
+ * or if AFMUX is selected but the function not used, typically for
|
|
+ * TRACE. Otherwise, impact on power consumption.
|
|
+ *
|
|
+ * WARNING:
|
|
+ * Enabling High Speed mode while VDD > 2.7V
|
|
+ * with the OTP product_below_2v5 (OTP 18, BIT 13)
|
|
+ * erroneously set to 1 can damage the IC!
|
|
+ * => TF-A sets the register only if VDD < 2.7V (in DT)
|
|
+ * but this value needs to be consistent with board design.
|
|
+ */
|
|
+ if (bsec_read_otp(&otp, HW2_OTP) != BSEC_OK) {
|
|
+ otp = otp & PRODUCT_BELOW_2V5;
|
|
+ }
|
|
+
|
|
+ /* Get VDD = pwr-supply */
|
|
+ vdd_voltage = dt_get_pwr_vdd_voltage();
|
|
+ VERBOSE("VDD regulator voltage = %d\n", vdd_voltage);
|
|
+
|
|
+ /* Check if VDD is Low Voltage */
|
|
+ if (vdd_voltage == 0U) {
|
|
+ INFO("VDD unknown");
|
|
+ } else if (vdd_voltage < 2700000U) {
|
|
+ mmio_write_32(syscfg_base + SYSCFG_IOCTRLSETR,
|
|
+ SYSCFG_IOCTRLSETR_HSLVEN_TRACE |
|
|
+ SYSCFG_IOCTRLSETR_HSLVEN_QUADSPI |
|
|
+ SYSCFG_IOCTRLSETR_HSLVEN_ETH |
|
|
+ SYSCFG_IOCTRLSETR_HSLVEN_SDMMC |
|
|
+ SYSCFG_IOCTRLSETR_HSLVEN_SPI);
|
|
+
|
|
+ if (otp == 0U) {
|
|
+ INFO("Product_below_2v5=0: HSLVEN protected by HW\n");
|
|
+ }
|
|
+ } else {
|
|
+ if (otp != 0U) {
|
|
+ INFO("Product_below_2v5=1: HSLVEN update is\n");
|
|
+ INFO(" destructive, no update as VDD>2.7V\n");
|
|
+ }
|
|
+ }
|
|
+
|
|
+ VERBOSE("[0x%x] SYSCFG.IOCTRLSETR = 0x%08x\n",
|
|
+ (uint32_t)syscfg_base + SYSCFG_IOCTRLSETR,
|
|
+ mmio_read_32(syscfg_base + SYSCFG_IOCTRLSETR));
|
|
+
|
|
+ /*
|
|
+ * Activate automatic I/O compensation.
|
|
+ * Warning: need to ensure CSI enabled and ready in clock driver.
|
|
+ */
|
|
+ mmio_write_32(syscfg_base + SYSCFG_CMPENSETR, SYSCFG_CMPENSETR_MPU_EN);
|
|
+
|
|
+ while ((mmio_read_32(syscfg_base + SYSCFG_CMPCR) &
|
|
+ SYSCFG_CMPCR_READY) != 0U) {
|
|
+ ;
|
|
+ }
|
|
+
|
|
+ mmio_clrbits_32(syscfg_base + SYSCFG_CMPCR, SYSCFG_CMPCR_SW_CTRL);
|
|
+
|
|
+ VERBOSE("[0x%x] SYSCFG.cmpcr = 0x%08x\n",
|
|
+ (uint32_t)syscfg_base + SYSCFG_CMPCR,
|
|
+ mmio_read_32(syscfg_base + SYSCFG_CMPCR));
|
|
+}
|
|
diff --git a/plat/st/stm32mp1/stm32mp1_usb_desc.c b/plat/st/stm32mp1/stm32mp1_usb_desc.c
|
|
new file mode 100644
|
|
index 0000000..410cfa1
|
|
--- /dev/null
|
|
+++ b/plat/st/stm32mp1/stm32mp1_usb_desc.c
|
|
@@ -0,0 +1,401 @@
|
|
+/*
|
|
+ * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved.
|
|
+ *
|
|
+ * SPDX-License-Identifier: BSD-3-Clause
|
|
+ */
|
|
+
|
|
+#include <bsec.h>
|
|
+#include <debug.h>
|
|
+#include <platform_def.h>
|
|
+#include <stm32mp1_usb_desc.h>
|
|
+#include <string.h>
|
|
+#include <usb_core.h>
|
|
+#include <usb_st_dfu.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: Configuation Descriptor size */
|
|
+ USB_DESC_TYPE_CONFIGURATION, /* bDescriptorType: Configuration */
|
|
+ USB_DFU_CONFIG_DESC_SIZ,
|
|
+ /* wTotalLength: Bytes returned */
|
|
+ 0x00,
|
|
+ 0x01,/* bNumInterfaces: 1 interface*/
|
|
+ 0x01,/* bConfigurationValue: Configuration value*/
|
|
+ 0x02,/* iConfiguration: Index of string descriptor
|
|
+ * describing the configuration
|
|
+ */
|
|
+ 0xC0,/* bmAttributes: bus powered and Supprts Remote Wakeup */
|
|
+ 0x32,/* MaxPower 100 mA: this current is used for detecting Vbus */
|
|
+ /* 09 */
|
|
+
|
|
+ /* Descriptor of DFU interface 0 Alternate setting 0 */
|
|
+ USBD_DFU_IF_DESC(0), /* This interface is mandatory for all devices */
|
|
+
|
|
+ /* Descriptor of DFU interface 0 Alternate setting 1 */
|
|
+ USBD_DFU_IF_DESC(1),
|
|
+
|
|
+ /* Descriptor of DFU interface 0 Alternate setting 2 */
|
|
+ USBD_DFU_IF_DESC(2),
|
|
+
|
|
+ /* Descriptor of DFU interface 0 Alternate setting 3 */
|
|
+ USBD_DFU_IF_DESC(3),
|
|
+
|
|
+ /* Descriptor of DFU interface 0 Alternate setting 4 */
|
|
+ USBD_DFU_IF_DESC(4),
|
|
+
|
|
+ /* Descriptor of DFU interface 0 Alternate setting 5 */
|
|
+ USBD_DFU_IF_DESC(5),
|
|
+
|
|
+ /* DFU Functional Descriptor */
|
|
+ 0x09,/* blength = 9 Bytes */
|
|
+ DFU_DESCRIPTOR_TYPE,/* DFU Functional Descriptor*/
|
|
+ DFU_BM_ATTRIBUTE,/* bmAttribute
|
|
+ * bitCanDnload = 1 (bit 0)
|
|
+ * bitCanUpload = 1 (bit 1)
|
|
+ * bitManifestationTolerant = 1 (bit 2)
|
|
+ * bitWillDetach = 1 (bit 3)
|
|
+ * Reserved (bit4-6)
|
|
+ * bitAcceleratedST = 0 (bit 7)
|
|
+ */
|
|
+ 0xFF,/* DetachTimeOut = 255 ms */
|
|
+ 0x00,
|
|
+ /* WARNING: In DMA mode the multiple MPS packets feature
|
|
+ * is still not supported ==> In this case,
|
|
+ * when using DMA USBD_DFU_XFER_SIZE should be set
|
|
+ * to 64 in usbd_conf.h
|
|
+ */
|
|
+ TRANSFER_SIZE_BYTES(USBD_DFU_XFER_SIZE),/* TransferSize = 1024 Byte*/
|
|
+ ((USB_DFU_VERSION >> 0) & 0xFF), /* bcdDFUVersion*/
|
|
+ ((USB_DFU_VERSION >> 8) & 0xFF)
|
|
+};
|
|
+
|
|
+static uint8_t usb_local_string_dec[USBD_MAX_STR_DESC_SIZ];
|
|
+
|
|
+/*
|
|
+ * Convert Hex 32Bits value into char
|
|
+ * value: value to convert
|
|
+ * pbuf: pointer to the buffer
|
|
+ * len: buffer length
|
|
+ */
|
|
+static void int_to_unicode(uint32_t value, uint8_t *pbuf, uint8_t len)
|
|
+{
|
|
+ uint8_t idx = 0;
|
|
+
|
|
+ for (idx = 0; idx < len; idx++) {
|
|
+ if (((value >> 28)) < 0xA)
|
|
+ pbuf[2 * idx] = (value >> 28) + '0';
|
|
+ else
|
|
+ pbuf[2 * idx] = (value >> 28) + 'A' - 10;
|
|
+ value = value << 4;
|
|
+ pbuf[(2 * idx) + 1] = 0;
|
|
+ }
|
|
+}
|
|
+
|
|
+/*
|
|
+ * Create the serial number string descriptor
|
|
+ */
|
|
+static void update_serial_num_string(void)
|
|
+{
|
|
+ /* serial number is set to 0*/
|
|
+ uint8_t i;
|
|
+ uint32_t deviceserial[3] = {0, 0, 0};
|
|
+
|
|
+ for (i = 0; i < 3; i++) {
|
|
+ if (bsec_shadow_read_otp(&deviceserial[i], i + UID0_OTP) !=
|
|
+ BSEC_OK) {
|
|
+ ERROR("BSEC: UID%d Error\n", i);
|
|
+ return;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ int_to_unicode(deviceserial[0], (uint8_t *)&usb_stm32mp1_serial[2], 8);
|
|
+ int_to_unicode(deviceserial[1], (uint8_t *)&usb_stm32mp1_serial[18], 8);
|
|
+ int_to_unicode(deviceserial[2], (uint8_t *)&usb_stm32mp1_serial[34], 8);
|
|
+}
|
|
+
|
|
+/*
|
|
+ * usb_get_qualifier_desc
|
|
+ * return Device Qualifier descriptor
|
|
+ * param : length : pointer data length
|
|
+ * return : pointer to descriptor buffer
|
|
+ */
|
|
+static uint8_t *stm32mp1_get_qualifier_desc(uint16_t *length)
|
|
+{
|
|
+ *length = sizeof(usbd_stm32mp1_qualifier_desc);
|
|
+ return (uint8_t *)usbd_stm32mp1_qualifier_desc;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * stm32mp1_get_dfu_desc
|
|
+ * return Device Qualifier descriptor
|
|
+ * param : length : pointer data length
|
|
+ * return : pointer to descriptor buffer
|
|
+ */
|
|
+static uint8_t *stm32mp1_get_dfu_desc(uint16_t *len)
|
|
+{
|
|
+ *len = USB_DFU_DESC_SIZ;
|
|
+ return ((uint8_t *)usb_stm32mp1_config_desc + (9 * 7));
|
|
+}
|
|
+
|
|
+/*
|
|
+ * stm32mp1_get_config_desc
|
|
+ * return configuration descriptor
|
|
+ * param : speed : current device speed
|
|
+ * param : length : pointer data length
|
|
+ * return : pointer to descriptor buffer
|
|
+ */
|
|
+static uint8_t *stm32mp1_get_config_desc(uint16_t *length)
|
|
+{
|
|
+ *length = sizeof(usb_stm32mp1_config_desc);
|
|
+ return (uint8_t *)usb_stm32mp1_config_desc;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * stm32mp1_get_string
|
|
+ * Convert Ascii string into unicode one
|
|
+ * param : desc : descriptor buffer
|
|
+ * param : unicode : Formatted string buffer (unicode)
|
|
+ * param : len : descriptor length
|
|
+ * return : None
|
|
+ */
|
|
+static void stm32mp1_get_string(uint8_t *desc, uint8_t *unicode, uint16_t *len)
|
|
+{
|
|
+ uint8_t idx = 0;
|
|
+
|
|
+ if (!desc)
|
|
+ return;
|
|
+
|
|
+ *len = strlen((char *)desc) * 2 + 2;
|
|
+ unicode[idx++] = *len;
|
|
+ unicode[idx++] = USB_DESC_TYPE_STRING;
|
|
+
|
|
+ while (*desc != '\0') {
|
|
+ unicode[idx++] = *desc++;
|
|
+ unicode[idx++] = 0x00;
|
|
+ }
|
|
+}
|
|
+
|
|
+/*
|
|
+ * stm32mp1_device_desc
|
|
+ * Returns the device descriptor.
|
|
+ * length: Pointer to data length variable
|
|
+ * return : Pointer to descriptor buffer
|
|
+ */
|
|
+static uint8_t *stm32mp1_device_desc(uint16_t *length)
|
|
+{
|
|
+ *length = sizeof(usb_stm32mp1_desc);
|
|
+ return (uint8_t *)usb_stm32mp1_desc;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * stm32mp1_lang_id_desc
|
|
+ * Returns the LangID string descriptor.
|
|
+ * speed: Current device speed
|
|
+ * length: Pointer to data length variable
|
|
+ * return : Pointer to descriptor buffer
|
|
+ */
|
|
+static uint8_t *stm32mp1_lang_id_desc(uint16_t *length)
|
|
+{
|
|
+ *length = sizeof(usb_stm32mp1_lang_id_desc);
|
|
+
|
|
+ return (uint8_t *)usb_stm32mp1_lang_id_desc;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * stm32mp1_product_desc
|
|
+ * Returns the product string descriptor.
|
|
+ * length: Pointer to data length variable
|
|
+ * return : Pointer to descriptor buffer
|
|
+ */
|
|
+static uint8_t *stm32mp1_product_desc(uint16_t *length)
|
|
+{
|
|
+ stm32mp1_get_string((uint8_t *)USBD_PRODUCT_HS_STRING,
|
|
+ usb_local_string_dec, length);
|
|
+
|
|
+ return usb_local_string_dec;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * stm32mp1_manufacturer_desc
|
|
+ * Returns the manufacturer string descriptor.
|
|
+ * length: Pointer to data length variable
|
|
+ * return : Pointer to descriptor buffer
|
|
+ */
|
|
+static uint8_t *stm32mp1_manufacturer_desc(uint16_t *length)
|
|
+{
|
|
+ stm32mp1_get_string((uint8_t *)USBD_MANUFACTURER_STRING,
|
|
+ usb_local_string_dec, length);
|
|
+
|
|
+ return usb_local_string_dec;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * stm32mp1_serial_desc
|
|
+ * Returns the serial number string descriptor.
|
|
+ * length: Pointer to data length variable
|
|
+ * return : Pointer to descriptor buffer
|
|
+ */
|
|
+static uint8_t *stm32mp1_serial_desc(uint16_t *length)
|
|
+{
|
|
+ *length = USB_SIZ_STRING_SERIAL;
|
|
+
|
|
+ /* Update the serial number string descriptor
|
|
+ * with the data from the unique ID
|
|
+ */
|
|
+ update_serial_num_string();
|
|
+
|
|
+ return (uint8_t *)usb_stm32mp1_serial;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * stm32mp1_Config_desc
|
|
+ * Returns the configuration string descriptor.
|
|
+ * length: Pointer to data length variable
|
|
+ * return : Pointer to descriptor buffer
|
|
+ */
|
|
+static uint8_t *stm32mp1_config_desc(uint16_t *length)
|
|
+{
|
|
+ stm32mp1_get_string((uint8_t *)USBD_CONFIGURATION_HS_STRING,
|
|
+ usb_local_string_dec, length);
|
|
+
|
|
+ return usb_local_string_dec;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * stm32mp1_interface_desc
|
|
+ * Returns the interface string descriptor.
|
|
+ * length : Pointer to data length variable
|
|
+ * return : Pointer to descriptor buffer
|
|
+ */
|
|
+static uint8_t *stm32mp1_interface_desc(uint16_t *length)
|
|
+{
|
|
+ stm32mp1_get_string((uint8_t *)USBD_INTERFACE_HS_STRING,
|
|
+ usb_local_string_dec, length);
|
|
+
|
|
+ return usb_local_string_dec;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * stm32mp1_get_usr_desc
|
|
+ * Manages the transfer of memory interfaces string descriptors.
|
|
+ * param : index: descriptor index
|
|
+ * param : length : pointer data length
|
|
+ * return : pointer to the descriptor table or NULL if the descriptor
|
|
+ * is not supported.
|
|
+ */
|
|
+static uint8_t *stm32mp1_get_usr_desc(uint8_t index, uint16_t *length)
|
|
+{
|
|
+ uint8_t *ret;
|
|
+
|
|
+ if (index > (USBD_IDX_INTERFACE_STR + USBD_DESC_MAX_ITF_NUM))
|
|
+ return NULL;
|
|
+
|
|
+ switch (index) {
|
|
+ case 6:
|
|
+ stm32mp1_get_string((uint8_t *)"@Partition0 /0x00/1*256Ke",
|
|
+ usb_local_string_dec, length);
|
|
+ ret = usb_local_string_dec;
|
|
+ break;
|
|
+ case 7:
|
|
+ stm32mp1_get_string((uint8_t *)"@FSBL /0x01/1*1Me",
|
|
+ usb_local_string_dec, length);
|
|
+ ret = usb_local_string_dec;
|
|
+ break;
|
|
+ case 8:
|
|
+ stm32mp1_get_string((uint8_t *)"@Partition2 /0x02/1*1Me",
|
|
+ usb_local_string_dec, length);
|
|
+ ret = usb_local_string_dec;
|
|
+ break;
|
|
+ case 9:
|
|
+ stm32mp1_get_string((uint8_t *)"@Partition3 /0x03/1*16Me",
|
|
+ usb_local_string_dec, length);
|
|
+ ret = usb_local_string_dec;
|
|
+ break;
|
|
+ case 10:
|
|
+ stm32mp1_get_string((uint8_t *)"@Partition4 /0x04/1*16Me",
|
|
+ usb_local_string_dec, length);
|
|
+ ret = usb_local_string_dec;
|
|
+ break;
|
|
+ case 11:
|
|
+ stm32mp1_get_string((uint8_t *)"@virtual /0xF1/1*512Ba",
|
|
+ usb_local_string_dec, length);
|
|
+ ret = usb_local_string_dec;
|
|
+ break;
|
|
+ default:
|
|
+ ret = NULL;
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static const usb_desc_t dfu_desc = {
|
|
+ .get_device_desc = stm32mp1_device_desc,
|
|
+ .get_lang_id_desc = stm32mp1_lang_id_desc,
|
|
+ .get_manufacturer_desc = stm32mp1_manufacturer_desc,
|
|
+ .get_product_desc = stm32mp1_product_desc,
|
|
+ .get_configuration_desc = stm32mp1_config_desc,
|
|
+ .get_serial_desc = stm32mp1_serial_desc,
|
|
+ .get_interface_desc = stm32mp1_interface_desc,
|
|
+ .get_usr_desc = stm32mp1_get_usr_desc,
|
|
+ .get_hs_config_desc = stm32mp1_get_config_desc,
|
|
+ .get_fs_config_desc = stm32mp1_get_config_desc,
|
|
+ .get_other_speed_config_desc = stm32mp1_get_config_desc,
|
|
+ .get_device_qualifier_desc = stm32mp1_get_qualifier_desc,
|
|
+ .get_dfu_desc = stm32mp1_get_dfu_desc
|
|
+};
|
|
+
|
|
+void stm32mp_usb_init_desc(usb_handle_t *pdev)
|
|
+{
|
|
+ register_platform(pdev, &dfu_desc);
|
|
+}
|
|
diff --git a/tools/cert_create/Makefile b/tools/cert_create/Makefile
|
|
index 7b10e3e..c03629a 100644
|
|
--- a/tools/cert_create/Makefile
|
|
+++ b/tools/cert_create/Makefile
|
|
@@ -1,5 +1,5 @@
|
|
#
|
|
-# Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved.
|
|
+# Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
|
|
#
|
|
# SPDX-License-Identifier: BSD-3-Clause
|
|
#
|
|
@@ -22,7 +22,7 @@ OBJECTS := src/cert.o \
|
|
src/tbbr/tbb_ext.o \
|
|
src/tbbr/tbb_key.o
|
|
|
|
-CFLAGS := -Wall -std=c99
|
|
+HOSTCCFLAGS := -Wall -std=c99
|
|
|
|
MAKE_HELPERS_DIRECTORY := ../../make_helpers/
|
|
include ${MAKE_HELPERS_DIRECTORY}build_macros.mk
|
|
@@ -46,9 +46,9 @@ endif
|
|
endif
|
|
|
|
ifeq (${DEBUG},1)
|
|
- CFLAGS += -g -O0 -DDEBUG -DLOG_LEVEL=40
|
|
+ HOSTCCFLAGS += -g -O0 -DDEBUG -DLOG_LEVEL=40
|
|
else
|
|
- CFLAGS += -O2 -DLOG_LEVEL=20
|
|
+ HOSTCCFLAGS += -O2 -DLOG_LEVEL=20
|
|
endif
|
|
ifeq (${V},0)
|
|
Q := @
|
|
@@ -57,7 +57,7 @@ else
|
|
endif
|
|
|
|
$(eval $(call add_define,USE_TBBR_DEFS))
|
|
-CFLAGS += ${DEFINES}
|
|
+HOSTCCFLAGS += ${DEFINES}
|
|
|
|
# Make soft links and include from local directory otherwise wrong headers
|
|
# could get pulled in from firmware tree.
|
|
@@ -72,15 +72,15 @@ HOSTCC ?= gcc
|
|
all: clean ${BINARY}
|
|
|
|
${BINARY}: ${OBJECTS} Makefile
|
|
- @echo " LD $@"
|
|
+ @echo " HOSTLD $@"
|
|
@echo 'const char build_msg[] = "Built : "__TIME__", "__DATE__; \
|
|
const char platform_msg[] = "${PLAT_MSG}";' | \
|
|
- ${HOSTCC} -c ${CFLAGS} -xc - -o src/build_msg.o
|
|
+ ${HOSTCC} -c ${HOSTCCFLAGS} -xc - -o src/build_msg.o
|
|
${Q}${HOSTCC} src/build_msg.o ${OBJECTS} ${LIB_DIR} ${LIB} -o $@
|
|
|
|
%.o: %.c
|
|
- @echo " CC $<"
|
|
- ${Q}${HOSTCC} -c ${CFLAGS} ${INC_DIR} $< -o $@
|
|
+ @echo " HOSTCC $<"
|
|
+ ${Q}${HOSTCC} -c ${HOSTCCFLAGS} ${INC_DIR} $< -o $@
|
|
|
|
clean:
|
|
$(call SHELL_DELETE_ALL, src/build_msg.o ${OBJECTS})
|
|
diff --git a/tools/doimage/Makefile b/tools/doimage/Makefile
|
|
index bc74369..9f0d89d 100644
|
|
--- a/tools/doimage/Makefile
|
|
+++ b/tools/doimage/Makefile
|
|
@@ -7,11 +7,11 @@
|
|
PROJECT = doimage
|
|
OBJECTS = doimage.o
|
|
|
|
-CFLAGS = -Wall -Werror
|
|
+HOSTCCFLAGS = -Wall -Werror
|
|
ifeq (${DEBUG},1)
|
|
- CFLAGS += -g -O0 -DDEBUG
|
|
+ HOSTCCFLAGS += -g -O0 -DDEBUG
|
|
else
|
|
- CFLAGS += -O2
|
|
+ HOSTCCFLAGS += -O2
|
|
endif
|
|
|
|
ifeq (${MARVELL_SECURE_BOOT},1)
|
|
@@ -19,13 +19,13 @@ DOIMAGE_CC_FLAGS := -DCONFIG_MVEBU_SECURE_BOOT
|
|
DOIMAGE_LD_FLAGS := -lconfig -lmbedtls -lmbedcrypto -lmbedx509
|
|
endif
|
|
|
|
-CFLAGS += ${DOIMAGE_CC_FLAGS}
|
|
+HOSTCCFLAGS += ${DOIMAGE_CC_FLAGS}
|
|
|
|
# Make soft links and include from local directory otherwise wrong headers
|
|
# could get pulled in from firmware tree.
|
|
INCLUDE_PATHS = -I.
|
|
|
|
-CC := gcc
|
|
+HOSTCC ?= gcc
|
|
RM := rm -rf
|
|
|
|
.PHONY: all clean
|
|
@@ -33,15 +33,15 @@ RM := rm -rf
|
|
all: ${PROJECT}
|
|
|
|
${PROJECT}: ${OBJECTS} Makefile
|
|
- @echo " LD $@"
|
|
- ${Q}${CC} ${OBJECTS} ${DOIMAGE_LD_FLAGS} -o $@
|
|
+ @echo " HOSTLD $@"
|
|
+ ${Q}${HOSTCC} ${OBJECTS} ${DOIMAGE_LD_FLAGS} -o $@
|
|
@echo
|
|
@echo "Built $@ successfully"
|
|
@echo
|
|
|
|
-%.o: %.c %.h Makefile
|
|
- @echo " CC $<"
|
|
- ${Q}${CC} -c ${CFLAGS} ${INCLUDE_PATHS} $< -o $@
|
|
+%.o: %.c Makefile
|
|
+ @echo " HOSTCC $<"
|
|
+ ${Q}${HOSTCC} -c ${HOSTCCFLAGS} ${INCLUDE_PATHS} $< -o $@
|
|
|
|
clean:
|
|
${Q}${RM} ${PROJECT}
|
|
diff --git a/tools/fiptool/Makefile b/tools/fiptool/Makefile
|
|
index 9bdafe0..ef35014 100644
|
|
--- a/tools/fiptool/Makefile
|
|
+++ b/tools/fiptool/Makefile
|
|
@@ -1,5 +1,5 @@
|
|
#
|
|
-# Copyright (c) 2014-2017, ARM Limited and Contributors. All rights reserved.
|
|
+# Copyright (c) 2014-2018, ARM Limited and Contributors. All rights reserved.
|
|
#
|
|
# SPDX-License-Identifier: BSD-3-Clause
|
|
#
|
|
@@ -13,11 +13,11 @@ OBJECTS := fiptool.o tbbr_config.o
|
|
V ?= 0
|
|
|
|
override CPPFLAGS += -D_GNU_SOURCE -D_XOPEN_SOURCE=700
|
|
-CFLAGS := -Wall -Werror -pedantic -std=c99
|
|
+HOSTCCFLAGS := -Wall -Werror -pedantic -std=c99
|
|
ifeq (${DEBUG},1)
|
|
- CFLAGS += -g -O0 -DDEBUG
|
|
+ HOSTCCFLAGS += -g -O0 -DDEBUG
|
|
else
|
|
- CFLAGS += -O2
|
|
+ HOSTCCFLAGS += -O2
|
|
endif
|
|
LDLIBS := -lcrypto
|
|
|
|
@@ -36,15 +36,15 @@ HOSTCC ?= gcc
|
|
all: ${PROJECT}
|
|
|
|
${PROJECT}: ${OBJECTS} Makefile
|
|
- @echo " LD $@"
|
|
+ @echo " HOSTLD $@"
|
|
${Q}${HOSTCC} ${OBJECTS} -o $@ ${LDLIBS}
|
|
@${ECHO_BLANK_LINE}
|
|
@echo "Built $@ successfully"
|
|
@${ECHO_BLANK_LINE}
|
|
|
|
%.o: %.c %.h Makefile
|
|
- @echo " CC $<"
|
|
- ${Q}${HOSTCC} -c ${CPPFLAGS} ${CFLAGS} ${INCLUDE_PATHS} $< -o $@
|
|
+ @echo " HOSTCC $<"
|
|
+ ${Q}${HOSTCC} -c ${CPPFLAGS} ${HOSTCCFLAGS} ${INCLUDE_PATHS} $< -o $@
|
|
|
|
clean:
|
|
$(call SHELL_DELETE_ALL, ${PROJECT} ${OBJECTS})
|
|
diff --git a/tools/stm32image/Makefile b/tools/stm32image/Makefile
|
|
index 80dfbec..9c9b7b5 100644
|
|
--- a/tools/stm32image/Makefile
|
|
+++ b/tools/stm32image/Makefile
|
|
@@ -12,12 +12,12 @@ PROJECT := stm32image${BIN_EXT}
|
|
OBJECTS := stm32image.o
|
|
V := 0
|
|
|
|
-override CPPFLAGS += -D_GNU_SOURCE
|
|
-CFLAGS := -Wall -Werror -pedantic -std=c99
|
|
+HOSTCCFLAGS := -Wall -Werror -pedantic -std=c99 -D_GNU_SOURCE
|
|
+
|
|
ifeq (${DEBUG},1)
|
|
- CFLAGS += -g -O0 -DDEBUG
|
|
+ HOSTCCFLAGS += -g -O0 -DDEBUG
|
|
else
|
|
- CFLAGS += -O2
|
|
+ HOSTCCFLAGS += -O2
|
|
endif
|
|
|
|
ifeq (${V},0)
|
|
@@ -26,22 +26,22 @@ else
|
|
Q :=
|
|
endif
|
|
|
|
-CC := gcc
|
|
+HOSTCC := gcc
|
|
|
|
.PHONY: all clean distclean
|
|
|
|
all: ${PROJECT}
|
|
|
|
${PROJECT}: ${OBJECTS} Makefile
|
|
- @echo " LD $@"
|
|
- ${Q}${CC} ${OBJECTS} -o $@
|
|
+ @echo " HOSTLD $@"
|
|
+ ${Q}${HOSTCC} ${OBJECTS} -o $@
|
|
@${ECHO_BLANK_LINE}
|
|
@echo "Built $@ successfully"
|
|
@${ECHO_BLANK_LINE}
|
|
|
|
-%.o: %.c %.h Makefile
|
|
- @echo " CC $<"
|
|
- ${Q}${CC} -c ${CFLAGS} $< -o $@
|
|
+%.o: %.c Makefile
|
|
+ @echo " HOSTCC $<"
|
|
+ ${Q}${HOSTCC} -c ${HOSTCCFLAGS} $< -o $@
|
|
|
|
clean:
|
|
$(call SHELL_DELETE_ALL, ${PROJECT} ${OBJECTS})
|
|
diff --git a/tools/stm32image/stm32image.c b/tools/stm32image/stm32image.c
|
|
index 2607928..41024e2 100644
|
|
--- a/tools/stm32image/stm32image.c
|
|
+++ b/tools/stm32image/stm32image.c
|
|
@@ -22,7 +22,7 @@
|
|
#define VER_MINOR 1
|
|
#define VER_VARIANT 0
|
|
#define HEADER_VERSION_V1 0x1
|
|
-#define TF_BINARY_TYPE 0x0
|
|
+#define TF_BINARY_TYPE 0x10
|
|
|
|
/* Default option : bit0 => no signature */
|
|
#define HEADER_DEFAULT_OPTION (__cpu_to_le32(0x00000001))
|
|
--
|
|
2.7.4
|
|
|